Pytorch訓練神經網絡過程解析

 

pytorch單步實現2層的神經網絡:
 


import os
import torch
import pandas as pd
from skimage import io, transform
import numpy as np

import matplotlib.pyplot as plt
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils
# 忽略警告
import warnings
warnings.filterwarnings('ignore')

dtype = torch.float
device = torch.device('cpu')

N, D_in, H, D_out = 64, 1000, 100, 10

x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)

w1 = torch.randn(D_in, H, device = device, dtype= dtype)
w2 = torch.randn(H, D_out, device = device, dtype=dtype)

learning_rate = 1e-6
for t in range(500):
    # 前向傳遞:計算預測y
    h = x.mm(w1)    # 矩陣相乘
    h_relu= h.clamp(min=0)
    y_pred = h_relu.mm(w2)

    loss = (y_pred - y).pow(2).sum().item()
    print(t, loss)

    # Backprop計算 w1和 w2相對於損耗的梯度
    grad_y_pred = 2. * (y_pred -y)
    grad_w2 = h_relu.t().mm(grad_y_pred)
    grad_h_relu = grad_y_pred.mm(w2.t())

    grad_h = grad_h_relu.clone()
    grad_h[h<0] = 0
    grad_w1 = x.t().mm(grad_h)

    # 使用梯度下降更新權重
    w1 -= learning_rate *grad_w1
    w2 -= learning_rate *grad_w2

#  PyTorch中的 autograd 包提供自動求導

""""
這個tensor上的任何PyTorch的操作
都將構造一個計算圖,從而允許我們稍後在圖中執行反向傳播。如果這個 tensor x 的
requires_grad=True ,那麼反向傳播之後 x.grad 將會是另一個張量,其爲x關於某個標量值的梯度
"""

# 使用Tensors上的操作計算和打印丟失。
# loss是一個形狀爲()的張量
# loss.item() 得到這個張量對應的python數值
loss = (y_pred - y).pow(2).sum()
print(t, loss.item())
# 使用autograd計算反向傳播。這個調用將計算loss對所有requires_grad=True的tensor的梯度。
# 這次調用後,w1.grad和w2.grad將分別是loss對w1和w2的梯度張量。
loss.backward()
# 使用梯度下降更新權重。對於這一步,我們只想對w1和w2的值進行原地改變;不想爲更新階段構建計算圖,
# 所以我們使用torch.no_grad()上下文管理器防止PyTorch爲更新構建計算圖
with torch.no_grad():
    w1 -= learning_rate * w1.grad
    w2 -= learning_rate * w2.grad
    # 反向傳播後手動將梯度設置爲零
    w1.grad.zero_()
    w2.grad.zero_()

使用優化函數進行梯度更新
 

import torch
# N是批大小;D是輸入維度
# H是隱藏層維度;D_out是輸出維度
N, D_in, H, D_out = 64, 1000, 100, 10
# 產生隨機輸入和輸出張量
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)
# 使用nn包定義模型和損失函數
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.ReLU(),
torch.nn.Linear(H, D_out),
)
loss_fn = torch.nn.MSELoss(reduction='sum')
# 使用optim包定義優化器(Optimizer)Optimizer將會爲我們更新模型的權重。
# 這裏我們使用Adam優化方法;optim包還包含了許多別的優化算法。
# Adam構造函數的第一個參數告訴優化器應該更新哪些張量。
learning_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
for t in range(500):
    # 前向傳播:通過像模型輸入x計算預測的y
    y_pred = model(x)
    # 計算並打印loss
    loss = loss_fn(y_pred, y)
    print(t, loss.item())
    # 在反向傳播之前,使用optimizer將它要更新的所有張量的梯度清零(這些張量是模型可學習的權重)
    optimizer.zero_grad()
    # 反向傳播:根據模型的參數計算loss的梯度
    loss.backward()
    # 調用Optimizer的step函數使它所有參數更新
    optimizer.step()

with torch.no_grad() 作用:

如果我們想計算某些的tensor的梯度,我們只需
要在建立這個tensor時加入這麼一句: requires_grad=True 。這個tensor上的任何PyTorch的操作
都將構造一個計算圖,從而允許我們稍後在圖中執行反向傳播。如果這個 tensor x 的
requires_grad=True ,那麼反向傳播之後 x.grad 將會是另一個張量,其爲x關於某個標量值的梯度。
有時可能希望防止PyTorch在 requires_grad=True 的張量執行某些操作時構建計算圖;例如,在
訓練神經網絡時,我們通常不希望通過權重更新步驟進行反向傳播。在這種情況下,我們可以使
用 torch.no_grad() 上下文管理器來防止構造計算圖。

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