def fit(self, X, y=None):
        """Fit detector. y is ignored in unsupervised methods.

        Parameters
        ----------
        X : numpy array of shape (n_samples, n_features)
            The input samples.

        y : Ignored
            Not used, present for API consistency by convention.

        Returns
        -------
        self : object
            Fitted estimator.
        """
        # validate inputs X and y (optional)
        X = check_array(X)
        self._set_n_classes(y)

        # Verify and construct the hidden units
        self.n_samples_, self.n_features_ = X.shape[0], X.shape[1]

        # Standardize data for better performance
        if self.preprocessing:
            self.scaler_ = StandardScaler()
            X_norm = self.scaler_.fit_transform(X)
        else:
            X_norm = np.copy(X)

        # Shuffle the data for validation as Keras do not shuffling for
        # Validation Split
        np.random.shuffle(X_norm)

        # Validate and complete the number of hidden neurons
        if np.min(self.hidden_neurons) > self.n_features_ and self.use_ae:
            raise ValueError("The number of neurons should not exceed "
                             "the number of features")

        # Build DeepSVDD model & fit with X
        self.model_ = InnerDeepSVDD(self.n_features, use_ae=self.use_ae,
                                    hidden_neurons=self.hidden_neurons,
                                    hidden_activation=self.hidden_activation,
                                    output_activation=self.output_activation,
                                    dropout_rate=self.dropout_rate,
                                    l2_regularizer=self.l2_regularizer)
        X_norm = torch.tensor(X_norm, dtype=torch.float32)
        if self.c is None:
            self.c = 0.0
            self.model_._init_c(X_norm)

        # Predict on X itself and calculate the reconstruction error as
        # the outlier scores. Noted X_norm was shuffled has to recreate
        if self.preprocessing:
            X_norm = self.scaler_.transform(X)
        else:
            X_norm = np.copy(X)

        X_norm = torch.tensor(X_norm, dtype=torch.float32)
        dataset = TensorDataset(X_norm, X_norm)
        dataloader = DataLoader(dataset, batch_size=self.batch_size,
                                shuffle=True)

        best_loss = float('inf')
        best_model_dict = None

        optimizer = optimizer_dict[self.optimizer](self.model_.parameters(),
                                                   weight_decay=self.l2_regularizer)
        w_d = 1e-6 * sum(
            [torch.linalg.norm(w) for w in self.model_.parameters()])

        for epoch in range(self.epochs):
            self.model_.train()
            epoch_loss = 0
            for batch_x, _ in dataloader:
                optimizer.zero_grad()
                outputs = self.model_(batch_x)
                dist = torch.sum((outputs - self.c) ** 2, dim=-1)
                if self.use_ae:
                    loss = torch.mean(dist) + w_d + torch.mean(
                        torch.square(outputs - batch_x))
                else:
                    loss = torch.mean(dist) + w_d

                # loss.backward()
                optimizer.step()
                epoch_loss += loss.item()
                if epoch_loss < best_loss:
                    best_loss = epoch_loss
                    best_model_dict = self.model_.state_dict()
            print(f"Epoch {epoch + 1}/{self.epochs}, Loss: {epoch_loss}")
        self.best_model_dict = best_model_dict

        self.decision_scores_ = self.decision_function(X)
        self._process_decision_scores()
        return self
Fit detector. y is ignored in unsupervised methods.

        Parameters
        ----------
        X : numpy array of shape (n_samples, n_features)
            The input samples.

        y : Ignored
            Not used, present for API consistency by convention.

        Returns
        -------
        self : object
            Fitted estimator.
        
pyod/models/deep_svdd.py