torch.nn是专门为神经网络设计的模块化接口。nn构建于Autograd之上,用来定义和运行神经网络。nn.Module是nn中最重要的类,可以把它看作一个网络的封装,包含网络各层定义以及forward方法、调用forward(input)方法,可返回前向传播结果。下面以LeNet网络为例:
LeNet网络结构
1.定义网络
1.1 定义网络时候,需要继承nn.Module,并实现它的forward方法,把网络中具有可学参数的层放在构造函数__init__中。其他的建议放外面,在forward中使用nn.functional代替。
eg:
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
#nn.Module子类的函数必须在构造函数中执行父类的构造函数
#下式等价于nn.Module.__init__(self)
super(Net,self).__init__()
#卷积层‘1’表示输入图片为单通道,‘6’表示输出通道数,‘5’表示卷积核为5*5
self.conv1=nn.Conv2d(1,6,5)
#卷积层
self.conv2 = nn.Conv2d (6, 16, 5)
#仿射层、全连接层,y=wx+b
#一般定义一个linear层的时候,写法为nn.Linear(in_features,out_features)
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’表示自适应
#这句话一般出现在model类的forward函数中,具体位置一般都是在调用分类器之前。分类器是一个简单的nn.Linear()结构,
# 输入输出都是维度为一的值,x = x.view(x.size(0), -1) 这句话的出现就是为了将前面多维度的tensor展平成一维
#view()函数的功能根reshape类似,用来转换size大小。x = x.view(batchsize, -1)中batchsize指转换后有几行,
# 而-1指在不告诉函数有多少列的情况下,根据原tensor数据和batchsize自动分配列数。
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()
print(net)
out:
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)
)
1.2 网络的可学习参数通过net.parameters()返回,net.named_parameters可同时返回可学习的参数及名称。
params=list(net.parameters())
#print(params)
print(len(params))
for name,parameters in net.named_parameters():
print(name,':',parameters.size())
out:10
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])
1.3 forward函数的输入输出都是Variable,只有Variable,才有自动求导功能,Tensor是没有的,所以输入时,需要把Tensor封装成Variable。
from torch.autograd import Variable import torch as t input=Variable(t.randn(1,1,32,32)) out=net(input) print(out.size()) out: torch.Size([1, 10])
net.zero_grad()#所有参数的梯度清零 out.backward(Variable(t.ones(1,10)))#反向传播
注意:torch.nn支持mini-batches,不支持一次只输一个样本,即一次必须是一个batch。如果只想输入一个样本,则用input.squeeze(0),将batch_size设为1。例如,nn.Conv2d输入必须是4维的,(nSamples,nChannels,Height,Width)