日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)
梯度下降和反向傳播
目標
- 知道什麼是梯度下降
- 知道什麼是反向傳播
1. 梯度是什麼?
梯度:是一個向量,導數+變化最快的方向(學習的前進方向)
回顧機器學習
2. 偏導的計算
2.1 常見的導數計算
2.2 多元函數求偏導
3. 反向傳播算法
3.1 計算圖和反向傳播
計算圖:通過圖的方式來描述函數的圖形
在上面的練習中,
,把它繪製成計算圖可以表示爲:
繪製成爲計算圖之後,可以清楚的看到向前計算的過程
之後,對每個節點求偏導可有:
那麼反向傳播的過程就是一個上圖的從右往左的過程,自變量a,b,c各自的偏導就是連線上的梯度的乘積:
3.2 神經網絡中的反向傳播
3.2.1 神經網絡的示意圖
3.2.2 神經網絡的計算圖
其中:
結果如下:
公式分爲兩部分:
- 括號外:左邊紅線部分
- 括號內
- 加號左邊:右邊紅線部分
- 加號右邊:藍線部分
但是這樣做,當模型很大的時候,計算量非常大
所以反向傳播的思想就是對其中的某一個參數單獨求梯度,之後更新,如下圖所示:
Pytorch自動求導
目標
-
知道
requires_grad
的作用 -
知道如何使用
backward
1. 前向計算
對於pytorch中的一個tensor,如果設置它的屬性 .requires_grad
爲True
,那麼它將會追蹤對於該張量的所有操作。或者可以理解爲,這個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>)
從上述代碼可以看出:
- x的requires_grad屬性爲True
- 之後的每次計算都會修改其
grad_fn
屬性,用來記錄做過的操作- 通過這個函數和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]])
因爲:
注意:在輸出爲一個標量的情況下,我們可以調用輸出tensor
的backward()
方法,但是在數據是一個向量的時候,調用backward()
的時候還需要傳入其他參數。
很多時候我們的損失函數都是一個標量,所以這裏就不再介紹損失爲向量的情況。
loss.backward()
就是根據損失函數,對參數(requires_grad=True)的去計算他的梯度,並且把它累加保存到x.gard
,此時還並未更新其梯度
注意點:
tensor.data
:- 在tensor的require_grad=False,tensor.data和tensor等價
- require_grad=True時,tensor.data僅僅是獲取tensor中的數據
tensor.numpy()
:require_grad=True
不能夠直接轉換,需要使用tensor.detach().numpy()