Я пытаюсь реализовать действительно случайный поиск по сетке, используя 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)
}
]
Мне интересно, есть ли более эффективный и лаконичный способ выполнения этого случайного поиска по сетке с аргументами кортежей?
Спасибо!