天天看點

pytorch 深度學習實踐 第4講 反向傳播

第4講 反向傳播 back propagation

pytorch學習視訊——B站視訊連結:《PyTorch深度學習實踐》完結合集_哔哩哔哩_bilibili

視訊内容筆記以及小練習源碼,如有錯誤請指出,三扣。

目錄如下:

  1. 一個簡單的神經網絡
  2. 反向傳播
  3. 舉個栗子
  4. 小練習推導
  5. Tensor in PyTorch

1. 一個簡單的神經網絡

兩層,都是線性模型。存在一個問題是這個神經網絡可以直接通過化簡最終變成一層(權重訓練失去了意義),如圖公式。為了防止這種情況發生,在每一層網絡輸出時加入一個非線性函數(即激活函數),來阻止這種化簡。

pytorch 深度學習實踐 第4講 反向傳播

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​

pytorch 深度學習實踐 第4講 反向傳播

3. 舉個栗子

假設這裡的計算就是f = x * w, ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L​已知等于5,可以反向求出x, w的偏導(梯度),然後沿着導數為負的方向,也即梯度下降的方向來調整權重。

pytorch 深度學習實踐 第4講 反向傳播
  • 完整過程:

    前饋過程——反向傳播——梯度下降法更新權重

    pytorch 深度學習實踐 第4講 反向傳播

4. 小練習推導

  • practice 1
    pytorch 深度學習實踐 第4講 反向傳播
    推導如圖所示:
    pytorch 深度學習實踐 第4講 反向傳播
  • practice 2
    pytorch 深度學習實踐 第4講 反向傳播
    推導如圖所示:
    pytorch 深度學習實踐 第4講 反向傳播

5. Tensor in PyTorch

  • tensor

    張量,就是一個多元數組。用Tensor來存儲資料—— . data存儲權重值; . grad 導數(也是一個Tenor,是以也有data部分)。

    結構如圖所示:

pytorch 深度學習實踐 第4講 反向傳播

​ 張量的計算參考代碼注釋部分。

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()函數詳解
  • 練習——如圖所示非線性模型:
    pytorch 深度學習實踐 第4講 反向傳播
    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上經過測試,筆記純屬個人了解,如有錯誤勿介或者歡迎路過的大佬指出 嘻嘻嘻。)

——未完待續……