CNN 基本模块与维度传播:参考答案

目录

\[ \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} \]

CNN 基本模块与维度传播:参考答案#

返回正文练习 · 返回答案索引

说明#

以下答案与正文10道题逐题对应。推导题给出主要步骤;编程和实验题给出参考程序和检查方法,并说明结果适用于哪些条件。

  1. 各层维度依次为 \(m\times8\times32\times32\)⁠、\(m\times8\times16\times16\)⁠、\(m\times16\times16\times16\)⁠、\(m\times16\)⁠、\(m\times10\)⁠。第一卷积参数量为 \(8[3(3)(3)+1]=224\)⁠,第二卷积为 \(16[8(3)(3)+1]=1168\)⁠,线性层为 \(10(16+1)=170\)⁠,总计 \(224+1168+170=1562\)⁠。池化与全局平均池化没有可训练参数。

  2. 第一卷积后 \(r_1=1+(3-1)(1)=3\)⁠、\(j_1=1\)⁠;池化后 \(r_2=3+(2-1)(1)=4\)⁠、\(j_2=2\)⁠;第二卷积后 \(r_3=4+(3-1)(2)=8\)⁠、\(j_3=2\)⁠。因此最后一个特征位置覆盖输入上的 \(8\times8\) 区域,相邻特征中心在输入上相隔 2 个像素。边界填充会使部分感受野落到填充值上,但不改变理论跨度。

  3. 四个窗口分别是左上、右上、左下、右下的 \(2\times2\) 块。最大池化输出为 \(\begin{bmatrix}6&8\\14&16\end{bmatrix}\)⁠;平均池化输出为 \(\begin{bmatrix}3.5&5.5\\11.5&13.5\end{bmatrix}\)⁠。两种运算输出维度均为 \(2\times2\)⁠。

  4. 一个固定窗口的最大池化只依赖元素集合的最大值,排列不会改变该最大值,所以输出不变。例如一维输入 \([0,1,0,0]\) 用大小 2、步幅 2 最大池化得到 \([1,0]\)⁠;向右平移并以 0 填充得到 \([0,0,1,0]\)⁠,池化结果为 \([0,1]\)⁠。输出发生位置变化,若采用裁剪边界还可能丢失响应,因此局部排列不变不能被解释为全局平移不变。

  5. 模型和跟踪器可利用虚拟前向自动确定线性层输入:

    class SmallCNN(nn.Module):
        def __init__(self):
            super().__init__()
            self.features = nn.Sequential(
                nn.Conv2d(3, 8, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
                nn.Conv2d(8, 16, 3, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d(1))
            with torch.no_grad():
                width = self.features(torch.zeros(1, 3, 32, 32)).flatten(1).shape[1]
            self.classifier = nn.Linear(width, 10)
        def forward(self, x):
            return self.classifier(self.features(x).flatten(1))
    
    trace = []
    def hook(module, inputs, output):
        trace.append((module.__class__.__name__, tuple(inputs[0].shape),
                      tuple(output.shape), sum(p.numel() for p in module.parameters())))
    

    只给叶子模块注册钩子,可避免父模块与子模块重复计数。

  6. 按输出尺寸公式逐层得到 \(32,16,16,1\) 的空间变化,与钩子记录逐项比较;批次轴应始终为 \(m\)⁠。手工参数量 1562 必须与框架总数完全相等,而不是近似相等。若维度不一致,先检查 NCHW 顺序、填充、步幅和 flatten 起始轴;若参数不一致,检查偏置及分类输出层输入维度。

  7. \(m=1\)\(m=7\) 进行前向传播,除第 0 轴外的维度应相同;空间尺寸只要能通过两次卷积与一次池化就应得到合法输出;输入通道不是 3 时应报错;AdaptiveAvgPool2d(1) 与沿高度和宽度求均值的结果一致。完成一次交叉熵后向传播后,每个 requires_grad 参数都有相同维度的梯度,并且 isfinite 的检查结果应为真。

  8. MLP 与 CNN 应使用相同的数据划分、预处理方法、随机种子和更新次数。两个模型在验证集上尝试相同数量的学习率,并为每个学习率使用相同的训练量。CNN 能利用局部连接和权重共享,在图像任务上通常可以用较少参数取得较好的泛化结果;MLP 的矩阵运算在较小输入上也可能运行得较快。哪个模型预测更准确、运行更快,应根据本题实际测量的结果判断。表中报告测试指标的均值与标准差、训练秒数、固定批量预测时间、实际参数量及峰值内存。

  9. 三组保持下采样位置与输出维度一致;步幅卷积会增加可训练参数和乘加量,最大池化与平均池化没有参数。各组使用相同的数据划分、随机种子和训练量,并采用相同的方法选择学习率等超参数,只改变下采样方法。报告任务指标、训练时间、固定批量预测时间、参数量、乘加量及峰值内存。最大池化的梯度较稀疏,平均池化会平均分配信息,步幅卷积能够学习下采样方法;哪一种更好取决于具体数据。

  10. 宽度翻倍会使相邻卷积层参数量和计算量增长快于线性比例,而特征图内存近似随通道数增长。每组使用相同划分、种子、优化器和更新次数,报告测试性能及波动、训练时间、参数量与峰值内存。若更宽网络没有改善性能,应检查样本量、正则化和训练是否充分;不能只因参数更多就认定模型更好。