深度學習模型訓練過程中常遭遇過擬合問題,影響模型泛化能力。本文介紹三種避免過擬合的技術:早停法、丟棄法和 L1/L2 正則化,並提供 TensorFlow/Keras 實作範例。早停法監控驗證損失,在損失停止下降時提前終止訓練,避免模型過度擬合訓練資料。丟棄法隨機忽略部分神經元輸出,降低模型對特定特徵的依賴,提升泛化能力。L1/L2 正則化則透過約束模型權重大小,降低模型複雜度,同樣有助於防止過擬合。文章也討論了學習率和模型容量調整對模型效能的影響,並簡要介紹 Keras Tuner 的自動化超引數最佳化功能,讓讀者對提升模型效能有更全面的認識。

提升模型效能的技術

在深度學習模型的訓練過程中,過擬合(overfitting)是一個常見的問題。為瞭解決這個問題,我們可以採用多種技術來提升模型的效能。本篇文章將介紹三種常用的技術:早停法(Early Stopping)、丟棄法(Dropout)以及 L1 和 L2 正則化(Regularization)。

早停法(Early Stopping)

早停法是一種根據模型的驗證損失(validation loss)來決定何時停止訓練的技術。當模型的驗證損失在一段時間內沒有改善時,早停法會停止訓練並還原到最佳的模型引數。

內容解密:

在程式碼中,我們使用了 EarlyStopping 回撥函式來實作早停法。其中,monitor='val_loss' 表示我們關注的是驗證損失,patience=10 表示我們容忍 10 個 epoch 的驗證損失沒有改善,restore_best_weights=True 表示我們會還原到最佳的模型引數。

from tensorflow.keras.callbacks import EarlyStopping

early_stopping = EarlyStopping(
    monitor='val_loss',
    patience=10,
    restore_best_weights=True
)

history = self.model.fit(
    train_features,
    train_labels,
    epochs=epochs,
    batch_size=batch_size,
    callbacks=[early_stopping],
    validation_split=0.2
)

內容解密:

在輸出結果中,我們可以看到早停法被觸發的資訊,包括停止時的 epoch 數、還原的最佳模型引數的 epoch 數等。這些資訊可以幫助我們瞭解模型的訓練過程。

丟棄法(Dropout)

丟棄法是一種透過隨機丟棄神經元的輸出來防止過擬合的技術。在訓練過程中,丟棄法的丟棄率(dropout rate)可以控制丟棄的神經元的比例。

內容解密:

在程式碼中,我們使用了 Dropout 層來實作丟棄法。其中,Dropout(0.5) 表示我們丟棄 50% 的神經元輸出。

from tensorflow.keras.layers import Dropout

self.model = Sequential([
    Dense(64, activation='relu', input_shape=self.input_shape),
    Dropout(0.5),
    Dense(32, activation='relu'),
    Dropout(0.5),
    Dense(16, activation='relu'),
    Dropout(0.5),
    Dense(1)
])

內容解密:

透過調整丟棄率,我們可以控制模型的複雜度。過高的丟棄率可能會導致模型欠擬合,而過低的丟棄率可能無法有效防止過擬合。

L1 和 L2 正則化(Regularization)

L1 和 L2 正則化是透過在損失函式中新增正則項來防止過擬合的技術。L1 正則化使用引數的絕對值,而 L2 正則化使用引數的平方值。

內容解密:

在程式碼中,我們使用了 l1 正則化來實作 L1 正則化。其中,l1(0.01) 表示我們對模型的引數增加了 L1 正則項。

from tensorflow.keras.regularizers import l1

self.model = Sequential([
    Dense(64, activation='relu', input_shape=self.input_shape, kernel_regularizer=l1(0.01)),
    Dense(32, activation='relu', kernel_regularizer=l1(0.01)),
    Dense(16, activation='relu', kernel_regularizer=l1(0.01)),
    Dense(1)
])

內容解密:

透過調整正則化的強度,我們可以控制模型的複雜度。過強的正則化可能會導致模型欠擬合,而過弱的正則化可能無法有效防止過擬合。

調整神經網路模型的正則化技術與學習率最佳化

在深度學習模型的訓練過程中,正則化技術和學習率的調整對於模型的效能和收斂速度具有至關重要的影響。本文將探討如何在 TensorFlow 中實作 L1 和 L2 正則化,以及如何調整學習率來最佳化模型的訓練過程。

L1 正則化的實作

L1 正則化透過在損失函式中新增權重的絕對值之和,來控制模型的複雜度,防止過擬合。以下是如何在 TensorFlow 中實作 L1 正則化的範例:

from tensorflow.keras.regularizers import l1

def create_and_train_model(
    self,
    train_features,
    train_labels,
    epochs=100,
    batch_size=32
):
    self.input_shape = (train_features.shape[1],)
    self.model = Sequential([
        Dense(
            64,
            activation='relu',
            kernel_regularizer=l1(0.01),
            input_shape=self.input_shape
        ),
        Dense(
            32,
            activation='relu',
            kernel_regularizer=l1(0.01)
        ),
        Dense(
            16,
            activation='relu',
            kernel_regularizer=l1(0.01)
        ),
        Dense(1)
    ])
    self.model.compile(optimizer='adam', loss='mse')
    history = self.model.fit(
        train_features,
        train_labels,
        epochs=epochs,
        batch_size=batch_size,
        verbose=0
    )
    return history

內容解密:

  1. 匯入 L1 正則化模組from tensorflow.keras.regularizers import l1 用於匯入 L1 正則化的函式。
  2. 設定 L1 正則化:在每個 Dense 層中使用 kernel_regularizer=l1(0.01),表示對該層的權重應用 L1 正則化,強度為 0.01。
  3. 模型編譯與訓練:使用 Adam 最佳化器和均方誤差(MSE)作為損失函式進行編譯,並進行模型訓練。

L2 正則化的實作

L2 正則化透過在損失函式中新增權重的平方和,來控制模型的複雜度。以下是如何在 TensorFlow 中實作 L2 正則化的範例:

from tensorflow.keras.regularizers import l2

def create_and_train_model(
    self,
    train_features,
    train_labels,
    epochs=100,
    batch_size=32
):
    self.input_shape = (train_features.shape[1],)
    self.model = Sequential([
        Dense(
            64,
            activation='relu',
            kernel_regularizer=l2(0.01),
            input_shape=self.input_shape
        ),
        Dense(
            32,
            activation='relu',
            kernel_regularizer=l2(0.01)
        ),
        Dense(
            16,
            activation='relu',
            kernel_regularizer=l2(0.01)
        ),
        Dense(1)
    ])
    self.model.compile(optimizer='adam', loss='mse')
    history = self.model.fit(
        train_features,
        train_labels,
        epochs=epochs,
        batch_size=batch_size,
        verbose=0
    )
    return history

內容解密:

  1. 匯入 L2 正則化模組from tensorflow.keras.regularizers import l2 用於匯入 L2 正則化的函式。
  2. 設定 L2 正則化:在每個 Dense 層中使用 kernel_regularizer=l2(0.01),表示對該層的權重應用 L2 正則化,強度為 0.01。
  3. 模型編譯與訓練:同樣使用 Adam 最佳化器和 MSE 損失函式進行編譯和訓練。

調整學習率

學習率是深度學習模型訓練中的一個關鍵超引數,它決定了每次迭代中向損失函式最小值移動的步長。適當的學習率可以顯著影響模型的效能和收斂速度。以下是如何在 TensorFlow 中調整學習率的範例:

from tensorflow.keras.optimizers import Adam

def create_and_train_model(
    self,
    train_features,
    train_labels,
    epochs=100,
    batch_size=32,
    learning_rate=0.001
):
    # ...
    self.model.compile(optimizer=Adam(learning_rate=learning_rate), loss='mse')
    # ...

內容解密:

  1. 匯入 Adam 最佳化器from tensorflow.keras.optimizers import Adam 用於匯入 Adam 最佳化器。
  2. 設定自定義學習率:在編譯模型時,使用 Adam(learning_rate=learning_rate) 設定自定義的學習率。
  3. 模型編譯與訓練:透過調整 learning_rate 引數來最佳化模型的訓練過程。

調整學習率與模型容量以提升模型效能

在深度學習模型的訓練過程中,學習率(Learning Rate)與模型容量(Model Capacity)是兩個至關重要的引數,它們直接影響模型的收斂速度、訓練穩定性以及最終的預測效能。本章節將探討如何透過調整這兩個關鍵引數來最佳化模型的表現。

學習率的調整

學習率決定了模型引數在每次更新時的步長。適當的學習率能夠加速模型的收斂並提升其預測能力。以下程式碼展示瞭如何在模型訓練過程中加入可自定義的學習率引數:

def create_and_train_model(
    self,
    train_features,
    train_labels,
    epochs=100,
    batch_size=32,
    learning_rate=0.001
):
    self.input_shape = (train_features.shape[1],)
    self.model = Sequential([
        Dense(
            64,
            activation='relu',
            input_shape=self.input_shape
        ),
        Dense(
            32,
            activation='relu'
        ),
        Dense(
            16,
            activation='relu'
        ),
        Dense(1)
    ])
    optimizer = Adam(learning_rate=learning_rate)
    self.model.compile(optimizer=optimizer, loss='mse')
    history = self.model.fit(
        train_features,
        train_labels,
        epochs=epochs,
        batch_size=batch_size,
        verbose=0
    )
    return history

內容解密:

  1. 學習率引數的引入:在方法簽名中新增了learning_rate引數,並設定預設值為0.001,以便在呼叫方法時能夠指定不同的學習率。
  2. 最佳化器的調整:使用Adam(learning_rate=learning_rate)來初始化最佳化器,使學習率變得可自定義。
  3. 模型編譯:在self.model.compile中使用自定義的最佳化器。

透過調整學習率,我們觀察到不同的訓練結果:

  • 當學習率設為0.01時,測試損失(Test Loss)為16.9786,R2分數(R2 Score)為0.9986,表現良好。
  • 當學習率設為0.0001時,測試損失明顯增加至1056.1927,但R2分數仍保持在0.9111,顯示出較慢的收斂速度。

模型容量的調整

模型容量決定了神經網路學習和表示複雜資料模式的能力。適當的模型容量能夠避免欠擬合(Underfitting)和過擬合(Overfitting)。以下展示瞭如何透過調整隱藏層的神經元數量來修改模型容量:

def create_and_train_model(
    self,
    train_features,
    train_labels,
    epochs=100,
    batch_size=32
):
    self.input_shape = (train_features.shape[1],)
    self.model = Sequential([
        Dense(
            128,
            activation='relu',
            input_shape=self.input_shape
        ),
        Dense(
            64,
            activation='relu'
        ),
        Dense(
            32,
            activation='relu'
        ),
        Dense(1)
    ])
    self.model.compile(optimizer='adam', loss='mse')
    history = self.model.fit(
        train_features,
        train_labels,
        epochs=epochs,
        batch_size=batch_size,
        verbose=0
    )
    return history

內容解密:

  1. 隱藏層神經元數量的調整:將第一、二、三隱藏層的神經元數量分別增加至128、64和32,以提升模型容量。
  2. 模型編譯與訓練:使用adam最佳化器和mse損失函式進行編譯,並進行訓練。

實驗結果顯示:

  • 當模型容量增加至128、64和32時,測試損失降至10.7748,R2分數提升至0.9991。
  • 當採用中等容量(96、48、24)時,測試損失為11.3233,R2分數為0.9990。

調整模型架構以提升效能

在前面的章節中,我們探討瞭如何透過改變神經網路的層數和每層的神經元數量來提升模型的表現。實驗結果顯示,無論是增加模型的深度還是寬度,都能有效改善模型的效能。

模型容量對效能的影響

首先,我們測試了不同容量的模型對效能的影響。我們建立了一個基線模型,並逐步增加其容量,觀察其在測試資料集上的表現。

基線模型

基線模型的架構如下:

self.model = Sequential([
    Dense(64, activation='relu', input_shape=self.input_shape),
    Dense(32, activation='relu'),
    Dense(16, activation='relu'),
    Dense(1)
])

內容解密:

  1. 輸入層形狀input_shape=self.input_shape 確保模型能夠接受正確形狀的輸入資料。
  2. 隱藏層:使用了三個隱藏層,分別具有 64、32 和 16 個神經元,皆採用 ReLU 作為啟用函式。
  3. 輸出層:最後一層只有一個神經元,用於輸出預測值。

測試結果顯示,基線模型的測試損失為 15.5924,R2 分數為 0.9987。

高容量模型

接著,我們增加模型的容量,修改後的模型架構如下:

self.model = Sequential([
    Dense(128, activation='relu', input_shape=self.input_shape),
    Dense(64, activation='relu'),
    Dense(32, activation='relu'),
    Dense(1)
])

內容解密:

  1. 增加神經元數量:第一個隱藏層的神經元數量增加到 128,有助於模型學習更複雜的模式。
  2. 保持逐層遞減:後續層的神經元數量逐漸減少,有助於模型提取更高層次的特徵。

高容量模型的測試損失降至 10.77,R2 分數提升至 0.9991,明顯優於基線模型。

改變模型架構:寬模型與深模型

除了改變模型的容量,我們還測試了不同架構的模型,包括寬模型和深模型,以比較它們對效能的影響。

寬模型

寬模型的架構如下:

self.model = Sequential([
    Dense(128, activation='relu', input_shape=self.input_shape),
    Dense(128, activation='relu'),
    Dense(1)
])

內容解密:

  1. 更寬的層:兩個隱藏層均包含 128 個神經元,使模型能夠學習更廣泛的特徵表示。
  2. 減少層數:僅有兩層隱藏層,減少了模型的深度。

寬模型的測試損失為 12.7816,R2 分數為 0.9989,表現優於基線模型但遜於深模型。

深模型

深模型的架構如下:

self.model = Sequential([
    Dense(64, activation='relu', input_shape=self.input_shape),
    Dense(64, activation='relu'),
    Dense(32, activation='relu'),
    Dense(16, activation='relu'),
    Dense(8, activation='relu'),
    Dense(1)
])

內容解密:

  1. 增加深度:模型具有五個隱藏層,每層的神經元數量逐漸減少,有助於捕捉更複雜的資料模式。
  2. 逐層遞減的神經元:從 64 個神經元逐漸減少到 8 個,有助於模型在不同層次上學習特徵。

深模型的測試損失為 10.2026,R2 分數為 0.9991,是所有測試模型中表現最好的。

自動化超引數最佳化

在前面的實驗中,我們手動調整了模型的超引數,如層數和神經元數量。雖然這種方法在某些情況下能夠獲得不錯的結果,但它非常耗時且容易陷入區域性最優。隨著模型變得越來越複雜,我們需要一種系統化、自動化的方法來進行超引數調優。

Keras Tuner 簡介

Keras Tuner 是一個專為深度學習設計的超引數最佳化工具,它能夠與 Keras 無縫整合,大大簡化了超引數調優的過程。透過自動化搜尋最佳超引陣列合,Keras Tuner 不僅節省了時間,還能提升模型的效能。

首先,我們需要匯入必要的函式庫:

from keras_tuner import HyperModel, RandomSearch

內容解密:

  1. HyperModel:Keras Tuner 中的基礎類別,用於定義可調優的超引數模型。
  2. RandomSearch:一種隨機搜尋策略,用於在指定的超引數空間中進行隨機抽樣搜尋。

使用 Keras Tuner,我們可以輕鬆地最佳化神經網路中的學習率、每層的神經元數量等超引數,從而獲得更好的模型效能。具體實作將在後續章節中詳細介紹。