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

news/2025/2/2 23:28:07 标签: python, 开发语言

文章目录

  • 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 函数代码

python"># 定义 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 总代码

python">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.niftyadmin.cn/n/5840359.html

相关文章

5.攻防世界simple_php

打开题目页面如下 看到是PHP代码&#xff0c;进行代码审计 <?php // 显示当前 PHP 文件的源代码 show_source(__FILE__); // 从 HTTP GET 请求中获取名为 a 的参数的值&#xff0c;并将其赋值给变量 $a。 // 符号是错误抑制符&#xff0c;它会抑制可能出现的未定义索引警…

Java基础知识总结(三十七)--io异常的处理方式

io一定要写finally&#xff1b; 写入数据的细节&#xff1a; 1&#xff1a;window中的换行符&#xff1a;\r\n两个符号组成。 linux&#xff1a;\n。 2&#xff1a;续写数据&#xff0c;只要在构造方法中传入新的参数true。 3&#xff1a;目录分割符&#xff1a;window \\ …

【华为OD-E卷 - 连续出牌数量 100分(python、java、c++、js、c)】

【华为OD-E卷 - 连续出牌数量 100分&#xff08;python、java、c、js、c&#xff09;】 题目 有这么一款单人卡牌游戏&#xff0c;牌面由颜色和数字组成&#xff0c;颜色为红、黄、蓝、绿中的一种&#xff0c;数字为0-9中的一个。游戏开始时玩家从手牌中选取一张卡牌打出&…

【Java异步编程】基于任务类型创建不同的线程池

文章目录 一. 按照任务类型对线程池进行分类1. IO密集型任务的线程数2. CPU密集型任务的线程数3. 混合型任务的线程数 二. 线程数越多越好吗三. Redis 单线程的高效性 使用线程池的好处主要有以下三点&#xff1a; 降低资源消耗&#xff1a;线程是稀缺资源&#xff0c;如果无限…

为AI聊天工具添加一个知识系统 之79 详细设计之20 正则表达式 之7

本文要点 要点 “正则表达式” 本来是计算机科学计算机科学的一个概念。本项目将它推广&#xff08;扩张&#xff09;到认知科学的“认知范畴”概念&#xff0c; 聚合&#xff08;收敛&#xff09;到 神经科学 的“神经元”概念。 做法是&#xff1a;用reg 来系统化定义认知…

litemall,又一个小商场系统

litemall Spring Boot后端 Vue管理员前端 微信小程序用户前端 Vue用户移动端 代码地址&#xff1a;litemall: 又一个小商城。 litemall Spring Boot后端 Vue管理员前端 微信小程序用户前端 Vue用户移动端

数据结构:优先级队列—堆

一、优先级队列 1、优先级队列概念 优先级队列&#xff0c;听名字我们就知道他是一种队列&#xff0c;队列在前面我们已经学习过了&#xff0c;它是一种先进先出的数据结构&#xff0c;但是在特殊的情况下&#xff0c;我们我们队列中元素是带有一定优先级的&#xff0c;它需要…

SQL入门到精通 理论+实战 -- 在 MySQL 中学习SQL语言

目录 一、环境准备 1、MySQL 8.0 和 Navicat 下载安装 2、准备好的表和数据文件&#xff1a; 二、SQL语言简述 1、数据库基础概念 2、什么是SQL 3、SQL的分类 4、SQL通用语法 三、DDL&#xff08;Data Definition Language&#xff09;&#xff1a;数据定义语言 1、操…