PyTorch学习之神经网络

PyTorch学习之 神经网络

学习网站

http://pytorch123.com/SecondSection/neural_networks/


神经网络

神经网络可以通过torch.nn包来构建,它是基于自动梯度来构建一些模型,一个nn.Module包括层和一个方法forward(input),同时也会返回一个输出(output)。
下图是一个简单的前馈神经网络LeNet,一个简单的神经网络包括一下几点:

  • 定义一个包含可训练参数的神经网络
  • 迭代整个输入
  • 通过神经网络处理输入
  • 计算损失函数值
  • 反向传播梯度到神经网络的参数
  • 更新网络的参数,典型的一个简单的更新方法: weight = weight - learning_rate*gradient·

使用torch编写上面的神经网络

# -*- coding: UTF-8 -*-
"""
Modify: 2019-12-14
"""
import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        # super(Net,self) 首先找到 Net 的父类(就是类 nn.Module),
        # 然后把类 Net 的对象转换为类 FooParent 的对象
        super(Net, self).__init__()
        #构建卷积
        self.conv1 = nn.Conv2d(1, 6, 5)  # 输入 1, 输出 6, 卷积 5*5,即6个不同的5*5卷积
        self.conv2 = nn.Conv2d(6, 16, 5) # 输入 6, 输出 16, 卷积 5*5
        #构建全连接 y = wx + b
        self.fc1 = nn.Linear(16*5*5, 120) # 因为有16张 5*5 map, 所以有 16*5*5 = 400个输入,因此有120个400*1的向量
        self.fc2 = nn.Linear(120, 84) # 84 个 120 * 1 个向量
        self.fc3 = nn.Linear(84, 10)  # 10个 84 * 1 个向量

    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # 2*2 的最大值池化, relu为激活函数
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) # 如果池化窗口是矩形的,则可以只设定为2
        x = x.view(-1, self.num_flat_features(x)) # view函数将张量x变形成一维的向量形式,作为全连接的输入
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:]     # 单张图像的size
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

net = Net()
print(net)
# 输出
# Net(
#   (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
#   (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
#   (fc1): Linear(in_features=400, out_features=120, bias=True)
#   (fc2): Linear(in_features=120, out_features=84, bias=True)
#   (fc3): Linear(in_features=84, out_features=10, bias=True)
# )

# 一个模型的训练参数可以通过调用 net.parameterss()返回
params = list(net.parameters())
print(len(params))
print(params[0].size())
# 输出
# 10
# torch.Size([6, 1, 5, 5])

#下面尝试随机生成一个32*32的输入。注意:期望的输入维度是32*32
# 为了使用这个网络在MNIST数据上使用,需要把数据集中的图像维度修改为32*32
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
#输出
# tensor([[ 0.0469,  0.0975,  0.0686,  0.0793,  0.0673,  0.0325, -0.0455, -0.0428,
# #          -0.0671, -0.0067]], grad_fn=<AddmmBackward>)

#把所有参数梯度缓存器置0, 用随机的梯度来反向传播
net.zero_grad()
out.backward(torch.randn(1, 10))

上面的代码定义了一个神经而桑落,并且处理了输入以及调用反向传播。

下面开始,计算损失值和更新网络中的权重:

  1. 损失函数:一个损失函数需要一对输入:模型输出和目标,然后计算一个值来评估输出距离目标有多远。nn包中包含着一些不同的损失函数,一个简单的损失函数就是 nn.MSELoss ,即均方误差。
output = net(input)
target = torch.randn(10)     # 目标值
target = target.view(1, -1)  # 将其变换成与输出值相同的尺寸格式
criterion = nn.MSELoss()     # MSELoss
loss = criterion(output, target)  #计算输出与目标之间的损失函数
print(loss)
#输出
#tensor(0.3130, grad_fn=<MseLossBackward>)
  1. 反向传播:为了使损失进行反向传播,需要做的仅仅是使用loss.backward()。首先要清空现存的梯度,否则会和现存的梯度累计到一起
net.zero_grad()
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()
print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

#输出
# conv1.bias.grad before backward
# tensor([0., 0., 0., 0., 0., 0.])
# conv1.bias.grad after backward
# tensor([-0.0040, -0.0041,  0.0244, -0.0020, -0.0054, -0.0084])
  1. 更新神经网络参数
    最简单的更新计算方式就是使用随机梯度下降 weight = weight - learning_rate * gradient
    python实现方式
learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)

torch.optim中内置了多种权重更新规则,类似于SGD, Nesterov-SGD,Adam, RMSProp等。
使用方式如下:

import torch.optim as optim
# 创建优化器
optimizer = optim.SGD(net.parameters(), lr=0.01)

# 在训练的循环中加入一下代码
optimizer.zero_grad()   # 将梯度置0
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()    # 更新权重
发布了38 篇原创文章 · 获赞 29 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/ruotianxia/article/details/103532073
今日推荐