优化器是机器学习、深度学习、神经网络和人工智能中非常核心的一个术语。它用来描述:模型在得到梯度之后,如何更新权重和偏置,使损失函数逐渐变小。 换句话说,优化器是在回答:模型已经知道自己错在哪里之后,下一步参数应该怎样改。
如果说反向传播负责计算“每个参数对错误负多少责任”,那么优化器负责根据这些梯度真正调整参数。因此,优化器常用于神经网络训练、梯度下降、深度学习框架、模型收敛、学习率设置和大模型训练,是理解模型如何学习的重要基础概念。
一、基本概念:什么是优化器
优化器(Optimizer)是用于更新模型参数的算法。
在神经网络中,模型参数主要包括:
• 权重 W
• 偏置 b
• 嵌入向量参数
• 归一化层参数
• 其他可学习参数
训练模型时,通常先通过前向传播计算预测结果,再通过损失函数衡量预测错误,然后通过反向传播计算梯度。
得到梯度后,优化器会根据一定规则更新参数。
最基本的参数更新形式是:
其中:
• θ 表示模型参数
• L 表示损失函数
• ∂L/∂θ 表示损失对参数 θ 的梯度
• η 表示学习率
• ← 表示用右边的新值更新左边的参数
从通俗角度看:优化器就是根据梯度,决定参数往哪个方向走、每次走多远。
例如,如果某个权重增大会让损失变大,那么优化器就会把它调小;如果某个权重减小会让损失变大,那么优化器就会把它调大。
因此,优化器是模型训练过程中真正执行“学习动作”的部分。
二、为什么需要优化器
优化器之所以重要,是因为神经网络训练本质上是一个优化问题。
模型训练的目标是:找到一组参数,使损失函数尽可能小。
可以写成:
其中:
• θ 表示模型参数
• θ* 表示理想情况下最优的参数
• L(θ) 表示参数为 θ 时的损失
• argmin 表示使损失最小的参数取值
从通俗角度看,模型训练就像在一座山谷中寻找最低点:
• 损失函数是一片地形
• 参数位置是人在地形中的当前位置
• 梯度告诉我们哪里上坡、哪里下坡
• 优化器决定我们如何往低处走
如果没有优化器,模型虽然能计算预测和梯度,但不会真正改进参数。
例如,反向传播告诉我们:
表示损失对权重 W 的梯度。
但仅仅知道梯度还不够,还需要决定:
• 参数是否马上更新
• 更新幅度多大
• 是否结合历史梯度
• 是否给不同参数使用不同步长
• 是否加入动量或自适应调整
这些问题都由优化器处理。
从通俗角度看:反向传播负责提供方向感,优化器负责真正迈步。
三、优化器与梯度下降的关系
梯度下降(Gradient Descent)是最基础的优化方法,也是理解优化器的起点。
梯度下降的基本思想是:沿着损失函数下降最快的方向更新参数。
对于参数 θ,更新规则为:
其中:
• ∇θL(θ) 表示损失函数对参数 θ 的梯度
• η 表示学习率
梯度指向损失上升最快的方向,因此如果要让损失下降,就要沿着梯度的反方向走。
从通俗角度看:
• 梯度方向:上坡最快的方向
• 负梯度方向:下坡最快的方向
所以更新公式中有一个减号:
表示沿负梯度方向移动。
优化器可以看作梯度下降思想的不同实现和改进。
例如:
• SGD 是基础梯度下降的随机小批量版本
• Momentum 在 SGD 中加入惯性
• RMSProp 会根据历史平方梯度调整步长
• Adam 同时结合动量和自适应学习率
因此,梯度下降是基本思想,优化器是具体算法。
四、学习率:优化器中最重要的超参数
学习率(Learning Rate)是优化器中最重要的超参数之一。
它通常记为:
在更新公式中:
学习率 η 决定每次参数更新的步长。
如果学习率太大,参数更新可能过猛,导致损失震荡甚至发散:
• 步子太大,容易越过最低点
如果学习率太小,训练会非常慢,模型可能长时间无法收敛:
• 步子太小,虽然稳定,但走得太慢
从通俗角度看:学习率决定优化器每次“下山”迈多大一步。
学习率合适时,模型可以较稳定地接近较低损失;学习率不合适时,即使模型结构正确,也可能训练效果很差。
在实际训练中,常见做法包括:
• 先尝试常用默认学习率
• 观察训练损失是否稳定下降
• 使用学习率衰减
• 使用 warmup
• 使用自适应优化器
• 结合验证集表现调整学习率
因此,优化器效果不仅取决于算法本身,也强烈依赖学习率设置。
五、常见优化器之一:SGD
SGD 是随机梯度下降(Stochastic Gradient Descent)的缩写。它是最基础、最经典的优化器之一。
在完整梯度下降中,每次更新参数都使用全部训练数据计算梯度。
但真实数据集往往很大,每次都用全部数据会很慢。
SGD 的思想是:每次只用一个样本或一小批样本估计梯度,然后更新参数。
在现代深度学习中,更常见的是小批量随机梯度下降(Mini-batch SGD)。
更新规则仍然可以写成:
其中:
• L_batch 表示当前小批量样本上的损失
• ∇θL_batch(θ) 表示当前小批量上的梯度
从通俗角度看:SGD 不等看完整本书再总结规律,而是看一小批样本就更新一次。
SGD 的优点是:
• 简单
• 计算开销较低
• 泛化能力常常不错
• 理论和实践都非常成熟
SGD 的局限是:
• 更新方向有噪声
• 对学习率较敏感
• 收敛速度可能较慢
• 在复杂损失地形中可能震荡
因此,SGD 常常和 Momentum、学习率调度等方法一起使用。
六、Momentum:给参数更新加入惯性
Momentum 是在 SGD 基础上加入“动量”的方法。
普通 SGD 每次只根据当前梯度更新参数。
如果梯度方向不断变化,参数可能来回震荡。
Momentum 的思想是:不要只看当前梯度,还要参考过去一段时间的更新方向。
可以写成:
其中:
• v_t 表示第 t 步的速度或动量
• γ 表示动量系数
• η 表示学习率
• ∇θL(θ_t) 表示当前梯度
从通俗角度看,Momentum 像一个带惯性的球在山坡上滚动:
• 如果连续几步方向一致,就加速前进
• 如果某个方向来回震荡,就互相抵消
这使训练通常更加稳定,也可能加快收敛。
Momentum 的优势是:
• 减少震荡
• 加速一致方向上的更新
• 在狭长谷底中表现更好
从实践角度看,Momentum 常用于 SGD 优化深层神经网络,尤其在计算机视觉模型训练中曾经非常常见。
七、Adam:最常用的自适应优化器之一
Adam 是 Adaptive Moment Estimation 的缩写,是现代深度学习中最常用的优化器之一。
它结合了两类思想:
• Momentum:记录梯度的一阶矩,也就是平均方向
• RMSProp 类方法:记录梯度平方的二阶矩,用于调整每个参数的步长
Adam 的核心思想是:不同参数可以根据自己的梯度历史,使用不同的自适应更新幅度。
简化理解,可以认为 Adam 会同时估计:
表示梯度的移动平均;
表示梯度平方的移动平均。
然后用它们调整参数更新。
从通俗角度看:Adam 不只是问“往哪里走”,还会根据历史情况判断“每个参数应该走多快”。
Adam 的优点是:
• 收敛通常较快
• 对学习率相对不那么敏感
• 适合稀疏梯度
• 在自然语言处理、Transformer、大语言模型训练中非常常见
Adam 的局限是:
• 泛化表现不一定总比 SGD 好
• 默认参数虽然常用,但不是所有任务最优
• 在某些任务中需要配合权重衰减、学习率调度和 warmup
在实践中,Adam 或 AdamW 常常是训练神经网络时的默认首选。
八、AdamW 与权重衰减
AdamW 是 Adam 的一个重要变体,尤其常用于 Transformer 和大语言模型训练。
它主要改进了 Adam 中权重衰减的处理方式。
权重衰减(Weight Decay)是一种正则化方法,用来抑制参数过大。
常见思想是让参数更新时额外向 0 收缩:
其中:
• λ 表示权重衰减系数
• θ 表示参数
从通俗角度看:权重衰减像是在训练时提醒模型,参数不要变得太大。
参数过大可能导致模型过度依赖训练数据中的细节,从而增加过拟合风险。
AdamW 的特点是将权重衰减与 Adam 的梯度自适应更新更清楚地分离出来,因此在很多深度学习任务中比普通 Adam 加 L2 正则更稳定。
从实践角度看:
• Adam 常用于一般深度学习训练
• AdamW 常用于 Transformer、大语言模型和预训练模型微调
• 权重衰减可以帮助控制模型复杂度
需要注意,权重衰减不是越大越好。过强的权重衰减可能使模型欠拟合。
九、优化器的优势、局限与使用注意事项
1、优化器的主要作用
优化器的主要作用可以概括为:
• 根据梯度更新参数
• 使损失函数逐步减小
• 控制训练过程的收敛速度
• 影响训练稳定性
• 影响最终模型效果
从通俗角度看:优化器决定模型如何从错误中学习。
同一个模型、同一批数据,如果优化器和学习率选择不同,训练效果可能差别很大。
2、常见优化器如何选择
常见经验是:
• 入门或表格小模型:可以从 SGD、Adam 开始
• 深度神经网络:Adam 是常见默认选择
• Transformer 和大语言模型:AdamW 更常见
• 计算机视觉经典 CNN:SGD + Momentum 仍然常见
• 稀疏特征任务:Adam、Adagrad 等自适应方法可能更方便
不过,这些只是经验,并不是绝对规则。
最终选择要看:
• 数据规模
• 模型结构
• 损失曲线
• 验证集表现
• 训练稳定性
• 泛化效果
3、使用优化器时需要注意的问题
使用优化器时,需要注意:
• 学习率通常比优化器名称更关键
• 损失不下降时,要先检查学习率、数据和损失函数
• 损失震荡可能说明学习率过大
• 训练很慢可能说明学习率过小
• Adam 收敛快,但不一定总是泛化最好
• 权重衰减可以缓解过拟合,但过大可能欠拟合
• 不同参数组可以设置不同学习率
• 训练时通常需要定期观察训练集和验证集曲线
从实践角度看,优化器不是孤立发挥作用的。它必须与学习率、初始化、批量大小、归一化、损失函数和模型结构共同考虑。
十、Python 示例
下面给出几个简单示例,用来帮助理解优化器的基本使用。
示例 1:手动实现一次梯度下降更新
假设有一个简单模型:
损失为:
用 Python 手动更新参数:
# 输入特征、参数和真实值x = 2.0 # 输入特征w = 3.0 # 权重b = 1.0 # 偏置y = 10.0 # 真实标签 learning_rate = 0.1 # 学习率 # 前向传播:计算预测值和损失z = w * x + b # 预测值 = w*x + bloss = (z - y) ** 2 # 平方损失 (预测值 - 真实值)^2 # 手动计算损失对各参数的梯度(链式法则)dL_dz = 2 * (z - y) # ∂L/∂z = 2(z - y)dL_dw = dL_dz * x # ∂L/∂w = ∂L/∂z * ∂z/∂w = dL_dz * xdL_db = dL_dz # ∂L/∂b = ∂L/∂z * ∂z/∂b = dL_dz * 1 # 梯度下降更新参数w = w - learning_rate * dL_dwb = b - learning_rate * dL_db print("更新后的 w:", w)print("更新后的 b:", b)print("更新前损失:", loss) # 注意:更新后损失未重新计算,输出的是更新前的损失这个例子展示了优化器最基本的思想:根据梯度和学习率更新参数。
示例 2:PyTorch 中使用 SGD
import torch # PyTorch框架import torch.nn as nn # 神经网络模块import torch.optim as optim # 优化器模块 # 构造训练数据:y = 2x + 1X = torch.tensor([[1.0], [2.0], [3.0], [4.0]]) # 输入特征y = torch.tensor([[3.0], [5.0], [7.0], [9.0]]) # 真实标签 # 线性模型:输入1维,输出1维model = nn.Linear(1, 1) # 均方误差损失函数loss_fn = nn.MSELoss() # SGD优化器,学习率0.01optimizer = optim.SGD(model.parameters(), lr=0.01) # 训练1000轮for epoch in range(1000): optimizer.zero_grad() # 清空梯度 y_pred = model(X) # 前向传播:预测值 loss = loss_fn(y_pred, y) # 计算损失 loss.backward() # 反向传播,计算梯度 optimizer.step() # 更新参数 print("权重:", model.weight.item()) # 应接近2.0print("偏置:", model.bias.item()) # 应接近1.0print("最终损失:", loss.item()) # 接近0这个训练流程中:
• optimizer.zero_grad() 清空上一轮梯度
• loss.backward() 计算当前梯度
• optimizer.step() 根据梯度更新参数
这就是 PyTorch 中最常见的训练循环结构。
示例 3:PyTorch 中使用 Adam
import torch # PyTorch框架import torch.nn as nn # 神经网络模块import torch.optim as optim # 优化器模块 # 训练数据:y = 2x + 1X = torch.tensor([[1.0], [2.0], [3.0], [4.0]]) # 输入特征y = torch.tensor([[3.0], [5.0], [7.0], [9.0]]) # 真实标签 # 线性回归模型(输入1维,输出1维)model = nn.Linear(1, 1) # 均方误差损失函数loss_fn = nn.MSELoss() # Adam优化器(自适应学习率),学习率0.01optimizer = optim.Adam(model.parameters(), lr=0.01) # 训练1000轮for epoch in range(1000): optimizer.zero_grad() # 清空梯度 y_pred = model(X) # 前向传播:预测值 loss = loss_fn(y_pred, y) # 计算损失 loss.backward() # 反向传播,计算梯度 optimizer.step() # 更新参数 # 输出训练结果print("权重:", model.weight.item()) # 应接近2.0print("偏置:", model.bias.item()) # 应接近1.0print("最终损失:", loss.item()) # 接近0这个例子中,Adam 会根据梯度历史自适应调整参数更新幅度。
从通俗角度看:SGD 更像固定步长下山,Adam 更像会根据路况自动调整步伐。
示例 4:使用 AdamW 和权重衰减
import torch # PyTorch框架import torch.nn as nn # 神经网络模块import torch.optim as optim # 优化器模块 # 定义一个简单的分类模型:4维输入 → ReLU → 3维输出(logits)model = nn.Sequential( nn.Linear(4, 16), # 全连接层:4 → 16 nn.ReLU(), # ReLU激活 nn.Linear(16, 3) # 输出层:16 → 3) # AdamW 优化器(Adam with weight decay),学习率0.001,权重衰减0.01optimizer = optim.AdamW( model.parameters(), # 待优化的模型参数 lr=0.001, # 学习率 weight_decay=0.01 # 权重衰减(L2正则化)) print(optimizer) # 打印优化器配置这个例子中:
• lr=0.001 表示学习率
• weight_decay=0.01 表示权重衰减系数
• AdamW 常用于 Transformer、预训练模型和许多现代深度学习任务
示例 5:观察不同学习率的影响
import torchimport torch.nn as nnimport torch.optim as optim def train_with_lr(lr): """使用指定学习率训练线性模型,返回最终损失""" # 训练数据:y = 2x + 1 X = torch.tensor([[1.0], [2.0], [3.0], [4.0]]) y = torch.tensor([[3.0], [5.0], [7.0], [9.0]]) # 线性模型(输入1维,输出1维) model = nn.Linear(1, 1) loss_fn = nn.MSELoss() # 均方误差损失 optimizer = optim.SGD(model.parameters(), lr=lr) # SGD优化器 # 训练100轮 for epoch in range(100): optimizer.zero_grad() # 清空梯度 y_pred = model(X) # 前向传播 loss = loss_fn(y_pred, y) # 计算损失 loss.backward() # 反向传播 optimizer.step() # 更新参数 return loss.item() # 返回最终损失值 # 测试不同学习率对训练效果的影响for lr in [0.0001, 0.01, 1.0]: final_loss = train_with_lr(lr) print(f"学习率 {lr},最终损失:{final_loss}")这个例子可以观察:
• 学习率太小,训练可能很慢
• 学习率合适,损失下降较稳定
• 学习率太大,训练可能震荡或发散
因此,在实际训练中,学习率往往是最需要认真调节的超参数之一。
📘 小结
优化器是模型训练中根据梯度更新参数的算法。反向传播负责计算梯度,优化器负责利用梯度调整权重和偏置,使损失函数逐渐减小。SGD 是最基础的优化器,Momentum 引入历史方向,Adam 使用自适应更新,AdamW 常用于现代深度学习和大模型训练。对初学者而言,可以把优化器理解为:模型根据错误得到梯度后,真正决定参数如何迈出下一步的学习规则。
“点赞有美意,赞赏是鼓励”