4、神经网络的模块化接口torch.nn
本博客参考 http://studyai.com/pytorch-1.4/beginner/blitz/neural_networks_tutorial.html + 《PyTorch入门与实践》
torch.nn最核心的类是nn.Module,一个 nn.Module
包含若干 layers, 和一个方法 forward(input)
, 该方法返回 output
。
自定义的网络类需要继承nn.Module,其构造函数里必须执行一次父类构造函数。
网络中拥有可学习的参数的层要放在构造函数中,不拥有的随意。
torch.nn
仅支持 mini-batches。 整个 torch.nn
package 仅支持以样本的 mini-batch 作为输入,而不支持单个样本作为输入。
例如, nn.Conv2d
将接受一个shape为 nSamples x nChannels x Height x Width
的 4D Tensor 作为输入。
如果你有一个单样本, 请使用 input.unsqueeze(0)
将batch_size设为1(即nSamples),1 x nChannels x Height x Width
神经网络的训练步骤:
1、定义一个神经网络
2、处理输入并backward
3、计算损失(度量 网络的输出 离 我们期望的正确输出 还有多远)
4、使用优化器(优化方法)更新网络的权重和参数
#代码中的数据参考上图
########################################### 1、定义一个神经网络 import torch.nn as nn import torch.nn.functional as F class Net(nn.Module): #定义网络类,继承自nn.Module def __init__(self): #类的构造函数 super(Net,self).__init__() #执行一次父类的构造函数(硬性要求),等价于 nn.Module.__init__(self) ## 卷积层 self.conv1=nn.Conv2d(1,6,5) #输入图像 1 个通道, 6 个输出通道, 5x5 方形卷积核 self.conv2=nn.Conv2d(6,16,5) #上层的6作为此层的输入,输出16通道,5x5 ## 仿射层/全连接层,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): #卷积→激活→池化 # 最大池化的窗口大小(2, 2) x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # 如果池化窗口是方形的,你只需要指定单个数字 x = F.max_pool2d(F.relu(self.conv2(x)), 2) #-1代表自适应,reshape 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)
只要nn.Module子类中定义了forward函数,backward函数就会被自动实现。下图输出的结果:
# 参数个数 print(len(list(net.parameters()))) # 输出参数 for name in net.parameters(): print(name) # 参数名,每个参数的大小 for name,param in net.named_parameters(): print(name,":",param.size())
########################################### 2、处理输入并backward
# 尝试一个 32x32 的随机输入,这个网络(LeNet)期望的输入尺寸是 32x32 input=t.randn(1,1,32,32) out=net(input) #使用已设定的网络,1个输入,输出10个 print(out.size()) print(out) #反向传播前,所有参数的梯度清零 net.zero_grad() out.backward(t.randn(1, 10))
########################################### 3、计算损失(度量 网络的输出 离 我们期望的正确输出 还有多远) output=net(input) target=t.randn(10) #一个虚拟的目标值, 为了举例子,不要太在意 target=target.view(1,-1) # 使其具有与输出相同的shape criterion=nn.MSELoss() #损失函数中的一种:平均平方误差(mean-squared error),nn.CrossEntropyLoss交叉熵损失 loss=criterion(output,target) print(loss)
net.zero_grad() #把net中所有可学习参数的梯度清零 print("反向传播之前conv1.bias的梯度") print(net.conv1.bias.grad) loss.backward() #反向传播,该图会动态生成并自动微分,也会自动计算图中参数的导数 print("反向传播之后conv1.bias的梯度") print(net.conv1.bias.grad)
########################################### 4、使用优化器(优化方法)更新网络的权重和参数 import torch.optim as optim optimizer=optim.SGD(net.parameters(),lr=0.01) #新建优化器,指定要调整的参数和学习率。SGD随机梯度下降法 #先梯度清零 optimizer.zero_grad() #等效 net.zero_grad() #计算损失 output=net(input) loss=criterion(output,target) #反向传播 loss.backward() #更新参数 optimizer.step()