本站原创文章,转载请说明来自《老饼讲解-深度学习》www.bbbdata.com
顺序模块是深度学习中最常用的模块形式,它按顺序调用每一个模块
而pytorch为顺序模块提供了一种快捷的AIP-Sequential来封装顺序模块
本文讲解pytorch的Sequential顺序模块API的使用以及展示一个日常应用例子
本节讲解pytorch如何使用Sequential函数构建顺序模块
什么是顺序模块
顺序模块是指模块的运算就是按顺序连续调用一连串的模块,如下:
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.L1 = nn.Linear(2,3) # 定义第一个线性层模块
self.A1 = nn.ReLU(inplace=True) # 定义第一个线性层激活函数模块
self.L2 = nn.Linear(3,2) # 定义第二个线性层模块
def forward(self, x):
# 按顺序连续调用各个模块
y = self.L1(x) # 调用第一个线性层模块
y = self.A1(y) # 调用第一个线性层激活函数模块
y = self.L2(y) # 调用第二个线性层模块
return y
model = Model() # 初始化模型
以上例子就是一个顺序模块,它在forward中只是简单地按顺序调用L1、A1、L2模块
顺序模块是深度学习中最常见的场景,因为深度学习中的模型往往就是层层前馈的结构
利用Sequential构建顺序模块
由于顺序模块使用非常频繁,而上述写法比较重复与繁琐,
pytorch提供了Sequential函数,可以把这些连续调用的模块按顺序组装为一个整体的顺序模块,
具体示例如下
from torch import nn
from collections import OrderedDict
# 以Sequential的方式定义一个Module并初始化
model = nn.Sequential(OrderedDict({
'L1':nn.Linear(2,3),
'A1':nn.ReLU(inplace=True),
'L2':nn.Linear(3,2)
}))
# -------打印模型参数-------------------
param_dict = model.state_dict() # 从模型中提取出模型参数
for key in param_dict: # 历遍所有参数名称
print(key,':',param_dict[key].data) # 打印参数名称和数据
运行结果如下:
可以看到,通过Sequential可以快速、简洁地构建一个顺序模块
利用Sequential构建顺序模块(不带名称)
在顺序模块的应用中,往往各个子模块的名称并不重要,
因此,Sequential提供了一种更简洁的写法,它默认将以0,1,2.....对子模块进行命名
具体示例如下:
from torch import nn
# 以Sequential的方式定义一个Module并初始化
model = nn.Sequential(
nn.Linear(2,3),
nn.ReLU(inplace=True),
nn.Linear(3,2)
)
# -------打印模型参数-------------------
param_dict = model.state_dict() # 从模型中提取出模型参数
for key in param_dict: # 历遍所有参数名称
print(key,':',param_dict[key].data) # 打印参数名称和数据
运行结果如下:
可以看到,在不传入子模块名称时,Sequential以0,1,2.....对子模块进行命名
本节展示一个利用Sequential构建一个卷积神经网络的例子,以说明Sequential为模型构建带来的好处
Sequential使用实例
下面展示一个pytorch使用Sequential构建模型的实例,它可以使模型的整体结构更加清晰与易理解
具体示例如下:
import torch
from torch import nn
# 卷积神经网络的结构
class ConvNet(nn.Module):
def __init__(self,in_channel,num_classes):
super(ConvNet, self).__init__()
#------------特征抽取层--------
self.feature= nn.Sequential(
# C1层:输出14*14
nn.Conv2d(in_channel,8, kernel_size=7,stride=1,padding=3),
nn.ReLU(inplace=True),
nn.AvgPool2d(kernel_size=2,stride=2),
# C2层:输出7*7
nn.Conv2d(8,16, kernel_size=5,stride=1,padding=2),
nn.ReLU(inplace=True),
nn.AvgPool2d(kernel_size=2,stride=2),
)
# ----------特征拟合层--------
self.classifier= nn.Sequential(
# 第一个全连接层
nn.Linear(784, 256),
nn.ReLU(inplace=True),
nn.Dropout(p=0.5),
# 第二个全连接层
nn.Linear(256, num_classes)
)
def forward(self, x):
f = self.feature(x) # 抽取特征
f = nn.Flatten()(f) # 对特征展平
y = self.classifier(f) # 拟合特征
return y
上述例子构建了一个卷积神经网络,由于卷积神经网络的卷积层的功能是特征抽取,全连接层的功能是特征拟合,
所以代码中利用Sequential把卷积层组装为feature模块,把全连接层组装为classifier模块
这样可以使得模块结构意义更加清晰,在forward里的代码也更简洁,整体代码更加结构化,更具可读性
老饼语:关于函数与模块
很多计算pytorch都提供了函数与模块两种Api,
例如ReLu,既有ReLu函数torch.nn.functional.relu,也有ReLu模块nn.ReLU
刚接触pytorch时,老饼非常疑惑,为什么既要有函数又要有模块,
直到了解Sequential后才明白,模块主要是提供给Sequential使用的
也就是说,torch.nn.functional.relu函数一般在forward中使用,
而ReLu模块则在Sequential里使用,因为Sequential是只针对连续模块的
End