Вопрос или проблема
Я обучил модель LSTM для определения фальшивых доменных имен.
Мой набор данных выглядит так:
домен,фейк
google, 0
bezqcuoqzcjloc,1
...
с 50% нормальных и 50% фейковых доменных имен.
Вот мой код для тренировки LSTM:
def build_model(max_features, maxlen):
"""Создать модель LSTM"""
model = Sequential()
model.add(Embedding(max_features, 128, input_length=maxlen))
model.add(LSTM(128))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss="binary_crossentropy",
optimizer="rmsprop")
return model
def run(max_epoch=25, nfolds=10, batch_size=128):
"""Запустить обучение/тестирование на модели логистической регрессии"""
indata = data.get_data()
# Извлечь данные и метки
X = [x[1] for x in indata]
labels = [x[0] for x in indata]
# Сгенерировать словарь допустимых символов
valid_chars = {x:idx+1 for idx, x in enumerate(set(''.join(X)))}
max_features = len(valid_chars) + 1
maxlen = 100
# Преобразовать символы в int и дополнить
X = [[valid_chars[y] for y in x] for x in X]
X = sequence.pad_sequences(X, maxlen=maxlen)
# Преобразовать метки в 0-1
y = [0 if x == 'benign' else 1 for x in labels]
final_data = []
for fold in range(nfolds):
print("fold %u/%u" % (fold+1, nfolds))
X_train, X_test, y_train, y_test, _, label_test = train_test_split(X, y, labels,
test_size=0.2)
print("Создание модели...")
model = build_model(max_features, maxlen)
print("Обучение...")
X_train, X_holdout, y_train, y_holdout = train_test_split(X_train, y_train, test_size=0.05)
best_iter = -1
best_auc = 0.0
out_data = {}
for ep in range(max_epoch):
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=1)
t_probs = model.predict_proba(X_holdout)
t_auc = sklearn.metrics.roc_auc_score(y_holdout, t_probs)
print("Эпоха %d: auc = %f (лучший=%f)" % (ep, t_auc, best_auc))
if t_auc > best_auc:
best_auc = t_auc
best_iter = ep
probs = model.predict_proba(X_test)
out_data = {'y':y_test, 'labels': label_test, 'probs':probs, 'epochs': ep,
'confusion_matrix': sklearn.metrics.confusion_matrix(y_test, probs > .5)}
print(sklearn.metrics.confusion_matrix(y_test, probs > .5))
else:
# Улучшение больше не происходит...выход и расчет статистики
if (ep-best_iter) > 2:
break
print('Сохранение модели LSTM...')
model.save('LSTMmodel.h5')
final_data.append(out_data)
return final_data
if __name__ == '__main__':
run()
Я обучил и протестировал ее на наборе данных №1.
Затем я решил посмотреть, каковы будут предсказания, используя эту обученную модель на другом наборе данных, похожем на набор данных №1, но с другими доменными именами, очевидно.
Вот мой код:
LSTM_model = load_model('LSTMmodel_2.h5')
data = pickle.load(open('testdata.pkl', 'rb'))
# Извлечь данные и метки
X = [x[1] for x in data]
labels = [x[0] for x in data]
# Сгенерировать словарь допустимых символов
valid_chars = {x:idx+1 for idx, x in enumerate(set(''.join(X)))}
max_features = len(valid_chars) + 1
maxlen = 100
# Преобразовать символы в int и дополнить
X = [[valid_chars[y] for y in x] for x in X]
X = sequence.pad_sequences(X, maxlen=maxlen)
# Преобразовать метки в 0-1
y = [0 if x == 'benign' else 1 for x in labels]
y_pred = LSTM_model.predict(X)
acc = accuracy_score(y, y_pred.round())
print(acc)
print(sklearn.metrics.confusion_matrix(y, y_pred.round()))
print(sklearn.metrics.f1_score(y, y_pred.round()))
Но как результаты по точности, матрице путаницы или f1-скор мне дают следующие:
accuracy = 0.541563570018245
confusion matrix = [[26764 3258]
[33427 16573]]
F1-score = 0.47466025117784355
Что не так с моей моделью? Должен ли я делать несколько эпох при тестировании обученной модели на наборе данных №2?
Что меня не радует, так это то, что когда я обучал и тестировал свою модель, у меня были очень хорошие результаты, а при проверке на новом наборе данных она не работает так хорошо.
Если ваша модель сойдется на ваших обучающих данных, но не работает на тестовых данных, то, вероятно, причина в том, что вы переобучили свою модель. Попробуйте запустить до max_epoch=5 и затем сохранить модель, чтобы посмотреть, будет ли она работать лучше.
Вы могли бы попробовать несколько разных подходов. Поскольку похоже, что переобучение может быть проблемой, вы могли бы попробовать early stopping обратные вызовы:
callbacks = [
EarlyStopping(monitor="val_loss", patience=5)]
Чтобы использовать этот обратный вызов, вы могли бы сначала установить свой раздел валидации на что-то вроде этого:
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=1, validation_split = 0.2)
Вы также можете попробовать настроить уровни dropout, используя keras.tuner и адаптировать свой слой dropout вот так:
model.add(Dropout(hp.Float('dropout_' + str(i), min_value=0.0, max_value=1.0, step=0.05)))
Наконец, вы также можете настроить рекуррентный dropout в компоненте вашего слоя LSTM.
Ответ или решение
Когда ваша модель LSTM показывает хорошие результаты на обучающей выборке, но не справляется с тестовой выборкой, это может указывать на проблему переобучения. Рассмотрим несколько аспектов, которые могут помочь улучшить производительность вашей модели.
1. Анализ переобучения
Переобучение происходит, когда модель слишком хорошо подстраивается под обучающие данные, теряя способность обобщать информацию на новых данных. Для начала можно проверить следующие аспекты:
Следите за метриками
Запоминайте значения метрик (например, точности и AUC) для обучающей и валидационной выборок в процессе обучения. Если точность обучающей выборки значительно выше, чем у валидационной, это верный знак переобучения.
2. Использование валидации
В вашем коде отсутствует валидационная выборка (в вашем случае X_holdout). Добавив validation_split
в модель, вы получите возможность следить за производительностью на валидационной выборке и остановить обучение, когда оно перестанет улучшаться:
model.fit(X_train, y_train, batch_size=batch_size, epochs=1, validation_split=0.2)
3. Раннее завершение
Добавление обратного вызова EarlyStopping
может помочь автоматизировать этот процесс. Так вы сможете избежать продолжения обучения, когда ваша модель перестаёт улучшать свои результаты:
from keras.callbacks import EarlyStopping
callbacks = [
EarlyStopping(monitor="val_loss", patience=5)
]
Теперь добавьте этот обратный вызов в метод fit
:
model.fit(X_train, y_train, batch_size=batch_size, epochs=max_epoch, callbacks=callbacks, validation_split=0.2)
4. Оптимизация регуляризации
Параметры регуляризации, такие как Dropout
, могут быть оптимизированы. Попробуйте тестировать разные значения регуляризации:
model.add(Dropout(rate=0.3)) # Оптимизируйте значение dropout
5. Настройка гиперпараметров
Вместо использования фиксированных значений настраивайте гиперпараметры модели. Инструменты, такие как Keras Tuner, могут помочь вам в этом, позволяя находить оптимальные значения для количества нейронов в LSTM, значения Dropout
и других параметров.
6. Анализ применения на новом наборе данных
При тестировании модели на новом наборе данных убедитесь, что данные в обоих наборах имеют одинаковую предобработку. К примеру, если для обучения использовались символы, которых нет в тестовых данных, это может негативно сказаться на результатах.
7. Обучение на больших данных
Если у вас есть возможность, попробуйте увеличить объем данных для обучения. Большие объемы данных могут помочь улучшить способность вашей модели к обобщению.
Заключение
Обратите внимание на качества вашей модели. Выявление факторов, способствующих улучшению или ухудшению производительности, — это и есть процесс машинного обучения. Комбинируя подходы по предотвращению переобучения и выбирая оптимальные гиперпараметры, вы сможете значительно улучшить результаты. Попробуйте применить указанные рекомендации на практике и отследить изменения в производительности.