4.4 自定义层

    我们先介绍如何定义一个不含模型参数的自定义层。事实上,这和4.1节(模型构造)中介绍的使用Module类构造模型类似。下面的CenteredLayer类通过继承Module类自定义了一个将输入减掉均值后输出的层,并将层的计算定义在了forward函数里。这个层里不含模型参数。

    我们可以实例化这个层,然后做前向计算。

    1. layer = CenteredLayer()
    2. layer(torch.tensor([1, 2, 3, 4, 5], dtype=torch.float))

    输出:

    1. tensor([-2., -1., 0., 1., 2.])

    我们也可以用它来构造更复杂的模型。

    1. net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())

    下面打印自定义层各个输出的均值。因为均值是浮点数,所以它的值是一个很接近0的数。

    1. 0.0

    我们还可以自定义含模型参数的自定义层。其中的模型参数可以通过训练学出。

    在4.2节(模型参数的访问、初始化和共享)中介绍了Parameter类其实是Tensor的子类,如果一个TensorParameter,那么它会自动被添加到模型的参数列表里。所以在自定义含模型参数的层时,我们应该将参数定义成Parameter,除了像4.2.1节那样直接定义成Parameter类外,还可以使用ParameterListParameterDict分别定义参数的列表和字典。

    ParameterList接收一个Parameter实例的列表作为输入然后得到一个参数列表,使用的时候可以用索引来访问某个参数,另外也可以使用appendextend在列表后面新增参数。

    1. class MyDense(nn.Module):
    2. def __init__(self):
    3. super(MyDense, self).__init__()
    4. self.params = nn.ParameterList([nn.Parameter(torch.randn(4, 4)) for i in range(3)])
    5. def forward(self, x):
    6. for i in range(len(self.params)):
    7. x = torch.mm(x, self.params[i])
    8. return x
    9. net = MyDense()

    输出:

    1. MyDense(
    2. (params): ParameterList(
    3. (0): Parameter containing: [torch.FloatTensor of size 4x4]
    4. (1): Parameter containing: [torch.FloatTensor of size 4x4]
    5. (2): Parameter containing: [torch.FloatTensor of size 4x4]
    6. (3): Parameter containing: [torch.FloatTensor of size 4x1]
    7. )
    8. )

    ParameterDict接收一个Parameter实例的字典作为输入然后得到一个参数字典,然后可以按照字典的规则使用了。例如使用update()新增参数,使用keys()返回所有键值,使用items()返回所有键值对等等,可参考官方文档

    1. MyDictDense(
    2. (params): ParameterDict(
    3. (linear1): Parameter containing: [torch.FloatTensor of size 4x4]
    4. (linear2): Parameter containing: [torch.FloatTensor of size 4x1]
    5. (linear3): Parameter containing: [torch.FloatTensor of size 4x2]
    6. )

    这样就可以根据传入的键值来进行不同的前向传播:

    1. x = torch.ones(1, 4)
    2. print(net(x, 'linear1'))
    3. print(net(x, 'linear2'))
    4. print(net(x, 'linear3'))

    输出:

    1. tensor([[-0.8783]], grad_fn=<MmBackward>)
    2. tensor([[ 2.2193, -1.6539]], grad_fn=<MmBackward>)

    我们也可以使用自定义层构造模型。它和PyTorch的其他层在使用上很类似。

    输出:

    1. Sequential(
    2. (0): MyDictDense(
    3. (params): ParameterDict(
    4. (linear1): Parameter containing: [torch.FloatTensor of size 4x4]
    5. (linear2): Parameter containing: [torch.FloatTensor of size 4x1]
    6. (linear3): Parameter containing: [torch.FloatTensor of size 4x2]
    7. )
    8. )
    9. (1): MyListDense(
    10. (params): ParameterList(
    11. (0): Parameter containing: [torch.FloatTensor of size 4x4]
    12. (1): Parameter containing: [torch.FloatTensor of size 4x4]
    13. (2): Parameter containing: [torch.FloatTensor of size 4x4]
    14. (3): Parameter containing: [torch.FloatTensor of size 4x1]
    15. )
    16. )
    17. )
    • 可以通过Module类自定义神经网络中的层,从而可以被重复调用。