Pytorch深度学习实战3-6:详解网络骨架模块nn.Module(附实例)
Posted Mr.Winter`
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pytorch深度学习实战3-6:详解网络骨架模块nn.Module(附实例)相关的知识,希望对你有一定的参考价值。
目录
1 什么是nn.Module?
在实际应用过程中,经典网络结构(如卷积神经网络)往往不能满足我们的需求,因而大多数时候都需要自定义模型,比如:多输入多输出(MIMO)、多分支模型、跨层连接模型等。nn.Module
就是Pytorch
中用于自定义模型的核心方法。在Pytorch
中,自定义层、自定义块、自定义模型,都是通过继承nn.Module
类完成的。
nn.Module
的定义如下
class Module(object):
def __init__(self):
def forward(self, *input):
def __call__(self, *input, **kwargs):
def parameters(self, recurse=True):
def named_parameters(self, prefix='', recurse=True):
def children(self):
def named_children(self):
def modules(self):
def named_modules(self, memo=None, prefix=''):
def train(self, mode=True):
def eval(self):
def zero_grad(self):
...
注意:自定义网络需要继承nn.Module
类,并重点实现上面的构造函数__init__
构造函数和forward()
这两个方法。
2 从一个例子说起
下面是一个自定义感知机的实例
# 感知机
class Perception(nn.Module):
def __init__(self, inDim, hidDim, outDim):
super(Perception, self).__init__()
self.perception = nn.Sequential(
nn.Linear(inDim, hidDim),
nn.Sigmoid(),
nn.Linear(hidDim, outDim),
nn.Sigmoid()
)
def forward(self, x):
return self.perception(x)
测试模块
perception = Perception(5,20,10)
print(perception(torch.Tensor([1,2,3,4,5]))) # 自动调用forward()前向传播
其中nn.Sequential()
可以序列化封装若干个相连的组件,在希望快速搭建模型且无需考虑中间过程的情形下,推荐使用nn.Sequential()
进行局部模块化。
从上面的实例可以看出:
- 一般把网络中的特定结构(如全连接层、卷积层等)以序列的形式放在构造函数
__init__()
中 - 将模型自定义的各个层的连接关系和数据通路设计放在
forward()
函数中,以实现模型功能并保证数据结构正常 - 不具有可学习参数的层(如
ReLU
、dropout
、BatchNormanation
层等)可并入__init__()
内部的某个层,或在forward()
函数中进行层间连接
库nn.functional
同样提供了大量网络模块和组件,与nn.Module
类不同在于其更偏向底层——nn.Module
封装了对学习参数的维护,更注重模型结构;nn.functional
需要手动指定参数和结构,例如下面线性模型Linear
的核心源码,其前向过程仍然调用了底层的nn.functional
实现。
class Linear(Module):
def __init__(self, in_features: int, out_features: int) -> None:
super(Linear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.weight = Parameter(torch.Tensor(out_features, in_features))
self.bias = Parameter(torch.Tensor(out_features))
def forward(self, input: Tensor) -> Tensor:
return F.linear(input, self.weight, self.bias)
一般在设计通过已有nn.Module
无法组装的网络结构时,可以调用底层的nn.functional
实现;或是存在无需优化学习参数的结构(如损失函数、激活函数等),可以调用nn.functional
(即作为单纯函数使用)避免实例化nn.Module
,轻量化网络
# 使用nn.Module需要实例化后调用
lossFunc = nn.CrossEntropyLoss()
loss = lossFunc(output, label)
# 使用nn.functional则只作为函数即可
loss = F.cross_entropy(output, label)
3 nn.Module主要方法
nn.Module的主要属性与方法列举如表所示。
序号 | 属性/方法 | 含义 |
---|---|---|
1 | forward() | 模型前向传播 |
2 | train() | 训练模式 |
3 | eval() | 评估模式 |
4 | named_parameters() | 返回模型各可学习参数的名称和参数组成的列表 |
5 | parameters() | 返回模型各可学习参数组成的列表 |
6 | children() | 返回一个迭代器,其中每个元素是Sequential 序列类型,可以使用下标索引来进一步获取每一个Sequenrial 里面的具体层,比如conv 层、dense 层等 |
7 | named_children() | 返回一个迭代器,其中每个元素是一个二元组,第一元是名称,第二元是该名称对应的层或Sequential 序列 |
4 自定义网络一般步骤
自定义网络一般步骤总结如下:
- 自定义一个继承自Module的类
- 实现构造函数
_init__
,在其中参数化网络层,比如卷积神经网络的卷积核大小、池化层尺寸,全连接网络的输入输出大小等; - 实现前向传播
forward()
接口,定义网络的连接情况或其他运算方式(如向量拼接、向量变维、数据处理等)
下面再给出一个卷积神经网络的实例加深理解
class CNN(nn.Module):
def __init__(self):
super().__init__()
self.convPoolLayer_1 = nn.Sequential(
nn.Conv2d(in_channels=1, out_channels=10, kernel_size=5),
nn.MaxPool2d(kernel_size=2),
nn.ReLU()
)
self.convPoolLayer_2 = nn.Sequential(
nn.Conv2d(in_channels=10, out_channels=20, kernel_size=5),
nn.MaxPool2d(kernel_size=2),
nn.ReLU()
)
self.fcLayer = nn.Linear(320, 10)
def __str__(self) -> str:
return "cnn_model"
def forward(self, x):
batchSize = x.size(0)
x = self.convPoolLayer_1(x)
x = self.convPoolLayer_2(x)
x = x.reshape(batchSize, -1)
x = self.fcLayer(x)
return x
🔥 更多精彩专栏:
Pytorch深度学习实战3-5:详解计算图与自动微分机(附实例)
目录
1 计算图原理
计算图(Computational Graph)是机器学习领域中推导神经网络和其他模型算法,以及软件编程实现的有效工具。
计算图的核心是将模型表示成一张拓扑有序(Topologically Ordered)的有向无环图(Directed Acyclic Graph),其中每个节点 u i u_i ui包含数值信息(可以是标量、向量、矩阵或张量)和算子信息 f i f_i fi。拓扑有序指当前节点仅在全体指向它的节点被计算后才进行计算。
计算图的优点在于:
- 可以通过基本初等映射 的拓扑联结,形成复合的复杂模型,大多数神经网络模型都可以被计算图表示;
- 便于实现自动微分机(Automatic Differentiation Machine),对给定计算图可基于链式法则由节点局部梯度进行反向传播。
计算图的基本概念如表所示,基于计算图的基本前向传播和反向传播算法如表
符号 | 含义 |
---|---|
n n n | 计算图的节点数 |
l l l | 计算图的叶节点数 |
L L L | 计算图的叶节点索引集 |
C C C | 计算图的非叶节点索引集 |
E E E | 计算图的有向边集合 |
u i u_i ui | 计算图中的第 i i i节点或其值 |
d i d_i di | u i u_i ui 的维度 |
f i f_i fi | u i u_i ui的算子 |
α i \\alpha _i αi | u i u_i ui的全体关联输入 |
J j → i \\boldsymbolJ_j\\rightarrow i Jj→i | 节点 u i u_i ui关于节点 u j u_j uj的雅克比矩阵 |
P i \\boldsymbolP_i Pi | 输出节点关于输入节点的雅克比矩阵 |
2 基于计算图的传播
基于计算图的前向传播算法如下
基于计算图的反向传播算法如下
以第一节的图为例,可知 E = ( 1 , 3 ) , ( 2 , 3 ) , ( 2 , 4 ) , ( 3 , 4 ) E=\\left\\ \\left( 1,3 \\right) ,\\left( 2,3 \\right) ,\\left( 2,4 \\right) ,\\left( 3,4 \\right) \\right\\ E=(1,3),(2,3),(2,4),(3,4)。首先进行前向传播:
u 3 = u 1 + u 2 = 5 u 4 = u 2 u 3 = 15 \\begincases u_3=u_1+u_2=5\\\\ u_4=u_2u_3=15\\\\\\endcases u3=u1+u2=5u4=u2u3=15
J 1 → 3 = ∂ u 3 / ∂ u 1 = 1 J 2 → 3 = ∂ u 3 / ∂ u 2 = 1 J 2 → 4 = ∂ u 4 / ∂ u 2 = u 3 = 5 J 3 → 4 = ∂ u 4 / ∂ u 3 = u 2 = 3 \\begincases \\boldsymbolJ_1\\rightarrow 3=\\partial u_3/\\partial u_1=1\\\\ \\boldsymbolJ_2\\rightarrow 3=\\partial u_3/\\partial u_2=1\\\\ \\boldsymbolJ_2\\rightarrow 4=\\partial u_4/\\partial u_2=u_3=5\\\\ \\boldsymbolJ_3\\rightarrow 4=\\partial u_4/\\partial u_3=u_2=3\\\\\\endcases ⎩ ⎨ ⎧J1→3=∂u3/∂u1=1J2→3=∂u3/∂u2=1J2→4=∂u4/∂u2=u3=5J3→4=∂u4/∂u3=u2=3
接着进行反向传播:
P 4 = 1 P 3 = P 4 J 3 → 4 = 3 P 2 = P 4 J 2 → 4 + P 3 J 2 → 3 = 8 P 1 = P 3 J 1 → 3 = 3 \\begincases \\boldsymbolP_4=1\\\\ \\boldsymbolP_3=\\boldsymbolP_4\\boldsymbolJ_3\\rightarrow 4=3\\\\ \\boldsymbolP_2=\\boldsymbolP_4\\boldsymbolJ_2\\rightarrow 4+\\boldsymbolP_3\\boldsymbolJ_2\\rightarrow 3=8\\\\ \\boldsymbolP_1=\\boldsymbolP_3\\boldsymbolJ_1\\rightarrow 3=3\\\\\\endcases ⎩ ⎨ ⎧P4=1P3=P4J3→4=3P2=P4J2→4+P3J2→3=8P1=P3J1→3=3
3 神经网络计算图
一个神经网络的计算图实例如下,所有参数都可以用之前的模型表示
L
u
1
=
W
1
∈
R
n
1
×
n
0
u
2
=
b
1
∈
R
n
1
以上是关于Pytorch深度学习实战3-6:详解网络骨架模块nn.Module(附实例)的主要内容,如果未能解决你的问题,请参考以下文章 深度学习-Pytorch张量tensor详解(线性回归实战) Pytorch深度学习实战3-7:详解数据加载DataLoader与模型处理