0.本章内容
Pytorch中集成了许多现成的模块,如包torch.nn中,集成了一些常见的网络层,如卷积等;包torch.optim中集成了许多常用的优化算法,如SGD,Adam等。本章将就torch.nn以及torch.optim做简要介绍。
1.torch.nn
直观理解
- 在keras、TFLearn等高级的深度学习集成库中,将许多计算进行更加高级的封装
- torch.nn包内就是类似这种高级封装,里面包括了卷积,池化,RNN等计算,以及其他如Loss计算,可以把torch.nn包内的各个类想象成神经网络的一层
- 创建一个torch.nn中的层后,对其输入Variable,将得到对应输出的Variable,具体例子见下示例
作用
- 它的作用包括,能够接受一个输入,并得到一个输出(forward操作)。同时,他保存了该层学习的参数,以及其他的一些状态变量
- 这种方式将网络高度模块化,使得网络的每个运算都像积木一样一层又一层叠加。
实现机制
- torch.nn包里面的大部分类都是继承了父类torch.nn.Modules,即本质上所有torch.nn中的层(如卷积、池化)都是torch.nn.Modules
- torch.nn.Modules可以简单认为是网络一层,包括该层的参数,以及一些操作,如forward,调用参数等
- 同样地,它的作用包括,能够接受一个输入,并得到一个输出(forward操作)。同时,他保存了该层学习的参数,以及其他的一些状态变量。并实现各类功能的方法,如返回Modules的参数等
- 因此可以把torch.nn以及torch.nn.Modules看做是一个定义好的小网络(包括其参数),给该网络一个输入,其将得到一个输出。输入输出都是Variable
- 更多Modules具体机制以及如何重写将在后面章节介绍
torch.nn示例
import torch.nn as nn
import torch
from torch.autograd import Variable
# nn.Sequential是一个Module的容器,里面包含多个Module。里面的Module在forward时将按顺序进行操作,如下即Conv->BN->ReLU->Pool
# nn.Conv2d是2维卷积,其第一个参数为输入通道数,第二个参数为输出通道数
# 注意Conv2d只接收batch输入,不接受单个数据输入,即输入必须是(N,C,H,W)
# BN层的参数是通道数
# 各层的参数已经自动初始化
model = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=5, padding=2),
nn.BatchNorm2d(16),
nn.ReLU(),
nn.MaxPool2d(2)
)
# 输出模型
print '模型: ', model
# 输出模型参数
print '模型参数: ', model.parameters
# 输出卷积层参数个数
print '卷积层参数个数: ', list(model.parameters())[0].size()
# print list(model.parameters())[0] # 输出卷积层参数
# 得到model的某一层
conv = model[0]
# model forward得到输出,model的输入输出都是Variable
# 由于forward使用了__call__函数,因此可以直接利用Modules的对象来调用forward
input_var = Variable(torch.randn(1, 1, 10, 10))
output_var = model(input_var) # 这里使用output_var = model.forward(input_var)也是可行
print output_var.size()
# model backward, output_var是一个Variable,网络在forward过程中已经建立计算图,因此使用backward可计算该model的所有可学习参数的梯度
output_var.backward(torch.ones(output_var.size()))
# 对卷积层进行重新初始化
print '旧的参数值: ', model[0].weight.data[0]
new_weight = torch.zeros(conv.weight.size())
conv.weight.data = new_weight
print '新的参数值: ', model[0].weight.data[0]
# torch.nn中也包含Loss计算,先定义好loss_fn后,可以像调用函数一样在后面进行调用
loss_fn = torch.nn.MSELoss(size_average=False)
print(loss_fn)
# 如下调用loss_fn,y_pred与y是输入的Variable,输出是计算结果的Variable
# loss = loss_fn(y_pred, y)
2 torch.optim示例
torch.optim中有许多常用的优化算法,其实用方法十分简单,详见以下示例:
# 创建一个optim,并指定对应的参数
learning_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# 将对应参数梯度置0,注意如果没有置0,则将会与上一次梯度进行叠加
optimizer.zero_grad()
# forward 然后 backward 得到梯度
y = model(x)
# 得到对应loss
loss = loss_fn(y_pred, y)
# backward后,计算出loss对制定Variable(requires_grad=True)的梯度
loss.backward()
# 更新参数
optimizer.step()
3. 例子
在学习了,torch.nn以及torch.optim,终于可以不用自己手写网络层以及优化函数了,下面将使用torch.nn及torch.optim来完成前几个章节建立的简单神经网络
import torch
from torch.autograd import Variable
# N为batch size; D_in为输入维度;
# H为隐藏层单元数; D_out为输出层维度.
N, D_in, H, D_out = 64, 1000, 100, 10
# 随机生成输入数据x,label y
x = Variable(torch.randn(N, D_in))
y = Variable(torch.randn(N, D_out), requires_grad=False)
# 使用torch.nn建立网络
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.ReLU(),
torch.nn.Linear(H, D_out),
)
# 使用torch.nn中MSELoss定义损失函数
loss_fn = torch.nn.MSELoss(size_average=False)
# 定义优化器
learning_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
for t in range(20000):
# Forward 前向传播
y_pred = model(x).mean()
# 计算loss
loss = loss_fn(y_pred, y)
print(t, loss.data[0])
optimizer.zero_grad()
# 后向传播
loss.backward()
if t % 100 == 0:
print(y_pred.data[0])
# 更新梯度
optimizer.step()