通俗易懂讲透Adam优化器(本科生/研究生都能看懂)

本文用直白语言+形象比喻+公式拆解+可运行代码,把Adam优化器讲得明明白白,不用复杂数学基础也能完全理解,适合深度学习入门、面试复习、课程笔记。


一、先搞懂:Adam到底是什么?

Adam = 自适应矩估计(Adaptive Moment Estimation)
它是深度学习最常用、最万能的优化器,相当于:

动量法 + RMSProp 的结合体

一句话总结:
Adam 会记住历史更新方向,还会根据梯度大小自动调步子,又快又稳找到最优解。

超形象比喻

你在下山找最低点(最小损失):

  • 动量法:记住你刚才往哪走,顺着惯性加速,不原地晃
  • RMSProp:看坡度陡不陡,陡就走小步,平就走大步
  • Adam既有惯性,又会看路,智能下山

二、Adam 核心思想(不用公式也能懂)

  1. 一阶动量(m):梯度的移动平均,相当于“惯性”,顺着趋势走,减少震荡
  2. 二阶动量(v):梯度平方的移动平均,相当于“看坡度”,自动调学习率
  3. 偏差校正:刚开始训练时数据不准,修正一下,让前期更稳定
  4. 参数更新:用校正后的动量,智能调整每一步

三、Adam 公式一步步拆解(超详细)

0. 先看普通梯度下降(对照)

θt+1=θt−α⋅gt\theta_{t+1} = \theta_t - \alpha \cdot g_tθt+1=θtαgt
固定学习率,所有参数步子一样,很笨。


1. 初始化(超简单)

  • 学习率 α\alphaα:默认 0.001
  • 一阶动量系数 β1\beta_1β1:默认 0.9
  • 二阶动量系数 β2\beta_2β2:默认 0.999
  • 防除零 ϵ\epsilonϵ10−810^{-8}108
  • 动量初始值:m0=0, v0=0m_0=0,\ v_0=0m0=0, v0=0

2. 计算梯度

gt=∇L(θt)g_t = \nabla L(\theta_t)gt=L(θt)
梯度就是当前参数该往哪改、改多少。


3. 更新一阶动量(惯性)

mt=β1mt−1+(1−β1)gtm_t = \beta_1 m_{t-1} + (1-\beta_1) g_tmt=β1mt1+(1β1)gt

  • 保留上一步的惯性
  • 加上当前梯度
  • 让更新更顺滑,不抖动

4. 更新二阶动量(看坡度)

vt=β2vt−1+(1−β2)gt2v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2vt=β2vt1+(1β2)gt2

  • 记录梯度平方的平滑值
  • 梯度大 → vvv 大 → 学习率变小
  • 梯度小 → vvv 小 → 学习率变大

5. 偏差校正(关键!)

刚开始 mmmvvv 都接近0,不准,所以要校正:
m^t=mt1−β1t\hat{m}_t = \frac{m_t}{1-\beta_1^t}m^t=1β1tmt
v^t=vt1−β2t\hat{v}_t = \frac{v_t}{1-\beta_2^t}v^t=1β2tvt
让前期训练更稳定。


6. 最终参数更新(Adam 核心)

θt+1=θt−α⋅m^tv^t+ϵ\theta_{t+1} = \theta_t - \alpha \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t}+\epsilon}θt+1=θtαv^t +ϵm^t

✅ 含义:

  • 惯性方向 m^\hat{m}m^ 决定往哪走
  • 梯度大小 v^\sqrt{\hat{v}}v^ 决定走多快
  • 每个参数独立自适应学习率

四、Adam 完整流程(7步背下来)

  1. 初始化参数 θ\thetaθ、动量 m=0,v=0m=0, v=0m=0,v=0
  2. 计算当前梯度 gtg_tgt
  3. 更新一阶动量 mtm_tmt
  4. 更新二阶动量 vtv_tvt
  5. 做偏差校正得到 m^t\hat{m}_tm^tv^t\hat{v}_tv^t
  6. 用校正动量更新参数 θ\thetaθ
  7. 重复直到收敛

五、PyTorch 实战代码(可直接复制运行)

用Adam训练简单神经网络做回归,带可视化。

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 1. 生成虚拟回归数据
X, y = make_regression(n_samples=2000, n_features=10, noise=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 转为Tensor
X_train = torch.tensor(X_train, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32).view(-1, 1)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_test = torch.tensor(y_test, dtype=torch.float32).view(-1, 1)

# 标准化
scaler = StandardScaler()
X_train = torch.tensor(scaler.fit_transform(X_train), dtype=torch.float32)
X_test = torch.tensor(scaler.transform(X_test), dtype=torch.float32)

# 2. 搭建简单神经网络
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(10, 64)
        self.fc2 = nn.Linear(64, 64)
        self.fc3 = nn.Linear(64, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x

model = Net()

# 3. 损失函数 + Adam优化器(核心!)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)  # 直接用Adam

# 4. 训练
epochs = 200
train_loss = []
test_loss = []

for epoch in range(epochs):
    model.train()
    optimizer.zero_grad()

    # 前向传播
    outputs = model(X_train)
    loss = criterion(outputs, y_train)

    # 反向传播 + Adam更新
    loss.backward()
    optimizer.step()

    train_loss.append(loss.item())

    # 测试集损失
    model.eval()
    with torch.no_grad():
        pred = model(X_test)
        t_loss = criterion(pred, y_test)
        test_loss.append(t_loss.item())

    if (epoch + 1) % 20 == 0:
        print(f"Epoch [{epoch+1}/{epochs}], Train Loss: {loss.item():.4f}, Test Loss: {t_loss.item():.4f}")

# 5. 可视化结果
plt.figure(figsize=(14, 6))

# 损失曲线
plt.subplot(1, 2, 1)
plt.plot(train_loss, label="Train Loss", linewidth=2)
plt.plot(test_loss, label="Test Loss", linewidth=2, linestyle="--")
plt.title("Train vs Test Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.grid()

# 预测 vs 真实
plt.subplot(1, 2, 2)
with torch.no_grad():
    y_pred = model(X_test).numpy()
plt.scatter(y_test.numpy(), y_pred, alpha=0.7, s=30)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', linewidth=2)
plt.xlabel("True Value")
plt.ylabel("Predict Value")
plt.title("Predict vs True")
plt.grid()

plt.tight_layout()
plt.show()

六、Adam 优点(面试必背)

  1. 自适应学习率:每个参数自动调整,不用手动衰减
  2. 收敛超快:结合动量+RMSProp,比普通SGD快很多
  3. 稳定性强:偏差校正让前期训练更稳
  4. 适用范围极广:CNN、RNN、Transformer、GAN都能用
  5. 对稀疏梯度友好:NLP、推荐系统效果好

七、Adam 缺点(真实工程要知道)

  1. 可能收敛不充分:后期步子太小,难到全局最优
  2. 小数据集易过拟合
  3. 对超参数有一点敏感(但默认值基本够用)
  4. 某些场景不如SGD(比如特别注重泛化的任务)

八、Adam 最适合哪些场景?

深度学习必用:CNN、RNN、Transformer
稀疏数据:NLP、推荐系统、文本分类
大规模数据:ImageNet、大规模语音/视频
不稳定损失:GAN、强化学习
不想手动调学习率:快速实验、炼丹


九、Adam vs SGD vs AdaGrad 速记

优化器 优点 缺点 适用场景
SGD 简单、泛化好 慢、要调学习率 小数据集、高精度
AdaGrad 自适应、稀疏好 学习率衰减太快 凸优化、小模型
Adam 快、稳、自适应 可能收敛不充分 深度学习首选

十、一句话总结

Adam = 动量 + RMSProp + 偏差校正
它是深度学习最通用、最省心的优化器,收敛快、稳定性强,几乎适合所有深度模型。
如果不知道选什么优化器,直接用 Adam!

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐