在构建卷积神经网络(CNN)模型时,灵活获取网络中间层的输出至关重要。无论是用于特征可视化、模型诊断,还是构建复杂的前向传播逻辑,掌握不同层级(卷积层、全连接层)的输出方法都是基本功。本文将以一个经典的图像分类场景为例,使用 PyTorch 框架,手把手演示两种常见的输出模式。
核心场景与输入数据
我们假设处理的是单张 28x28 像素的RGB图像(例如MNIST数据集的彩色化版本),批次大小为1。首先创建对应的随机输入张量。
import torch
import torch.nn as nn
# 定义输入张量x,模拟一个大小为 [batch_size, 通道, 高, 宽] 的图像
x = torch.rand(size=(1, 3, 28, 28))
方法一:获取多个卷积层的连续输出
在有些架构中(如特征金字塔网络),我们需要获取每一层 卷积神经网络 处理后的特征图。下面定义三个连续的卷积层,并依次进行前向传播。
# 定义第一个卷积层conv1
conv1 = nn.Conv2d(
in_channels=3,
out_channels=16,
kernel_size=3,
stride=2,
padding=1
)
# 定义第二个卷积层conv2
conv2 = nn.Conv2d(
in_channels=16,
out_channels=32,
kernel_size=3,
stride=2,
padding=1
)
# 定义第三个卷积层conv3
conv3 = nn.Conv2d(
in_channels=32,
out_channels=64,
kernel_size=3,
stride=2,
padding=1
)
# 执行前向传播,每层的输出作为下一层的输入
x = conv1(x)
x = conv2(x)
x = conv3(x)
# 最终输出为第三个卷积层的特征图
output = x
print(f‘多个卷积层连续输出的形状:{output.shape}‘)
输出结果:
torch.Size([1, 64, 4, 4])
结果表示我们得到了一个包含64个通道、空间尺寸为4x4的特征图。
方法二:卷积层与全连接层组合输出
在标准的分类网络中,卷积层负责提取空间特征,而 全连接层 则负责将这些特征整合并映射到类别空间。这里我们在两个卷积层后接入三个全连接层。
# 重新初始化输入
x = torch.rand(size=(1, 3, 28, 28))
# 使用前面定义的conv1和conv2
# 定义第一个全连接层fc1(注意计算正确的输入维度)
fc1 = nn.Linear(in_features=32 * 7 * 7, out_features=64)
# 定义第二个全连接层fc2
fc2 = nn.Linear(in_features=64, out_features=32)
# 定义第三个全连接层fc3(假设是10分类任务)
fc3 = nn.Linear(in_features=32, out_features=10)
# 前向传播流程
x = conv1(x) # 卷积层1
x = conv2(x) # 卷积层2
# 将二维特征图展平为一维向量,以适应全连接层的输入
x = torch.flatten(x, start_dim=1)
x = fc1(x) # 全连接层1
x = fc2(x) # 全连接层2
x = fc3(x) # 全连接层3(输出层)
output = x
print(f‘卷积层+全连接层组合输出的形状:{output.shape}‘)
输出结果:
torch.Size([1, 10])
结果表示网络输出了10个 logits 值,对应10个类别的预测分数。
关键点与实践意义
- 维度变换:卷积层输出是四维张量
[N, C, H, W],在输入全连接层前,必须通过 flatten 操作将其转换为二维张量 [N, -1]。start_dim=1 表示从通道维度开始展平,保留批次维度。
- 特征传递:在第一种方法中,我们只关心卷积特征的逐层变换;第二种方法则是经典的“特征提取器(卷积)+分类器(全连接)”范式。
- 参数计算:定义
nn.Linear 时,in_features 必须与展平后特征向量的长度严格一致,否则会引发运行时错误。这是搭建自定义网络时最常见的错误之一。
掌握这两种基础而重要的输出模式,是设计和调试更复杂深度学习模型(如多任务学习、注意力机制模型)的基石。在实际项目中,你可以将这些层封装到 nn.Module 子类中,构建结构清晰、可复用的网络模块。