1. 程式人生 > >學習筆記13:隨機梯度下降法(Stochastic gradient descent, SGD)

學習筆記13:隨機梯度下降法(Stochastic gradient descent, SGD)

假設我們提供了這樣的資料樣本(樣本值取自於y=3*x1+4*x2):
x1x2y
1419
2526
5119
4229

x1和x2是樣本值,y是預測目標,我們需要以一條直線來擬合上面的資料,待擬合的函式如下:


我們的目的就是要求出θ1和θ2的值,讓h(θ)儘量逼近目標值y。

這是一個線性迴歸問題,若對線性迴歸有所瞭解的同學就知道:利用最小二乘法則和梯度下降法可以求出兩個引數,而深度學習也同樣可以利用這兩種方法求得所有的網路引數,因此,在這裡用這個數學模型來解釋BGD、SGD、MSGD這幾個概念。

梯度下降法原理

我們首先確定損失函式:


其中,J(θ)是損失函式,m代表每次取多少樣本進行訓練,如果採用SGD進行訓練,那每次隨機取一組樣本,m=1;如果是批處理,則m等於每次抽取作為訓練樣本的數量。θ是引數,對應(1式)的θ1和θ2。求出了θ1和θ2,h(x)的表示式就出來了:

我們的目標是讓損失函式J(θ)的值最小,根據梯度下降法,首先要用J(θ)對θ求偏導:


由於是要最小化損失函式,所以引數θ按其負梯度方向來更新:


示例:

BGD(Batch gradient descent)批量梯度下降法:每次迭代使用所有的樣本

每次迭代都需要把所有樣本都送入,這樣的好處是每次迭代都顧及了全部的樣本,做的是全域性最優化。
  1. #-*- coding: utf-8 -*-
  2. import random  
  3. #用y = Θ1*x1 + Θ2*x2來擬合下面的輸入和輸出
  4. #input1  1   2   5   4
  5. #input2  4   5   1   2
  6. #output  19  26  19  20
  7. input_x = [[1
    ,4], [2,5], [5,1], [4,2]]  #輸入
  8. y = [19,26,19,20]   #輸出
  9. theta = [1,1]       #θ引數初始化
  10. loss = 10#loss先定義一個數,為了進入迴圈迭代
  11. step_size = 0.01#步長
  12. eps =0.0001#精度要求
  13. max_iters = 10000#最大迭代次數
  14. error =0#損失值
  15. iter_count = 0#當前迭代次數
  16. err1=[0,0,0,0]      #求Θ1梯度的中間變數1
  17. err2=[0,0,0,0]      #求Θ2梯度的中間變數2
  18. while( loss > eps and iter_count < max_iters):   #迭代條件
  19.     loss = 0
  20.     err1sum = 0
  21.     err2sum = 0
  22.     for i in range (4):     #每次迭代所有的樣本都進行訓練
  23.         pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1]  #預測值
  24.         err1[i]=(pred_y-y[i])*input_x[i][0]  
  25.         err1sum=err1sum+err1[i]  
  26.         err2[i]=(pred_y-y[i])*input_x[i][1]  
  27.         err2sum=err2sum+err2[i]  
  28.     theta[0] = theta[0] - step_size * err1sum/4#對應5式
  29.     theta[1] = theta[1] - step_size * err2sum/4#對應5式
  30.     for i in range (4):  
  31.         pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1]   #預測值
  32.         error = (1/(2*4))*(pred_y - y[i])**2#損失值
  33.         loss = loss + error  #總損失值
  34.     iter_count += 1
  35.     print ("iters_count", iter_count)  
  36. print ('theta: ',theta )  
  37. print ('final loss: ', loss)  
  38. print ('iters: ', iter_count)  
theta:  [3.0044552563214433, 3.9955447274498894]
final loss:  9.428456066652548e-05
iters:  97

SGD(Stochastic gradientdescent)隨機梯度下降法:每次迭代使用一組樣本

針對BGD演算法訓練速度過慢的缺點,提出了SGD演算法,普通的BGD演算法是每次迭代把所有樣本都過一遍,每訓練一組樣本就把梯度更新一次。而SGD演算法是從樣本中隨機抽出一組,訓練後按梯度更新一次,然後再抽取一組,再更新一次,在樣本量及其大的情況下,可能不用訓練完所有的樣本就可以獲得一個損失值在可接受範圍之內的模型了。

  1. #-*- coding: utf-8 -*-
  2. import random  
  3. #用y = Θ1*x1 + Θ2*x2來擬合下面的輸入和輸出
  4. #input1  1   2   5   4
  5. #input2  4   5   1   2
  6. #output  19  26  19  20
  7. input_x = [[1,4], [2,5], [5,1], [4,2]]  #輸入
  8. y = [19,26,19,20]   #輸出
  9. theta = [1,1]       #θ引數初始化
  10. loss = 10#loss先定義一個數,為了進入迴圈迭代
  11. step_size = 0.01#步長
  12. eps =0.0001#精度要求
  13. max_iters = 10000#最大迭代次數
  14. error =0#損失值
  15. iter_count = 0#當前迭代次數
  16. while( loss > eps and iter_count < max_iters):    #迭代條件
  17.     loss = 0
  18.     i = random.randint(0,3)  #每次迭代在input_x中隨機選取一組樣本進行權重的更新
  19.     pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1#預測值
  20.     theta[0] = theta[0] - step_size * (pred_y - y[i]) * input_x[i][0]  
  21.     theta[1] = theta[1] - step_size * (pred_y - y[i]) * input_x[i][1]  
  22.     for i in range (3):  
  23.         pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1#預測值
  24.         error = 0.5*(pred_y - y[i])**2
  25.         loss = loss + error  
  26.     iter_count += 1
  27.     print ('iters_count', iter_count)  
  28. print ('theta: ',theta )  
  29. print ('final loss: ', loss)  
  30. print ('iters: ', iter_count)  

MBGD(Mini-batch gradient descent)小批量梯度下降:每次迭代使用b組樣本


SGD相對來說要快很多,但是也有存在問題,由於單個樣本的訓練可能會帶來很多噪聲,使得SGD並不是每次迭代都向著整體最優化方向,因此在剛開始訓練時可能收斂得很快,但是訓練一段時間後就會變得很慢。在此基礎上又提出了小批量梯度下降法,它是每次從樣本中隨機抽取一小批進行訓練,而不是一組。

  1. #-*- coding: utf-8 -*-
  2. import random  
  3. #用y = Θ1*x1 + Θ2*x2來擬合下面的輸入和輸出
  4. #input1  1   2   5   4
  5. #input2  4   5   1   2
  6. #output  19  26  19  20
  7. input_x = [[1,4], [2,5], [5,1], [4,2]]  #輸入
  8. y = [19,26,19,20]       #輸出
  9. theta = [1,1]           #θ引數初始化<