Skip to content

優化總覽——SGD、Adam、學習率排程與縮放規則|MIT 6.7960 主題單元

2026年8月30日1 分鐘
TL;DR從 SGD 到 Adam,用縮放規則一次搞懂深度學習優化器怎麼選、學習率怎麼調

🌏 English version

影片狀態:僅附相關補充影片;原講次錄影未確認。 影片來源與說明

MIT 6.7960 Fall 2024 OCW 這篇主題單元整理的是「優化」這個主題,OCW 沒有對應的單一講次,相關影片分散在兩講:Lec 02 How to Train a Neural Net(Sara Beery 主講:SGD、動量、反向傳播)與 Lec 07 Scaling Rules for Optimization(Jeremy Bernstein 主講:用最陡下降與範數推導學習率為什麼隨網路寬度漂移,以及怎麼讓最佳學習率與寬度無關)。本文其餘內容(Adam/AdamW、學習率排程、批次大小的縮放規則、決策樹)是本站依一般文獻整理的補充,不是這兩支影片的逐段摘要。

優化器的譜系:從 SGD 到 Adam

深度學習優化器演進的主線是:怎麼在高維非凸地形裡,用最少的超參數調整,穩定收斂到好解。

優化器核心思想適用情境缺點
SGD純梯度下降,可加動量小模型、凸問題、要理論保證時深層網路收斂慢、需精心調 LR
SGD + Momentum累積歷史梯度方向,穿越鞍點影像分類、ResNet 類架構仍需手調 LR、對 ill-conditioned 敏感
Adam一階動量 + 二階自適應學習率NLP、Transformer、快速原型大批次易發散、weight decay 需分離
AdamWAdam + 解耦 weight decay現代 LLM/ViT 訓練預設同 Adam,但正則化更正確
Lion / Sophia符號梯度 / 二階近似大模型預訓練嘗試生態較新、超參數敏感

關鍵洞見:優化器選擇不如「縮放規則」重要(這是本文的整理判斷,不是 Lec 07 的原話;Lec 07 談的是最佳學習率如何隨寬度與深度漂移)——同樣的優化器,學習率、批次大小、權重衰減若不按規則縮放,大模型照樣訓不動。

縮放規則:大批次怎麼調學習率

常見的經驗法則(Linear Scaling Rule,來自一般文獻;Lec 02、Lec 07 的字幕都沒有講批次大小的縮放):

lr_new = lr_base × (batch_size_new / batch_size_base)

前提條件:

  • 使用 SGD + Momentum 或 AdamW(自適應優化器近似成立)
  • 學習率在「穩定區間」內(太大會發散、太小收斂慢)
  • Warmup 步數同比例增長:warmup_steps_new = warmup_base × (batch_size_new / batch_size_base)

為什麼有效:大批次梯度方差下降 ∝ 1/√B,信噪比提升,可以承受更大步長。但超過「critical batch size」後,收益遞減甚至發散。

實務上對 Transformer 採用 sqrt scaling(學習率 ∝ √B)更穩健,見 Kaplan et al. 2020 與 Chinchilla 的實驗。

學習率排程:Warmup → Cosine → Decay

現代標準排程(Warmup + Cosine Annealing):

import torch
from torch.optim.lr_scheduler import LambdaLR, CosineAnnealingLR, SequentialLR

def get_lr_scheduler(optimizer, warmup_steps, total_steps, min_lr_ratio=0.1):
    """Warmup + Cosine decay,回傳可直接 step() 的 scheduler"""
    def warmup_lambda(step):
        return min(1.0, step / warmup_steps)
    
    warmup_scheduler = LambdaLR(optimizer, warmup_lambda)
    cosine_scheduler = CosineAnnealingLR(
        optimizer, 
        T_max=total_steps - warmup_steps,
        eta_min=optimizer.param_groups[0]['lr'] * min_lr_ratio
    )
    return SequentialLR(optimizer, [warmup_scheduler, cosine_scheduler], [warmup_steps])

# 使用範例
model = torch.nn.Linear(512, 10)
optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.1)
scheduler = get_lr_scheduler(optimizer, warmup_steps=2000, total_steps=100_000)

for step in range(100_000):
    loss = model(torch.randn(32, 512)).sum()
    loss.backward()
    optimizer.step()
    scheduler.step()
    optimizer.zero_grad()

相關影片的主題順序(依字幕各主題出現的相對位置估算,不是精確時間碼;兩支影片都約 1 小時 20 分):

  • Lec 02:約前 25% 是梯度下降、學習率與動量(Adam 只在約 14% 處被簡短帶過);約 40%–70% 是反向傳播與鏈式法則;後段是把不可微的模組、資料預處理接進訓練。
  • Lec 07:約 20%–35% 是二階展開與 Newton/Gauss-Newton;約 35%–60% 是最陡下降(steepest descent)與範數;約 64%–76% 是譜範數與 RMS 範數;約 77%–98% 是初始化與寬度、深度縮放,目標是讓最佳學習率與寬度無關。
  • 兩支影片的字幕都沒有出現:AdamW 的 weight decay 解耦、warmup/cosine 等學習率排程、critical batch size、批次大小的縮放規則。

實戰決策樹:新專案怎麼選優化器與超參數

START: 新模型、新資料集
│
├─ 是不是 Transformer / LLM / ViT 大模型?
│   ├─ 是 → AdamW (lr=3e-4, wd=0.1, β=(0.9,0.95)) + Warmup+Cosine
│   └─ 否 → 是 CNN (ResNet/EfficientNet)?
│       ├─ 是 → SGD + Momentum (lr=0.1, momentum=0.9, wd=1e-4) + Cosine
│       └─ 否 → 先試 AdamW (lr=1e-3, wd=0.01),觀察 loss curve
│
├─ 批次大小要放大?
│   ├─ 是 → 線性縮放 lr、同比例增 warmup、監控 gradient norm
│   └─ 否 → 維持 base config
│
└─ 觀察訓練前 1000 steps:
    ├─ Loss 爆炸 → lr 除 10、加 gradient clipping (1.0)
    ├─ Loss 震盪不下降 → lr 除 3、延長 warmup
    └─ Loss 平滑下降 → 繼續跑、記錄 best checkpoint

PyTorch 完整可跑範例:優化器對比實驗

"""優化器對比:SGD vs AdamW 在 MLP 上的收斂行為"""
import torch
import torch.nn as nn
import matplotlib.pyplot as plt

class MLP(nn.Module):
    def __init__(self, dim=256, depth=4):
        super().__init__()
        layers = []
        for _ in range(depth):
            layers += [nn.Linear(dim, dim), nn.ReLU()]
        layers.append(nn.Linear(dim, 10))
        self.net = nn.Sequential(*layers)
    
    def forward(self, x):
        return self.net(x)

def train_one_epoch(model, opt, scheduler, loader, device):
    model.train()
    total_loss = 0
    for x, y in loader:
        x, y = x.to(device), y.to(device)
        opt.zero_grad()
        loss = nn.functional.cross_entropy(model(x), y)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        opt.step()
        if scheduler:
            scheduler.step()
        total_loss += loss.item()
    return total_loss / len(loader)

# 合成資料
torch.manual_seed(42)
train_data = torch.utils.data.TensorDataset(
    torch.randn(5000, 256), torch.randint(0, 10, (5000,))
)
loader = torch.utils.data.DataLoader(train_data, batch_size=128, shuffle=True)
device = 'cuda' if torch.cuda.is_available() else 'cpu'

# 三組優化器設定
configs = {
    'SGD+Momentum': dict(lr=0.1, momentum=0.9, weight_decay=1e-4, opt_fn=torch.optim.SGD),
    'Adam': dict(lr=3e-4, betas=(0.9, 0.999), weight_decay=0.1, opt_fn=torch.optim.Adam),
    'AdamW': dict(lr=3e-4, betas=(0.9, 0.95), weight_decay=0.1, opt_fn=torch.optim.AdamW),
}

results = {}
for name, cfg in configs.items():
    opt_fn = cfg.pop('opt_fn')
    model = MLP().to(device)
    opt = opt_fn(model.parameters(), **cfg)
    scheduler = get_lr_scheduler(opt, warmup_steps=50, total_steps=500)
    
    losses = []
    for epoch in range(20):
        loss = train_one_epoch(model, opt, scheduler, loader, device)
        losses.append(loss)
    results[name] = losses
    print(f"{name}: final loss = {losses[-1]:.4f}")

# 繪圖
plt.figure(figsize=(8, 5))
for name, losses in results.items():
    plt.plot(losses, label=name, marker='o')
plt.yscale('log')
plt.xlabel('Epoch')
plt.ylabel('Loss (log scale)')
plt.title('Optimizer Comparison on Synthetic MLP Task')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('optimizer_comparison.png', dpi=150)
print("Saved plot to optimizer_comparison.png")

常見坑與避雷指南

症狀可能原因修正
Loss 前幾步就變 NaNlr 太大、無 gradient clippinglr ÷ 10、加 clip_grad_norm_(1.0)
驗證 loss 不降、訓練 loss 降過擬合、weight decay 太小調大 wd、加 dropout、早停
大批次訓練不收斂Linear scaling 失效改 sqrt scaling、延長 warmup、檢查 batch norm 統計量
AdamW 權重衰減無效用了 weight_decay 參數但優化器是 Adam改用 torch.optim.AdamW(解耦)

課程影片來源

2026-10-10 已即時回 MIT OCW Fall 2024 官方錄影列表核對:本文是主題單元,不對應單一講次(早期曾標為 L03,但 OCW 的 Lec 03 其實是 Approximation Theory),且 OCW 沒有一講專門講 Adam 與學習率排程。下方兩支是相關講次:Lec 02 How to Train a Neural Net(SGD、反向傳播、自動微分)與 Lec 07 Scaling Rules for Optimization(優化縮放規則)。它們是主題補充,不能證明本文全部內容來自這兩講。

YouTube:MIT 6.7960 Fall 2024 — Lec 02. How to Train a Neural Net
YouTube:MIT 6.7960 Fall 2024 — Lec 07. Scaling Rules for Optimization

原始影片:MIT 6.7960 Fall 2024 — Lec 02. How to Train a Neural Net、MIT 6.7960 Fall 2024 — Lec 07. Scaling Rules for Optimization

課程與錄影入口:

查核日期:2026-10-10。

編號說明:本站 L03–L06 這四篇的編號,是本站早期依一般深度學習教學順序(優化、正則化、CNN、現代 CNN)自行規劃的,沒有逐一對照 OCW 講次表;OCW Fall 2024 的 Lec 03–06 實際是 Approximation Theory、Architectures: Grids、Architectures: Graphs、Generalization Theory,所以這四篇的 L 編號與 OCW 講次不同。2026-10-13 起標題改依 OCW 講次:CNN 架構篇對應 Lec 04,標為第 4 堂;優化、正則化、現代 CNN 三篇沒有對應的單一講次,改標主題單元。網址維持不變,所以現代 CNN 篇的網址仍帶 l06;從 Lec 07 起各篇本來就與 OCW 講次一致。

內容核對:已依字幕核對(2026-10-10):讀了 Lec 02(Sara Beery)與 Lec 07(Jeremy Bernstein)兩支字幕;兩支影片都不含 AdamW、學習率排程、批次大小縮放規則,原「影片時間戳」章節與「講義推導 Linear Scaling Rule」的說法不成立,已改寫為相對位置的主題順序並標明為本站補充,另更正參考資料中 Lec 07 的 YouTube ID(原誤寫成 Lec 08 的 Q1HOKrNeh2M)。

更新紀錄

  • 2026-10-10:標註影片狀態,核對錄影來源與取得方式。
  • 2026-10-10:重查影片狀態。OCW 沒有對應「優化總覽」的單一講次,改附 Lec 02 與 Lec 07 兩支相關補充影片,狀態改為「僅附相關補充影片;原講次錄影未確認」。
  • 2026-10-10:依字幕核對影片內容。原「影片時間戳」章節對不上 Lec 07 字幕(沒有 Adam/AdamW/排程/critical batch size),已改為依字幕相對位置的主題順序,並更正參考資料的影片 ID 與講者歸屬說法。

參考資料