问题与目标
将 32×32 图片展平后接全连接层,会丢掉像素的二维邻接结构,也会产生大量参数。卷积网络用小型卷积核在整张图上共享参数,逐步提取局部纹理、边缘和更高层组合。
本篇用人工张量跑通卷积、池化和全连接分类头。输入形状是 (N, C, H, W),输出是三类 logits,重点核对每个阶段的特征图形状。

同一组卷积核参数作用于所有空间位置,局部区域的加权响应组成新的特征图。
核心概念
卷积核在空间位置之间共享
二维卷积核在图像上滑动,每个位置对覆盖的局部区域做加权汇总。同一组权重用于所有位置,因此参数数量不随图片宽高线性增长。
Conv2d(in_channels, out_channels, kernel_size) 的每个输出通道都会组合所有输入通道。彩色图像通常有 3 个输入通道,不是对 RGB 各自完成独立分类。
输出尺寸
忽略 dilation 时,单个空间维度的输出大小为:
floor((input + 2 * padding - kernel_size) / stride) + 1
kernel_size=3, padding=1, stride=1 会保持宽高;stride=2 通常使尺寸大约减半。网络连接全连接层前,必须知道卷积部分最后输出多少元素。
池化、感受野和下采样
最大池化保留局部强响应,平均池化保留局部均值。它们会降低空间分辨率,减少后续计算,也会丢失精确位置信息。
多层卷积堆叠后,高层特征图中一个位置对应原图更大范围,即感受野增大。感受野是理论覆盖范围,不表示范围内每个像素影响相同。
NCHW 是 PyTorch 图像的常用布局
N: batch size
C: channels
H: height
W: width
单张灰度图可能是 (H, W),交给 Conv2d 前需要补成 (1, 1, H, W)。来自其他图像库的数组常是 HWC,需用 permute(2, 0, 1) 转换,不能用 reshape() 直接改数字。
可运行实现
import torch
from torch import nn
torch.manual_seed(42)
images = torch.randn(8, 1, 28, 28)
class TinyCNN(nn.Module):
def __init__(self) -> None:
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 8, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(8, 16, kernel_size=3, padding=1),
nn.ReLU(),
nn.AdaptiveAvgPool2d((1, 1)),
)
self.classifier = nn.Linear(16, 3)
def forward(self, inputs: torch.Tensor) -> torch.Tensor:
features = self.features(inputs)
flattened = torch.flatten(features, start_dim=1)
return self.classifier(flattened)
model = TinyCNN()
x = images
for layer in model.features:
x = layer(x)
print(type(layer).__name__, tuple(x.shape))
logits = model(images)
print("logits:", logits.shape)
print("parameters:", sum(p.numel() for p in model.parameters()))
第一次池化将 28×28 变为 14×14,自适应平均池化将每个通道汇总为 1×1,因此分类层接收 16 个特征。自适应池化减少了全连接层对固定图像尺寸的依赖,但输入仍需要满足卷积层的通道契约。
用人工图像检查卷积响应
edge = torch.zeros(1, 1, 7, 7)
edge[:, :, :, 3:] = 1.0
detector = nn.Conv2d(1, 1, kernel_size=3, bias=False)
with torch.no_grad():
detector.weight.copy_(torch.tensor([[[[-1., 0., 1.], [-1., 0., 1.], [-1., 0., 1.]]]]))
print(detector(edge)[0, 0].round())
这个卷积核对竖直亮度变化产生强响应。训练中的卷积核不由人工指定,而是通过反向传播学习。

输入只包含竖直亮度分界,因此竖直边缘卷积核产生强响应,水平边缘响应接近零。
常见问题与排查
Conv2d期望 4 维输入:检查是否缺少 batch 或 channel 维度。- 输入通道不匹配:灰度图常为 1,RGB 常为 3,与第一个卷积层保持一致。
- 全连接层乘法报错:打印卷积部分输出形状,不要靠猜测展平大小。
- 图片数值范围不一致:明确是 0到255 还是 0到1,并使用训练时相同的归一化。
- 图像分类分数高但换背景失效:模型可能学到背景或水印,需要查错误样本和数据生成过程。
小结
CNN 的关键是局部连接、参数共享和层级特征。卷积层生成特征图,池化或步幅卷积降低分辨率,多层堆叠扩大感受野。每次结构调整都能推导 NCHW 形状,才能将卷积原理稳定地转成代码。
许可协议:CC BY-NC 4.0
更新于 1 小时前
觉得文章有帮助?点个赞吧!
0 条评论


