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

Python 梯度下降法(六):Nadam Optimize

文章目录

  • Python 梯度下降法(六):Nadam Optimize
    • 一、数学原理
      • 1.1 介绍
      • 1.2 符号定义
      • 1.3 实现流程
    • 二、代码实现
      • 2.1 函数代码
      • 2.2 总代码
    • 三、优缺点
      • 3.1 优点
      • 3.2 缺点
    • 四、相关链接

Python 梯度下降法(六):Nadam Optimize

一、数学原理

1.1 介绍

Nadam(Nesterov-accelerated Adaptive Moment Estimation)优化算法是 Adam 优化算法的改进版本,结合了 Nesterov 动量(Nesterov Momentum)和 Adam 算法的优点。

Nadam 在 Adam 算法的基础上引入了 Nesterov 动量的思想。Adam 算法通过计算梯度的一阶矩估计(均值)和二阶矩估计(未中心化的方差)来自适应地调整每个参数的学习率。而 Nesterov 动量则是在计算梯度时,考虑了参数在动量作用下未来可能到达的位置的梯度,从而让优化过程更具前瞻性。

1.2 符号定义

设置一下超参数:

参数说明
η \eta η学习率,控制参数更新的步长
m m m一阶矩估计,梯度均值
β 1 \beta_{1} β1一阶矩指数衰减率,通常取 0.9 0.9 0.9
v v v二阶矩估计,梯度未中心化方差
β 2 \beta_{2} β2二阶矩指数衰减率,通常取 0.999 0.999 0.999
ϵ \epsilon ϵ无穷小量,用于避免分母为零, 1 0 − 8 10^{-8} 108
g t g_{t} gt t t t时刻位置的梯度
θ \theta θ需要进行拟合的参数

1.3 实现流程

  1. 初始化参数: θ n × 1 \theta_{n\times 1} θn×1 m 0 ⃗ n × 1 = 0 \vec{m_{0}}_{n\times 1}=0 m0 n×1=0 v 0 ⃗ n × 1 = 0 \vec{v_{0}}_{n\times 1}=0 v0 n×1=0
  2. 更新一阶矩估计 m t m_{t} mt m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_{t}=\beta_{1}m_{t-1}+(1-\beta_{1})g_{t} mt=β1mt1+(1β1)gt
  3. 更新二阶矩估计 v t v_{t} vt v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_{t}=\beta_{2}v_{t-1}+(1-\beta_{2})g_{t}^{2} vt=β2vt1+(1β2)gt2
  4. 偏差修正:由于 m 0 , v 0 = 0 m_{0},v_{0}=0 m0,v0=0,在训练初期会存在偏差,需要进行修正: m ^ t = m t 1 − β 1 t , v ^ t = v t 1 − β 2 t \hat{m}_{t}=\frac{m_{t}}{1-\beta_{1}^{t}},\hat{v}_{t}=\frac{v_{t}}{1-\beta_{2}^{t}} m^t=1β1tmt,v^t=1β2tvt
  5. 计算预估一阶矩: m ~ t = β 1 m ^ t + ( 1 − β 1 ) g t 1 − β 1 t \widetilde{m}_{t}=\beta_{1}\hat{m}_{t}+\frac{(1-\beta_{1})g_{t}}{1-\beta_{1}^{t}} m t=β1m^t+1β1t(1β1)gt
  6. 更新模型参数 θ t \theta_{t} θt θ t = θ t − 1 − η v t ^ + ϵ ⊙ m ~ t \theta_{t}=\theta_{t-1}-\frac{\eta}{\sqrt{ \hat{v_{t}} }+\epsilon}\odot\widetilde{m}_{t} θt=θt1vt^ +ϵηm t

二、代码实现

2.1 函数代码

# 定义 Nadam 函数
def nadam_optimizer(X, y, eta, num_iter=1000, beta1=0.9, beta2=0.999, epsilon=1e-8, threshold=1e-8):
    """
    X: 数据 x  mxn,可以在传入数据之前进行数据的归一化
    y: 数据 y  mx1
    eta: 学习率
    num_iter: 迭代次数
    beta: 衰减率
    epsilon: 无穷小
    threshold: 阈值
    """
    m, n = X.shape
    theta, mt, vt = np.random.randn(n, 1), np.zeros((n, 1)), np.zeros((n, 1))  # 初始化数据
    loss_ = []
    
    for t in range(1, num_iter + 1):
        
        # 计算梯度
        h = X.dot(theta)
        err = h - y
        loss_.append(np.mean(err ** 2) / 2)
        g = (1 / m) * X.T.dot(err)
                
        # 一阶矩估计
        mt = beta1 * mt + (1 - beta1) * g
        # 二阶矩估计
        vt = beta2 * vt + (1 - beta2) * g ** 2

        # 先计算偏差修正,后面需要使用到,并且去除负数
        m_hat, v_hat = mt / (1 - pow(beta1, t)), np.maximum(vt / (1 - pow(beta2, t)), 0)

        # 计算预估一阶矩
        m_pre = beta1 * m_hat + (1 - beta1) * g / (1 - pow(beta1, t))
        
        # 更新参数
        theta = theta - np.multiply((eta / (np.sqrt(v_hat) + epsilon)), m_pre)

        # 检查是否收敛
        if t > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
            print(f"Converged at iteration {t}")
            break

    return theta.flatten(), loss_

2.2 总代码

import numpy as np
import matplotlib.pyplot as plt

# 设置 matplotlib 支持中文
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

# 定义 Nadam 函数
def nadam_optimizer(X, y, eta, num_iter=1000, beta1=0.9, beta2=0.999, epsilon=1e-8, threshold=1e-8):
    """
    X: 数据 x  mxn,可以在传入数据之前进行数据的归一化
    y: 数据 y  mx1
    eta: 学习率
    num_iter: 迭代次数
    beta: 衰减率
    epsilon: 无穷小
    threshold: 阈值
    """
    m, n = X.shape
    theta, mt, vt = np.random.randn(n, 1), np.zeros((n, 1)), np.zeros((n, 1))  # 初始化数据
    loss_ = []
    
    for t in range(1, num_iter + 1):
        
        # 计算梯度
        h = X.dot(theta)
        err = h - y
        loss_.append(np.mean(err ** 2) / 2)
        g = (1 / m) * X.T.dot(err)
                
        # 一阶矩估计
        mt = beta1 * mt + (1 - beta1) * g
        # 二阶矩估计
        vt = beta2 * vt + (1 - beta2) * g ** 2

        # 先计算偏差修正,后面需要使用到,并且去除负数
        m_hat, v_hat = mt / (1 - pow(beta1, t)), np.maximum(vt / (1 - pow(beta2, t)), 0)

        # 计算预估一阶矩
        m_pre = beta1 * m_hat + (1 - beta1) * g / (1 - pow(beta1, t))
        
        # 更新参数
        theta = theta - np.multiply((eta / (np.sqrt(v_hat) + epsilon)), m_pre)

        # 检查是否收敛
        if t > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
            print(f"Converged at iteration {t}")
            break

    return theta.flatten(), loss_


# 生成一些示例数据
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
# 添加偏置项
X_b = np.c_[np.ones((100, 1)), X]

# 超参数
eta = 0.1

# 运行 Nadam 优化器
theta, loss_ = nadam_optimizer(X_b, y, eta)
print("最优参数 theta:")
print(theta)

# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_, label="损失函数图像")
plt.title("损失函数图像")
plt.xlabel("迭代次数")
plt.ylabel("损失值")
plt.legend()  # 显示图例
plt.grid(True)  # 显示网格线
plt.show()

1738389513_xunsrs0jxa.png1738389512232.png

三、优缺点

3.1 优点

自适应学习率:NAdam 继承了 Adam 的自适应学习率特性,能够根据梯度的一阶矩(均值)和二阶矩(方差)动态调整每个参数的学习率。这使得 NAdam 在处理不同尺度的参数时更加高效,尤其适合稀疏梯度问题。

Nesterov 动量:NAdam 引入了 Nesterov 动量,能够在更新参数时先根据当前动量预测参数的未来位置,再计算梯度。这种“前瞻性”的更新方式使得 NAdam 能够更准确地调整参数,从而加速收敛。

快速收敛:由于结合了 Adam 的自适应学习率和 Nesterov 动量的前瞻性更新,NAdam 在大多数优化问题中能够比 Adam 和传统梯度下降法更快地收敛。特别是在非凸优化问题中,NAdam 的表现通常优于其他优化算法。

鲁棒性:NAdam 对超参数的选择相对鲁棒,尤其是在学习率和动量参数的选择上。这使得 NAdam 在实际应用中更容易调参。

适合大规模数据:NAdam 能够高效处理大规模数据集和高维参数空间,适合深度学习中的大规模优化问题。

3.2 缺点

计算复杂度较高:由于 NAdam 需要同时维护一阶矩和二阶矩估计,并计算 Nesterov 动量,其计算复杂度略高于传统的梯度下降法。虽然现代深度学习框架(如 PyTorch、TensorFlow)已经对 NAdam 进行了高效实现,但在某些资源受限的场景下,计算开销仍然是一个问题。

对初始学习率敏感:尽管 NAdam 对超参数的选择相对鲁棒,但初始学习率的选择仍然对性能有较大影响。如果初始学习率设置不当,可能会导致收敛速度变慢或无法收敛。

可能陷入局部最优:在某些复杂的非凸优化问题中,NAdam 可能会陷入局部最优解,尤其是在损失函数存在大量鞍点或平坦区域时。

内存占用较高:NAdam 需要存储一阶矩和二阶矩估计,这会增加内存占用。对于非常大的模型(如 GPT-3 等),内存占用可能成为一个瓶颈。

理论分析较少:相比于 Adam 和传统的梯度下降法,NAdam 的理论分析相对较少。虽然实验结果表明 NAdam 在大多数任务中表现优异,但其理论性质仍需进一步研究。

四、相关链接

Python 梯度下降法合集:

  • Python 梯度下降法(一):Gradient Descent-CSDN博客
  • Python 梯度下降法(二):RMSProp Optimize-CSDN博客
  • Python 梯度下降法(三):Adagrad Optimize-CSDN博客
  • Python 梯度下降法(四):Adadelta Optimize-CSDN博客
  • Python 梯度下降法(五):Adam Optimize-CSDN博客
  • Python 梯度下降法(六):Nadam Optimize-CSDN博客
  • Python 梯度下降法(七):Summary-CSDN博客

http://www.kler.cn/a/529232.html

相关文章:

  • 全面认识了解DeepSeek+利用ollama在本地部署、使用和体验deepseek-r1大模型
  • 99.24 金融难点通俗解释:MLF(中期借贷便利)vs LPR(贷款市场报价利率)
  • unity学习24:场景scene相关生成,加载,卸载,加载进度,异步加载场景等
  • SQLite Update 语句详解
  • 实现网站内容快速被搜索引擎收录的方法
  • pytorch实现文本摘要
  • yes镜像站群/PHP驱动的镜像站群架构实践
  • 数据库安全管理中的用户和角色管理:打造安全高效的数据环境
  • 什么是Rust?它有什么特点?为什么要学习Rust?
  • 微信小程序实战0 设置
  • 【llm对话系统】大模型 Llama、Qwen 和 ChatGLM 的网络结构和训练方法对比
  • 1.4 Go 数组
  • MySQL知识点总结(十七)
  • 计算机网络之物理层通信基础(奈奎斯特定理与香农定理)
  • UE 导入sbsar插件
  • 【大模型LLM面试合集】大语言模型架构_MHA_MQA_GQA
  • 使用C# 如何获取本机连接的WIFI名称[C# ---1]
  • InnoSetup使用教程笔记
  • Anaconda 全面解析:从入门到精通的操作教程
  • MiniMind——跑通项目
  • Java知识速记 == 与equals
  • 截止到2025年2月1日,Linux的Wayland还有哪些问题是需要解决的?
  • 群晖搭建Gitea教程(使用系统自带的postgresql)
  • 用 JavaScript 打造交互式表格:添加与删除行功能
  • Linux文件类型
  • 台账思维和GIS思维在资产管理中的不同模式