Pytorch_第三篇_Pytorch Autograd (自動求導機制)

Pytorch Autograd (自動求導機制)


Introduce

Pytorch Autograd庫 (自動求導機制) 是訓練神經網絡時,反向偏差傳播(BP)算法的核心。python

本文經過logistic迴歸模型來介紹Pytorch的自動求導機制。首先,本文介紹了tensor與求導相關的屬性。其次,經過logistic迴歸模型來幫助理解BP算法中的前向傳播以及反向傳播中的導數計算。git

如下均爲初學者筆記。github


note: 如下用x表明建立的tensor張量。算法

  • x.requires_grad:True or False,用來指明該張量在反向傳播過程當中是否須要求導。
  • with torch.no_grad()::當咱們在作模型評估的時候是不須要求導的,能夠嵌套一層with torch.no_grad()以減小可能的計算和內存開銷。
  • x.grad:返回損失函數對該張量求偏導的值,在調用backward()以後纔有。
  • x.grad_fn:存儲計算圖上某中間節點進行的操做,如加減乘除等,用於指導反向傳播時loss對該節點的求偏導計算。
  • x.is_leaf:True or False,用於判斷某個張量在計算圖中是不是葉子張量。葉子張量我我的認爲能夠理解爲目標函數中非中間因變量(中間函數、通常是運算獲得的張量),如神經網絡中的權值參數w就是葉子張量(通常是手動建立的張量)。
  • x.detach():返回tensor的數據以及requires_grad屬性,且返回的tensor與原始tensor共享存儲空間,即一個改變會致使另一個改變。所以,若是咱們在backward以前對x.detach()返回的張量進行改變會致使原始x的改變,從而致使求導錯誤,可是這時系統會報錯提醒。
    (note:雖然x.data也與x.detach()做用類似,可是x.data不被Autograd系統追蹤,所以若是遇到上述問題並不會報錯。推薦使用x.detach()
  • x.item():若是張量只包含一個元素,即標量(0維張量,scalar),能夠用x.item()返回,一般loss只包含一個數值,所以經常使用loss.item()。
  • x.tolist():若是張量只包含多個元素,能夠用x.tolist()轉換成python list返回。

Build Logistic regression Model

假設有一個損失函數以下(Logistic迴歸):網絡

\[z = w1x1+w2x2+b \]

\[y_p = sigmoid(z) \]

\[Loss(y_p,y_t) = -{1\over n}\sum_{i=1}^n (y_tlog(y_p)+(1-y_t)log(1-y_p)) \]

摘自吳恩達機器學習框架

由損失函數構建簡單計算圖模型以下:機器學習

如今咱們經過上述例子來理解前向傳播和反向傳播。在上述簡單的神經網絡模型中,咱們須要對權值參數w1,w2以及閾值參數b進行更新。神經網絡訓練的整體過程以下:先由輸入層逐級前向傳播計算loss輸出,再有輸出層loss反向計算各層梯度傳播偏差,以此更新各層的權值參數w和閾值參數b。函數

在該模型中咱們須要求出loss對w一、w2以及b的偏導,以此利用SGD更新各參數。對於根據鏈式法則的逐級求導過程再也不贅述,吳恩達機器學習SGD部分有詳細的計算過程以及解釋。學習

如今咱們利用pytorch實現logistic迴歸模型,並手動實現參數更新。ui

import torch
import numpy as np

# 可能網絡上有許多資料在Tensor外再額外封裝一層Variable,然而從Pytorch0.4版本之後,Variable已經合併進Tensor了,所以之後的代碼能夠直接用Tensor,沒必要要再封裝一層Variable。

# 讀入數據 x_t,y_t
x_t = torch.tensor(np.array([[1,1],[1,0],[0,1],[0,0]]),requires_grad=False,dtype=torch.float)
y_t = torch.tensor([[0],[1],[0],[1]],requires_grad=False,dtype=torch.float)
print(x_t.size())
# 定義權值參數w和閾值參數b
w = torch.randn([2,1], requires_grad=True,dtype=torch.float)
b = torch.zeros(1, requires_grad=True,dtype=torch.float)
print(w.size())
# 構建邏輯迴歸模型
def logistic_model(x_t):
    a = torch.matmul(x_t,w) + b
    return torch.sigmoid(a)

y_p = logistic_model(x_t)

# 計算偏差
def get_loss(y_p, y_t):
    return -torch.mean(y_t * torch.log(y_p)+(1-y_t) * torch.log(1-y_p))

loss = get_loss(y_p, y_t)
print(loss)

# 自動求導
loss.backward()
# note:若是loss爲一個標量(通常都是),那麼loss.backward()不須要指定任何參數。然而若是有多個損失,即loss爲一個向量tensor([loss1, loss2,loss3]),則須要指定一個gradient參數,它是與loss形狀匹配的張量,如tensor([1.0,1.0,0.1]),裏面數字我我的理解爲表明各損失的權重。

# 查看 w 和 b 的梯度
print(w.grad)
print(b.grad)

# 更新一次參數
w.data = w.data - 1e-2 * w.grad.data
b.data = b.data - 1e-2 * b.grad.data

'''
note:
存在兩個問題:
1. 若是沒有前面先更新一次參數,後面直接進行迭代更新的話,會報錯,具體緣由也沒搞懂。
2. 利用pycharm運行pytorch代碼,調用了backward()以後,程序運行完成進程並不會終止,須要手動到任務管理器中kill進程,具體緣由也不清楚。
'''

# epoch
for e in range(10000):  # 進行 10000 次更新
    y_p = logistic_model(x_t)
    loss = get_loss(y_p, y_t)

    w.grad.zero_()  # 歸零梯度
    b.grad.zero_()  # 歸零梯度
    loss.backward()

    w.data = w.data - 1e-2 * w.grad.data  # 更新 w
    b.data = b.data - 1e-2 * b.grad.data  # 更新 b
    print('epoch: {}, loss: {}'.format(e, loss.data.item()))

print(w)
print(b)

'''
每500次迭代打印出輸出結果,咱們看到損失函數在迭代中逐步降低:
epoch: 0, loss: 0.9426676034927368
epoch: 500, loss: 0.5936437249183655
epoch: 1000, loss: 0.4318988025188446
epoch: 1500, loss: 0.33194077014923096
epoch: 2000, loss: 0.265964150428772
epoch: 2500, loss: 0.22003984451293945
epoch: 3000, loss: 0.18663322925567627
epoch: 3500, loss: 0.1614413857460022
epoch: 4000, loss: 0.14187511801719666
epoch: 4500, loss: 0.12630191445350647
epoch: 5000, loss: 0.11365044862031937
epoch: 5500, loss: 0.10319262742996216
epoch: 6000, loss: 0.09441888332366943
epoch: 6500, loss: 0.08696318417787552
epoch: 7000, loss: 0.08055643737316132
epoch: 7500, loss: 0.07499672472476959
epoch: 8000, loss: 0.07013023644685745
epoch: 8500, loss: 0.06583743542432785
epoch: 9000, loss: 0.06202460825443268
epoch: 9500, loss: 0.05861698091030121
至此,手動實現梯度降低,logistic模型搭建完成,以後將嘗試利用pytorch框架搭建神經網絡。

'''

本文參考-1

本文參考-2

相關文章
相關標籤/搜索