1. 程式人生 > 實用技巧 >神經網路訓練中回撥函式的實用教程

神經網路訓練中回撥函式的實用教程

作者|Andre Ye
編譯|VK
來源|Towards Data Science

回撥函式是神經網路訓練的重要組成部分

回撥操作可以在訓練的各個階段執行,可能是在epoch之間,在處理一個batch之後,甚至在滿足某個條件的情況下。回撥可以利用許多創造性的方法來改進訓練和效能,節省計算資源,並提供有關神經網路內部發生的事情的結論。

本文將詳細介紹重要回調的基本原理和程式碼,以及建立自定義回撥的過程。


ReduceLROnPlateau是Keras中預設包含的回撥。神經網路的學習率決定了梯度的比例因子,因此過高的學習率會導致優化器超過最優值,而學習率過低則會導致訓練時間過長。很難找到一個靜態的、效果很好的、不變的學習率。

顧名思義,“降低高原學習率”就是在損失指標停止改善或達到穩定時降低學習率。一般學習率減少2到10倍,這有助於磨練引數的最佳值。

要使用ReduceLROnPlateau,必須首先建立回撥物件。有四個引數很重要:

  • monitor,它用來監視指標
  • factor,它是新的學習率將被降低(乘以)的因子
  • persistence,回撥啟用之前等待的停滯epoch數
  • min_lr,它可以降低到的最小學習率。這可以防止不必要和不有益的減少。
from keras.callbacks import ReduceLROnPlateau
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
                              patience=5, min_lr=0.001)
model.fit(X_train, Y_train, callbacks=[reduce_lr])

當使用model.fit時,可以指定回撥引數。注意,這可以接受一個列表,因此可以安排多個回撥。

LearningRateScheduler是ReduceLROnPlateau的另一種選擇,它允許使用者根據epoch來安排學習率。如果你知道(可能來自以前的研究或實驗)網路的學習率在從epochs 1-10時應該是x, 在epochs 10-20是應該是y,LearningRateScheduler可以幫助實現這些變化。以上epoch的數字可以任意變化。

建立學習率排程器需要一個使用者定義的函式,該函式將epoch和learning rate作為引數。返回物件應該是新的學習率。

from keras.callbacks import LearningRateScheduler

def scheduler(epoch, lr): #定義回撥schedule
   if lr < 0.001: return lr * 1.5 #如果lr太小,增加lr
   elif epoch < 5: return lr #前五個epoch,不改變lr
   elif epoch < 10: return lr * tf.math.exp(-0.1) #第五到第十個epoch,減少lr
   else: return lr * tf.math.exp(-0.05) #第10個epoch之後,減少量更少
  
callback = LearningRateScheduler(scheduler) #建立回撥物件
model.fit(X_train, y_train, epochs=15, callbacks=[callback])

然後,將其轉換為Keras回撥後,就可以用於模型的訓練。這些排程程式非常有用,允許對網路進行控制,但建議在第一次訓練網路時使用ReduceLROnPlateau,因為它更具適應性。然後,可以進行視覺化模型,看是否能提供關於如何構造一個適當的LR排程器的相關想法。

此外,你可以同時使用ReduceLROnPlateau和LearningRateScheduler,例如,使用排程程式硬編碼一些學習速率(例如在前10個epoch不更改),同時利用自適應能力,在高原上降低學習率以提升效能。

EarlyStopping可以非常有助於防止在訓練模型時產生額外的冗餘執行。冗餘執行會導致高昂的計算成本。當網路在給定的時間段內沒有得到改善時,網路完成訓練並停止使用計算資源。與ReduceLROnPlateau類似,EarlyStopping需要monitor。

from keras.callbacks import EarlyStopping
  
callback = EarlyStopping(monitor='loss', patience=5)
model.fit(X_train, y_train, epochs=15, callbacks=[callback])

TerminateOnNaN有助於防止在訓練中產生梯度爆炸問題,因為輸入NaN會導致網路的其他部分發生爆炸。如果不採用TerminateOnNaN,Keras並不阻止網路的訓練。另外,nan會導致對計算能力的需求增加。為了防止這些情況發生,新增TerminateOnNaN是一個很好的安全檢查。

rom keras.callbacks import TerminateOnNaN
model.fit(X_train, y_train, epochs=15, callbacks = [TerminateOnNaN()])

由於許多原因,ModelCheckpoint可以以某種頻率(也許每隔10個左右的epoch)儲存模型的權重,因此它非常有用。

  • 如果訓練模型時突然中斷,則不需要完全重新訓練模型。

  • 如果,比如說,在第30個epoch,模型開始顯示出過擬合的跡象或其他問題,比如梯度爆炸,我們可以用最近儲存的權重重新載入模型(比如在第25個epoch),並調整引數以避免該問題,而無需重新進行大部分訓練。

  • 能夠提取某個epoch的權重並將其重新載入到另一個模型中有利於遷移學習。

在下面的場景中,ModelCheckpoint用於儲存具有最佳效能的模型的權重。在每個epoch,如果模型比其他記錄的epoch表現更好,則其權重儲存在一個檔案中(覆蓋前一個的權重)。在訓練結束時,我們使用model.load_weights進行載入.

from keras.callbacks import ModelCheckpoint

callback = ModelCheckpoint( #建立回撥
    filepath='/filepath/checkpoint', #告訴回撥要儲存權重的filepath在哪
    save_weights_only=True, #只保留權重(更有效),而不是整個模型
    monitor='val_acc', #度量
    mode='max', #找出使度量最大化的模型權重
    save_best_only=True #只保留最佳模型的權重(更有效),而不是所有的權重
)

model.fit(X_train, y_train, epochs=15, callbacks=[callback])
model.load_weights(checkpoint_filepath) #將最佳權重灌入模型中。

或者,如果需要基於頻率的儲存(每5個epoch儲存一次),請將save_freq設定為5

編寫自定義回撥是Keras包含的最好的特性之一,它允許執行高度特定的操作。但是,請注意,構造它比使用預設回撥要複雜得多。

我們的自定義回撥將採用類的形式。類似於在PyTorch中構建神經網路,我們可以繼承keras.callbacks.Callback回撥,它是一個基類。

我們的類可以有許多函式,這些函式必須具有下面列出的給定名稱以及這些函式將在何時執行。例如,將在每個epoch開始時執行on_epoch_begin函式。下面是Keras將從自定義回撥中讀取的所有函式,但是可以新增其他“helper”函式。

class CustomCallback(keras.callbacks.Callback): #繼承keras的基類
    def on_train_begin(self, logs=None):
        #日誌是某些度量的字典,例如鍵可以是 ['loss', 'mean_absolute_error']
    def on_train_end(self, logs=None): ...
    def on_epoch_begin(self, epoch, logs=None): ...
    def on_epoch_end(self, epoch, logs=None): ...
    def on_test_begin(self, logs=None): ...
    def on_test_end(self, logs=None): ...
    def on_predict_begin(self, logs=None): ...
    def on_predict_end(self, logs=None): ...
    def on_train_batch_begin(self, batch, logs=None): ...
    def on_train_batch_end(self, batch, logs=None): ...
    def on_test_batch_begin(self, batch, logs=None): ...
    def on_test_batch_end(self, batch, logs=None): ...
    def on_predict_batch_begin(self, batch, logs=None): ...
    def on_predict_batch_end(self, batch, logs=None): ...

根據函式的不同,你可以訪問不同的變數。例如,在函式on_epoch_begin中,該函式既可以訪問epoch編號,也可以訪問當前度量、日誌的字典。如果需要其他資訊,比如學習率,可以使用keras.backend.get_value.

然後,可以像對待其他回撥函式一樣對待你自定義的回撥函式。

model.fit(X_train, y_train, epochs=15, callbacks=[CustomCallback()])

自定義回撥的一些常見想法:

  • 在JSON或CSV檔案中記錄訓練結果。

  • 每10個epoch就通過電子郵件傳送訓練結果。

  • 在決定何時儲存模型權重或者新增更復雜的功能。

  • 訓練一個簡單的機器學習模型(例如使用sklearn),通過將其設定為類變數並以(x: action, y: change)的形式獲取資料,來學習何時提高或降低學習率。


當在神經網路中使用回撥函式時,你的控制力增強,神經網路變得更容易擬合。

原文連結:https://towardsdatascience.com/a-short-practical-guide-to-callbacks-in-neural-network-training-3a4d69568aef

歡迎關注磐創AI部落格站:
http://panchuang.net/

sklearn機器學習中文官方文件:
http://sklearn123.com/

歡迎關注磐創部落格資源彙總站:
http://docs.panchuang.net/