第二章 无约束优化
前言本文将系统讲解 梯度下降(Gradient Descent, GD)、随机梯度下降(Stochastic Gradient Descent, SGD)、动量法(Momentum)、Nesterov 加速梯度(NAG)、AdaGrad、RMSProp 和 Adam 等主流优化器,揭示其数学原理、收敛特性与适用场景,并提供 从零实现 + PyTorch 对比 的完整 Python 代码与可视化。
一、问题设定:无约束优化目标:
$$ \min_{\mathbf{x} \in \mathbb{R}^n} f(\mathbf{x}) $$
其中 $f $ 是可微(通常光滑)的目标函数,如机器学习中的损失函数。
✅ 核心思想:沿负梯度方向迭代更新参数,因为梯度指向函数增长最快的方向,负梯度即最速下降方向。
二、1. 梯度下降(Gradient Descent, GD)算法$$ \mathbf{x}{k+1} = \mathbf{x}k - \eta \nabla f(\mathbf{x}_k) $$
$ \eta > 0 $:学习率(步长)$ \nabla f(\mathbf{x}_k) $:全批量梯度特点确定性算法(相同初值 → 相同路径)收敛慢(尤其病态条件数大时)每次需计算全部数据梯度 → 计算开销大三、2. 随机梯度下降(Stochastic Gradient Descent, SGD)动机在机器学习中,$ f(\mathbf{x}) = \frac{1}{N} \sum{i=1}^N \elli(\mathbf{x}) $,GD 需遍历全部 $ N $ 个样本。
SGD 每次随机采样一个样本(或小批量)估计梯度:
$$ \mathbf{x}{k+1} = \mathbf{x}k - \eta \nabla \ell{ik}(\mathbf{x}k), \quad ik \sim \text{Uniform}(1, \dots, N) $$
特点随机性:路径抖动,但期望梯度无偏计算高效:每次只用一个样本可逃离局部极小/鞍点需学习率衰减以保证收敛Mini-batch SGD:折中方案,每次用 \( B \ll N \) 个样本,兼顾效率与稳定性。
四、3. 动量法(Momentum)动机GD/SGD 在峡谷地形中会“之字形”震荡,收敛慢。
引入速度变量 $\mathbf{v} $ 积累历史梯度:
$$ \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} $$
$ \beta \in [0,1) $:动量系数(通常 0.9)物理类比:带摩擦的球滚下山坡优势抑制震荡,加速收敛提高稳定性五、4. Nesterov Accelerated Gradient (NAG)改进先看“前方”再更新,避免冲过头:
$$ \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为每个参数分配独立学习率,根据历史梯度平方和调整:
$$ \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 $:防除零(如 $ 10^{-8} $)缺点:学习率单调递减,可能过早停止(b) RMSProp解决 AdaGrad 学习率衰减过快问题,引入指数移动平均:
$$ \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} $$
$ \gamma \approx 0.9 $(c) Adam(Adaptive Moment Estimation)结合动量 + RMSProp,目前最流行的优化器:
$$ \begin{aligned} \mathbf{m}k &= \beta1 \mathbf{m}{k-1} + (1 - \beta1) \mathbf{g}k \quad &\text{(一阶矩)} \\ \mathbf{v}k &= \beta2 \mathbf{v}{k-1} + (1 - \beta2) \mathbf{g}k \odot \mathbf{g}k \quad &\text{(二阶矩)} \\ \hat{\mathbf{m}}k &= \frac{\mathbf{m}k}{1 - \beta1^k}, \quad \hat{\mathbf{v}}k = \frac{\mathbf{v}k}{1 - \beta2^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} $$
默认参数:$ \beta1 = 0.9, \beta2 = 0.999, \eta = 0.001 $七、Python 代码实现1. 导入库import numpy as npimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d import Axes3Dnp.random.seed(42)2. 定义测试函数(Beale 函数,非凸)$$ f(x, y) = (1.5 - x + xy)^2 + (2.25 - x + xy^2)^2 + (2.625 - x + xy^3)^2 $$
全局最小值在 $ (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 + term3def 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) Adamdef 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 update5. 运行对比实验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 torchimport torch.nn as nnimport 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:https://gitee.com/wy18585051844/ai_learning
《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》
转载请注明来自海坡下载,本文标题:《无约束优化问题(人工智能之数学基础 优化理论第二章 无约束优化)》
京公网安备11000000000001号
京ICP备11000001号
还没有评论,来说两句吧...