Pytorch学习记录(4) torch.nn.module的使用
-
torch.nn.module的定义:
torch.nn是专门为神经网络设计的模块化接口. nn构建于autograd之上,可以用来定义和运行神经网络。
nn.Module是nn中十分重要的类,包含网络各层的定义及forward方法。
在用户自定义神经网络时,需要继承自nn.Module类。
![](https://img-blog.csdnimg.cn/img_convert/76792d93d9d1dc579063b7d3df3bf21f.png)
我们可以通过重写子类的__init__与forward函数,实现自己需要的神经网络以及向前传播函数。
具体相关函数的参数介绍可以参考Module — PyTorch 1.13 documentation
-
torch.nn.module的简单使用:
在官网中,对于nn.module的代码介绍如下:
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module): # Model类继承自nn.Module
def __init__(self): # 构造函数
super(Model, self).__init__() # 在构造函数中要调用Module的构造函数
self.conv1 = nn.Conv2d(1, 20, 5) # 卷积操作
self.conv2 = nn.Conv2d(20, 20, 5) # 卷积操作
def forward(self, x): # 前向传播函数
x = F.relu(self.conv1(x)) # 先卷积操作conv1,后非线性操作relu
return F.relu(self.conv2(x))
在定义自己的神经网络时,可以通过以下的方法:
1)需要继承nn.Module类,并实现forward方法。继承nn.Module类之后,在构造函数中要调用Module的构造函数, super(Linear, self).init()
2)一般把网络中具有可学习参数的层放在构造函数__init__()中。
3)不具有可学习参数的层(如ReLU)可放在构造函数中,也可不放在构造函数中(而在forward中使用nn.functional来代替)。可学习参数放在构造函数中,并且通过nn.Parameter()使参数以parameters(一种tensor,默认是自动求导)的形式存在Module中,并且通过parameters()或者named_parameters()以迭代器的方式返回可学习参数。
4)只要在nn.Module中定义了forward函数,backward函数就会被自动实现(利用Autograd)。而且一般不是显式的调用forward(layer.forward), 而是layer(input), 会自执行forward().
5)在forward中可以使用任何Variable支持的函数,毕竟在整个pytorch构建的图中,是Varible在流动。还可以使用if, for, print, log等python语法。
-
构建一个简单的自定义层
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear, CrossEntropyLoss
from torch.utils.data import DataLoader
# 加载数据集,转换成tensor类型
dataset = torchvision.datasets.CIFAR10(root="./data", train=False, download=True,
transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=1)
# 创建网络
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
# 定义计算loss
loss = CrossEntropyLoss()
m = Model()
# 设置优化器
optim = torch.optim.SGD(m.parameters(), lr=0.01)
for epoch in range(20):
running_loss = 0.0
for data in dataloader:
imgs, targets = data
outputs = m(imgs)
result_loss = loss(outputs, targets) # 计算数据集经过神经网络后的输出和真实数据输出之间的误差
optim.zero_grad() # 梯度清零————要把网络模型当中每一个 调节 参数梯度 调为0,参数清零
result_loss.backward() # 反向传播求解梯度————调用存损失函数的反向传播,求出每个节点的梯度,
optim.step() # 更新权重参数————调用优化器,对每个参数进行调优,循环
running_loss = running_loss + result_loss # 对整体损失的求和
print(running_loss)
PS:在机器学习中,优化器(optimizer)是一种用于更新模型参数以最小化训练误差的算法。它可以将损失函数的梯度作为输入,并根据该梯度调整模型参数的值。
先将梯度值归零,:optimizer.zero_grad();
然后反向传播计算得到每个参数的梯度值:loss.backward();
最后通过梯度下降执行一步参数更新:optimizer.step();
由于pytorch的动态计算图,当我们使用loss.backward()和opimizer.step()进行梯度下降更新参数的时候,梯度并不会自动清零。并且这两个操作是独立操作。
![](https://img-blog.csdnimg.cn/img_convert/d900fe8728c88106a7812515a123995a.png)
4. 总结
本文的实践说明了如何使用Module父类来拓展实现自定义模型、自定义层,我们发现二者有异曲同工之处,这也是pytorch如此受欢迎的原因之一了。