不带模型参数

对于不带模型参数的自定义层,我们既可以对它进行实例化,也可以将他作为一层隐藏层放在网络当中。对于这种自定义层,可以不需要明确传入的参数形状。

  1. class CenteredLayer(nn.Module):
  2. def __init__(self, **kwargs):
  3. super(CenteredLayer, self).__init__(**kwargs)
  4. def forward(self, x):
  5. return x - x.mean()
  6. # 可以实例化该层
  7. layer = CenteredLayer()
  8. print(layer(torch.tensor([1, 2, 3, 4, 5], dtype=torch.float)))
  9. # 也可以使用它构造更复杂的模型
  10. net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())
  11. y = net(torch.rand(2, 8))
  12. print(y.mean().item())

含模型参数

在自定义含模型参数的层时,我们应该将参数定义成Parameter,除了直接定义成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. self.params.append(nn.Parameter(torch.randn(4, 1)))
  6. def forward(self, x):
  7. for i in range(len(self.params)):
  8. x = torch.mm(x, self.params[i])
  9. return x
  10. net = MyDense()
  11. print(net(torch.rand(3, 4)))
  12. print(net)
  13. 结果:
  14. tensor([[-0.8253],
  15. [ 4.7919],
  16. [ 6.3828]], grad_fn=<MmBackward>)
  17. MyDense(
  18. (params): ParameterList(
  19. (0): Parameter containing: [torch.FloatTensor of size 4x4]
  20. (1): Parameter containing: [torch.FloatTensor of size 4x4]
  21. (2): Parameter containing: [torch.FloatTensor of size 4x4]
  22. (3): Parameter containing: [torch.FloatTensor of size 4x1]
  23. )
  24. )

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

  1. class MyDictDense(nn.Module):
  2. def __init__(self):
  3. super(MyDictDense, self).__init__()
  4. self.params = nn.ParameterDict({
  5. 'linear1': nn.Parameter((torch.randn(4, 4))),
  6. 'linear2': nn.Parameter((torch.randn(4, 1)))
  7. })
  8. self.params.update({'linear3': nn.Parameter(torch.randn(4, 2))})
  9. def forward(self, x, choice='linear1'):
  10. return torch.mm(x, self.params[choice])
  11. net = MyDictDense()
  12. print(net(torch.rand(3, 4), 'linear2'))
  13. 结果:
  14. tensor([[ 0.2083],
  15. [ 1.0280],
  16. [-0.3583]], grad_fn=<MmBackward>)

使用update更新参数时,会将新的参数加入到字典中。不过这种用字典的方式貌似是无序的,顺序还得通过自己手动定义forward函数来实现。
我们也完全可以使用这些自定义层来构造模型:

  1. net = nn.Sequential(
  2. MyDictDense(),
  3. MyDense(),
  4. )
  5. print(net)
  6. 结果:
  7. Sequential(
  8. (0): MyDictDense(
  9. (params): ParameterDict(
  10. (linear1): Parameter containing: [torch.FloatTensor of size 4x4]
  11. (linear2): Parameter containing: [torch.FloatTensor of size 4x1]
  12. (linear3): Parameter containing: [torch.FloatTensor of size 4x2]
  13. )
  14. )
  15. (1): MyDense(
  16. (params): ParameterList(
  17. (0): Parameter containing: [torch.FloatTensor of size 4x4]
  18. (1): Parameter containing: [torch.FloatTensor of size 4x4]
  19. (2): Parameter containing: [torch.FloatTensor of size 4x4]
  20. (3): Parameter containing: [torch.FloatTensor of size 4x1]
  21. )
  22. )
  23. )