TL; DR; nn.Sequential和nn.Module都可以用于设计神经网络,前者可以视为一个网络容器,容纳了不同的层,同时按照文本出现的先后自动定义了数据的流动顺序;后者更为灵活,通过定义forward方法,使用户可以自行设计数据的流动方向,实现更为复杂的操作。
在学习Pytorch时发现有两种方式可以构造神经网络模型,分别时创建nn.Sequential容器和继承nn.Module对象,主要参考了这篇博客,并形成了如下学习笔记。
一、比较
(一)nn.Sequential是一个容器
nn.Sequential是一个容器,里面容纳这按顺序排列的网络结构的对象,如nn.Linear, nn.Relu, nn.Conv2d, etc. 官方的例子是:
# Sequential使用实例
model = nn.Sequential(
nn.Conv2d(1,20,5),
nn.ReLU(),
nn.Conv2d(20,64,5),
nn.ReLU()
)
# Sequential with OrderedDict使用实例
model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1,20,5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20,64,5)),
('relu2', nn.ReLU())
]))
(二)nn.Module是一个预制类
nn.Module是设计网络是需要继承的一个类,包含Pytorch官方写好的API,减轻用户的开发负担。通常在继承nn.Module后还需要定义forward方法,以确定数据传递方式(或称数据流向),例如:
class LinearRegression(nn.Module):
def __init__(self, input_dim, output_dim):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(input_dim, output_dim) # nn.Linear是全连接层对象,线性回归就是就是一个不接入激活函数的全连接层
def forward(self, x):
'''
该方法会被框架自动调用,不用人手动调用
'''
output = self.linear(x)
return output
input_dim = 1
output_dim = 1
model = LinearRegression(input_dim, output_dim)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 启用GPU
model.to(device)
二、二者关系
特别的由于nn.Module采用定义了forward方法,所以其实可以将nn.Sequential写入继承了nn.Module的子类中,将其作为网路的一个部分嵌入(事实上,nn.Sequential完全也可以出现在forward方法里,但是这样会使得代码过于杂乱),比如这样:
class 网络名字(nn.Module):
def __init__(self, 一些定义的参数):
super(网络名字, self).__init__()
self.layer1 = nn.Linear(num_input, num_hidden)
self.layer2 = nn.Sequential(...)
...
三、补充:关于nn.functional的使用
通常使用如下方式调用nn.functional:
import torch.nn.functional as F
这里主要讨论F.relu函数和nn.Relu对象的使用,F.relu通常直接出现在forward方法里面,而nn.Relu出现在网络定义中,这篇博客给出了实际的例子。