神经网络(Neural network)里面的节点,类似我们的神经元。
神经网络也可以有很多不同的连接方式,这样就会产生不同的结构(structure)在这个神经网络里面,我们有很多逻辑回归函数,其中每个逻辑回归都有自己的权重和自己的偏差,这些权重和偏差就是参数,这些神经元连接方式都是手动去设计的。
概念: 前馈(feedforward)也可以称为前向,从信号流向来理解就是输入信号进入网络后,信号流动是单向的,即信号从前一层流向后一层,一直到输出层,其中任意两层之间的连接并没有反馈(feedback),亦即信号没有从后一层又返回到前一层。
输入相应的数值之后,神经网络在每一层直接乘相应的权重,然后在输入到设置好的激活函数中,得到下一层的输入,然后再次重复之前的操作,将信号一层一层的向下传递,最后得到网络的输出。
对于一个深度学习的网络结构应该分为以下几层:
前馈的理解: 现在传递的方向是由前往后传,所以叫做Feedforward
深度的理解: Deep = Many hidden layer指的是拥有很多隐藏层
为什么引入矩阵计算: 随着层数变多,错误率降低,随之运算量增大,通常都是超过亿万级的计算。对于这样复杂的结构,我们一定不会一个一个的计算,对于亿万级的计算,使用循环效率很低。这里我们就引入矩阵计算(Matrix Operation) 能使得我们的运算的速度以及效率高很多。这样写成矩阵运算的好处是,你可以使用GPU加速。
通过隐藏层进行特征转换。把隐藏层通过特征提取来替代原来的特征工程,这样在最后一个隐藏层输出的就是一组新的特征(相当于黑箱操作)而对于输出层,其实是把前面的隐藏层的输出当做输入(经过特征提取得到的一组最好的特征)然后通过一个多分类器(可以是softmax函数)得到最后的输出y。
对于损失,我们不单单要计算一笔数据的,而是要计算整体所有训练数据的损失,然后把所有的训练数据的损失都加起来,得到一个总体损失L。接下来就是在function set里面找到一组函数能最小化这个总体损失L,或者是找一组神经网络的参数�θ,来最小化总体损失L。
在神经网络中计算损失最好的方法就是反向传播,我们可以用很多框架来进行计算损失,比如说TensorFlow,theano,Pytorch等等
如何找到最优的函数和最好的一组参数呢,我们用的就是梯度下降。
对于从0搭建一个深度学习项目来说,应该是分为以下步骤:
项目研究:我们会先对现有产品进行研究,以探索它们的弱点。
理论项目研究:接下来,我们需要了解相关的研究和开源项目,许多人在开始实践之前至少要看几十篇论文和项目。深度学习 ( DL ) 代码简练,但很难排查缺陷,且很多研究论文常常遗漏了实现细节。许多项目始于开源实现,解决的问题也很相似,因此我们可以多多搜索开源项目。
我们可以使用公开数据集或者自定义数据集。公开数据集可以提供更整齐的样本和基线模型性能,如果你有多个可用的公开数据集,请选择与你的问题最相关且质量最好的样本;如果没有相应领域的公开数据集,我们可以根据项目的实际需要自己去搜集数据,创建数据集。
高质量数据集应该包括以下特征:
注意事项:
首先灵活简单的模型: 从较少网络层和自定义开始设计,后面再做一些必要的超参数精调方案。这些都需要查证损失函数一直在降低,不要一开始就在较大的模型上浪费时间。
优先性以及增量设计: 把复杂问题分解成小问题,一步一步解决。在设计模型的过程中,我们会遇到许多惊喜。相比于做个要不断改变的长期计划,还不如以优先性驱动的计划。使用更短、更小的设计迭代,从而保证项目可管理性。
避免随机改进: 首先分析自己模型的弱点,而不是随意地改进。随意做改进反而适得其反,会成比例的增加训练成本,而回报极小。
限制: 我们把限制应用到网络设计,从而保证训练更高效。建立深度学习并不是简单的把网络层堆在一起。增加好的限制(constraints)能使得学习更为有效,或者更智能。
设计细节: 选择深度学习软件框架 迁移学习,许多预训练模型可用于解决深度学习难题,我们可以先将自己的思路在原有的模型上进行模拟,看效果如何。
成本函数: 并非所有的成本函数都是等价的,它会影响模型的训练难度。有些成本函数是相当标准的,但有些问题域需要仔细考虑。
度量标准: 良好的度量标准有助于更好地比较和调整模型。
正则化: L1 正则化和 L2 正则化都很常见,但 L2 正则化在深度学习中更受欢迎。L1 正则化有何优点?L1 正则化可以产生更加稀疏的参数,这有助于解开底层表示。由于每个非零参数会往成本上添加惩罚,与 L2 正则化相比,L1 更加青睐零参数,即与 L2 正则化中的许多微小参数相比,它更喜欢零参数。L1 正则化使过滤器更干净、更易于解释,因此是特征选择的良好选择。L1 对异常值的脆弱性也较低,如果数据不太干净,运行效果会更好。然而,L2 正则化仍然更受欢迎,因为解可能更稳定。
梯度下降: 始终密切监视梯度是否消失或爆炸,梯度下降问题有许多可能的原因,这些原因难以证实。不要跳至学习速率调整或使模型设计改变太快,小梯度可能仅仅由编程 Bug 引起,如输入数据未正确缩放或权重全部初始化为零。如果消除了其他可能的原因,则在梯度爆炸时应用梯度截断(特别是对于 NLP)。跳过连接是缓解梯度下降问题的常用技术。在 ResNet 中,残差模块允许输入绕过当前层到达下一层,这有效地增加了网络的深度。
缩放: 缩放输入特征。我们通常将特征缩放为以零为均值在特定范围内,如 [-1, 1]。特征的不适当缩放是梯度爆炸或降低的一个最常见的原因。有时我们从训练数据中计算均值和方差,以使数据更接近正态分布。如果缩放验证或测试数据,要再次利用训练数据的均值和方差。
Dropout: 可以将 Dropout 应用于层以归一化模型。2015 年批量归一化兴起之后,dropout 热度降低。批量归一化使用均值和标准差重新缩放节点输出。这就像噪声一样,迫使层对输入中的变量进行更鲁棒的学习。由于批量归一化也有助于解决梯度下降问题,因此它逐渐取代了 Dropout。结合 Dropout 和 L2 正则化的好处是领域特定的。通常,我们可以在调优过程中测试 dropout,并收集经验数据来证明其益处。
激活函数: 在 DL 中,ReLU 是最常用的非线性激活函数。如果学习速率太高,则许多节点的激活值可能会处于零值。如果改变学习速率没有帮助,我们可以尝试 leaky ReLU 或 PReLU。在 leaky ReLU 中,当 x < 0 时,它不输出 0,而是具有小的预定义向下斜率(如 0.01 或由超参数设置)。参数 ReLU(PReLU)往前推动一步。每个节点将具有可训练斜率。
拆分数据集: 为了测试实际性能,我们将数据分为三部分: 70 % 用于训练,20 % 用于验证,10 % 用于测试。确保样本在每个数据集和每批训练样本中被充分打乱。在训练过程中,我们使用训练数据集来构建具有不同超参数的模型。我们使用验证数据集来运行这些模型,并选择精确度最高的模型。如果你的测试结果与验证结果有很大差异,则应将数据打乱地更加充分或收集更多的数据。
自定义层: 深度学习软件包中的内建层已经得到了更好的测试和优化。尽管如此,如果想自定义层,你需要:
归一化: 深度学习的一大挑战是可复现性。在调试过程中,如果初始模型参数在 session 间保持变化,就很难进行调试。因此,我们明确地对所有随机发生器初始化了种子。我们在项目中对 python、NumPy 和 TensorFlow 都初始化了种子。在精调过程中,我们我们关闭了种子初始化,从而为每次运行生成不同的模型。为了复现模型的结果,我们将对其进行 checkpoint,并在稍后重新加载它。
优化器: Adam 优化器是深度学习中最流行的优化器之一。它适用于很多种问题,包括带稀疏或带噪声梯度的模型。其易于精调的特性使得它能快速获得很好的结果。实际上,默认的参数配置通常就能工作得很好。Adam 优化器结合了 AdaGrad 和 RMSProp 的优点。Adam 对每个参数使用相同的学习率,并随着学习的进行而独立地适应。Adam 是基于动量的算法,利用了梯度的历史信息。因此,梯度下降可以运行得更加平滑,并抑制了由于大梯度和大学习率导致的参数振荡问题。
Adam 优化器调整
Adam 有 4 个可配置参数:
β(动量)通过累积梯度的历史信息来平滑化梯度下降。通常对于早期阶段,默认设置已经能工作得很好。否则,最可能需要改变的参数应该是学习率。
在为深度神经网络排除故障方面,人们总是太快、太早地下结论了。在了解如何排除故障前,我们要先考虑要寻找什么,再花费数小时时间追踪故障。这部分我们将讨论如何可视化深度学习模型和性能指标。
TensorBoard:
在每一步追踪每个动作、检查结果非常重要。在预置包如 TensorBoard 的帮助下,可视化模型和性能指标变得简单,且奖励几乎是同时的。
数据可视化(输入、输出):
验证模型的输入和输出。在向模型馈送数据之前,先保存一些训练和验证样本用于视觉验证。
指标(损失 & 准确率):
除了定期记录损失和准确率之外,我们还可以记录和绘制它们,以分析其长期趋势。下图是 TensorBoard 上展示的准确率和交叉熵损失。
绘制损失图能够帮助我们调整学习率。损失的任意长期上升表明学习率太高了。如果学习率较低,则学习的速度变慢。
这里是另一个学习率太高的真实样本。我们能看到损失函数突然上升(可能由梯度突然上升引起)。
我们使用准确率图调整正则化因子。如果验证和训练准确率之间存在很大差距,则该模型出现过拟合。为了缓解过拟合,我们需要提高正则化因子。
深度学习的问题解决步骤
在前期开发中,我们会同时遇到多个问题。就像前面提到的,深度学习训练由数百万次迭代组成。找到 bug 非常难,且容易崩溃。从简单开始,渐渐做一些改变。正则化这样的模型优化可以在代码 degug 后做。以功能优先的方式检查模型:
用小量的训练数据使模型过拟合是 debug 深度学习的最好方式。 如果在数千次迭代内,损失值不下降,进一步 debgug 代码。准确率超越瞎猜的概念,你就获得了第一个里程碑。然后对模型做后续的修改:增加网络层和自定义;开始用完整训练数据做训练;通过监控训练和验证数据集之间的准确率差别,来增加正则化控制过拟合。
初始化超参数
许多超参数与模型优化更为相关。关掉超参数或者使用缺省值。使用 Adam 优化器,它速度快、高效且缺省学习率也很好。前期的问题主要来自于 bug,而不是模型设计和精调问题。在做微调之前,先过一遍下面的检查列表。这些问题更常见,也容易检查。如果损失值还没下降,就调整学习率。如果损失值降的太慢,学习率增加 10。如果损失值上升或者梯度爆炸,学习率降低 10。重复这个过程,直到损失值逐渐下降。典型的学习率在 1 到 1e-7 之间。
检查列表
数据:
模型:
权重初始化
把权重全部初始化到 0 是最常见的错误,深度网络也学不到任何东西。权重要按照高斯分布做初始化:
缩放与归一化
人们对缩放与归一化都有很好地理解,但这仍旧是最被轻视的问题之一。如果输入特征和节点输出都被归一化,就能更容易地训练模型。如果做的不准确,损失值就不会随着学习率降低。我们应该监控输入特征和每层节点输出的的直方图。要适当的缩放输入。而对节点的输出,完美的形状是零均值,且值不太大(正或负)。如果不是且遇到该层有梯度问题,则在卷积层做批归一化,在 RNN 单元上做层归一化。
损失函数
检查和测试损失函数的准确性。模型的损失值一定要比随机猜测的值低。
分析误差
检查表现不好(误差)的地方并加以改进,且对误差进行可视化。
正则化精调
关掉正则化(使得模型过拟合)直到做出合理的预测。
一旦模型代码可以工作了,接下来调整的参数是正则化因子。我们需要增加训练数据的体量,然后增加正则化来缩小训练和验证准确率之间的差别。不要做的太过分,因为我们想要稍微让模型过拟合。密切监测数据和正则化成本。长时间尺度下,正则化损失不应该控制数据损失。如果用大型正则化还不能缩小两个准确率间的差距,那先 degug 正则化代码或者方法。
类似于学习率,我们以对数比例改变测试值,例如开始时改变 1/10。注意,每个正则化因子都可能是完全不同的数量级,我们可以反复调整这些参数。
多个损失函数
在第一次实现中,避免使用多个数据损失函数。每个损失函数的权重可能有不同的数量级,也需要一些精力去调整。如果我们只有一个损失函数,就可以只在意学习率了。
固定变量
当我们使用预训练模型,我们可以固定特定层的模型参数,从而加速计算。一定要再次检查是否有变量固定的错误。
提升模型容量
要想提升模型容量,我们可以向深度网络(DN)逐渐添加层和节点。更深的层会输出更复杂的模型。调参过程更重实践而非理论。我们逐渐添加层和节点,可以与模型过拟合,因为我们可以用正则化方式再将其调低。重复该迭代过程直到准确率不再提升,不再值得训练、计算性能的降低。
对于非常深层的网络,梯度消失问题很严重。我们可以添加跳跃连接(类似 ResNet 中的残差连接)来缓解该问题。
模型 & 数据集设计变化
以下是提升性能的检查列表:
我们应该在激活函数之前密切监控激活直方图。如果它们的规模差别很大,那么梯度下降将会无效。使用归一化。如果深度网络有大量无效节点,那么我们应该进一步追踪该问题。它可能是由 bug、权重初始化或梯度消失导致的。如果都不是,则试验一些高级 ReLU 函数,如 leaky ReLU。
数据集收集 & 清洗
如果你想构建自己的数据集,那么最好的建议就是仔细研究如何收集样本。找最优质的资源,过滤掉与你问题无关的所有数据,分析误差。
数据增强
收集有标签的数据是一件昂贵的工作。对于图片来说,我们可以使用数据增强方法如旋转、随机剪裁、移位等方式来对已有数据进行修改,生成更多的数据。颜色失真则包括色调、饱和度和曝光偏移。
监督学习
我们还可以使用无标注数据补充训练数据。使用模型分类数据。把具备高置信预测的样本添加到具备对应标签预测的训练数据集中。
调整
学习率调整
我们先简单回顾一下如何调整学习率。在早期开发阶段,我们关闭任意非关键超参数或设置为 0,包括正则化。在具备 Adam 优化器的情况下,默认学习率通常性能就很好了。如果我们对自己的代码很有信心,但是损失并没有下降,则需要调整学习率。典型的学习率在 1 和 1e-7 之间。每次把学习率降低 10%,并在简短迭代中进行测试,密切监控损失。如果它持续上升,那么学习率太高了。如果它没有下降,则学习率太低。提高学习率,直到损失提前变得平缓。
超参数调整
在模型设计稳定后,我们也可以进一步调整模型。最经常调整的超参数是:
Mini-batch 尺寸
通常的批尺寸是 8、16、32 或 64。如果批尺寸太小,则梯度下降不会很顺畅,模型学习的速度慢,损失可能会振荡。如果批尺寸太大,则完成一次训练迭代(一轮更新)的时间太长,得到的返回结果较小。我们密切监控整个学习速度和损失。如果损失振荡剧烈,则我们会知道批尺寸降低的幅度太大了。批尺寸影响正则化因子等超参数。一旦我们确定好批尺寸,我们通常就锁定了值。
学习率 & 正则化因子
我们可以使用上述方法进一步调整学习率和正则化因子。我们监控损失,来控制学习率和验证与训练准确率之间的差距,从而调整正则化因子。调参不是线性过程。超参数是有关联的,我们将反复调整超参数。学习率和正则化因子高度相关,有时需要一起调。不要太早进行精细调整,有可能浪费时间。设计改变的话这些努力就白费了。
Dropout
Dropout 率通常在 20% 到 50% 之间。我们先从 20% 开始。如果模型出现过拟合,则提高值。
其他调整
稀疏度激活函数
模型参数的稀疏度能使计算优化变得简单,并减少能耗(这对于移动设备来说至关重要)。如果需要,我们可以用 L1 正则化替代 L2 正则化。ReLU 是最流行的激活函数。对于一些深度学习竞赛,人们使用更高级的 ReLU 变体以提高准确率。在一些场景中它还可以减少无效节点。
高级调参
一些高级精细调参方法:
我们没有使用固定的学习率,而是定期降低学习率。超参数包括学习率下降的频率和幅度。例如,你可以在每十万次迭代时减少 0.95 的学习率。要调整这些参数,我们需要监控成本,以确定参数下降地更快但又不至于过早平缓。
高级优化器使用动量使梯度下降过程流畅进行。Adam 优化器中存在两种动量设置,分别控制一阶(默认 0.9)和二阶(默认 0.999)动量。对于具备梯度陡降的问题领域如 NLP,我们可以稍稍提高动量值。
当验证误差持续上升时,过拟合可通过停止训练来缓解。
但是,这只是概念的可视化。实时误差可能暂时上升,然后再次下降。我们可以定期检查模型,记录对应的验证误差。稍后我们来选择模型。
网格搜索
一些超参数是高度相关的。我们应该使用对数尺度上的可能性网格一起调整它们。网格搜索的计算量很大。对于较小的项目,它们会被零星使用。我们开始用较少的迭代来调整粗粒度参数。在后期的细调阶段,我们会使用更长的迭代,并将数值调至 3(或更低)。
模型集合
在机器学习中,我们可以从决策树中投票进行预测。这种方法非常有效,因为判断失误通常是有局部性质的:两个模型发生同一个错误的几率很小。在深度学习中,我们可以从随机猜测开始训练(提交一个没有明确设置的随机种子),优化模型也不是唯一的。我们可以使用验证数据集测试多次选出表现最佳的模型,也可以让多个模型进行内部投票,最终输出预测结果。这种方式需要进行多个会话,肯定非常耗费系统资源。我们也可以训练一次,检查多个模型,随后在这个过程中选出表现最佳的模型。通过集合模型,我们可以基于这些进行准确的预测:
模型集合在提高一些问题的预测准确率上非常有效,经常会被深度学习数据竞赛的队伍所采用。
模型提升
在微调模型以外,我们也可以尝试使用模型的不同变体来提升性能。
阅读量:244
点赞量:0
收藏量:0