5.1 神经网络: 层和块

news2025/5/12 0:04:11

1 层(Layer)

1.1 定义

层是深度学习模型中的基本构建单元,它由一组神经元组成,负责对输入数据进行特定的数学运算和变换,以提取数据的某种特征或表示。每一层可以看作是一个函数,它接收输入数据,并通过该层的权重和偏置等参数以及激活函数等操作,产生输出。

1.2 作用

不同的层可以实现不同的功能,比如卷积层可以用于提取图像的空间特征,池化层可以用于下采样以减少数据的维度和计算量,全连接层可以用于对全局特征进行综合和分类等。通过堆叠多层,模型可以逐步学习数据的复杂模式和层次化特征,从而对输入数据进行更深入的理解和处理,以完成如分类、回归、生成等任务。

2 块(Block)

2.1 定义

块是比层更高层次的构建单元,它通常由多个层按照某种特定的方式组合而成,形成一个相对独立的功能模块。块可以看作是一个封装好的子网络,具有一致的输入输出接口,可以在不同的位置重复使用。
块(block)可以描述单个层、由多个层组成的组件或整个模型本身
块由类(class)表示。 它的任何子类都必须定义一个将其输入转换为输出的前向传播函数, 并且必须存储任何必需的参数(有些块不需要任何参数)。
块必须具有反向传播函数

2.2 作用

块的设计主要是为了提高模型的性能和效率,以及增强模型的可扩展性和可重用性。例如,ResBlock(残差块)通过引入残差连接,解决了深层网络训练时梯度消失和梯度爆炸的问题,使得网络可以更有效地训练;Inception Block(Inception块)通过多尺度卷积操作,能够同时捕捉不同尺度的特征,提高模型对特征的表达能力。还有像Transformer中的Encoder Block和Decoder Block,它们分别负责编码和解码序列信息,通过堆叠多个这样的块可以构建强大的序列处理模型。

3 两者的区别与联系

区别

(1)粒度不同
层是模型的微观构成部分,是最基本的计算单元;块则是由多个层组成的宏观模块,是对多个层的进一步抽象和封装。
(2)功能侧重不同
层主要关注于实现具体的数学运算和特征提取;块更侧重于组合多个层以实现某种特定的结构或功能,解决某些特定的问题或满足特定的性能要求。

联系

(1)块是由层构成的,多个层按照一定的规则组合在一起就形成了一个块。
(2)层和块在构建深度学习模型时是相互配合的,层是块的基础,块则是构建更复杂模型结构的重要单元。通过对不同层和块的组合和堆叠,可以构建出各种各样功能强大的深度学习模型,以应对不同的任务和数据特点。

4 多层感知机代码

MLP: 包含256个隐藏单元和ReLU激活函数的全连接隐藏层, 具有10个隐藏单元且不带激活函数的全连接输出层

import torch
from torch import nn
from torch.nn import functional as F

net = nn.Sequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))

X = torch.rand(2, 20)
net(X)

4.1 自定义块

class MLP(nn.Module):
    # 用模型参数声明层。这里,我们声明两个全连接的层
    def __init__(self):
        # 调用MLP的父类Module的构造函数来执行必要的初始化。
        # 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)
        super().__init__()
        self.hidden = nn.Linear(20, 256)  # 隐藏层
        self.out = nn.Linear(256, 10)  # 输出层

    # 定义模型的前向传播,即如何根据输入X返回所需的模型输出
    def forward(self, X):
        # 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。
        return self.out(F.relu(self.hidden(X)))
net = MLP()
net(X)

4.2 顺序块

4.2.1 代码示例

import torch
import torch.nn as nn

# 定义 MySequential 类
class MySequential(nn.Module):
    def __init__(self, *args):
        super().__init__()
        for idx, module in enumerate(args):
            self._modules[str(idx)] = module

    def forward(self, X):
        for block in self._modules.values():
            X = block(X)
        return X

定义一个简单的神经网络模型,使用 MySequential 组合多个层

model = MySequential(
    nn.Linear(4, 8),       # 第一层:输入维度4,输出维度8的全连接层
    nn.ReLU(),             # 第二层:ReLU 激活函数
    nn.Linear(8, 10),      # 第三层:输入维度8,输出维度10的全连接层
    nn.Sigmoid()           # 第四层:Sigmoid 激活函数
)

# 输入张量,假设 batch_size 为 2,输入特征维度为4
X = torch.randn(2, 4)
print("输入 X 的形状:", X.shape)

# 前向传播
output = model(X)
print("输出 output 的形状:", output.shape)

4.2.2 MySequential调用过程

在上述案例中,for idx, module in enumerate(args): self._modules[str(idx)] = module 这段代码在实例化 MySequential 模型时执行,具体来说,当创建 model 实例时,传入的 args 包含四个模块:nn.Linear(4, 8)nn.ReLU()nn.Linear(8, 10)nn.Sigmoid()。以下是这段代码在该案例中的具体执行过程:

  1. 调用 MySequential 的构造函数

    • 当执行 model = MySequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 10), nn.Sigmoid()) 时,会调用 MySequential 类的 __init__ 方法,传入的 args 是一个包含四个模块的元组。
  2. 初始化父类

    • 执行 super().__init__(),完成 nn.Module 父类的初始化,这包括初始化 _modules 这个有序字典,用于存储子模块。
  3. 遍历 args 中的模块

    • 使用 enumerate(args) 遍历传入的模块。enumerate 会返回每个模块及其对应的索引:
      • 第一次迭代:idx = 0module = nn.Linear(4, 8)
      • 第二次迭代:idx = 1module = nn.ReLU()
      • 第三次迭代:idx = 2module = nn.Linear(8, 10)
      • 第四次迭代:idx = 3module = nn.Sigmoid()
  4. 将模块添加到 _modules

    • 对于每次迭代,将当前模块添加到 _modules 有序字典中,键为索引的字符串形式,值为对应的模块:
      • 第一次迭代后:self._modules["0"] = nn.Linear(4, 8)
      • 第二次迭代后:self._modules["1"] = nn.ReLU()
      • 第三次迭代后:self._modules["2"] = nn.Linear(8, 10)
      • 第四次迭代后:self._modules["3"] = nn.Sigmoid()
  5. 最终结果

  • _modules 有序字典中按顺序存储了传入的四个模块,键分别为 "0""1""2""3",对应的值分别是 nn.Linear(4, 8)nn.ReLU()nn.Linear(8, 10)nn.Sigmoid()

  • 这些模块被正确地注册为 MySequential 实例的子模块,这样在后续的前向传播过程中,可以通过 _modules.values() 按顺序获取并执行这些模块,确保输入数据依次经过每个模块的处理。

这段代码在实例化 MySequential 时,将传入的模块按照顺序添加到 _modules 中,为后续的前向传播做好准备。

4.2.3 forward方法调用过程

在上面的例子中,forward 方法的执行过程如下:

  1. 调用 forward 方法

当执行 output = model(X) 时,会自动调用 MySequential 类的 forward 方法,将输入张量 X 传递进去。

  1. 遍历 _modules.values()

forward 方法中通过 self._modules.values() 获取按顺序排列的子模块集合:

for block in self._modules.values():
  1. 依次执行每个模块的前向传播

对于每个模块(block),将当前的输入 X 传递给该模块进行前向传播:

X = block(X)

4.2.4 forward方法具体执行过程示例

假设输入张量 X 的形状为 (2, 4)

  1. 第一个模块:block = nn.Linear(4, 8)

    • 输入:X(形状 (2, 4)
    • 进行线性变换,权重矩阵 W 的形状为 (8, 4),偏置项 b 的形状为 (8,)
    • 输出:经过线性变换后的张量(形状 (2, 8)
  2. 第二个模块:block = nn.ReLU()

    • 输入:上一步得到的张量(形状 (2, 8)
    • 应用 ReLU 激活函数,将负值变为 0,正值保持不变
    • 输出:ReLU 激活后的张量(形状 (2, 8)
  3. 第三个模块:block = nn.Linear(8, 10)

    • 输入:ReLU 激活后的张量(形状 (2, 8)
    • 进行线性变换,权重矩阵 W 的形状为 (10, 8),偏置项 b 的形状为 (10,)
    • 输出:经过线性变换后的张量(形状 (2, 10)
  4. 第四个模块:block = nn.Sigmoid()

    • 输入:上一步得到的张量(形状 (2, 10)
    • 应用 Sigmoid 激活函数,将每个元素压缩到 (0, 1) 的范围内
    • 输出:Sigmoid 激活后的张量(形状 (2, 10)
  5. 返回最终输出
    所有模块执行完毕后,将最后得到的张量作为整个模型的输出返回:

return X

在上面的例子中,最终输出张量的形状为 (2, 10)

4.3 在前向传播中自定义过程

在前向传播函数中执行Python的控制流,如计算函数 f ( x , w ) = c ∗ w T x f(x,w)=c*w^Tx f(x,w)=cwTx的层, 其中x是输入, w是参数,c是某个在优化过程中没有更新的指定常量

4.3.1 FixedHiddenMLP类示例

class FixedHiddenMLP(nn.Module):
    def __init__(self):
        super().__init__()
        # 不计算梯度的随机权重参数。因此其在训练期间保持不变
        self.rand_weight = torch.rand((20, 20), requires_grad=False)
        self.linear = nn.Linear(20, 20)

    def forward(self, X):
        X = self.linear(X)
        # 使用创建的常量参数以及relu和mm函数
        X = F.relu(torch.mm(X, self.rand_weight) + 1)
        # 复用全连接层。这相当于两个全连接层共享参数
        X = self.linear(X)
        # 控制流
        while X.abs().sum() > 1:
            X /= 2
        return X.sum()

4.3.2 FixedHiddenMLP 类解析

这个类定义了一个包含特定隐藏层结构的多层感知机(MLP),它具有以下特点:

  • __init__ 方法 :用于初始化模型的参数和层。
  • forward 方法 :定义了模型的前向传播逻辑,包括线性变换、激活函数、矩阵乘法、控制流语句等。
  1. 初始化过程
 self.rand_weight = torch.rand((20, 20), requires_grad=False)
  • 随机权重参数 self.rand_weight :创建一个形状为 (20, 20) 的随机权重矩阵,并设置 requires_grad=False,表示这个参数在训练过程中不计算梯度,即保持不变。
   self.linear = nn.Linear(20, 20)
  • 全连接层 self.linear :定义一个输入和输出维度都为 20 的全连接层,这个层的权重和偏置会在训练过程中更新。
  1. 前向传播过程
  X = self.linear(X)
  • 第一步:全连接层 :将输入 X 传递给全连接层 self.linear,进行线性变换,输出结果的形状与输入相同,为 (batch_size, 20)
  X = F.relu(torch.mm(X, self.rand_weight) + 1)
  • 第二步:矩阵乘法和激活函数 :将上一步的输出与随机权重矩阵 self.rand_weight 进行矩阵乘法操作,然后加上 1,再应用 ReLU 激活函数。这一步的计算可以表示为 X = F.relu(torch.mm(X, self.rand_weight) + 1)。矩阵乘法操作将输入特征与随机权重矩阵相乘,加上 1 后应用 ReLU 激活函数,引入非线性。
   X = self.linear(X)
  • 第三步:复用全连接层 :再次将上一步的输出传递给全连接层 self.linear,进行线性变换。这相当于两个全连接层共享相同的参数。
while X.abs().sum() > 1:
            X /= 2
  • 第四步:控制流语句 :使用一个 while 循环检查张量 X 的绝对值之和是否大于 1。如果是,则将 X 除以 2,直到其绝对值之和小于或等于 1。这个控制流语句用于对输出进行归一化,确保其值不会过大。
   return X.sum()
  • 第五步:返回结果 :最后返回张量 X 的所有元素之和。
  1. 总结

这个 FixedHiddenMLP 类定义了一个具有特定隐藏层结构的多层感知机。它的前向传播过程包括两次全连接层的线性变换,中间插入了矩阵乘法和 ReLU 激活函数,并使用了控制流语句对输出进行归一化。这种结构展示了如何在深度学习模型中使用控制流语句和共享参数的层。

在实际使用中,这个模型的输入需要是一个二维张量,形状为 (batch_size, 20),其中 batch_size 是批量大小。模型的输出是一个标量,即张量 X 的所有元素之和。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2373525.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

20250510解决NanoPi NEO core开发板在Ubuntu core22.04.3系统下适配移远的4G模块EC200A-CN的问题

1、h3-eflasher-friendlycore-jammy-4.14-armhf-20250402.img.gz 在WIN10下使用7-ZIP解压缩/ubuntu20.04下使用tar 2、Win32DiskImager.exe 写如32GB的TF卡。【以管理员身份运行】 3、TF卡如果已经做过会有3个磁盘分区,可以使用SD Card Formatter/SDCardFormatterv5…

Linux系统之----模拟实现shell

在前面一个阶段的学习中,我们已经学习了环境变量、进程控制等等一系列知识,也许有人会问,学这个东西有啥用?那么,今天我就和大家一起综合运用一下这些知识,模拟实现下shell! 首先我们来看一看我…

TCP黏包解决方法

1. 问题描述 TCP客户端每100ms发送一次数据,每次为16006字节的数据长度。由于TCP传输数据时,为了达到最佳传输效能,数据包的最大长度需要由MSS限定(MSS就是TCP数据包每次能够传输的最大数据分段),超过这个长度会进行自动拆包。也就是说虽然客户端一次发送16006字节数据,…

vue访问后端接口,实现用户注册

文章目录 一、后端接口文档二、前端代码请求响应工具调用后端API接口页面函数绑定单击事件,调用/api/user.js中的函数 三、参考视频 一、后端接口文档 二、前端代码 请求响应工具 /src/utils/request.js //定制请求的实例//导入axios npm install axios import …

Nginx性能调优与深度监控

目录 1更改进程数与连接数 (1)进程数 (2)连接数 2,静态缓存功能设置 (1)设置静态资源缓存 (2)验证静态缓存 3,设置连接超时 4,日志切割 …

如何在大型项目中解决 VsCode 语言服务器崩溃的问题

在大型C/C项目中,VS Code的语言服务器(如C/C扩展)可能因内存不足或配置不当频繁崩溃。本文结合系统资源分析与实战技巧,提供一套完整的解决方案。 一、问题根源诊断 1.1 内存瓶颈分析 通过top命令查看系统资源使用情况&#xff…

AutoDL实现端口映射与远程连接AutoDL与Pycharm上传文件到远程服务器(李沐老师的环境)

文章目录 以上配置的作用前提AutoDL实现端口映射远程连接AutoDLPycharm上传文件到远程服务器以上配置的作用 使用AutoDL的实例:因本地没有足够强的算力,所以需要使用AutoDL AutoDL端口映射:当在实例上安装深度学习的环境,但因为实例的linux系统问题,无法图形化显示d2l中的文件…

13.thinkphp的Session和cookie

一.Session 1. 在使用Session之前,需要开启初始化,在中间件文件middleware.php; // Session 初始化 \think\middleware\SessionInit::class 2. TP6.0不支持原生$_SESSION的获取方式,也不支持session_开头的函数&…

多线程获取VI模块的YUV数据

一.RV1126 VI模块采集摄像头YUV数据的流程 step1:VI模块初始化 step2:启动VI模块工作 step3:开启多线程采集VI数据并保存 1.1初始化VI模块: VI模块的初始化实际上就是对VI_CHN_ATTR_S的参数进行设置、然后调用RK_MPI_VI_SetC…

[ctfshow web入门] web68

信息收集 highlight_file被禁用了,使用cinclude("php://filter/convert.base64-encode/resourceindex.php");读取index.php,使用cinclude("php://filter/convert.iconv.utf8.utf16/resourceindex.php");可能有些乱码,不…

16前端项目----交易页

交易 交易页Trade修改默认地址商品清单reduce计算总数和总价应用 统一引入接口提交订单 交易页Trade 在computed中mapState映射出addressInfo和orderInfo&#xff0c;然后v-for渲染到组件当中 修改默认地址 <div class"address clearFix" v-for"address in …

2003-2020年高铁线路信息数据

2003-2020年高铁线路信息数据 1、时间&#xff1a;2003-2020年 2、来源&#xff1a;Chinese High-speed Rail and Airline Database&#xff0c;CRAD 3、指标&#xff1a;高铁线路名称、起点名、终点名、开通时间、线路长度(km)、设计速度(km/h&#xff09;、沿途主要车站 …

MySQL COUNT(*) 查询优化详解!

目录 前言1. COUNT(*) 为什么慢&#xff1f;—— InnoDB 的“计数烦恼” &#x1f914;2. MySQL 执行 COUNT(*) 的方式 (InnoDB)3. COUNT(*) 优化策略&#xff1a;快&#xff01;准&#xff01;狠&#xff01;策略一&#xff1a;利用索引优化带 WHERE 子句的 COUNT(*) (最常见且…

nginx配置协议

1. 7层协议 OSI&#xff08;Open System Interconnection&#xff09;是一个开放性的通行系统互连参考模型&#xff0c;他是一个定义的非常好的协议规范&#xff0c;共包含七层协议。直接上图&#xff0c;这样更直观些&#xff1a; 1.1 协议配置 1.1.1 7层配置 这里我们举例…

UE5 PCG学习笔记

https://www.bilibili.com/video/BV1onUdY2Ei3/?spm_id_from333.337.search-card.all.click&vd_source707ec8983cc32e6e065d5496a7f79ee6 一、安装PCG 插件里选择以下进行安装 移动目录后&#xff0c;可以使用 Update Redirector References&#xff0c;更新下&#xff0…

《用MATLAB玩转游戏开发》打砖块:向量反射与实时物理模拟MATLAB教程

《用MATLAB玩转游戏开发&#xff1a;从零开始打造你的数字乐园》基础篇&#xff08;2D图形交互&#xff09;-《打砖块&#xff1a;向量反射与实时物理模拟》MATLAB教程 &#x1f3ae; 文章目录 《用MATLAB玩转游戏开发&#xff1a;从零开始打造你的数字乐园》基础篇&#xff08…

vue配置代理解决前端跨域的问题

文章目录 一、概述二、报错现象三、通过配置代理来解决修改request.js中的baseURL为/api在vite.config.js中增加代理配置 四、参考资料 一、概述 跨域是指由于浏览器的同源策略限制&#xff0c;向不同源(不同协议、不同域名、不同端口)发送ajax请求会失败 二、报错现象 三、…

java+vert.x实现内网穿透jrp-nat

用java vert.x开发一个内网穿透工具 内网穿透概述技术原理常见内网穿透工具用java vert.x开发内网穿透工具 jrp-nat为什么用java开发内网穿透工具&#xff1f;jrp-nat功能实现图解jrp-nat内网穿透工具介绍jrp-nat内网穿透工具特点jrp-nat软件架构jrp-nat安装教程jrp-nat程序下载…

【程序员AI入门:应用开发】8.LangChain的核心抽象

一、 LangChain 的三大核心抽象 1. ChatModel&#xff08;聊天模型&#xff09; 核心作用&#xff1a;与大模型&#xff08;如 GPT-4、Claude&#xff09;交互的入口&#xff0c;负责处理输入并生成输出。关键功能&#xff1a; 支持同步调用&#xff08;model.invoke&#xf…

每天五分钟机器学习:KTT条件

本文重点 在前面的课程中,我们学习了拉格朗日乘数法求解等式约束下函数极值,如果约束不是等式而是不等式呢?此时就需要KTT条件出手了,KTT条件是拉格朗日乘数法的推广。KTT条件不仅统一了等式约束与不等式约束的优化问题求解范式,KTT条件给出了这类问题取得极值的一阶必要…