5.1 神经网络: 层和块
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 Fnet = 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)] = moduledef 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()
。以下是这段代码在该案例中的具体执行过程:
-
调用
MySequential
的构造函数- 当执行
model = MySequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 10), nn.Sigmoid())
时,会调用MySequential
类的__init__
方法,传入的args
是一个包含四个模块的元组。
- 当执行
-
初始化父类
- 执行
super().__init__()
,完成nn.Module
父类的初始化,这包括初始化_modules
这个有序字典,用于存储子模块。
- 执行
-
遍历
args
中的模块- 使用
enumerate(args)
遍历传入的模块。enumerate
会返回每个模块及其对应的索引:- 第一次迭代:
idx = 0
,module = nn.Linear(4, 8)
- 第二次迭代:
idx = 1
,module = nn.ReLU()
- 第三次迭代:
idx = 2
,module = nn.Linear(8, 10)
- 第四次迭代:
idx = 3
,module = nn.Sigmoid()
- 第一次迭代:
- 使用
-
将模块添加到
_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()
- 第一次迭代后:
- 对于每次迭代,将当前模块添加到
-
最终结果
-
_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
方法的执行过程如下:
- 调用
forward
方法
当执行 output = model(X)
时,会自动调用 MySequential
类的 forward
方法,将输入张量 X
传递进去。
- 遍历
_modules.values()
forward
方法中通过 self._modules.values()
获取按顺序排列的子模块集合:
for block in self._modules.values():
- 依次执行每个模块的前向传播
对于每个模块(block
),将当前的输入 X
传递给该模块进行前向传播:
X = block(X)
4.2.4 forward方法具体执行过程示例
假设输入张量 X
的形状为 (2, 4)
:
-
第一个模块:
block = nn.Linear(4, 8)
- 输入:
X
(形状(2, 4)
) - 进行线性变换,权重矩阵
W
的形状为(8, 4)
,偏置项b
的形状为(8,)
- 输出:经过线性变换后的张量(形状
(2, 8)
)
- 输入:
-
第二个模块:
block = nn.ReLU()
- 输入:上一步得到的张量(形状
(2, 8)
) - 应用 ReLU 激活函数,将负值变为 0,正值保持不变
- 输出:ReLU 激活后的张量(形状
(2, 8)
)
- 输入:上一步得到的张量(形状
-
第三个模块:
block = nn.Linear(8, 10)
- 输入:ReLU 激活后的张量(形状
(2, 8)
) - 进行线性变换,权重矩阵
W
的形状为(10, 8)
,偏置项b
的形状为(10,)
- 输出:经过线性变换后的张量(形状
(2, 10)
)
- 输入:ReLU 激活后的张量(形状
-
第四个模块:
block = nn.Sigmoid()
- 输入:上一步得到的张量(形状
(2, 10)
) - 应用 Sigmoid 激活函数,将每个元素压缩到
(0, 1)
的范围内 - 输出:Sigmoid 激活后的张量(形状
(2, 10)
)
- 输入:上一步得到的张量(形状
-
返回最终输出
所有模块执行完毕后,将最后得到的张量作为整个模型的输出返回:
return X
在上面的例子中,最终输出张量的形状为 (2, 10)
4.3 在前向传播中自定义过程
在前向传播函数中执行Python的控制流,如计算函数 f ( x , w ) = c ∗ w T x f(x,w)=c*w^Tx f(x,w)=c∗wTx的层, 其中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 /= 2return X.sum()
4.3.2 FixedHiddenMLP 类解析
这个类定义了一个包含特定隐藏层结构的多层感知机(MLP),它具有以下特点:
__init__
方法 :用于初始化模型的参数和层。forward
方法 :定义了模型的前向传播逻辑,包括线性变换、激活函数、矩阵乘法、控制流语句等。
- 初始化过程
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 的全连接层,这个层的权重和偏置会在训练过程中更新。
- 前向传播过程
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
的所有元素之和。
- 总结
这个 FixedHiddenMLP
类定义了一个具有特定隐藏层结构的多层感知机。它的前向传播过程包括两次全连接层的线性变换,中间插入了矩阵乘法和 ReLU 激活函数,并使用了控制流语句对输出进行归一化。这种结构展示了如何在深度学习模型中使用控制流语句和共享参数的层。
在实际使用中,这个模型的输入需要是一个二维张量,形状为 (batch_size, 20)
,其中 batch_size
是批量大小。模型的输出是一个标量,即张量 X
的所有元素之和。
相关文章:
5.1 神经网络: 层和块
1 层(Layer) 1.1 定义 层是深度学习模型中的基本构建单元,它由一组神经元组成,负责对输入数据进行特定的数学运算和变换,以提取数据的某种特征或表示。每一层可以看作是一个函数,它接收输入数据ÿ…...

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! 首先我们来看一看我…...
2025年数维杯赛题C题专家 组委会C题专家疑集锦
1、段前段后距,行间距有要求嘛 C题专家:一般是单倍行距 2、请问参考文献和附录上方也要有图示页眉吗?ai使用报告放在附录里还是附录之后? C题专家:附录 3、第三问的那个三天都在一个城市可以吗?这样我们列两份城市的清明自由行,还是说…...

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

vue访问后端接口,实现用户注册
文章目录 一、后端接口文档二、前端代码请求响应工具调用后端API接口页面函数绑定单击事件,调用/api/user.js中的函数 三、参考视频 一、后端接口文档 二、前端代码 请求响应工具 /src/utils/request.js //定制请求的实例//导入axios npm install axios import …...
[原创](现代Delphi 12指南):[macOS 64bit App开发]: 如何获取自身程序的所在的目录?
[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…...

Nginx性能调优与深度监控
目录 1更改进程数与连接数 (1)进程数 (2)连接数 2,静态缓存功能设置 (1)设置静态资源缓存 (2)验证静态缓存 3,设置连接超时 4,日志切割 …...
机器学习第四讲:无监督学习 → 给无标签积木自由组合,发现隐藏规律
机器学习第四讲:无监督学习 → 给无标签积木自由组合,发现隐藏规律 资料取自《零基础学机器学习》。 查看总目录:学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章:DeepSeek R1本地与线上满血版部署:超详细…...
2025年5月计划(linux+Gpu精粹催眠+UE独立游戏)
终于步入正轨了,4月份为了各种面试,一会学这,一会学那。 现在,有大量的业余时间了,也该干点正事了。 按照规划, 1,ue独立游戏(十分钟的视频即可) 2,linux-&…...

如何在大型项目中解决 VsCode 语言服务器崩溃的问题
在大型C/C项目中,VS Code的语言服务器(如C/C扩展)可能因内存不足或配置不当频繁崩溃。本文结合系统资源分析与实战技巧,提供一套完整的解决方案。 一、问题根源诊断 1.1 内存瓶颈分析 通过top命令查看系统资源使用情况ÿ…...
从爬虫到网络---<基石9> 在VPS上没搞好Docker项目,把他卸载干净
1.停止并删除所有正在运行的容器 docker ps -a # 查看所有容器 docker stop $(docker ps -aq) # 停止所有容器 docker rm $(docker ps -aq) # 删除所有容器如果提示没有找到容器,可以忽略这些提示。 2.删除所有镜像 docker images # 查看所有镜像 dock…...

AutoDL实现端口映射与远程连接AutoDL与Pycharm上传文件到远程服务器(李沐老师的环境)
文章目录 以上配置的作用前提AutoDL实现端口映射远程连接AutoDLPycharm上传文件到远程服务器以上配置的作用 使用AutoDL的实例:因本地没有足够强的算力,所以需要使用AutoDL AutoDL端口映射:当在实例上安装深度学习的环境,但因为实例的linux系统问题,无法图形化显示d2l中的文件…...
LeetCode 热题 100 24. 两两交换链表中的节点
LeetCode 热题 100 | 24. 两两交换链表中的节点 大家好,今天我们来解决一道经典的链表问题——两两交换链表中的节点。这道题在 LeetCode 上被标记为中等难度,要求两两交换链表中的相邻节点,并返回交换后链表的头节点。 问题描述 给你一个链…...

13.thinkphp的Session和cookie
一.Session 1. 在使用Session之前,需要开启初始化,在中间件文件middleware.php; // Session 初始化 \think\middleware\SessionInit::class 2. TP6.0不支持原生$_SESSION的获取方式,也不支持session_开头的函数&…...
好用的播放器推荐
以下是一些好用的播放器推荐,按照不同平台和使用场景分类: 电脑端 VLC Media Player 特点:开源、跨平台,支持几乎所有的音视频格式,无需额外安装解码器。具备强大的功能,如播放列表管理、视频和音频滤镜、…...

多线程获取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");可能有些乱码,不…...
深入浅出 JDBC 与数据库连接池
在Java开发中,与数据库进行交互是几乎每个项目都离不开的功能。JDBC(Java DataBase Connectivity)作为Java操作数据库的标准规范,为开发者提供了底层的数据库访问支持。而数据库连接池则是提高数据库操作效率和性能的重要工具。本…...

16前端项目----交易页
交易 交易页Trade修改默认地址商品清单reduce计算总数和总价应用 统一引入接口提交订单 交易页Trade 在computed中mapState映射出addressInfo和orderInfo,然后v-for渲染到组件当中 修改默认地址 <div class"address clearFix" v-for"address in …...
Python时间模块
time 和 datetime 是 Python 中处理时间的两个重要模块,它们提供了不同的功能来处理时间相关的操作。 time模块 time 模块主要提供与系统时间相关的基础功能,侧重于时间戳和简单的时间格式处理。 time.time():返回当前时间的时间戳…...

2003-2020年高铁线路信息数据
2003-2020年高铁线路信息数据 1、时间:2003-2020年 2、来源:Chinese High-speed Rail and Airline Database,CRAD 3、指标:高铁线路名称、起点名、终点名、开通时间、线路长度(km)、设计速度(km/h)、沿途主要车站 …...
mac u盘重装mac10.15Catalina系统
我的电脑提mac2017的air 重装过程 (文件夹中间有空格时为 Install\ macOS\ Catalina 才行) (有需要的,最好做一下备份,有些东西可以及时找到配置和文件之类的, u盘制作是在mac电脑上操作的) 一、先下载系统镜像文件或自行到官方…...

MySQL COUNT(*) 查询优化详解!
目录 前言1. COUNT(*) 为什么慢?—— InnoDB 的“计数烦恼” 🤔2. MySQL 执行 COUNT(*) 的方式 (InnoDB)3. COUNT(*) 优化策略:快!准!狠!策略一:利用索引优化带 WHERE 子句的 COUNT(*) (最常见且…...

nginx配置协议
1. 7层协议 OSI(Open System Interconnection)是一个开放性的通行系统互连参考模型,他是一个定义的非常好的协议规范,共包含七层协议。直接上图,这样更直观些: 1.1 协议配置 1.1.1 7层配置 这里我们举例…...
自动化创业机器人:现状、挑战与Y Combinator的启示
自动化创业机器人:现状、挑战与Y Combinator的启示 前言 AI驱动的自动化创业机器人,正逐步从科幻走向现实。我们设想的未来是:商业分析、PRD、系统设计、代码实现、测试、运营,全部可以在monorepo中由AI和人类Co-founder协作完成…...
Activity动态切换Fragment
Activity 动态切换 Fragment 是 Android 开发中常见的需求,用于构建灵活的用户界面。 以下是实现 Activity 动态切换 Fragment 的几种方法,以及一些最佳实践: 1. 使用 FragmentManager 和 FragmentTransaction (推荐) 这是最常用和推荐的方…...

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

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

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