tft每日頭條

 > 科技

 > python梯度上升法實現梯度下降

python梯度上升法實現梯度下降

科技 更新时间:2024-06-29 09:51:08

對于一元二次函數的極值來說,可以通過配方法求得。但是,事實是我們生活的這個世界,絕大多數的函數都比一元二次函數要複雜,從而無法通過一些數學的公式化的手段來求得極值。

而現在,我們有了計算機,而計算機有極強的算力,我們就可以依托于計算機的算力以及一些算法來輔助我們對于原本無法求得極值的任意函數得到近似極值。

為什麼是近似極值? 因為這是通過計算機的疊代計算得到的,而計算機是依托于浮點計算的,所以我們得到的是近似極值解。但是,這種近似解,已經夠用了。試想,除了純粹的數學,我們的世界哪裡不是近似的?例如,時間,人們永遠無法知道最精确的時間,因為人用來測量時間的工具是有誤差的;同樣,長度,重量。現實世界凡是人測出來的都是有誤差的,隻是誤差可接受範圍,這就是近似。

我們這裡介紹的方法: 梯度下降方法求極值,也是人工智能領域,也就是機器學習最重要的方法,在機器學習領域,這個方法,也叫 反向傳播,本質上就是梯度求極值,把參數學習到的過程。

我們依然先是以一元二次函數為例子,來介紹梯度下降法求極值。在下節課,會介紹對任意函數使用梯度下降求極值,并且介紹目前最主流的深度學習工具 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

python梯度上升法實現梯度下降(青少年Python編程)1

我們知道實際的最小值是 x=-1.0 時, y=1.0, 我們看到當我們的采樣點隻有很少的時候,2或3的時候,因為無法采樣到 x=-1, 所以最小值是 2.0 與實際的 1.0 差距很大。當我們增大采樣點的時候,越靠近 x=-1.0 的時候,得到的最小值越接近 y=1.0。

那是不是用這種方法就可以計算最小值了呢?理論上是可以的。但這裡面還存在一些問題

  1. 我們的采樣區間如何确定?在這裡我們直接将對稱軸包含在了采樣區間,而實際可能我們無法知道這種對稱信息
  2. 還有沒有其他的極值點?這也是無法确定的。
  3. 采樣點設置多少個?間隔多少這也是一個問題。
  4. 計算量與采樣點一樣,是不是能否縮減一些?

我們希望我們給定一個起始點,程序能夠自動尋找最小值點的,這樣就不用圈定采樣區間了,當自動尋找到最小值的時候自動停止。這裡我們介紹一個新的方法,梯度下降法來求解一元二次函數最小值。

我們觀察一元二次函數的圖像,我們發現對于圖像上任意一個點,總是能夠沿着一個方向向最小值前進,那麼,這個變化的方向就是梯度,我們通過給梯度增加一個步長變化,使得 x 逐步的疊代就能夠找到最小值。

python梯度上升法實現梯度下降(青少年Python編程)2

什麼是梯度?

梯度就是在該點的導數。對于 來說,對 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每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved