深度学习(5)
·
一、神经网络核心组件
| 组件 | 定义与作用 |
|---|---|
| 层 | 神经网络的基本结构单元,核心功能是将输入张量通过数据变换(如卷积、线性变换)转换为输出张量 |
| 模型 | 由多个 “层” 按特定逻辑组合而成的完整网络,实现从输入数据到预测结果的端到端映射 |
| 损失函数 | 参数学习的目标函数,用于量化模型预测值(Y')与真实值(Y)的差异,训练中需最小化该函数 |
| 优化器 | 用于最小化损失函数的工具,通过调整模型参数(如权重),逐步降低损失,实现模型优化 |
二、构建神经网络的主要工具
2.1 两大工具的核心特性
-
nn.Module
- 本质:可继承的基类,继承后能自动提取模型中可学习的参数(如权重 weight、偏置 bias),无需手动管理。
- 适用场景:适用于构建含可学习参数的层,如卷积层(nn.Conv2d)、全连接层(nn.Linear)、dropout 层(nn.Dropout) 等。
- 写法示例:
self.linear1 = nn.Linear(in_dim, n_hidden_1)(实例化后调用)。
-
nn.functional
- 本质:纯函数集合,无参数自动管理功能,仅实现数据变换逻辑。
- 适用场景:适用于无参数的操作,如激活函数(nn.functional.relu)、池化层(nn.functional.max_pool2d) 等。
- 写法示例:
x = F.relu(self.bn1(x))(直接调用函数并传参)。
2.2 两大工具的核心区别
| 对比维度 | nn.Module | nn.functional |
|---|---|---|
| 参数管理 | 自动定义、管理 weight/bias | 需手动定义、传入 weight/bias |
| 模型容器适配 | 可与 nn.Sequential 等容器结合使用 | 无法与 nn.Sequential 结合使用 |
| dropout 状态转换 | 调用 model.eval () 后自动切换状态 | 需手动控制训练 / 测试状态 |
| 代码复用性 | 高(实例化后可重复调用) | 低(每次调用需重复传参) |
三、模型构建的三种方法
3.1 方法 1:直接继承 nn.Module 基类
- 核心逻辑:通过继承
nn.Module,在__init__中定义网络层,在forward中实现正向传播流程。 - 关键参数示例:输入维度
28×28=784,第一隐藏层300维,第二隐藏层100维,输出层10维(适配 10 分类任务)。 - 代码要点:
- 需调用
super(Model_Seq, self).__init__()初始化父类。 - 层定义:如
self.flatten = nn.Flatten()(展平 28×28 张量为 784 维向量)、self.linear1 = nn.Linear(784, 300)。 - 正向传播:
x = F.relu(self.bn1(self.linear1(self.flatten(x)))),最终通过F.softmax(x, dim=1)输出概率。
- 需调用
- 运行结果特点:打印模型时可清晰看到各层名称及参数(如
(linear1): Linear(in_features=784, out_features=300, bias=True))。
3.2 方法 2:使用 nn.Sequential 按层顺序构建
- 三种实现方式:
实现方式 特点 代码示例片段 可变参数 无法指定层名称,按顺序排列 nn.Sequential(nn.Flatten(), nn.Linear(784, 300), ...)add_module 方法 可通过 add_module("名称", 层)指定名称Seq_module.add_module("flatten", nn.Flatten())OrderedDict 以有序字典传入,层名称与层绑定 from collections import OrderedDict; nn.Sequential(OrderedDict([("flatten", nn.Flatten()), ...])) - 优势:代码简洁,无需手动定义
forward方法,层按顺序自动执行。
3.3 方法 3:继承 nn.Module + 模型容器
- 核心逻辑:继承
nn.Module基类,在__init__中用nn.Sequential/nn.ModuleList/nn.ModuleDict封装层,兼顾灵活性与组织性。 - 三种容器示例:
- nn.Sequential 容器:将多个层组合为一个子模块,如
self.layer1 = nn.Sequential(nn.Linear(784, 300), nn.BatchNorm1d(300)),正向传播时直接调用self.layer1(x)。 - nn.ModuleList 容器:以列表形式管理层,需在
forward中循环调用,如self.layers = nn.ModuleList([nn.Flatten(), nn.Linear(784, 300), ...]),正向传播:for layer in self.layers: x = layer(x)。 - nn.ModuleDict 容器:以字典形式管理层(键为层名称,值为层),需指定层执行顺序,如
self.layers_dict = nn.ModuleDict({"flatten": nn.Flatten(), ...}),正向传播:按列表["flatten", "linear1", ...]循环调用。
- nn.Sequential 容器:将多个层组合为一个子模块,如
四、自定义网络模块(以 ResNet 为例)
4.1 两种残差块设计
| 残差块类型 | 设计目的 | 核心结构差异 |
|---|---|---|
| RestNetBasicBlock | 输入与输出张量形状一致时,实现 “恒等映射” | 仅含 2 个 3×3 卷积层 + 批量规范化层,直接将输入与输出相加(x + output) |
| RestNetDownBlock | 输入与输出形状不一致(如通道数 / 分辨率变化),需调整维度以实现相加 | 在 2 个 3×3 卷积层基础上,增加 1×1 卷积层(extra),用于调整输入通道数与分辨率,最终相加extra_x + out |
4.2 ResNet18 网络结构
- 层结构详情:
- 初始层:
conv1(3 输入通道→64 输出通道,7×7 卷积核, stride=2,padding=3)→bn1(批量规范化)→maxpool(3×3 池化核,stride=2,padding=1)。 - 残差块组:
layer1:2 个RestNetBasicBlock(64 通道→64 通道,stride=1)。layer2:1 个RestNetDownBlock(64→128 通道,stride=[2,1])+1 个RestNetBasicBlock(128→128 通道)。layer3:1 个RestNetDownBlock(128→256 通道,stride=[2,1])+1 个RestNetBasicBlock(256→256 通道)。layer4:1 个RestNetDownBlock(256→512 通道,stride=[2,1])+1 个RestNetBasicBlock(512→512 通道)。
- 输出层:
avgpool(自适应平均池化,输出 1×1 特征图)→展平(512 维)→fc(512→10 输出通道,适配 10 分类)。
- 初始层:
五、模型训练流程
- 加载预处理数据集:导入已预处理的数据集(如 MNIST,28×28 手写数字),准备训练集与测试集。
- 定义损失函数:选择适配任务的损失函数(如分类任务用交叉熵损失,文档中未指定具体函数,但明确其为 “参数学习的目标函数”)。
- 定义优化方法:选择优化器(如 SGD、Adam),用于最小化损失函数以更新模型参数。
- 循环训练模型:迭代训练集,执行正向传播(计算预测值)、反向传播(计算梯度,
loss.backward())、参数更新(optimizer.step())。 - 循环测试或验证模型:迭代测试集 / 验证集,关闭梯度计算(
torch.no_grad()),评估模型性能(如准确率)。 - 可视化结果:通过图表(如损失曲线、准确率曲线)展示训练与测试过程的结果。
4. 关键问题
问题 1:nn.Module 与 nn.functional 在 PyTorch 构建神经网络中的核心区别是什么?
答案
二者核心区别体现在 3 个维度:
- 参数管理:nn.Module 可自动定义、管理 weight/bias 等可学习参数(如 nn.Linear 实例化后无需手动传入参数);nn.functional 需手动定义参数,且每次调用需传入(如
nn.functional.linear(x, weight, bias)),不利于代码复用。 - 模型容器适配:nn.Module 可与 nn.Sequential、nn.ModuleList 等模型容器结合使用,便于层的组织;nn.functional 无法适配 nn.Sequential,仅能单独调用。
- dropout 状态转换:使用 nn.Module 的 nn.Dropout 时,调用
model.eval()后会自动切换为测试状态(关闭 dropout);nn.functional.dropout 需手动通过training参数控制状态(如nn.functional.dropout(x, training=self.training))。
问题 2:PyTorch 中,继承 nn.Module 基类构建模型与使用 nn.Sequential 构建模型的适用场景有何差异?
答案
- 继承 nn.Module 基类的适用场景:适用于复杂网络结构(如含分支、多输入 / 多输出、自定义正向传播逻辑的网络)。例如 ResNet 的残差块需将输入与卷积输出相加,需在
forward中自定义该逻辑,无法通过 nn.Sequential 的线性流程实现;此外,需灵活调整层执行顺序或插入条件判断时,也需使用该方式。 - 使用 nn.Sequential 的适用场景:适用于层结构简单、按线性顺序执行的网络(如基础全连接网络、简单卷积网络)。例如文档中 28×28 输入→展平→线性层→批量规范化→激活函数→输出的分类网络,层按固定顺序执行,无需自定义逻辑,此时 nn.Sequential 可简化代码(无需手动定义
forward),提升开发效率。
问题 3:ResNet 中的两种残差块(RestNetBasicBlock 与 RestNetDownBlock)的设计目的及结构差异是什么?
答案
-
设计目的差异:
- RestNetBasicBlock:用于输入与输出张量形状一致(通道数、分辨率相同)的场景,实现 “恒等映射”,确保残差连接(输入直接加到输出)时维度匹配,避免梯度消失。
- RestNetDownBlock:用于输入与输出形状不一致(如通道数增加、分辨率降低)的场景,需通过额外结构调整输入维度,使残差连接可实现(输入经调整后与输出维度匹配)。
-
结构差异:
- RestNetBasicBlock:仅包含 2 个 3×3 卷积层 + 对应批量规范化层,正向传播为 “卷积 1→批量规范化→ReLU→卷积 2→批量规范化→输入 + 输出→ReLU”,无额外维度调整层。
- RestNetDownBlock:在 2 个 3×3 卷积层 + 批量规范化层的基础上,增加 1 个1×1 卷积层 + 批量规范化层(命名为
extra),正向传播时先将输入通过extra调整通道数与分辨率(extra_x = self.extra(x)),再与卷积输出相加(extra_x + out),最终经 ReLU 输出。
更多推荐


所有评论(0)