本文基于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() # 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_featuresout_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]])

总结

  • 我们可以通过基本层类设计自定义层。这允许我们定义灵活的新层,其行为与深度学习框架中的任何现有层不同。
  • 在自定义层定义完成后,我们就可以在任意环境和网络架构中调用该自定义层。
  • 层可以有局部参数,这些参数可以通过内置函数创建。