本文基于d2l项目内容整理,介绍深度学习中参数管理的核心概念和实用技巧,包括参数访问、初始化和共享等重要主题。
深度学习框架支持自定义适合任意任务的层,有的专门用于图像、文本或序列数据的处理,有的可以执行动态规划等。
1. 不带参数的层
与块类的实现类似,继承nn.Module
类并实现前向传播的forward()
方法即可定义一个新的层。
例如,定义一个层,读取输入并与均值相减后输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import torch from torch import nn
class CenteredLayer(nn.Module): def __init__(self): super().__init__()
@staticmethod def forward(data): return data - data.mean()
if __name__ == '__main__': layer = CenteredLayer() print(layer(torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32)))
|
输出结果:
1
| tensor([-2., -1., 0., 1., 2.])
|
2. 带参数的层
自定义的层可能需要记录在训练过程中不断更新的参数(如权重和偏置),手动管理参数的过程很繁琐。现代深度学习框架内置的参数管理 API 可以很方便地管理访问、初始化、共享、保存和加载参数。
在 PyTorch 中,nn.Parameter()
用于将定义的张量自动添加到Module.parameters
参数迭代器,实现对参数的注册。使参数自动参与梯度计算requires_grad=True
与反向传播,保证层间的参数共享。
例如,定义一个全连接层,用weight
参数表示权重,用bias
参数表示偏置。使用 ReLU 函数
激活输出值。同时,可为层指定输出形状的形参in_features
和out_features
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import torch from torch import nn from torch.nn import functional as F
class LinearReLU(nn.Module): def __init__(self, in_features, out_features): super().__init__() self.weight = nn.Parameter(torch.randn(in_features, out_features)) self.bias = nn.Parameter(torch.randn(out_features))
def forward(self, x): return F.relu(x @ self.weight.data + self.bias.data)
if __name__ == '__main__': linear = LinearReLU(5, 3) print(f'{linear.weight = }') print(f'{linear(torch.rand(2, 5)) = }')
|
输出结果:
1 2 3 4 5 6 7 8
| linear.weight = Parameter containing: tensor([[ 7.3203e-01, -5.7376e-01, 5.4769e-01], [-9.2961e-02, -5.1345e-01, -2.9226e+00], [-1.6591e-03, 1.1632e+00, 1.5749e+00], [-1.7442e-01, 4.9862e-01, 1.7185e+00], [ 8.3327e-01, -1.0872e+00, -3.3840e-02]], requires_grad=True) linear(torch.rand(2, 5)) = tensor([[2.0723, 0.4304, 0.0000], [1.7495, 1.1964, 0.0000]])
|
总结
- 我们可以通过基本层类设计自定义层。这允许我们定义灵活的新层,其行为与深度学习框架中的任何现有层不同。
- 在自定义层定义完成后,我们就可以在任意环境和网络架构中调用该自定义层。
- 层可以有局部参数,这些参数可以通过内置函数创建。