第4講 反向傳播 back propagation
pytorch學習視訊——B站視訊連結:《PyTorch深度學習實踐》完結合集_哔哩哔哩_bilibili
視訊内容筆記以及小練習源碼,如有錯誤請指出,三扣。
目錄如下:
- 一個簡單的神經網絡
- 反向傳播
- 舉個栗子
- 小練習推導
- Tensor in PyTorch
1. 一個簡單的神經網絡
兩層,都是線性模型。存在一個問題是這個神經網絡可以直接通過化簡最終變成一層(權重訓練失去了意義),如圖公式。為了防止這種情況發生,在每一層網絡輸出時加入一個非線性函數(即激活函數),來阻止這種化簡。
2. 反向傳播
-
由輸出(損失函數)來調整輸入(權重)的過程
在如下單層網絡中,已知由損失函數對輸出Z的偏導 ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L(也是由loss求偏導一層一層傳回來的),
一層一層傳播求出損失函數對該層網絡的輸入x和W的偏導(此時的x可以看成是該層網絡的一般輸入/中間結果):
∂ L ∂ x = ∂ L ∂ z ⋅ ∂ z ∂ x \frac{\partial L}{\partial x}=\frac{\partial L}{\partial z} \cdot \frac{\partial z}{\partial x} ∂x∂L=∂z∂L⋅∂x∂z
∂ L ∂ ω = ∂ L ∂ z ⋅ ∂ z ∂ ω {\frac{\partial L}{\partial \omega}=\frac{\partial L}{\partial z} \cdot \frac{\partial z}{\partial \omega}} ∂ω∂L=∂z∂L⋅∂ω∂z
3. 舉個栗子
假設這裡的計算就是f = x * w, ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L已知等于5,可以反向求出x, w的偏導(梯度),然後沿着導數為負的方向,也即梯度下降的方向來調整權重。
-
完整過程:
前饋過程——反向傳播——梯度下降法更新權重
4. 小練習推導
- practice 1 推導如圖所示:
- practice 2 推導如圖所示:
5. Tensor in PyTorch
-
tensor
張量,就是一個多元數組。用Tensor來存儲資料—— . data存儲權重值; . grad 導數(也是一個Tenor,是以也有data部分)。
結構如圖所示:
張量的計算參考代碼注釋部分。
quadratic_model_job.py
import torch
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# 定義權重w,w為一個張量Tensor,初始值為1
w = torch.tensor([1.0])
# True表示需要計算w的梯度
w.requires_grad = True
def forward(x):
# 由于w是一個tensor,x會先轉換成tensor再計算,是以forward(x)也是一個張量
return x * w
def loss(x, y):
y_pred = forward(x)
# loss也是一個tensor
return (y_pred - y) ** 2
print("Predict(before training)", 4, forward(4).item())
for epoch in range(100):
for x, y in zip(x_data, y_data):
# 建構計算圖
# 前饋過程——計算損失
l = loss(x, y)
# 反向傳播,求出從loss處到w所需要的梯度值,存儲在w中
l.backward()
# item()将w的梯度轉換成标量
print('\t grad: ', x, y, w.grad.item())
# print(w.grad.data, w.grad, w.item(), w.data)
# 梯度下降——更新權重
# 使用tensor直接計算會産生計算圖,是以w.grad計算會産生計算圖,用w.grad.data計算,隻更新數值,不用建立新的計算圖模型
w.data = w - 0.01 * w.grad.data
# 将目前計算完儲存下來的的梯度值清0,下次用新的Loss計算新的梯度
w.grad.data.zero_()
print("progress: ", epoch, l.item())
print("Predict(after training)", 4, forward(4).item())
- torch之backward()函數
for epoch in range(100): for x, y in zip(x_data, y_data): # 建構計算圖 # 前饋過程——計算損失 l = loss(x, y) # 反向傳播,求出從loss處到w所需要的梯度值,存儲在w中 l.backward()
反向傳播函數,在這個例子中求出從loss處到w所需要的梯度值,存儲在w中。執行完該函數後就釋放計算圖,下一次計算時使用新的loss構造新的計算圖。
參考:(pytorch中backward()函數詳解 - 練習——如圖所示非線性模型: quadratic_model_job.py
import torch
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# 定義三個參數
w1 = torch.tensor([1.0])
w2 = torch.tensor([1.0])
b = torch.tensor([1.0])
# True表示需要計算梯度
w1.requires_grad = True
w2.requires_grad = True
b.requires_grad = True
def forward(x):
# 由于w是一個tensor,x會先轉換成tensor再計算,是以forward(x)也是一個張量
return w1 * (x ** 2) + w2 * x + b
def loss(x, y):
y_pred = forward(x)
# loss也是一個tensor
return (y_pred - y) ** 2
print("Predict(before training)", 4, forward(4).item())
for epoch in range(100):
for x, y in zip(x_data, y_data):
# 建構計算圖
# 前饋過程——計算損失
l = loss(x, y)
# 反向傳播
l.backward()
# item()将w的梯度轉換成标量
print('\t grad: ', x, y, w1.grad.item(), w2.grad.item(), b.grad.item())
# 梯度下降——更新權重
# 使用tensor直接計算會産生計算圖,是以w.grad計算會産生計算圖,用w.grad.data計算,隻更新數值,不用建立新的計算圖模型
# 學習率使用0.02比0.01效果更好
w1.data = w1 - 0.02 * w1.grad.data
w2.data = w2 - 0.02 * w2.grad.data
b.data = b - 0.02 * b.grad.data
# 将目前計算完儲存下來的的梯度值清0,下次用新的Loss計算新的梯度
w1.grad.data.zero_()
w2.grad.data.zero_()
b.grad.data.zero_()
print("progress: ", epoch, l.item())
print("Predict(after training)", 4, forward(4).item())
# 分别列印三個參數訓練後的值
print("w1:", w1.data.item(), "\nw2", w2.data.item(), "\nb:", b.data.item())
(代碼了解請參考注釋,以上代碼已經在pycharm上經過測試,筆記純屬個人了解,如有錯誤勿介或者歡迎路過的大佬指出 嘻嘻嘻。)
——未完待續……