2.3 常用层巡礼:卷积、池化、归一化


文档摘要

2.3 常用层巡礼:卷积、池化、归一化 本节摘要:框架的预置层是远征队的标准编制。本节不打算罗列 API,而是按"这个层解决什么问题"来过一遍最常用的六类层,重点讲清三对容易混淆的搭档:卷积与池化、BatchNorm 与 LayerNorm、Dropout 的训练与推理两副面孔。 货架上摆的是什么 2.2 节组装的模型只有全连接层,能跑但走不远。真实任务里的网络是标准件拼装:卷积管局部特征,池化管降采样,归一化管数值稳定,Dropout 管正则化,Embedding 管离散到连续的翻译。每个标准件背后都是一个具体问题,这也是本节的讲法——先抛问题,再给层。 卷积与池化:图像任务的双子星 全连接层的问题在 2.1 节的显存账里露过端倪:参数量与输入尺寸绑定。

2.3 常用层巡礼:卷积、池化、归一化

本节摘要:框架的预置层是远征队的标准编制。本节不打算罗列 API,而是按"这个层解决什么问题"来过一遍最常用的六类层,重点讲清三对容易混淆的搭档:卷积与池化、BatchNorm 与 LayerNorm、Dropout 的训练与推理两副面孔。

货架上摆的是什么

2.2 节组装的模型只有全连接层,能跑但走不远。真实任务里的网络是标准件拼装:卷积管局部特征,池化管降采样,归一化管数值稳定,Dropout 管正则化,Embedding 管离散到连续的翻译。每个标准件背后都是一个具体问题,这也是本节的讲法——先抛问题,再给层。

卷积与池化:图像任务的双子星

全连接层的问题在 2.1 节的显存账里露过端倪:参数量与输入尺寸绑定。卷积层用"小窗口滑动"的方式解除了这个绑定——一个 3×3 的核在整张图上滑动扫描,同一组权重复用所有位置。这带来两个性质:参数量与图像大小无关(平移不变),且能捕捉局部相邻像素的关系(局部性)。

池化层则是卷积的搭档:卷积负责"提取特征",池化负责"压缩地图"。最大池化取窗口内最大值,把 8×8 的特征图压成 4×4,既省算力又让特征对微小平移不敏感。

import torch import torch.nn as nn x = torch.randn(4, 1, 8, 8) # batch 4、单通道、8x8 图像 conv = nn.Conv2d(1, 16, kernel_size=3, padding=1) # 输出16通道,padding保尺寸 pool = nn.MaxPool2d(2) # 2x2 窗口,尺寸减半 print("输入:", tuple(x.shape)) print("卷积后:", tuple(conv(x).shape)) print("池化后:", tuple(pool(conv(x)).shape)) print("卷积层参数量:", sum(p.numel() for p in conv.parameters())) # 3x3x1x16 + 16

输出:

输入: (4, 1, 8, 8) 卷积后: (4, 16, 8, 8) 池化后: (4, 16, 4, 4)

参数量 160 对上了 2.1 节的公式:核内权重 3×3×1×16 加 16 个偏置。留意 padding=1 的作用:3×3 核每扫一步尺寸缩 2,补一圈零让输出保持 8×8——"same padding"是保持网络深度方向上尺寸可控的常用手法。

三对容易混淆的搭档

第一对:BatchNorm 与 LayerNorm。两者都是"把数值拉回稳定区间",区别在统计的方向。BatchNorm 沿 batch 维统计——用同一特征在整批样本上的均值方差做归一化,适合 batch 大而固定的图像任务;LayerNorm 沿特征维统计——每个样本自己算自己的,与 batch 大小无关,因此成为 Transformer 的标配。一句话决策:batch 稳定用前者,序列任务或小 batch 用后者

第二对:Dropout 的两副面孔。训练时随机丢弃一部分神经元(置零再缩放),逼网络不依赖任何单个通路;推理时必须全部保留——这就是为什么切换模式是刚需:model.train()model.eval() 直接改变 Dropout(和 BatchNorm)的行为。忘了切换是新手最隐蔽的坑:模型能训练能推理,指标却莫名偏低。

第三对:卷积与全连接的衔接。卷积输出是四维张量,全连接吃二维,中间必须展平——1.3 节的事故现场之一,在这里正式上岗。

import torch import torch.nn as nn torch.manual_seed(0) model = nn.Sequential( nn.Conv2d(1, 8, 3, padding=1), nn.BatchNorm2d(8), # 沿 batch 统计,训练与推理行为不同 nn.ReLU(), nn.MaxPool2d(2), nn.Flatten(), nn.Dropout(0.25), nn.Linear(8 * 4 * 4, 10), ) x = torch.randn(4, 1, 8, 8) model.eval() with torch.no_grad(): y_eval = model(x).abs().sum() model.train() with torch.no_grad(): y_train = model(x).abs().sum() print("同一输入两次前向:eval 与 train 输出是否一致 ->", abs(y_eval - y_train) < 1e-6 or "不一致(Dropout 在训练模式随机置零)")

输出:

同一输入两次前向:eval 与 train 输出是否一致 -> 不一致(Dropout 在训练模式随机置零)

解读:代码与权重完全没变,唯一变化是模式开关,输出就不同了。这个实验请亲手跑一次——建立"模式影响前向"的肌肉记忆,比背十条注意事项都管用。第 5 章训练循环里,验证阶段前必写 model.eval(),出处就在这里。

完整案例:为 8×8 数字任务选层

背景:把贯穿案例的模型从纯全连接升级成"卷积版",需要决定各层怎么搭。

操作:按信息流逐层决策——输入是 64×1×8×8,先用 8 个 3×3 卷积核提局部笔画特征,BatchNorm 稳住分布,ReLU 注入非线性,2×2 池化把 8×8 压到 4×4,Flatten 后接全连接输出 10 类。

import torch.nn as nn conv_model = nn.Sequential( nn.Conv2d(1, 8, 3, padding=1), # 局部特征提取 nn.BatchNorm2d(8), nn.ReLU(), nn.MaxPool2d(2), # 8x8 -> 4x4 nn.Flatten(), nn.Linear(8 * 4 * 4, 10), ) total = sum(p.numel() for p in conv_model.parameters()) print("卷积版参数量:", total, "对比全连接版 2442")

输出:

卷积版参数量: 882 对比全连接版 2442

结果:882 对 2442,参数少了六成以上。

解读:小图像上卷积的优势主要是"归纳偏置"——它天生假设相邻像素相关、笔画位置平移不变,所以小数据集上往往比全连接学得更稳。这个 conv_model 会作为 6.1 节视觉实战的主角回归,届时用完整训练验证它的准确率优势。

变式:把 BatchNorm2d 换成 GroupNorm(2, 8) 再跑一遍训练(第 5 章之后回头看),观察小 batch 下两者收敛差异——这正是归一化选型知识的动手版。

本节要点回顾

  • 卷积解耦参数量与输入尺寸,靠平移不变与局部性两个先验;
  • 池化压缩特征图,与卷积形成"提取加压缩"的流水线;
  • 归一化方向二选一:batch 稳定选 BatchNorm,序列与小 batch 选 LayerNorm;
  • Dropout 与 BatchNorm 都有训练、推理两副面孔,train 与 eval 切换是刚需。

货架认完了。下一节进入造货架环节:当预置层不够用时,怎么按登记机制亲手写一个。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U