当前位置: 首页 > news >正文

【深度学习】自定义层

自定义层

深度学习成功背后的一个因素是神经网络的灵活性:
我们可以用创造性的方式组合不同的层,从而设计出适用于各种任务的架构。例如,研究人员发明了专门用于处理图像、文本、序列数据和执行动态规划的层。
有时我们会遇到或要自己发明一个现在在深度学习框架中还不存在的层。在这些情况下,必须构建自定义层。本节将展示如何构建自定义层。

不带参数的层

首先,我们(构造一个没有任何参数的自定义层)。
回忆一下块的介绍,这应该看起来很眼熟。

下面的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_unitsunits,分别表示输入数和输出数。

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)

我们可以[使用自定义层直接执行前向传播计算]。

linear(torch.rand(2, 5))
tensor([[0., 0., 0.],
        [0., 0., 0.]])

我们还可以(使用自定义层构建模型),就像使用内置的全连接层一样使用自定义层。

net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
net(torch.rand(2, 64))
tensor([[0.],
        [0.]])

相关文章:

  • std::ranges::views::counted
  • SCT2632-3A持续输出电流,输入电压范围:4.2V-60V,降压DCDC转换器
  • 神经网络机器学习中说的过拟合是什么意思
  • 【论文笔记】Best Practices and Lessons Learned on Synthetic Data for Language Models
  • 编译OpenSSL
  • JVM内存结构笔记04-字符串常量池
  • 神经网络完成训练的详细过程
  • linux - ubuntu 使用时一些小问题整理 --- 持续更新
  • 【音视频】H265-NALU-AVpacket-PS-RTP(GB28181)
  • 业务数据分析极简通用方法论
  • 3.12-3 html
  • VSTO(C#)Excel开发5:调整表格到一页
  • K8S学习之基础二十七:k8s中daemonset控制器
  • @RestControllerAdvice注解
  • Adaptive AUTOSAR UCM模块——快速入门
  • 安卓Compose中accompanist库使用详解
  • 【蓝桥杯python研究生组备赛】003 贪心
  • Python Reverse Engineering的中文意思是什么?概念分析、工具与技术、实施步骤、扩展阅读?
  • 部署达梦数据库到服务器
  • MySQL:SQL优化实际案例解析(持续更新)
  • 安徽凤阳通报鼓楼瓦片脱落:去年3月维修竣工,已成立调查组
  • 张宇祥已任上海闵行区委常委、副区长
  • 深一度|上座率连创纪录撬动文旅,中超可否复制大连模式
  • 美国贸易政策|特朗普模式:你想做交易吗?
  • 海外考古大家访谈|冈村秀典:礼制的形成与早期中国
  • 贞丰古城:新垣旧梦间的商脉与烟火