Настройка гиперпараметров в Keras (MLP) через RandomizedSearchCV

Я уже некоторое время пытаюсь настроить нейронную сеть, но, к сожалению, не могу добиться от нее хорошей производительности. У меня есть набор данных временных рядов, и я использую RandomizedSearchCV для двоичной классификации. Мой код ниже. Любые предложения или помощь будут оценены. Во-первых, я все еще пытаюсь понять, как включить раннюю остановку.

РЕДАКТИРОВАТЬ: забыл добавить, что я измеряю производительность на основе метрики F1-macro и не могу получить оценку выше 0,68. Еще я заметил, что чем больше параметров я пытаюсь оценить одновременно (увеличить сетку), тем хуже моя оценка.

train_size = int(0.70*X.shape[0])
X_train, X_test, y_train, y_test = X[0:train_size], X[train_size:],y[0:train_size], y[train_size:]


from numpy.random import seed
seed(3)
from tensorflow import set_random_seed
set_random_seed(4)

from imblearn.pipeline import Pipeline

def create_model(activation_1='relu', activation_2='relu', 
                 neurons_input = 1, neurons_hidden_1=1,
                 optimizer='adam',
                 input_shape=(X_train.shape[1],)):

  model = Sequential()
  model.add(Dense(neurons_input, activation=activation_1, input_shape=input_shape, kernel_initializer='random_uniform'))

  model.add(Dense(neurons_hidden_1, activation=activation_2, kernel_initializer='random_uniform'))


  model.add(Dense(2, activation='sigmoid'))

  model.compile (loss = 'sparse_categorical_crossentropy', optimizer=optimizer)
  return model


clf=KerasClassifier(build_fn=create_model, verbose=0)

param_grid = {
    'clf__neurons_input':[5, 10, 15, 20, 25, 30, 35],
    'clf__neurons_hidden_1':[5, 10, 15, 20, 25, 30, 35],
    'clf__optimizer': ['Adam', 'Adamax','Adadelta'],
    'clf__activation_1': ['softmax', 'softplus', 'softsign', 'relu', 'tanh', 'sigmoid', 'hard_sigmoid', 'linear'],
    'clf__activation_2': ['softmax', 'softplus', 'softsign', 'relu', 'tanh', 'sigmoid', 'hard_sigmoid', 'linear'],
    'clf__batch_size': [40,60,80,100]}


pipe = Pipeline([
    ('oversample', SMOTE(random_state=12)),
    ('clf', clf)
    ])

my_cv = TimeSeriesSplit(n_splits=5).split(X_train)

rs_keras = RandomizedSearchCV(pipe, param_grid, cv=my_cv, scoring='f1_macro', refit='f1_macro', verbose=3, n_jobs=1,random_state=42)
rs_keras.fit(X_train, y_train)

print("Best: %f using %s" % (rs_keras.best_score_, rs_keras.best_params_))

from sklearn.metrics import classification_report, confusion_matrix
y_pred=rs_keras.predict(X_test)
clfreport = classification_report(y_test, y_pred)
cm = confusion_matrix(y_test, y_pred)
print (clfreport)
print (cm)
scores_test = rs_keras.score(X_test,y_test)
print ("Testing:", scores_test)

Мои оценкивведите здесь описание изображения


person eemamedo    schedule 13.04.2019    source источник
comment
Похоже, у вас очень несбалансированные данные. Что вы делаете по этому поводу? Может быть, проблема в том, что все ваши модели не могут найти хорошее решение из-за дисбаланса, а не из-за оптимизации гиперпараметров?   -  person Mischa Lisovyi    schedule 16.04.2019
comment
Использование SMOTE через конвейер.   -  person eemamedo    schedule 16.04.2019
comment
Хорошо, логично, теперь я могу найти это в коде. Следующий вопрос, который приходит мне на ум без доступа к данным: почему вы думаете, что F1 0,68 уже не велик? Может быть, ваша сетевая архитектура не подходит для этой проблемы? (временные ряды часто обрабатываются с помощью RNN вместо полносвязных сетей) Или, может быть, статистика class 1 сильно колеблется (поскольку ее доля мала), и ваша тестовая выборка сильно отличается от обучающей? (какова производительность на тренировочном наборе и выполняли ли вы EDA для сравнения распределений между обучающими и тестовыми наборами?)   -  person Mischa Lisovyi    schedule 17.04.2019
comment
Я еще раз взгляну на тестовый набор. Интересно, действительно ли SMOTE так сильно портит базовый дистрибутив, что тестовый набор больше не является представлением сбалансированного обучающего набора.   -  person eemamedo    schedule 18.04.2019
comment
Чтобы устранить артефакты SMOTE, вы также можете попробовать использовать веса в обучении вместо повторной выборки. Здесь был связанный вопрос   -  person Mischa Lisovyi    schedule 18.04.2019
comment
Я также пытался использовать class_weights, но, похоже, это не работает должным образом; У меня по-прежнему есть модель, отображающая поведение несбалансированного набора данных (конечная метрика сильно зависит от доминирующего класса).   -  person eemamedo    schedule 18.04.2019


Ответы (1)


О ранней остановке,

clf=KerasClassifier(build_fn=create_model, verbose=0)

stop = EarlyStopping(monitor='your_metric', min_delta=0, 
                         patience=5, verbose=1, mode='auto',
                         baseline=None, restore_best_weights=True)
.
.
.
grid.fit(x_train_sc, y_train_sc, callbacks = [stop])

Он должен работать. (Я тестировал его без структуры конвейера.)

Кстати, когда я пробовал свой набор данных с конвейерной структурой, он работал не так, как я думал. В моем случае я пытался стандартно масштабировать данные, но gridsearch сначала не масштабировал данные, поэтому они вошли в классификатор без масштабирования. Это было проблемой для меня.

Я предлагаю вам преобразовать данные перед gridsearch и попробовать без конвейера. Я знаю о проблемах с утечкой данных, но другого выхода не нашел.

person Masmm    schedule 18.04.2019
comment
Я пробовал раньше останавливаться, но, похоже, учитывались только потери на тренировках. Для val_loss выдается ошибка, в которой говорится, что что-то подобное не является приемлемой метрикой. Я склоняюсь к регуляризаторам l1_l2 или добавляю дропауты. - person eemamedo; 18.04.2019
comment
И относительно трубопровода; Я посмотрю на это. Это не должно иметь большого значения, но я попробую, несмотря ни на что. Спасибо. - person eemamedo; 18.04.2019
comment
val_loss — метрика мониторинга по умолчанию, она должна была быть принята. Вероятно, функция ранней остановки заботится только о KerasClassifier. (т.е. проверка проводится gridsearchCV). Вы можете попробовать передать validation_split=x.x с функцией подгонки, используя **fit_params, но я сомневаюсь, что это оптимальный способ. Если у вас есть время, вы можете использовать функции поиска в качестве общего случая. Я имею в виду, что вы можете взять best_params_ , использовать их для обучения сети и настройки. (Увеличение размера партии может ускорить процесс...). - person Masmm; 18.04.2019
comment
@eemamedo Для регуляризации: Ссылка - person Masmm; 18.04.2019