什麼是優化器?¶
在深度學習中,優化器就像一位“智能嚮導”,幫助模型從大量參數中找到讓損失函數(比如模型預測與真實標籤的差距)最小化的方向。想象你在爬山,想從山頂(高損失)走到山谷(低損失),優化器就是決定你每一步往哪走、走多遠的“導航系統”。它的核心任務是更新模型參數,讓模型在訓練數據上的表現越來越好。
爲什麼需要不同的優化器?¶
不同的優化器針對不同的問題設計,各有優缺點:
- SGD(隨機梯度下降):最基礎的優化器,每次用一個樣本的梯度更新參數。
- 優點:簡單、內存佔用小。
- 缺點:收斂慢,對學習率敏感(學習率太大易震盪,太小收斂慢)。
-
改進:加入“動量”(Momentum)可加速收斂,類似物理中的“慣性”,讓參數更新更平滑。
-
Adam(自適應矩估計):目前最流行的優化器,結合了動量和自適應學習率。
- 優點:默認參數表現好,收斂快,對學習率不敏感,適合大多數場景。
-
特點:會根據參數的歷史梯度自動調整學習率,讓不同參數有不同的更新速度。
-
AdamW:Adam的改進版,加入了權重衰減(L2正則化),能有效防止過擬合。
PyTorch中的優化器概覽¶
PyTorch的torch.optim模塊提供了多種優化器,以下是初學者最常用的幾種:
| 優化器 | 核心特點 | 適用場景 |
|---|---|---|
| SGD | 基礎隨機梯度下降,需手動調學習率和動量 | 簡單模型、需要嚴格控制參數時 |
| SGD+Momentum | 加入動量,加速收斂,減少震盪 | 訓練波動大的模型(如RNN) |
| Adam | 自適應學習率+動量,默認參數效果優異 | 大多數深度學習任務(CNN、Transformer等) |
| AdamW | Adam+權重衰減,避免過擬合 | 數據量小或模型複雜時 |
實戰:用PyTorch實現優化器對比¶
下面我們用一個簡單的線性迴歸模型,對比SGD和Adam的優化效果。目標是讓模型學習到y = 2x + 3的線性關係(加入噪聲模擬真實數據)。
步驟1:準備數據¶
生成帶噪聲的線性數據:
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
# 設置隨機種子,保證結果可復現
torch.manual_seed(42)
# 生成100個樣本,每個樣本1個特徵,標籤爲 y = 2x + 3 + 噪聲
x = torch.randn(100, 1) * 10 # 輸入特徵
y = 2 * x + 3 + torch.randn(100, 1) * 1.5 # 真實關係+噪聲
步驟2:定義模型¶
用PyTorch的nn.Module定義簡單線性模型:
class LinearRegression(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(in_features=1, out_features=1) # 輸入1維,輸出1維
# 初始化兩個模型,分別用SGD和Adam優化
model_sgd = LinearRegression()
model_adam = LinearRegression()
步驟3:定義損失函數和優化器¶
損失函數用均方誤差(MSE),優化器分別用SGD和Adam:
# 損失函數:均方誤差
criterion = nn.MSELoss()
# SGD優化器:學習率設爲0.01,需手動控制學習率
optimizer_sgd = optim.SGD(model_sgd.parameters(), lr=0.01)
# Adam優化器:默認參數,無需手動調參
optimizer_adam = optim.Adam(model_adam.parameters(), lr=0.01)
步驟4:訓練模型¶
訓練循環:前向傳播→計算損失→反向傳播→更新參數
def train(optimizer, model, x, y, epochs=1000):
losses = []
for epoch in range(epochs):
# 前向傳播:模型預測
pred = model(x)
loss = criterion(pred, y)
losses.append(loss.item())
# 反向傳播+參數更新
optimizer.zero_grad() # 清空梯度(避免累積)
loss.backward() # 計算梯度
optimizer.step() # 更新參數
# 每100輪打印一次損失
if (epoch + 1) % 100 == 0:
print(f'Epoch {epoch+1}, Loss: {loss.item():.4f}')
return losses
# 分別訓練兩個模型
losses_sgd = train(optimizer_sgd, model_sgd, x, y)
losses_adam = train(optimizer_adam, model_adam, x, y)
步驟5:對比結果¶
訓練後,我們可以通過損失曲線和最終參數觀察效果:
- 損失曲線:
plt.figure(figsize=(10, 5))
plt.plot(losses_sgd, label='SGD')
plt.plot(losses_adam, label='Adam')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve Comparison')
plt.legend()
plt.show()
(直觀感受:Adam收斂更快,損失下降更平穩;SGD可能震盪且收斂慢)
- 最終參數:
print("SGD訓練後的參數:")
print(f"權重: {model_sgd.linear.weight.item():.2f}, 偏置: {model_sgd.linear.bias.item():.2f}")
print("\nAdam訓練後的參數:")
print(f"權重: {model_adam.linear.weight.item():.2f}, 偏置: {model_adam.linear.bias.item():.2f}")
(輸出應爲接近真實值 權重≈2,偏置≈3,Adam參數更穩定)
總結與建議¶
- 初學者首選Adam:默認參數幾乎適用於所有場景,收斂快且穩定性高,不用手動調學習率。
- SGD的適用場景:若需要嚴格控制參數(如小數據集),或想嘗試動量、學習率調整等技巧。
- 關鍵技巧:訓練時若損失不下降,嘗試增大學習率(
lr=0.1)或換AdamW(防過擬合)。
通過實戰,你可以發現:優化器就像工具,沒有絕對“最好”的,只有“最適合”的。先從Adam開始,再根據任務需求嘗試其他優化器吧!