正则化与泛化控制:参考答案

目录

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

正则化与泛化控制:参考答案#

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

说明#

以下答案与正文 9 道题逐题对应。推导题给出主要步骤;编程和实验题给出参考程序、检查方法与公平比较要求。实验结果会随数据和模型而变化,因此应根据实际结果作出结论,不能把参考答案中的一般趋势当作固定结论。

  1. \(\bU\) 为先对数据损失和 \(\ell_2\) 项执行一步梯度更新后得到的临时参数。由于

    \[\nabla_{\bW} \frac{\lambda_2}{2}\lVert\bW\rVert_F^2 =\lambda_2\bW,\]

    普通梯度下降的更新式为

    \[\bW^{+} =(1-\alpha\lambda_2)\bW -\alpha\nabla_{\bW}\mathcal{J}_{\mathrm{data}} -\alpha\lambda_1\bS =\bU-\alpha\lambda_1\bS,\]

    其中,矩阵 \(\bS\) 的每个元素都是相应权重绝对值的次梯度:

    \[\begin{split}S_{ij}\in \begin{cases} \{1\}, & w_{ij}>0,\\ [-1,1], & w_{ij}=0,\\ \{-1\}, & w_{ij}<0. \end{cases}.\end{split}\]

    普通次梯度更新每次减去一个有限步长,权重可能从正数跨到负数而没有恰好落在 0。近端梯度法先用数据损失和 \(\ell_2\) 项得到 \(\bU\)⁠,再逐元素执行软阈值

    \[W_{ij}^{+} =\operatorname{sign}(U_{ij}) \max\!\left(|U_{ij}|-\alpha\lambda_1,0\right).\]

    \(|U_{ij}|\leq\alpha\lambda_1\) 时,结果精确等于 0,因此软阈值能够直接产生稀疏解。若偏置不参与正则化,应把它从以上范数和更新中排除。

  2. Adam 加耦合 \(\ell_2\) 惩罚时,进入一阶矩和二阶原点矩估计的梯度为

    \[\bG_{\mathrm{reg}}^{(t)} =\bG^{(t)}+\lambda_{\ell_2}\bW^{(t)}.\]

    AdamW 只用 \(\bG^{(t)}\) 计算两个矩估计,并在自适应更新之外执行

    \[\bW^{(t+1)} =(1-\alpha\lambda_{\mathrm{wd}})\bW^{(t)} -\alpha \frac{\widehat{\bv}_W^{(t+1)}} {\sqrt{\widehat{\bs}_W^{(t+1)}}+\epsilon}.\]

    对普通梯度下降,有

    \[\bW^{(t+1)} =\bW^{(t)} -\alpha\left(\bG^{(t)}+\lambda\bW^{(t)}\right) =(1-\alpha\lambda)\bW^{(t)}-\alpha\bG^{(t)}.\]

    因而耦合 \(\ell_2\) 惩罚与乘法式权重衰减在这个条件下等价。Adam 会把惩罚梯度一起送入两个矩估计,并对不同坐标进行不同的缩放;AdamW 的统一收缩不进入矩估计,所以这个等价关系不能直接推广到 Adam。实践中通常把权重矩阵放入衰减参数组,把偏置和归一化层的尺度参数、平移参数放入不衰减参数组;最终仍应按模型名称和结构核对分组。

  3. 由于 \(\mathbb{E}(M)=q\)⁠,所以

    \[\mathbb{E}(\widetilde a\mid a) =\frac{a}{q}\mathbb{E}(M)=a.\]

    又因为 \(M^2=M\)⁠,所以

    \[\operatorname{Var}(\widetilde a\mid a) =\frac{a^2}{q^2}\operatorname{Var}(m) =\frac{a^2(1-q)}{q}.\]

    保留数量服从 \(\operatorname{Binomial}(100,0.8)\)⁠,其期望为 80;每个被保留的激活变为 \(2/0.8=2.5\)⁠;所有激活之和的期望为 \(80(2.5)=200\)⁠,与原来的总和相同。训练阶段已经用 \(1/q\) 对齐了期望,因此推断时关闭随机掩码并使用完整激活,不再除以 \(q\)⁠。

  4. 记第 \(k\) 个模型的预测误差为 \(e_k\)⁠,则平均误差为 \(\overline e=K^{-1}\sum_{k=1}^{K}e_k\)⁠。利用 \(\operatorname{Var}(e_k)=\sigma^2\)\(\operatorname{Cov}(e_j,e_k)=\rho\sigma^2\)⁠,可得

    \[\begin{split}\begin{aligned} \operatorname{Var}(\overline e) &=\frac{1}{K^2} \left[ K\sigma^2+K(K-1)\rho\sigma^2 \right]\\ &=\sigma^2\left[ \rho+\frac{1-\rho}{K} \right]. \end{aligned}\end{split}\]

    \(\rho=0\) 时,方差为 \(\sigma^2/K\)⁠;当 \(\rho=1\) 时,方差仍为 \(\sigma^2\)⁠;当 \(K\to\infty\) 时,方差趋于 \(\rho\sigma^2\)⁠。因此,增加成员只能减小误差中彼此不同的部分,不能消除所有成员共同具有的误差。成员数量很多但误差高度相关时,集成收益仍然有限。

  5. 一种参考实现如下。state 可以是模型的状态字典;深复制可以防止后续训练原地修改已经保存的最佳参数。

    import copy
    import numpy as np
    
    class EarlyStopper:
        def __init__(self, patience, min_delta=0.0):
            if patience < 1:
                raise ValueError("patience 必须为正整数")
            if min_delta < 0:
                raise ValueError("min_delta 不能为负数")
            self.patience = int(patience)
            self.min_delta = float(min_delta)
            self.best_loss = np.inf
            self.best_epoch = None
            self.best_state = None
            self.bad_epochs = 0
    
        def update(self, val_loss, state, epoch):
            if not np.isfinite(val_loss):
                raise ValueError("验证损失必须是有限数")
            improved = val_loss < self.best_loss - self.min_delta
            if improved:
                self.best_loss = float(val_loss)
                self.best_epoch = int(epoch)
                self.best_state = copy.deepcopy(state)
                self.bad_epochs = 0
            else:
                self.bad_epochs += 1
            return self.bad_epochs >= self.patience
    
        def restore(self):
            if self.best_state is None:
                raise RuntimeError("尚未保存最佳状态")
            return copy.deepcopy(self.best_state)
    

    例如,令验证损失依次为 \(0.8,0.5,0.5,0.6\)⁠,取 patience=2min_delta=0第二轮是最佳轮,相同损失不算改进,第四轮结束后停止,restore() 应返回第二轮的状态而不是第四轮状态。还应测试最小改进量恰好位于边界时的行为。停止器只接收验证损失,不接收测试指标;所有训练方案确定以后,才在测试集上评价一次。

  6. 倒置 Dropout 和高斯输入噪声可以写成两个只在训练阶段工作的函数:

    import numpy as np
    
    def inverted_dropout(x, keep_prob, training, rng):
        x = np.asarray(x)
        if not 0 < keep_prob <= 1:
            raise ValueError("keep_prob 必须位于 (0, 1]")
        if not training or keep_prob == 1:
            return x.copy(), np.ones_like(x, dtype=bool)
        mask = rng.random(x.shape) < keep_prob
        return x * mask / keep_prob, mask
    
    def gaussian_input_noise(x, sigma, training, rng):
        x = np.asarray(x)
        if sigma < 0:
            raise ValueError("sigma 不能为负数")
        if not training or sigma == 0:
            return x.copy()
        noise = rng.normal(loc=0.0, scale=sigma, size=x.shape)
        return x + noise
    

    两个由相同种子建立的生成器应产生相同结果;keep_prob=1sigma=0training=False 时,输出应逐元素等于输入。对固定标量 \(a\) 重复采样 Dropout,经验均值应接近 \(a\)⁠,经验方差应接近 \(a^2(1-q)/q\)⁠;对固定输入重复加入高斯噪声,输出均值应接近原输入,逐元素方差应接近 \(\sigma^2\)⁠。还应测试概率越界、负噪声标准差、输出维度和有限性。与框架实现比较时,要分别切换训练模式和评估模式。

  7. 公平比较可以采用如下流程:先确定相同的数据划分、初始参数、批次顺序、Adam 设置和最大训练量;对 \(\ell_1\)⁠、\(\ell_2\) 与 AdamW 分别设置包含 0 在内且数量相同的候选强度,并只根据验证集选择。三种方法应作用于同一参数集合,例如都排除偏置和归一化参数。\(\ell_1\)\(\ell_2\) 组把惩罚加入损失,AdamW 组只计算数据损失并执行解耦衰减。

      报告时应区分数据损失与含惩罚项的训练目标,因为不同惩罚下的总目标不能直接比较。权重统计至少包括 \(\lVert\bW\rVert_1\)⁠、\(\lVert\bW\rVert_F\)⁠,以及按预先确定阈值计算的近零权重比例;阈值不能在看到结果后为某个方法单独调整。还应报告多个固定随机种子下的任务指标均值与标准差、训练—验证差距、训练秒数、固定批量预测时间、参数量和峰值内存。适度正则化可能减小训练—验证差距,过强正则化可能造成欠拟合,最终结论应以实际验证与测试结果为准。

  8. 采用固定训练轮数的实验组在实验前确定轮数,并在该轮结束后保存参数;提前停止组设定相同的最大轮数,但根据验证损失、耐心轮数和最小改进量决定何时停止,并恢复最佳检查点。两组应共享数据划分、初始参数、批次顺序、优化器、学习率和验证频率。若希望只研究停止规则,不能同时改变数据增强、模型结构或正则化系数。

      需要记录提前停止组的最佳轮、实际停止轮和恢复后的指标,并分别报告两组的训练时间和测试表现。限制训练时长会阻止参数继续拟合训练数据中的细微波动,因此可能产生隐式正则化作用;但停止太早也可能造成欠拟合。测试集不能用于选择固定轮数、耐心轮数或最小改进量,只能在所有方案确定后用于最终评价。

  9. 第一种比较方式让每个成员使用相同结构和相同训练量,因而 \(K=3,5\) 的总训练量高于 \(K=1\)⁠;它回答“增加完整训练的成员能带来多少收益”。第二种方式固定所有成员共享的总训练预算,例如把总更新次数分配给 \(K\) 个成员;它回答“在相同计算预算下,训练多个较弱成员是否值得”。两种方式不能混在同一结论中。

      对每个 \(K\)⁠,应使用预先确定的随机种子集合独立训练成员,并平均分类概率。报告单个成员和集成的任务指标、成员误差之间的平均相关系数、总训练时间、运行全部成员后的固定批量预测时间、参数存储总量和峰值内存。随着 \(K\) 增大,若误差相关性较低,集成方差和测试误差可能下降;若误差相关性很高,收益会很快达到上限。部署结论还应说明成员能否并行运行,因为并行可以降低等待时间,却不会消除总计算量与存储量的增加。