1、引言
首先再次安利一篇文章,这篇文章详细介绍了若是使用一个深度神经网络去实现人脸识别,这里面对卷积、池化、全链接、激活函数都有一个较为详细的解释,看完这篇文章,再来看这篇文章,相信会有一种醍醐灌顶之效:06-01 DeepLearning-图像识别网络
上一篇文章咱们介绍了实现反向传播的 autograd 这个工具,可是若是直接用这个来写深度学习的代码,对于神经网络中各类层的定义就足够让人头疼了,因此仍是有一点复杂。架构
所以在 torch 中,torch.nn 的出现就是专门为神经网络设计的模块化接口,nn 构建与 autograd 之上,能够用来定义和运行神经网络。其中 nn.Module 是 nn 中最重要的类,能够把它看做是一个网络的封装,包含网络中各层的定义和 forward 方法,调用 forward(input) 方法,能够轻松的实现前向传播。ide
接下来咱们将以卷积神经网络 LeNet 网络为例,看看如何用 nn.Module 实现,其中 LeNet 网络架构以下图所示:模块化
上述图示是一个基础的前向传播网络:接收输入,通过层层传递运算,获得一个输出。函数
固然,这篇文章的重心是告诉咱们如何利用 nn 这个工具箱搭建一个基础的神经网络架构,至于 nn 的具体用法将在将来的分享中详细介绍,也就是说这一篇文章只是笼统的介绍 nn,只要看清楚本篇文章的大致脉络便可,至于细节将来都会一一介绍。工具
2、定义网络定义网络的时候须要继承 nn.Module,并实现它的的 forward 方法,把网络中具备可学习参数的层放到构造函数 __init__ 中。若是某一层不具备可学习的参数,则便可以放在构造函数中,也能够不放入。学习
import torch as t import torch.nn as nn import torch.nn.functional as F from torch.autograd import Variable as V class Net(nn.Module): def __init__(self): super(Net, self).__init__() # nn.Module 子类的函数必须在构造函数中执行父类的构造函数 # 卷积层 self.conv1 = nn.Conv2d(1, 6, 5) # '1'表示输入图片为单通道,‘6’表示输出通道数,‘5’表示卷积核为 5*5 self.conv2 = nn.Conv2d(6, 16, 5) # 仿射层/全链接层,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): # 卷积-》激活-》池化 x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) x = F.max_pool2d(F.relu(self.conv2(x)), 2) # reshape,‘-1’表示自适应 x = x.view(x.size()[0], -1) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x net = Net() 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) )
经过 nn.module 成功定义网络结构后,有3个点须要注意:优化
params = list(net.parameters()) len(params)
10
for name, parameters in net.named_parameters(): print(f'{name}: {parameters.size()}')
conv1.weight: torch.Size([6, 1, 5, 5]) conv1.bias: torch.Size([6]) conv2.weight: torch.Size([16, 6, 5, 5]) conv2.bias: torch.Size([16]) fc1.weight: torch.Size([120, 400]) fc1.bias: torch.Size([120]) fc2.weight: torch.Size([84, 120]) fc2.bias: torch.Size([84]) fc3.weight: torch.Size([10, 84]) fc3.bias: torch.Size([10])
input = V(t.randn(1, 1, 32, 32)) # 定义输入 out = net(input) out.size() # 输出的形状
torch.Size([1, 10])
net.zero_grad() # 全部参数的梯度清零 out.backward(V(t.ones(1, 10))) # 反向传播
注:torch.nn只支持 mini-batches,不支持一次输入一个样本。若是想一次输入一个样本,能够用 input.unsqueeze(0) 把 batch_size 设置为 1。例如,nn.Conv2d输入必须是 4 维的,形如nSamples × nChannels × Height × Width,可让 nSample 设为 1,也就是 1 × nChannels × Height × Width`设计
3、损失函数nn 实现了神经网络中大多数的损失函数,例如 nn.MSELoss 计算均方偏差,nn.CrossEntropyLoss 计算交叉熵损失。blog
output = net(input) # net(input)的输出的形状是(1,10) target = V(t.arange(0, 10)).view(1, 10).float() criterion = nn.MSELoss() loss = criterion(output, target) loss
tensor(28.5546, grad_fn=<MseLossBackward>)
若是对 loss 进行反向传播溯源(使用 grad_fn 属性),能够看到它的计算图以下:
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d -> view -> linear -> relu -> linear -> relu -> linear -> MSELoss -> loss
当调用 loss.backward() 时,该图会动态生成并自动微分,也会自动计算图中参数的导数
# 运行.backward,观察调用以前和调用以后的 grad net.zero_grad() # 把 net 中全部可学习参数的梯度清零 print(f'反向传播以前conv1.bias 的梯度:{net.conv1.bias.grad}') loss.backward() print(f'反向传播以后conv1.bias 的梯度:{net.conv1.bias.grad}')
反向传播以前conv1.bias 的梯度:tensor([0., 0., 0., 0., 0., 0.]) 反向传播以后conv1.bias 的梯度:tensor([ 0.1055, 0.0943, -0.1617, 0.0416, -0.0787, 0.0285])4、优化器
在反向传播完成全部参数的梯度计算后,还须要使用优化方法更新网络的权重和参数。在 torch.optim 中实现了深度学习中绝大多数的优化方法,这里不详解介绍,将来会详细介绍,目前能成为一个合格的调包侠便可。
import torch.optim as optim # 新建一个优化器,指定要调整的参数和学习率 optimizer = optim.SGD(net.parameters(), lr=0.01) # 在训练过程当中,先将梯度清零(和 net.zero_grad()效果同样) optimizer.zero_grad() # 计算损失 output = net(input) loss = criterion(output, target) # 反向传播 loss.backward() # 更新参数 optimizer.step()5、数据加载和预处理
在深度学习中数据加载和预处理是很是麻烦的,可是 torch 提供了一些列简化和加快处理数据的工具,将来咱们也都会详解介绍。而且torch 也把一些经常使用的数据集都保存在了 torchvision 中。
6、Hub模块简介上面给出了定义一个完整的神经网络的流程,可是仍是太复杂了,若是你仅仅只是想使用一个神经网络模型完成本身的一个小demo,而不是本身费尽心思的写一个模型出来,那么hub模块就能够知足你的要求,你能够从hub模块官网获取任何一个已存的模块,而后丢入你的数据就能够得到结果,而不须要本身巴拉巴拉写一堆代码。也就是说,别人用轮子造航母,你直接把航母拿来用。
如下就是hub模块的大概用法,固然,更详细的内容能够去官网查询:
import torch model = torch.hub.load('pytorch/vision:v0.4.2', 'deeplabv3_resnet101', pretrained=True) # 加载模型,第一次加载须要一点点时间 model.eval() # 释放模型7、总结
上面笼统的介绍了如何利用 nn 这个工具箱去搭建一个神经网络,可是只给出了一个流程,不少细节咱们尚未详细解释,但这已经足够了。
下一篇文章咱们就将详细介绍 nn 工具箱的各类细节方面的东西,等你看完下一篇文章若是再跳回来看这篇文章,相信定会有醍醐灌顶之效。