(二十一)池化、通道与图形分类网络
1. 从局部窗口取最大值
上节代码最后的池化按 2×2 窗口、每次跨两格,分别取最大值,得到 [[5,7],[6,9]]。MaxPool2d(2) 没有需要训练的窗口权重,它把每个局部区域概括为一个最大值,输出的空间长宽各缩为一半。
2. 沿每一层核对形状
# 续写同一文件:training_project/src/readingtorch/models.py
class SymbolCNN(nn.Module):
def __init__(self):
super().__init__()
# 空间大小依次为 8×8、4×4、2×2,最后每张图得到 32 个数。
self.features = nn.Sequential(
nn.Conv2d(1, 4, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(4, 8, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
)
self.head = nn.Sequential(nn.Flatten(), nn.Dropout(0.2), nn.Linear(32, 3))
def forward(self, x):
return self.head(self.features(x)) # 三个未做 softmax 的 logits。
def build_model(task):
if task == "regression":
return ReadingRegressor()
if task == "images":
return SymbolCNN()
raise ValueError("未知模型任务")第一层 Conv2d(1,4,3,padding=1) 用四组权重读单通道图,得到四张特征图;第二层把前一层的四个通道一起读入,每组卷积权重会合并四个通道的对应窗口,再输出八张特征图。
| 经过的动作 | 一批数据的形状 |
|---|---|
| 原始单通道图 | (B,1,8,8) |
| 第一层卷积与 ReLU | (B,4,8,8) |
| 第一次池化 | (B,4,4,4) |
| 第二层卷积与 ReLU | (B,8,4,4) |
| 第二次池化 | (B,8,2,2) |
Flatten() |
(B,32) |
| Dropout、线性分类层 | (B,3) |
Flatten 默认保留批次轴,把每张图的 8×2×2 个数排成 32 项。末层输出三个 logits,与长度 B 的类别编号一起进入交叉熵。
第一层参数数为 4×(1×3×3+1)=40,第二层为 8×(4×3×3+1)=296,末层为 3×(32+1)=99,合计 435。每组窗口权重在所有位置复用,参数数量没有再乘图像位置数。