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时设置好的。

【注:本文为作者原创】

posted @ 2023-04-22 21:50  Bai_Er  阅读(108)  评论(0编辑  收藏  举报