第 8 章:深度模型训练的优化(Optimization for Training Deep Models)
深度学习算法在许多语境下涉及优化:例如在 PCA 类模型中做推断就需要解一个优化问题;分析式优化也常被用来写证明或设计算法。在深度学习涉及的所有优化问题里,神经网络训练是最困难的一类——通常需要花上数天到数月时间、在数百台机器上才能解出单个训练实例。这套针对神经网络训练的专用优化技术就是本章的主题。本章聚焦一个特定的优化情形:寻找神经网络参数 \(\theta\) 以显著降低代价函数 \(J(\theta)\),后者通常包含一个在整个训练集上评估的性能度量以及额外的正则化项。作者提醒若不熟悉基于梯度的优化基本原理,可回看第 4 章。章首导言预告了行文次序:(1)描述机器学习训练用优化与纯优化的区别;(2)给出神经网络优化中若干具体挑战;(3)定义若干实用算法,包括优化算法本身以及参数初始化策略;(4)介绍学习率自适应或利用二阶导数信息的更高级算法;(5)综述把简单优化算法组合成高层流程的优化策略。
8.1 学习与纯优化的区别(How Learning Differs from Pure Optimization)
训练深度模型用的优化算法与传统的纯优化算法在若干方面有别。机器学习通常以间接方式起作用:在大多数场景里我们关心的是某个性能度量 \(P\),它在测试集上定义且常常不可被直接计算;我们只能间接地优化 \(P\)——通过降低另一个代价函数 \(J(\theta)\),并寄望这能反过来提升 \(P\)。这与纯优化形成对比,纯优化里最小化 \(J\) 本身就是目的。用于训练深度模型的优化算法也通常对机器学习目标函数的特殊结构有针对性。典型的代价函数可以写成训练集上的一个平均,例如
其中 \(L\) 是逐样本损失函数,\(f(x; \theta)\) 是输入 \(x\) 时的预测输出,\(\hat{p}_{\text{data}}\) 是经验分布。在监督学习情形下,\(y\) 是目标输出。本章发展不带正则化的监督情形,\(L\) 的参数是 \(f(x; \theta)\) 与 \(y\);但读者很容易把这一发展推广到把 \(\theta\) 或 \(x\) 也作为参数(用来开发各种正则化或无监督学习)。方程 (8.1) 定义的代价函数是相对于训练集的目标函数。我们通常更愿意最小化相对于数据生成分布 \(p_{\text{data}}\) 的版本
8.1.1 经验风险最小化(Empirical Risk Minimization)
机器学习算法的目标是降低 (8.2) 给出的期望泛化误差。这个量称为风险(risk),其期望是相对于真实底层分布 \(p_{\text{data}}\) 取得的。如果我们知道真实分布 \(p_{\text{data}}(x, y)\),风险最小化就是一个可用优化算法求解的优化任务。但当我们并不知道 \(p_{\text{data}}(x, y)\),只掌握训练样本时,机器学习问题就出现了。把机器学习问题重新转化为优化问题的最简单方式是最小化训练集上的期望损失——也就是把真实分布 \(p(x, y)\) 替换为由训练集定义的经验分布 \(\hat{p}(x, y)\)。于是最小化经验风险
其中 \(m\) 是训练样本数。基于最小化这一平均训练误差的训练过程称为经验风险最小化(empirical risk minimization)。在这一设定下,机器学习仍与直截了当的优化很类似:不是直接优化风险,而是优化经验风险并希望风险也能显著下降。多种理论结果给出了真实风险可以在何种条件下被降低的保证。但经验风险最小化易于过拟合:高容量模型会简单地记忆训练集;在许多情形下经验风险最小化并不真正可行——最有效的现代优化算法基于梯度下降,但许多有用损失函数(如 0-1 损失)没有有用的导数(在处处导数要么为零要么无定义)。这两个问题决定了在深度学习语境下我们很少使用经验风险最小化,转而必须用一种略有不同的方式:我们实际优化的量与真正想优化的量之间存在更大距离。
8.1.2 代理损失函数与提前停止(Surrogate Loss Functions and Early Stopping)
我们真正关心的损失函数(如分类错误率)有时无法被有效优化——例如,即便对线性分类器,最小化期望 0-1 损失也通常是难解的(关于输入维度指数级),Marcotte and Savard (1992)。这种情形下通常改而优化一个代理损失函数(surrogate loss function)来作为替代。例如正确类别的负对数似然通常被用作 0-1 损失的代理:负对数似然允许模型估计各类别在给定输入下的条件概率,而如果模型能做好这一估计,就能在期望意义上选取分类错误率最低的类别。在某些情况下,代理损失函数反而能让模型学到更多东西。例如在使用对数似然代理训练时,训练集 0-1 损失已经降到零之后,测试集 0-1 损失往往还能继续下降很长时间——这是因为即便期望 0-1 损失已经是零,仍可通过把类别之间进一步分开而提升分类器的鲁棒性,从而获得一个更自信可靠的分类器,从训练数据中提取出比单纯最小化训练集 0-1 损失更多的信息。优化用于训练算法与一般优化的一个非常重要的区别在于:训练算法通常并不停在局部极小点。机器学习算法通常最小化一个代理损失函数,但会在某个基于提前停止(7.8 节)的收敛准则满足时停住。提前停止准则通常基于真实底层损失函数,例如在验证集上测得的 0-1 损失,并被设计成一旦过拟合开始出现就让算法停下。训练往往在代理损失函数仍具有较大梯度时停止——这与纯优化设定(算法在梯度变得很小时被认为已收敛)截然不同。
8.1.3 批和最小批算法(Batch and Minibatch Algorithms)
机器学习算法与一般优化算法在另一方面也不同:目标函数通常分解为训练样本上的求和。机器学习的优化算法通常基于仅用完整代价函数中一部分项来估计代价函数的期望值,然后据此计算每次参数更新。例如最大似然估计问题在取对数后分解为对每个样本的求和:
最大化该和等价于最大化经验分布下的期望:
大多数优化算法使用的目标函数 \(J\) 的性质本身也是训练集上的期望。最常用的性质是梯度:
精确计算这一期望代价很高,因为它要求对整个数据集中的每个样本都评估模型。实践中我们只需从数据集中随机采样少量样本、再对那些样本求平均就能算出这些期望。标准误差的均值(5.46 节)的标准差从 \(n\) 个样本估计出来是 \(\sigma / \sqrt{n}\),其中 \(\sigma\) 是样本值的真实标准差;\(\sqrt{n}\) 出现在分母意味着使用更多样本来估计梯度时其收益小于线性。设想两个假设性的梯度估计:一个基于 100 个样本,另一个基于 10000 个样本。后者所需计算量是前者的 100 倍,但均值的标准误差只下降为 1/10。多数优化算法如果允许它们快速计算梯度的近似估计而非缓慢地计算精确梯度,其收敛(在总计算量意义上、而非更新次数意义上)反而快得多。从少量样本统计估计梯度的另一个动机是训练集中的冗余:最坏情形下训练集中所有 \(m\) 个样本都彼此相同——基于采样的梯度估计可只用 1 个样本就计算出正确梯度,比朴素方法省 \(m\) 倍计算量。实践中不太可能真的遇到这种最坏情形,但可能存在大量样本对梯度的贡献非常相似。使用整个训练集的优化算法称为批(batch)或确定性(deterministic)梯度方法,因为它们同时处理所有训练样本。该术语有些令人困惑,因为"batch"也常被用来描述小批量随机梯度下降中的"minibatch"。通常"batch gradient descent"暗指使用完整训练集,而用"batch"指代一组样本则不然——例如"batch size"通常描述的是 minibatch 的大小。一次只用一个样本的优化算法有时称为随机(stochastic)或在线(online)方法。"online"一词通常保留给从不断产生的新样本流中抽取样本的情形,而不是对固定大小训练集做若干遍。深度学习使用的大多数算法介于两者之间——使用多于一个但少于全部训练样本,传统上称为 minibatch 或 minibatch stochastic 方法,现在一般直接称为随机方法。随机方法的典范例子是随机梯度下降,详见 8.3.1 节。Minibatch 大小一般受以下因素驱动:(1)较大批提供更精确的梯度估计但收益次线性;(2)极小批通常会欠利用多核架构,激励使用某个绝对最小批大小,低于它时处理 minibatch 的时间不再下降;(3)若批中所有样本并行处理(通常如此),内存消耗随批大小线性增长,对许多硬件是限制批大小的关键因素;(4)特定尺寸的数组在某些硬件上运行更快——使用 GPU 时 2 的幂次批量大小(如 32 到 256,16 有时用于大模型)通常有更优的运行时间;(5)小批量能带来正则化效应(Wilson and Martinez, 2003),可能因其给学习过程带来噪声——批量大小为 1 时泛化误差往往最好;用如此小的批量训练时为保持稳定性需要小的学习率(因为梯度估计方差大),而总运行时间可能很高——既因学习率小、又因需更多步才能遍历整个训练集。不同算法对 minibatch 中信息的利用方式不同。有些算法对采样误差更敏感——要么因为它们使用的信息难以用少样本精确估计,要么因为它们使用信息的方式放大了采样误差。仅基于梯度 \(g\) 计算更新的方法通常比较稳健、能处理 100 这样较小的批量;用 Hessian 矩阵 \(H\) 计算 \(H^{-1} g\) 这类更新的二阶方法通常需要 10000 这样大得多的批量,这些大批量对最小化 \(H^{-1} g\) 估计的波动是必要的。即便 \(H\) 被完美估计但条件数较差,乘以 \(H\) 或 \(H^{-1}\) 也会放大 \(g\) 中已存在的误差;\(g\) 估计的极小变化能导致 \(H^{-1} g\) 的更新大幅变化,即使 \(H\) 被完美估计。当然 \(H\) 只能被近似估计,所以 \(H^{-1} g\) 还会包含比"在 \(g\) 估计上应用病态运算"所预期的更多误差。Minibatch 必须被随机选取——从一组样本中计算期望梯度的无偏估计要求这些样本独立。我们也希望两次相邻的梯度估计彼此独立,所以两次相邻的 minibatch 也应彼此独立。许多数据集天然以"相邻样本高度相关"的方式排列,例如一个医疗数据集可能按患者顺序列出血液样本。若按此顺序抽取 minibatch,每个 minibatch 会主要代表一名患者。在数据顺序有意义的场景下,有必要在选 minibatch 前打乱样本顺序。在包含数十亿样本的非常大数据集上每次都真正均匀随机抽样在实践中可能不可行——通常只须在事前把数据顺序打乱一次并存储下来就能凑合用。这种偏离真正随机选取的做法在实际中没有显示出明显的损害;但从不打乱顺序则会严重降低算法有效性。许多机器学习的优化问题在样本上分解得足够好,使得不同样本的更新可并行计算——也即可以同时对一个 minibatch \(X\) 计算更新 \(J(X)\),同时对其他几个 minibatch 也计算更新。这种异步并行分布式方法在 12.1.3 节进一步讨论。Minibatch 随机梯度下降的一个有趣动机是:只要样本不重复,它实际上在沿真实泛化误差 (8.2) 的梯度方向前进。大多数 minibatch SGD 实现会把数据集打乱一次然后多次遍历。第一次遍历中每个 minibatch 用于计算真实泛化误差的无偏估计;第二次遍历中估计变得有偏,因为它由已用过的样本再采样形成,而非从数据生成分布中抽取新的公平样本。在样本从不重复的在线学习情形下随机梯度下降最小化泛化误差最容易看出:每个 (x, y) 都从 \(p_{\text{data}}\) 取得,每次经历都是 \(p_{\text{data}}\) 的公平样本。当 \(x\) 与 \(y\) 都是离散时,泛化误差 (8.2) 可写为求和
其精确梯度为
对数似然情况下 8.5 和 8.6 已示同一事实;该结论对似然以外的损失函数 \(L\) 同样成立。\(x\) 与 \(y\) 连续时也可在关于 \(p_{\text{data}}\) 与 \(L\) 的温和假设下推得类似结果。因此可从数据生成分布 \(p_{\text{data}}\) 中抽取一个 minibatch 样本 \(\{x^{(1)}, \ldots, x^{(m)}\}\) 及对应目标 \(y^{(i)}\),并计算该 minibatch 上损失关于参数的梯度,得到精确泛化误差梯度的无偏估计
沿 \(\hat{g}\) 方向更新 \(\theta\) 即对泛化误差执行 SGD。该解释只在样本不被重复使用时才成立。实践中通常最好对训练集做若干遍(除非训练集极大),但只有第一遍沿泛化误差的无偏梯度;后续遍虽然因训练误差下降提供的收益通常足以抵消训练-测试误差差距扩大的损害。当数据集增大速度超过算力时,每个训练样本只使用一次甚至对训练集做一次不完整遍历的情形越来越普遍。在极大训练集下过拟合不再是问题,欠拟合与计算效率成为主要考量。Bottou and Bousquet (2008) 讨论了样本数增长时计算瓶颈对泛化误差的影响。
8.2 神经网络优化中的挑战(Challenges in Neural Network Optimization)
一般而言优化是极其困难的任务。传统上机器学习通过精心设计目标函数和约束来回避一般优化的困难,使问题成为凸问题。但训练神经网络时我们必须面对一般的非凸情形。即便凸优化也并非毫无复杂性。本节总结若干训练深度模型时最突出的优化挑战。
8.2.1 病态(Ill-Conditioning)
即便优化凸函数也存在挑战,其中最突出的是 Hessian 矩阵 \(H\) 的病态问题。这是大多数数值优化(无论凸与否)中的一个非常一般的问题,详见 4.3.1 节。病态问题在神经网络训练中普遍存在,其表现之一是使 SGD"卡住"——即便极小的步长也会增加代价函数。由 (4.9) 式的二阶 Taylor 展开可知,梯度下降一步 \(-\epsilon g\) 大致会给代价带来
的增量。当 \(\frac{1}{2} \epsilon^2 g^{\top} H g\) 超过 \(\epsilon g^{\top} g\) 时梯度的病态就成为问题。要判断病态是否对神经网络训练有害,可监测 \(g^{\top} g\) 与 \(g^{\top} H g\)。在很多情形下梯度范数在学习过程中并未显著缩小,但 \(g^{\top} H g\) 增长一个数量级以上。结果是尽管存在强梯度,学习却变得很慢——必须把学习率缩小以补偿更强的曲率。图 8.1 给出一个神经网络成功训练中梯度显著增大的例子。病态在神经网络训练之外的其他场合也存在,但用于其他场合的某些技术在神经网络中并不太适用。例如牛顿法是处理具有病态 Hessian 矩阵的凸函数的极佳工具,但作者在后续章节中将论证牛顿法需重大修改才能用于神经网络。
8.2.2 局部极小(Local Minima)
凸优化问题最显著的特征之一是它可以归约为寻找局部极小——任何局部极小都保证是全局极小;一些凸函数在底部有一段平台而非单点全局极小,但平台上任何点都是可接受解。优化凸函数时,只要找到任意临界点就已知找到了好解。对于非凸函数(如神经网络),可能有许多局部极小。事实上几乎任何深度模型都必然有极其大量的局部极小。然而作者指出这并不一定是主要问题。神经网络和任何含多个等价参数化潜变量的模型都因模型可识别性问题而具有多个局部极小。所谓"模型可识别"是指足够大的训练集能排除除一种以外的所有参数设置。含潜变量的模型常不可识别,因为交换潜变量位置可得到等价模型。例如把神经网络第 1 层单元 \(i\) 的入向权向量与单元 \(j\) 的入向权向量交换,再对出向权向量做同样交换即可。若有 \(m\) 层、每层 \(n\) 个单元,则有 \(n!^m\) 种隐藏单元排列方式。这种不可识别性称为权重空间对称性(weight space symmetry)。除权重空间对称性外,许多神经网络还有额外的不可识别性来源。例如在任何 ReLU 或 maxout 网络中,可把某单元的所有入向权重和偏置乘以 \(\alpha\) 同时把所有出向权重乘以 \(1/\alpha\)——这意味着若代价函数不包含像权重衰减那样直接依赖权重(而非模型输出)的项,则 ReLU 或 maxout 网络的每个局部极小都坐落在一条 \((m \times n)\) 维双曲线上、由等价的局部极小构成。这些可识别性问题意味着神经网络代价函数中可能有极其大量甚至不可数无穷多的局部极小。但所有由不可识别性产生的局部极小在代价函数值上彼此等价,因此它们并非严重的非凸性问题。若局部极小具有比全局极小更高的代价,则它才成为问题。可以构造不含隐藏单元的小型神经网络使其拥有代价高于全局极小的局部极小(Sontag and Sussman 1989;Brady et al. 1989;Gori and Tesi 1992)。如果高代价局部极小很常见,则对基于梯度的优化算法将是严重问题。但实际感兴趣的网络是否存在许多高代价局部极小、优化算法是否真会遇到它们仍是开放问题。多年来多数实践者相信局部极小是神经网络优化的常见麻烦;今天看来似乎并非如此。该问题仍是活跃研究方向,但专家们现在推测:对足够大的神经网络而言,大多数局部极小都具有低代价函数值,重要的是找到参数空间中代价低但非极小的点而非真正的全局极小(Saxe et al. 2013;Dauphin et al. 2014;Goodfellow et al. 2015;Choromanska et al. 2014)。许多实践者把神经网络优化的几乎所有困难都归咎于局部极小。作者鼓励实践者仔细排查具体问题。能排除局部极小作为问题的检验方法是绘制梯度范数随时间变化曲线——若梯度范数并不缩小到可以忽略的程度,则问题既非局部极小也非任何其他类型的临界点。这种反向检验可以排除局部极小。在高维空间中很难正向确认局部极小就是问题——许多其他结构也具有小梯度。
8.2.3 平台、鞍点与其他平坦区域(Plateaus, Saddle Points and Other Flat Regions)
对许多高维非凸函数,局部极小(以及极大)实际上比另一种零梯度点——鞍点——更罕见。鞍点周围有些点代价更高,有些更低。在鞍点处 Hessian 矩阵既有正特征值也有负特征值:沿正特征值对应特征向量方向的点代价高于鞍点,沿负特征值方向的点代价更低。可把鞍点视为沿某个截面是局部极小、沿另一截面是局部极大。见图 4.5 示意。许多类随机函数表现出以下行为:低维空间中局部极小常见,高维空间中局部极小罕见而鞍点更常见。对从 \(\mathbb{R}^n\) 到 \(\mathbb{R}\) 的此类函数 \(f\),鞍点数与局部极小数的期望比随 \(n\) 指数级增长。直观理解:局部极小处 Hessian 只有正特征值,鞍点处 Hessian 正负特征值都有。想象每个特征值的符号由抛硬币决定。一维时抛一次硬币就得到局部极小(正面)很容易;\(n\) 维时 \(n\) 次硬币全是正面的概率指数级地小。详见 Dauphin et al. (2014) 对相关理论工作的综述。许多随机函数的一个惊人性质是 Hessian 特征值在我们到达代价更低的区域时更可能为正——在硬币类比中,处于低代价临界点时抛 \(n\) 次都是正面的概率更大。这意味着局部极小更可能具有低代价,而高代价临界点更可能是鞍点。极高代价临界点更可能是局部极大。许多类随机函数都满足这一性质。神经网络是否也如此?Baldi and Hornik (1989) 在理论上证明:不含非线性、训练把输入复制为输出的浅自编码器(前馈网络,第 14 章)具有全局极小与鞍点,但没有代价高于全局极小的局部极小。他们未经证明地观察该结果可推广到更深的不含非线性网络;这样的网络输出是输入的线性函数,但因为代价函数是参数的非凸函数而成为研究非线性神经网络的有用模型——本质上是多个矩阵的复合。Saxe et al. (2013) 给出了这种网络完整学习动力学的精确解,并显示这些模型的学习能捕捉带非线性激活函数的深度模型训练中所观察到的许多定性特征。Dauphin et al. (2014) 实验显示真实神经网络也具有含非常多高代价鞍点的损失函数。Choromanska et al. (2014) 给出额外理论论证,显示另一类与神经网络相关的高维随机函数也如此。鞍点的扩散对训练算法意味着什么?对仅用梯度信息的一阶优化算法情况尚不明朗:鞍点附近梯度常变得很小,但经验上梯度下降在许多情况下似乎能逃离鞍点。Goodfellow et al. (2015) 对若干当时最先进神经网络的学习轨迹做了可视化(图 8.2),这些可视化显示代价函数在权重全为零处一个显著鞍点附近出现平坦化,但梯度下降轨迹也能迅速逃离该区域。Goodfellow et al. (2015) 还论证连续时间梯度下降在分析上可被证明是受附近鞍点排斥而非吸引,但更现实地使用梯度下降时情况可能不同。对牛顿法而言鞍点构成明显问题——梯度下降被设计成"下坡移动",不显式地寻找临界点;牛顿法却被设计成求解梯度为零的点,不做适当修改时会跳到鞍点。高维空间中鞍点的扩散或许解释了为什么二阶方法没有成功取代梯度下降用于神经网络训练。Dauphin et al. (2014) 引入无鞍牛顿法做二阶优化并显示它显著优于传统版本。二阶方法要扩展到大神经网络仍很困难,但这种无鞍方法若可扩展则前景广阔。零梯度点除极小和鞍点外还有其他类型。极大点从优化角度看与鞍点类似——许多算法不被它们吸引但未修改的牛顿法会被吸引。许多类随机函数的极大点在高维空间中也指数级罕见,与极小一样。也可能存在很宽的平坦常值区域——这些位置梯度和 Hessian 都为零——会对所有数值优化算法造成大麻烦。凸问题中宽平坦区域必全由全局极小构成,但一般优化问题中这类区域可能对应高目标值。
8.2.4 悬崖与梯度爆炸(Cliffs and Exploding Gradients)
具有很多层的神经网络常在参数空间中出现类似悬崖的极陡区域(图 8.3)。它们由多个大权重相乘产生。在极陡悬崖结构的表面,梯度更新步会把参数推得极远——通常直接跳离悬崖结构。从悬崖之上或之下接近它都会有危险,但幸运的是用 10.11.1 节描述的梯度截断启发法可避免其最严重后果。基本思想是:梯度只指定无穷小区域内的最优方向,不指定最优步长;当传统梯度下降建议走很大一步时,梯度截断启发法会介入把步长缩减到足够小,使其不太可能走出梯度所指近似最陡下降方向的区域。悬崖结构在循环神经网络的代价函数中最常见——因为这类模型涉及许多因子的相乘,每一时间步一个因子,长时间序列因此带来极端的乘法深度。
8.2.5 长期依赖(Long-Term Dependencies)
神经网络优化算法必须克服的另一种困难出现在计算图极深时。具有很多层的前馈网络有非常深的计算图;循环网络(第 10 章)也通过在长时间序列的每一步重复应用相同操作而构造出非常深的计算图。重复使用相同参数会引起特别突出的困难。设想计算图中有一条由反复乘以矩阵 \(W\) 组成的路径——\(t\) 步后等价于乘以 \(W^t\)。设 \(W\) 有特征分解 \(W = V \operatorname{diag}(\lambda) V^{-1}\),易得
任何幅值不接近 1 的特征值 \(\lambda_i\),若幅值大于 1 就会爆炸、若幅值小于 1 就会消失。消失和爆炸梯度问题指的就是这样的图中梯度也按 \(\operatorname{diag}(\lambda)^t\) 缩放。消失梯度让我们难以知道参数应朝哪个方向移动以改善代价函数;爆炸梯度则使学习变得不稳定。前文描述的激励梯度截断的悬崖结构是爆炸梯度现象的一个例子。每一时间步重复乘 \(W\) 的过程与求矩阵 \(W\) 最大特征值及对应特征向量的幂法算法非常相似。从这一观点看 \(x^{\top} W^t\) 最终会丢掉 \(x\) 中与 \(W\) 主特征向量正交的所有分量就不足为奇了。循环网络在每一步使用同一矩阵 \(W\),前馈网络则不是——所以即便很深的纯前馈网络也能基本避免消失和爆炸梯度问题(Sussillo, 2014)。关于循环网络训练困难的进一步讨论推迟到 10.7 节,等循环网络细节展开后。
8.2.6 不精确梯度(Inexact Gradients)
多数优化算法在设计时假设我们可以访问精确梯度或 Hessian 矩阵。实践中我们通常只有这些量的有噪声甚至有偏的估计。几乎所有深度学习算法至少在使用一个 minibatch 训练样本来计算梯度这点上都依赖基于采样的估计。另一些情形下我们想要最小化的目标函数本身不可解——目标不可解时其梯度通常也不可解,此时我们只能近似梯度。这些问题主要出现在第三部分更高级的模型中——例如对比散度给出了近似 Boltzmann 机不可解对数似然梯度的技术。多种神经网络优化算法被设计成能容忍梯度估计中的不完美;也可以通过选择比真实损失更易近似的代理损失来回避问题。
8.2.7 局部与全局结构的不对应(Poor Correspondence between Local and Global Structure)
前文讨论的许多问题对应损失函数在单点处的性质——若 \(J(\theta)\) 在当前点 \(\theta\) 处病态、\(\theta\) 处于悬崖上、或 \(\theta\) 处于隐藏了下山机会的鞍点,单步就可能很困难。即便在单点处克服了所有这些问题,若局部最速改进的方向并不指向更远处代价低得多的区域,仍可能表现很差。Goodfellow et al. (2015) 论证训练的许多运行时间花在到达解所需的轨迹长度上——图 8.2 显示学习轨迹大部分时间绕一座山形结构走出宽阔的弧线。许多研究优化的困难都聚焦于训练是否到达全局极小、局部极小或鞍点,但实践中神经网络并不到达任何类型的临界点。图 8.1 显示神经网络通常并不到达梯度小的区域——这种临界点甚至不一定存在。例如损失函数 \(-\log p(y \mid x; \theta)\) 可能不存在全局极小点,而是随模型变得更自信而渐近逼近某值。对离散 \(y\)、\(p(y \mid x)\) 由 softmax 提供的分类器,若模型能正确分类训练集中所有样本则负对数似然可任意接近零但永远无法达到零。类似地,\(p(y \mid x) = \mathcal{N}(y; f(\theta), \beta^{-1})\) 的实值模型其负对数似然可渐近到负无穷——若 \(f(\theta)\) 能正确预测训练集所有 \(y\) 目标,学习算法会无限增大 \(\beta\)。图 8.4 给出一个即便不存在任何局部极小或鞍点、局部优化仍找不到好代价函数值的失败例子。未来的研究需要进一步发展对影响学习轨迹长度因素的理解,并更好地刻画过程的结果。许多现有研究方向旨在为具有困难全局结构的问题找到好的初始点,而非开发使用非局部移动的算法。梯度下降以及所有对训练神经网络有效学习算法都基于小的局部移动。前述章节主要关注这些局部移动的正确方向为何难以计算。有些性质(如梯度)只能被近似估计,估计中存在偏差或方差——此时局部下降可能定义不出到达有效解的合理短路径,或者根本不能沿局部下降路径走。目标函数可能有病态或梯度不连续等问题,使梯度能良好建模目标函数的区域非常小——此时局部下降以步长 \(\epsilon\) 可能定义出到达解的合理短路径,但我们只能以步长 \(\delta \ll \epsilon\) 计算局部下降方向——此时局部下降或许仍能定义出到解的路径,但该路径包含很多步,走完整条路径需要高计算成本。有时局部信息无法提供指引,例如函数具有宽平坦区域、或我们恰好落在临界点上(后者通常只发生在显式求解临界点的方法如牛顿法上)——此时局部下降根本定义不到达解的路径。其他情形下局部移动可能过于贪婪,把我们引到一条沿下坡移动但远离任何解的路径上(图 8.4),或沿一条到解的不必要长轨迹(图 8.2)。目前我们还不理解上述哪些问题对使神经网络优化困难最相关,这是活跃研究方向。无论哪些问题最显著,若参数空间中存在一块区域能通过一条局部下降可循的路径与解合理直接相连、且我们能将学习初始化到该良好区域,则所有问题都可能被回避。这一观点指向研究为传统优化算法选择好的初始点。
8.2.8 优化的理论极限(Theoretical Limits of Optimization)
若干理论结果显示我们可能为神经网络设计的任何优化算法都存在性能极限(Blum and Rivest 1992;Judd 1989;Wolpert and MacReady 1997)。这些结果通常对实践中的神经网络使用影响很小。有些理论结果仅适用于神经网络单元输出离散值的情形;然而多数神经网络单元输出平滑递增的值,使基于局部搜索的优化可行。有些理论结果显示存在不可解的问题类,但要判断一个具体问题是否属于该类很难。另一些结果显示对给定大小的网络找解是不可解的,但实践中我们可以通过使用更大的网络(更多参数设置对应可接受解)来轻松找到解。此外神经网络训练中我们通常并不关心找到函数精确极小,而只寻求把函数值降低到足以得到好的泛化误差。对优化算法能否达到此目标的理论分析极其困难;为优化算法性能发展更现实的界仍是机器学习研究的重要目标。
8.3 基本算法(Basic Algorithms)
作者此前介绍了沿整个训练集梯度下山的梯度下降算法(4.3 节);该算法可被随机梯度下降沿随机选取的 minibatch 的梯度下山而大幅加速(5.9 与 8.1.3 节)。
8.3.1 随机梯度下降(Stochastic Gradient Descent)
随机梯度下降(SGD)及其变体可能是机器学习(特别是深度学习)中最常用的优化算法。如 8.1.3 节所述,从数据生成分布独立同分布采样的 \(m\) 个样本组成的 minibatch 上梯度平均可给出梯度的无偏估计。算法 8.1 给出沿该估计下山的步骤(采样 minibatch → 计算梯度估计 \(\hat{g} \leftarrow +\frac{1}{m} \nabla_{\theta} \sum_i L(f(x^{(i)}; \theta), y^{(i)})\) → 更新 \(\theta \leftarrow \theta - \epsilon \hat{g}\))。SGD 的一个关键参数是学习率——此前我们把 SGD 描述为使用固定学习率 \(\epsilon\);实践中学习率必须随时间逐渐下降,所以我们把第 \(k\) 次迭代的学习率记为 \(\epsilon_k\)。这是因为 SGD 梯度估计带来一个噪声源(\(m\) 个训练样本的随机采样),即便到达极小点也不会消失。相比之下,批梯度下降中总代价函数的真实梯度在接近并到达极小点时会变小并变为 0,所以批梯度下降可用固定学习率。SGD 收敛的一个充分条件是
实践中学习率常在 \(\tau\) 次迭代前线性衰减:
其中 \(\alpha = k/\tau\);\(\tau\) 之后 \(\epsilon\) 常保持不变。学习率可通过试错选择,但通常最好通过监测学习曲线(目标函数随时间变化)来选。这更多是艺术而非科学,该主题的多数指导都应被略带怀疑地看待。使用线性计划时要选的参数是 \(\epsilon_0\)、\(\epsilon_\tau\) 与 \(\tau\)。\(\tau\) 通常设为需要对训练集做几百遍所需的迭代次数;\(\epsilon_\tau\) 通常设为 \(\epsilon_0\) 约 1% 的值。主要问题在于如何设 \(\epsilon_0\):若太大学习曲线会出现剧烈震荡、代价函数经常显著上升;温和的震荡则无妨——尤其在使用 dropout 之类带来随机代价函数时。若学习率太小学习进展缓慢,若初始学习率太小则学习可能卡在高代价值上。通常从总训练时间和最终代价值看,最优初始学习率比前 100 次迭代左右表现最好的学习率更高——因此通常最好监测前几次迭代,使用一个比当时表现最好的学习率更高、但又不会引起严重不稳定的值。SGD 及相关 minibatch / 在线梯度优化最重要的性质是每次更新的计算时间不随训练样本数增长——这使它即便训练样本数极大也能收敛。对足够大的数据集,SGD 可能在处理完整个训练集前就收敛到距最终测试集误差的某个固定容差内。优化算法收敛率研究中常测量的量是过量误差 \(J(\theta) - \min_{\theta} J(\theta)\)。SGD 用于凸问题时过量误差在 \(k\) 次迭代后为 \(O(1/\sqrt{k})\),强凸情形为 \(O(1/k)\)。这些界在不附加假设时不可改进。批梯度下降理论上比 SGD 有更好的收敛率——但 Cramér-Rao 下界(Cramér 1946;Rao 1945)指出泛化误差不能以快于 \(O(1/k)\) 的速度下降。Bottou and Bousquet (2008) 论证对机器学习任务而言追求比 \(O(1/k)\) 更快的优化算法可能得不偿失——更快的收敛可能对应过拟合。此外渐近分析掩盖了 SGD 在少量步数后的许多优势。对大数据集而言,SGD 在仅评估极少量样本的梯度时就能取得快速初始进展的能力,胜过其慢的渐近收敛。本章余下介绍的大多数算法在实践中能带来真实益处,但都被 \(O(1/k)\) 渐近分析掩盖的常数因子埋没。也可以在训练过程中逐渐增大 minibatch 大小,从而兼顾批与随机梯度下降两者的优点。更多 SGD 信息见 Bottou (1998)。
8.3.2 动量(Momentum)
虽然随机梯度下降仍是极常用的优化策略,用它学习有时会很慢。动量法(momentum, Polyak 1964)被设计来加速学习——尤其在面临高曲率、小但一致的梯度、或噪声梯度时。动量算法累积过去梯度的指数衰减移动平均并沿其方向继续前进。动量效果见图 8.5。形式上,动量算法引入变量 \(v\) 起速度(velocity)作用——即参数在参数空间中移动的方向和速度。速度被设为过去负梯度的指数衰减平均。"动量"之名源于物理类比:负梯度是把粒子在参数空间中推动的力,遵循牛顿运动定律。物理中的动量是质量乘以速度;在动量学习算法中我们假设单位质量,所以速度向量 \(v\) 也可视为粒子的动量。超参数 \(\alpha \in [0, 1)\) 决定之前梯度贡献指数衰减的速度。更新规则为
速度 \(v\) 累积梯度元素 \(\nabla_{\theta} \frac{1}{m} \sum_{i=1}^m L(f(x^{(i)}; \theta), y^{(i)})\)。\(\alpha\) 相对 \(\epsilon\) 越大,之前梯度对当前方向的影响越大。带动量的 SGD 算法见算法 8.2(采样 minibatch → 计算梯度估计 \(g \leftarrow \frac{1}{m} \nabla_{\theta} \sum_i L \to\) 计算速度更新 \(v \leftarrow \alpha v - \epsilon g\) → 更新 \(\theta \leftarrow \theta + v\))。之前步长只是梯度范数乘以学习率;现在步长大小取决于一连串梯度的大小和方向。步长在许多连续梯度指向完全相同方向时最大。若动量算法总观察到梯度 \(g\),则它将沿 \(-g\) 方向加速直至到达终止速度——每步大小为
因此从 \(1/(1-\alpha)\) 角度理解动量超参数是有帮助的:例如 \(\alpha = 0.9\) 相当于把最大速度乘以 10(相对梯度下降)。实践中 \(\alpha\) 的常用值包括 .5、.9、.99。像学习率一样 \(\alpha\) 也可随时间调整——通常从较小值开始后增大;调整 \(\alpha\) 不如缩小 \(\epsilon\) 重要。我们可以把动量算法视为模拟一个受连续时间牛顿动力学作用的粒子,物理类比有助于建立动量与梯度下降算法行为的直观理解。粒子在任意时刻的位置由 \(\theta(t)\) 给出,粒子受净力 \(f(t)\)。该力使粒子加速:
与其把它视为位置的二阶微分方程,可引入变量 \(v(t)\) 表示粒子在时刻 \(t\) 的速度,把牛顿动力学改写为一阶微分方程组:
动量算法本质是用数值模拟解这些微分方程。一种简单数值方法是 Euler 法,即在每步沿各梯度方向取小的有限步长以模拟由方程定义的动力学。这解释了动量更新的基本形式,但具体"力"是什么?一种力与代价函数负梯度 \(-\nabla_{\theta} J(\theta)\) 成正比——它把粒子沿代价函数表面向下推。梯度下降算法对每个梯度只走一步,动量算法使用的牛顿场景则用这个力来改变粒子的速度。可把粒子想成在冰面上滑动的冰球——每当它滑到陡峭部分就会加速并继续沿该方向滑行直到开始上坡。还需另一种力。若唯一力是代价函数的梯度,粒子可能永远不停——想象冰球滑下谷底一侧又直接冲上另一侧,在完全无摩擦的冰面上永远来回震荡。为解决这个问题,引入另一种力,比例于 \(-v(t)\)。物理术语中这种力对应粘性阻力(viscous drag),就像粒子必须在糖浆这样的阻力介质中推进——它使粒子逐渐失能并最终收敛到局部极小。为什么选 \(-v(t)\) 和粘性阻力?部分原因是数学便利——速度的整数次幂易于处理。但其他物理系统也有基于速度其他整数次幂的其他阻力。例如空气中的粒子受到湍流阻力(turbulent drag),力与速度平方成正比;地面运动的粒子受干摩擦(dry friction),力大小恒定。我们可逐个排除:湍流阻力(速度平方)在速度小时变得很弱,不足以迫使粒子停下——非零初速度的粒子只受湍流阻力时会永远远离起点,到起点距离 \(O(\log t)\) 增长。所以必须用更小次幂的速度。若用零次幂(干摩擦),力又过强——当代价函数梯度力小但非零时,恒定摩擦力会使粒子在到达局部极小前停下。粘性阻力避免这两个问题——它弱到梯度仍可推动运动直到到达极小,但又强到在没有足够梯度时不引发运动。
8.3.3 Nesterov 动量(Nesterov Momentum)
Sutskever et al. (2013) 引入动量算法的一个变体,灵感来自 Nesterov 加速梯度法(Nesterov 1983, 2004)。其更新规则为
其中 \(\alpha\) 与 \(\epsilon\) 起到与标准动量法中类似的作用。Nesterov 动量与标准动量的差别在于梯度评估的位置:Nesterov 动量在施加当前速度之后再评估梯度,因此可被理解为对标准动量法加上一个校正因子。完整 Nesterov 动量算法见算法 8.3(采样 minibatch → 临时更新 \(\tilde{\theta} \leftarrow \theta + \alpha v\) → 在临时点计算梯度 \(g \leftarrow \frac{1}{m} \nabla_{\tilde{\theta}} \sum_i L \to\) 速度更新 \(v \leftarrow \alpha v - \epsilon g\) → 更新 \(\theta \leftarrow \theta + v\))。在凸批梯度情形下,Nesterov 动量把过量误差的收敛率从 \(O(1/k)\) 提升到 \(O(1/k^2)\)(Nesterov 1983)。遗憾的是在随机梯度情形下 Nesterov 动量并不提升收敛率。
8.4 参数初始化策略(Parameter Initialization Strategies)
一些优化算法本质上非迭代,直接求解解点;其他算法本质上迭代,但对适当类的优化问题无论初始化如何都能在可接受时间内收敛到可接受的解。深度学习训练算法通常不具有这两项便利。深度模型的训练算法本质上迭代,因此要求用户指定迭代的初始起点;且训练深度模型是足够困难的任务,以至于多数算法对初始化选择都很敏感。初始点可决定算法是否能收敛——某些初始点极度不稳定,算法会遇到数值困难并彻底失败。学习若能收敛,初始点也决定学习收敛速度以及收敛到高代价还是低代价的点。代价相近的点可能在泛化误差上有天壤之别,初始点也能影响泛化。现代初始化策略是简单且启发式的。设计更好的初始化策略很困难,因为神经网络优化本身尚未被充分理解。多数初始化策略基于在网络被初始化时获得某些好的性质。但我们并不清楚这些性质在哪些条件下能在学习开始后被保留。一个更深的困难是有些初始点从优化角度看有利但从泛化角度看有害。我们对初始点如何影响泛化的理解尤为初步,对如何选择初始点几乎不提供指导。或许唯一能完全确定地知道的性质是初始参数需要"打破对称性"——若两个具有相同激活函数的隐藏单元被连接到相同输入,则它们必须具有不同的初始参数。若初始参数相同,确定性学习算法应用于确定性代价和模型时会一直以相同方式更新两个单元。即便模型或训练算法(如使用 dropout)能利用随机性为不同单元计算不同更新,通常也最好初始化每个单元使它与其他所有单元计算不同函数。这有助于确保没有输入模式在前向传播的零空间丢失、没有梯度模式在反向传播的零空间丢失。让每个单元计算不同函数的目标推动了参数的随机初始化。可以显式搜索一个所有基函数都互不相同的大集合,但这通常带来明显的计算代价——例如若输出数不超过输入数,可对初始权重矩阵做 Gram-Schmidt 正交化以保证每个单元都计算与其他单元极不同的函数。从高维空间上的高熵分布随机初始化计算上更便宜、且不太可能给任何单元分配与其他单元相同的函数。实践中我们通常把每个单元的偏置设为启发式选定的常数,只对权重做随机初始化。额外参数(如编码预测条件方差的参数)通常也类似偏置那样设为启发式常数。我们几乎总是把模型中所有权重初始化为从高斯或均匀分布采样的值。选择高斯或均匀分布似乎影响不大,但尚未被详尽研究。初始分布的尺度对优化过程的结果以及网络的泛化能力都有很大影响。较大初始权重带来更强的对称打破效应、帮助避免冗余单元——也帮助避免在前向或反向通过每层线性部分时信号丢失(矩阵中较大值在矩阵乘法后产生较大输出)。但过大的初始权重在前向或反向传播中可能造成值爆炸。在循环网络中大权重也可能导致混沌(对输入极小扰动极度敏感、确定性前向传播表现出随机行为)。爆炸梯度问题在一定程度上可被梯度截断(在做梯度下降步前对梯度值做阈值化)缓解。大权重也可能造成极端值使激活函数饱和、引起饱和单元完全失去梯度。这些相互制约的因素决定理想初始权重尺度。优化和正则化视角对如何初始化网络给出截然不同的洞见。优化视角认为权重应大到足以成功传播信息,但某些正则化顾虑鼓励把权重设小。SGD 这类对权重做小增量改变、并倾向于停在靠近初始参数区域的优化算法(无论是因为被困在低梯度区域、还是因为触发了基于过拟合的提前停止准则)表达了一个先验——最终参数应接近初始参数。回顾 7.8 节,对某些模型带提前停止的梯度下降等价于权重衰减。一般情形下带提前停止的梯度下降虽不等同于权重衰减,但提供了一个类比来思考初始化效应。可把把参数 \(\theta\) 初始化为 \(\theta_0\) 视为类似对参数施加均值为 \(\theta_0\) 的高斯先验 \(p(\theta)\)。从这一观点看把 \(\theta_0\) 选在 0 附近是合理的。该先验说单元之间不相互作用比相互作用更可能;只有当目标函数的似然项表达了对它们相互作用的强烈偏好时它们才会相互作用。反之若把 \(\theta_0\) 初始化为大值,则先验指定了哪些单元应相互作用以及如何相互作用。若干启发式可用于选择初始权重的尺度。一种启发式是对有 \(m\) 个输入、\(n\) 个输出的全连接层把每个权重从 \(U(-1/\sqrt{m}, 1/\sqrt{m})\) 采样;Glorot and Bengio (2010) 建议用归一化初始化
后者启发式设计成在"所有层具有相同激活方差"和"所有层具有相同梯度方差"两个目标之间折中。公式推导假设网络只由一串矩阵乘法组成,不含非线性。真实神经网络显然违反该假设,但许多为线性模型设计的策略在其非线性对应物上也表现不错。Saxe et al. (2013) 建议初始化为随机正交矩阵,配以一个仔细选择的尺度或增益因子 \(g\) 以考虑每层所施加的非线性。他们为不同类型的非线性激活函数推导出具体的尺度因子值。该初始化方案也由"深度网络为不含非线性的矩阵乘法序列"模型驱动;在这种模型下该方案保证到达收敛所需的总训练迭代数与深度无关。增大尺度因子 \(g\) 把网络推向"激活在前向传播中范数增大、梯度在反向传播中范数增大"的区域。Sussillo (2014) 表明正确设置增益因子足以训练深度达 1000 层的网络,无需使用正交初始化。该方法的一个关键洞见是前馈网络中激活与梯度可在前向或反向传播每步按随机游走行为增长或缩小——因为前馈网络在每层使用不同权重矩阵。若该随机游走被调成保持范数,则前馈网络可基本避免同一权重矩阵在每步使用时出现的消失/爆炸梯度问题(8.2.5 节)。可惜这些对初始权重的最优准则往往并不带来最优性能。原因可能有三:(1)我们可能用了错误准则——在整个网络中保持信号范数未必真有益处;(2)初始化时所施加的性质在学习开始后未必被保留;(3)准则可能在提升优化速度的同时意外增大泛化误差。实践中我们通常需把权重尺度当作超参数,最优值大致接近但不完全等于理论预测值。把所有初始权重都设为同一标准差(如 \(1/\sqrt{m}\))的尺度规则有一缺点:层变大时每个单独权重都变得极小。Martens (2010) 引入一种称为稀疏初始化(sparse initialization)的替代方案:每个单元被初始化为恰好有 \(k\) 个非零权重。其思想是让单元的输入总量独立于输入数 \(m\) 而不使单个权重元素的幅值随 \(m\) 缩小。稀疏初始化有助于在初始化时让各单元之间更多样,但也对被选为大高斯值的权重施加了很强的先验。因为梯度下降缩小"不正确"的大值需要很长时间,这种初始化方案对 maxout 单元这种含多个必须相互协调的滤波器的单元会造成问题。当计算资源允许时通常最好把每层权重的初始尺度当作超参数,并用 11.4.2 节描述的超参数搜索算法(如随机搜索)来选这些尺度。使用密集还是稀疏初始化的选择也可作为超参数。也可手动搜索最佳初始尺度。一个选择初始尺度的好经验法则是看单个 minibatch 数据上激活或梯度的范围或标准差。若权重过小,激活范围在 minibatch 沿前向传播通过网络时会缩小。反复识别首个具有不可接受小激活的层并增大其权重,最终可获得整个网络都具有合理初始激活的网络。若此时学习仍太慢,看梯度的范围或标准差以及激活也会有用。该过程原则上可被自动化,并且通常比基于验证集误差的超参数优化计算代价低——因为它基于初始模型在单批数据上行为的反馈,而非基于训练模型在验证集上的反馈。这一协议虽然长期作为启发式使用,但 Mishkin and Matas (2015) 近期给出了更形式化指定与研究。迄今我们关注的是权重的初始化;其他参数的初始化通常更简单。偏置的设置方法必须与权重的设置方法协调。把偏置设为 0 与多数权重初始化方案兼容。有几种情形会把某些偏置设为非零值:(1)若偏置是输出单元的偏置,则把它初始化为获得输出正确的边缘统计量通常是有益的。为此假设初始权重足够小、单元输出仅由偏置决定。这就把偏置设为反激活函数作用于训练集输出边缘统计量。例如若输出是类别上的分布,且该分布是一个高度偏斜的分布,类别 \(i\) 的边缘概率由某向量 \(c\) 的元素 \(c_i\) 给出,则可解方程 \(\text{softmax}(b) = c\) 设置偏置向量 \(b\)。这不仅适用于分类器,也适用于第三部分会遇到的模型(自编码器、Boltzmann 机)——这些模型有输出应与输入数据 \(x\) 相似的层,把这些层的偏置初始化为匹配 \(x\) 的边缘分布很有帮助。(2)有时为避免在初始化时引起太多饱和会希望选择偏置。例如 ReLU 隐藏单元的偏置可设为 0.1 而非 0,以避免 ReLU 在初始化时饱和。该做法与不希望强偏置输入的权重初始化方案不兼容——例如不推荐与随机游走初始化(Sussillo 2014)一起使用。(3)有时某单元控制其他单元是否能参与某函数。在这种情形下有一个输出为 \(u\) 的单元和另一个 \(h \in [0, 1]\) 的单元,两者相乘产生输出 \(uh\)。可把 \(h\) 视为门,决定 \(uh \approx u\) 还是 \(uh \approx 0\)。这种情形下希望把 \(h\) 的偏置设为使 \(h\) 在初始化时大多数时候接近 1——否则 \(u\) 没有学习机会。例如 Jozefowicz et al. (2015) 主张把 LSTM 模型(10.10 节)遗忘门的偏置设为 1。另一类常见参数是方差或精度参数。例如用条件方差估计的线性回归可用模型
其中 \(\beta\) 是精度参数。实践中可安全地把方差或精度参数初始化为 1。另一方法是假设初始权重足够接近零以至于设置偏置时可忽略权重效应,然后把偏置设为产生正确的输出边缘均值、把方差参数设为训练集输出的边缘方差。除了这些简单的常数或随机参数初始化方法外,也可以用机器学习来初始化模型参数。本书第三部分讨论的一种常见策略是用相同输入上训练的无监督模型的参数来初始化监督模型。也可在相关任务上做监督训练;甚至在无关任务上做监督训练有时也能给出比随机初始化收敛更快的初始点。这些初始化策略中有些能带来更快收敛和更好泛化是因为它们在模型初始参数中编码了关于分布的信息;其他明显表现好主要是因为它们把参数设为合适的尺度或让不同单元彼此计算不同函数。
8.5 自适应学习率算法(Algorithms with Adaptive Learning Rates)
神经网络研究者长期认识到学习率一直是设置起来最困难的超参数之一,因为它对模型性能有显著影响。4.3 与 8.2 节已讨论过代价对参数空间某些方向常高度敏感而对其他方向不敏感。动量算法能部分缓解这些问题,但代价是引入另一个超参数。在这种背景下自然会问是否有别的方法。如果我们认为敏感性的方向大致沿坐标轴排列,那么对每个参数使用单独的学习率并在学习过程中自动调整它们就是有意义的。Delta-bar-delta 算法(Jacobs 1988)是一种早期启发式方法,在训练时为每个模型参数适应学习率。其基本思想:若损失对某参数的偏导数保持同号,则学习率应增大;若偏导数变号,则学习率应减小。当然这种规则只能用于全批优化。近期出现了多种基于增量(或小批量)的方法,可适应模型参数的学习率。本节简要回顾若干这样的算法。
8.5.1 AdaGrad
AdaGrad 算法(算法 8.4)通过让所有模型参数的学习率按其历史平方值之和的平方根的倒数成比例缩放,来分别为它们适应学习率(Duchi et al. 2011)。损失偏导数最大的参数对应其学习率快速下降,偏导数小的参数学习率相对下降较少。整体效果是在参数空间中更平缓的方向取得更大进展。在凸优化语境下 AdaGrad 具有若干理想理论性质。然而经验上发现——对深度神经网络模型训练而言——从训练开始累积的平方梯度会导致有效学习率过早过度下降。AdaGrad 对一些但非所有深度学习模型表现良好。
8.5.2 RMSProp
RMSProp 算法(Hinton 2012)修改 AdaGrad 以在非凸设定下表现更好——把梯度累积改为指数加权移动平均。AdaGrad 被设计成在应用于凸函数时快速收敛。当应用于非凸函数训练神经网络时,学习轨迹可能经过许多不同结构最终到达一个局部凸碗形区域。AdaGrad 按平方梯度的全部历史缩小学习率,可能在到达这种凸结构前已让学习率过小。RMSProp 使用指数衰减平均丢弃极端过去的历史,从而能在找到凸碗后快速收敛——就像在那个碗内被初始化的 AdaGrad 实例。RMSProp 的标准形式见算法 8.5,与 Nesterov 动量组合见算法 8.6。相比 AdaGrad,使用移动平均引入了一个新超参数 \(\rho\) 控制移动平均的长度尺度。经验上 RMSProp 已被证明是神经网络的一种有效且实用的优化算法——它目前是深度学习实践者最常用的优化方法之一。
8.5.3 Adam
Adam(Kingma and Ba 2014)是另一种自适应学习率优化算法,呈现于算法 8.7。名字"Adam"来自"adaptive moments"。在已有算法语境下,它或许可被看作 RMSProp 与动量的组合变体,有若干重要区别。第一,Adam 中的动量被直接实现为梯度一阶矩的指数加权估计。在 RMSProp 上加动量最直接的方式是对再缩放后的梯度施加动量。在再缩放基础上用动量缺乏明确的理论动机。第二,Adam 包含对两个估计的偏差修正——一阶矩(动量项)和(无中心的)二阶矩——以修正它们在原点被初始化的情况(见算法 8.7)。RMSProp 也包含(无中心的)二阶矩估计,但缺少修正因子——因此与 Adam 不同,RMSProp 的二阶矩估计在训练初期可能有高偏差。Adam 一般被认为对超参数选择相当稳健,尽管学习率有时需要从建议默认值调整。
8.5.4 选择正确的优化算法
本节讨论了一系列相关算法,每个都试图通过为每个模型参数适应学习率来应对优化深度模型的挑战。自然的问题是:该选哪个算法?目前没有共识。Schaul et al. (2014) 对大量优化算法在广泛学习任务上做了有价值的对比。结果显示自适应学习率类算法(以 RMSProp 和 AdaDelta 为代表)表现得相当稳健,但并未出现单一最佳算法。目前最流行且活跃使用的优化算法包括 SGD、带动量 SGD、RMSProp、带动量 RMSProp、AdaDelta 和 Adam。选择使用哪种算法目前主要取决于用户对该算法的熟悉程度(便于调超参数)。
8.6 近似二阶方法(Approximate Second-Order Methods)
本节讨论二阶方法在深度网络训练中的应用。详见 LeCun et al. (1998a) 的早期处理。为叙述简洁,我们只考察经验风险目标函数:
不过本节讨论的方法容易推广到包含参数正则化项等更一般的目标函数(第 7 章)。
8.6.1 牛顿法(Newton's Method)
4.3 节介绍了二阶梯度方法。与一阶方法不同,二阶方法利用二阶导数改进优化。最广泛使用的二阶方法是牛顿法。现在更详细地描述牛顿法,重点放在其应用于神经网络训练上。牛顿法是一种基于使用二阶 Taylor 级数展开近似 \(J(\theta)\) 在某点 \(\theta_0\) 附近的形式、忽略更高阶导数的优化方案:
其中 \(H\) 是 \(J\) 关于 \(\theta\) 在 \(\theta_0\) 处求值的 Hessian。求解该函数的临界点得牛顿参数更新规则:
因此对局部二次函数(\(H\) 正定),通过把梯度以 \(H^{-1}\) 再缩放,牛顿法直接跳到极小点。若目标函数凸但非二次(存在高阶项),该更新可被迭代,得到牛顿法训练算法(算法 8.8:计算梯度 \(g \leftarrow \frac{1}{m} \nabla_{\theta} \sum_i L\)、计算 Hessian \(H \leftarrow \frac{1}{m} \nabla_{\theta}^2 \sum_i L\)、计算 \(H^{-1}\)、更新 \(\Delta \theta = -H^{-1} g\)、\(\theta = \theta + \Delta \theta\))。对非二次曲面,只要 Hessian 保持正定牛顿法就可被迭代使用。这意味着一个两步迭代过程:第一步更新或计算逆 Hessian(即更新二次近似),第二步按 (8.27) 更新参数。8.2.3 节曾讨论牛顿法只在 Hessian 正定时才适用。在深度学习中目标函数表面通常非凸且具有许多特征——如鞍点——对牛顿法构成问题。若 Hessian 特征值并不全为正,例如靠近鞍点时,牛顿法实际上可能使更新朝错误方向移动。该情形可通过正则化 Hessian 避免。常见正则化策略包括在 Hessian 对角线加一个常数 \(\alpha\),正则化更新变为
该正则化策略被用于牛顿法的近似,如 Levenberg–Marquardt 算法(Levenberg 1944;Marquardt 1963),只要 Hessian 负特征值仍相对接近零就工作得相当好。在存在更极端曲率方向的情形下,\(\alpha\) 必须足够大以抵消负特征值。但随 \(\alpha\) 增大,Hessian 被 \(\alpha I\) 对角线主导,牛顿法选择的方向收敛到标准梯度除以 \(\alpha\)。强负曲率存在时,\(\alpha\) 可能需要大到使牛顿法的步比带合适学习率的梯度下降还小。除了目标函数某些特征(如鞍点)造成的挑战外,把牛顿法用于训练大神经网络还受到其施加的巨大计算负担限制。Hessian 元素数是参数数的平方,所以对 \(k\) 个参数(甚至对很小的神经网络 \(k\) 也能达百万)的网络,牛顿法需对 \(k \times k\) 矩阵求逆——计算复杂度 \(O(k^3)\)。而且由于参数每次更新都会变化,逆 Hessian 必须在每次训练迭代时计算。因此只有参数非常少的网络才可被牛顿法实际训练。本节余下讨论试图获得牛顿法某些优势同时回避计算障碍的替代方法。
8.6.2 共轭梯度(Conjugate Gradients)
共轭梯度是一种通过沿共轭方向迭代下降以避免显式计算逆 Hessian 的方法。其灵感来自对最速下降法弱点的仔细研究(详见 4.3 节)——最速下降法迭代地在与梯度相关的方向上做线搜索。图 8.6 说明最速下降法应用于二次碗时如何以相当低效的来回锯齿模式前进。原因是每次线搜索方向由梯度给出时,保证与上一次线搜索方向正交。设前一次搜索方向为 \(d_{t-1}\)。在最小点——线搜索终止处——方向 \(d_{t-1}\) 的方向导数为零:\(\nabla_{\theta} J(\theta) \cdot d_{t-1} = 0\)。由于该点处的梯度定义当前搜索方向 \(d_t = \nabla_{\theta} J(\theta)\),在方向 \(d_{t-1}\) 上无贡献——因此 \(d_t\) 与 \(d_{t-1}\) 正交。这一关系见图 8.6 中最速下降的多轮迭代。如图所示,选取正交下降方向不会保留前次搜索方向上的最小值——这引发锯齿形进展模式:沿当前梯度方向下降到最小点时,必须在之前的梯度方向上重新最小化目标函数。于是每次线搜索结束时沿梯度走其实在某种意义上撤销了上一次线搜索中已取得的进展。共轭梯度法试图解决这一问题。在共轭梯度法中我们寻找与上一次线搜索方向共轭的搜索方向,即它不会撤销在该方向上已取得的进展。在训练迭代 \(t\) 时,下一搜索方向 \(d_t\) 形如
其中 \(\beta_t\) 是控制应在当前搜索方向上加入多少 \(d_{t-1}\) 方向的系数。当 \(d_t^{\top} H d_{t-1} = 0\) 时两个方向 \(d_t\) 与 \(d_{t-1}\) 被定义为共轭,其中 \(H\) 是 Hessian 矩阵。直接施加共轭性需计算 \(H\) 的特征向量以选择 \(\beta_t\),这不能满足"开发比牛顿法对大问题计算上更可行"的目标。我们能否不借助这些计算就计算出共轭方向?幸运的是可以。两种计算 \(\beta_t\) 的流行方法为:(1)Fletcher-Reeves:
(2)Polak-Ribière:
在二次曲面上共轭方向保证沿前次方向的梯度不会增大。因此我们保持沿前次方向的最小值。结果是在 \(k\) 维参数空间中,共轭梯度法最多需要 \(k\) 次线搜索即可到达极小。共轭梯度算法见算法 8.9(初始化 \(\rho_0 = 0, g_0 = 0, t = 1\);每轮初始化 \(g_t = 0\)、计算梯度 \(g_t \leftarrow \frac{1}{m} \nabla_{\theta} \sum_i L\)、Polak-Ribière 计算 \(\beta_t\)、非线性共轭梯度可选地把 \(\beta_t\) 重置为零(如 \(t\) 是某常数 \(k\) 的倍数时);计算搜索方向 \(\rho_t = -g_t + \beta_t \rho_{t-1}\);线搜索 \(\epsilon^* = \arg\min_{\epsilon} \frac{1}{m} \sum_i L(f(x^{(i)}; \theta_t + \epsilon \rho_t), y^{(i)})\)——真正二次代价函数时可解析求解 \(\epsilon^*\);更新 \(\theta_{t+1} = \theta_t + \epsilon^* \rho_t\);\(t \leftarrow t+1\))。非线性共轭梯度:迄今我们讨论的是应用于二次目标函数的共轭梯度法。本章主要兴趣当然在于为训练神经网络等深度学习模型探索优化方法,其对应目标函数远非二次。令人惊讶的是共轭梯度法在这一设定下仍适用,尽管需要一些修改。在没有目标为二次的保证时,共轭方向不再保证沿前次方向仍保持目标极小。因此非线性共轭梯度算法包含偶发重置——此时共轭梯度法被沿未改变梯度方向的线搜索重新启动。实践者报告在把非线性共轭梯度算法应用于神经网络训练时结果合理,不过在启动非线性共轭梯度前用几轮随机梯度下降做初始化通常有益。此外(共轭)梯度算法传统上被写成批方法,但 minibatch 版本已成功用于神经网络训练(Le et al. 2011)。针对神经网络的共轭梯度适配方法更早就被提出,例如缩放共轭梯度算法(Moller 1993)。
8.6.3 BFGS
Broyden–Fletcher–Goldfarb–Shanno(BFGS)算法试图带来牛顿法的若干优势而不承担其计算负担。在这层意义上 BFGS 与共轭梯度法类似。但 BFGS 在近似牛顿更新上采取更直接的方式。回顾牛顿更新
其中 \(H\) 是 \(J\) 关于 \(\theta\) 在 \(\theta_0\) 处求值的 Hessian。应用牛顿更新的主要计算困难是逆 Hessian \(H^{-1}\) 的计算。拟牛顿法(quasi-Newton methods,BFGS 是其中最突出的)所采取的方法是用一个矩阵 \(M_t\) 近似逆——\(M_t\) 通过低秩更新迭代细化以成为 \(H^{-1}\) 的更好近似。BFGS 近似的具体规定与推导在多本优化教科书中给出,包括 Luenberger (1984)。一旦逆 Hessian 近似 \(M_t\) 被更新,下降方向 \(\rho_t\) 由 \(\rho_t = M_t g_t\) 确定。在此方向上做线搜索以确定步长 \(\epsilon^*\)。最终参数更新由
给出。像共轭梯度法一样,BFGS 算法迭代一系列线搜索,方向上结合二阶信息。但与共轭梯度不同,BFGS 的成功并不严重依赖线搜索找到非常接近线上真正最小值的点。因此相对共轭梯度而言 BFGS 的优势是能在每条线搜索上花更少时间细化。但 BFGS 算法必须存储逆 Hessian 矩阵 \(M\),需要 \(O(n^2)\) 内存——这使 BFGS 对通常有百万参数的现代深度学习模型不实用。Limited Memory BFGS(或 L-BFGS):BFGS 算法的内存代价可通过避免存储完整逆 Hessian 近似 \(M\) 而显著降低。L-BFGS 算法用与 BFGS 相同方法计算近似 \(M\),但起始假设 \(M^{(t-1)}\) 是单位矩阵而非从一步到下一步存储近似。若配合精确线搜索,L-BFGS 定义的各方向彼此共轭。但与共轭梯度法不同,该过程在线搜索只到达近似最小点时仍表现良好。这里描述的 L-BFGS 不存储策略可被推广为通过在每步存储用于更新 \(M\) 的部分向量包含更多 Hessian 信息——每步仅需 \(O(n)\) 成本。
8.7 优化策略与元算法(Optimization Strategies and Meta-Algorithms)
许多优化技术并非严格的算法,而是可被特化以产出算法的通用模板,或可被并入多种算法的子例程。
8.7.1 批归一化(Batch Normalization)
批归一化(Ioffe and Szegedy 2015)是近期深度神经网络优化中最令人兴奋的创新之一——它实际上根本不是优化算法,而是一种自适应重参数化方法,动机来自训练极深模型的困难。极深模型涉及若干函数或层的复合。梯度告诉我们在假设其他层不变的前提下应如何更新每个参数。实践中我们同时更新所有层。当我们做更新时,复合在一起的许多函数被同时改变,使用的更新是在假设其他函数保持不变的前提下算出的,因此可能产生意料之外的结果。作为一个简单例子,假设深度神经网络每层只有一个单元且每层不使用激活函数:\(\hat{y} = x w_1 w_2 w_3 \ldots w_l\)。这里 \(w_i\) 是第 \(i\) 层使用的权重。第 \(i\) 层输出为 \(h_i = h_{i-1} w_i\)。输出 \(\hat{y}\) 是输入 \(x\) 的线性函数,但关于权重 \(w_i\) 的非线性函数。假设代价函数对 \(\hat{y}\) 给了大小 1 的梯度,希望略微减小 \(\hat{y}\)。反向传播算法可计算梯度 \(g = \nabla_w \hat{y}\)。考虑当 \(w \leftarrow w - \epsilon g\) 时会发生什么。\(\hat{y}\) 的一阶 Taylor 级数近似预测 \(\hat{y}\) 的值会下降 \(\epsilon g^{\top} g\)。若我们希望 \(\hat{y}\) 下降 .1,按梯度中可用的一阶信息应把学习率 \(\epsilon\) 设为 \(.1 / g^{\top} g\)。但实际更新将包含二阶、三阶直至 \(l\) 阶效应。\(\hat{y}\) 的新值为
该更新产生的一个二阶项例子为 \(\epsilon^2 g_1 g_2 \prod_{i=3}^l w_i\)。当 \(\prod_{i=3}^l w_i\) 较小时该二阶项可忽略,但若第 3 到第 \(l\) 层权重大于 1 则它可能指数级大。这使得选择合适学习率非常困难——因为对某层参数的更新效应强烈依赖于所有其他层。二阶优化算法通过计算考虑这些二阶交互的更新来解决此问题,但可以看到在极深网络中即便更高阶交互也很显著。即便二阶优化算法也代价高昂且通常需要许多近似使其不能真正考虑所有显著的二阶交互。构建 \(n\) 阶(\(n > 2\))优化算法看起来希望渺茫。我们还能怎么办?批归一化提供了一种优雅的方式来重新参数化几乎任何深度网络。这种重参数化显著降低了跨多层协调更新的问题。批归一化可被应用于网络中任何输入或隐藏层。设 \(H\) 是要被归一化的层的激活 minibatch,排成设计矩阵形式,每行的激活对应一个样本。要归一化 \(H\) 我们用
替换它,其中 \(\mu\) 是包含每个单元均值的向量,\(\sigma\) 是包含每个单元标准差的向量。这里的算术基于把向量 \(\mu\) 和 \(\sigma\) 广播应用于矩阵 \(H\) 的每一行。在每行内算术是逐元素的——所以 \(H_{i,j}\) 通过减去 \(\mu_j\) 并除以 \(\sigma_j\) 被归一化。网络的其余部分随后以与原始网络对 \(H\) 完全相同的方式对 \(H'\) 进行运算。训练时,
以及
其中 \(\delta\) 是如 \(10^{-8}\) 这样的小正值,用来避免遇到 \(z = 0\) 处平方根的未定义梯度。关键在于我们对这些用于计算均值、标准差以及将它们应用于 \(H\) 归一化的操作反向传播。这意味着梯度永远不会提出一个仅用来增大 \(h_i\) 标准差或均值的操作——归一化操作抹去了这种作用的效果并在梯度中将其分量清零。这是批归一化方法的一个主要创新。此前的方法包括对代价函数加惩罚以鼓励单元具有归一化激活统计、或在每次梯度下降步后介入重新归一化单元统计。前者通常导致归一化不完美,后者通常浪费时间——学习算法反复提出改变均值和方差而归一化步反复撤销这种改变。批归一化对模型重参数化使一些单元按定义始终被标准化,巧妙地绕过了这两个问题。测试时 \(\mu\) 和 \(\sigma\) 可被训练时收集的运行均值替换。这使模型可在单个样本上评估,无需使用依赖于整个 minibatch 的 \(\mu\) 和 \(\sigma\) 定义。重新看 \(\hat{y} = x w_1 w_2 \ldots w_l\) 例子,可通过归一化 \(h_{l-1}\) 大体上解决学习该模型的困难。设 \(x\) 抽自单位高斯,则 \(h_{l-1}\) 也来自高斯——因为从 \(x\) 到 \(h_l\) 的变换是线性的。但 \(h_{l-1}\) 不再有零均值和单位方差。施加批归一化后我们得到归一化的 \(\hat{h}_{l-1}\),恢复零均值和单位方差性质。对几乎任何对下层的更新 \(\hat{h}_{l-1}\) 都将保持单位高斯。输出 \(\hat{y}\) 可被学习为简单线性函数 \(\hat{y} = w_l \hat{h}_{l-1}\)。该模型的学习现在很简单——因为在多数情形下下层参数实际上没有影响,它们的输出总是被重归一化为单位高斯。在少数极端情形下下层可能有影响。把某下层权重改为 0 可使输出退化、改变某下层权重的符号可翻转 \(\hat{h}_{l-1}\) 与 \(y\) 的关系。这些情形很罕见。没有归一化时几乎每次更新都会对 \(h_{l-1}\) 的统计量产生极端影响。批归一化使该模型显著更易学。在这个例子中学习容易的代价是下层变得无用。在我们的线性例子中下层不再有害,但也不再有益——因为我们已把一阶和二阶统计量归一化掉,而这正是线性网络能影响的全部。在带非线性激活函数的深度神经网络中下层可执行数据的非线性变换,所以仍有用。批归一化仅用于标准化每个单元的均值和标准差以稳定学习,但允许单元之间的关系和单个单元的非线性统计量改变。因为网络最末层能学习线性变换,实际上可能希望消除一层内单元之间的所有线性关系。Desjardins et al. (2015) 采取的就是这种做法,他们启发了批归一化。遗憾的是消除所有线性交互比标准化每个单元的均值和标准差要昂贵得多——目前批归一化仍是最实用的方法。标准化一个单元的均值和标准差会降低包含该单元神经网络的表达能力。为保持网络表达能力,常见做法是用 \(\gamma H' + \beta\) 替换隐藏单元激活批 \(H\) 而非仅用归一化的 \(H'\)。\(\gamma\) 和 \(\beta\) 是可学习参数,允许新变量具有任意均值和标准差。乍看这似乎无用——为什么先把均值设为 0 又引入一个允许它被设为任意值 \(\beta\) 的参数?答案是新参数化能表示与旧参数化相同的输入函数族,但新参数化具有不同的学习动力学。在旧参数化中 \(H\) 的均值由 \(H\) 下层参数的复杂交互决定。在新参数化中 \(\gamma H' + \beta\) 的均值仅由 \(\beta\) 决定。新参数化更易被梯度下降学习。大多数神经网络层形如 \(\phi(X W + b)\),其中 \(\phi\) 是固定非线性激活函数如 ReLU。自然的疑问是我们应把批归一化应用于输入 \(X\) 还是变换后的值 \(X W + b\)。Ioffe and Szegedy (2015) 推荐应用于后者;更具体地说 \(X W + b\) 应被 \(X W\) 的归一化版本替换。偏置项应被省略因为它与批归一化重参数化应用的 \(\beta\) 参数冗余。层的输入通常是前一层非线性激活函数(如 ReLU)的输出。输入的统计量因此更非高斯、不太能通过线性操作标准化。在卷积网络(第 9 章)中重要的是在特征图每个空间位置应用相同的归一化 \(\mu\) 和 \(\sigma\),以使特征图的统计量不随空间位置变化。
8.7.2 坐标下降(Coordinate Descent)
某些情形下可通过把优化问题拆成几块来快速求解。若我们先关于单变量 \(x_i\) 最小化 \(f(x)\),再关于另一变量 \(x_j\) 最小化,依此类推,反复循环所有变量,则我们保证到达一个(局部)极小。该做法称为坐标下降(coordinate descent),因为我们一次优化一个坐标。更一般地,块坐标下降(block coordinate descent)指关于变量子集同时最小化。"坐标下降"一词常被用来指代块坐标下降以及严格的单坐标下降。坐标下降在以下情形最合适:优化问题中不同变量能清晰分成几组且各组扮演相对独立角色、或关于一组变量优化显著比关于所有变量优化更高效。例如考虑代价函数
该函数描述一种称为稀疏编码的学习问题,其目标是寻找能线性地把激活值矩阵 \(H\) 解码为训练集 \(X\) 重建的权重矩阵 \(W\)。稀疏编码的大多数应用也涉及权重衰减或 \(W\) 列范数上的约束以防止 \(H\) 极小而 \(W\) 极大的病态解。函数 \(J\) 非凸,但我们可以把训练算法的输入分成两组:字典参数 \(W\) 与编码表示 \(H\)。关于任一组变量最小化目标函数都是凸问题。块坐标下降因此给出一种优化策略——通过在固定 \(H\) 优化 \(W\) 与固定 \(W\) 优化 \(H\) 之间交替,能使用高效的凸优化算法。坐标下降在变量值强烈影响另一变量最优值时不是好策略,如函数 \(f(x) = (x_1 - x_2)^2 + \alpha(x_1^2 + x_2^2)\)(\(\alpha\) 为正常数)——第一项鼓励两变量值接近,第二项鼓励它们接近零。解是把两者都设为零。牛顿法作为正定二次问题能一步求解。但对小的 \(\alpha\),坐标下降进展极慢——因为第一项不允许把单个变量改为与另一变量当前值显著不同的值。
8.7.3 Polyak 平均(Polyak Averaging)
Polyak 平均(Polyak and Juditsky 1992)由对优化算法在参数空间中走过的轨迹上的若干点取平均构成。若梯度下降的 \(t\) 次迭代访问点 \(\theta^{(1)}, \ldots, \theta^{(t)}\),则 Polyak 平均算法的输出为 \(\hat{\theta}^{(t)} = \frac{1}{t} \sum_i \theta^{(i)}\)。在某些问题类上如梯度下降应用于凸问题,该方法有强收敛保证。用于神经网络时其论证更启发式但实际表现良好。基本思想是优化算法可能在一个谷底两侧来回跳几次而从不到达谷底附近的点。但两侧位置的平均应该接近谷底。在非凸问题中优化轨迹所走过的路径可能非常复杂并访问许多不同区域。把参数空间中距当前点可能隔着代价函数中大屏障的过去点纳入平均看起来没什么用。因此把 Polyak 平均用于非凸问题时通常采用指数衰减的运行平均:
运行平均方法在大量应用中使用。近期例子见 Szegedy et al. (2015)。
8.7.4 监督预训练(Supervised Pretraining)
有时若模型复杂难优化或任务非常困难,直接训练模型解决具体任务可能雄心过大。有时更有效的是先训练一个简单模型解决该任务、再让模型更复杂。也可先训练模型解决更简单的任务、再转向最终任务。这些"先在简单任务上训练简单模型再面对训练期望模型解决期望任务的挑战"的策略统称为预训练(pretraining)。贪心算法把一个问题拆成许多分量,再分别求解每个分量的最优版本。遗憾的是把各自分量最优组合起来并不保证产生最优完整解。然而贪心算法在计算上比求解最佳联合解的算法便宜得多,若非最优,贪心解的质量往往可接受。贪心算法之后可跟随一个微调阶段——联合优化算法搜索全问题的最优解。用贪心解初始化联合优化算法可大幅加速并提升其找到的解的质量。预训练(特别是贪心预训练)算法在深度学习中无处不在。本节具体描述那些把监督学习问题拆为其他更简单监督学习问题的预训练算法。这种方法称为贪心监督预训练(greedy supervised pretraining)。在 Bengio et al. (2007) 原始版本的贪心监督预训练中,每个阶段包含一个监督学习训练任务,只涉及最终神经网络的层子集。贪心监督预训练的例子见图 8.7:每个新加的隐藏层被预训练为浅监督 MLP 的一部分,输入为之前训练好的隐藏层的输出。Simonyan and Zisserman (2015) 不逐层预训练,而是预训练一个深度卷积网络(11 个有权重层)然后用其前 4 层和最后 3 层来初始化更深的网络(最多 19 个有权重层);新网络的中间层被随机初始化,然后被联合训练。Yu et al. (2010) 探索的另一选择是使用之前训练好的 MLP 输出以及原始输入作为每个新加阶段的输入。为什么贪心监督预训练会有帮助?Bengio et al. (2007) 最初讨论的假设是它有助于为深度层次中的中间层提供更好的指导。一般而言预训练在优化和泛化两方面都可能有所帮助。与监督预训练相关的方法把这一思想扩展到迁移学习语境:Yosinski et al. (2014) 用 8 个有权重层的深度卷积网络在一组任务上预训练(1000 个 ImageNet 物体类别的一个子集),然后用第一个网络的前 \(k\) 层初始化同尺寸的第二个网络。第二个网络的所有层(上层被随机初始化)被联合训练以执行另一组任务(ImageNet 1000 类中另一个子集),且任务训练样本数比第一组少。神经网络迁移学习的其他方法见 15.2 节。另一相关工作是 FitNets(Romero et al. 2015)。该方法从训练一个深度足够浅、宽度足够大(每层单元数)以至于容易训练的网络开始。该网络随后成为第二个网络(指定为学生)的教师。学生网络更深更瘦(11 到 19 层),在正常情况下用 SGD 难以训练。学生网络的训练被做得更容易——它不仅被训练为预测原始任务的输出,还被训练为预测教师网络的中间层值。这项额外任务提供关于隐藏层应如何被使用的一套提示,并可简化优化问题。引入额外参数用以从学生网络更深的中间层回归 5 层教师网络的中间层。然而目标不是预测最终分类目标,而是预测教师网络的中间隐藏层。学生网络下层因此有两个目标:帮助学生网络输出完成任务、并预测教师网络的中间层。虽然瘦深网络看起来比宽浅网络更难训练,但瘦深网络可能泛化更好——且若瘦到参数远少于宽网络,计算成本也低得多。没有隐藏层提示时学生网络在实验中表现很差(无论训练集还是测试集)。中间层提示因而可能成为帮助训练那些原本难以训练的神经网络的工具之一,但其他优化技术或架构上的变化也可能解决问题。
8.7.5 设计模型以辅助优化(Designing Models to Aid Optimization)
改进优化时最佳策略未必总是改进优化算法。相反深度模型优化的许多改进来自设计更易优化的模型。原则上我们可以用以锯齿非单调模式增减的激活函数,但这会使优化极其困难。实践上选一个易优化的模型族比用强大的优化算法更重要。过去 30 年神经网络学习的大多数进展都来自改变模型族而非改变优化过程。1980 年代用于训练神经网络的带动量随机梯度下降仍被现代最先进神经网络应用所使用。具体而言现代神经网络反映了一种设计选择:使用层之间的线性变换以及几乎处处可微、在大部分定义域内具有显著斜率的激活函数。具体来说 LSTM、ReLU 和 maxout 单元等模型创新都朝着使用比 sigmoidal 单元深度网络等旧模型更线性函数的方向移动。这些模型具有让优化更容易的良好性质。只要线性变换的 Jacobian 具有合理奇异值,梯度就能流过许多层。此外线性函数沿单一方向持续增大,所以即便模型输出与正确值相去甚远,从梯度也能明确知道输出应朝哪个方向移动以减少损失。换言之现代神经网络被设计为它们的局部梯度信息合理地对应于朝向远距离解的移动。其他模型设计策略也能帮助让优化更容易。例如层之间的线性路径或跳跃连接缩短了下层参数到输出的最短路径长度,从而缓解梯度消失问题(Srivastava et al. 2015)。与跳跃连接相关的思想是把输出的额外副本附加到网络的中间隐藏层上,如 GoogLeNet(Szegedy et al. 2014a)和 deeply-supervised nets(Lee et al. 2014)。这些"辅助头"被训练为执行与网络顶部主输出相同的任务以确保下层接收大梯度。训练完成后辅助头可被丢弃。这是前节介绍的预训练策略的替代:可以在单阶段中联合训练所有层但改变架构,使中间层(特别是下层)能通过更短路径获得关于它们应做什么的提示。这些提示为下层提供误差信号。
8.7.6 延拓方法与课程学习(Continuation Methods and Curriculum Learning)
8.2.7 节论证过许多优化挑战源于代价函数的全局结构,不能仅通过更好地估计局部更新方向解决。克服该问题的主要策略是尝试把参数初始化在与解通过参数空间中一条局部下降可循的短路径相连的区域。延拓方法(continuation methods)是一类通过选择初始点以保证局部优化把大部分时间花在空间中表现良好区域的策略。延拓方法的思想是对相同参数构造一系列目标函数。为最小化代价函数 \(J(\theta)\),我们构造新代价函数 \(\{J^{(0)}, \ldots, J^{(n)}\}\)。这些代价函数被设计成越来越难——\(J^{(0)}\) 相当容易最小化,\(J^{(n)}\)(最难)则是激励整个过程的真实代价函数 \(J(\theta)\)。当我们说 \(J^{(i)}\) 比 \(J^{(i+1)}\) 更容易时,意思是它在 \(\theta\) 空间的更多区域上表现良好。随机初始化更可能落在局部下降能成功最小化代价函数的区域——因为该区域更大。代价函数系列被设计成使一个函数的解是下一个函数的好初始点。因此我们从解一个容易问题开始,再细化解以解逐步更难的问题,直到我们到达真实底层问题的解。传统延拓方法(早于延拓方法在神经网络训练中的使用)通常基于平滑目标函数。这类方法的例子及相关方法综述见 Wu (1997)。延拓方法与模拟退火密切相关——后者给参数加噪声(Kirkpatrick et al. 1983)。延拓方法近年来极其成功;近期文献(特别是 AI 应用)综述见 Mobahi and Fisher (2015)。延拓方法传统上主要被设计来解决局部极小的挑战——具体而言它们被设计为在存在许多局部极小时仍能到达全局极小。为此这些延拓方法通过"模糊"原始代价函数构造更容易的代价函数。该模糊操作可通过采样近似
完成。该方法的直觉是某些非凸函数在模糊后变为近似凸。在许多情形下该模糊保留了关于全局极小位置的足够信息,使我们能通过求解逐步不那么模糊的版本找到全局极小。该方法可能以三种方式失败。第一种:它可能成功定义了一系列代价函数,其中第一个是凸的且极小从一个函数跟踪到下一个最终到达全局极小,但可能需要极多逐步代价函数使整个过程代价仍高。NP 难优化问题即使可应用延拓方法仍是 NP 难。另两种失败方式都对应方法不可应用:第一,函数可能无论怎么模糊都变不成凸——例如函数 \(J(\theta) = -\theta^{\top} \theta\);第二,函数可能因模糊而变为凸,但该模糊函数的极小可能跟踪到原始代价函数的局部极小而非全局极小。虽然延拓方法最初主要被设计来处理局部极小问题,但局部极小已不再被认为是神经网络优化的主要问题。幸运的是延拓方法仍能有所帮助。延拓方法引入的更容易目标函数能消除平坦区域、降低梯度估计方差、改善 Hessian 矩阵的条件数,或做其他让局部更新更易计算或改善局部更新方向与向全局解进展之间对应关系的事。Bengio et al. (2009) 观察到一种称为课程学习(curriculum learning)或 shaping 的方法可被解释为延拓方法。课程学习基于规划一种学习过程的思想——从学习简单概念开始,逐步进展到学习更复杂概念。Skinner 1958;Peterson 2004;Krueger and Dayan 2009 以及 Solomonoff 1989;Elman 1993;Sanger 1994 等先前工作表明该基本策略可加速动物训练和机器学习中的进展。Bengio et al. (2009) 把该策略论证为延拓方法——通过让更简单例子的影响更大(要么把对代价函数的贡献系数设得更大、要么更频繁地采样)使早期 \(J^{(i)}\) 更容易——并实验证明在大规模神经语言建模任务上按课程进行能得到更好结果。课程学习已在广泛自然语言(Spitkovsky et al. 2010;Collobert et al. 2011a;Mikolov et al. 2011b;Tu and Honovar 2011)和计算机视觉(Kumar et al. 2010;Lee and Grauman 2011;Supancic and Ramanan 2013)任务上成功。课程学习也被验证与人类教学方式一致(Khan et al. 2011):教师先展示更容易和更具原型性的例子,然后帮助学习者用更不明显的例子细化决策面。基于课程的策略比基于均匀采样的策略对人类教学更有效,且也能提高其他教学策略的有效性(Basu and Christensen 2013)。课程学习研究的另一重要贡献出现在训练循环神经网络捕捉长期依赖的语境中:Zaremba and Sutskever (2014) 发现用随机课程能得到好得多的结果——其中容易和困难例子的随机混合始终呈现给学习者,但更困难例子(这里是那些具长期依赖的)的平均比例逐渐增大。用确定性课程时未观察到相对基线(从完整训练集做普通训练)的改进。现在我们已经描述了神经网络模型的基本族以及如何正则化和优化它们。在后续章节中我们将转向神经网络族的特化——使神经网络能扩展到非常大尺寸并处理具有特殊结构的输入数据。本章讨论的优化方法常可直接应用于这些专用架构、几乎或完全无需修改。
本章个人批注
本章是 Goodfellow 把"训练深度模型的优化"作为独立主题展开的一章。读完后最深的印象是:作者把整个优化问题拆成了三组互不重叠的范畴:(1)机器学习优化的根本差异(8.1);(2)神经网络作为非凸优化问题特有的若干具体挑战(8.2);(3)针对这些挑战的实用算法与元算法(8.3–8.7)。每组内部都隐含一个统一的核心:用某种方式应对"训练不是纯优化、神经网络的代价函数具有非凸结构"这两大前提。
8.1.3 这节虽然用了大量篇幅讲 minibatch 的实际驱动因素(硬件、利用率、内存、GPU 友好的 2 幂次批量、噪声作为正则化等),但其中最有理论意味的反而是末尾那段"minibatch SGD 只要样本不重复就在沿真实泛化误差 (8.2) 的梯度方向前进"——这是把经验风险最小化与泛化误差最小化首次统一的论述。8.5、8.6 给出的"第二个 epoch 开始估计就是有偏的"也很有指导意义:实际中虽然我们做多遍遍历,但只有第一遍在严格意义上沿泛化误差梯度。
8.2.3 鞍点这一节是本章最具"科学观更新"意味的一节。作者明确指出"多年来多数实践者相信局部极小是神经网络优化的常见麻烦,今天看来似乎并非如此",引用了 Dauphin 2014 的"鞍点比局部极小指数级多"理论、Saxe 2013 对线性网络的精确解、Goodfellow 2015 的"梯度范数随训练不缩小"实证,以及图 8.2 的轨迹可视化。这种"用概率论(抛硬币)解释鞍点比例"的可视化论证非常有助于消除对深度学习优化的神秘感。8.2.4 悬崖与梯度爆炸把"循环网络中长时间序列的极端乘法深度"作为悬崖结构最常见来源,并自然衔接 10.11.1 的梯度截断。8.2.7 局部与全局结构的不对应那段(Goodfellow 2015 的轨迹长度论证、损失函数可能不存在全局极小点而只是渐近逼近)解释了为什么"优化算法的渐进收敛速度"对深度学习是个有上限的问题——Cramér-Rao 下界 \(O(1/k)\) 既是理论上限也是经验上限。8.2.8 关于理论极限的存在性提醒我:Blum-Rivest、Judd、Wolpert-MacReady 这些"不可解"结果虽然对实践影响小,但说明"用更大网络绕开难度"是工程师面对不可解性的通用套路。
8.3.1 SGD 那一段我特别欣赏 Bottou-Bousquet (2008) 的论断:对机器学习任务追求比 \(O(1/k)\) 更快的优化算法可能得不偿失——更快收敛可能对应过拟合。这把"优化速度 vs 泛化能力"在收敛率层面首次明确对立。8.3.2 动量一节最精彩的是把动量算法解释为"带粘性阻力的牛顿粒子在参数空间中滑动":粒子受力 \(-\nabla_{\theta} J\) 加 \(-v\) 形式的粘性阻力(不能用湍流阻力 \(v^2\)——速度小时太弱;不能用干摩擦——力过强),并明示"用 \(-v\) 是数学便利"。8.3.3 Nesterov 动量是"在临时点 \(\theta + \alpha v\) 处计算梯度再做速度更新",并明确指出"在随机梯度情形下 Nesterov 动量并不提升收敛率"——这种"凸 / 随机"分界对实际工程意义重大。
8.4 参数初始化策略是本章信息密度最高的一节之一。作者给出了四条几乎并列的设计原则:(a)打破对称性(让每个单元计算不同函数);(b)尺度选择(过小信号消失、过大激活饱和或梯度爆炸);(c)正则化视角(早期停止等价于高斯先验 \(\theta_0\) 居 0);(d)正交 / 随机游走初始化(用足够大的 gain 因子可训练 1000 层)。理论上的具体方案包括 Glorot-Bengio (2010) 的 \(U(-\sqrt{6/(m+n)}, \sqrt{6/(m+n)})\)、Saxe 2013 的随机正交矩阵配 gain 因子、Sussillo 2014 的随机游走理论。最引人注意的是这段"理论最优准则经常并非实际最优准则"的诚实陈述——"这可能是由于错误准则 / 性质不能保留 / 提升速度反而增大泛化误差"三种原因,迫使实践者把"初始权重尺度"作为超参数通过超参数搜索算法调。偏置初始化的三种特殊情形(输出偏置调边缘统计量、ReLU 偏置设为 0.1 避饱和、遗忘门偏置设为 1 让门常开)也很有操作性。
8.5 自适应学习率算法一节是现代深度学习最常用的算法集合。作者给出的演进路径很清晰:Delta-bar-delta(按偏导数符号变化调,1988)→ AdaGrad(按历史平方梯度累积缩放,2011)→ RMSProp(用指数加权平均代替累积,Hinton 2012 讲义)→ Adam(再加偏差修正 + 一阶矩估计,Kingma-Ba 2014)→ 实用建议(Schaul 2014 实验显示无单一最佳算法)。Adam 把动量直接实现为梯度一阶矩的指数加权估计这一点很关键——它和"在 RMSProp 的再缩放梯度上额外加动量"不同,理论动机更清晰。
8.6 近似二阶方法一节信息量集中在"为什么二阶方法在深度学习中不流行":(i)8.2.3 鞍点问题(牛顿法求解 \(\nabla J = 0\) 会跳到鞍点);(ii)Hessian 计算与存储代价 \(O(k^2)\) 与 \(O(k^3)\)。作者给出了三种缓解方案:Levenberg-Marquardt 正则化(共轭梯度方向的子集)→ 共轭梯度(避免存 Hessian,最多 \(k\) 次线搜索收敛)→ BFGS / L-BFGS(用秩-2 更新近似逆 Hessian,L-BFGS 把存储从 \(O(n^2)\) 降到 \(O(n)\))。共轭梯度那段"为什么最速下降会有锯齿形模式"的解释(每次新搜索方向与上次线搜索方向正交,必然撤销上次进展)特别清楚。
8.7 优化策略与元算法一节内容最杂。8.7.1 批归一化是本章最具"工程普适性"的方案——它解决了"非常深的网络中各层同时更新导致所有函数都同时变化、用基于其他层不变的梯度做的更新可能产生意料之外结果"的问题。批归一化的核心创新点是"反向传播通过均值/标准差的计算以及归一化操作"——这保证梯度永远不会提出一个仅用来增大 \(h_i\) 标准差或均值的操作。在 \(\hat{y} = x w_1 w_2 \ldots w_l\) 的线性例子中作者清楚地论证了"批归一化使下层几乎无用但无害,让 \(\hat{y}\) 可作为简单线性函数学习",并指出"在线性网络中我们已把一阶二阶统计量归一化掉,所以下层确实无用;但在带非线性激活的深度网络中下层仍可执行非线性变换"。8.7.4 监督预训练一节我特别喜欢 FitNets(Romero 2015)的例子:把一个浅宽的教师网络中间层值作为额外监督信号,让学生网络(深瘦)不仅预测输出还预测教师中间层,"提示"(hints)的存在与否在实验中效果差异巨大。8.7.5 设计模型以辅助优化那段"过去 30 年神经网络学习的大多数进展都来自改变模型族而非改变优化过程"是本章最具历史洞见的句子——把 LSTM、ReLU、maxout 都归到"使用更线性函数"的设计哲学下。8.7.6 延拓方法与课程学习那一段最有指导意义的是 Zaremba-Sutskever 2014 的"随机课程"——始终呈现容易和困难例子的随机混合、但逐步增大困难例子的平均比例,确定性课程反而没用。
两个读时的小疑虑:(i)8.3.3 末尾"Nesterov 动量在随机梯度情形下不提升收敛率"作者没有给出严格证明,而是引 Nesterov 1983 的凸批梯度结果;(ii)8.7.1 末尾"在卷积网络中特征图每个空间位置应用相同的归一化 \(\mu\) 和 \(\sigma\)"在写作时(2016 年初)layer normalization / group normalization 还没出现,作者没预料到后续会衍生出多种 BN 变体。
与上下章的衔接(一段话)
从全书结构看,第 5 章给出了泛化与机器学习的基本工作定义,第 7 章在第 5 章基础上系统展开了深度学习专属的正则化策略,第 8 章正是沿着第 7 章末预告的"另一中心主题是优化"展开。第 7 章与第 8 章在概念上互为表里:第 7 章把"通过修改学习算法以降低泛化误差而非训练误差"作为正则化的工作定义;第 8 章则把"训练即优化"作为前提(8.1.1、8.1.2 讨论了为什么这个前提在机器学习中需要修正),并系统讨论训练深度模型时特有的非凸优化挑战。两章都强调"代价函数"——第 7 章讨论在代价函数上加什么约束能改善泛化,第 8 章讨论如何高效最小化代价函数。第 8 章与第 4 章(数值计算)的关系更直接:4.3 节是本章 8.3.1 随机梯度下降、8.6 近似二阶方法的基础;8.2 列举的挑战(病态、局部极小、鞍点、悬崖、长期依赖、不精确梯度、局部-全局不对应、理论极限)很多在第 4 章已经预示过,本章把它们整合到神经网络训练的语境下。第 8 章与后续章节的关系:8.4 参数初始化策略中提到的 ReLU 偏置设为 0.1、maxout 单元"对初始化敏感"等具体技术会在第 9 章卷积网络、第 10 章循环网络被实际调用;8.7.1 批归一化会在第 9 章卷积网络、第 10 章循环网络、第 11 章实践方法论中作为默认工程组件出现;8.7.2 坐标下降会在第 14 章自编码器、第 13 章线性因子模型、第 17 章蒙特卡洛方法中作为基本求解工具;8.7.3 Polyak 平均与 8.7.4 监督预训练会在第 11 章被作为实践方法再次讨论。从这个意义上看第 8 章是全书的"优化方法学中心":把第 4 章的数值优化一般理论具体落到神经网络训练语境,给后续各章(卷积网络、循环网络、实践方法论、生成模型等)提供可调用的优化工具库。