對于一元二次函數的極值來說,可以通過配方法求得。但是,事實是我們生活的這個世界,絕大多數的函數都比一元二次函數要複雜,從而無法通過一些數學的公式化的手段來求得極值。
而現在,我們有了計算機,而計算機有極強的算力,我們就可以依托于計算機的算力以及一些算法來輔助我們對于原本無法求得極值的任意函數得到近似極值。
為什麼是近似極值? 因為這是通過計算機的叠代計算得到的,而計算機是依托于浮點計算的,所以我們得到的是近似極值解。但是,這種近似解,已經夠用了。試想,除了純粹的數學,我們的世界哪裡不是近似的?例如,時間,人們永遠無法知道最精确的時間,因為人用來測量時間的工具是有誤差的;同樣,長度,重量。現實世界凡是人測出來的都是有誤差的,隻是誤差可接受範圍,這就是近似。
我們這裡介紹的方法: 梯度下降方法求極值,也是人工智能領域,也就是機器學習最重要的方法,在機器學習領域,這個方法,也叫 反向傳播,本質上就是梯度求極值,把參數學習到的過程。
我們依然先是以一元二次函數為例子,來介紹梯度下降法求極值。在下節課,會介紹對任意函數使用梯度下降求極值,并且介紹目前最主流的深度學習工具 pytorch.
梯度下降法求解一元二次函數最小值我們僅僅以 a > 0, 有最小值的情況為例,函數是: , 配方法,我們可以知道,當 x=-1時,最小值是 y=1.
以計算機的思維考慮問題,計算機的能力是算力,可以快速的叠代。那麼,如果我們應用這種能力到求解該一元二次函數的最小值。很自然的想到,我将定義域,這裡假設是: [-1, 1], 我們将定義域分割成無數個點,也就形成了 , 接下來計算 , 我們将最小的 k 選取出來,就得到了最小值。顯然, n取值越大,就越精細,那麼,我們就能夠得到越精确的值。
直接上代碼。我們使用上節課,我們封裝的一元二次函數類,來幫助我們計算函數的值。
importnumpyasnp
importmatplotlib.pyplotasplt
frommatplotlib.axesimportAxes
fromprogramming.draw_curveimportdraw_line_by_kb
fromprogramming.pointimportPoint
fromprogramming.intervalimportInterval
fromprogramming.quadratic_functionimportQuadraticFunction
classMinValueByIterate:
"""
叠代法求最小值
"""
def__init__(self,n:int,interval:Interval):
self.n=n
self.interval=interval
def__call__(self,qf:QuadraticFunction):
points=qf.sample_points(interval=self.interval,num_points=self.n)
y=[point.yforpointinpoints]
x=[point.xforpointinpoints]
index=np.argmin(y)
returnPoint(x=x[index],y=y[index])
測試下,我們求得極值情況。在這裡,我們對 n 的選擇從 [2, 20],選擇不同的采樣點來看看得到的極值情況。
qf=QuadraticFunction(a=1.0,b=2,c=2)
items=list()
forninrange(2,20):
min_value=MinValueByIterate(n=n,interval=Interval(left=-2,
right=2,
is_left_closed=True,
is_right_closed=True))
min_point=min_value(qf=qf)
print(f"當x={min_point.x},最小值是{min_point.y}")
items.append((n,min_point))
#繪制所有的最小值
min_value_draw_n=[item[0]foriteminitems]
#使用直屬換算,增加識别度
min_value_draw_y=[np.exp(item[1].y)foriteminitems]
fig=plt.figure(num=1,figsize=(4,4))#創建畫布
axes:Axes=fig.add_subplot(111)#創建坐标系
axes.grid()#設置坐标系樣式
axes.set_aspect(1)#設置x,y坐标軸比例
axes.scatter(x=min_value_draw_n,y=min_value_draw_y,c="r")
draw_line_by_kb(axes=axes,k=0,b=np.exp(1.0),begin_x=-1,end_x=25)
plt.show()
當 x = -2.0, 最小值是 2.0
當 x = -2.0, 最小值是 2.0
當 x = -0.6666666666666667, 最小值是 1.1111111111111112
當 x = -1.0, 最小值是 1.0
當 x = -1.2, 最小值是 1.04
當 x = -1.3333333333333335, 最小值是 1.1111111111111112
當 x = -0.8571428571428572, 最小值是 1.0204081632653061
當 x = -1.0, 最小值是 1.0
當 x = -1.1111111111111112, 最小值是 1.0123456790123457
當 x = -1.2, 最小值是 1.04
當 x = -0.9090909090909092, 最小值是 1.0082644628099173
當 x = -1.0, 最小值是 1.0
當 x = -1.0769230769230769, 最小值是 1.0059171597633136
當 x = -1.1428571428571428, 最小值是 1.0204081632653061
當 x = -0.9333333333333333, 最小值是 1.0044444444444445
當 x = -1.0, 最小值是 1.0
當 x = -1.0588235294117647, 最小值是 1.0034602076124568
當 x = -1.1111111111111112, 最小值是 1.0123456790123457
我們知道實際的最小值是 x=-1.0 時, y=1.0, 我們看到當我們的采樣點隻有很少的時候,2或3的時候,因為無法采樣到 x=-1, 所以最小值是 2.0 與實際的 1.0 差距很大。當我們增大采樣點的時候,越靠近 x=-1.0 的時候,得到的最小值越接近 y=1.0。
那是不是用這種方法就可以計算最小值了呢?理論上是可以的。但這裡面還存在一些問題
我們希望我們給定一個起始點,程序能夠自動尋找最小值點的,這樣就不用圈定采樣區間了,當自動尋找到最小值的時候自動停止。這裡我們介紹一個新的方法,梯度下降法來求解一元二次函數最小值。
我們觀察一元二次函數的圖像,我們發現對于圖像上任意一個點,總是能夠沿着一個方向向最小值前進,那麼,這個變化的方向就是梯度,我們通過給梯度增加一個步長變化,使得 x 逐步的叠代就能夠找到最小值。
什麼是梯度?
梯度就是在該點的導數。對于 來說,對 x 求導得到: , 叠代 .當 x = 1, , 我們沿着 -4 方向叠代; 當 x=-2時 , 我們沿着 2 方向叠代。
接下來我們就用梯度來對一元二次函數進行叠代,求解最小值吧。
開始編程我們針對 函數進行梯度計算,我們的類中有梯度計算成員函數,計算梯度的時候需要 學習率以及最大叠代步數。當我們找到一個比現在最小值大的就停止叠代。
classGradientDescent:
"""
梯度下降
"""
def_gradient(self,x:float):
"""
梯度計算
"""
return2*x 2
def__call__(self,int_x:float=None,learning_rate:float=0.01,num_steps:int=1000):
x=int_x
min_x=np.inf
min_y=np.inf
foriinrange(num_steps):
x-=self._gradient(x)*learning_rate
y=x*x 2*x 2
ify<min_y:
min_x=x
min_y=y
else:
break
returni,Point(x=min_x,y=min_y)
測試下我們的梯度下降法求解的最小值吧.
gradient_descent=GradientDescent()
step,point=gradient_descent(10,learning_rate=0.1,num_steps=1000)
print(f"叠代了:{step}步,當{point.x}時,最小值是{point.y}")
叠代了: 90 步, 當 -0.9999999791314865 時,最小值是 1.0000000000000004
我們看到,當我們叠代了90步的時候,得到了最小值 1.0,x 與 -1.0 有一點誤差,這并不要緊。
在這個過程中,我們并沒有指定具體的區間,而是我們随機給了一個初始值 10(實際上可以給任何初始值),程序使用梯度下降自動尋找了最小值。是不是非常 Cool!
總結在這節課我們學習了如何使用計算機思維,并應用梯度下降法來求解最小值。這個方法與配方法比最大的優勢在于,我們可以對任意函數進行最小值求解計算,而這就是人工智能最核心的算法-反向傳播。
下節課,我們來看看如何對任意函數進行求解,并同時會介紹自動計算梯度的工具 pytorch,也是目前最主要的幾個深度學習框架之一。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!