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)