自定义层
深度学习成功背后的一个因素是神经网络的灵活性:
我们可以用创造性的方式组合不同的层,从而筹划出适用于各种任务的架构。例如,研究人员发明了专门用于处理图像、文本、序列数据和执办法态规划的层。
有时我们会碰到或要自己发明一个现在在深度学习框架中还不存在的层。在这些情况下,必须构建自定义层。本节将展示如何构建自定义层。
不带参数的层
起首,我们(构造一个没有任何参数的自定义层)。
回想一下块的介绍,这应该看起来很眼熟。
下面的CenteredLayer类要从其输入中减去均值。要构建它,我们只需继续底子层类并实现前向传播功能。
- import torch
- import torch.nn.functional as F
- from torch import nn
- class CenteredLayer(nn.Module):
- def __init__(self):
- super().__init__()
- def forward(self, X):
- return X - X.mean() #X.mean()计算输入张量 X 的均值
复制代码 让我们向该层提供一些数据,验证它是否能按预期工作。
- layer = CenteredLayer()
- layer(torch.FloatTensor([1, 2, 3, 4, 5]))
复制代码- tensor([-2., -1., 0., 1., 2.])
复制代码 现在,我们可以[将层作为组件合并到更复杂的模型中]。
- net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())
复制代码 作为额外的健全性检查,我们可以在向该网络发送随机数据后,检查均值是否为0。由于我们处理的是浮点数,因为存储精度的原因,我们仍然大概会看到一个非常小的非零数。
- Y = net(torch.rand(4, 8))
- Y.mean()
复制代码- tensor(3.2596e-09, grad_fn=<MeanBackward0>)
复制代码 [带参数的层]
以上我们知道了如何定义简单的层,下面我们继续定义具有参数的层,这些参数可以通过练习进行调解。
我们可以利用内置函数来创建参数,这些函数提供一些基本的管理功能。比如管理访问、初始化、共享、保存和加载模型参数。
这样做的好处之一是:我们不需要为每个自定义层编写自定义的序列化程序。
现在,让我们实现自定义版本的全连接层。
回想一下,该层需要两个参数,一个用于表示权重,另一个用于表示偏置项。在此实现中,我们利用修正线性单位作为激活函数。该层需要输入参数:in_units和units,分别表示输入数和输出数。
- class MyLinear(nn.Module):
- """
- 自定义线性层,继承自 nn.Module。
- 参数:
- in_units (int): 输入特征的维度。
- units (int): 输出特征的维度。
- """
- def __init__(self, in_units, units):
- # 调用父类 nn.Module 的构造函数
- super().__init__()
- # 定义可学习的权重参数,形状为 (in_units, units)
- self.weight = nn.Parameter(torch.randn(in_units, units))
- # 定义可学习的偏置参数,形状为 (units,)
- self.bias = nn.Parameter(torch.randn(units,))
- def forward(self, X):
- """
- 前向传播方法。
- 参数:
- X (torch.Tensor): 输入张量。
- 返回:
- torch.Tensor: 经过线性变换和 ReLU 激活后的输出张量。
- """
- # 计算线性变换,即输入 X 与权重矩阵的矩阵乘法,再加上偏置
- linear = torch.matmul(X, self.weight.data) + self.bias.data
- # 对线性变换的结果应用 ReLU 激活函数
- return F.relu(linear)
复制代码 nn.Parameter 是 torch.Tensor 的子类,当你把一个张量封装进 nn.Parameter 时,这个张量就会主动成为 nn.Module 类的可练习参数。在模型练习过程中,这些参数会被优化器更新。
接下来,我们实例化MyLinear类并访问其模型参数。
- linear = MyLinear(5, 3)
- linear.weight
复制代码- Parameter containing:
- tensor([[ 0.1775, -1.4539, 0.3972],
- [-0.1339, 0.5273, 1.3041],
- [-0.3327, -0.2337, -0.6334],
- [ 1.2076, -0.3937, 0.6851],
- [-0.4716, 0.0894, -0.9195]], requires_grad=True)
复制代码 我们可以[利用自定义层直接实行前向传播计算]。
- tensor([[0., 0., 0.],
- [0., 0., 0.]])
复制代码 我们还可以(利用自定义层构建模型),就像利用内置的全连接层一样利用自定义层。
- net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
- net(torch.rand(2, 64))
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |