人工智能之数学基础 优化理论:第二章 无约束优化

38 阅读6分钟

人工智能之数学基础 优化理论

第二章 无约束优化----公式关注公众号


@TOC


前言

本文将系统讲解 梯度下降(Gradient Descent, GD)随机梯度下降(Stochastic Gradient Descent, SGD)动量法(Momentum)Nesterov 加速梯度(NAG)AdaGradRMSPropAdam 等主流优化器,揭示其数学原理、收敛特性与适用场景,并提供 从零实现 + PyTorch 对比 的完整 Python 代码与可视化。


一、问题设定:无约束优化

目标:

minxRnf(x)\min_{\mathbf{x} \in \mathbb{R}^n} f(\mathbf{x})

其中 ff 是可微(通常光滑)的目标函数,如机器学习中的损失函数。

核心思想:沿负梯度方向迭代更新参数,因为梯度指向函数增长最快的方向,负梯度即最速下降方向。


二、1. 梯度下降(Gradient Descent, GD)

算法

xk+1=xkηf(xk)\mathbf{x}_{k+1} = \mathbf{x}_k - \eta \nabla f(\mathbf{x}_k)
  • η>0\eta > 0:学习率(步长)
  • f(xk)\nabla f(\mathbf{x}_k):全批量梯度

特点

  • 确定性算法(相同初值 → 相同路径)
  • 收敛慢(尤其病态条件数大时)
  • 每次需计算全部数据梯度 → 计算开销大

三、2. 随机梯度下降(Stochastic Gradient Descent, SGD)

动机

在机器学习中,f(x)=1Ni=1Ni(x)f(\mathbf{x}) = \frac{1}{N} \sum_{i=1}^N \ell_i(\mathbf{x}),GD 需遍历全部 NN 个样本。

SGD 每次随机采样一个样本(或小批量)估计梯度:

xk+1=xkηik(xk),ikUniform(1,,N)\mathbf{x}_{k+1} = \mathbf{x}_k - \eta \nabla \ell_{i_k}(\mathbf{x}_k), \quad i_k \sim \text{Uniform}(1, \dots, N)

特点

  • 随机性:路径抖动,但期望梯度无偏
  • 计算高效:每次只用一个样本
  • 可逃离局部极小/鞍点
  • 学习率衰减以保证收敛

🔑 Mini-batch SGD:折中方案,每次用 ( B \ll N ) 个样本,兼顾效率与稳定性。


四、3. 动量法(Momentum)

动机

GD/SGD 在峡谷地形中会“之字形”震荡,收敛慢。

引入速度变量 v\mathbf{v} 积累历史梯度:

vk+1=βvk+f(xk)xk+1=xkηvk+1\begin{aligned} \mathbf{v}_{k+1} &= \beta \mathbf{v}_k + \nabla f(\mathbf{x}_k) \\ \mathbf{x}_{k+1} &= \mathbf{x}_k - \eta \mathbf{v}_{k+1} \end{aligned}
  • β[0,1)\beta \in [0,1):动量系数(通常 0.9)
  • 物理类比:带摩擦的球滚下山坡

优势

  • 抑制震荡,加速收敛
  • 提高稳定性

五、4. Nesterov Accelerated Gradient (NAG)

改进

先看“前方”再更新,避免冲过头:

vk+1=βvk+f(xkηβvk)xk+1=xkηvk+1\begin{aligned} \mathbf{v}_{k+1} &= \beta \mathbf{v}_k + \nabla f(\mathbf{x}_k - \eta \beta \mathbf{v}_k) \\ \mathbf{x}_{k+1} &= \mathbf{x}_k - \eta \mathbf{v}_{k+1} \end{aligned}

✅ 理论上对凸函数有更优收敛率。


六、5. 自适应学习率方法

(a) AdaGrad

为每个参数分配独立学习率,根据历史梯度平方和调整:

gk=f(xk)Gk=Gk1+gkgkxk+1=xkηGk+ϵgk\begin{aligned} \mathbf{g}_k &= \nabla f(\mathbf{x}_k) \\ \mathbf{G}_k &= \mathbf{G}_{k-1} + \mathbf{g}_k \odot \mathbf{g}_k \\ \mathbf{x}_{k+1} &= \mathbf{x}_k - \frac{\eta}{\sqrt{\mathbf{G}_k + \epsilon}} \odot \mathbf{g}_k \end{aligned}
  • \odot:逐元素乘
  • ϵ\epsilon:防除零(如 10810^{-8}
  • 缺点:学习率单调递减,可能过早停止

(b) RMSProp

解决 AdaGrad 学习率衰减过快问题,引入指数移动平均

gk=f(xk)sk=γsk1+(1γ)gkgkxk+1=xkηsk+ϵgk\begin{aligned} \mathbf{g}_k &= \nabla f(\mathbf{x}_k) \\ \mathbf{s}_k &= \gamma \mathbf{s}_{k-1} + (1 - \gamma) \mathbf{g}_k \odot \mathbf{g}_k \\ \mathbf{x}_{k+1} &= \mathbf{x}_k - \frac{\eta}{\sqrt{\mathbf{s}_k + \epsilon}} \odot \mathbf{g}_k \end{aligned}
  • γ0.9\gamma \approx 0.9

(c) Adam(Adaptive Moment Estimation)

结合动量 + RMSProp,目前最流行的优化器:

mk=β1mk1+(1β1)gk(一阶矩)vk=β2vk1+(1β2)gkgk(二阶矩)m^k=mk1β1k,v^k=vk1β2k(偏差修正)xk+1=xkηv^k+ϵm^k\begin{aligned} \mathbf{m}_k &= \beta_1 \mathbf{m}_{k-1} + (1 - \beta_1) \mathbf{g}_k \quad &\text{(一阶矩)} \\ \mathbf{v}_k &= \beta_2 \mathbf{v}_{k-1} + (1 - \beta_2) \mathbf{g}_k \odot \mathbf{g}_k \quad &\text{(二阶矩)} \\ \hat{\mathbf{m}}_k &= \frac{\mathbf{m}_k}{1 - \beta_1^k}, \quad \hat{\mathbf{v}}_k = \frac{\mathbf{v}_k}{1 - \beta_2^k} \quad &\text{(偏差修正)} \\ \mathbf{x}_{k+1} &= \mathbf{x}_k - \frac{\eta}{\sqrt{\hat{\mathbf{v}}_k} + \epsilon} \odot \hat{\mathbf{m}}_k \end{aligned}
  • 默认参数:β1=0.9,β2=0.999,η=0.001\beta_1 = 0.9, \beta_2 = 0.999, \eta = 0.001

七、Python 代码实现

1. 导入库

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

np.random.seed(42)

2. 定义测试函数(Beale 函数,非凸)

f(x,y)=(1.5x+xy)2+(2.25x+xy2)2+(2.625x+xy3)2f(x, y) = (1.5 - x + xy)^2 + (2.25 - x + xy^2)^2 + (2.625 - x + xy^3)^2

全局最小值在 (3,0.5)(3, 0.5),值为 0。

def beale(xy):
    x, y = xy[0], xy[1]
    term1 = (1.5 - x + x*y)**2
    term2 = (2.25 - x + x*y**2)**2
    term3 = (2.625 - x + x*y**3)**2
    return term1 + term2 + term3

def grad_beale(xy):
    x, y = xy[0], xy[1]
    # 手动推导梯度(或用 SymPy)
    df_dx = -2*(1.5 - x + x*y)*(1 - y) \
            -2*(2.25 - x + x*y**2)*(1 - y**2) \
            -2*(2.625 - x + x*y**3)*(1 - y**3)
    df_dy = 2*(1.5 - x + x*y)*x \
            + 4*(2.25 - x + x*y**2)*x*y \
            + 6*(2.625 - x + x*y**3)*x*y**2
    return np.array([df_dx, df_dy])

3. 通用优化器框架

def optimize(optimizer_update, x0, lr, n_iter=100, **kwargs):
    x = np.array(x0, dtype=float)
    trajectory = [x.copy()]
    
    for k in range(1, n_iter + 1):
        grad = grad_beale(x)
        x = optimizer_update(x, grad, lr, k, **kwargs)
        trajectory.append(x.copy())
    
    return np.array(trajectory)

4. 实现各优化器

(a) 梯度下降(GD)

def gd_update(x, grad, lr, k, **kwargs):
    return x - lr * grad

(b) 动量法

def momentum_update(x, grad, lr, k, beta=0.9, state=None):
    if state is None:
        state = {'v': np.zeros_like(x)}
    v = beta * state['v'] + grad
    state['v'] = v
    return x - lr * v, state

为简化,下面使用闭包保存状态:

def make_momentum(beta=0.9):
    v = None
    def update(x, grad, lr, k):
        nonlocal v
        if v is None:
            v = np.zeros_like(x)
        v = beta * v + grad
        return x - lr * v
    return update

(c) Adam

def make_adam(beta1=0.9, beta2=0.999, eps=1e-8):
    m = v = None
    def update(x, grad, lr, k):
        nonlocal m, v
        if m is None:
            m = np.zeros_like(x)
            v = np.zeros_like(x)
        m = beta1 * m + (1 - beta1) * grad
        v = beta2 * v + (1 - beta2) * (grad ** 2)
        m_hat = m / (1 - beta1 ** k)
        v_hat = v / (1 - beta2 ** k)
        return x - lr * m_hat / (np.sqrt(v_hat) + eps)
    return update

5. 运行对比实验

x0 = [-1.0, 1.5]  # 初始点
n_iter = 50

# 定义优化器
optimizers = {
    'GD': lambda: gd_update,
    'Momentum': lambda: make_momentum(beta=0.9),
    'Adam': lambda: make_adam()
}

trajectories = {}
for name, opt_factory in optimizers.items():
    traj = optimize(opt_factory(), x0, lr=0.01, n_iter=n_iter)
    trajectories[name] = traj

# 最终结果
for name, traj in trajectories.items():
    final_val = beale(traj[-1])
    print(f"{name}: 最终点={traj[-1]}, f={final_val:.6f}")

6. 可视化优化路径

# 绘制等高线
x = np.linspace(-2, 4, 200)
y = np.linspace(-1, 2, 200)
X, Y = np.meshgrid(x, y)
Z = np.array([beale([xi, yi]) for xi, yi in zip(X.ravel(), Y.ravel())]).reshape(X.shape)

plt.figure(figsize=(12, 4))
for i, (name, traj) in enumerate(trajectories.items()):
    plt.subplot(1, 3, i+1)
    plt.contour(X, Y, Z, levels=30, cmap='viridis', alpha=0.7)
    plt.plot(traj[:, 0], traj[:, 1], 'ro-', markersize=3, label=name)
    plt.plot(3, 0.5, 'g*', markersize=15, label='全局最优')
    plt.title(f'{name} 优化路径')
    plt.xlabel('x'); plt.ylabel('y')
    plt.legend(); plt.grid(True)

plt.tight_layout()
plt.show()

📈 可见:Adam 和 Momentum 路径更平滑、收敛更快;GD 震荡明显。


7. 在机器学习中的应用(线性回归)

# 生成数据
np.random.seed(0)
X = np.random.randn(100, 1)
y = 2 * X.squeeze() + 1 + 0.1 * np.random.randn(100)

# 添加偏置项
X_b = np.c_[np.ones((100, 1)), X]  # [1, x]

def loss(w):
    return np.mean((X_b @ w - y)**2)

def grad_loss(w):
    return 2 * X_b.T @ (X_b @ w - y) / len(y)

# 使用 Adam 优化
w0 = np.random.randn(2)
traj_w = optimize(make_adam(), w0, lr=0.1, n_iter=100)

# 绘制损失曲线
losses = [loss(w) for w in traj_w]
plt.figure(figsize=(8, 4))
plt.plot(losses, 'b-')
plt.title('训练损失(Adam)')
plt.xlabel('迭代次数'); plt.ylabel('MSE')
plt.grid(True)
plt.show()

print("学到的参数:", traj_w[-1], "(真实: [1, 2])")

8. 与 PyTorch 优化器对比

import torch
import torch.nn as nn
import torch.optim as optim

# PyTorch 实现
model = nn.Linear(1, 1)
model.weight.data.fill_(0.0)
model.bias.data.fill_(0.0)

criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.1)

losses_torch = []
for epoch in range(100):
    optimizer.zero_grad()
    outputs = model(torch.tensor(X, dtype=torch.float32))
    loss_val = criterion(outputs.squeeze(), torch.tensor(y, dtype=torch.float32))
    loss_val.backward()
    optimizer.step()
    losses_torch.append(loss_val.item())

# 对比损失曲线
plt.plot(losses, 'b-', label='From-scratch Adam')
plt.plot(losses_torch, 'r--', label='PyTorch Adam')
plt.legend(); plt.grid(True)
plt.title('自实现 vs PyTorch Adam')
plt.show()

✅ 两者应高度一致,验证实现正确性。


九、优化器选择指南

场景推荐优化器
凸问题、小数据GD 或 L-BFGS
深度学习(默认)Adam
需要精细调参SGD + 动量 + 学习率调度
稀疏数据(NLP)AdaGrad / Adam
理论保证强收敛SGD(带衰减)

💡 经验法则

  • 先用 Adam 快速原型;
  • 若需最高精度,切换到 SGD + 动量 + 学习率衰减;
  • 学习率是最重要的超参!

十、总结

优化器核心思想优点缺点
GD全梯度下降稳定慢、内存大
SGD随机梯度快、可逃局部最优噪声大
Momentum梯度累积抑制震荡需调 β
Adam自适应 + 动量自动调学习率、鲁棒可能泛化略差

🔚 关键洞见

  • 所有优化器都是梯度的一阶近似
  • 自适应方法降低了调参难度;
  • 动量模拟物理惯性,提升收敛性;
  • 没有免费午餐:不同问题适合不同优化器。

后续

python过渡项目部分代码已经上传至gitee,后续会逐步更新。

资料关注

公众号:咚咚王 gitee:gitee.com/wy185850518…

《Python编程:从入门到实践》 《利用Python进行数据分析》 《算法导论中文第三版》 《概率论与数理统计(第四版) (盛骤) 》 《程序员的数学》 《线性代数应该这样学第3版》 《微积分和数学分析引论》 《(西瓜书)周志华-机器学习》 《TensorFlow机器学习实战指南》 《Sklearn与TensorFlow机器学习实用指南》 《模式识别(第四版)》 《深度学习 deep learning》伊恩·古德费洛著 花书 《Python深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》 《深入浅出神经网络与深度学习+(迈克尔·尼尔森(Michael+Nielsen)》 《自然语言处理综论 第2版》 《Natural-Language-Processing-with-PyTorch》 《计算机视觉-算法与应用(中文版)》 《Learning OpenCV 4》 《AIGC:智能创作时代》杜雨+&+张孜铭 《AIGC原理与实践:零基础学大语言模型、扩散模型和多模态模型》 《从零构建大语言模型(中文版)》 《实战AI大模型》 《AI 3.0》