Pytorch 自動求導、梯度下降和反向傳播

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)


 

梯度下降和反向傳播

目標

  1. 知道什麼是梯度下降
  2. 知道什麼是反向傳播

1. 梯度是什麼?

梯度:是一個向量,導數+變化最快的方向(學習的前進方向)

回顧機器學習

2. 偏導的計算

2.1 常見的導數計算

2.2 多元函數求偏導

3. 反向傳播算法

3.1 計算圖和反向傳播

計算圖:通過圖的方式來描述函數的圖形

在上面的練習中,

,把它繪製成計算圖可以表示爲:

繪製成爲計算圖之後,可以清楚的看到向前計算的過程

之後,對每個節點求偏導可有:

那麼反向傳播的過程就是一個上圖的從右往左的過程,自變量a,b,c​各自的偏導就是連線上的梯度的乘積:

3.2 神經網絡中的反向傳播

3.2.1 神經網絡的示意圖

3.2.2 神經網絡的計算圖

其中:

結果如下:

公式分爲兩部分:

  1. 括號外:左邊紅線部分
  2. 括號內
    1. 加號左邊:右邊紅線部分
    2. 加號右邊:藍線部分

但是這樣做,當模型很大的時候,計算量非常大

所以反向傳播的思想就是對其中的某一個參數單獨求梯度,之後更新,如下圖所示:


Pytorch自動求導

目標

  1. 知道requires_grad的作用

  2. 知道如何使用backward

1. 前向計算

對於pytorch中的一個tensor,如果設置它的屬性 .requires_gradTrue,那麼它將會追蹤對於該張量的所有操作。或者可以理解爲,這個tensor是一個參數,後續會被計算梯度,更新該參數。

1.1 計算過程

假設有以下條件(1/4表示求均值,xi中有4個數),使用torch完成其向前計算的過程

如果x爲參數,需要對其進行梯度的計算和更新

那麼,在最開始隨機設置x的值的過程中,需要設置他的requires_grad屬性爲True,其默認值爲False

import torch
x = torch.ones(2, 2, requires_grad=True)  #初始化參數x並設置requires_grad=True用來追蹤其計算曆史
print(x)
#tensor([[1., 1.],
#        [1., 1.]], requires_grad=True)

y = x+2
print(y)
#tensor([[3., 3.],
#        [3., 3.]], grad_fn=<AddBackward0>)

z = y*y*3  #平方x3
print(x)
#tensor([[27., 27.],
#        [27., 27.]], grad_fn=<MulBackward0>) 

out = z.mean() #求均值
print(out)
#tensor(27., grad_fn=<MeanBackward0>)

從上述代碼可以看出:

  1. x的requires_grad屬性爲True
  2. 之後的每次計算都會修改其grad_fn屬性,用來記錄做過的操作
    1. 通過這個函數和grad_fn能夠組成一個和前一小節類似的計算圖

1.2 requires_grad和grad_fn

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)  #False
a.requires_grad_(True)  #就地修改
print(a.requires_grad)  #True
b = (a * a).sum()
print(b.grad_fn) # <SumBackward0 object at 0x4e2b14345d21>
with torch.no_gard():
    c = (a * a).sum()  #tensor(151.6830),此時c沒有gard_fn

print(c.requires_grad) #False

注意:

爲了防止跟蹤歷史記錄(和使用內存),可以將代碼塊包裝在with torch.no_grad():中。在評估模型時特別有用,因爲模型可能具有requires_grad = True的可訓練的參數,但是我們不需要在此過程中對他們進行梯度計算。

2. 梯度計算

對於1.1 中的out而言,我們可以使用backward方法來進行反向傳播,計算梯度

得到

tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

因爲:

注意:在輸出爲一個標量的情況下,我們可以調用輸出tensorbackward() 方法,但是在數據是一個向量的時候,調用backward()的時候還需要傳入其他參數。

很多時候我們的損失函數都是一個標量,所以這裏就不再介紹損失爲向量的情況。

loss.backward()就是根據損失函數,對參數(requires_grad=True)的去計算他的梯度,並且把它累加保存到x.gard,此時還並未更新其梯度

注意點:

  1. tensor.data:
    • 在tensor的require_grad=False,tensor.data和tensor等價
    • require_grad=True時,tensor.data僅僅是獲取tensor中的數據
  2. tensor.numpy():
    • require_grad=True不能夠直接轉換,需要使用tensor.detach().numpy()

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章