Передача аргумента кортежа в RandomSearchCV в scikit-learn - PullRequest
0 голосов
/ 27 апреля 2020

Я пытаюсь реализовать действительно случайный поиск по сетке, используя scikit-learn, специально для модели MLPRegressor.

model = Pipeline([
            ('scaler', StandardScaler()),
            ('mlp', MLPRegressor())
        ])

Эта модель принимает аргумент кортежа hidden_layer_sizes. Я не могу передать аргумент кортежа в аргумент param_distributions функции RandomizedSearchCV. После некоторых попыток я нашел обходной путь, но я не думаю, что это самый эффективный способ сделать это.

Для некоторого фона я могу использовать предопределенную сетку следующим образом, и она отлично работает

fixed_grid = [
  {'mlp__hidden_layer_sizes': [(10,10), (20,20)], 
   'mlp__tol': [1e-3, 1e-2],
   'mlp__max_iter': [5000, 10000]
  }
]

Однако случайная сетка не работает должным образом, так как она не может правильно сэмплировать кортеж.

from scipy.stats import randint
from sklearn.utils.fixes import loguniform

random_grid = [
  {'mlp__hidden_layer_sizes': [tuple([randint(10, 30), randint(10, 30)])], # 2 layers
   'mlp__tol': loguniform(1e-5, 1e-1),
   'mlp__max_iter': randint(low=500, high=2000)
  }
]

Приведенная выше сетка приводит к следующему фрагменту ошибки

AppData\Local\Continuum\anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:536: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details: 
TypeError: '<=' not supported between instances of 'rv_frozen' and 'int'

  FitFailedWarning)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

~\AppData\Local\Continuum\anaconda3\lib\site-packages\sklearn\model_selection\_search.py in fit(self, X, y, groups, **fit_params)
    737             refit_start_time = time.time()
    738             if y is not None:
--> 739                 self.best_estimator_.fit(X, y, **fit_params)
    740             else:
    741                 self.best_estimator_.fit(X, **fit_params)

~\AppData\Local\Continuum\anaconda3\lib\site-packages\sklearn\pipeline.py in fit(self, X, y, **fit_params)
    352                                  self._log_message(len(self.steps) - 1)):
    353             if self._final_estimator != 'passthrough':
--> 354                 self._final_estimator.fit(Xt, y, **fit_params)
    355         return self
    356 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\sklearn\neural_network\_multilayer_perceptron.py in fit(self, X, y)
    625         self : returns a trained MLP model.
    626         """
--> 627         return self._fit(X, y, incremental=False)
    628 
    629     @property

~\AppData\Local\Continuum\anaconda3\lib\site-packages\sklearn\neural_network\_multilayer_perceptron.py in _fit(self, X, y, incremental)
    319         # Validate input parameters.
    320         self._validate_hyperparameters()
--> 321         if np.any(np.array(hidden_layer_sizes) <= 0):
    322             raise ValueError("hidden_layer_sizes must be > 0, got %s." %
    323                              hidden_layer_sizes)

TypeError: '<=' not supported between instances of 'rv_frozen' and 'int'

Вышеуказанная ошибка связана с тем, что количество нейронов в каждом слое выбрано неправильно. Чтобы отладить это, я использую следующий код

from sklearn.model_selection import ParameterSampler
param_grid = {
    'a': [tuple([randint(10, 30), randint(10, 30)])],
    'b': [randint(10,30)],
    'c': [tuple(np.random.randint(10, 30, 2))],
    'd': [(random.randint(10, 30), random.randint(10, 30)) for i in range(0, 2)],
}

param_list = list(ParameterSampler(param_grid, n_iter=2, random_state=101))
param_list

Как видно, результаты параметров 'a' и 'b' выбраны неправильно.

[{'d': (17, 14),
  'c': (23, 21),
  'b': <scipy.stats._distn_infrastructure.rv_frozen at 0x21157e15948>,
  'a': (<scipy.stats._distn_infrastructure.rv_frozen at 0x21157dfc188>,
   <scipy.stats._distn_infrastructure.rv_frozen at 0x21157e21b88>)},
 {'d': (13, 16),
  'c': (23, 21),
  'b': <scipy.stats._distn_infrastructure.rv_frozen at 0x21157e15948>,
  'a': (<scipy.stats._distn_infrastructure.rv_frozen at 0x21157dfc188>,
   <scipy.stats._distn_infrastructure.rv_frozen at 0x21157e21b88>)}]

Как Обходной путь, я определил случайную сетку следующим образом. По сути, я определяю список из 100 случайных кортежей и позволяю функции RandomSearchCV выбирать из этого списка. Это работает, но все еще есть вероятность, что число нейронов будет повторяться, так как значение, используемое в каждой итерации, отбирается из списка только из 100 кортежей.

random_grid = [
  {'mlp__hidden_layer_sizes': [(random.randint(10, 30), random.randint(10, 30)) for i in range(0, 100)], # 2 layers
   'mlp__tol': loguniform(1e-5, 1e-1),
   'mlp__max_iter': randint(low=500, high=2000)
  }
]

Мне интересно, есть ли более эффективный и лаконичный способ выполнения этого случайного поиска по сетке с аргументами кортежей?

Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...