梯度下降是一种优化算法,它沿着目标函数的负梯度方向移动,以找到函数的最小值。
梯度下降的一个限制是它对每个输入变量使用相同的步长(学习率)。AdaGrad,顾名思义,是梯度下降优化算法的一个扩展,它允许优化算法使用的每个维度中的步长根据搜索过程中看到的变量梯度(偏导数)自动调整。
AdaGrad 的一个限制是,它在搜索结束时可能导致每个参数的步长非常小,这会大大减慢搜索的进度,并可能导致无法找到最优解。
均方根传播(Root Mean Squared Propagation),简称 RMSProp,是梯度下降和 AdaGrad 版梯度下降的一个扩展,它在调整每个参数的步长时,使用衰减的偏梯度平均值。使用衰减的移动平均值允许算法忘记早期梯度,专注于搜索过程中看到的最近观察到的偏梯度,从而克服了 AdaGrad 的局限性。
在本教程中,您将学习如何从头开始开发梯度下降与 RMSProp 优化算法。
完成本教程后,您将了解:
- 梯度下降是一种优化算法,它利用目标函数的梯度来导航搜索空间。
- 可以使用衰减的偏导数移动平均值(称为 RMSProp)来更新梯度下降,为每个输入变量提供自动自适应的步长。
- 如何从零开始实现 RMSProp 优化算法,并将其应用于目标函数并评估结果。
通过我的新书《机器学习优化》快速启动您的项目,其中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。
从零开始使用 RMSProp 进行梯度下降
照片作者:pavel ahmed,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 梯度下降
- 均方根传播(RMSProp)
- 带 RMSProp 的梯度下降
- 二维测试问题
- 带 RMSProp 的梯度下降优化
- RMSProp 的可视化
梯度下降
梯度下降是一种优化算法。
它在技术上被称为一阶优化算法,因为它显式地使用了目标函数的一阶导数。
一阶方法依赖梯度信息来帮助指导寻找最小值……
——第69页,《优化算法》,2019年。
一阶导数,或简称“导数”,是目标函数在特定点(例如,某个输入)的变化率或斜率。
如果目标函数有多个输入变量,则称其为多元函数,输入变量可以看作一个向量。反过来,多元目标函数的导数也可以看作一个向量,通常称为梯度。
- 梯度:多元目标函数的一阶导数。
导数或梯度指向特定输入处目标函数最陡峭上升的方向。
梯度下降指一种最小化优化算法,它沿着目标函数的负梯度方向“下坡”移动,以找到函数的最小值。
梯度下降算法需要一个正在优化的目标函数以及目标函数的导数函数。目标函数 f() 为给定的输入集返回一个分数,导数函数 f'() 为给定的输入集提供目标函数的导数。
梯度下降算法需要问题中的一个起点(x),例如输入空间中随机选择的一个点。
然后计算导数,并在输入空间中迈出一步,预计会导致目标函数下坡移动(假设我们正在最小化目标函数)。
通过首先计算输入空间中的移动距离(计算为步长(称为 alpha 或学习率)乘以梯度)来进行下坡移动。然后将其从当前点减去,确保我们沿着与梯度相反的方向移动,即沿着目标函数的下坡方向。
- x = x – 步长 * f'(x)
给定点处目标函数越陡峭,梯度的幅值越大,反之,在搜索空间中迈出的步长也越大。所迈步长的大小由步长超参数进行缩放。
- **步长**(*alpha*):控制算法每次迭代中在搜索空间中逆着梯度移动距离的超参数。
如果步长太小,在搜索空间中的移动会很小,搜索将花费很长时间。如果步长太大,搜索可能会在搜索空间中跳跃并跳过最优解。
现在我们已经熟悉了梯度下降优化算法,让我们来看看 RMSProp。
想要开始学习优化算法吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
均方根传播(RMSProp)
均方根传播,简称 RMSProp,是梯度下降优化算法的一个扩展。
这是一个未公开发表的扩展,首次在 Geoffrey Hinton 的神经网络课程讲义中进行了描述,特别是讲座 6e,标题为“rmsprop:用梯度的最近幅度的运行平均值除以梯度”。
RMSProp 旨在加速优化过程,例如减少达到最优解所需的函数评估次数,或提高优化算法的能力,例如获得更好的最终结果。
它与另一个梯度下降的扩展——自适应梯度(Adaptive Gradient),或称 AdaGrad——有关。
AdaGrad 专门用于探索自动定制搜索空间中每个参数的步长(学习率)的思想。这是通过首先计算给定维度的步长,然后使用计算出的步长,通过偏导数在该维度中移动来实现的。然后对搜索空间中的每个维度重复此过程。
Adagrad 通过首先对迄今为止在搜索中看到的该参数的偏导数求和,然后将初始步长超参数除以偏导数平方和的平方根来计算每个参数的步长。
一个参数的自定义步长计算如下:
- cust_step_size = step_size / (1e-8 + sqrt(s))
其中 cust_step_size 是搜索过程中给定点的输入变量的计算步长,step_size 是初始步长,sqrt() 是平方根运算,s 是迄今为止在搜索中看到的输入变量的偏导数平方和。
这对于具有许多曲率的优化问题中搜索的振荡具有平滑作用。
AdaGrad 根据平方梯度的整个历史来缩小学习率,并且可能在到达凸结构之前就已经将学习率缩小得太小。
— 第 307-308 页,深度学习,2016。
AdaGrad 的一个问题是它会过度减慢搜索速度,导致在运行结束时每个参数或搜索维度都具有非常小的学习率。这会导致搜索过早停止,在找到最小值之前。
RMSProp 扩展了 Adagrad 以避免单调递减学习率的效果。
— 第 78 页,优化算法,2019。
RMSProp 可以被认为是 AdaGrad 的一个扩展,因为它在计算每个参数的学习率时,使用的是偏导数的衰减平均值或移动平均值,而不是求和。
这是通过添加一个我们称之为 rho 的新超参数来实现的,它像动量一样作用于偏导数。
RMSProp 维护平方梯度的衰减平均值。
— 第 78 页,优化算法,2019。
使用偏导数的衰减移动平均值,搜索可以忘记早期的偏导数值,并专注于最近看到的搜索空间形状。
RMSProp 使用指数衰减平均值来丢弃极端过去的历史,以便在找到凸碗后能够快速收敛,就像它是 AdaGrad 算法在该碗中初始化的一样。
— 第 308 页,深度学习,2016。
一个参数的均方偏导数计算如下:
- s(t+1) = (s(t) * rho) + (f'(x(t))^2 * (1.0-rho))
其中 s(t+1) 是算法当前迭代中一个参数的平方偏导数的衰减移动平均值,s(t) 是前一次迭代的平方偏导数的衰减移动平均值,f'(x(t))^2 是当前参数的平方偏导数,rho 是一个超参数,通常具有像动量一样的 0.9 值。
考虑到我们使用的是偏导数的衰减平均值,并且计算该平均值的平方根为该技术带来了名称,例如,均方偏导数的平方根或均方根 (RMS)。例如,参数的自定义步长可以写为:
- cust_step_size(t+1) = step_size / (1e-8 + RMS(s(t+1)))
一旦我们有了参数的自定义步长,我们就可以使用自定义步长和偏导数 f'(x(t)) 来更新参数。
- x(t+1) = x(t) – cust_step_size(t+1) * f'(x(t))
然后,对于每个输入变量重复此过程,直到创建一个新的搜索空间点并对其进行评估。
RMSProp 是梯度下降的一个非常有效的扩展,也是通常用于拟合深度学习神经网络的首选方法之一。
实践证明,RMSProp 是深度神经网络一种有效且实用的优化算法。它目前是深度学习从业者常规使用的首选优化方法之一。
— 第 308 页,深度学习,2016。
现在我们对 RMSprop 算法有了了解,让我们探索一下如何实现它并评估其性能。
带 RMSProp 的梯度下降
在本节中,我们将探索如何使用 RMSProp 算法实现具有自适应梯度的梯度下降优化算法。
二维测试问题
首先,让我们定义一个优化函数。
我们将使用一个简单的二维函数,它将每个维度的输入平方,并将有效输入范围定义为-1.0到1.0。
下面的 objective() 函数实现了这个功能:
1 2 3 |
# 目标函数 def objective(x, y): return x**2.0 + y**2.0 |
我们可以创建一个数据集的三维图来感受响应曲面的曲率。
下面列出了绘制目标函数的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 绘制测试函数的三维图 from numpy import arange from numpy import meshgrid from matplotlib import pyplot # 目标函数 def objective(x, y): return x**2.0 + y**2.0 # 定义输入范围 r_min, r_max = -1.0, 1.0 # 以 0.1 为增量均匀采样输入范围 xaxis = arange(r_min, r_max, 0.1) yaxis = arange(r_min, r_max, 0.1) # 从坐标轴创建网格 x, y = meshgrid(xaxis, yaxis) # 计算目标值 results = objective(x, y) # 使用 jet 配色方案创建曲面图 figure = pyplot.figure() axis = figure.gca(projection='3d') axis.plot_surface(x, y, results, cmap='jet') # 显示绘图 pyplot.show() |
运行示例将创建目标函数的三维曲面图。
我们可以看到熟悉的碗形,全局最小值在 f(0, 0) = 0。

测试目标函数的三维图
我们还可以创建函数的二维图。这将在以后我们想要绘制搜索进度时提供帮助。
以下示例创建了目标函数的等高线图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# 绘制测试函数的等高线图 from numpy import asarray from numpy import arange from numpy import meshgrid from matplotlib import pyplot # 目标函数 def objective(x, y): return x**2.0 + y**2.0 # 定义输入范围 bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]]) # 以 0.1 为增量均匀采样输入范围 xaxis = arange(bounds[0,0], bounds[0,1], 0.1) yaxis = arange(bounds[1,0], bounds[1,1], 0.1) # 从坐标轴创建网格 x, y = meshgrid(xaxis, yaxis) # 计算目标值 results = objective(x, y) # 使用50个级别和jet颜色方案创建填充等高线图 pyplot.contourf(x, y, results, levels=50, cmap='jet') # 显示绘图 pyplot.show() |
运行示例将创建目标函数的二维等高线图。
我们可以看到碗状被压缩成用颜色梯度显示的等高线。我们将使用这个图来绘制搜索过程中探索的特定点。

测试目标函数的二维等高线图
现在我们有了测试目标函数,让我们看看如何实现 RMSProp 优化算法。
带 RMSProp 的梯度下降优化
我们可以将带 RMSProp 的梯度下降应用于测试问题。
首先,我们需要一个函数来计算此函数的导数。
- f(x) = x^2
- f'(x) = x * 2
x^2 的导数在每个维度上都是 x * 2。下面的 derivative() 函数实现了这一点。
1 2 3 |
# 目标函数的导数 def derivative(x, y): return asarray([x * 2.0, y * 2.0]) |
接下来,我们可以实现梯度下降优化。
首先,我们可以在问题的边界内选择一个随机点作为搜索的起点。
这假设我们有一个数组,它定义了搜索的边界,每行一个维度,第一列定义最小值,第二列定义最大值。
1 2 3 |
... # 生成初始点 solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0]) |
接下来,我们需要将每个维度的平方偏导数的衰减平均值初始化为 0.0。
1 2 3 |
... # 每个变量的平均平方梯度列表 sq_grad_avg = [0.0 for _ in range(bounds.shape[0])] |
然后,我们可以枚举搜索优化算法的固定次数迭代,该次数由“*n_iter*”超参数定义。
1 2 3 4 |
... # 运行梯度下降 for it in range(n_iter): ... |
第一步是使用 *derivative()* 函数计算当前解的梯度。
1 2 3 |
... # 计算梯度 gradient = derivative(solution[0], solution[1]) |
然后,我们需要计算偏导数的平方,并使用“rho”超参数更新平方偏导数的衰减平均值。
1 2 3 4 5 6 7 |
... # 更新平方偏导数的平均值 for i in range(gradient.shape[0]): # 计算平方梯度 sg = gradient[i]**2.0 # 更新平方梯度的移动平均值 sq_grad_avg[i] = (sq_grad_avg[i] * rho) + (sg * (1.0-rho)) |
然后,我们可以使用平方偏导数的移动平均值和梯度来计算下一个点的步长。
我们将一次处理一个变量,首先计算该变量的步长,然后计算该变量的新值。这些值会累积在一个数组中,直到我们拥有一个完全新的解,该解是根据自定义步长从当前点出发的最陡下降方向。
1 2 3 4 5 6 7 8 9 10 |
... # 逐个变量构建解 new_solution = list() for i in range(solution.shape[0]): # 计算此变量的步长 alpha = step_size / (1e-8 + sqrt(sq_grad_avg[i])) # 计算此变量的新位置 value = solution[i] - alpha * gradient[i] # 存储此变量 new_solution.append(value) |
然后可以使用 *objective()* 函数来评估这个新解,并报告搜索的性能。
1 2 3 4 5 6 |
... # 评估候选点 solution = asarray(new_solution) solution_eval = objective(solution[0], solution[1]) # 报告进展 print('>%d f(%s) = %.5f' % (it, solution, solution_eval)) |
就是这样。
我们可以将所有这些内容整合成一个名为 rmsprop() 的函数,该函数接受目标函数和导数函数的名称、包含域边界的数组以及算法迭代总数和初始学习率的超参数值,并返回最终解及其评估值。
完整的函数如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 带 rmsprop 的梯度下降算法 def rmsprop(objective, derivative, bounds, n_iter, step_size, rho): # 生成初始点 solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0]) # 每个变量的平均平方梯度列表 sq_grad_avg = [0.0 for _ in range(bounds.shape[0])] # 运行梯度下降 for it in range(n_iter): # 计算梯度 gradient = derivative(solution[0], solution[1]) # 更新平方偏导数的平均值 for i in range(gradient.shape[0]): # 计算平方梯度 sg = gradient[i]**2.0 # 更新平方梯度的移动平均值 sq_grad_avg[i] = (sq_grad_avg[i] * rho) + (sg * (1.0-rho)) # 逐个变量构建解 new_solution = list() for i in range(solution.shape[0]): # 计算此变量的步长 alpha = step_size / (1e-8 + sqrt(sq_grad_avg[i])) # 计算此变量的新位置 value = solution[i] - alpha * gradient[i] # 存储此变量 new_solution.append(value) # 评估候选点 solution = asarray(new_solution) solution_eval = objective(solution[0], solution[1]) # 报告进度 print('>%d f(%s) = %.5f' % (it, solution, solution_eval)) return [solution, solution_eval] |
注意:为了清晰起见,我们故意使用了列表和命令式编码风格,而不是矢量化操作。您可以随意修改实现,使其成为使用 NumPy 数组的矢量化实现,以获得更好的性能。
然后,我们可以定义我们的超参数并调用 rmsprop() 函数来优化我们的测试目标函数。
在这种情况下,我们将使用 50 次迭代算法,初始学习率为 0.01,rho 超参数值为 0.99,这些值都是经过一些反复试验后确定的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
... # 初始化伪随机数生成器 seed(1) # 定义输入范围 bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]]) # 定义总迭代次数 n_iter = 50 # 定义步长 step_size = 0.01 # rmsprop 的动量 rho = 0.99 # 执行带 rmsprop 的梯度下降搜索 best, score = rmsprop(objective, derivative, bounds, n_iter, step_size, rho) print('Done!') print('f(%s) = %f' % (best, score)) |
将所有这些内容整合在一起,带 RMSProp 的梯度下降优化示例的完整代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# 用于二维测试函数的梯度下降优化与 RMSProp from math import sqrt from numpy import asarray from numpy.random import rand from numpy.random import seed # 目标函数 def objective(x, y): return x**2.0 + y**2.0 # 目标函数的导数 def derivative(x, y): return asarray([x * 2.0, y * 2.0]) # 带 rmsprop 的梯度下降算法 def rmsprop(objective, derivative, bounds, n_iter, step_size, rho): # 生成初始点 solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0]) # 每个变量的平均平方梯度列表 sq_grad_avg = [0.0 for _ in range(bounds.shape[0])] # 运行梯度下降 for it in range(n_iter): # 计算梯度 gradient = derivative(solution[0], solution[1]) # 更新平方偏导数的平均值 for i in range(gradient.shape[0]): # 计算平方梯度 sg = gradient[i]**2.0 # 更新平方梯度的移动平均值 sq_grad_avg[i] = (sq_grad_avg[i] * rho) + (sg * (1.0-rho)) # 逐个变量构建解 new_solution = list() for i in range(solution.shape[0]): # 计算此变量的步长 alpha = step_size / (1e-8 + sqrt(sq_grad_avg[i])) # 计算此变量的新位置 value = solution[i] - alpha * gradient[i] # 存储此变量 new_solution.append(value) # 评估候选点 solution = asarray(new_solution) solution_eval = objective(solution[0], solution[1]) # 报告进度 print('>%d f(%s) = %.5f' % (it, solution, solution_eval)) return [solution, solution_eval] # 初始化伪随机数生成器 seed(1) # 定义输入范围 bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]]) # 定义总迭代次数 n_iter = 50 # 定义步长 step_size = 0.01 # rmsprop 的动量 rho = 0.99 # 执行带 rmsprop 的梯度下降搜索 best, score = rmsprop(objective, derivative, bounds, n_iter, step_size, rho) print('Done!') print('f(%s) = %f' % (best, score)) |
运行示例会将 RMSProp 优化算法应用于我们的测试问题,并报告算法每次迭代的搜索性能。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到,在约 33 次搜索迭代后找到了一个接近最优解,输入值接近 0.0 和 0.0,评估值为 0.0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
... >30 f([-9.61030898e-14 3.19352553e-03]) = 0.00001 >31 f([-3.42767893e-14 2.71513758e-03]) = 0.00001 >32 f([-1.21143047e-14 2.30636623e-03]) = 0.00001 >33 f([-4.24204875e-15 1.95738936e-03]) = 0.00000 >34 f([-1.47154482e-15 1.65972553e-03]) = 0.00000 >35 f([-5.05629595e-16 1.40605727e-03]) = 0.00000 >36 f([-1.72064649e-16 1.19007691e-03]) = 0.00000 >37 f([-5.79813754e-17 1.00635204e-03]) = 0.00000 >38 f([-1.93445677e-17 8.50208253e-04]) = 0.00000 >39 f([-6.38906842e-18 7.17626999e-04]) = 0.00000 >40 f([-2.08860690e-18 6.05156738e-04]) = 0.00000 >41 f([-6.75689941e-19 5.09835645e-04]) = 0.00000 >42 f([-2.16291217e-19 4.29124484e-04]) = 0.00000 >43 f([-6.84948980e-20 3.60848338e-04]) = 0.00000 >44 f([-2.14551097e-20 3.03146089e-04]) = 0.00000 >45 f([-6.64629576e-21 2.54426642e-04]) = 0.00000 >46 f([-2.03575780e-21 2.13331041e-04]) = 0.00000 >47 f([-6.16437387e-22 1.78699710e-04]) = 0.00000 >48 f([-1.84495110e-22 1.49544152e-04]) = 0.00000 >49 f([-5.45667355e-23 1.25022522e-04]) = 0.00000 完成! f([-5.45667355e-23 1.25022522e-04]) = 0.000000 |
RMSProp 的可视化
我们可以在域的等高线图上绘制搜索的进度。
这可以提供对算法迭代过程中搜索进展的直观感受。
我们必须更新 rmsprop() 函数,以维护搜索过程中找到的所有解的列表,然后在搜索结束时返回此列表。
包含这些更改的更新版本函数如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# 带 rmsprop 的梯度下降算法 def rmsprop(objective, derivative, bounds, n_iter, step_size, rho): # 跟踪所有解决方案 solutions = list() # 生成初始点 solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0]) # 每个变量的平均平方梯度列表 sq_grad_avg = [0.0 for _ in range(bounds.shape[0])] # 运行梯度下降 for it in range(n_iter): # 计算梯度 gradient = derivative(solution[0], solution[1]) # 更新平方偏导数的平均值 for i in range(gradient.shape[0]): # 计算平方梯度 sg = gradient[i]**2.0 # 更新平方梯度的移动平均值 sq_grad_avg[i] = (sq_grad_avg[i] * rho) + (sg * (1.0-rho)) # 构建解 new_solution = list() for i in range(solution.shape[0]): # 计算此变量的学习率 alpha = step_size / (1e-8 + sqrt(sq_grad_avg[i])) # 计算此变量的新位置 value = solution[i] - alpha * gradient[i] new_solution.append(value) # 存储新解 solution = asarray(new_solution) solutions.append(solution) # 评估候选点 solution_eval = objective(solution[0], solution[1]) # 报告进度 print('>%d f(%s) = %.5f' % (it, solution, solution_eval)) return solutions |
然后我们可以像以前一样执行搜索,这次检索解决方案列表而不是最终的最佳解决方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
... # 初始化伪随机数生成器 seed(1) # 定义输入范围 bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]]) # 定义总迭代次数 n_iter = 50 # 定义步长 step_size = 0.01 # rmsprop 的动量 rho = 0.99 # 执行带 rmsprop 的梯度下降搜索 solutions = rmsprop(objective, derivative, bounds, n_iter, step_size, rho) |
然后我们可以像以前一样创建目标函数的等高线图。
1 2 3 4 5 6 7 8 9 10 |
... # 以 0.1 为增量均匀采样输入范围 xaxis = arange(bounds[0,0], bounds[0,1], 0.1) yaxis = arange(bounds[1,0], bounds[1,1], 0.1) # 从坐标轴创建网格 x, y = meshgrid(xaxis, yaxis) # 计算目标值 results = objective(x, y) # 使用50个级别和jet颜色方案创建填充等高线图 pyplot.contourf(x, y, results, levels=50, cmap='jet') |
最后,我们可以将搜索过程中找到的每个解决方案绘制成一个由线连接的白点。
1 2 3 4 |
... # 将样本绘制为黑色圆圈 solutions = asarray(solutions) pyplot.plot(solutions[:, 0], solutions[:, 1], '.-', color='w') |
将所有内容整合在一起,下面列出了在测试问题上执行 RMSProp 优化并在等高线图上绘制结果的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# 在测试函数等高线图上绘制 rmsprop 搜索的示例 from math import sqrt from numpy import asarray from numpy import arange from numpy.random import rand from numpy.random import seed from numpy import meshgrid from matplotlib import pyplot from mpl_toolkits.mplot3d import Axes3D # 目标函数 def objective(x, y): return x**2.0 + y**2.0 # 目标函数的导数 def derivative(x, y): return asarray([x * 2.0, y * 2.0]) # 带 rmsprop 的梯度下降算法 def rmsprop(objective, derivative, bounds, n_iter, step_size, rho): # 跟踪所有解决方案 solutions = list() # 生成初始点 solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0]) # 每个变量的平均平方梯度列表 sq_grad_avg = [0.0 for _ in range(bounds.shape[0])] # 运行梯度下降 for it in range(n_iter): # 计算梯度 gradient = derivative(solution[0], solution[1]) # 更新平方偏导数的平均值 for i in range(gradient.shape[0]): # 计算平方梯度 sg = gradient[i]**2.0 # 更新平方梯度的移动平均值 sq_grad_avg[i] = (sq_grad_avg[i] * rho) + (sg * (1.0-rho)) # 构建解 new_solution = list() for i in range(solution.shape[0]): # 计算此变量的学习率 alpha = step_size / (1e-8 + sqrt(sq_grad_avg[i])) # 计算此变量的新位置 value = solution[i] - alpha * gradient[i] new_solution.append(value) # 存储新解 solution = asarray(new_solution) solutions.append(solution) # 评估候选点 solution_eval = objective(solution[0], solution[1]) # 报告进度 print('>%d f(%s) = %.5f' % (it, solution, solution_eval)) return solutions # 初始化伪随机数生成器 seed(1) # 定义输入范围 bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]]) # 定义总迭代次数 n_iter = 50 # 定义步长 step_size = 0.01 # rmsprop 的动量 rho = 0.99 # 执行带 rmsprop 的梯度下降搜索 solutions = rmsprop(objective, derivative, bounds, n_iter, step_size, rho) # 以 0.1 为增量均匀采样输入范围 xaxis = arange(bounds[0,0], bounds[0,1], 0.1) yaxis = arange(bounds[1,0], bounds[1,1], 0.1) # 从坐标轴创建网格 x, y = meshgrid(xaxis, yaxis) # 计算目标值 results = objective(x, y) # 使用50个级别和jet颜色方案创建填充等高线图 pyplot.contourf(x, y, results, levels=50, cmap='jet') # 将样本绘制为黑色圆圈 solutions = asarray(solutions) pyplot.plot(solutions[:, 0], solutions[:, 1], '.-', color='w') # 显示绘图 pyplot.show() |
运行示例像以前一样执行搜索,但在此情况下,创建了目标函数的等高线图。
在这种情况下,我们可以看到搜索过程中找到的每个解决方案都显示为一个白点,从最优值上方开始,并逐渐靠近图中中心的最优值。

测试目标函数等高线图和 RMSProp 搜索结果
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
论文
- 讲座 6e,rmsprop:将梯度除以其近期幅度的运行平均值,机器学习神经网络,Geoffrey Hinton。
书籍
API
文章
- 梯度下降,维基百科.
- 随机梯度下降,维基百科.
- 梯度下降优化算法综述, 2016.
总结
在本教程中,您将了解如何从头开始开发具有 RMSProp 优化算法的梯度下降。
具体来说,你学到了:
- 梯度下降是一种优化算法,它利用目标函数的梯度来导航搜索空间。
- 梯度下降可以通过使用每个输入变量的自动自适应步长来更新,该步长使用偏导数的衰减平均值,称为 RMSProp。
- 如何从零开始实现 RMSProp 优化算法,并将其应用于目标函数并评估结果。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
非常棒的文章!
我对粒子群优化也很感兴趣,您有相关的文章吗?
如果没有,它最常用于哪些应用或在哪些情况下使用?
谢谢。
目前还没有。
PSO 用于优化没有导数的高维实值函数。
谢谢!!我一直想把它替换掉神经网络系统,因为反向传播需要更长的时间。您对此有什么看法?
您不会移除反向传播,它将与 RMSprop 一起使用。
谢谢您,先生
不客气。
嗨,Jason,
是否有可能在 sklearn 中从头开始运行 RMSProp、Adadelta、Adamax 和 Nadam 公式进行优化?
我正在使用 Sklearn MLP regressor,我想将上述优化器的结果与 Sklearn 中的 Adam 进行比较?
如果不可能,我能否将我的 Sklearn MLP 模型复制到 Tensorflow 中并在那里比较优化器?
期待您的回复。
此致,
Faraz