深度學習模型的訓練過程中,常會遇到過擬合問題,導致模型泛化能力下降。本文以 CIFAR-10 影像分類別任務為例,探討如何利用卷積神經網路(CNN)建構模型,並透過增加模型深度、加入 Dropout 和批次正規化等技術來提升模型效能。首先,我們嘗試增加捲積層數,並使用 padding='same' 解決了因維度縮減而產生的錯誤。接著,引入 Dropout 技術,分別在卷積層和全連線層設定不同的丟棄率,有效降低過擬合風險。最後,我們加入批次正規化層,提升模型訓練穩定性並加速收斂,並分析了不同最佳化器對模型效能的影響,實驗結果顯示,適當的正則化技術和最佳化器選擇能有效提升模型在 CIFAR-10 資料集上的分類別準確度。
使用 ChatGPT 建構 CIFAR-10 的 CNN 模型
深度擴充套件模型架構
在初始模型基礎上,我們嘗試增加兩層具有 128 個濾波器的卷積層,以增強模型的深度學習能力。然而,在執行程式碼時,系統回報了一個 ValueError 錯誤。為瞭解決這個問題,我們採用了提示策略(prompting strategy),將錯誤訊息回饋給 ChatGPT 並請求其協助修正。
錯誤訊息解析
錯誤訊息如下:
ValueError: Exception encountered when calling layer "conv2d_38" (type Conv2D).
Negative dimension size caused by subtracting 3 from 2 for '{{node conv2d_38/Conv2D}} = Conv2D[T=DT_FLOAT, data_format="NHWC", dilations=[1, 1, 1, 1], explicit_paddings=[], padding="VALID", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](Placeholder, conv2d_38/Conv2D/ReadVariableOp)' with input shapes: [?,2,2,64], [3,3,64,128].
程式碼修正與解說
ChatGPT 根據錯誤訊息提供了修正後的程式碼:
# 定義修改後的模型,增加兩層具有 128 個濾波器的卷積層
modified_model_64_to_128 = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
Conv2D(128, (3, 3), activation='relu', padding='same'), # 新增 padding='same'
Conv2D(128, (3, 3), activation='relu', padding='same'), # 新增 padding='same'
MaxPooling2D((2, 2)),
Flatten(),
Dense(64, activation='relu'),
Dense(10, activation='softmax')
])
# 編譯模型
modified_model_64_to_128.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 顯示模型摘要資訊
modified_model_64_to_128.summary()
# 訓練模型
history_64_to_128 = modified_model_64_to_128.fit(x_train_resized, y_train,
epochs=10,
batch_size=32,
validation_data=(x_test_resized, y_test))
# 評估模型效能
test_loss_64_to_128, test_accuracy_64_to_128 = modified_model_64_to_128.evaluate(x_test_resized, y_test, verbose=0)
print("測試損失(修改後的模型,含 64 到 128 個濾波器):", test_loss_64_to_128)
print("測試準確率(修改後的模型,含 64 到 128 個濾波器):", test_accuracy_64_to_128)
內容解密:
- 錯誤原因:原始程式碼在新增具有 128 個濾波器的卷積層時,未考慮到前一層 MaxPooling 後的維度縮減,導致卷積運算時出現負維度錯誤。
- 解決方案:在新增的卷積層中加入
padding='same',確保輸入資料的維度與卷積核相容,避免維度縮減過多。 - 模型訓練結果:修改後的模型成功訓練,但準確率下降至 69%,顯示增加層數未必能提升模型效能。
加入 Dropout 正則化
在實驗增加層數後,我們進一步嘗試加入 Dropout 正則化技術,以防止模型過擬合。我們向 ChatGPT 請求在先前的程式碼基礎上加入 Dropout 層。
程式碼實作與解說
ChatGPT 回應如下,並提供加入 Dropout 的程式碼:
from tensorflow.keras.layers import Dropout
# 定義加入 Dropout 正則化的模型
modified_model_64_to_128_with_dropout = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
Conv2D(128, (3, 3), activation='relu', padding='same'),
Dropout(0.25), # 新增 Dropout 正則化,丟棄率為 25%
Conv2D(128, (3, 3), activation='relu', padding='same'),
Dropout(0.25), # 新增 Dropout 正則化,丟棄率為 25%
MaxPooling2D((2, 2)),
Flatten(),
Dense(64, activation='relu'),
Dropout(0.5), # 新增 Dropout 正則化,丟棄率為 50%
Dense(10, activation='softmax')
])
# 編譯加入 Dropout 的模型
modified_model_64_to_128_with_dropout.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
內容解密:
- Dropout 的作用:在訓練過程中隨機丟棄部分神經元,以減少模型的過擬合風險。
- Dropout 率的選擇:本例中,我們在卷積層後使用 25% 的丟棄率,在全連線層前使用 50% 的丟棄率,以平衡模型的複雜度與泛化能力。
使用 ChatGPT 建構 CIFAR-10 的 CNN 模型:正則化技術的應用
在深度學習模型的訓練過程中,過擬合(Overfitting)是一個常見的問題。為了提升模型的泛化能力,我們可以採用不同的正則化技術,例如丟棄法(Dropout)和批次正規化(Batch Normalization)。本章節將探討如何使用 ChatGPT 來實作這些技術,以最佳化 CIFAR-10 資料集上的卷積神經網路(CNN)模型。
套用丟棄法(Dropout)提升模型泛化能力
丟棄法是一種透過在訓練過程中隨機丟棄神經元來防止過擬合的技術。我們將在現有的 CNN 模型中加入丟棄層,以觀察其對模型效能的影響。
程式碼實作
from tensorflow.keras.layers import Dropout
# 定義帶有丟棄法的修改模型
modified_model_64_to_128_with_dropout = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
Conv2D(128, (3, 3), activation='relu', padding='same'),
Dropout(0.25), # 第一層丟棄法,丟棄率為 25%
MaxPooling2D((2, 2)),
Conv2D(128, (3, 3), activation='relu', padding='same'),
Dropout(0.5), # 第二層丟棄法,丟棄率為 50%
MaxPooling2D((2, 2)),
Flatten(),
Dense(64, activation='relu'),
Dense(10, activation='softmax')
])
# 編譯模型
modified_model_64_to_128_with_dropout.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 顯示模型摘要
modified_model_64_to_128_with_dropout.summary()
# 使用丟棄法訓練修改後的模型
history_64_to_128_with_dropout = modified_model_64_to_128_with_dropout.fit(x_train_resized, y_train,
epochs=10,
batch_size=32,
validation_data=(x_test_resized, y_test))
# 評估帶有丟棄法的修改模型在測試資料集上的效能
test_loss_64_to_128_with_dropout, test_accuracy_64_to_128_with_dropout = modified_model_64_to_128_with_dropout.evaluate(x_test_resized, y_test,
verbose=0)
print("測試損失(帶有丟棄法的修改模型):", test_loss_64_to_128_with_dropout)
print("測試準確度(帶有丟棄法的修改模型):", test_accuracy_64_to_128_with_dropout)
程式碼解析
- 新增丟棄層:在卷積層後新增
Dropout層,第一層的丟棄率設為 25%,第二層設為 50%。這些引數可以根據實驗結果進行調整,以達到最佳的正則化效果。 - 編譯與訓練:使用相同的最佳化器和損失函式編譯模型,並進行訓練。
- 評估效能:在測試資料集上評估模型的損失和準確度。
結果分析
透過比較加入丟棄法前後的模型效能,我們可以觀察到模型的泛化能力是否有所提升。為了更直觀地理解丟棄法的效果,我們可以使用以下程式碼繪製訓練和驗證過程中的損失和準確度曲線。
import matplotlib.pyplot as plt
# 繪製訓練歷史中的損失
plt.plot(history_64_to_128_with_dropout.history['loss'], label='訓練損失')
plt.plot(history_64_to_128_with_dropout.history['val_loss'], label='驗證損失')
plt.title('訓練與驗證損失')
plt.xlabel('訓練輪次')
plt.ylabel('損失')
plt.legend()
plt.show()
# 繪製訓練歷史中的準確度
plt.plot(history_64_to_128_with_dropout.history['accuracy'], label='訓練準確度')
plt.plot(history_64_to_128_with_dropout.history['val_accuracy'], label='驗證準確度')
plt.title('訓練與驗證準確度')
plt.xlabel('訓練輪次')
plt.ylabel('準確度')
plt.legend()
plt.show()
圖表解析
- 訓練損失 vs. 驗證損失:該圖表顯示了隨著訓練輪次的增加,訓練和驗證損失的變化趨勢。如果兩者之間存在較大差距,則表明存在過擬合。丟棄法透過防止模型過度依賴特定特徵來減少這種差距。
- 訓練準確度 vs. 驗證準確度:該圖表展示了訓練和驗證準確度的變化趨勢。丟棄法可以提高模型的泛化能力,從而改善驗證準確度。
套用批次正規化(Batch Normalization)提升模型穩定性
批次正規化是一種透過正規化每一層的神經元輸入來穩定和加速訓練過程的技術。我們將在現有的 CNN 模型中加入批次正規化層,以觀察其對模型效能的影響。
程式碼實作
from tensorflow.keras.layers import BatchNormalization
# 定義帶有批次正規化的修改模型
modified_model_64_to_128_with_batchnorm = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
BatchNormalization(), # 新增批次正規化
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
BatchNormalization(), # 新增批次正規化
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
Conv2D(128, (3, 3), activation='relu', padding='same'),
BatchNormalization(), # 新增批次正規化
MaxPooling2D((2, 2)),
Conv2D(128, (3, 3), activation='relu', padding='same'),
BatchNormalization(), # 新增批次正規化
MaxPooling2D((2, 2)),
Flatten(),
Dense(64, activation='relu'),
BatchNormalization(), # 新增批次正規化
Dense(10, activation='softmax')
])
程式碼解析
- 新增批次正規化層:在卷積層和全連線層後新增
BatchNormalization層,以穩定和加速模型的訓練過程。
透過本章節的實踐,我們學習瞭如何使用 ChatGPT 和 TensorFlow/Keras API 在 CIFAR-10 資料集上構建和最佳化 CNN 模型,並透過加入丟棄法和批次正規化來提升模型的泛化能力和穩定性。這些技術對於構建高效、穩健的深度學習模型具有重要意義。
批次正規化(Batch Normalization)技術的應用與非訓練引數解析
在深度學習模型訓練中,批次正規化是一種重要的技術,能夠提升模型的穩定性並加速收斂過程。本章節將探討如何在卷積神經網路(CNN)中加入批次正規化層,並深入解析由此引入的非訓練引數的計算方法。
加入批次正規化的CNN模型實作
首先,我們需要在原有的CNN模型架構中加入批次正規化層。以下為修改後的模型程式碼:
# 定義修改後的模型並加入批次正規化層
modified_model_64_to_128_with_batchnorm = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
BatchNormalization(), # 第一層卷積後的批次正規化
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
BatchNormalization(), # 第二層卷積後的批次正規化
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
Conv2D(128, (3, 3), activation='relu'),
BatchNormalization(), # 第三層卷積後的批次正規化
MaxPooling2D((2, 2)),
Conv2D(128, (3, 3), activation='relu'),
BatchNormalization(), # 第四層卷積後的批次正規化
MaxPooling2D((2, 2)),
Flatten(),
Dense(64, activation='relu'),
BatchNormalization(), # 全連線層後的批次正規化
Dense(10, activation='softmax')
])
# 編譯修改後的模型
modified_model_64_to_128_with_batchnorm.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 顯示模型摘要資訊
modified_model_64_to_128_with_batchnorm.summary()
# 訓練模型
history_64_to_128_with_batchnorm = modified_model_64_to_128_with_batchnorm.fit(
x_train_resized, y_train,
epochs=10,
batch_size=32,
validation_data=(x_test_resized, y_test)
)
# 評估模型在測試資料集上的表現
test_loss_64_to_128_with_batchnorm, test_accuracy_64_to_128_with_batchnorm = \
modified_model_64_to_128_with_batchnorm.evaluate(x_test_resized, y_test, verbose=0)
print("測試損失(加入批次正規化的模型):", test_loss_64_to_128_with_batchnorm)
print("測試準確度(加入批次正規化的模型):", test_accuracy_64_to_128_with_batchnorm)
程式碼解析:
- 在每個卷積層後加入
BatchNormalization()層,以正規化該層的輸出。 - 編譯模型時使用Adam最佳化器和稀疏分類別交叉熵損失函式。
- 訓練模型並評估其在測試資料集上的表現。
非訓練引數的計算
從模型摘要資訊中,我們可以看到有832個非訓練引數。這些引數來自於批次正規化層的移動平均值和移動變異數。
詳細計算過程如下:
第一個批次正規化層(32個通道):
- 移動平均值:32
- 移動變異數:32
- 總計:32 + 32 = 64
第二個批次正規化層(64個通道):
- 移動平均值:64
- 移動變異數:64
- 總計:64 + 64 = 128
第三個批次正規化層(128個通道):
- 移動平均值:128
- 移動變異數:128
- 總計:128 + 128 = 256
第四個批次正規化層(128個通道):
- 移動平均值:128
- 移動變異數:128
- 總計:128 + 128 = 256
第五個批次正規化層(64個通道):
- 移動平均值:64
- 移動變異數:64
- 總計:64 + 64 = 128
將上述所有批次正規化層的非訓練引數加總:64 + 128 + 256 + 256 + 128 = 832。
不同最佳化器的比較
為了進一步提升模型效能,我們可以嘗試使用不同的最佳化器,如SGD、Adam和RMSProp。以下為相關程式碼和比較結果:
# 定義不同的最佳化器
optimizers = {
'SGD': SGD(),
'Adam': Adam(),
'RMSProp': RMSprop()
}
# 分別使用不同的最佳化器編譯和訓練模型
for name, optimizer in optimizers.items():
model = Sequential([...]) # 定義模型架構
model.compile(optimizer=optimizer,
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train_resized, y_train,
epochs=10,
batch_size=32,
validation_data=(x_test_resized, y_test))
# 評估模型在測試資料集上的表現
test_loss, test_accuracy = model.evaluate(x_test_resized, y_test, verbose=0)
print(f"最佳化器:{name}, 測試準確度:{test_accuracy}")
程式碼解析:
- 定義多個最佳化器,包括SGD、Adam和RMSProp。
- 分別使用這些最佳化器編譯和訓練模型。
- 評估每個模型在測試資料集上的表現,並比較其準確度。
綜上所述,批次正規化技術能夠提升模型的穩定性和效能,而選擇適當的最佳化器對於模型的收斂速度和最終效能也至關重要。透過實驗不同的組態,我們可以找到最適合特定任務的模型架構和訓練策略。