跳转至

📐 优化理论

难度:⭐⭐⭐⭐⭐ | 预计学习时间:8-10小时 | 重要性:理解训练过程的核心

🎯 学习目标

  • 掌握梯度下降及其变体(SGD/Momentum/Adam)的数学推导
  • 理解凸优化与非凸优化的区别
  • 掌握学习率调度策略
  • 了解约束优化(拉格朗日/KKT条件)在SVM等模型中的应用

1. 梯度下降基础

1.1 梯度与方向导数

梯度 \(\nabla f(x)\) 指向函数增长最快方向。负梯度方向是局部下降最快方向。

\[x_{t+1} = x_t - \eta \nabla f(x_t)\]
Python
import numpy as np
import matplotlib.pyplot as plt

def gradient_descent_2d(f, grad_f, x0, lr=0.1, n_iters=50):
    """2D梯度下降可视化"""
    path = [x0.copy()]
    x = x0.copy()
    for _ in range(n_iters):
        g = grad_f(x)
        x = x - lr * g
        path.append(x.copy())
    return np.array(path)  # np.array创建NumPy数组

# Rosenbrock函数(经典难优化函数)
def rosenbrock(x):
    return (1 - x[0])**2 + 100*(x[1] - x[0]**2)**2

def rosenbrock_grad(x):
    dx = -2*(1 - x[0]) - 400*x[0]*(x[1] - x[0]**2)
    dy = 200*(x[1] - x[0]**2)
    return np.array([dx, dy])

x0 = np.array([-1.0, 1.0])
path = gradient_descent_2d(rosenbrock, rosenbrock_grad, x0, lr=0.001, n_iters=200)
print(f"起点: {x0}, 终点: {path[-1]}, 最优: [1, 1]")

1.2 学习率的影响

学习率 效果 典型值
太大 震荡/发散
太小 收敛极慢
适中 稳定收敛 \(10^{-3} \sim 10^{-1}\)

1.3 梯度下降收敛性分析(凸函数情况)

假设: - \(f\)\(L\)-smooth 凸函数(梯度Lipschitz连续):\(\|\nabla f(x) - \nabla f(y)\| \leq L\|x - y\|\) - \(f\)\(\mu\)-强凸函数(可选,加速收敛):\(f(y) \geq f(x) + \nabla f(x)^T(y-x) + \frac{\mu}{2}\|y-x\|^2\)

收敛性证明

\(L\)-smooth 性质,对凸函数有:

\[f(x_{t+1}) \leq f(x_t) + \nabla f(x_t)^T(x_{t+1} - x_t) + \frac{L}{2}\|x_{t+1} - x_t\|^2\]

代入 \(x_{t+1} = x_t - \eta \nabla f(x_t)\)

\[f(x_{t+1}) \leq f(x_t) - \eta \|\nabla f(x_t)\|^2 + \frac{L\eta^2}{2}\|\nabla f(x_t)\|^2 = f(x_t) - \eta\left(1 - \frac{L\eta}{2}\right)\|\nabla f(x_t)\|^2\]

\(\eta = \frac{1}{L}\) 时,\(1 - \frac{L\eta}{2} = \frac{1}{2}\),故:

\[f(x_{t+1}) \leq f(x_t) - \frac{1}{2L}\|\nabla f(x_t)\|^2\]

由凸性 \(f(x^*) \geq f(x_t) + \nabla f(x_t)^T(x^* - x_t)\),结合Cauchy-Schwarz:

\[\|\nabla f(x_t)\| \geq \frac{f(x_t) - f(x^*)}{\|x_t - x^*\|}\]

收敛速率: - 一般凸函数:\(f(x_T) - f(x^*) = O(1/T)\)(次线性收敛) - 强凸函数(\(\mu > 0\)):\(f(x_T) - f(x^*) = O((1 - \mu/L)^T)\)(线性收敛)

Python
import numpy as np

def gradient_descent_convergence_demo():
    """演示梯度下降收敛性"""
    # 二次函数 f(x) = 0.5 * x^T A x - b^T x
    # 最优解 x* = A^{-1} b
    A = np.array([[2.0, 0.5], [0.5, 1.0]])  # 正定矩阵
    b = np.array([1.0, 1.0])
    x_star = np.linalg.solve(A, b)  # np.linalg线性代数运算
    f_star = 0.5 * x_star @ A @ x_star - b @ x_star

    L = np.linalg.eigvalsh(A).max()  # Lipschitz常数
    mu = np.linalg.eigvalsh(A).min()  # 强凸参数
    eta = 1.0 / L  # 最优学习率

    x = np.array([5.0, 5.0])
    errors = []

    for t in range(100):
        grad = A @ x - b
        x = x - eta * grad
        f_val = 0.5 * x @ A @ x - b @ x
        errors.append(f_val - f_star)

    print(f"L = {L:.2f}, μ = {mu:.2f}, 条件数 = {L/mu:.2f}")
    print(f"理论收敛率: O((1 - μ/L)^t) = O({1 - mu/L:.4f}^t)")
    print(f"实际收敛: f(x_10) - f* = {errors[9]:.6f}, f(x_50) - f* = {errors[49]:.10f}")

gradient_descent_convergence_demo()

2. SGD及其变体

优化器对比:SGD vs Momentum vs Adam

2.1 随机梯度下降

\[\theta_{t+1} = \theta_t - \eta \nabla_\theta L(\theta_t; x_i, y_i)\]
  • 每次只用一个/一小批样本估计梯度
  • 方差大,但能逃离局部最优
  • Mini-batch SGD 是实际标配(batch_size=32~256)

2.2 Momentum(动量法)

\[v_t = \gamma v_{t-1} + \eta \nabla L(\theta_t)$$ $$\theta_{t+1} = \theta_t - v_t\]

物理直觉:小球沿坡滚下,积累速度。\(\gamma\) 典型值 \(0.9\)

2.3 Adam(面试最常问)

结合Momentum(一阶矩估计)+ RMSProp(二阶矩估计):

\[m_t = \beta_1 m_{t-1} + (1-\beta_1)g_t \quad \text{(一阶矩,梯度均值)}$$ $$v_t = \beta_2 v_{t-1} + (1-\beta_2)g_t^2 \quad \text{(二阶矩,梯度平方的均值)}\]

偏差修正: $\(\hat{m}_t = \frac{m_t}{1-\beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1-\beta_2^t}\)$

更新规则: $\(\theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t\)$

Python
class AdamOptimizer:
    """手写Adam优化器"""

    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999, eps=1e-8):  # __init__构造方法,创建对象时自动调用
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.eps = eps
        self.m = None  # 一阶矩
        self.v = None  # 二阶矩
        self.t = 0     # 时间步

    def step(self, params, grads):
        if self.m is None:
            self.m = np.zeros_like(params)
            self.v = np.zeros_like(params)

        self.t += 1
        self.m = self.beta1 * self.m + (1 - self.beta1) * grads
        self.v = self.beta2 * self.v + (1 - self.beta2) * grads**2

        # 偏差修正
        m_hat = self.m / (1 - self.beta1**self.t)
        v_hat = self.v / (1 - self.beta2**self.t)

        params -= self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
        return params

# 对比SGD vs Momentum vs Adam
def compare_optimizers():
    """在Rosenbrock函数上对比优化器"""
    x_sgd = np.array([-1.0, 1.0])
    x_mom = np.array([-1.0, 1.0])
    x_adam = np.array([-1.0, 1.0])

    adam = AdamOptimizer(lr=0.01)
    v_mom = np.zeros(2)

    paths = {"SGD": [x_sgd.copy()], "Momentum": [x_mom.copy()], "Adam": [x_adam.copy()]}

    for _ in range(500):
        g = rosenbrock_grad(x_sgd)
        x_sgd = x_sgd - 0.0005 * g
        paths["SGD"].append(x_sgd.copy())

        g = rosenbrock_grad(x_mom)
        v_mom = 0.9 * v_mom + 0.0005 * g
        x_mom = x_mom - v_mom
        paths["Momentum"].append(x_mom.copy())

        g = rosenbrock_grad(x_adam)
        x_adam = adam.step(x_adam, g)
        paths["Adam"].append(x_adam.copy())

    for name, path in paths.items():
        p = np.array(path)
        print(f"{name:10s}: 终点=({p[-1,0]:.4f}, {p[-1,1]:.4f}), "
              f"距最优={np.linalg.norm(p[-1] - [1, 1]):.6f}")

compare_optimizers()

2.4 优化器对比

优化器 特点 推荐场景
SGD+Momentum 泛化好,需调lr CV任务(如ResNet训练)
Adam 收敛快,默认好用 NLP/Transformer/通用
AdamW Adam+权重衰减解耦 常用,常见于Transformer/LLM训练
LAMB/LARS 大batch训练 分布式训练
Lion 较新的优化器,更省内存 实验阶段

3. 学习率调度

学习率调度策略对比

3.1 常见策略

Python
import numpy as np
import matplotlib.pyplot as plt

# 模拟不同学习率策略
steps = 100
lrs = {}

# Step Decay
lr = 0.1
lrs["StepDecay"] = []
for i in range(steps):
    if i in [30, 60, 80]: lr *= 0.1
    lrs["StepDecay"].append(lr)

# Cosine Annealing
lrs["Cosine"] = [0.1 * 0.5 * (1 + np.cos(np.pi * i / steps)) for i in range(steps)]  # 列表推导式,简洁创建列表

# Warmup + Cosine (Transformer标配)
warmup = 10
lrs["Warmup+Cosine"] = []
for i in range(steps):
    if i < warmup:
        lrs["Warmup+Cosine"].append(0.1 * (i + 1) / warmup)
    else:
        progress = (i - warmup) / (steps - warmup)
        lrs["Warmup+Cosine"].append(0.1 * 0.5 * (1 + np.cos(np.pi * progress)))

# 1/sqrt(t) decay (原始Transformer)
lrs["InvSqrt"] = [0.1 * min(1/(i+1)**0.5, (i+1)*warmup**(-1.5)) for i in range(steps)]

for name, lr_list in lrs.items():
    plt.plot(lr_list, label=name)
plt.xlabel("Step"); plt.ylabel("LR"); plt.legend(); plt.title("学习率调度策略对比")
plt.show()

3.2 Warmup为什么重要?

  • 训练初期参数随机,梯度方向不稳定
  • 大学习率会导致前期loss爆炸
  • Warmup让模型先"稳住",再加速训练
  • 在大模型训练中常见 Warmup→Cosine Decay 组合

4. 凸优化与非凸优化

凸优化vs非凸优化

4.1 凸函数

\(f\) 是凸函数当且仅当:\(f(\lambda x + (1-\lambda)y) \leq \lambda f(x) + (1-\lambda)f(y)\)

等价条件:Hessian矩阵 \(H \succeq 0\)(半正定)

  • 凸优化:局部最优 = 全局最优,SVM/逻辑回归是凸
  • 非凸优化:DL都是非凸,有大量鞍点

4.2 深度学习的优化景观

Python
# 可视化:高维空间中鞍点远多于局部最小值
# Hessian特征值:n维空间,每个方向独立为正/负(概率各50%)
# 所有方向都为正(局部最小)的概率 = 0.5^n → 指数衰减!

import matplotlib.pyplot as plt

dims = np.arange(1, 101)
p_local_min = 0.5 ** dims

plt.semilogy(dims, p_local_min)
plt.xlabel("参数维度")
plt.ylabel("随机临界点是局部最小值的概率")
plt.title("高维空间中鞍点远多于局部最小值")
plt.grid(True)
plt.show()

# 这就是为什么SGD实际效果好——大多数"卡住"是鞍点,SGD噪声能逃出

5. 约束优化

拉格朗日乘子法可视化

5.1 拉格朗日乘子法

\[\min f(x) \quad \text{s.t.} \quad g_i(x) \leq 0, \; h_j(x) = 0\]

拉格朗日函数: $\(L(x, \lambda, \nu) = f(x) + \sum_i \lambda_i g_i(x) + \sum_j \nu_j h_j(x)\)$

5.2 KKT条件(SVM推导核心)

  1. 原始可行\(g_i(x^*) \leq 0\)
  2. 对偶可行\(\lambda_i \geq 0\)
  3. 互补松弛\(\lambda_i g_i(x^*) = 0\)支持向量机名字的来源!
  4. 稳定性\(\nabla_x L = 0\)

5.3 SVM对偶问题推导

原始问题\(\min_{w,b} \frac{1}{2}\|w\|^2 \quad \text{s.t.} \quad y_i(w \cdot x_i + b) \geq 1, \; \forall i\)

Step 1: 构造拉格朗日函数(引入乘子 \(\alpha_i \geq 0\)):

\[L(w, b, \alpha) = \frac{1}{2}\|w\|^2 - \sum_{i=1}^n \alpha_i [y_i(w \cdot x_i + b) - 1]\]

Step 2: 对原始变量求导并令其为0

\[\frac{\partial L}{\partial w} = w - \sum_i \alpha_i y_i x_i = 0 \quad \Rightarrow \quad w = \sum_i \alpha_i y_i x_i\]
\[\frac{\partial L}{\partial b} = -\sum_i \alpha_i y_i = 0 \quad \Rightarrow \quad \sum_i \alpha_i y_i = 0\]

Step 3: 代回拉格朗日函数消去 \(w\)\(b\)

\(w = \sum_i \alpha_i y_i x_i\) 代入 \(L\)

\[L = \frac{1}{2}\left\|\sum_i \alpha_i y_i x_i\right\|^2 - \sum_i \alpha_i y_i \left(\sum_j \alpha_j y_j x_j\right) \cdot x_i - b\underbrace{\sum_i \alpha_i y_i}_{=0} + \sum_i \alpha_i\]
\[= \frac{1}{2}\sum_{i,j} \alpha_i \alpha_j y_i y_j (x_i \cdot x_j) - \sum_{i,j} \alpha_i \alpha_j y_i y_j (x_i \cdot x_j) + \sum_i \alpha_i\]
\[= \sum_i \alpha_i - \frac{1}{2}\sum_{i,j} \alpha_i \alpha_j y_i y_j (x_i \cdot x_j)\]

对偶问题\(\max_\alpha \sum_i \alpha_i - \frac{1}{2}\sum_{i,j} \alpha_i \alpha_j y_i y_j (x_i \cdot x_j) \quad \text{s.t.} \; \alpha_i \geq 0, \; \sum_i \alpha_i y_i = 0\)

注意:对偶问题中只涉及 \(x_i \cdot x_j\)(内积),这正是核技巧的入口——将内积替换为核函数 \(K(x_i, x_j)\) 即可处理非线性分类。

Python
from sklearn.svm import SVC
from sklearn.datasets import make_classification

X, y = make_classification(n_samples=100, n_features=2,
                           n_redundant=0, random_state=42)

svc = SVC(kernel='linear', C=1.0)
svc.fit(X, y)

print(f"支持向量数量: {svc.n_support_}")
print(f"总样本数: {len(X)}")
print(f"支持向量比例: {sum(svc.n_support_)/len(X):.2%}")
# 互补松弛条件: 只有支持向量的α>0,其余都=0

6. 深度学习优化技巧

6.1 梯度消失/爆炸

问题 原因 解决方案
梯度消失 sigmoid饱和/深层链式乘法 ReLU/ResNet/LayerNorm/LSTM
梯度爆炸 大权重连乘 梯度裁剪(Gradient Clipping)
Python
import torch

def gradient_clipping_demo():
    """梯度裁剪演示 — 大模型训练常用"""
    model = torch.nn.Linear(10, 10)

    # 模拟大梯度
    x = torch.randn(1, 10) * 100
    loss = model(x).sum()
    loss.backward()  # 反向传播计算梯度

    # 裁剪前
    total_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=float('inf'))
    print(f"裁剪前梯度范数: {total_norm:.2f}")

    # 重新计算
    model.zero_grad()
    loss = model(x).sum()
    loss.backward()

    # 裁剪(max_norm=1.0是LLM常用值)
    # 注意: clip_grad_norm_ 返回裁剪前的梯度范数
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    post_clip_norm = sum(p.grad.norm()**2 for p in model.parameters() if p.grad is not None).sqrt()
    print(f"裁剪后梯度范数: {post_clip_norm:.2f}")

gradient_clipping_demo()

6.2 权重初始化

\[\text{Xavier}: W \sim N\left(0, \frac{2}{n_{in} + n_{out}}\right) \quad \text{(tanh/sigmoid)}$$ $$\text{Kaiming}: W \sim N\left(0, \frac{2}{n_{in}}\right) \quad \text{(ReLU,当前标配)}\]

🎓 面试常考题

  1. SGD vs Adam,什么时候用哪个? — CV用SGD+Momentum泛化好,NLP/LLM用AdamW
  2. Adam的超参数含义?\(\beta_1\)=一阶矩(梯度均值)衰减(0.9),\(\beta_2\)=二阶矩(梯度平方均值)衰减(0.999),\(\epsilon\)=数值稳定(\(10^{-8}\))
  3. 为什么需要Warmup? — 初期参数随机梯度不稳,大lr会发散
  4. 梯度消失怎么解决? — ResNet(残差连接)、LayerNorm、ReLU、LSTM门控
  5. SVM为什么要转对偶? — 引入核函数、样本维度>特征维度时高效
  6. KKT互补松弛条件的物理含义? — 只有在约束边界上的样本(支持向量)才对决策有贡献
  7. 为什么DL不怕局部最优? — 高维空间鞍点远多于局部最小,且好的局部最小loss差不多
  8. BatchNorm为什么有效? — 减少Internal Covariate Shift,允许更大lr,有轻微正则化效果

📖 7. Adam优化器家族深度解析

7.1 从SGD到Adam的演进

优化器 更新规则 核心思想 适用场景
SGD \(\theta \leftarrow \theta - \eta g\) 最朴素 凸优化
Momentum \(v \leftarrow \beta v + g; \theta \leftarrow \theta - \eta v\) 指数滑动平均 加速收敛
RMSProp 自适应学习率 per-param 二阶矩估计 非平稳目标
Adam 一阶矩+二阶矩+偏差校正 集大成者 通用默认
AdamW Adam + 解耦权重衰减 修正L2正则化 Transformer标配

7.2 Adam vs AdamW 的关键区别

Adam with L2 regularization

\[g_t = \nabla L(\theta_t) + \lambda \theta_t$$ $$m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t$$ $$v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2\]

问题:L2正则化项也被自适应学习率缩放了,大梯度参数的正则化被削弱!

AdamW(解耦权重衰减)

\[g_t = \nabla L(\theta_t)$$ ← 梯度不含正则项 $$m_t, v_t$$ 更新同上 $$\theta_{t+1} = \theta_t - \eta \left(\frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} + \lambda \theta_t\right)\]

权重衰减独立于自适应学习率,对每个参数的惩罚一致。

Python
import torch

class AdamW:
    """手写AdamW优化器"""
    def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0.01):
        self.params = list(params)
        self.lr = lr
        self.beta1, self.beta2 = betas
        self.eps = eps
        self.wd = weight_decay
        self.t = 0
        self.m = [torch.zeros_like(p) for p in self.params]
        self.v = [torch.zeros_like(p) for p in self.params]

    def step(self):
        self.t += 1
        for i, p in enumerate(self.params):  # enumerate同时获取索引和元素
            if p.grad is None:
                continue
            g = p.grad.data

            # 一阶矩(均值)
            self.m[i] = self.beta1 * self.m[i] + (1 - self.beta1) * g
            # 二阶矩(方差)
            self.v[i] = self.beta2 * self.v[i] + (1 - self.beta2) * g ** 2

            # 偏差校正
            m_hat = self.m[i] / (1 - self.beta1 ** self.t)
            v_hat = self.v[i] / (1 - self.beta2 ** self.t)

            # 参数更新 = Adam步 + 解耦权重衰减
            p.data -= self.lr * (m_hat / (v_hat.sqrt() + self.eps) + self.wd * p.data)

    def zero_grad(self):
        for p in self.params:
            if p.grad is not None:
                p.grad.zero_()

# 验证:对比PyTorch官方实现
model = torch.nn.Linear(10, 1)
opt_official = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)
print("AdamW手写实现完成")

7.3 学习率调度策略

Python
import math

class CosineAnnealingWarmup:
    """Warmup + Cosine退火调度器"""
    def __init__(self, optimizer, warmup_steps, total_steps, min_lr=1e-6):
        self.optimizer = optimizer
        self.warmup_steps = warmup_steps
        self.total_steps = total_steps
        self.min_lr = min_lr
        self.base_lr = optimizer.param_groups[0]['lr']
        self.step_count = 0

    def step(self):
        self.step_count += 1
        if self.step_count <= self.warmup_steps:
            # 线性Warmup
            lr = self.base_lr * self.step_count / self.warmup_steps
        else:
            # Cosine退火
            progress = (self.step_count - self.warmup_steps) / (self.total_steps - self.warmup_steps)
            lr = self.min_lr + 0.5 * (self.base_lr - self.min_lr) * (1 + math.cos(math.pi * progress))

        for pg in self.optimizer.param_groups:
            pg['lr'] = lr
        return lr

# 可视化调度曲线
model = torch.nn.Linear(10, 1)
opt = torch.optim.AdamW(model.parameters(), lr=3e-4)
scheduler = CosineAnnealingWarmup(opt, warmup_steps=1000, total_steps=50000)

lrs = [scheduler.step() for _ in range(50000)]
print(f"Warmup结束lr: {lrs[999]:.6f}")
print(f"中间lr: {lrs[25000]:.6f}")
print(f"最终lr: {lrs[-1]:.6f}")

为什么Warmup有效? Adam初期二阶矩估计不准(偏差校正不够),直接用大lr会导致参数剧烈震荡。Warmup给优化器"热身"时间。


📖 8. 分布式优化

8.1 数据并行(Data Parallel)梯度同步

\(N\) 个GPU各持有模型副本,每个GPU处理 \(\frac{B}{N}\) 个样本:

\[g = \frac{1}{N} \sum_{i=1}^{N} g_i\]

通过AllReduce操作同步梯度后统一更新参数。

8.2 梯度累积(穷人的大Batch)

Python
def train_with_gradient_accumulation(model, dataloader, optimizer, accumulation_steps=4):
    """梯度累积:用小显存实现大batch效果"""
    model.train()  # train()开启训练模式
    optimizer.zero_grad()

    for step, (x, y) in enumerate(dataloader):
        loss = model(x, y) / accumulation_steps  # 除以累积步数
        loss.backward()  # 梯度累积

        if (step + 1) % accumulation_steps == 0:
            # 梯度裁剪(防梯度爆炸)
            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
            optimizer.step()  # 根据梯度更新模型参数
            optimizer.zero_grad()

# 等价于batch_size = micro_batch * accumulation_steps * n_gpus
print("梯度累积: 4次micro_batch=8 ≈ 1次batch=32")

8.3 混合精度训练

Python
# PyTorch AMP (Automatic Mixed Precision)
scaler = torch.amp.GradScaler('cuda')

for x, y in dataloader:
    optimizer.zero_grad()

    # 前向:自动选fp16/fp32
    with torch.amp.autocast(device_type='cuda'):
        output = model(x)
        loss = criterion(output, y)

    # 反向:loss scale防止fp16下溢
    scaler.scale(loss).backward()
    scaler.step(optimizer)
    scaler.update()

为什么混合精度有效? fp16计算速度2x,显存减半,但动态范围小(±65504)。通过loss scaling防止梯度下溢,master weight保持fp32精度。


🎯 面试高频题(扩展)

  1. Adam和SGD哪个泛化好? — SGD+Momentum通常泛化更好(更可能到平坦极小值),Adam收敛快但可能到尖锐极小值。实践中有时采用Adam预训练+SGD微调
  2. 梯度裁剪有几种方式? — clip_grad_norm_(按总范数缩放所有参数梯度)和clip_grad_value_(逐元素截断),前者更常用
  3. 为什么大batch需要线性缩放lr? — batch增大k倍,梯度方差减小k倍,可用更大lr(k倍)加速收敛。但有上限,超大batch需要LARS/LAMB
  4. 混合精度训练的loss scaling原理? — fp16动态范围小,小梯度会下溢为0。乘以scale放大到fp16可表示范围,更新时再除回来
  5. ZeRO优化是什么? — DeepSpeed的显存优化:Stage1分片优化器状态,Stage2再分片梯度,Stage3再分片参数。可线性减少显存
  6. 为什么Transformer常用AdamW? — 自适应学习率有助于训练稳定,解耦weight decay避免正则化被自适应缩放削弱

✅ 学习检查清单

  • 能手写Adam优化器
  • 能解释SGD/Momentum/Adam的区别和适用场景
  • 能解释Warmup+Cosine调度的原因
  • 能解释凸优化vs非凸优化
  • 能写出SVM的拉格朗日函数和KKT条件
  • 能解释梯度消失/爆炸的原因和解决方案