【动手学深度学习】深入浅出深度学习之RMSProp算法的设计与实现

目录

🌞一、实验目的

🌞二、实验准备

🌞三、实验内容

🌼1. 认识RMSProp算法

🌼2. 在optimizer_compare_naive.py中加入RMSProp

🌼3. 在optimizer_compare_mnist.py中加入RMSProp

🌼4. 问题的解决

🌞四、实验心得


🌞一、实验目的

  1. 深入学习RMSProp算法的原理和工作机制;

  2. 根据RMSProp算法的原理,设计并实现一个RMSProp优化器;

  3. 在optimizer_compare_naive.py中加入RMSProp做比较分析;

  4. 在optimizer_compare_mnist.py中加入RMSProp做比较分析。


🌞二、实验准备

  1. 根据GPU安装pytorch版本实现GPU运行实验代码;

  2. 配置环境用来运行 Python、Jupyter Notebook和相关库等相关库。


🌞三、实验内容

资源获取:关注公众号【科创视野】回复  深度学习

🌼1. 认识RMSProp算法

RMSProp(Root Mean Square Propagation)算法是由Geoffrey Hinton在2012年提出的,是对传统的梯度下降算法的改进。它是一种常用的优化算法,用于在深度学习中更新神经网络的参数。

RMSProp算法的基本原理和工作机制如下:

1.基本原理:

RMSProp算法旨在解决传统梯度下降算法中学习率选择的问题。传统梯度下降算法使用固定的学习率,在不同参数上可能导致收敛速度过慢或不收敛。RMSProp通过自适应调整学习率来解决这个问题,对于每个参数使用不同的学习率,根据历史梯度的信息来自动调整。

2.工作机制:

RMSProp使用指数加权平均来计算梯度的平方的移动平均值。对于每个参数的梯度g,计算平方梯度的移动平均值s:

s = β * s + (1 - β) * g^2

其中,β是一个衰减因子,控制历史梯度对当前梯度影响的权重,一般取值范围在0到1之间。然后,更新参数时使用调整后的学习率。对于每个参数的学习率η,计算调整后的学习率:

η' = η / (√(s) + ε)

其中,ε是一个很小的常数,用于避免除以零的情况。最后,使用调整后的学习率更新参数:

参数 = 参数 - η' * 梯度

在每次迭代中,RMSProp算法会根据历史梯度的信息调整学习率,使得对于梯度较大的参数,学习率较小,对于梯度较小的参数,学习率较大,从而更好地适应不同参数的更新需求。

RMSProp算法通过自适应调整学习率,可以提高神经网络的收敛速度和性能。与其他自适应学习率算法(如AdaGrad和Adam)相比,RMSProp在一些情况下可能更稳定和有效。然而,选择合适的学习率和衰减因子对于算法的性能仍然很重要,需要通过实验来确定最佳的超参数设置。

🌼2. 在optimizer_compare_naive.py中加入RMSProp

分析optimizer_compare_naive.py源码如下:

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from collections import OrderedDict
from common.optimizer import *def f(x, y):return x**2 / 20.0 + y**2def df(x, y):return x / 10.0, 2.0*yinit_pos = (-7.0, 2.0)
params = {}
params['x'], params['y'] = init_pos[0], init_pos[1]
grads = {}
grads['x'], grads['y'] = 0, 0optimizers = OrderedDict()
optimizers["SGD"] = SGD(lr=0.95)
optimizers["Momentum"] = Momentum(lr=0.1)
optimizers["AdaGrad"] = AdaGrad(lr=1.5)
optimizers["Adam"] = Adam(lr=0.3)idx = 1for key in optimizers:optimizer = optimizers[key]x_history = []y_history = []params['x'], params['y'] = init_pos[0], init_pos[1]for i in range(30):x_history.append(params['x'])y_history.append(params['y'])grads['x'], grads['y'] = df(params['x'], params['y'])optimizer.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 > 7Z[mask] = 0# plot 
fig, axs = plt.subplots(2, 2, figsize=(10, 10), sharey=True, tight_layout=True)
idx = 0for key in optimizers:optimizer = optimizers[key]x_history = []y_history = []params['x'], params['y'] = init_pos[0], init_pos[1]for i in range(30):x_history.append(params['x'])y_history.append(params['y'])grads['x'], grads['y'] = df(params['x'], params['y'])optimizer.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 > 7Z[mask] = 0ax = axs[idx//2, idx%2]ax.plot(x_history, y_history, 'o-', color="red")ax.contour(X, Y, Z)ax.set_ylim(-10, 10)ax.set_xlim(-10, 10)ax.plot(0, 0, '+')ax.set_title(key)ax.set_xlabel("x")ax.set_ylabel("y")idx += 1plt.subplots_adjust(hspace=0.5, wspace=0.5)
plt.show()

分析:

该源码主要是用来展示不同优化器在二维空间中的优化效果。

1.首先是导入必要的库:

  1. sys、os:用于操作系统相关功能。
  2. numpy:用于进行数值计算。
  3. matplotlib.pyplot:用于绘图。
  4. collections.OrderedDict:有序字典,用于存储优化器。

2.定义函数f(x, y)和df(x, y):

  1. f(x, y):定义了一个简单的二维函数,即 f(x, y) = x^2 / 20 + y^2。
  2. df(x, y):计算函数f(x, y)在(x, y)点处的偏导数,即 (f/x, f/y) = (x/10, 2y)

3.初始化参数和梯度:

  1. init_pos:初始位置,为(-7.0, 2.0)。
  2. params:存储优化器中使用的参数,包括x和y。
  3. grads:存储梯度,包括x和y的偏导数。

4.定义优化器:

  1. 使用collections.OrderedDict()创建了一个有序字典optimizers,用于存储不同的优化器。
  2. 分别添加了"SGD"、"Momentum"、"AdaGrad"和"Adam"四种优化器,并给定了不同的学习率。

5.迭代优化器并绘制图形:

  1. 使用for循环遍历optimizers中的每个优化器。
  2. 初始化空列表x_history和y_history,用于存储参数更新的历史轨迹。
  3. 在每个优化器下进行30次迭代:
  4. 将当前参数位置params['x']和params['y']添加到x_history和y_history中。
  5. 计算当前位置的梯度grads['x']和grads['y']。
  6. 调用优化器的update方法,更新参数params。
  7. 生成x和y的取值范围,用于绘制等高线图。
  8. 绘制当前优化器的参数更新轨迹、等高线图和起点位置。
  9. 设置标题、坐标轴等信息。

6.显示图形:

  1. 使用plt.show()显示绘制的图形。

以上代码展示了四种不同的优化器在二维空间中的优化过程。通过迭代更新参数,每个优化器根据自己的更新策略不断优化目标函数,并绘制出参数更新轨迹和等高线图,以便比较不同优化器的效果。

源码运行结果为:

这里其实我们很容易可以发现在头文件处导入了from common.optimizer import *,而这个库是书籍提供的因此我们打开后查看其目录层级如下图:

由于使用了其中的optimizer因此查看其内容如下:

# coding: utf-8
import numpy as npclass SGD:"""随机梯度下降法(Stochastic Gradient Descent)"""def __init__(self, lr=0.01):self.lr = lrdef update(self, params, grads):for key in params.keys():params[key] -= self.lr * grads[key] class Momentum:"""Momentum SGD"""def __init__(self, lr=0.01, momentum=0.9):self.lr = lrself.momentum = momentumself.v = Nonedef update(self, params, grads):if self.v is None:self.v = {}for key, val in params.items():                                self.v[key] = np.zeros_like(val)for key in params.keys():self.v[key] = self.momentum*self.v[key] - self.lr*grads[key] params[key] += self.v[key]class Nesterov:"""Nesterov's Accelerated Gradient (http://arxiv.org/abs/1212.0901)"""def __init__(self, lr=0.01, momentum=0.9):self.lr = lrself.momentum = momentumself.v = Nonedef update(self, params, grads):if self.v is None:self.v = {}for key, val in params.items():self.v[key] = np.zeros_like(val)for key in params.keys():self.v[key] *= self.momentumself.v[key] -= self.lr * grads[key]params[key] += self.momentum * self.momentum * self.v[key]params[key] -= (1 + self.momentum) * self.lr * grads[key]class AdaGrad:"""AdaGrad"""def __init__(self, lr=0.01):self.lr = lrself.h = Nonedef update(self, params, grads):if self.h is None:self.h = {}for key, val in params.items():self.h[key] = np.zeros_like(val)for key in params.keys():self.h[key] += grads[key] * grads[key]params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)class RMSprop:"""RMSprop"""def __init__(self, lr=0.01, decay_rate = 0.99):self.lr = lrself.decay_rate = decay_rateself.h = Nonedef update(self, params, grads):if self.h is None:self.h = {}for key, val in params.items():self.h[key] = np.zeros_like(val)for key in params.keys():self.h[key] *= self.decay_rateself.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
class Adam:"""Adam (http://arxiv.org/abs/1412.6980v8)"""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] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]#self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)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)#unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias#unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias#params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)

Common分析:

1.这里定义了几种优化算法,包括随机梯度下降法(SGD)、动量法(Momentum)、Nesterov加速梯度法(Nesterov)、AdaGrad、RMSprop和Adam。这些优化算法用于在机器学习和深度学习中更新模型参数以最小化损失函数。

2.SGD(随机梯度下降法):每次迭代时,通过乘以学习率(lr)和梯度值更新参数。即 params[key] -= lr * grads[key]。

3.Momentum(动量法):引入动量(momentum)的概念,通过累积之前的速度来决定当前的更新方向。在每次迭代中,更新速度和参数值。速度(self.v)初始化为零,然后根据当前梯度和动量参数更新速度和参数。更新速度的公式为 self.v[key] = self.momentumself.v[key] - self.lrgrads[key],更新参数的公式为 params[key] += self.v[key]。

4.Nesterov's Accelerated Gradient(Nesterov加速梯度法):与Momentum类似,但在更新参数之前使用了动量的“预期”位置。在每次迭代中,先根据当前速度和动量参数更新速度和参数的“预期”位置,然后再根据当前梯度更新速度和参数的值。更新速度的公式为 self.v[key] *= self.momentum,self.v[key] -= self.lr * grads[key],更新参数的公式为 params[key] += self.momentum * self.momentum * self.v[key],params[key] -= (1 + self.momentum) * self.lr * grads[key]。

5.AdaGrad:针对不同参数的梯度值进行归一化处理,对于每个参数,根据梯度平方的累积和和学习率更新参数。归一化的方式是除以历史梯度平方的平方根加上一个很小的数(1e-7)以避免除以零。更新参数的公式为 params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7),其中 self.h[key] 为历史梯度平方的累积和。

6.RMSprop与AdaGrad类似,但不是累积所有历史梯度平方的和,而是通过指数加权平均的方式计算历史梯度平方的累积和。在每次迭代中,更新参数的方式与AdaGrad相同,只是累积和的计算方式不同。更新参数的公式为 params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7),其中 self.h[key] *= self.decay_rate,self.h[key] += (1 - self.decay_rate继续解释Adam算法:

7.Adam:结合了动量法和RMSprop的优点。它使用两个动量参数(beta1和beta2)和一个迭代计数器(iter)来更新参数。初始化时,将动量(m)和二阶矩估计(v)初始化为零。在每次迭代中,更新动量和二阶矩估计的值,然后根据当前的学习率计算修正后的学习率。最后,根据修正后的学习率和二阶矩估计来更新参数。更新动量和二阶矩估计的公式为:

self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])

self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])

修正后的学习率(lr_t)计算公式为:

lr_t = self.lr * np.sqrt(1.0 - self.beta2self.iter) / (1.0 - self.beta1self.iter)

最终,根据修正后的学习率和二阶矩估计来更新参数的公式为:

params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)

根据上述的common分析,为了添加RMSProp优化器,还需进行以下步骤:

1. 导入RMSProp优化器类:

  1. 在代码开头导入RMSProp类, from common.optimizer import RMSProp

2.在优化器字典中添加RMSProp优化器:

  1. 在optimizers字典中添加RMSProp优化器,类似于其他优化器的添加方式,指定合适的学习率:
optimizers["RMSProp"] = RMSProp(lr=0.1, decay_rate=0.99)

3.在循环中使用RMSProp优化器更新参数:

  1. 在循环迭代的部分,根据当前优化器选择RMSProp进行参数更新。
  2. 在每次迭代时,调用RMSProp优化器的update方法更新参数。
for i in range(30):x_history.append(params['x'])y_history.append(params['y'])grads['x'], grads['y'] = df(params['x'], params['y'])optimizer.update(params, grads)

4. 最后,运行代码并观察RMSProp优化器的效果。

  1. 当运行代码时,RMSProp优化器将被迭代,并在绘图中显示其参数更新轨迹。

添加RMSProp后代码为:

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from collections import OrderedDict
from common.optimizer import *def f(x, y):return x**2 / 20.0 + y**2def df(x, y):return x / 10.0, 2.0*yinit_pos = (-7.0, 2.0)
params = {}
params['x'], params['y'] = init_pos[0], init_pos[1]
grads = {}
grads['x'], grads['y'] = 0, 0optimizers = OrderedDict()
optimizers["SGD"] = SGD(lr=0.95)
optimizers["Momentum"] = Momentum(lr=0.1)
optimizers["AdaGrad"] = AdaGrad(lr=1.5)
optimizers["Adam"] = Adam(lr=0.3)
optimizers["RMSProp"] = RMSprop(lr=0.1, decay_rate=0.99)  # 添加RMSProp优化器idx = 1for key in optimizers:optimizer = optimizers[key]x_history = []y_history = []params['x'], params['y'] = init_pos[0], init_pos[1]for i in range(30):x_history.append(params['x'])y_history.append(params['y'])grads['x'], grads['y'] = df(params['x'], params['y'])optimizer.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 > 7Z[mask] = 0# plot 
fig, axs = plt.subplots(3, 2, figsize=(15, 20), sharey=True, tight_layout=True)
idx = 1for key in optimizers:optimizer = optimizers[key]x_history = []y_history = []params['x'], params['y'] = init_pos[0], init_pos[1]for i in range(30):x_history.append(params['x'])y_history.append(params['y'])grads['x'], grads['y'] = df(params['x'], params['y'])optimizer.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 > 7Z[mask] = 0ax = axs[(idx - 1) // 2, (idx - 1) % 2]ax.plot(x_history, y_history, 'o-', color="red")ax.contour(X, Y, Z)ax.set_ylim(-10, 10)ax.set_xlim(-10, 10)ax.plot(0, 0, '+')ax.set_title(key)ax.set_xlabel("x")ax.set_ylabel("y")idx += 1plt.show()

运行结果为:

🌼3. 在optimizer_compare_mnist.py中加入RMSProp

分析optimizer_compare_mnist.py源码如下:

# coding: utf-8
import os
import sys
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.util import smooth_curve
from common.multi_layer_net import MultiLayerNet
from common.optimizer import *# 0:读入MNIST数据==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000# 1:进行实验的设置==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()networks = {}
train_loss = {}
for key in optimizers.keys():networks[key] = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100],output_size=10)train_loss[key] = []    # 2:开始训练==========
for i in range(max_iterations):batch_mask = np.random.choice(train_size, batch_size)x_batch = x_train[batch_mask]t_batch = t_train[batch_mask]for key in optimizers.keys():grads = networks[key].gradient(x_batch, t_batch)optimizers[key].update(networks[key].params, grads)loss = networks[key].loss(x_batch, t_batch)train_loss[key].append(loss)if i % 100 == 0:print( "===========" + "iteration:" + str(i) + "===========")for key in optimizers.keys():loss = networks[key].loss(x_batch, t_batch)print(key + ":" + str(loss))# 3.绘制图形==========
markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D"}
x = np.arange(max_iterations)
for key in optimizers.keys():plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.ylim(0, 1)
plt.legend()
plt.show()

源码分析:

1.数据准备

  1. 通过调用load_mnist函数加载了MNIST数据集,将训练数据集和测试数据集分别赋值给(x_train, t_train)和(x_test, t_test)变量。
  2. train_size记录了训练数据集的样本数量,batch_size定义了每个小批量训练的样本数量,max_iterations定义了训练的迭代次数。

2.实验设置

  1. 定义字典optimizers包含了不同的优化算法对象,包括SGD、Momentum、AdaGrad和Adam。
  2. 定义空的字典networks用于存储不同优化算法下的神经网络模型。
  3. 定义空的字典train_loss用于存储不同优化算法下的训练损失。

3.开始训练

  1. 使用一个循环迭代max_iterations次进行训练。
  2. 在每次迭代中,通过随机选择索引生成一个小批量的训练数据,并根据选择的优化算法计算梯度并更新模型参数。
  3. 计算当前模型在训练数据上的损失,并将其存储到train_loss字典中。
  4. 每隔100次迭代,打印出各个优化算法的损失。

4.绘制图形

  1. 使用smooth_curve函数平滑训练损失曲线。
  2. 使用不同的标记符号和颜色,将各个优化算法的训练损失曲线绘制在同一张图上。
  3. 添加坐标轴标签和图例,并显示图形。
  4. 过比较不同优化算法在训练过程中的损失变化情况,可以对比它们的性能和收敛速度,进而选择最合适的优化算法来训练神经网络模型。

运行结果如下:

图4-4

前文的common的RMSprop定义如下:

class RMSprop:"""RMSprop"""def __init__(self, lr=0.01, decay_rate=0.99):self.lr = lrself.decay_rate = decay_rateself.h = Nonedef update(self, params, grads):if self.h is None:self.h = {}for key, val in params.items():self.h[key] = np.zeros_like(val)for key in params.keys():self.h[key] *= self.decay_rateself.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

为了添加RMSProp优化器,还需进行以下步骤:

1. 取消注释optimizers['RMSprop'] = RMSprop()这一行,以导入RMSprop优化器。

2.在实验设置部分(步骤1)的循环中,为RMSprop优化器添加一个网络和训练损失的条目。修改以下代码段:

optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()networks = {}
train_loss = {}
for key in optimizers.keys():networks[key] = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100],output_size=10)train_loss[key] = []

将其修改为:

optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
optimizers['RMSprop'] = RMSprop()networks = {}
train_loss = {}
for key in optimizers.keys():networks[key] = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100],output_size=10)train_loss[key] = []

3.在训练部分(步骤2)的循环中,更新RMSprop优化器的参数。修改以下代码段:

for i in range(max_iterations):batch_mask = np.random.choice(train_size, batch_size)x_batch = x_train[batch_mask]t_batch = t_train[batch_mask]for key in optimizers.keys():grads = networks[key].gradient(x_batch, t_batch)optimizers[key].update(networks[key].params, grads)loss = networks[key].loss(x_batch, t_batch)train_loss[key].append(loss)if i % 100 == 0:print( "===========" + "iteration:" + str(i) + "===========")for key in optimizers.keys():loss = networks[key].loss(x_batch, t_batch)print(key + ":" + str(loss))

结果以上详细分析,最终加入的RMSprop的代码为:

# coding: utf-8
import os
import sys
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.util import smooth_curve
from common.multi_layer_net import MultiLayerNet
from common.optimizer import *# 0:读入MNIST数据==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000# 1:进行实验的设置==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
optimizers['RMSprop'] = RMSprop()  # 添加RMSProp优化器networks = {}
train_loss = {}
for key in optimizers.keys():networks[key] = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100],output_size=10)train_loss[key] = []    # 2:开始训练==========
for i in range(max_iterations):batch_mask = np.random.choice(train_size, batch_size)x_batch = x_train[batch_mask]t_batch = t_train[batch_mask]for key in optimizers.keys():grads = networks[key].gradient(x_batch, t_batch)if key == 'RMSprop':  # 添加RMSProp更新部分optimizer = optimizers[key]optimizer.lr = 0.01  # 可根据需要设置学习率optimizer.decay_rate = 0.99  # 可根据需要设置衰减率optimizer.update(networks[key].params, grads)else:optimizers[key].update(networks[key].params, grads)loss = networks[key].loss(x_batch, t_batch)train_loss[key].append(loss)if i % 100 == 0:print("===========" + "iteration:" + str(i) + "===========")for key in optimizers.keys():loss = networks[key].loss(x_batch, t_batch)print(key + ":" + str(loss))# 3.绘制图形==========
markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D", "RMSprop": "v"}
x = np.arange(max_iterations)
for key in optimizers.keys():plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.ylim(0, 1)
plt.legend()
plt.show()

运行结果:

图4-5

🌼4. 问题的解决

1. 如果我们设置γ = 1,实验会发生什么?为什么?

解:如果将RMSprop算法中的decay_rate参数γ设置为1,即self.decay_rate = 1。在RMSprop算法中,decay_rate参数用于控制历史梯度平方和的衰减率。在每次更新参数时,历史梯度平方和会乘以decay_rate,表示旧的历史梯度平方和的贡献在更新中保持不变。当decay_rate等于1时,历史梯度平方和不会被衰减,它将保持不变。这意味着在每次参数更新中,历史梯度平方和的值不会改变,对梯度的调整没有任何影响。

结果是RMSprop算法将变得与普通的梯度下降算法(如SGD)类似,因为历史梯度平方和的衰减不再发挥作用。实验中的网络更新将类似于SGD,不会发生自适应调整学习率的效果。从而导致算法的性能下降,训练过程中的更新步长可能过大,且收敛速度可能变慢。

图4-6 设置γ = 1的RMSprop两次结果(右图不显示)

2. 旋转优化问题以最小化f(x) = 0.1*(x1 + x2)**2 + 2(x1 x2)**2。收敛会发生什么?

解:在使用优化算法进行收敛时,不同的优化算法可能表现出不同的收敛行为:

SGD:由于旋转对称性,SGD可能会在搜索空间中震荡并缓慢收敛到最优点。它的收敛速度较慢。

Momentum:具有积累梯度的特性,可以在梯度方向上加速收敛。由于旋转对称性,Momentum算法可能会更快地收敛到最优点。

AdaGrad:通过自适应地调整学习率来处理不同特征的梯度变化。然而,在旋转优化问题中,由于旋转对称性,AdaGrad可能会导致学习率过早地衰减,从而导致收敛速度较慢。

Adam:结合了Momentum和AdaGrad的优点,具有较好的收敛性能。由于旋转对称性,Adam算法可能会更快地收敛到最优点。

RMSProp:自适应学习率的优化算法,通过调整学习率的大小来适应不同特征的梯度变化。在旋转优化问题中,由于函数 f(x) 具有旋转对称性,不同方向上的梯度变化可能会不同。RMSProp算法的自适应学习率机制可以在不同方向上调整学习率的大小,从而有助于更快地收敛到最优点。

3. 随着优化的进展,需要调整γ吗?RMSProp算法对此有多敏感?

解:通常情况下,较小的默认值(例如0.9或0.99)已经可以在许多问题上产生良好的效果,因此通常不需要频繁地调整γ的值。

RMSProp算法在大多数情况下对γ的选择相对不太敏感。


🌞四、实验心得

通过此次实验,我深入学习了RMSProp算法的原理和工作机制,并成功实现了一个RMSProp优化器。RMSProp算法通过自适应地调整学习率和使用梯度平方的指数加权移动平均缓存,可以在训练过程中加速收敛并提高性能。

在实验中,我将RMSProp算法应用于神经网络的训练过程。首先,选择了适当的神经网络模型和训练数据集,然后使用自己实现的RMSProp优化器进行参数更新。通过观察训练过程中的损失函数值和准确率等指标,从而比较使用RMSProp算法和传统梯度下降算法在训练过程中的性能和收敛速度。

在收集实验结果和进行分析时,我记录了训练过程中的损失函数值和准确率,并绘制了曲线图。通过对比使用RMSProp算法和传统梯度下降算法的实验结果,我发现RMSProp算法在加速收敛和提高性能方面表现出色。相较于传统梯度下降算法,使用RMSProp算法的自适应学习率调整和梯度平方的指数加权移动平均缓存机制使得它能够在训练过程中自动调整学习率,并更有效地利用梯度信息,从而加速了模型的收敛速度和提高了性能。并且能够更快地收敛到较低的损失函数值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/794290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

atoi()函数---使用和模拟实现(详解)

目录 一、前言二、声明三、描述四、参数五、返回值六、使用七、模拟实现 一、前言 二、声明 int atoi(const char *str)三、描述 C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)需要包含头文件&#xff…

大语言模型基石:文字与数字的起源与演变

大语言模型基石:文字与数字的起源与演变 1、文字 1.1、起源 我们的祖先在还没有发明文字和语言之前就已经开始使用“咿咿呀呀”的声音来传播信息了,比如在野外活动遇到危险,然后发出“咿咿呀呀”的声音来提醒同伴小心,同伴在接收…

考古:IT架构演进之IOE架构

考古:IT架构演进之IOE架构 IOE架构(IBM, Oracle, EMC)出现在20世纪末至21世纪初,是一种典型的集中式架构体系。在这个阶段,企业的关键业务系统往往依赖于IBM的小型机(后来还包括大型机)、Oracle…

基于SpringBoot+Vue的儿童书法机构管理系统

一、项目背景介绍: 儿童书法机构的管理是一个具有挑战性的任务,需要有效的信息管理和资源分配。传统的手动管理方式存在着效率低下、易出错等问题。为了解决这些问题,基于SpringBootVue的儿童书法机构管理系统应运而生。该系统利用现代化的技…

Linux--进程(2)

目录 前言 1. 进程的状态 1.1 进程排队 1.2 运行,阻塞,挂起 2.Linux下具体的进程状态 2.1僵尸和孤儿 3.进程的优先级 4.Linux的调度与切换 前言 这篇继续来学习进程的其它知识 上篇文章:Linux--进程(1)-CS…

ES12 学习

文章目录 1. 逻辑赋值操作符2. 数字分隔符_3. replaceAll4. Promise.any5. WeakRefs6. FinalizationRegistry 1. 逻辑赋值操作符 逻辑赋值操作符 ??、&&、|| let a true let b true a && b // a a && b a || b // a a || b obj.introduction ?…

Redis -- 缓存击穿问题

缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。 常见的解决方案有两种: 互斥锁 逻辑过期 逻辑分析:假设线程1在查询缓存之后&…

静态路由协议实验1

要求: 使用静态路由协议使得全网可达。 第一步、规划IP地址。并配置IP。 第二步、写静态路由 [r1]ip route-static 192.168.3.0 24 192.168.2.2 [r1]ip route-static 192.168.4.0 24 192.168.2.2 [r1]ip route-static 192.168.5.0 24 192.168.2.2[r2]ip route-st…

一、next-auth 身份验证凭据-使用电子邮件和密码注册登录

一、next-auth 身份验证凭据-使用电子邮件和密码注册登录 文章目录 一、next-auth 身份验证凭据-使用电子邮件和密码注册登录一、前言二、前置准备1、环境配置2、相关库安装(1)vercel 配置(2)Yarn 包管理配置 3、next项目初始化与…

【Oracle】oracle、mysql、sql server三者区别

欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Oracle》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对知识…

Shell脚本之基础-2

目录 一、字符处理 cut命令 awk命令 sed命令 字符串排序 二、条件判断 文件类型判断 文件权限判断 两个文件的判断 整数比较 字符串判断 多重判断 三、流程控制 if分支 if else 双分支结构 case分支 for循环 while循环 一、字符处理 cut命令 命令格式&#x…

深入剖析JavaScript中的this(下)

五、事件处理函数的this 5.1 事件绑定 <button id"btn">点击我</button>function handleClick(e) {console.log(this);// <button id"btn">点击我</button> }document.getElementById(btn).addEventListener(click, handleClick…

CSS基础:4种简单选择器的详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。大专生&#xff0c;2年时间从1800到月入过万&#xff0c;工作5年买房。 分享成长心得。 261篇原创内容-公众号 后台回复“前端工具”可获取开发工具&#xff0c;持续更新中 后台回复“前端基础…

MySQL客户端安装并配置免密登录

最近在写脚本时需要向MySQL数据库中存储数据&#xff0c;且脚本运行的服务器与MySQL服务器不是同一台服务器&#xff0c;而且需要保证MySQL密码的安全性&#xff0c;不能在脚本中暴露&#xff0c;所以就需要在服务器上安装MySQL客户端&#xff0c;并配置免密登录。 一、虚拟机…

Git安装教程(图文安装)

Git Bash是git(版本管理器)中提供的一个命令行工具&#xff0c;外观类似于Windows系统内置的cmd命令行工具。 可以将Git Bash看作是一个终端模拟器&#xff0c;它提供了类似于Linux和Unix系统下Bash Shell环境的功能。通过Git Bash&#xff0c;用户可以在Windows系统中运行基于…

Vue项目登录页实现获取短信验证码的功能

之前我们写过不需要调后端接口就获取验证码的方法,具体看《无需后端接口,用原生js轻松实现验证码》这个文章。现在我们管理后台有个需求,就是登录页面需要获取验证码,用户可以输入验证码后进行登录。效果如下,当我点击获取验证码后能获取短信验证码: 这里在用户点击获取…

Linux 线程:线程同步、生产者消费者模型

目录 一、死锁 二、条件变量实现线程同步 1、为什么需要线程同步 2、条件变量、同步、竞态条件 3、条件变量函数&#xff1a;初始化 销毁 等待 唤醒 4、实现简单的多线程程序 不唤醒则一直等待 实现线程同步 三、生产者消费者 1、借助超市模型理解 2、优点 四、基于…

数字乡村创新实践探索:科技赋能农业现代化与乡村治理体系现代化同步推进

随着信息技术的飞速发展&#xff0c;数字乡村作为乡村振兴的重要战略方向&#xff0c;正日益成为推动农业现代化和乡村治理体系现代化的关键力量。科技赋能下的数字乡村&#xff0c;不仅提高了农业生产的效率和品质&#xff0c;也为乡村治理带来了新的机遇和挑战。本文旨在探讨…

Linux 环境下 Redis基础配置及开机自启

Linux 环境下 Redis基础配置及开机自启 linux环境安装redis<redis-6.0.5.tar.gz> 1-redis基本安装配置 解压 获取到tar包后&#xff0c;解压到相关目录&#xff0c;一般是将redis目录放在usr/local/redis目录下&#xff0c;可以使用-C指定到解压下目录 tar -zvxf re…

Java数据结构栈

栈&#xff08;Stack&#xff09; 概念 栈是一种先进后出的数据结构。 栈的使用 import java.util.Stack; public class Test {public static void main(String[] args) {Stack<Integer> s new Stack();s.push(1);s.push(2);s.push(3);s.push(4);System.out.println(s…