機器學習的項目,不可避免的須要補充一些優化算法,對於優化算法,登山算法仍是比較重要的.鑑於此,花了些時間仔細閱讀了些登山算法的paper.基於這些,作一些總結.python
1. 登山算法簡單描述算法
2. 登山算法的主要算法app
2.1 首選登山算法dom
2.2 最陡登山算法機器學習
2.3 隨機從新開始登山算法ide
2.4 模擬退火算法(也是登山算法)函數
3. 實例求解學習
登山算法,是一種局部貪心的最優算法. 該算法的主要思想是:每次拿相鄰點與當前點進行比對,取二者中較優者,做爲爬坡的下一步.優化
舉一個例子,求解下面表達式atom
的最大值. 且假設 x,y均按爲0.1間隔遞增.
爲了更好的描述,咱們先使用pyhton畫出該函數的圖像:
圖像的python代碼:
1 # encoding:utf8 2 from matplotlib import pyplot as plt 3 import numpy as np 4 from mpl_toolkits.mplot3d import Axes3D 5 6 7 def func(X, Y, x_move=0, y_move=0): 8 def mul(X, Y, alis=1): 9 return alis * np.exp(-(X * X + Y * Y)) 10 11 return mul(X, Y) + mul(X - x_move, Y - y_move, 2) 12 13 14 def show(X, Y): 15 fig = plt.figure() 16 ax = Axes3D(fig) 17 X, Y = np.meshgrid(X, Y) 18 Z = func(X, Y, 1.7, 1.7) 19 plt.title("demo_hill_climbing") 20 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow', ) 21 ax.set_xlabel('x label', color='r') 22 ax.set_ylabel('y label', color='g') 23 ax.set_zlabel('z label', color='b') 24 # 具體函數方法可用 help(function) 查看,如:help(ax.plot_surface) 25 # ax.scatter(X,Y,Z,c='r') #繪點 26 plt.show() 27 28 if __name__ == '__main__': 29 X = np.arange(-2, 4, 0.1) 30 Y = np.arange(-2, 4, 0.1) 31 32 show(X,Y)
對於上面這個問題,咱們使用登山算法該如何求解呢? 下面咱們從登山算法中的幾種方式分別求解一下這個小題.
1. 首選登山算法
依次尋找該點X的鄰近點中首次出現的比點X價值高的點,並將該點做爲登山的點(此處說的價值高,在該題中是指Z或f(x,y)值較大). 依次循環,直至該點的鄰近點中再也不有比其大的點. 咱們成爲該點就是山的頂點,又稱爲最優勢.
那麼解題思路就有:
1. 隨機選擇一個爬山的起點S(x0,y0,z0),並以此爲起點開始爬山.直至"登頂".
下面是咱們實現的代碼:
1 # encoding:utf8 2 from random import random, randint 3 4 from matplotlib import pyplot as plt 5 import numpy as np 6 from mpl_toolkits.mplot3d import Axes3D 7 8 9 def func(X, Y, x_move=1.7, y_move=1.7): 10 def mul(X, Y, alis=1): 11 return alis * np.exp(-(X * X + Y * Y)) 12 13 return mul(X, Y) + mul(X - x_move, Y - y_move, 2) 14 15 16 def show(X, Y, Z): 17 fig = plt.figure() 18 ax = Axes3D(fig) 19 plt.title("demo_hill_climbing") 20 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow', ) 21 ax.set_xlabel('x label', color='r') 22 ax.set_ylabel('y label', color='g') 23 ax.set_zlabel('z label', color='b') 24 # ax.scatter(X,Y,Z,c='r') #繪點 25 plt.show() 26 27 28 def drawPaht(X, Y, Z,px,py,pz): 29 fig = plt.figure() 30 ax = Axes3D(fig) 31 plt.title("demo_hill_climbing") 32 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow', ) 33 ax.set_xlabel('x label', color='r') 34 ax.set_ylabel('y label', color='g') 35 ax.set_zlabel('z label', color='b') 36 ax.plot(px,py,pz,'r.') #繪點 37 plt.show() 38 39 40 def hill_climb(X, Y): 41 global_X = [] 42 global_Y = [] 43 44 len_x = len(X) 45 len_y = len(Y) 46 # 隨機爬山點 47 st_x = randint(0, len_x-1) 48 st_y = randint(0, len_y-1) 49 50 def argmax(stx, sty, alisx=0, alisy=0): 51 cur = func(X[0][st_x], Y[st_y][0]) 52 next = func(X[0][st_x + alisx], Y[st_y + alisy][0]) 53 54 return cur < next and True or False 55 56 while (len_x > st_x >= 0) or (len_y > st_y >= 0): 57 if st_x + 1 < len_x and argmax(st_x, st_y, 1): 58 st_x += 1 59 elif st_y + 1 < len_x and argmax(st_x, st_y, 0, 1): 60 st_y += 1 61 elif st_x >= 1 and argmax(st_x, st_y, -1): 62 st_x -= 1 63 elif st_y >= 1 and argmax(st_x, st_y, 0, -1): 64 st_y -= 1 65 else: 66 break 67 global_X.append(X[0][st_x]) 68 global_Y.append(Y[st_y][0]) 69 return global_X, global_Y, func(X[0][st_x], Y[st_y][0]) 70 71 72 if __name__ == '__main__': 73 X = np.arange(-2, 4, 0.1) 74 Y = np.arange(-2, 4, 0.1) 75 X, Y = np.meshgrid(X, Y) 76 Z = func(X, Y, 1.7, 1.7) 77 px, py, maxhill = hill_climb(X, Y) 78 print px,py,maxhill 79 drawPaht(X, Y, Z,px,py,func(np.array(px), np.array(py), 1.7, 1.7))
對比幾回運行的結果:
從上圖中,咱們能夠比較清楚的觀察到,首選登山算法的缺陷.
2.那麼最陡登山算法呢?
簡單描述:
最陡登山算法是在首選登山算法上的一種改良,它規定每次選取鄰近點價值最大的那個點做爲爬上的點.
下面咱們來實現一下它:
1 # encoding:utf8 2 from random import random, randint 3 4 from matplotlib import pyplot as plt 5 import numpy as np 6 from mpl_toolkits.mplot3d import Axes3D 7 8 9 def func(X, Y, x_move=1.7, y_move=1.7): 10 def mul(X, Y, alis=1): 11 return alis * np.exp(-(X * X + Y * Y)) 12 13 return mul(X, Y) + mul(X - x_move, Y - y_move, 2) 14 15 16 def show(X, Y, Z): 17 fig = plt.figure() 18 ax = Axes3D(fig) 19 plt.title("demo_hill_climbing") 20 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow', ) 21 ax.set_xlabel('x label', color='r') 22 ax.set_ylabel('y label', color='g') 23 ax.set_zlabel('z label', color='b') 24 # ax.scatter(X,Y,Z,c='r') #繪點 25 plt.show() 26 27 28 def drawPaht(X, Y, Z, px, py, pz): 29 fig = plt.figure() 30 ax = Axes3D(fig) 31 plt.title("demo_hill_climbing") 32 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow', ) 33 ax.set_xlabel('x label', color='r') 34 ax.set_ylabel('y label', color='g') 35 ax.set_zlabel('z label', color='b') 36 ax.plot(px, py, pz, 'r.') # 繪點 37 plt.show() 38 39 40 def hill_climb(X, Y): 41 global_X = [] 42 global_Y = [] 43 44 len_x = len(X) 45 len_y = len(Y) 46 # 隨機爬山點 47 st_x = randint(0, len_x - 1) 48 st_y = randint(0, len_y - 1) 49 50 def argmax(stx, sty, alisx, alisy): 51 cur = func(X[0][stx], Y[sty][0]) 52 next = func(X[0][alisx], Y[alisy][0]) 53 if cur < next: 54 return alisx, alisy 55 return stx, sty 56 #return cur < next and alisx, alisy or stx, sty 57 58 tmp_x = st_x 59 tmp_y = st_y 60 while (len_x > st_x >= 0) or (len_y > st_y >= 0): 61 if st_x + 1 < len_x: 62 tmp_x, tmp_y = argmax(tmp_x, tmp_y, (st_x + 1), st_y) 63 64 if st_x >= 1: 65 tmp_x, tmp_y = argmax(tmp_x, tmp_y, st_x - 1, st_y) 66 67 if st_y + 1 < len_x: 68 tmp_x, tmp_y = argmax(tmp_x, tmp_y, st_x, st_y + 1) 69 70 if st_y >= 1: 71 tmp_x, tmp_y = argmax(tmp_x, tmp_y, st_x, st_y - 1) 72 73 if tmp_x != st_x or tmp_y != st_y: 74 st_x = tmp_x 75 st_y = tmp_y 76 else: 77 break 78 global_X.append(X[0][st_x]) 79 global_Y.append(Y[st_y][0]) 80 return global_X, global_Y, func(X[0][st_x], Y[st_y][0]) 81 82 83 if __name__ == '__main__': 84 X = np.arange(-2, 4, 0.1) 85 Y = np.arange(-2, 4, 0.1) 86 X, Y = np.meshgrid(X, Y) 87 Z = func(X, Y, 1.7, 1.7) 88 px, py, maxhill = hill_climb(X, Y) 89 print px, py, maxhill 90 drawPaht(X, Y, Z, px, py, func(np.array(px), np.array(py), 1.7, 1.7))
從這個結果來看,由於範圍擴大了一點,因此效果會好一點點,當依舊是一個局部最優算法.
3.隨機從新開始登山算法呢?
簡單的描述:
隨機從新開始登山算法是基於最陡登山算法,其實就是加一個達到全局最優解的條件,若是知足該條件,就結束運算,反之則無限次重複運算最陡登山算法.
因爲此題,並無結束的特徵條件,咱們這裏就不給予實現.
4.模擬退火算法
簡單描述:
(1)隨機挑選一個單元k,並給它一個隨機的位移,求出系統所以而產生的能量變化ΔEk。
(2)若ΔEk⩽0,該位移可採納,而變化後的系統狀態可做爲下次變化的起點;
若ΔEk>0,位移後的狀態可採納的機率爲
式中T爲溫度,而後從(0,1)區間均勻分佈的隨機數中挑選一個數R,若R<Pk,則將變化後的狀態做爲下次的起點;不然,將變化前的狀態做爲下次的起點。
(3)轉第(1)步繼續執行,知道達到平衡狀態爲止。
代碼實現爲:
1 # encoding:utf8 2 from random import random, randint 3 4 from matplotlib import pyplot as plt 5 import numpy as np 6 from mpl_toolkits.mplot3d import Axes3D 7 8 9 def func(X, Y, x_move=1.7, y_move=1.7): 10 def mul(X, Y, alis=1): 11 return alis * np.exp(-(X * X + Y * Y)) 12 13 return mul(X, Y) + mul(X - x_move, Y - y_move, 2) 14 15 16 def show(X, Y, Z): 17 fig = plt.figure() 18 ax = Axes3D(fig) 19 plt.title("demo_hill_climbing") 20 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow', ) 21 ax.set_xlabel('x label', color='r') 22 ax.set_ylabel('y label', color='g') 23 ax.set_zlabel('z label', color='b') 24 # ax.scatter(X,Y,Z,c='r') #繪點 25 plt.show() 26 27 28 def drawPaht(X, Y, Z, px, py, pz): 29 fig = plt.figure() 30 ax = Axes3D(fig) 31 plt.title("demo_hill_climbing") 32 ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color='b' ) 33 ax.set_xlabel('x label', color='r') 34 ax.set_ylabel('y label', color='g') 35 ax.set_zlabel('z label', color='b') 36 ax.plot(px, py, pz, 'r.') # 繪點 37 plt.show() 38 39 40 def hill_climb(X, Y): 41 global_X = [] 42 global_Y = [] 43 # 初始溫度 44 temperature = 105.5 45 # 溫度降低的比率 46 delta = 0.98 47 # 溫度精確度 48 tmin = 1e-10 49 50 len_x = len(X) 51 len_y = len(Y) 52 53 # 隨機爬山點 54 st_x = X[0][randint(0, len_x - 1)] 55 st_y = Y[randint(0, len_y - 1)][0] 56 st_z = func(st_x, st_y) 57 58 def argmax(stx, sty, alisx, alisy): 59 cur = func(st_x, st_y) 60 next = func(alisx, alisy) 61 62 return cur < next and True or False 63 64 while (temperature > tmin): 65 # 隨機產生一個新的鄰近點 66 # 說明: 溫度越高幅度鄰近點跳躍的幅度越大 67 tmp_x = st_x + (random() * 2 - 1) * temperature 68 tmp_y = st_y + + (random() * 2 - 1) * temperature 69 if 4 > tmp_x >= -2 and 4 > tmp_y >= -2: 70 if argmax(st_x, st_y, tmp_x, tmp_y): 71 st_x = tmp_x 72 st_y = tmp_y 73 else: # 有機會跳出局域最優解 74 pp = 1.0 / (1.0 + np.exp(-(func(tmp_x, tmp_y) - func(st_x, st_y)) / temperature)) 75 if random() < pp: 76 st_x = tmp_x 77 st_y = tmp_y 78 temperature *= delta # 以必定的速率降低 79 global_X.append(st_x) 80 global_Y.append(st_y) 81 return global_X, global_Y, func(st_x, st_y) 82 83 84 if __name__ == '__main__': 85 X = np.arange(-2, 4, 0.1) 86 Y = np.arange(-2, 4, 0.1) 87 X, Y = np.meshgrid(X, Y) 88 Z = func(X, Y, 1.7, 1.7) 89 px, py, maxhill = hill_climb(X, Y) 90 print px, py, maxhill 91 drawPaht(X, Y, Z, px, py, func(np.array(px), np.array(py), 1.7, 1.7))
效果: