code: def fit(self, X, y):
      global keras_imported, KerasRegressor, KerasClassifier, EarlyStopping, ModelCheckpoint, TerminateOnNaN, keras_load_model
      self.model_name = get_name_from_model(self.model)
  
      X_fit = X
  
      if self.model_name[:12] == "DeepLearning" or self.model_name in [
          "BayesianRidge",
          "LassoLars",
          "OrthogonalMatchingPursuit",
          "ARDRegression",
          "Perceptron",
          "PassiveAggressiveClassifier",
          "SGDClassifier",
          "RidgeClassifier",
          "LogisticRegression",
          "XGBClassifier",
          "XGBRegressor",
      ]:
          if self.model_name[:3] == "XGB" and scipy.sparse.issparse(X):
              ones = [[1] for x in range(X.shape[0])]
              # Trying to force XGBoost to play nice with sparse matrices
              X_fit = scipy.sparse.hstack((X, ones))
  
          elif scipy.sparse.issparse(X_fit):
              X_fit = X_fit.todense()
  
          if self.model_name[:12] == "DeepLearning":
              if keras_imported == False:
                  # Suppress some level of logs
                  os.environ["TF_CPP_MIN_VLOG_LEVEL"] = "3"
                  os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
                  from keras.callbacks import (
                      EarlyStopping,
                      ModelCheckpoint,
                      TerminateOnNaN,
                  )
                  from keras.models import (
                      load_model as keras_load_model,
                  )
                  from keras.wrappers.scikit_learn import (
                      KerasRegressor,
                      KerasClassifier,
                  )
  
                  keras_imported = True
  
              # For Keras, we need to tell it how many input nodes to expect, which is our num_cols
              num_cols = X_fit.shape[1]
  
              model_params = self.model.get_params()
              del model_params["build_fn"]
              try:
                  del model_params["feature_learning"]
              except:
                  pass
              try:
                  del model_params["num_cols"]
              except:
                  pass
  
              if self.type_of_estimator == "regressor":
                  self.model = KerasRegressor(
                      build_fn=utils_models.make_deep_learning_model,
                      num_cols=num_cols,
                      feature_learning=self.feature_learning,
                      **model_params,
                  )
              elif self.type_of_estimator == "classifier":
                  self.model = KerasClassifier(
                      build_fn=utils_models.make_deep_learning_classifier,
                      num_cols=num_cols,
                      feature_learning=self.feature_learning,
                      **model_params,
                  )
  
      if self.model_name[:12] == "DeepLearning":
          try:
              if self.is_hp_search == True:
                  patience = 5
                  verbose = 0
              else:
                  patience = 25
                  verbose = 2
  
              X_fit, y, X_test, y_test = self.get_X_test(X_fit, y)
              if isinstance(X_test, pd.DataFrame):
                  X_test = X_test.values
              else:
                  try:
                      X_test = X_test.toarray()
                  except AttributeError as e:
                      pass
  
              if not self.is_hp_search:
                  print(
                      "\nWe will stop training early if we have not seen an improvement in validation accuracy in {} epochs".format(
                          patience
                      )
                  )
                  print(
                      "To measure validation accuracy, we will split off a random 10 percent of your training data set"
                  )
  
              early_stopping = EarlyStopping(
                  monitor="val_loss", patience=patience, verbose=verbose
              )
              terminate_on_nan = TerminateOnNaN()
  
              now_time = datetime.datetime.now()
              time_string = (
                  str(now_time.year)
                  + "_"
                  + str(now_time.month)
                  + "_"
                  + str(now_time.day)
                  + "_"
                  + str(now_time.hour)
                  + "_"
                  + str(now_time.minute)
              )
  
              temp_file_name = (
                  "tmp_dl_model_checkpoint_"
                  + time_string
                  + str(random.random())
                  + ".h5"
              )
              model_checkpoint = ModelCheckpoint(
                  temp_file_name,
                  monitor="val_loss",
                  save_best_only=True,
                  mode="min",
                  period=1,
              )
  
              callbacks = [early_stopping, terminate_on_nan]
              if not self.is_hp_search:
                  callbacks.append(model_checkpoint)
  
              self.model.fit(
                  X_fit,
                  y,
                  callbacks=callbacks,
                  validation_data=(X_test, y_test),
                  verbose=verbose,
              )
  
              # TODO: give some kind of logging on how the model did here! best epoch, best accuracy, etc.
  
              if self.is_hp_search is False:
                  self.model = keras_load_model(temp_file_name)
  
              try:
                  os.remove(temp_file_name)
              except OSError as e:
                  pass
          except KeyboardInterrupt as e:
              print(
                  "Stopping training at this point because we heard a KeyboardInterrupt"
              )
              print(
                  "If the deep learning model is functional at this point, we will output the model in its latest form"
              )
              print(
                  "Note that this feature is an unofficial beta-release feature that is known to fail on occasion"
              )
  
              if self.is_hp_search is False:
                  self.model = keras_load_model(temp_file_name)
              try:
                  os.remove(temp_file_name)
              except OSError as e:
                  pass
  
      elif self.model_name[:4] == "LGBM":
          import lightgbm as lgb
  
          if scipy.sparse.issparse(X_fit):
              X_fit = X_fit.toarray()
  
          verbose = True
          if self.is_hp_search == True:
              verbose = False
  
          train_dynamic_n_estimators = False
          if self.model.get_params()["n_estimators"] == 2000:
              train_dynamic_n_estimators = True
  
              X_fit, y, X_test, y_test = self.get_X_test(X_fit, y)
  
              try:
                  X_test = X_test.toarray()
              except AttributeError as e:
                  pass
  
              if self.X_test is not None:
                  eval_name = "X_test_the_user_passed_in"
              else:
                  eval_name = "random_holdout_set_from_training_data"
  
              if self.type_of_estimator == "regressor":
                  if self.training_prediction_intervals == True:
                      eval_metric = "quantile"
                  else:
                      eval_metric = "rmse"
              elif self.type_of_estimator == "classifier":
                  if len(set(y_test)) > 2:
                      eval_metric = "multi_logloss"
                  else:
                      eval_metric = "binary_logloss"
  
          cat_feature_indices = self.get_categorical_feature_indices()
          if self.memory_optimized == True:
              X_fit.to_csv("_lgbm_dataset.csv")
              del X_fit
  
          if cat_feature_indices is None:
              if train_dynamic_n_estimators:
                  self.model.fit(
                      X_fit,
                      y,
                      eval_set=[(X_test, y_test)],
                      early_stopping_rounds=100,
                      eval_metric=eval_metric,
                      eval_names=[eval_name],
                      verbose=verbose,
                  )
              else:
                  self.model.fit(X_fit, y, verbose=verbose)
          else:
              if train_dynamic_n_estimators:
                  self.model.fit(
                      X_fit,
                      y,
                      eval_set=[(X_test, y_test)],
                      early_stopping_rounds=100,
                      eval_metric=eval_metric,
                      eval_names=[eval_name],
                      categorical_feature=cat_feature_indices,
                      verbose=verbose,
                  )
              else:
                  self.model.fit(
                      X_fit,
                      y,
                      categorical_feature=cat_feature_indices,
                      verbose=verbose,
                  )
  
      elif self.model_name[:8] == "CatBoost":
          if isinstance(X_fit, pd.DataFrame):
              X_fit = X_fit.values
          else:
              X_fit = X_fit.toarray()
  
          if (
              self.type_of_estimator == "classifier"
              and len(pd.Series(y).unique()) > 2
          ):
              # TODO: we might have to modify the format of the y values, converting them all to ints, then back again (sklearn has a useful inverse_transform on some preprocessing classes)
              self.model.set_params(loss_function="MultiClass")
  
          cat_feature_indices = self.get_categorical_feature_indices()
  
          self.model.fit(X_fit, y, cat_features=cat_feature_indices)
  
      elif self.model_name[:16] == "GradientBoosting":
          if not sklearn_version > "0.18.1":
              if isinstance(X_fit, pd.DataFrame):
                  X_fit = X_fit.values
              else:
                  X_fit = X_fit.toarray()
  
          patience = 20
          best_val_loss = -10000000000
          num_worse_rounds = 0
          best_model = deepcopy(self.model)
          X_fit, y, X_test, y_test = self.get_X_test(X_fit, y)
  
          # Add a variable number of trees each time, depending how far into the process we are
          if os.environ.get("is_test_suite", False) == "True":
              num_iters = (
                  list(range(1, 50, 1))
                  + list(range(50, 100, 2))
                  + list(range(100, 250, 3))
              )
          else:
              num_iters = (
                  list(range(1, 50, 1))
                  + list(range(50, 100, 2))
                  + list(range(100, 250, 3))
                  + list(range(250, 500, 5))
                  + list(range(500, 1000, 10))
                  + list(range(1000, 2000, 20))
                  + list(range(2000, 10000, 100))
              )
          # TODO: get n_estimators from the model itself, and reduce this list to only those values that come under the value from the model
  
          try:
              for num_iter in num_iters:
                  warm_start = True
                  if num_iter == 1:
                      warm_start = False
  
                  self.model.set_params(
                      n_estimators=num_iter, warm_start=warm_start
                  )
                  self.model.fit(X_fit, y)
  
                  if self.training_prediction_intervals == True:
                      val_loss = self.model.score(X_test, y_test)
                  else:
                      try:
                          val_loss = self._scorer.score(
                              self, X_test, y_test
                          )
                      except Exception as e:
                          val_loss = self.model.score(X_test, y_test)
  
                  if (
                      val_loss - self.min_step_improvement
                      > best_val_loss
                  ):
                      best_val_loss = val_loss
                      num_worse_rounds = 0
                      best_model = deepcopy(self.model)
                  else:
                      num_worse_rounds += 1
                  print(
                      "["
                      + str(num_iter)
                      + "] random_holdout_set_from_training_data's score is: "
                      + str(round(val_loss, 3))
                  )
                  if num_worse_rounds >= patience:
                      break
          except KeyboardInterrupt:
              print(
                  "Heard KeyboardInterrupt. Stopping training, and using the best checkpointed GradientBoosting model"
              )
              pass
  
          self.model = best_model
          print(
              "The number of estimators that were the best for this training dataset: "
              + str(self.model.get_params()["n_estimators"])
          )
          print(
              "The best score on the holdout set: " + str(best_val_loss)
          )
  
      else:
          self.model.fit(X_fit, y)
  
      if self.X_test is not None:
          del self.X_test
          del self.y_test
      gc.collect()
      return self
  
imports: from collections import Iterable
  from copy import deepcopy
  import datetime
  import gc
  import os
  import random
  import warnings
  import numpy
  import pandas
  import scipy
  from sklearn.base import BaseEstimator, TransformerMixin
  from sklearn.model_selection import train_test_split
  from sklearn import __version__
  from auto_ml import utils_models
  from auto_ml.utils_models import get_name_from_model
label_desc: Use image node_id 3 for calling the FinalModelATC obj's underlying member method code with example usage: obj.fit(X, y) and returns: self