卷积与池化的后向传播:参考答案

目录

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

卷积与池化的后向传播:参考答案#

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

说明#

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

  1. 链式法则给出 \(\partial\mathcal J/\partial W_{q,c,u,v}^{[l]}=\sum_{i,r,s}(\partial\mathcal J/\partial Z_{i,q,r,s}^{[l]})(\partial Z_{i,q,r,s}^{[l]}/\partial W_{q,c,u,v}^{[l]})\)⁠,而第二个因子是 \(A_{i,c,r+u-1,s+v-1}^{[l-1]}\)⁠。由于 \(\partial\mathcal J/\partial Z_{i,q,r,s}^{[l]}=\mathrm dZ_{i,q,r,s}^{[l]}\)⁠,所以得到正文公式。一个卷积核元素会用于 \(m\) 个样本中的所有合法输出位置,因此必须累加这些位置的贡献。若 \(\mathcal J\) 已经是批量平均损失,因子 \(1/m\) 已包含在 \(\mathrm d\bZ^{[l]}\) 中,最后不能再次除以 \(m\)⁠。

  2. 卷积核的四个位置分别收集所有对应输入,因此 \(\mathrm d\bW^{[l]}=\begin{bmatrix}1+2+4+5&2+3+5+6\\4+5+7+8&5+6+8+9\end{bmatrix}=\begin{bmatrix}12&16\\24&28\end{bmatrix}\)⁠。全 1 核把 \(\mathrm d\bZ^{[l]}\) 中的每个数加回它所覆盖的输入位置,故 \(\mathrm d\bA^{[l-1]}=\begin{bmatrix}1&2&1\\2&4&2\\1&2&1\end{bmatrix}\)⁠。中心位置被四个窗口覆盖,因此梯度为 4。

  3. 最大池化把 \(\mathrm dP_{i,c,r,s}^{[l+1]}=6\) 送到前向传播选中的最大值 4,因此该窗口对输入的梯度为 \(\begin{bmatrix}0&6\\0&0\end{bmatrix}\)⁠。平均池化对四个元素的局部导数均为 \(1/4\)⁠,所以梯度为 \(\begin{bmatrix}1.5&1.5\\1.5&1.5\end{bmatrix}\)⁠。若窗口内有并列最大值,程序必须按照框架规定的规则选定接收梯度的位置,并保证后向传播使用前向传播保存的同一位置。

  4. Taylor 展开 \(\mathcal J(\theta\pm h)=\mathcal J(\theta)\pm h\mathcal J'(\theta)+h^2\mathcal J''(\theta)/2\pm h^3\mathcal J'''(\theta)/6+\cdots\)⁠,相减再除以 \(2h\) 后首个截断项为 \(h^2\mathcal J'''(\theta)/6\)⁠。但两次接近数值相减会产生约 \(\varepsilon_{\mathrm{mach}}\) 量级误差,除以 \(h\) 后被放大。较大 \(h\) 受截断误差控制,过小 \(h\) 受舍入误差控制,因而存在中间最优范围。

  5. 后向程序复用前向传播保存的窗口位置。下面的 a_pad 是填充后的 \(\bA^{[l-1]}\)⁠,dz 对应 \(\mathrm d\bZ^{[l]}\)⁠:

    import numpy as np
    
    def conv2d_backward(dz, a_pad, w, padding=0,
                        stride=1, dilation=1):
        da_pad = np.zeros_like(a_pad, dtype=np.result_type(dz, w))
        dw = np.zeros_like(w, dtype=np.result_type(dz, a_pad))
        db = dz.sum(axis=(0, 2, 3))
        batch_size, c_out, h_out, w_out = dz.shape
        kh, kw = w.shape[2:]
        for i in range(batch_size):
            for q in range(c_out):
                for r in range(h_out):
                    for s in range(w_out):
                        rows = slice(r*stride, r*stride+dilation*kh, dilation)
                        cols = slice(s*stride, s*stride+dilation*kw, dilation)
                        g = dz[i, q, r, s]
                        dw[q] += g * a_pad[i, :, rows, cols]
                        da_pad[i, :, rows, cols] += g * w[q]
        if padding == 0:
            da = da_pad
        else:
            da = da_pad[:, :, padding:-padding, padding:-padding]
        return da, dw, db
    

    这里假定高、宽两端使用相同的整数填充;返回的 da 已裁掉人工边界,因而与未填充的 \(\bA^{[l-1]}\) 维度相同。若前向传播支持不同方向的填充,缓存中也应保存四个填充值,并分别裁掉相应边界。

  6. 对参数 \(\theta_j\) 的相对误差可用 \(|g_j-\widetilde g_j|/\max(1,|g_j|,|\widetilde g_j|)\)⁠。中心差分 只适合 float64 小张量并应尝试多个 \(h\)⁠;将手工后向传播与 PyTorch 自动微分 对照时,必须复制完全相同的 \(\bA^{[l-1]}\)⁠、\(\bW^{[l]}\)⁠、\(\bb^{[l]}\)\(\mathrm d\bZ^{[l]}\)⁠。若自动微分结果与手工结果一致而中心差分不稳定,先调整 \(h\)⁠;若两种检查都不一致,则检查核方向、填充裁剪和重叠累加。

  7. 全 1 核与全 1 的 \(\mathrm d\bZ^{[l]}\) 应复现第 2 题的重叠计数;代码中应检查 db == dz.sum((0, 2, 3))da.shape == a.shapedw.shape == w.shape池化测试应使用具有唯一最大值的窗口和可以手算的平均值;dz=0 时三个卷积梯度都应为 0;批量、通道或空间维度不兼容时应报告错误。还应检查所有结果都是有限数,并用非对称卷积核确认核方向正确。

  8. 三种后向实现使用相同的 \(\bW^{[l]}\)⁠、批次顺序、随机种子和参数更新次数,并先确认 \(\mathrm d\bA^{[l-1]}\)⁠、\(\mathrm d\bW^{[l]}\)\(\mathrm d\bb^{[l]}\) 在允许误差内一致。朴素 NumPy 通常训练最慢,向量化实现会增加保存窗口所需的内存,框架自动微分 通常能调用经过优化的程序;具体差异取决于硬件。结果表应包含测试指标、梯度最大误差、训练时间、参数量和峰值内存。模型预测只进行前向传播,因此后向实现不会直接改变预测所需的计算。

  9. 最大池化通常只在每个窗口的最大位置产生非零梯度,平均池化则把梯度分到全部元素,因此非零比例和范数分布不同。两组固定划分、种子、初始化、更新次数和通道数,报告多种子任务指标、梯度统计、训练与固定批量预测时间、参数量和峰值内存。池化本身都无参数;性能差异不能仅由梯度稀疏性单独解释。

  10. float64 用于小规模参考,float32 是常见基线,混合精度需使用损失缩放并检查非有限梯度。三组共享数据、种子、更新次数和学习率规则,报告任务指标及波动、失败步数、训练时间、参数量与峰值内存。参数个数相同,但存储字节数不同;混合精度可能降低内存,也可能因硬件或算子不支持而没有收益。