[PyTorch] 笔记03:神经网络
Posted 小郭学数据
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[PyTorch] 笔记03:神经网络相关的知识,希望对你有一定的参考价值。
源自PyTorch 1.4教程[1]
Outline
-
LeNet概述 -
LeNet实现 -
定义网络 -
计算损失 -
反向传播 -
更新权重
[PyTorch] 笔记03:神经网络
构建神经网络所需要的包可以是torch.nn
而nn包则依赖于autograd包来定义模型并对它们求导
今天写的是LeNet网络,用来识别手写体
数据集的选用可以用mnist,可参见pytorch实现mnist手写数字识别[2]
1. LeNet概述
-
一般的网络学习步骤可以分为以下几个步骤: -
定义网络,通过网络进行正向传播传递 -
使用网络输出来计算损失 -
使用loss.backward()通过网络进行反向传播误差 -
使用优化器(比如随机梯度下降算法)更新权重 -
复盘一下LeNet的网路结构 -
当时使用的是平均池化,今天用最大池化来实现它 -
由两个卷积层,两个池化,三个全连接层组成的网络结构 -
当时是softmax函数实现多分类,今天用全连接实现
2. LeNet实现
2.1 定义网络
-
包含初始化,前向传播,统计全连接层前输入的特征个数
-
网络执行过程:conv1-->maxpool-->conv2-->maxpool-->fc1-->fc2-->fc3
-
每一层之后执行激活函数relu -
代码如下:
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 输入图像channel:1;输出channel:6;5x5卷积核
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 2x2 Max pooling
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# 如果是方阵,则可以只使用一个数字进行定义,树池为2*2矩阵
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
#变成一个1*num_flat_features(x)的张量
x = x.view(-1, self.num_flat_features(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:] # 除去批处理维度的其他所有维度
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net)
-
super() 函数是用于调用父类的一个方法,即调用了nn.Module。
-
Conv2d
-
一般用于二维图像,Conv1d常用于文本数据的处理 -
接口定义如下: -
class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
-
参数含义: -
in_channels:输入通道 -
out_channels:输出通道 -
kernel_size:过滤器大小 -
stride:步长 -
padding:填充数 -
dilation:卷积核即过滤器之间的空间距离 -
groups:分组卷积 -
bias:是否加偏移量即wx+b中的b -
关于groups介绍可参见nn.Conv2d中groups参数的理解 python [3] -
最大池化
-
实现方式:nn.MaxPool2d(),torch.nn.functional.max_pool2d() -
输出
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.zero_grad()
out.backward(torch.randn(1, 10))
-
先开始不知道到这样做的目的是啥,问了同学,最后还问了老师,你敢信? -
后来啊,猛的一发现它是跟运行loss.backward()之后做了个比较,就是看了看计算损失函数之前的梯度和之后的梯度,也没啥太大意义。蒙了一下午,晕了,真的是。 -
注 「torch.nn只支持小批量处理(mini-batches)。整个torch.nn包只支持小批量样本的输入,不支持单个样本的输入」
2.2 计算损失
-
一个损失函数接受一对(output, target)作为输入,计算一个值来估计网络的输出和目标值相差多少 -
常见的损失函数可参见几种常见的损失函数 [4] -
损失函数计算的是一个样本的损失,代价函数计算的是整个样本损失的平均值
#计算损失,使用均方误差损失函数
output = net(input)
target = torch.randn(10) # 本例子中使用模拟数据
target = target.view(1, -1) # 使目标值与数据值尺寸一致
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)
#输出
tensor(0.9866, grad_fn=<MseLossBackward>)
2.3 反向传播
-
调用loss.backward()反向传播误差,查看conv1层的偏置(bias)在反向传播前后的梯度 -
代码如下:
net.zero_grad() # 清零所有参数(parameter)的梯度缓存
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.0003, 0.0005, -0.0140, 0.0026, 0.0057, -0.0056])
2.4 更新权重
-
使用的更新规则:随机梯度下降算法(SGD) -
代码如下:
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
-
常见的更新规则有: -
Mini-batch梯度下降 -
动量梯度下降法 Momentum -
RMSprop算法 -
Adam算法
下节写如何训练一个图片分类器
「欢迎批评指正,一起学习进步!!!」
Reference
PyTorch 1.4教程: https://pytorch.apachecn.org/docs/1.4/blitz/neural_networks_tutorial.html
[2]pytorch实现mnist手写数字识别: https://www.jianshu.com/p/0504d5bfc26f
[3]nn.Conv2d中groups参数的理解 python: https://blog.csdn.net/qq_39938666/article/details/89378096
[4]几种常见的损失函数 : https://www.cnblogs.com/lliuye/p/9549881.html
以上是关于[PyTorch] 笔记03:神经网络的主要内容,如果未能解决你的问题,请参考以下文章