当前位置: 首页 > news >正文

完整教程:【人工智能】神经网络的优化器optimizer(四):Adam自适应动量优化器

完整教程:【人工智能】神经网络的优化器optimizer(四):Adam自适应动量优化器

一.算法背景

        Adam(Adaptive Moment Estimation)是一种广泛应用于深度学习模型训练的自适应优化算法,由Diederik P. Kingma和Jimmy Lei Ba于2014年提出,旨在解决传统优化算法在深度学习中的局限性。它融合了Momentum动量优化器和RMSProp动态自适应学习率优化器两种主流优化技术的优势。

二.数学公式

        Adam优化器通过计算梯度的一阶矩(均值)和二阶矩(方差)来为每个参数自适应地调整学习率。其数学实现步骤如下:

        一阶矩阵估计(动量项,类似于动量优化器中的动量计算,记录梯度的指数加权平均值):

m_{t}=\beta_{1} m_{t-1}+(1-\beta _{1}^{t})g_{t}

        二阶矩阵估计(自适应学习率项,类似于RMSProp,记录梯度平方的指数加权平均值):

V_{t}=\beta_{2} V_{t-1}+(1-\beta _{2}^{t})g_{t}

        偏差修正(下面会说为什么要做这个):

m_{t}=\frac{m_{t}}{1-\beta_{1}^{t}}

V_{t}=\frac{V_{t}}{1-\beta_{2}^{t}}

        参数更新(和前几个优化器的更新流程一样):

\Theta _{t+1}=\Theta _{t}-\eta \cdot \frac{m_{t}}{\sqrt{V_{t}+\epsilon }}

        代码实现如下:

import numpy as np
from collections import OrderedDict
import matplotlib.pyplot as plt
class Adam:def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):self.lr = lrself.beta1 = beta1self.beta2 = beta2self.iter = 0self.m = Noneself.v = Nonedef update(self, params, grads):if self.m is None:self.m, self.v = {}, {}for key, val in params.items():self.m[key] = np.zeros_like(val)self.v[key] = np.zeros_like(val)self.iter += 1lr_t  = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)for key in params.keys():self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
optimizers= Adam(lr=0.3)
init_pos = (-7.0, 2.0)
params = {}
params['x'], params['y'] = init_pos[0], init_pos[1]
grads = {}
grads['x'], grads['y'] = 0, 0
x_history = []
y_history = []
def f(x, y):return x**2 / 20.0 + y**2
def df(x, y):return x / 10.0, 2.0*y
for i in range(30):x_history.append(params['x'])y_history.append(params['y'])grads['x'], grads['y'] = df(params['x'], params['y'])optimizers.update(params, grads)
x = np.arange(-10, 10, 0.01)
y = np.arange(-5, 5, 0.01)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
# for simple contour line
mask = Z > 7
Z[mask] = 0
idx = 1# plot
plt.subplot(2, 2, idx)
idx += 1
plt.plot(x_history, y_history, 'o-', color="red")
plt.contour(X, Y, Z)
plt.ylim(-10, 10)
plt.xlim(-10, 10)
plt.plot(0, 0, '+')
# colorbar()
# spring()
plt.title("Momentum")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

        运行结果如下:

三.为什么要进行偏差修正

        它解决了指数加权平均在初始阶段的估计偏差问题。Adam优化器使用指数加权移动平均(EWMA)来计算梯度的一阶矩(m)和二阶矩(v)估计。在初始阶段,这些估计值会存在系统性偏差,原因在于:

  1. 初始化问题‌:m和v通常初始化为0向量,导致初始估计明显偏低,在t较小时,1-\beta ^{t}接近于0,导致未修正的m和v远小于真实梯度统计量,计算出的学习率会异常偏大。

  2. 指数加权特性‌:早期时间步的估计值受初始值影响较大, 修正项随着t的增加逐渐趋近于1,在训练后期影响变小,但在初期至关重要。

  3. 训练不稳定:参数更新幅度在初期波动剧烈,可能错过合理的优化方向,增加收敛到次优解的风险,需要更多迭代次数才能克服初始偏差,特别是在稀疏梯度问题上表现更差。

        进行偏差修正后,从第一轮迭代就开始积累有意义的梯度统计量,加速模型早期的学习过程,减少对初期学习率的敏感度,使默认参数(β₁=0.9, β₂=0.999)在大多数情况下都能良好工作。

        误差修正通过以下数学公式实现:

m_{t}=\frac{m_{t}}{1-\beta_{1}^{t}}

V_{t}=\frac{V_{t}}{1-\beta_{2}^{t}}

        其中:

  • \beta _{1}\beta_{2}是衰减率(通常取0.9和0.999)

  • t是当前时间步(迭代次数)

  • m_{t}v_{t}是未修正的矩估计

        以下使用代码对不进行偏差修正和进行偏差修正的参数更新轨迹和损失函数收敛的对比:

import numpy as np
import matplotlib.pyplot as plt
class AdamWithCorrection:"""带误差修正的Adam优化器"""def __init__(self, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):self.learning_rate = learning_rateself.beta1 = beta1self.beta2 = beta2self.epsilon = epsilonself.m = Noneself.v = Noneself.t = 0self.history = {'params': [], 'loss': []}def update(self, params, grads, loss):if self.m is None:self.m = np.zeros_like(params)self.v = np.zeros_like(params)self.t += 1self.m = self.beta1 * self.m + (1 - self.beta1) * gradsself.v = self.beta2 * self.v + (1 - self.beta2) * (grads ** 2)# 误差修正m_hat = self.m / (1 - self.beta1 ** self.t)v_hat = self.v / (1 - self.beta2 ** self.t)params -= self.learning_rate * m_hat / (np.sqrt(v_hat) + self.epsilon)self.history['params'].append(params.copy())self.history['loss'].append(loss)return params
class AdamWithoutCorrection:"""不带误差修正的Adam优化器"""def __init__(self, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):self.learning_rate = learning_rateself.beta1 = beta1self.beta2 = beta2self.epsilon = epsilonself.m = Noneself.v = Noneself.t = 0self.history = {'params': [], 'loss': []}def update(self, params, grads, loss):if self.m is None:self.m = np.zeros_like(params)self.v = np.zeros_like(params)self.t += 1self.m = self.beta1 * self.m + (1 - self.beta1) * gradsself.v = self.beta2 * self.v + (1 - self.beta2) * (grads ** 2)# 无误差修正params -= self.learning_rate * self.m / (np.sqrt(self.v) + self.epsilon)self.history['params'].append(params.copy())self.history['loss'].append(loss)return params
# 定义优化问题
def loss_function(x):return np.sum(0.5 * x**2)  # 简单的二次函数
def gradient_function(x):return x  # 梯度就是x本身
# 初始化参数
params_corr = np.array([3.0, -2.0])
params_no_corr = params_corr.copy()
# 初始化优化器
optimizer_corr = AdamWithCorrection(learning_rate=0.1)
optimizer_no_corr = AdamWithoutCorrection(learning_rate=0.1)
# 优化过程
for i in range(100):grads_corr = gradient_function(params_corr)grads_no_corr = gradient_function(params_no_corr)loss_corr = loss_function(params_corr)loss_no_corr = loss_function(params_no_corr)params_corr = optimizer_corr.update(params_corr, grads_corr, loss_corr)params_no_corr = optimizer_no_corr.update(params_no_corr, grads_no_corr, loss_no_corr)
# 可视化结果
plt.figure(figsize=(15, 5))
# 1. 参数轨迹对比
plt.subplot(1, 2, 1)
params_history_corr = np.array(optimizer_corr.history['params'])
params_history_no_corr = np.array(optimizer_no_corr.history['params'])
plt.plot(params_history_corr[:, 0], params_history_corr[:, 1], label='With Correction', color='blue')
plt.plot(params_history_no_corr[:, 0], params_history_no_corr[:, 1], label='Without Correction', color='red')
plt.scatter([0], [0], color='green', marker='*', s=200, label='Optimal Point')
plt.title('Parameter Trajectory Comparison')
plt.xlabel('Parameter 1')
plt.ylabel('Parameter 2')
plt.legend()
plt.grid(True)
# 2. 损失曲线对比
plt.subplot(1, 2, 2)
plt.plot(optimizer_corr.history['loss'], label='With Correction', color='blue')
plt.plot(optimizer_no_corr.history['loss'], label='Without Correction', color='red')
plt.title('Loss Convergence Comparison')
plt.xlabel('Iteration')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

        运行代码可以清晰地看到两者之间的区别:

四.和其他优化器的对比

        与其他优化器的对比:

        特点对比:

特性AdamSGDMomentumRMSProp
自适应学习率
动量机制
参数独立调整
偏差修正
收敛速度中等中等
超参数数量4123
http://www.jsqmd.com/news/46948/

相关文章:

  • 轻松速通:TTS播放、文件播放与录音的核心功能解析!
  • 2025 中国法兰阀门十大品牌推荐:密封升级 + 场景适配,优质厂家护航流体系统安全
  • FPGA专用CLKUSR时钟引脚严重警告——Cyclone 10 GX
  • OPCUA探讨(五)——客户端代码解读:监控变量值与报警
  • 2025 年度中国截止阀十大品牌推荐:绿色智造 + 特种工况突破,引领行业高质量发展
  • 修改DTS适配遥控用户码
  • nginx性能优化之tcp调优
  • 2025年11月安徽聚乙烯瓶、高阻隔瓶、聚酯瓶、农药瓶供应商排行榜:安徽金汇龙包装领跑行业
  • 2025年11月中国/安徽/聚乙烯瓶、高阻隔瓶、聚酯瓶、农药瓶厂家TOP10推荐:安徽金汇龙包装强势登顶
  • rich dataset 3D人体场景数据集
  • ICPC2025沈阳打铁日志
  • UModel 数据治理:运维世界模型构建实践
  • 【springboot】 WebMvcConfigurer的使用
  • 2025年11月21日
  • 实用指南:一文搞懂 DeepSeek API:兼容 OpenAI 接口的智能对话模型调用指南
  • 形容词Test
  • James Watsons
  • 2025年11月江苏/徐州vr设备、vr体验馆、5d影院、9d影院、拓普互动厂家推荐榜:拓普互动强势登顶
  • 计算机网络:物理层 - 实践
  • 2025年11月中国/江苏/徐州vr设备、vr体验馆、5d影院、9d影院、拓普互动厂家TOP10:拓普互动领跑榜单
  • MongoDB 平替新方案:金仓多模数据库驱动电子证照国产化落地 - 详解
  • 高考数学如何有效提分?一位家长关于分阶段选择数学老师的心得体会
  • 最佳加密货币钱包选择指南:企业级安全与功能全解析
  • 让 Maven 能找到本地 JAR 而无需把它上传到公共仓库:
  • Windows Server 2019 中文版、英文版下载 (2025 年 11 月更新)
  • TSMaster + SkyEye:更早、更快、更全面的数字化验证正在成为行业共识
  • 2025年11月中国/江苏/徐州MPP电力管,PE管,喷灌机管,建筑排水管,虹吸管综合评测与权威推荐榜单
  • Windows 11 25H2 | 24H2 中文版、英文版 (x64、ARM64) 下载 (2025 年 11 月更新)
  • python-oop-1
  • 留学中介文书原创占比谁最大?业内锐评的专业榜单来了!