Pytorch创建module的几种方式
一、使用torch.nn中组装方法
注意,当你初始化好自己的module后,pytorch会默认自动初始化module里面的网络参数的
1.nn.Sequential组装net
import torch
from torch import nn
net = nn.Sequential(
nn.Linear(10, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
使用print(net)
, 结果为
Sequential(
(0): Linear(in_features=10, out_features=128, bias=True)
(1): ReLU()
(2): Linear(in_features=128, out_features=10, bias=True)
)
这种方式写,可以用net[]索引得到网络的某一层
比如print(net[0])
, 得到
Linear(in_features=10, out_features=128, bias=True)
上述构建module的方式也可以这样写也,这样的话相当于给每一层网络起了一个名字。
from collections import OrderedDict
net_prime = nn.Sequential(OrderedDict([
('linear1', nn.Linear(10, 128)),
('relu', nn.ReLU()),
('linear2', nn.Linear(128, 1))
]))
这时print(net_prime)
得到的结果是:
Sequential(
(linear1): Linear(in_features=10, out_features=128, bias=True)
(relu): ReLU()
(linear2): Linear(in_features=128, out_features=1, bias=True)
)
可以看到,每一层网络的名称已经被自定义了,这时可以用名称索引网络层print(net_prime.linear1)
,得到结果:
Linear(in_features=10, out_features=128, bias=True)
2.使用ModuleList
显然,ModuleList创建的module,其类似List的各种属性
net = nn.ModuleList([nn.Linear(784, 256), nn.ReLU()]) # 定义module
net.append(nn.Linear(256, 10)) # 在module的最后新增一层网络
print(net[-1]) # 打印最后一层网络
print(net)
得到结果:
Linear(in_features=256, out_features=10, bias=True)
ModuleList(
(0): Linear(in_features=784, out_features=256, bias=True)
(1): ReLU()
(2): Linear(in_features=256, out_features=10, bias=True)
)
3.使用ModuleDict
显然,ModuleDict创建的module,其类似Dict的各种属性,每一个键值对分别是该层网络的名称和该层网络的结构。
net = nn.ModuleDict({
'linear': nn.Linear(784, 256),
'act': nn.ReLU(),
})
# 添加网络层
net['output'] = nn.Linear(256, 10)
print(net['linear'])
print(net)
得到输出结果:
Linear(in_features=784, out_features=256, bias=True)
ModuleDict(
(linear): Linear(in_features=784, out_features=256, bias=True)
(act): ReLU()
(output): Linear(in_features=256, out_features=10, bias=True)
)
4.三种方式的对比
nn.Sequential 和 nn.ModuleList和nn.ModuleDict的区别:
nn.Sequential内部实现了forward函数,因此可以不用写forward函数。而nn.ModuleList和nn.ModuleDict则没有实现内部forward函数。
nn.Sequential需要严格按照顺序执行,而其它两个模块则可以任意调用。
比如,使用nn.Sequential创建的module,将其包装为class时,可以这么写
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.model = nn.Sequential(
nn.Linear(10, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
def forward(self, x):
# 简单写下,实际使用时输入的参数x能不能匹配这里的net输入是需要考虑的
# 因为self.net()是使用nn.Sequential创建的,x输出进去后会自动根据定义的网络层顺序调用,最后得到结果(因为Sequential会为该self.net自动生成一个内置的forward函数),但是使用ModuleList或者ModuleDict创建self.net就不可以这样来使用,需要自己动手实现self.net的forward函数
y = self.model(x)
return y
二、不使用任何组装方法
class Net(nn.Module):
def __init__(self, num_inputs, num_hiddens, num_outputs):
super(Net, self).__init__()
self.hidden = nn.Linear(num_inputs, num_hiddens)
self.act = nn.ReLU()
self.output = nn.Linear(num_hiddens, num_outputs)
def forward(self, x): # 因为继承该类自nn.Module, 这个函数s是callable,可以通过该类的 实例化对象名称(x), 自动调用该函数
a = self.act(self.hidden(x))
return self.output(a)
使用print打印一下看下效果
net = Net(10, 128, 5)
print(net)
得到输出结果:
TNet(
(hidden): Linear(in_features=10, out_features=128, bias=True)
(act): ReLU()
(output): Linear(in_features=128, out_features=5, bias=True)
)
如果定义一个随机的,看下输出结果
X = torch.rand((1, 10))
print(X)
print(net(X))
print(net(X).shape)
输出结果是:
tensor([[0.7814, 0.2781, 0.0170, 0.3828, 0.7887, 0.8665, 0.1628, 0.3811, 0.9612,
0.4713]])
tensor([[-0.1424, -0.0780, 0.1286, 0.0140, -0.0790]],
grad_fn=<AddmmBackward0>)
torch.Size([1, 5])
可以看到当输入X的维度是(1, 10)时,该module计算得到的输出维度是(1, 5),其中的10和5都是我们在初始化net时设置好的。
【注:本文为作者原创】