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() 上下文管理器来防止构造计算图。

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