\[ \begin{align}\begin{aligned}\newcommand{\ba}{\boldsymbol{a}}
\newcommand{\bb}{\boldsymbol{b}}
\newcommand{\be}{\boldsymbol{e}}
\newcommand{\bq}{\boldsymbol{q}}
\newcommand{\bk}{\boldsymbol{k}}
\newcommand{\bw}{\boldsymbol{w}}
\newcommand{\bx}{\boldsymbol{x}}
\newcommand{\by}{\boldsymbol{y}}
\newcommand{\bz}{\boldsymbol{z}}
\newcommand{\bd}{\boldsymbol{d}}
\newcommand{\bv}{\boldsymbol{v}}
\newcommand{\bs}{\boldsymbol{s}}\\\newcommand{\btheta}{\boldsymbol{\theta}}
\newcommand{\bbeta}{\boldsymbol{\beta}}
\newcommand{\bgamma}{\boldsymbol{\gamma}}
\newcommand{\bsigma}{\boldsymbol{\sigma}}
\newcommand{\md}{\mbox{d}}
\newcommand{\bmu}{\boldsymbol{\mu}}
\newcommand{\bone}{\boldsymbol{1}}
\newcommand{\bzero}{\boldsymbol{0}}
\newcommand{\bepsilon}{\boldsymbol{\epsilon}}
\newcommand{\bphi}{\boldsymbol{\phi}}
\newcommand{\bh}{\boldsymbol{h}}
\newcommand{\bc}{\boldsymbol{c}}
\newcommand{\br}{\boldsymbol{r}}
\newcommand{\bQ}{\boldsymbol{Q}}
\newcommand{\bK}{\boldsymbol{K}}
\newcommand{\bV}{\boldsymbol{V}}
\newcommand{\bSigma}{\boldsymbol{\Sigma}}
\newcommand{\bg}{\boldsymbol{g}}
\newcommand{\bxi}{\boldsymbol{\xi}}
\newcommand{\bvarepsilon}{\boldsymbol{\varepsilon}}
\newcommand{\bdelta}{\boldsymbol{\delta}}
\newcommand{\bq}{\boldsymbol{q}}
\newcommand{\bk}{\boldsymbol{k}}
\newcommand{\bJ}{\boldsymbol{J}}
\newcommand{\bp}{\boldsymbol{p}}
\newcommand{\bi}{\boldsymbol{i}}
\newcommand{\bo}{\boldsymbol{o}}
\newcommand{\bE}{\boldsymbol{E}}
\newcommand{\bH}{\boldsymbol{H}}
\newcommand{\bL}{\boldsymbol{L}}
\newcommand{\bu}{\boldsymbol{u}}
\newcommand{\bLambda}{\boldsymbol{\Lambda}}
\newcommand{\trans}{^{\rm\scriptsize T}}
\newcommand{\var}{\mathrm{var}}\\\newcommand{\bA}{\boldsymbol{A}}
\newcommand{\bB}{\boldsymbol{B}}
\newcommand{\bC}{\boldsymbol{C}}
\newcommand{\bD}{\boldsymbol{D}}
\newcommand{\bG}{\boldsymbol{G}}
\newcommand{\bI}{\boldsymbol{I}}
\newcommand{\bM}{\boldsymbol{M}}
\newcommand{\bP}{\boldsymbol{P}}
\newcommand{\bS}{\boldsymbol{S}}
\newcommand{\bU}{\boldsymbol{U}}
\newcommand{\bW}{\boldsymbol{W}}
\newcommand{\bX}{\boldsymbol{X}}
\newcommand{\bY}{\boldsymbol{Y}}
\newcommand{\bZ}{\boldsymbol{Z}}
\newcommand{\cotp}{\textcolor[RGB]{48,209,88}{TP}}
\newcommand{\cotn}{\textcolor[RGB]{100,210,255}{TN}}
\newcommand{\cofp}{\textcolor[RGB]{94,92,230}{FP}}
\newcommand{\cofn}{\textcolor[RGB]{191,90,242}{FN}}\\\newcommand{\numcotp}{\textcolor[RGB]{48,209,88}{50}}
\newcommand{\numcotn}{\textcolor[RGB]{100,210,255}{30}}
\newcommand{\numcofp}{\textcolor[RGB]{94,92,230}{10}}
\newcommand{\numcofn}{\textcolor[RGB]{191,90,242}{10}}
\DeclareMathOperator*{\argmin}{arg\,min}\end{aligned}\end{align} \]
AlexNet 与 CIFAR-10 实现:参考答案
返回正文练习 · 返回答案索引
说明
以下答案与正文10道题逐题对应。推导题给出主要步骤;编程和实验题给出参考程序和检查方法,并说明结果适用于哪些条件。
首层输出为 \(\lfloor(32-11)/4\rfloor+1=6\),第一次池化输出为 \(\lfloor(6-3)/2\rfloor+1=2\)。填充 2 的 \(5\times5\) 卷积仍输出 2;第二次 \(3\times3\) 池化要求输入至少为 3,但当前只有 2,公式给出 \(\lfloor(2-3)/2\rfloor+1=0\),因此该步非法。这说明结构适配不能只修改最终线性层。
空间尺寸链为 \(227\rightarrow55\rightarrow27\rightarrow27\rightarrow13\rightarrow13\rightarrow13\rightarrow13\rightarrow6\)。其中三个 \(3\times3\) 卷积都使用填充 1,故保持 13;最后池化得到 6。于是经典展平维度为 \(256(6)(6)=9216\)。一些资料把输入概括为约 \(224\times224\),通常会同时采用不同的裁剪、首层填充或边界处理约定;计算时必须先明确整套配置,不能把 \(224\times224\) 输入与本题的无填充 \(227\times227\) 尺寸链混用。
第一线性层参数量为 \(4096[256(6)(6)+1]=37752832\),第二层为 \(4096(4096+1)=16781312\),第三层为 \(10(4096+1)=40970\),合计 54575114。仅分类输出层就超过五千万参数,因此其权重存储和矩阵运算可能超过卷积部分;缩小空间尺寸或用全局平均池化可显著减少该成本。
训练输出为 \((1,0,1,0)\odot(2,0,-4,6)/0.5=(4,0,-8,0)\)。对随机掩码取条件期望时,每个位置以概率 0.5 保留并放大 2 倍,因此期望仍为 \((2,0,-4,6)\)。评估模式不采样掩码也不再缩放,直接输出原激活。
适配网络可以保留“多层卷积 + 大分类输出层”的思想,但匹配小输入:
class AlexNetCIFAR(nn.Module):
def __init__(self, classes=10):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(64, 192, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(192, 256, 3, padding=1), nn.ReLU(),
nn.Conv2d(256, 256, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.AdaptiveAvgPool2d((2, 2)))
self.classifier = nn.Sequential(nn.Dropout(0.5), nn.Linear(256*2*2, 512),
nn.ReLU(), nn.Dropout(0.5), nn.Linear(512, classes))
def forward(self, x):
return self.classifier(self.features(x).flatten(1))
也可用虚拟前向替代手工写出的 256*2*2。
可以在各层完成计算时记录其输出,按照 \(m\times d_C^{[l]}\times d_H^{[l]}\times d_W^{[l]}\) 的顺序与公式逐层核对。使用 next(model.parameters()).device == input.device 检查模型与输入位于同一设备;训练模式下,由于 Dropout 的随机屏蔽,同一输入的多次输出通常不同,评估模式下则应相同。参数量可把手工逐层求和的结果与 sum(p.numel()) 对照。若存在 BatchNorm 或 Dropout,维度与数值检查应明确使用 train 还是 eval 模式。
原始结构输入 32 应在第二次池化前被维度检查拒绝;适配结构对 \(m=1,8\) 均输出 \(m\times10\);train() 与 eval() 的 Dropout 行为符合第 4 题;模型与输入移动设备后输出设备相同;交叉熵后向传播后,每个参数梯度都应具有正确维度并且是有限数值。没有 GPU 时可以跳过 GPU 设备检查,不能把环境缺少 CUDA 当作模型错误。
两种方案使用相同的原始数据划分、随机种子和更新次数,并在验证集上尝试相同数量的优化器设置;但是,放大输入的方案每一步所需的计算量远大于使用原始尺寸的方案。报告测试指标及其波动、训练秒数、固定批量预测时间、参数量、乘加量和峰值内存。放大输入不会创造新的图像细节,却可能更接近经典 AlexNet 的尺寸变化过程;适配原始图像尺寸的结构通常计算效率更高。由于输入大小和网络结构同时改变,结果只能说明这两个具体方案在本题数据与硬件上的差异,不能单独说明某一项改动的作用。
三组只改变 Dropout 概率,复用划分、种子、初始化、批次顺序和更新次数。适度 Dropout 可能减小训练—验证差距,过强会减慢拟合;评估时 Dropout 关闭,所以参数量和预测计算图相同。报告任务指标、差距、训练时间、固定批量预测时间及峰值内存;计时应多次重复,不能把随机波动当作推断效率差异。
LRN 没有常见的可训练尺度参数,BatchNorm 增加逐通道尺度与平移并维护运行统计量。三组固定数据、种子、更新次数、增强和验证预算,报告测试性能、训练与固定批量预测计时、参数量和峰值内存。LRN 是 AlexNet 的历史组件,BatchNorm 属于现代训练配方;若后者更好,只能说明当前数据与训练设置下的比较结果,不能把修改后的网络称为原版 AlexNet。