如何快速掌握Adam优化算法

发布时间:2021-10-15 13:42:23 作者:iii
来源:亿速云 阅读:125

这篇文章主要讲解了“如何快速掌握Adam优化算法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何快速掌握Adam优化算法”吧!

本教程分为三个部分:他们是:

        二维测试问题

        Adam的梯度下降优化

        Adam可视化

梯度下降

梯度下降是一种优化算法。它在技术上称为一阶优化算法,因为它明确利用了目标目标函数的一阶导数。一阶导数,或简称为“导数”,是目标函数在特定点(例如,点)上的变化率或斜率。用于特定输入。如果目标函数采用多个输入变量,则将其称为多元函数,并且可以将输入变量视为向量。反过来,多元目标函数的导数也可以视为向量,通常称为梯度。

梯度:多元目标函数的一阶导数。

对于特定输入,导数或梯度指向目标函数最陡峭的上升方向。

梯度下降是指一种最小化优化算法,该算法遵循目标函数的下坡梯度负值来定位函数的最小值。梯度下降算法需要一个正在优化的目标函数和该目标函数的导数函数。目标函数f()返回给定输入集合的分数,导数函数f'()给出给定输入集合的目标函数的导数。梯度下降算法需要问题中的起点(x),例如输入空间中的随机选择点。

假设我们正在最小化目标函数,然后计算导数并在输入空间中采取一步,这将导致目标函数下坡运动。下坡运动是通过首先计算输入空间中的运动量来进行的,计算方法是将步长(称为alpha或学习率)乘以坡度。然后从当前点减去该值,以确保我们逆梯度移动或向下移动目标函数。

x(t)= x(t-1)–step* f'(x(t-1))

在给定点的目标函数越陡峭,梯度的幅度越大,反过来,在搜索空间中采取的步伐也越大。使用步长超参数来缩放步长的大小。

步长(alpha):超参数,控制算法每次迭代时相对于梯度在搜索空间中移动多远。

如果步长太小,则搜索空间中的移动将很小,并且搜索将花费很长时间。如果步长太大,则搜索可能会在搜索空间附近反弹并跳过最优值。

现在我们已经熟悉了梯度下降优化算法,下面让我们看一下Adam算法。

Adam优化算法

自适应运动估计算法(简称“Adam”)是梯度下降优化算法的扩展。Diederik Kingma和Jimmy Lei Ba在2014年发表的题为“Adam:随机优化方法”的论文中描述了该算法。Adam旨在加速优化过程,例如减少达到最佳状态所需的功能评估次数,或提高优化算法的功能,例如产生更好的最终结果。这是通过为每个要优化的输入参数计算步长来实现的。重要的是,每个步长都将根据每个变量遇到的梯度(偏导数)自动调整搜索过程的吞吐量。

让我们逐步介绍该算法的每个元素。首先,对于作为搜索一部分而被优化的每个参数,我们必须维持一个矩矢量和指数加权无穷大范数,分别称为m和v(真是希腊字母nu)。在搜索开始时将它们初始化为0.0。

m = 0

v = 0

该算法在从t=1开始的时间t内迭代执行,并且每次迭代都涉及计算一组新的参数值x,例如。从x(t-1)到x(t)。如果我们专注于更新一个参数,这可能很容易理解该算法,该算法概括为通过矢量运算来更新所有参数。首先,计算当前时间步长的梯度(偏导数)。

g(t)= f'(x(t-1))

接下来,使用梯度和超参数beta1更新第一时刻。

m(t)= beta1 * m(t-1)+(1 – beta1)* g(t)

然后,使用平方梯度和超参数beta2更新第二时刻。

v(t)= beta2 * v(t-1)+(1 – beta2)* g(t)^ 2

由于第一和第二力矩是用零值初始化的,所以它们是有偏的。接下来,对第一力矩和第二力矩进行偏差校正,并以第一力矩为起点:

mhat(t)= m(t)/(1 – beta1(t))

然后第二个时刻:

vhat(t)= v(t)/(1 – beta2(t))

注意,beta1(t)和beta2(t)指的是beta1和beta2超参数,它们在算法的迭代过程中按时间表衰减。可以使用静态衰减时间表,尽管该论文建议以下内容:

beta1(t)= beta1 ^ t

beta2(t)= beta2 ^ t

最后,我们可以为该迭代计算参数的值。

x(t)= x(t-1)– alpha * mhat(t)/(sqrt(vhat(t))+ eps)

其中alpha是步长超参数,eps是一个较小的值(epsilon),例如1e-8,可确保我们不会遇到被零除的误差,而sqrt()是平方根函数。

注意,可以使用对本文中列出的更新规则进行更有效的重新排序:

alpha(t)= alpha * sqrt(1 – beta2(t))/(1 – beta1(t)) x(t)= x(t-1)– alpha(t)* m(t)/(sqrt(v(t))+ eps)

回顾一下,该算法有三个超参数,它们是:

接下来,让我们看看如何在Python中从头开始实现该算法。

Adam梯度下降

在本节中,我们将探讨如何使用Adam实现梯度下降优化算法。

二维测试问题

首先,让我们定义一个优化函数。我们将使用一个简单的二维函数,该函数将每个维的输入平方,并定义有效输入的范围(从-1.0到1.0)。

下面的Objective()函数实现了此功能

# objective function  def objective(x, y):   return x**2.0 + y**2.0

我们可以创建数据集的三维图,以了解响应面的曲率。下面列出了绘制目标函数的完整示例。

# 3d plot of the test function  from numpy import arange  from numpy import meshgrid  from matplotlib import pyplot   # objective function  def objective(x, y):   return x**2.0 + y**2.0   # define range for input  r_min, r_max = -1.0, 1.0  # sample input range uniformly at 0.1 increments  xaxis = arange(r_min, r_max, 0.1)  yaxis = arange(r_min, r_max, 0.1)  # create a mesh from the axis  x, y = meshgrid(xaxis, yaxis)  # compute targets results = objective(x, y)  # create a surface plot with the jet color scheme  figure = pyplot.figure()  axis = figure.gca(projection='3d')  axis.plot_surface(x, y, results, cmap='jet') # show the plot  pyplot.show()

运行示例将创建目标函数的三维表面图。我们可以看到全局最小值为f(0,0)= 0的熟悉的碗形状。

如何快速掌握Adam优化算法

我们还可以创建函数的二维图。这在以后要绘制搜索进度时会很有帮助。下面的示例创建目标函数的轮廓图。

# contour plot of the test function  from numpy import asarray  from numpy import arange  from numpy import meshgrid  from matplotlib import pyplot   # objective function  def objective(x, y):   return x**2.0 + y**2.0   # define range for input  bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]])  # sample input range uniformly at 0.1 increments  xaxis = arange(bounds[0,0], bounds[0,1], 0.1)  yaxis = arange(bounds[1,0], bounds[1,1], 0.1)  # create a mesh from the axis  x, y = meshgrid(xaxis, yaxis)  # compute targets  results = objective(x, y)  # create a filled contour plot with 50 levels and jet color scheme  pyplot.contourf(x, y, results, levels=50, cmap='jet')  # show the plot  pyplot.show()

运行示例将创建目标函数的二维轮廓图。我们可以看到碗的形状被压缩为以颜色渐变显示的轮廓。我们将使用该图来绘制在搜索过程中探索的特定点。

如何快速掌握Adam优化算法

现在我们有了一个测试目标函数,让我们看一下如何实现Adam优化算法。

Adam梯度下降优化

我们可以将带有Adam的梯度下降应用于测试问题。首先,我们需要一个函数来计算此函数的导数。

f(x)= x ^ 2

f'(x)= x * 2

x ^ 2的导数在每个维度上均为x * 2。 derived()函数在下面实现了这一点。

# derivative of objective function  def derivative(x, y):   return asarray([x * 2.0, y * 2.0])

接下来,我们可以实现梯度下降优化。首先,我们可以选择问题范围内的随机点作为搜索的起点。假定我们有一个数组,该数组定义搜索范围,每个维度一行,并且第一列定义最小值,第二列定义维度的最大值。

# generate an initial point  x = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])  score = objective(x[0], x[1])

接下来,我们需要将第一时刻和第二时刻初始化为零。

# initialize first and second moments  m = [0.0 for _ in range(bounds.shape[0])]  v = [0.0 for _ in range(bounds.shape[0])]

然后,我们运行由“ n_iter”超参数定义的算法的固定迭代次数。

...  # run iterations of gradient descent  for t in range(n_iter):   ...

第一步是使用导数()函数计算当前解决方案的梯度。

# calculate gradient  gradient = derivative(solution[0], solution[1])

第一步是计算当前参数集的导数。

# calculate gradient g(t)  g = derivative(x[0], x[1])

接下来,我们需要执行Adam更新计算。为了提高可读性,我们将使用命令式编程样式一次执行一个变量的这些计算。

在实践中,我建议使用NumPy向量运算以提高效率。

...  # build a solution one variable at a time  for i in range(x.shape[0]):   ...

首先,我们需要计算力矩。

# m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)  m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]

然后是第二个时刻。

# v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2  v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2

然后对第一和第二时刻进行偏差校正。

# mhat(t) = m(t) / (1 - beta1(t))  mmhat = m[i] / (1.0 - beta1**(t+1)) # vhat(t) = v(t) / (1 - beta2(t))  vvhat = v[i] / (1.0 - beta2**(t+1))

然后最后是更新的变量值。

# x(t) = x(t-1) - alpha * mhat(t) / (sqrt(vhat(t)) + eps)  x[i] = x[i] - alpha * mhat / (sqrt(vhat) + eps)

然后,针对要优化的每个参数重复此操作。在迭代结束时,我们可以评估新的参数值并报告搜索的性能。

# evaluate candidate point  score = objective(x[0], x[1])  # report progress  print('>%d f(%s) = %.5f' % (t, x, score))

我们可以将所有这些结合到一个名为adam()的函数中,该函数采用目标函数和派生函数的名称以及算法超参数,并返回在搜索及其评估结束时找到的最佳解决方案。

下面列出了完整的功能。

# gradient descent algorithm with adam  def adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2, eps=1e-8):   # generate an initial point   x = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])   score = objective(x[0], x[1])   # initialize first and second moments   m = [0.0 for _ in range(bounds.shape[0])]   v = [0.0 for _ in range(bounds.shape[0])]   # run the gradient descent updates   for t in range(n_iter):    # calculate gradient g(t)    g = derivative(x[0], x[1])    # build a solution one variable at a time    for i in range(x.shape[0]):     # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)     m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]     # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2     v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2     # mhat(t) = m(t) / (1 - beta1(t))     mmhat = m[i] / (1.0 - beta1**(t+1))     # vhat(t) = v(t) / (1 - beta2(t))     vvhat = v[i] / (1.0 - beta2**(t+1))     # x(t) = x(t-1) - alpha * mhat(t) / (sqrt(vhat(t)) + eps)     x[i] = x[i] - alpha * mhat / (sqrt(vhat) + eps)    # evaluate candidate point    score = objective(x[0], x[1])    # report progress    print('>%d f(%s) = %.5f' % (t, x, score))   return [x, score]

注意:为了提高可读性,我们有意使用列表和命令式编码样式,而不是矢量化操作。随意将实现改编为带有NumPy数组的矢量化实现,以实现更好的性能。

然后,我们可以定义我们的超参数并调用adam()函数来优化我们的测试目标函数。

在这种情况下,我们将使用算法的60次迭代,初始步长为0.02,beta1和beta2值分别为0.8和0.999。经过一些反复试验后,发现了这些超参数值。

# seed the pseudo random number generator  seed(1)  # define range for input  bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]])  # define the total iterations  n_iter = 60 # steps size  alpha = 0.02  # factor for average gradient  beta1 = 0.8  # factor for average squared gradient  beta2 = 0.999  # perform the gradient descent search with adam  best, score = adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2)  print('Done!')  print('f(%s) = %f' % (best, score))

综合所有这些,下面列出了使用Adam进行梯度下降优化的完整示例。

# gradient descent optimization with adam for a two-dimensional test function  from math import sqrt  from numpy import asarray  from numpy.random import rand  from numpy.random import seed   # objective function  def objective(x, y):   return x**2.0 + y**2.0  # derivative of objective function  def derivative(x, y):   return asarray([x * 2.0, y * 2.0])  # gradient descent algorithm with adam  def adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2, eps=1e-8):   # generate an initial point   x = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])   score = objective(x[0], x[1])   # initialize first and second moments   m = [0.0 for _ in range(bounds.shape[0])]   v = [0.0 for _ in range(bounds.shape[0])]   # run the gradient descent updates   for t in range(n_iter):    # calculate gradient g(t)    g = derivative(x[0], x[1])    # build a solution one variable at a time    for i in range(x.shape[0]):     # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)     m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]     # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2     v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2     # mhat(t) = m(t) / (1 - beta1(t))     mmhat = m[i] / (1.0 - beta1**(t+1))     # vhat(t) = v(t) / (1 - beta2(t))     vvhat = v[i] / (1.0 - beta2**(t+1))     # x(t) = x(t-1) - alpha * mhat(t) / (sqrt(vhat(t)) + eps)     x[i] = x[i] - alpha * mhat / (sqrt(vhat) + eps)    # evaluate candidate point    score = objective(x[0], x[1])    # report progress    print('>%d f(%s) = %.5f' % (t, x, score))  return [x, score]  # seed the pseudo random number generator  seed(1)  # define range for input  bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]])  # define the total iterations  n_iter = 60  # steps size  alpha = 0.02  # factor for average gradient  beta1 = 0.8  # factor for average squared gradient  beta2 = 0.999  # perform the gradient descent search with adam  best, score = adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2)  print('Done!')  print('f(%s) = %f' % (best, score))

运行示例将Adam优化算法应用于我们的测试问题,并报告算法每次迭代的搜索性能。

注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑运行该示例几次并比较平均结果。

在这种情况下,我们可以看到在搜索53次迭代后找到了接近最佳的解决方案,输入值接近0.0和0.0,评估为0.0。

>50 f([-0.00056912 -0.00321961]) = 0.00001  >51 f([-0.00052452 -0.00286514]) = 0.00001  >52 f([-0.00043908 -0.00251304]) = 0.00001  >53 f([-0.0003283  -0.00217044]) = 0.00000  >54 f([-0.00020731 -0.00184302]) = 0.00000  >55 f([-8.95352320e-05 -1.53514076e-03]) = 0.00000  >56 f([ 1.43050285e-05 -1.25002847e-03]) = 0.00000  >57 f([ 9.67123406e-05 -9.89850279e-04]) = 0.00000  >58 f([ 0.00015359 -0.00075587]) = 0.00000  >59 f([ 0.00018407 -0.00054858]) = 0.00000  Done!  f([ 0.00018407 -0.00054858]) = 0.000000

Adam可视化

我们可以在域的轮廓图上绘制Adam搜索的进度。这可以为算法迭代过程中的搜索进度提供直观的认识。我们必须更新adam()函数以维护在搜索过程中找到的所有解决方案的列表,然后在搜索结束时返回此列表。下面列出了具有这些更改的功能的更新版本。

# gradient descent algorithm with adam  def adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2, eps=1e-8):   solutions = list()   # generate an initial point   x = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])   score = objective(x[0], x[1])   # initialize first and second moments   m = [0.0 for _ in range(bounds.shape[0])]   v = [0.0 for _ in range(bounds.shape[0])]   # run the gradient descent updates   for t in range(n_iter):    # calculate gradient g(t)    g = derivative(x[0], x[1])    # build a solution one variable at a time    for i in range(bounds.shape[0]):     # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)     m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]     # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2     v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2     # mhat(t) = m(t) / (1 - beta1(t))     mmhat = m[i] / (1.0 - beta1**(t+1))     # vhat(t) = v(t) / (1 - beta2(t))     vvhat = v[i] / (1.0 - beta2**(t+1))     # x(t) = x(t-1) - alpha * mhat(t) / (sqrt(vhat(t)) + ep)     x[i] = x[i] - alpha * mhat / (sqrt(vhat) + eps)    # evaluate candidate point    score = objective(x[0], x[1])    # keep track of solutions    solutions.append(x.copy())    # report progress    print('>%d f(%s) = %.5f' % (t, x, score))   return solutions

然后,我们可以像以前一样执行搜索,这一次将检索解决方案列表,而不是最佳的最终解决方案。

# seed the pseudo random number generator  seed(1)  # define range for input  bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]])  # define the total iterations  n_iter = 60  # steps size  alpha = 0.02  # factor for average gradient  beta1 = 0.8  # factor for average squared gradient  beta2 = 0.999  # perform the gradient descent search with adam  solutions = adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2)

然后,我们可以像以前一样创建目标函数的轮廓图。

# sample input range uniformly at 0.1 increments  xaxis = arange(bounds[0,0], bounds[0,1], 0.1)  yaxis = arange(bounds[1,0], bounds[1,1], 0.1)  # create a mesh from the axis  x, y = meshgrid(xaxis, yaxis)  # compute targets  results = objective(x, y)  # create a filled contour plot with 50 levels and jet color scheme  pyplot.contourf(x, y, results, levels=50, cmap='jet')

最后,我们可以将在搜索过程中找到的每个解决方案绘制成一条由一条线连接的白点。

# plot the sample as black circles  solutions = asarray(solutions)  pyplot.plot(solutions[:, 0], solutions[:, 1], '.-', color='w')

综上所述,下面列出了对测试问题执行Adam优化并将结果绘制在轮廓图上的完整示例。

# example of plotting the adam search on a contour plot of the test function  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  # objective function  def objective(x, y):   return x**2.0 + y**2.0  # derivative of objective function  def derivative(x, y):   return asarray([x * 2.0, y * 2.0])  # gradient descent algorithm with adam  def adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2, eps=1e-8):   solutions = list()   # generate an initial point   x = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])   score = objective(x[0], x[1])   # initialize first and second moments   m = [0.0 for _ in range(bounds.shape[0])]   v = [0.0 for _ in range(bounds.shape[0])]   # run the gradient descent updates   for t in range(n_iter):    # calculate gradient g(t)    g = derivative(x[0], x[1])    # build a solution one variable at a time    for i in range(bounds.shape[0]):     # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)     m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]     # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2     v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2     # mhat(t) = m(t) / (1 - beta1(t))     mmhat = m[i] / (1.0 - beta1**(t+1))     # vhat(t) = v(t) / (1 - beta2(t))     vvhat = v[i] / (1.0 - beta2**(t+1))     # x(t) = x(t-1) - alpha * mhat(t) / (sqrt(vhat(t)) + ep)     x[i] = x[i] - alpha * mhat / (sqrt(vhat) + eps)    # evaluate candidate point    score = objective(x[0], x[1])    # keep track of solutions    solutions.append(x.copy())    # report progress    print('>%d f(%s) = %.5f' % (t, x, score))   return solutions # seed the pseudo random number generator  seed(1)  # define range for input  bounds = asarray([[-1.0, 1.0], [-1.0, 1.0]])  # define the total iterations  n_iter = 60  # steps size  alpha = 0.02  # factor for average gradient  beta1 = 0.8 # factor for average squared gradient  beta2 = 0.999  # perform the gradient descent search with adam  solutions = adam(objective, derivative, bounds, n_iter, alpha, beta1, beta2)  # sample input range uniformly at 0.1 increments  xaxis = arange(bounds[0,0], bounds[0,1], 0.1)  yaxis = arange(bounds[1,0], bounds[1,1], 0.1)  # create a mesh from the axis  x, y = meshgrid(xaxis, yaxis)  # compute targets  results = objective(x, y)  # create a filled contour plot with 50 levels and jet color scheme  pyplot.contourf(x, y, results, levels=50, cmap='jet')  # plot the sample as black circles  solutions = asarray(solutions)  pyplot.plot(solutions[:, 0], solutions[:, 1], '.-', color='w')  # show the plot  pyplot.show()

运行示例将像以前一样执行搜索,但是在这种情况下,将创建目标函数的轮廓图。

在这种情况下,我们可以看到在搜索过程中找到的每个解决方案都显示一个白点,从最优点开始,逐渐靠近图中心的最优点。

如何快速掌握Adam优化算法

感谢各位的阅读,以上就是“如何快速掌握Adam优化算法”的内容了,经过本文的学习后,相信大家对如何快速掌握Adam优化算法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. 如何快速掌握前端开发技巧
  2. 怎么快速掌握Python基础语法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

adam

上一篇:apollo在spring-boot中的加载过程是什么

下一篇:Java如何实现爬虫

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》