前幾天我們陸續調整了 Epoch、Early Stopping 和 Batch Size,但模型在訓練時,還有一個非常重要的問題:
每次根據 Loss 更新 Weight 時,到底應該「改多少」?
如果每次只調整一點點,模型可能學得非常慢;但如果一次調整太多,又可能直接錯過比較好的方向。
而控制模型每次更新幅度的重要參數,就是今天要介紹的:Learning Rate(學習率)
前面介紹 Loss 時,我們知道模型大致會重複下面的過程:
輸入圖片
↓
模型預測
↓
計算 Loss
↓
計算參數需要調整的方向
↓
更新 Weight
↓
再次預測
但知道「往哪個方向調整」之後,還有另一個問題就是這一次到底要調整多少?
這就是 Learning Rate 會影響的地方
Learning Rate 決定模型每次更新參數時,調整的步伐有多大
假設我們現在站在一座山上,而山谷最低的位置代表比較低的 Loss,我們的目標就是從目前位置到最低點,模型會根據目前的方向一步一步往比較低的位置移動
Learning Rate 就很像是在規範我們每一步要跨多大步,如果步伐適當,就可以逐漸靠近比較低的 Loss。
但如果步伐太小或太大,都可能出現問題。
假設 Learning Rate 非常小:learning_rate=0.00001,模型每次更新 Weight 時,只會改變非常小的幅度
就像爬山時方向可能沒有錯,但是每一步都非常小,因此可能需要非常多次更新,才能逐漸接近比較好的位置。
訓練時可能會看到 Loss 有下降,但是下降得很慢,或是 Accuracy 有上升,但是改善速度很慢,也就是模型不是完全沒有學習,而是學得太慢
那如果我們把 Learning Rate 設得非常大呢?
例如 learning_rate=0.1,每次更新參數時,模型就會跨出很大一步。
模型明明想往 Loss 比較低的地方移動,卻因為每一步太大,不斷跨過比較好的位置。
因此 Loss 可能一下下降,一下上升,一下又下降,甚至可能無法穩定收斂,所以 Learning Rate 太大,不代表模型會學得比較快,步伐太大反而可能讓模型難以靠近適合的位置。
這裡就會遇到另一個常見的名詞:Convergence(收斂)
模型剛開始訓練時,Weight 還沒有學好,因此 Loss 通常比較高。
隨著模型不斷更新參數,如果訓練逐漸趨於穩定,可以說模型的最佳化過程正在逐漸收斂,而 Learning Rate 就會直接影響這個過程。
Learning Rate 太小可能收斂得很慢,Learning Rate 太大,可能產生較大的震盪,甚至難以穩定收斂
適當的 Learning Rate 有機會較穩定地降低 Loss
前面的 CNN 都是這樣寫:
model.compile(optimizer="adam",loss="sparse_categorical_crossentropy",metrics=["accuracy"])
我們並沒有自己設定 Learning Rate,這種情況下,Keras 會使用 Adam Optimizer 的預設 Learning Rate。
但今天既然要觀察 Learning Rate 的影響,我們就把它明確寫出來:
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
再放進:
model.compile(optimizer=optimizer,loss="sparse_categorical_crossentropy",metrics=["accuracy"])
這樣就可以自己控制 Learning Rate。
和上一篇 Batch Size 一樣,這次也不要直接猜哪個比較好。
我們實際比較:
Learning Rate = 0.0001
Learning Rate = 0.001
Learning Rate = 0.01
這三個數值分別相差 10 倍,可以比較清楚地觀察 Learning Rate 改變後的訓練情況。
為了公平比較:Dataset、CNN 架構、Batch Size、Early Stopping 都設相同
主要改變的只有:Learning Rate
上一篇我們已經把 CNN 寫成 create_model(),今天稍微修改一下,讓它可以接收不同的 Learning Rate:
import tensorflow as tf
# 建立 CNN Model
# learning_rate 可以由外面傳入不同的數值
def create_model(learning_rate):
model = tf.keras.Sequential([
# 輸入圖片
tf.keras.layers.Input(shape=(64, 64, 3)),
tf.keras.layers.Conv2D(32,kernel_size=(3, 3),activation="relu",padding="same"),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
tf.keras.layers.Conv2D(64,kernel_size=(3, 3),activation="relu",padding="same"),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128,activation="relu"),
tf.keras.layers.Dense(7,activation="softmax")
])
# 設定 Adam Optimizer 的 Learning Rate
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
model.compile(optimizer=optimizer,loss="sparse_categorical_crossentropy",metrics=["accuracy"])
return model
這樣我們就可以:
create_model(0.0001)
create_model(0.001)
create_model(0.01)
建立三個架構相同、Learning Rate 不同的 CNN。
這邊示範比較小的 Learning Rate,剩下兩個的寫法相同
from tensorflow.keras.callbacks import EarlyStopping
model_lr_0001 = create_model(0.0001)
early_stopping_0001 = EarlyStopping(monitor="val_loss",patience=3,restore_best_weights=True)
history_lr_0001 = model_lr_0001.fit(X_train,y_train,validation_data=(X_val, y_val),epochs=50,batch_size=32,callbacks=[early_stopping_0001])
這一篇我們主要想觀察的是模型「學習」與「收斂」的過程,因此比起只看 Accuracy,我更想先看看 Validation Loss。
import matplotlib.pyplot as plt
plt.plot(history_lr_0001.history["val_loss"],label="Learning Rate = 0.0001")
plt.plot(history_lr_001.history["val_loss"],label="Learning Rate = 0.001")
plt.plot(history_lr_01.history["val_loss"],label="Learning Rate = 0.01")
plt.xlabel("Epoch")
plt.ylabel("Validation Loss")
plt.title("Validation Loss with Different Learning Rates")
plt.legend()
plt.show()

Learning Rate = 0.0001
Validation Loss 從約 1.01 緩慢下降,後期大約維持在 0.79 左右。整體下降相對穩定,但需要較多 Epoch 才逐漸降低,表示 Learning Rate 較小時,每次參數更新的幅度也比較小。
Learning Rate = 0.001
Validation Loss 下降得比較快,從約 0.90 降到最低約 0.75。雖然後面稍微回升,但在這次實驗中達到了三組設定中最低的 Validation Loss。
Learning Rate = 0.01
一開始的 Validation Loss 接近 1.2,雖然很快下降,但後續出現較明顯的上下波動,最低大約只有降到 0.91 左右,之後又開始上升。相較另外兩組,整體 Validation Loss 也比較高。
這次的結果剛好可以看出 Learning Rate 對模型學習過程的影響,因此,Learning Rate 並不是越大,模型就一定學得越快、越好。
在這次 HAM10000 CNN 的實驗中,0.001 的 Validation Loss 表現較好;0.0001 的下降速度較慢,而 0.01 則出現較明顯的波動。
不過這只是這次模型與資料設定下的實驗結果,不能因此認為 0.001 適合所有模型。不同的模型架構、Dataset、Batch Size 或 Optimizer,都可能讓適合的 Learning Rate 不同。
最後一樣使用相同的 Test Data 評估三個模型:
跑完後的結果如下:
從結果可以看到,0.001 得到最高的 Test Accuracy,約為 74.97%;而 Learning Rate 提高到 0.01 後,Accuracy 降到 68.34%,Loss 也明顯增加。
| Learning Rate | 可能出現的情況 |
|---|---|
| 太小 | 每次參數更新幅度小,Loss 可能下降得較慢 |
| 太大 | 更新幅度太大,Loss 可能明顯震盪,甚至難以穩定收斂 |
| 適當 | 能以較穩定的方式降低 Loss |