#python #machine-learning #deep-learning
#python #машинное обучение #глубокое обучение
Вопрос:
Обычно мы можем определить обратный вызов для модели, чтобы остановить эпоху, если точность достигает определенного уровня.
Я работаю над настройкой параметров. val_acc очень нестабилен, как показано на рисунке.
def LSTM_model(X_train, y_train, X_test, y_test, num_classes, batch_size=68, units=128, learning_rate=0.005, epochs=20,
dropout=0.2, recurrent_dropout=0.2):
class myCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs={}):
if (logs.get('acc') > 0.90):
print("nReached 90% accuracy so cancelling training!")
self.model.stop_training = True
callbacks = myCallback()
Поскольку графики показывают, что val_acc (оранжевый) колеблется в пределах диапазона и на самом деле больше не растет.
Есть ли способ автоматически остановить обучение, как только общая тенденция val_acc перестанет увеличиваться?
Ответ №1:
Вы можете добиться этого с callback
помощью такого
class terminate_on_plateau(keras.callbacks.Callback):
def __init__(self):
self.patience = 10
self.val_loss = deque([],self.patience)
self.std_threshold = 1e-2
def on_epoch_end(self,epoch,logs=None):
val_loss,val_mae = model.evaluate(x_val,y_val)
self.val_loss.append(val_loss)
if len(self.val_loss) >= self.patience:
std = np.std(self.val_loss)
if std < self.std_threshold:
print('nn EarlyStopping on std invoked! nn')
# clear the deque
self.val_loss = deque([],self.patience)
model.stop_training = True
Как вы можете видеть, в terminate_on_plateau
, val_loss
из эпох хранятся в deque
максимальной длины self.patience
. Как только длина deque
будет достигнута self.patience
, стандартное отклонение val_loss
будет вычисляться для каждой новой эпохи, и процесс обучения будет завершен ( deque
оф val_loss
также будет очищен), если вычисленное std
значение меньше порогового значения.
Ниже приведен простой скрипт, который показывает вам, как использовать это
from collections import deque
import numpy as np
import tensorflow as tf
from tensorflow import keras
import tensorflow.keras.backend as K
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input,Dense
x = np.linspace(0,10,1000)
np.random.shuffle(x)
y = np.sin(x) x
x_train,x_val,y_train,y_val = train_test_split(x,y,test_size=0.3)
input_x = Input(shape=(1,))
y = Dense(10,activation='relu')(input_x)
y = Dense(10,activation='relu')(y)
y = Dense(1,activation='relu')(y)
model = Model(inputs=input_x,outputs=y)
adamopt = tf.keras.optimizers.Adam(lr=0.01, beta_1=0.9, beta_2=0.999, epsilon=1e-8)
class terminate_on_plateau(keras.callbacks.Callback):
def __init__(self):
self.patience = 10
self.val_loss = deque([],self.patience)
self.std_threshold = 1e-2
def on_epoch_end(self,epoch,logs=None):
val_loss,val_mae = model.evaluate(x_val,y_val)
self.val_loss.append(val_loss)
if len(self.val_loss) >= self.patience:
std = np.std(self.val_loss)
if std < self.std_threshold:
print('nn EarlyStopping on std invoked! nn')
# clear the deque
self.val_loss = deque([],self.patience)
model.stop_training = True
model.compile(loss='mse',optimizer=adamopt,metrics=['mae'])
history = model.fit(x_train,y_train,
batch_size=8,
epochs=100,
validation_data=(x_val, y_val),
verbose=1,
callbacks=[terminate_on_plateau()])
Комментарии:
1. Могу ли я узнать, почему вы решили вычислить val_loss вместо val_acc в этом случае, поскольку графики отображали точность? Подробнее, пожалуйста, поправьте меня, если я ошибаюсь. Могу ли я понимать «терпение» как размер окна, используемый для оценки std в течение эпох? например, std вычисляется каждые 10 эпох, если
patience
равно 10.2. @Leo Конечно, вы можете выбрать
val_acc
, при этом вам нужно только изменить этоmodel.evaluate(x_val,y_val)
на что-то, что вычисляетval_acc
. Я выбираюval_loss
просто для простоты. Этоpatience
числоval_loss
(илиval_acc
), которое используется для вычисления стандартного отклонения, я предлагаю вам немного прочитатьdeque
, поскольку я использую его для хранения историиval_loss
в моем коде, еслиpatience
оно равно 10, std будет вычисляться для каждой эпохи , как толькоdeque
достигнет максимальной длины, то есть 10.3. Да, это имеет смысл. Хотя я столкнулся с проблемой, во второй раз, когда я обучаю модель, она немедленно активирует обратные вызовы, я думаю, это потому, что данные в обратном вызове из последнего обучения не были удалены. Не могли бы вы изменить свои коды, чтобы исправить это?
4. @Leo Конечно, решение простое, просто добавьте эту строку
self.val_loss = deque([],self.patience)
прямо перед завершением процесса обучения. Ознакомьтесь с моим обновленным сообщением.
Ответ №2:
Приведенный ниже код предназначен для пользовательского обратного вызова, который остановит обучение, когда отслеживаемое количество не улучшится после терпения количества эпох. Установите для параметра acc_or_loss значение «потеря», чтобы отслеживать потери при проверке. Установите для него значение ‘acc’ для контроля точности проверки. Я рекомендую НЕ следить за точностью проверки, поскольку она может сильно колебаться, особенно в ранние эпохи. Я ввел операторы печати, чтобы вы могли видеть, что происходит во время обучения. Вы, конечно, можете удалить их позже. Если вы отслеживаете потерю проверки, обратный вызов останавливает обучение, если для определенного количества эпох потеря проверки превысила наименьшую потерю, обнаруженную в предыдущие эпохи. Если вы отслеживаете точность проверки, обратный вызов останавливает обучение, если для определенного количества эпох точность проверки осталась ниже максимальной точности проверки, зарегистрированной в предыдущие эпохи
class halt(keras.callbacks.Callback):
def __init__(self, patience, acc_or_loss):
self.acc_or_loss=acc_or_loss
super(halt, self).__init__()
self.patience=patience # specifies how many epochs without improvement before learning rate is adjusted
self.lowest_loss=np.inf
self.highest_acc=0
self.count=0
print ('initializing values ', 'count= ', self.count, ' lowest_loss= ', self.lowest_loss, 'highest acc= ', self.highest_acc)
def on_epoch_end(self, epoch, logs=None):
v_loss=logs.get('val_loss') # get the validation loss for this epoch
v_acc=logs.get('val_accuracy')
if self.acc_or_loss=='loss':
print (' for epoch ', epoch 1, ' v_loss= ', v_loss, ' lowest_loss= ', self.lowest_loss, 'count= ', self.count)
if v_loss< self.lowest_loss:
self.lowest_loss=v_loss
self.count=0
else:
self.count=self.count 1
if self.count>=self.patience:
print('There have been ', self.patience, ' epochs with no reduction of validation loss below the lowest loss')
print ('Terminating training')
self.model.stop_training = True
else:
print (' for epoch ', epoch 1, ' v_acc= ', v_acc, ' highest accuracy= ', self.highest_acc, 'count= ', self.count)
if v_acc>self.highest_acc:
self.count=0
self.highest_acc=v_acc
else:
self.count=self.count 1
if self.count>=self.patience:
print('There have been ', self.patience, ' epochs with noincrease in validation accuracy')
print ('Terminating training')
self.model.stop_training = True
patience= 2 # specify the patience value
acc_or_loss='loss' # specify to monitor validation loss or validation accuracy
callbacks=[halt(patience=patience, acc_or_loss=acc_or_loss)]
# in model.fit include callbacks=callbacks
Ответ №3:
Или вы можете просто использовать Keras
API в tensorflow : tf.keras.callbacks.EarlyStopping
Учитывая ваш первоначальный вопрос, я не уверен, зачем вам нужен пользовательский callbacks
Вот пример применения:
history = model.fit([trainX,trainX,trainX],
np.array(trainLabels),
validation_data = ([testX, testX, testX], np.array(testLabels)),
epochs=EPOCH,
batch_size=BATCH_SIZE,
steps_per_epoch = None,
callbacks=[tf.keras.callbacks.EarlyStopping(
monitor="val_acc",
patience=5,
mode="min",
restore_best_weights = True)])
Комментарии:
1. Режим должен быть «max», если вы хотите прекратить обучение, когда val_acc не увеличивается.
Ответ №4:
Некоторые из приведенных выше ответов немного сложны, вы можете использовать приведенный ниже код.
opt = tf.optimizers.Adadelta(learning_rate=0.01)
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=["accuracy"])
es = EarlyStopping(monitor='val_accuracy', mode='max', patience=20)
# will stop if validation accuracy is not improving till 20 epoches, you can give any number in patience.
ms = ModelCheckpoint('save_model.h5', monitor='val_accuracy', mode='max', save_best_only=True)
training_history = model.fit(x=X_train, y=y_train, validation_split=0.1, batch_size=5, epochs=1000, verbose=1,
callbacks = [es, ms])
Я только что скопировал этот код из своего проекта, который не предназначен для LSTM, вы можете настроить этот код в соответствии с вашей проблемой / задачей.