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

server/2025/2/5 21:31:37/

文章目录

  • 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  mx1eta: 学习率num_iter: 迭代次数beta: 衰减率epsilon: 无穷小threshold: 阈值"""m, n = X.shapetheta, 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 - yloss_.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}")breakreturn 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  mx1eta: 学习率num_iter: 迭代次数beta: 衰减率epsilon: 无穷小threshold: 阈值"""m, n = X.shapetheta, 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 - yloss_.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}")breakreturn 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.ppmy.cn/server/165238.html

相关文章

PyQt4学习笔记2】Qt 的 Model/View 架构

目录 一、Model/View 架构 1. Model/View 架构的核心思想 2. Model/View 架构的优势 3. 常见的 Model 和 View 类 模型类 (Model) 视图类 (View) 4. 信号和槽机制 5. 示例代码 6. 数据操作 设置数据(将特定位置的数据替换掉) 插入和删除数据 7. 自定义模型 8. 总结 二、Model/V…

OpenAI发布最新推理模型o3-mini

OpenAI于周五推出了新的AI"推理"模型o3-mini&#xff0c;这是该公司o系列推理模型家族的最新成员。 OpenAI此前在12月份就预告过这个模型&#xff0c;同时还展示了一个能力更强的系统o3。此次发布恰逢OpenAI面临诸多机遇与挑战的关键时刻。 目前&#xff0c;OpenAI…

(1)Linux高级命令简介

Linux高级命令简介 在安装好linux环境以后第一件事情就是去学习一些linux的基本指令&#xff0c;我在这里用的是CentOS7作演示。 首先在VirtualBox上装好Linux以后&#xff0c;启动我们的linux&#xff0c;输入账号密码以后学习第一个指令 简介 Linux高级命令简介ip addrtou…

C++和Python实现SQL Server数据库导出数据到S3并导入Redshift数据仓库

用C实现高性能数据处理&#xff0c;Python实现操作Redshift导入数据文件。 在Visual Studio 2022中用C和ODBC API导出SQL Server数据库中张表中的所有表的数据为CSV文件格式的数据流&#xff0c;用逗号作为分隔符&#xff0c;用双引号包裹每个数据&#xff0c;字符串类型的数据…

Android 9.0 mtk默认浏览器Browser下载app不能安装问题的解决办法

1.前言 在系统9.0的ROM定制化开发中,在开发mtk平台的时候,在系统默认浏览器Browser中发现在下载某些app的时候,结果显示的确实 在下载到内部存储的时候,点击安装的时候安装失败,所以就需要从Browser的下载流程中出发分析相关源码来实现具体的功能 2.mtk默认浏览器Browser…

使用python实现与本地ollama部署的deepseek对话

专栏总目录 按照ollama官方doc的example操作&#xff0c;没有成功与本地ollama上的deepseek-r1:1.5b通讯后&#xff0c;发现vscode可以调用本地ollama上的deepseek模型。 为了实现与ollama上的deepseek模型通讯&#xff0c;我使用wireshark对本地回环地址进行侦听后&#xff0c…

15JavaWeb——Maven高级篇

Maven高级 Web开发讲解完毕之后&#xff0c;我们再来学习Maven高级。其实在前面的课程当中&#xff0c;我们已经学习了Maven。 我们讲到 Maven 是一款构建和管理 Java 项目的工具。经过前面 10 多天 web 开发的学习&#xff0c;相信大家对于 Maven 这款工具的基本使用应该没什…

(动态规划路径基础 最小路径和)leetcode 64

视频教程 1.初始化dp数组&#xff0c;初始化边界 2、从[1行到n-1行][1列到m-1列]依次赋值 #include<vector> #include<algorithm> #include <iostream>using namespace std; int main() {vector<vector<int>> grid { {1,3,1},{1,5,1},{4,2,1}…