目录
一、不带参数的层
二、带参数的层
深度学习成功背后的一个因素是神经网络的灵活性:我们可以用创造性的方式组合不同的层,从而设计出适用于各种任务的架构。例如,研究人员发明了专门用于处理图像、文本、序列数据和执行动态规划的层。有时我们会遇到或要自己发明一个现在在深度学习框架中还不存在的层。在这些情况下,必须构建自定义层。自定义层和自定义网络没有本质区别,因为层(layer)其实也是nn.Module的子类。
首先,我们构造一个没有任何参数的自定义层。下面的`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()
让我们向该层提供一些数据,验证它是否能按预期工作。
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(-4.1910e-09, grad_fn=)
以上我们知道了如何定义简单的层,下面我们继续定义具有参数的层,这些参数可以通过训练进行调整。我们可以使用内置函数来创建参数,这些函数提供一些基本的管理功能。比如管理访问、初始化、共享、保存和加载模型参数。这样做的好处之一是:我们不需要为每个自定义层编写自定义的序列化程序。
现在,让我们实现自定义版本的全连接层,该层需要两个参数,一个用于表示权重,另一个用于表示偏置项。该层需要输入参数:`in_units`和`units`,分别表示输入数和输出数。在此实现中,我们使用修正线性单元作为激活函数。
class MyLinear(nn.Module):
def __init__(self, in_units, units):
super().__init__()
self.weight = nn.Parameter(torch.randn(in_units, units)) # 也算是初始化权重的一种方式
self.bias = nn.Parameter(torch.randn(units,)) # torch.randn()返回一个符合均值为0,方差为1的正态分布(标准正态分布)中填充随机数的张量
def forward(self, X):
# torch.matmul是tensor的乘法,输入可以是高维的。当输入都是二维时,就是普通的矩阵乘法,和tensor.mm函数用法相同。当输入有多维时,把多出的一维作为batch提出来,其他部分做矩阵乘法。
linear = torch.matmul(X, self.weight.data) + self.bias.data
return F.relu(linear)
接下来,我们实例化`MyLinear`类并访问其模型参数。
linear = MyLinear(5, 3)
print(linear.weight)
print(linear.bias)
Parameter containing:
tensor([[-1.0704, -0.8003, -0.5793],
[-0.6250, 0.2337, -0.2898],
[-0.7425, -0.7948, 0.3498],
[-0.5903, 0.4115, -0.2875],
[-0.7593, 0.4104, -0.8873]], requires_grad=True)
Parameter containing:
tensor([ 1.4250, 0.1016, -0.3040], requires_grad=True)
我们可以使用自定义层直接执行前向传播计算。
linear(torch.rand(2, 5)) # torch.rand()返回一个在区间[0, 1)的均匀分布中抽取的一组随机数的张量
tensor([[0., 0., 0.],
[0., 0., 0.]])
我们还可以使用自定义层构建模型,就像使用内置的全连接层一样使用自定义层。
net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
net(torch.rand(2, 64))
tensor([[0.],
[0.]])
补充:关于torch.rand()、torch.randn()、torch.randint()、torch.randperm()用法:torch.rand()、torch.randn()、torch.randint()、torch.randperm()用法-CSDN博客文章浏览阅读10w+次,点赞100次,收藏459次。torch.rand和torch.randn有什么区别? 一个均匀分布,一个是标准正态分布。torch.rand()#rand(*size, out=None, dtype=None)t1 = torch.rand(2,3)print(t1,t1.type())randn(*size, out=None, dtype=None)和randn_like(input, dtype=None)#randn(*size, out=None, dtype=None)#randn_like(in_torch.randhttps://blog.csdn.net/leilei7407/article/details/107710852