5分鐘快速掌握Adam優(yōu)化算法
梯度下降是一種優(yōu)化算法,遵循目標函數(shù)的負梯度以定位函數(shù)的最小值。
梯度下降的局限性是,所有輸入變量都使用單個步長(學習率)。像AdaGrad和RMSProp這樣的梯度下降的擴展會更新算法,以對每個輸入變量使用單獨的步長,但可能會導致步長迅速減小到非常小的值。自適應運動估計算法(Adam)是梯度下降的擴展,是AdaGrad和RMSProp等技術的自然繼承者,該技術可自動為目標函數(shù)的每個輸入變量調整學習率,并通過使用以指數(shù)方式降低梯度的移動平均值以更新變量。
在本教程中,您將發(fā)現(xiàn)如何從頭開始使用Adam優(yōu)化算法開發(fā)梯度下降。完成本教程后,您將知道:
- 梯度下降是一種優(yōu)化算法,它使用目標函數(shù)的梯度來導航搜索空間。
- 可以通過使用稱為Adam的偏導數(shù)的遞減平均值,將梯度下降更新為對每個輸入變量使用自動自適應步長。
- 如何從頭開始實施Adam優(yōu)化算法并將其應用于目標函數(shù)并評估結果。
教程概述
本教程分為三個部分:他們是:
- 梯度下降
- Adam優(yōu)化算法
- Adam梯度下降
二維測試問題
Adam的梯度下降優(yōu)化
Adam可視化
梯度下降
梯度下降是一種優(yōu)化算法。它在技術上稱為一階優(yōu)化算法,因為它明確利用了目標目標函數(shù)的一階導數(shù)。一階導數(shù),或簡稱為“導數(shù)”,是目標函數(shù)在特定點(例如,點)上的變化率或斜率。用于特定輸入。如果目標函數(shù)采用多個輸入變量,則將其稱為多元函數(shù),并且可以將輸入變量視為向量。反過來,多元目標函數(shù)的導數(shù)也可以視為向量,通常稱為梯度。
梯度:多元目標函數(shù)的一階導數(shù)。
對于特定輸入,導數(shù)或梯度指向目標函數(shù)最陡峭的上升方向。
梯度下降是指一種最小化優(yōu)化算法,該算法遵循目標函數(shù)的下坡梯度負值來定位函數(shù)的最小值。梯度下降算法需要一個正在優(yōu)化的目標函數(shù)和該目標函數(shù)的導數(shù)函數(shù)。目標函數(shù)f()返回給定輸入集合的分數(shù),導數(shù)函數(shù)f'()給出給定輸入集合的目標函數(shù)的導數(shù)。梯度下降算法需要問題中的起點(x),例如輸入空間中的隨機選擇點。
假設我們正在最小化目標函數(shù),然后計算導數(shù)并在輸入空間中采取一步,這將導致目標函數(shù)下坡運動。下坡運動是通過首先計算輸入空間中的運動量來進行的,計算方法是將步長(稱為alpha或學習率)乘以坡度。然后從當前點減去該值,以確保我們逆梯度移動或向下移動目標函數(shù)。
x(t)= x(t-1)–step* f'(x(t-1))
在給定點的目標函數(shù)越陡峭,梯度的幅度越大,反過來,在搜索空間中采取的步伐也越大。使用步長超參數(shù)來縮放步長的大小。
步長(alpha):超參數(shù),控制算法每次迭代時相對于梯度在搜索空間中移動多遠。
如果步長太小,則搜索空間中的移動將很小,并且搜索將花費很長時間。如果步長太大,則搜索可能會在搜索空間附近反彈并跳過最優(yōu)值。
現(xiàn)在我們已經熟悉了梯度下降優(yōu)化算法,下面讓我們看一下Adam算法。
Adam優(yōu)化算法
自適應運動估計算法(簡稱“Adam”)是梯度下降優(yōu)化算法的擴展。Diederik Kingma和Jimmy Lei Ba在2014年發(fā)表的題為“Adam:隨機優(yōu)化方法”的論文中描述了該算法。Adam旨在加速優(yōu)化過程,例如減少達到最佳狀態(tài)所需的功能評估次數(shù),或提高優(yōu)化算法的功能,例如產生更好的最終結果。這是通過為每個要優(yōu)化的輸入?yún)?shù)計算步長來實現(xiàn)的。重要的是,每個步長都將根據(jù)每個變量遇到的梯度(偏導數(shù))自動調整搜索過程的吞吐量。
讓我們逐步介紹該算法的每個元素。首先,對于作為搜索一部分而被優(yōu)化的每個參數(shù),我們必須維持一個矩矢量和指數(shù)加權無窮大范數(shù),分別稱為m和v(真是希臘字母nu)。在搜索開始時將它們初始化為0.0。
m = 0
v = 0
該算法在從t=1開始的時間t內迭代執(zhí)行,并且每次迭代都涉及計算一組新的參數(shù)值x,例如。從x(t-1)到x(t)。如果我們專注于更新一個參數(shù),這可能很容易理解該算法,該算法概括為通過矢量運算來更新所有參數(shù)。首先,計算當前時間步長的梯度(偏導數(shù))。
g(t)= f'(x(t-1))
接下來,使用梯度和超參數(shù)beta1更新第一時刻。
m(t)= beta1 * m(t-1)+(1 – beta1)* g(t)
然后,使用平方梯度和超參數(shù)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超參數(shù),它們在算法的迭代過程中按時間表衰減??梢允褂渺o態(tài)衰減時間表,盡管該論文建議以下內容:
beta1(t)= beta1 ^ t
beta2(t)= beta2 ^ t
最后,我們可以為該迭代計算參數(shù)的值。
x(t)= x(t-1)– alpha * mhat(t)/(sqrt(vhat(t))+ eps)
其中alpha是步長超參數(shù),eps是一個較小的值(epsilon),例如1e-8,可確保我們不會遇到被零除的誤差,而sqrt()是平方根函數(shù)。
注意,可以使用對本文中列出的更新規(guī)則進行更有效的重新排序:
alpha(t)= alpha * sqrt(1 – beta2(t))/(1 – beta1(t)) x(t)= x(t-1)– alpha(t)* m(t)/(sqrt(v(t))+ eps)
回顧一下,該算法有三個超參數(shù),它們是:
- alpha:初始步長(學習率),典型值為0.001。
- beta1:第一個動量的衰減因子,典型值為0.9。
- beta2:無窮大范數(shù)的衰減因子,典型值為0.999。
接下來,讓我們看看如何在Python中從頭開始實現(xiàn)該算法。
Adam梯度下降
在本節(jié)中,我們將探討如何使用Adam實現(xiàn)梯度下降優(yōu)化算法。
二維測試問題
首先,讓我們定義一個優(yōu)化函數(shù)。我們將使用一個簡單的二維函數(shù),該函數(shù)將每個維的輸入平方,并定義有效輸入的范圍(從-1.0到1.0)。
下面的Objective()函數(shù)實現(xiàn)了此功能
- # objective function
- def objective(x, y):
- return x**2.0 + y**2.0
我們可以創(chuàng)建數(shù)據(jù)集的三維圖,以了解響應面的曲率。下面列出了繪制目標函數(shù)的完整示例。
- # 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()
運行示例將創(chuàng)建目標函數(shù)的三維表面圖。我們可以看到全局最小值為f(0,0)= 0的熟悉的碗形狀。
我們還可以創(chuàng)建函數(shù)的二維圖。這在以后要繪制搜索進度時會很有幫助。下面的示例創(chuàng)建目標函數(shù)的輪廓圖。
- # 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()
運行示例將創(chuàng)建目標函數(shù)的二維輪廓圖。我們可以看到碗的形狀被壓縮為以顏色漸變顯示的輪廓。我們將使用該圖來繪制在搜索過程中探索的特定點。
現(xiàn)在我們有了一個測試目標函數(shù),讓我們看一下如何實現(xiàn)Adam優(yōu)化算法。
Adam梯度下降優(yōu)化
我們可以將帶有Adam的梯度下降應用于測試問題。首先,我們需要一個函數(shù)來計算此函數(shù)的導數(shù)。
f(x)= x ^ 2
f'(x)= x * 2
x ^ 2的導數(shù)在每個維度上均為x * 2。 derived()函數(shù)在下面實現(xiàn)了這一點。
- # derivative of objective function
- def derivative(x, y):
- return asarray([x * 2.0, y * 2.0])
接下來,我們可以實現(xiàn)梯度下降優(yōu)化。首先,我們可以選擇問題范圍內的隨機點作為搜索的起點。假定我們有一個數(shù)組,該數(shù)組定義搜索范圍,每個維度一行,并且第一列定義最小值,第二列定義維度的最大值。
- # 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”超參數(shù)定義的算法的固定迭代次數(shù)。
- ...
- # run iterations of gradient descent
- for t in range(n_iter):
- ...
第一步是使用導數(shù)()函數(shù)計算當前解決方案的梯度。
- # calculate gradient
- gradient = derivative(solution[0], solution[1])
第一步是計算當前參數(shù)集的導數(shù)。
- # calculate gradient g(t)
- g = derivative(x[0], x[1])
接下來,我們需要執(zhí)行Adam更新計算。為了提高可讀性,我們將使用命令式編程樣式一次執(zhí)行一個變量的這些計算。
在實踐中,我建議使用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)
然后,針對要優(yōu)化的每個參數(shù)重復此操作。在迭代結束時,我們可以評估新的參數(shù)值并報告搜索的性能。
- # evaluate candidate point
- score = objective(x[0], x[1])
- # report progress
- print('>%d f(%s) = %.5f' % (t, x, score))
我們可以將所有這些結合到一個名為adam()的函數(shù)中,該函數(shù)采用目標函數(shù)和派生函數(shù)的名稱以及算法超參數(shù),并返回在搜索及其評估結束時找到的最佳解決方案。
下面列出了完整的功能。
- # 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]
注意:為了提高可讀性,我們有意使用列表和命令式編碼樣式,而不是矢量化操作。隨意將實現(xiàn)改編為帶有NumPy數(shù)組的矢量化實現(xiàn),以實現(xiàn)更好的性能。
然后,我們可以定義我們的超參數(shù)并調用adam()函數(shù)來優(yōu)化我們的測試目標函數(shù)。
在這種情況下,我們將使用算法的60次迭代,初始步長為0.02,beta1和beta2值分別為0.8和0.999。經過一些反復試驗后,發(fā)現(xiàn)了這些超參數(shù)值。
- # 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進行梯度下降優(yōu)化的完整示例。
- # 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優(yōu)化算法應用于我們的測試問題,并報告算法每次迭代的搜索性能。
注意:由于算法或評估程序的隨機性,或者數(shù)值精度的差異,您的結果可能會有所不同??紤]運行該示例幾次并比較平均結果。
在這種情況下,我們可以看到在搜索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()函數(shù)以維護在搜索過程中找到的所有解決方案的列表,然后在搜索結束時返回此列表。下面列出了具有這些更改的功能的更新版本。
- # 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
然后,我們可以像以前一樣執(zhí)行搜索,這一次將檢索解決方案列表,而不是最佳的最終解決方案。
- # 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)
然后,我們可以像以前一樣創(chuàng)建目標函數(shù)的輪廓圖。
- # 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')
綜上所述,下面列出了對測試問題執(zhí)行Adam優(yōu)化并將結果繪制在輪廓圖上的完整示例。
- # 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()
運行示例將像以前一樣執(zhí)行搜索,但是在這種情況下,將創(chuàng)建目標函數(shù)的輪廓圖。
在這種情況下,我們可以看到在搜索過程中找到的每個解決方案都顯示一個白點,從最優(yōu)點開始,逐漸靠近圖中心的最優(yōu)點。