目录
优化基础
凸优化 (Convex Optimization)
函数 若为凸(convex)函数,则对任意两点 及 ,以下不等式成立。
凸函数的核心性质:
- 任何局部最小值(local minimum)都是全局最小值(global minimum)
- 梯度下降法的收敛得到保证
- 深度学习的损失函数大多是非凸(non-convex)的,但凸分析技巧依然有用
强凸(Strongly Convex):若存在 ,使得 成立,则收敛速度会加快为线性收敛(linear convergence)。
拉格朗日乘子法
用于处理等式约束的优化问题。
拉格朗日函数(Lagrangian):
在最优解处,、 成立。
KKT 条件
包含不等式约束在内的一般化优化问题:
KKT 条件(必要条件):
- 稳定性(Stationarity):
- 原始可行性(Primal feasibility):,
- 对偶可行性(Dual feasibility):
- 互补松弛性(Complementary slackness):
在凸问题中,KKT 条件同时也是充分条件。
鞍点 (Saddle Point)
在深度学习优化中,比局部最小值更大的问题是鞍点。在鞍点处,某些方向上函数值会增大,另一些方向上会减小,导致梯度为零。SGD 的随机噪声有助于逃离鞍点。
梯度下降系列
SGD 及其变体
基础 SGD:
带动量的 SGD (SGD with Momentum):
动量 是常用取值,它保留之前的梯度方向,从而减少震荡(oscillation)。
Nesterov 加速梯度 (Nesterov Accelerated Gradient, NAG):
不是在当前位置,而是在"向前看"的位置上计算梯度。
AdaGrad、RMSProp、Adam
AdaGrad:按参数自适应学习率
经常出现的特征学习率会变小,稀少出现的特征学习率会较大。缺点:学习率单调递减,可能导致训练停滞。
RMSProp:解决 AdaGrad 的累积问题
Adam(自适应矩估计,Adaptive Moment Estimation):
偏差校正(Bias correction):
默认超参数:,,
import torch
import torch.optim as optim
model = ... # 定义模型
# Adam optimizer
optimizer_adam = optim.Adam(
model.parameters(),
lr=1e-3,
betas=(0.9, 0.999),
eps=1e-8
)
# AdamW optimizer (分离 weight decay)
optimizer_adamw = optim.AdamW(
model.parameters(),
lr=1e-3,
betas=(0.9, 0.999),
eps=1e-8,
weight_decay=0.01 # 独立于 L2 应用
)
AdamW 与 Lion
AdamW:在 Adam 的基础上,不把 weight decay 作为 L2 惩罚项,而是直接应用在参数更新上。
这在数学上与普通 Adam 的 L2 正则化并不等价(详细说明见测验)。
Lion(EvoLved Sign Momentum):
Lion 只使用符号(sign),因此内存效率高,更新幅度也保持均匀。
| Optimizer | 内存 | 收敛速度 | 适合场景 |
|---|---|---|---|
| SGD+Momentum | 低 | 慢 | 计算机视觉、大批量 |
| Adam | 中等 | 快 | NLP、通用场景 |
| AdamW | 中等 | 快 | Transformer 训练 |
| Lion | 低 | 快 | 大规模模型 |
| L-BFGS | 高 | 非常快 | 小规模模型 |
二阶优化
Newton 方法
利用二阶导数(Hessian)。
这里 是 Hessian 矩阵。虽然具有二次收敛(quadratic convergence),但 Hessian 矩阵求逆的计算量为 ,在深度学习中并不现实。
L-BFGS (Limited-memory BFGS)
不直接存储 Hessian,而是用最近 个梯度差来近似。
其中 ,。
import torch
import torch.optim as optim
# L-BFGS 需要闭包(closure)函数
optimizer = optim.LBFGS(
model.parameters(),
lr=1.0,
max_iter=20,
history_size=10,
line_search_fn='strong_wolfe'
)
def closure():
optimizer.zero_grad()
output = model(input_data)
loss = criterion(output, target)
loss.backward()
return loss
optimizer.step(closure)
自然梯度下降法 (Natural Gradient)
利用 Fisher 信息矩阵,考虑参数空间的曲率。
Fisher 矩阵:
K-FAC(Kronecker-factored Approximate Curvature)是自然梯度法的一种实用实现。
学习率调度
Warmup
在训练初期逐步提高学习率,使训练更稳定。
Cosine Annealing
from torch.optim.lr_scheduler import CosineAnnealingLR, OneCycleLR, ReduceLROnPlateau
# Cosine Annealing
scheduler = CosineAnnealingLR(optimizer, T_max=100, eta_min=1e-6)
# OneCycleLR: Warmup + Cosine Decay
scheduler = OneCycleLR(
optimizer,
max_lr=1e-3,
total_steps=1000,
pct_start=0.3, # 30% warmup
anneal_strategy='cos'
)
# ReduceLROnPlateau: 验证损失不再改善时降低学习率
scheduler = ReduceLROnPlateau(
optimizer,
mode='min',
factor=0.5,
patience=10,
min_lr=1e-6
)
Cyclical Learning Rate (CLR)
周期性地变动学习率,帮助逃离鞍点。
| 调度器 | 特点 | 适合场景 |
|---|---|---|
| Cosine Annealing | 平滑衰减 | Transformer 预训练 |
| OneCycleLR | Warmup + 快速衰减 | 微调、短周期训练 |
| ReduceLROnPlateau | 自适应 | 常规训练、需要验证 |
| Cyclical LR | 周期性变动 | 逃离鞍点 |
| Linear Warmup | 初期稳定化 | LLM 训练 |
正则化技巧
L1 / L2 正则化
L2 正则化 (Ridge):
梯度:
L1 正则化 (Lasso):
L1 会诱导出稀疏(sparse)解。
Batch Normalization 与 Layer Normalization
Batch Normalization (BN):
这里 、 是小批量(mini-batch)内的统计量。沿批量方向做归一化。
Layer Normalization (LN):
这里的统计量是沿每个样本的特征维度计算的。
| 归一化 | 统计量计算方向 | 适合场景 |
|---|---|---|
| Batch Norm | 批量方向(相同特征) | CNN、大批量 |
| Layer Norm | 特征方向(相同样本) | Transformer、RNN |
| Instance Norm | 空间方向(相同通道) | 风格迁移 |
| Group Norm | 通道分组 | 小批量 |
Weight Decay 与 L2 正则化
在 SGD 中:
在这种情况下,weight decay 与 L2 正则化是等价的。但在 Adam 中:
- L2 Adam:把 加到梯度上之后,再应用自适应学习率 → 被自适应系数相除,正则化效果被削弱
- AdamW:在参数更新后直接减去 → 对所有参数施加均等的 weight decay
# Dropout
import torch.nn as nn
class RegularizedModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(512, 256)
self.bn1 = nn.BatchNorm1d(256)
self.ln1 = nn.LayerNorm(256)
self.dropout = nn.Dropout(p=0.3)
def forward(self, x):
x = self.fc1(x)
x = self.bn1(x) # 或使用 self.ln1(x)
x = torch.relu(x)
x = self.dropout(x)
return x
损失函数设计
Cross-Entropy Loss
二分类:
Focal Loss
用于解决类别不平衡问题。降低易分类样本的贡献。
这里 是正确类别的预测概率, 是 focusing parameter。当 时,等价于普通的 Cross-Entropy。
import torch
import torch.nn.functional as F
class FocalLoss(torch.nn.Module):
def __init__(self, alpha=0.25, gamma=2.0):
super().__init__()
self.alpha = alpha
self.gamma = gamma
def forward(self, logits, targets):
bce_loss = F.binary_cross_entropy_with_logits(
logits, targets.float(), reduction='none'
)
p = torch.sigmoid(logits)
p_t = p * targets + (1 - p) * (1 - targets)
focal_weight = (1 - p_t) ** self.gamma
alpha_t = self.alpha * targets + (1 - self.alpha) * (1 - targets)
loss = alpha_t * focal_weight * bce_loss
return loss.mean()
Contrastive Loss 与 Triplet Loss
Contrastive Loss(Siamese Network):
这里 , 表示相似对, 表示不相似对。
Triplet Loss:
使用锚点(anchor, a)、正样本(positive, p)、负样本(negative, n)。
InfoNCE Loss (NT-Xent)
对比学习(Contrastive Learning)的核心损失函数。
这里 是 temperature parameter, 是余弦相似度。
import torch
import torch.nn.functional as F
def info_nce_loss(features, temperature=0.07):
"""
features: (2N, D) - 每张图像的两个 augmentation view
"""
N = features.shape[0] // 2
features = F.normalize(features, dim=1)
# 计算相似度矩阵
similarity = torch.matmul(features, features.T) / temperature
# 去除自身相似度(将对角线设为 -inf)
mask = torch.eye(2 * N, dtype=torch.bool, device=features.device)
similarity.masked_fill_(mask, float('-inf'))
# 正样本对: i 与 i+N,i+N 与 i
labels = torch.cat([
torch.arange(N, 2 * N),
torch.arange(N)
]).to(features.device)
loss = F.cross_entropy(similarity, labels)
return loss
LLM 训练优化
梯度裁剪 (Gradient Clipping)
防止梯度爆炸(exploding gradient)。
import torch
def train_with_clipping(model, optimizer, loss, max_norm=1.0):
optimizer.zero_grad()
loss.backward()
# 监控梯度范数
total_norm = 0
for p in model.parameters():
if p.grad is not None:
param_norm = p.grad.data.norm(2)
total_norm += param_norm.item() ** 2
total_norm = total_norm ** 0.5
# 应用裁剪
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=max_norm)
optimizer.step()
return total_norm
ZeRO Optimizer (Zero Redundancy Optimizer)
模型训练时分三个阶段优化内存。
| ZeRO 阶段 | 分片对象 | 内存节省 |
|---|---|---|
| Stage 1 | Optimizer 状态 | ~4x |
| Stage 2 | + 梯度 | ~8x |
| Stage 3 | + 参数 | ~64x(以 N 张 GPU 为基准) |
混合精度(mixed precision) + ZeRO-3 可以让数十亿参数量级的模型在单节点上完成训练。
8-bit Adam
通过量化(quantization),把 optimizer 状态以 INT8 而非 FP32 存储。
- optimizer 状态内存节省 75%(相较于 FP32)
- 通过 block-wise quantization 将精度损失降到最低
- 可通过
bitsandbytes库实现
# bitsandbytes 8-bit Adam
import bitsandbytes as bnb
optimizer = bnb.optim.Adam8bit(
model.parameters(),
lr=1e-4,
betas=(0.9, 0.999)
)
Adafactor
用矩阵分解近似 Adam 的二阶矩。
只使用与参数量成比例的内存(行向量 + 列向量)。被用于 T5、PaLM 等超大规模模型的训练。
| Optimizer | 内存(相对于参数量的倍数) | LLM 适配度 |
|---|---|---|
| Adam | 8x(params + 2 states) | 一般 |
| AdamW | 8x | 好 |
| 8-bit Adam | 6x | 好 |
| Adafactor | ~2x | 非常好 |
| Lion | 6x | 好 |
测验
Q1. 为什么 Adam optimizer 需要 bias correction?
答案:为了校正初始矩估计值因零初始化而产生的偏差。
说明:Adam 中若把 、 初始化,则在初期时间步 上, 与 会低估真实梯度的矩。举例来说,在 时 ,而其真实期望值 ,要把它还原为 就必须乘以 。当 时,在 处会被校正为 。当 足够大时,,校正系数收敛到 1,效果随之消失。
Q2. 为什么 Weight Decay 和 L2 正则化在 Adam 中并不等价?
答案:因为 Adam 的自适应学习率会对 L2 惩罚项的梯度进行缩放。
说明:在 SGD 中,,两种方式在数学上是等价的。但在 Adam 中加入 L2 正则化后,梯度会变为 ,再被自适应缩放系数 相除。因此权重较大(即 较大)的参数,L2 惩罚也会随之变小。AdamW 把 weight decay 从自适应缩放中剥离出来,改为 的形式处理,从而对所有参数施加均等的正则化。
Q3. Batch Normalization 与 Layer Normalization 的区别,以及各自适合的场景是?
答案:BN 在批量维度上归一化,LN 在特征维度上归一化。
说明:BN 用小批量内相同特征(神经元)的均值/方差做归一化。因此依赖批量大小,批量较小时统计量的估计会不稳定。它适合像 CNN 那样具有空间特征、且批量足够大的场景。LN 是沿每个样本的特征维度做归一化,因此与批量大小无关。它适合像 Transformer 那样序列长度可变,或像 RNN 那样难以维持批量统计量的场景。推理时也不需要批量统计量,因此对在线推理更有利。
Q4. Focal Loss 在类别不平衡问题上比 Cross-Entropy 更有效的数学原理是什么?
答案:因为 权重会动态降低易分类样本的贡献。
说明:普通 CE 损失是 ,容易分类的多数类样本也会做出同等的贡献。观察 Focal Loss 的 项,当 (易分类样本)时,,权重变得非常小。相反,当 (难分类样本)时,,几乎维持原样。使用 时,易分类样本的损失会减小到 100 分之一。由此,模型得以集中学习难分类的少数类样本。
Q5. InfoNCE Loss 在对比学习中学到良好表示的原理是什么?
答案:让同一图像的不同 augmentation 对趋于相似,让不同图像趋于疏远,以此进行学习。
说明:InfoNCE 最大化互信息(mutual information)的下界。分子 提高正样本对(同一图像的两个 view)之间的相似度,分母则包含 个负样本对。Temperature 用于调节分布的尖锐程度。 越小,竞争越激烈,表示空间也就越具区分性。在大批量下提供多样的负样本,能让表示更具泛化性。SimCLR、MoCo、CLIP 等主要的对比学习模型都使用这一损失函数。
현재 단락 (1/264)
1. [优化基础:凸优化与 KKT 条件](#优化基础)