🐠 小批量随机梯度下降
type
status
date
slug
summary
tags
category
icon
password
Property

 
目前为止,我们在基于梯度的学习方法中遇到了两个极端情况:gd中使用完整数据集来计算梯度并更新参数, sgd中一次处理一个训练样本来取得进展。 二者各有利弊:每当数据非常相似时,梯度下降并不是非常“数据高效”。 而由于CPU和GPU无法充分利用向量化,随机梯度下降并不特别“计算高效”。 这暗示了两者之间可能有折中方案,这便涉及到小批量随机梯度下降(minibatch gradient descent)
 

向量化和缓存

使用小批量的决策的核心是计算效率。 当考虑与多个GPU和多台服务器并行处理时,这一点最容易被理解,我们需要向每个GPU发送至少一张图像。 有了每台服务器8个GPU和16台服务器,就能得到大小为128的小批量。
 
当涉及到单个GPU甚至CPU时,事情会更微妙一些: 这些设备有多种类型的内存、通常情况下多种类型的计算单元以及在它们之间不同的带宽限制。 例如,一个CPU有少量寄存器(register),L1和L2缓存,以及L3缓存(在不同的处理器内核之间共享)。 随着缓存的大小的增加,它们的延迟也在增加,同时带宽在减少。 可以说,处理器能够执行的操作远比主内存接口所能提供的多得多。
首先,具有16个内核和AVX-512向量化的2GHz CPU每秒可处理高达 个字节。 同时,GPU的性能很容易超过该数字100倍。 而另一方面,中端服务器处理器的带宽可能不超过100Gb/s,即不到处理器满负荷所需的十分之一。 更糟糕的是,并非所有的内存入口都是相等的:内存接口通常为64位或更宽(例如,在最多384位的GPU上)。 因此读取单个字节会导致由于更宽的存取而产生的代价。
🐠 动量法
type
status
date
slug
summary
tags
category
icon
password
Property

基础

泄漏平均值

小批量随机梯度下降作为加速计算的手段,它也有很好的副作用,即平均梯度减小了方差。 小批量随机梯度下降可以通过以下方式计算:
为了保持记法简单,在这里使用 作为样本的随机梯度下降,使用时间时更新的权重 。 如果我们能够从方差减少的影响中受益,甚至超过小批量上的梯度平均值,那很不错。 完成这项任务的一种选择是用泄漏平均值(leaky average)取代梯度计算:
其中。 这有效地将瞬时梯度替换为多个“过去”梯度的平均值。被称为动量(momentum), 它累加了过去的梯度。 为了更详细地解释,让我们递归地将扩展到
其中,较大的 相当于长期平均值,而较小的 相对于梯度法只是略有修正。 新的梯度替换不再指向特定实例下降最陡的方向,而是指向过去梯度的加权平均值的方向。 这使我们能够实现对单批量计算平均值的大部分好处,而不产生实际计算其梯度的代价。
上述推理构成了"加速"梯度方法的基础,例如具有动量的梯度。 在优化问题条件不佳的情况下(例如,有些方向的进展比其他方向慢得多,类似狭窄的峡谷),"加速"梯度还额外享受更有效的好处。 此外,它们允许我们对随后的梯度计算平均值,以获得更稳定的下降方向。 诚然,即使是对于无噪声凸问题,加速度这方面也是动量如此起效的关键原因之一。
正如人们所期望的,由于其功效,动量是深度学习及其后优化中一个深入研究的主题。
🐠 AdaGrad算法
type
status
date
slug
summary
tags
category
icon
password
Property
 

稀疏特征和学习率

假设训练一个语言模型,为了获得良好的准确性,大多希望在训练的过程中降低学习率,速度通常为 或更低。 现在讨论关于稀疏特征(即只在偶尔出现的特征)的模型训练,这对自然语言来说很常见。 例如,我们看到“预先条件”这个词比“学习”这个词的可能性要小得多。 但是,它在计算广告学和个性化协同过滤等其他领域也很常见。
只有在这些不常见的特征出现时,与其相关的参数才会得到有意义的更新。 鉴于学习率下降,我们可能最终会面临这样的情况:常见特征的参数相当迅速地收敛到最佳值,而对于不常见的特征,仍缺乏足够的观测以确定其最佳值。 换句话说,学习率要么对于常见特征而言降低太慢,要么对于不常见特征而言降低太快。
解决此问题的一个方法是记录我们看到特定特征的次数,然后将其用作调整学习率。 即我们可以使用大小为 的学习率,而不是 。 在这里 计下了我们截至 时观察到功能 的次数。 这其实很容易实施且不产生额外损耗。
AdaGrad算法通过将粗略的计数器 替换为先前观察所得梯度的平方之和来解决这个问题。 它使用 来调整学习率。 这有两个好处:首先,不再需要决定梯度何时算足够大。 其次,它会随梯度的大小自动变化。通常对应于较大梯度的坐标会显著缩小,而其他梯度较小的坐标则会得到更平滑的处理。 在实际应用中,它促成了计算广告学及其相关问题中非常有效的优化程序。 但是,它遮盖了AdaGrad固有的一些额外优势,这些优势在预处理环境中很容易被理解。

预处理

凸优化问题有助于分析算法的特点。 毕竟对于大多数非凸问题来说,获得有意义的理论保证很难,但是直觉和洞察往往会延续。 让我们来看看最小化 这一问题。
我们可以根据其特征分解 重写这个问题,来得到一个简化得多的问题,使每个坐标都可以单独解出:
这里使用了 ,且因此 。 修改后优化器为 且最小值为 。 这样更容易计算,因为 是一个包含 特征值的对角矩阵。
如果稍微扰动 ,我们会期望在 的最小化器中只产生微小的变化。 遗憾的是,情况并非如此。 虽然 的微小变化导致了 同样的微小变化,但 的(以及 的)最小化器并非如此。 每当特征值 很大时,我们只会看到 的最小值发声微小变化。 相反,对于小的 来说, 的变化可能是剧烈的。 最大和最小的特征值之比称为优化问题的条件数(condition number):
🐠 RMSProp算法
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
adagrad中的关键问题之一,是学习率按预定时间表 显著降低。 虽然这通常适用于凸问题,但对于深度学习中遇到的非凸问题,可能并不理想。 但是,作为一个预处理器,Adagrad算法按坐标顺序的适应性是非常可取的。
Tieleman.Hinton.2012建议以RMSProp算法作为将速率调度与坐标自适应学习率分离的简单修复方法。 问题在于,Adagrad算法将梯度 的平方累加成状态矢量 。 因此,由于缺乏规范化,没有约束力, 持续增长,几乎上是在算法收敛时呈线性递增。
解决此问题的一种方法是使用 。 对于 的合理分布来说,它将收敛。 遗憾的是,限制行为生效可能需要很长时间,因为该流程记住了值的完整轨迹。 另一种方法是按动量法中的方式使用泄漏平均值,即 ,其中参数 。 保持所有其它部分不变就产生了RMSProp算法。

算法

常数 通常设置为 ,以确保不会因除以零或步长过大而受到影响。 鉴于这种扩展,现在可以自由控制学习率 ,而不考虑基于每个坐标应用的缩放。 就泄漏平均值而言,可以采用与之前在动量法中适用的相同推理。 扩展 定义可获得
同之前在momentum小节一样,我们使用 。 因此,权重总和标准化为 且观测值的半衰期为 。 让我们图像化各种数值的$\gamma$在过去40个时间步长的权重。
notion image
🐠 Adadelta
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
Adadelta是AdaGrad的另一种变体, 主要区别在于前者减少了学习率适应坐标的数量。 此外,广义上Adadelta被称为没有学习率,因为它使用变化量本身作为未来变化的校准。 Adadelta算法是在Zeiler.2012中提出的。

Adadelta算法

Adadelta使用两个状态变量, 用于存储梯度二阶导数的泄露平均值, 用于存储模型本身中参数变化二阶导数的泄露平均值。
以下是Adadelta的技术细节。鉴于参数du jour是 ,获得了与rmsprop类似的以下泄漏更新:
rmsprop的区别在于,使用重新缩放的梯度 执行更新,即
那么,调整后的梯度是什么?可以按如下方式计算它:
其中 是重新缩放梯度的平方 的泄漏平均值初始化为 ,然后在每个步骤中使用 更新它,即
🐠 Adam算法
type
status
date
slug
summary
tags
category
icon
password
Property
 
  • sgd中:随机梯度下降在解决优化问题时比梯度下降更有效。
  • minibatch_sgd中:在一个小批量中使用更大的观测值集,可以通过向量化提供额外效率。这是高效的多机、多GPU和整体并行处理的关键。
  • momentum中:添加了一种机制,用于汇总过去梯度的历史以加速收敛
  • adagrad中:通过对每个坐标缩放来实现高效计算的预处理器
  • rmsprop中:通过学习率的调整来分离每个坐标的缩放
Adam算法 将所有这些技术汇总到一个高效的学习算法中。 不出预料,作为深度学习中使用的更强大和有效的优化算法之一,它非常受欢迎。 但是它并非没有问题——有时可能由于方差控制不良而发散。 在完善工作中,Zaheer.Reddi.Sachan.ea.2018给Adam算法提供了一个称为Yogi的热补丁来解决这些问题。
 
 

算法

Adam算法的关键组成部分之一是:它使用指数加权移动平均值来估算梯度的动量和二次矩,即它使用状态变量
🐠 学习率调度器
type
status
date
slug
summary
tags
category
icon
password
Property
 
到目前为止,主要关注如何更新权重向量的优化算法,而不是它们的更新速率。 然而,调整学习率通常与实际算法同样重要,有如下几方面需要考虑:
  • 首先,学习率的大小很重要。如果它太大,优化就会发散;如果它太小,训练就会需要过长时间,或者最终只能得到次优的结果。直观地说,这是最不敏感与最敏感方向的变化量的比率。
  • 其次,衰减速率同样很重要。如果学习率持续过高,可能最终会在最小值附近弹跳,从而无法达到最优解。 我们希望速率衰减,但要比 慢,这样能成为解决凸问题的不错选择。
  • 另一个同样重要的方面是初始化。这既涉及参数最初的设置方式,又关系到它们最初的演变方式。这被戏称为预热(warmup),即最初开始向着解决方案迈进的速度有多快。一开始的大步可能没有好处,特别是因为最初的参数集是随机的。最初的更新方向可能也是毫无意义的。
  • 最后,还有许多优化变体可以执行周期性学习率调整。例如,如何通过对整个路径参数求平均值来获得更好的解。
鉴于管理学习率需要很多细节,因此大多数深度学习框架都有自动应对这个问题的工具。 这里将梳理不同的调度策略对准确性的影响,并展示如何通过学习率调度器(learning rate scheduler)来有效管理。

一个简单的问题

从一个简单的问题开始,选择了一个稍微现代化的LeNet版本(激活函数使用relu而不是sigmoid,汇聚层使用最大汇聚层而不是平均汇聚层),并应用于Fashion-MNIST数据集。
notion image
 
🐟 线性回归
type
status
date
slug
summary
tags
category
icon
password
Property
目录
目录

原理

🐟 Softmax回归
type
status
date
slug
summary
tags
category
icon
password
Property

 

分类问题

一个图像分类问题,假设每个图像属于类别“猫”,“鸡”和“狗”中的一个,要选择如何表示标签?
有两个明显的选择:
  • 最直接的想法是选择, 其中整数分别代表。这是在计算机上存储此类信息的有效方法。 如果类别间有一些自然顺序, 比如,那么将这个问题转变为回归问题,并且保留这种格式是有意义的。
  • 但是一般的分类问题并不与类别之间的自然顺序有关。 幸运的是,统计学家很早以前就发明了一种表示分类数据的简单方法:one-hot编码(独热编码)。独热编码是一个向量,它的分量和类别一样多,别对应的分量设置为1,其他所有分量设置为0。在这个例子中,标签将是一个三维向量, 其中 对应于“猫”、 对应于“鸡”、 对应于“狗”:
 
🐋 DNN和前向传播算法
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
notion image

从感知机到神经网络

感知机模型是一个有若干输入和一个输出的模型,如下图:
notion image
输出和输入之间学习到一个线性关系,得到中间输出结果:
接着是一个神经元激活函数:
从而得到想要的输出结果1或者-1
🐋 激活函数
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
激活函数(activation function)通过计算加权和并加上偏置来确定神经元是否应该被激活, 它们将输入信号转换为输出的可微运算, 大多数激活函数都是非线性的

Sigmoid激活函数

对于一个定义域在, sigmoid函数将输入变换为区间(0, 1)上的输出。 因此,sigmoid通常称为挤压函数: 它将范围(-inf, inf)中的任意输入压缩到区间(0, 1)中的某个值:
notion image
在最早的神经⽹络中,科学家们感兴趣的是对“激发”或“不激发”的⽣物神经元进⾏建模。因此,这⼀领域的先驱,如⼈⼯神经元的发明者麦卡洛克和⽪茨,从他们开始就专注于阈值单元。阈值单元在其输⼊低于某个阈值时取值0,当输⼊超过阈值时取值1。
当⼈们的注意⼒逐渐转移到基于梯度的学习时,sigmoid函数是⼀个⾃然的选择,因为它是⼀个平滑的、可微的阈值单元近似。当我们想要将输出视作⼆分类问题的概率时,sigmoid仍然被⼴泛⽤作输出单元上的激活函数(可以将sigmoid视为softmax的特例)。然而,sigmoid在隐藏层中已经较少使⽤,它在⼤部分时候已经被更简单、更容易训练的ReLU所取代。
下⾯绘制sigmoid函数,当输⼊接近0时,sigmoid函数接近线性变换
🐋 反向传播算法(BP)
type
status
date
slug
summary
tags
category
icon
password
Property
 

DNN反向传播算法要解决的问题

什么时候需要这个反向传播算法?
回到监督学习的一般问题,假设有 个训练样本: ,其中 为输入向量,特征维度为 ,而 为输出向量,特征维度为 。我们需要利用这 个样本训练出一个模型,当有一个新的测试样本 来到时, 可以预测 向量的输出。
如果采用DNN的模型,即输入层有 个神经元,输出层有 个神经元,再加上一些含有若干神经元的隐藏层。此时我们需要找到合适的所有隐藏层和输出层对应的线性系数矩阵,偏倚向量 ,让所有的训练样本输入计算出的输出尽可能的等于或很接近样本输出。怎么找到合适的参数呢?
这里就很容易联想到可以用一个合适的损失函数来度量训练样本的输出损失,接着对这个损失函数进行优化求最小化的极值,对应的一系列线性系数矩阵,偏倚向量即为最终结果。在DNN中,损失函数优化极值求解的过程最常见的一般是通过梯度下降法来一步步迭代完成的,当然也可以是其他的迭代方法比如牛顿法与拟牛顿法。
对DNN的损失函数用梯度下降法进行迭代优化求极小值的过程即为反向传播算法。
 

DNN反向传播算法的基本思路

在进行DNN反向传播算法前,需要选择一个损失函数,来度量训练样本计算出的输出和真实的训练样本输出之间的损失。
训练样本计算出的输出是怎么得来的?
这个输出是随机选择一系列,用前向传播算法计算出来的。即通过一系列的计算: