神经网络工具nn
实现神经网络
torch 将张量转换为torch.cuda.TensorFloat并在GPU上进行计算
torch.autograd 构建计算图并自动获取梯度
torch.nn 具有共享层和损失函数的神经网络库
torch.optim 通用优化算法
神经网络基本结构
网络层:神经网络的基本模型
网络模型:层构成的网络
损失函数:参数学习的目标函数,通过最小化损失函数来更新参数
优化器:使损失函数最小
torch.nn模块
1. 构建网络模型
通过nn.Module
和nn.functional
构建网络层,前者继承自Module
类,包含各网络层的定义及forward方法,会自动提取可学习参数,只要实现了forward函数,backward函数就会利用autograd自动实现
- nn.Xxx继承自
nn.Module
,需先实例化并传入参数,能很好的与nn.Sequential
结合,而nn.functional.xxx
无法与之结合使用 - nn.Xxx不需要自己定义和管理
weight
和bias
参数,而nn.functional.xxx
需要自己定义,且每次调用时都需要手动传入,不利于代码复用 - Dropout操作在训练和测试阶段是有区别的,使用
nn.Xxx
定义Dropout,在调用model.eval()
时,自动实现状态转换,而nn.functional.xxx
无此功能
一般,卷积层,全连接层,Dropout层含有可学习参数的一般使用nn.Module,激活函数,池化层不含可学习参数的使用nn.functional
nn.Sequential()构建网络模型,若要对每层进行命名,采用nn.Sequential
组合网络层,通过add_module()
添加每一层,并给每一层进行命名
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv= torch.nn.Sequential(
OrderedDict([
("conv1", torch.nn.Conv2d(3, 32, 3, 1, 1)),
("relu1", torch.nn.ReLU()),
("pool", torch.nn.MaxPool2d(2)),
])
)
self.dense= torch.nn.Sequential(
OrderedDict([
("dense1", torch.nn.Linear(32*3*3, 128)),
("relu2", torch.nn.ReLU()),
("dense2", torch.nn.Linear(128, 10)),
])
)
2. 前向传播
forward()
函数将输入层,网络层,输出层连接,实现数据的前向传导
3. 反向传播
loss.backward()
利用复合函数的链式法则
4. 训练模型
训练阶段,需使模型处于训练模式,model.train()
会将所有的module设置为训练模式
测试阶段,model.eval()
会将所有的training
属性设置为False
缺省情况下梯度累加,需用optimizer.zero_grad()
手工将梯度初始化或清零
计算损失值,再调用loss.backward()
自动生成梯度,再使用optimizer.step()
执行优化器,将梯度反向传播
用GPU训练,需将模型,训练数据,测试数据to(device)
,若要用多GPU,需要用模型和数据引用nn.DataParallel
网络的可学习参数可通过net.parameters()
返回,net.named_parameters()
可同时返回可学习参数及名称,
forward()的输入输出都是Variable,只有Variable有自动求导能力,Tensor是没有的
net.zero_grad()
清空梯度
torch.nn只支持mini_batches,一次输入一个batch,可用 input.unsqueeze(0)将batch_size设置为1
torch.nn实现了大多数的损失函数,如nn.MSELoss均方误差,nn.CrossEntropyLoss交叉熵损失
构建神经网络
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
class Net(nn.Module):
def __init__(self) -> None:
super(Net,self).__init__()
# 卷积层1 表示输入图像为单通道,6表示输出通道数
# 表示卷积核为 5*5
self.conv1= nn.Conv2d(1, 6, 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()
print(net)
for name,parameters in net.named_parameters():
print(name,":",parameters.size())
input= Variable(torch.randn(1,1,32,32))
output= net(input)
print(output.size())
net.zero_grad()
output.backward(Variable(torch.ones(1,10)))
target= Variable(torch.arange(0,10))
criterion= nn.MSELoss()
loss= criterion(output, target)
print(net.conv1.bias.grad)
learning_rate= 0.01
for f in net.parameters():
f.data.sub_(f.grad.data* learning_rate)