罗然、雪清、Aileen编译

给卷积神经网络“修理工”的一份“说明书”

这篇文章的主要内容来自作者的自身经验和一些在线资源(如最出名的斯坦福大学的CS231n课程讲义),是关于如何调试卷积神经网络从而提升其性能的。

文章主要关注深度神经网络架构下的有监督学习方式。虽然这个指南基于Python3.6坏境使用tensorflow(TF)编程,但它仍然可以作为一种语言无关的指南来使用。

假设我们有一个卷积神经网络来训练和评估,并假设评估结果比预期的更糟。

下文是排除故障并逐步提高性能的步骤,第一部分是进行故障排除之前的必备事项和良好实践。每个后续的章节标题都对应着一个问题,该部分专门用于解决这个问题。

我们会先抛出“更为常见”的问题,在每个标题下,也会优先给出“最容易实现”的解决方案。

故障排除前…

以下是在编写深度学习算法时要遵循的最佳实践,关于这个主题的很好的资料来源于CS231n课程讲义以及Bengio的综述论文。

Stanford's CS231n课程讲义:

http://cs231n.github.io/

Bengio的综述论文:

https://arxiv.org/pdf/1206.5533v2.pdf

1.使用适当的日志记录和有意义的变量名称。在TF中能够通过名称来跟踪不同的变量,并在TF的可视化工具TensorBoard中显示出计算图。

最重要的是,每隔几个训练步骤都要确保记录了相关的值,例如:step_number, accuracy, loss, learning_rate。适用的话,加上更具体的度量标准(例如在图像分割任务中使用mean_intersection_over_union,即mean_iou)。之后,就可以根据训练步骤画出损失曲线。

译者注:IoU,预测窗口与标记窗口之间的交并比。

2. 确保你的网络连接正确。使用TensorBoard或其他调试技术确保计算图中每个操作的输入和输出都准确无误,还要确保在将数据和标签送入网络之前对其进行适当的预处理和匹配。

3. 实施数据扩充(data augmentation)技术。虽然这一点并不是对所有情况都适用,但是如果处理图像的话,应用简单的数据扩充技术(例如镜像,旋转,随机裁剪和尺度变换,添加噪声,elastically deforming等),大部分时候会带来巨大的性能提升。而且TF具有大多数这些操作的内置函数,十分良心了。

4. 对所有层使用权重初始化和正则化不要将权重初始化为相同的值,更糟的是将其初始化为0。这样做会带来对称性(symmetry)和潜在的梯度弥散问题,在大多数情况下会导致可怕的结果。通常,如果在权重初始化时遇到问题,可以考虑将Batch Normalization层添加到网络中。

BN论文链接:

https://arxiv.org/abs/1502.03167。

5. 确保正则项不会“压倒”损失函数中的其他项。关闭正则化,找出“损失”的数量级,然后适当地调整正则项大小。确保随着正则化强度的增加,损失也在增加。

6. 尝试过拟合一个小数据集。关闭正则化/随机失活/数据扩充,使用训练集的一小部分,让神经网络训练几个周期。确保可以实现零损失,如果没有,那么很可能什么地方出错了。

在某些情况下,将损失降到0尤其具有挑战性。例如,在图像语义分割中,如果你的损失涉及每个像素的softmax-ed logits和ground truth labels之间的交叉熵,那么可能真的难以将其降低到0。不过,你应当寻求达到接近100%的准确率,通过获取softmax-ed logits的argmax并将其与ground truth labels进行比较来计算。

译者注:在机器学习中,“ground truth”一词指的是监督学习技术中训练集分类的准确性,简单地说就是正确标注的数据。

7. 在过拟合上述小数据集的同时,找到合适的学习率下面的内容直接引自Bengio的论文:最优学习率通常接近于不会增加训练误差的最大学习率,一种可以指导启发式设置学习率的观测方法是,例如,以较大的学习率开始,如果训练误差发散,就用最大学习率除以3再试试,直到观察不到发散为止。

8. 执行梯度检验(gradient checks)。如果你在计算图中使用自定义操作——即不是内置的TF操作,则梯度检验尤其重要。下面的链接有一些实现梯度检验的技巧。

Gradient checks:

http://cs231n.github.io/neural-networks-3/

如果损失(Loss Value)没有改善…

如果你训练了几个周期,损失还是没有改善,甚至还越来越大,则应该考虑下面几个步骤了:

1.确保使用了合理的损失函数,而且优化的是正确的张量。此处提供常见的损失函数列表。

https://en.wikipedia.org/wiki/Loss_functions_for_classification

2. 使用一个得当的优化器此处提供了常用优化器列表。

https://keras.io/optimizers/

3. 确保变量真的在训练。为了检查这一点,你可以查看TensorBoard的直方图,或者编写一个脚本,在几个不同的训练实例中计算每个张量范数(L1或 L∞),并打印出这些张量的名称。

如果你的变量未按预期进行训练,请参阅下列文章

https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc#variable-not-training

4. 调整初始学习率并实施适当的学习率计划(learning rate schedule),这可能是最具影响力的“修复”。如果损失越来越严重,可能是初始学习率太大了。另一方面,如果损失几乎不变,可能是初始学习率太小了。无论如何,一旦确定了有效的初始学习率,就应该进行学习率衰减。像ADAM这样的优化器会在内部实现学习率衰减,但是,这些学习率的更新通常会很慢,在优化器之上实现自己的学习率计划会是个好主意。

5. 确保没有过拟合。有一些方法可以实现过拟合,也有一些方法可以避免它。绘制损失值与训练周期的曲线图,如果曲线看起来像抛物线,那么很可能过拟合了。

请参阅这篇文章:

https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc#overfitting

如果变量没在训练…

像上面说的那样,使用TensorBoard的直方图,或编写一个脚本,在几个不同的训练实例中计算每个张量范数,并打印出这些张量的名称。如果变量未按预期进行训练:

1. 确保TF将其视为可训练的变量。查看TF GraphKeys以获取更多详细信息。

https://www.tensorflow.org/api_docs/python/tf/GraphKeys

2. 确保没发生梯度弥散。如果下游变量(接近输出的变量)训练正常但上游变量(接近输入的变量)几乎不变,则可能遇上了梯度弥散的问题。

请参阅下面的文章:

https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc#vanishingexploding-gradients

3. 确保ReLus还在“放电”。如果大部分神经元“电压”被“钳制”为零,那么应该重新修正权重初始化策略,尝试使用不太激进的学习率计划,并尝试减少正则化权重衰减)。

译者注:ReLu,线性整流函数,又称修正线性单元,是一种人工神经网络中常用的激活函数

梯度弥散/梯度爆炸…

1. 考虑使用更好的权重初始化策略。如果在训练开始时梯度更新非常小,则这点尤其重要。

2. 考虑换一下激活函数如果正在使用ReLus,请考虑使用leaky ReLu或MaxOut激活函数替换它们。你应该完全避免sigmoid激活函数,并远离tanh。

3.如果用递归神经网络的话,考虑使用LSTM

详情请看这篇文章:

https://medium.com/@karpathy/yes-you-should-understand-backprop-e2f06eab496b

过拟合

过拟合就是网络“记住”了训练数据的情况。如果网络在训练集和验证集上,准确率差别很大,可能它就过拟合了。

参见此处的Train / Val准确率部分:

http://cs231n.github.io/neural-networks-3/

1. 实施数据扩充技术。可上翻至本文第一节“故障排除前”中的内容。

2. 实施随机失活(dropout)。随机失活指在训练期间每个步骤随机地忽略掉一些神经元,在前向传播期间这些神经元的贡献被移除并且在反向传播期间它们不被更新。

了解更多信息:

https://machinelearningmastery.com/dropout-regularization-deep-learning-models-keras/

3. 增加正则化

4. 实施批规范化操作(Batch normalization)

详情请看这里:

https://arxiv.org/abs/1502.03167

5. 实施基于验证集的早期停止(early stopping)。由于网络训练了太多个周期,因此可能会发生过拟合,早期停止有助于消除这个问题。

参考这里:

https://en.wikipedia.org/wiki/Early_stopping#Validation-based_early_stopping

6. 如果其他一切都失败了,请使用较小的网络。这真的应该是你的最后手段,事实上这里的课程讲义对这种做法保持谨慎。

还能调试些什么…

1. 考虑使用加权的损失函数(weighted loss function)。例如,在图像语义分割中,神经网络对输入图像中的每个像素进行分类。与其他类相比,某些类可能很少出现,在这种情况下,权衡少见的类可能会改进mean_iou度量。

2. 更网络架构。你之前的网络可能太深或太浅。

3. 考虑使用集成模型。

4. 用小数步长卷积(strided convolutions)替换最大值汇合层和平均值汇合层。

5. 执行彻底的超参数搜索。

6. 更改随机数种子。

7. 如果上面的方法都失败了,还是去寻找更多数据吧。

相关报道:

https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc

大数据文摘
大数据文摘

秉承“普及数据思维,传播数据文化,助⼒产业发展”的企业⽂化,我们专注于数据领域的资讯、案例、技术,形成了“媒体+教育+⼈才服务”的良性⽣态,致⼒于打造精准数据科学社区。

入门CNN
7
相关数据
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

范数技术

范数(norm),是具有“长度”概念的函数。在线性代数、泛函分析及相关的数学领域,是一个函数,其为向量空间内的所有向量赋予非零的正长度或大小。半范数反而可以为非零的向量赋予零长度。

激活函数技术

在 计算网络中, 一个节点的激活函数定义了该节点在给定的输入或输入的集合下的输出。标准的计算机芯片电路可以看作是根据输入得到"开"(1)或"关"(0)输出的数字网络激活函数。这与神经网络中的线性感知机的行为类似。 一种函数(例如 ReLU 或 S 型函数),用于对上一层的所有输入求加权和,然后生成一个输出值(通常为非线性值),并将其传递给下一层。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

交叉熵技术

交叉熵(Cross Entropy)是Loss函数的一种(也称为损失函数或代价函数),用于描述模型预测值与真实值的差距大小

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

学习率技术

在使用不同优化器(例如随机梯度下降,Adam)神经网络相关训练中,学习速率作为一个超参数控制了权重更新的幅度,以及训练的速度和精度。学习速率太大容易导致目标(代价)函数波动较大从而难以找到最优,而弱学习速率设置太小,则会导致收敛过慢耗时太长

损失函数技术

在数学优化,统计学,计量经济学,决策理论,机器学习和计算神经科学等领域,损失函数或成本函数是将一或多个变量的一个事件或值映射为可以直观地表示某种与之相关“成本”的实数的函数。

超参数技术

在机器学习中,超参数是在学习过程开始之前设置其值的参数。 相反,其他参数的值是通过训练得出的。 不同的模型训练算法需要不同的超参数,一些简单的算法(如普通最小二乘回归)不需要。 给定这些超参数,训练算法从数据中学习参数。相同种类的机器学习模型可能需要不同的超参数来适应不同的数据模式,并且必须对其进行调整以便模型能够最优地解决机器学习问题。 在实际应用中一般需要对超参数进行优化,以找到一个超参数元组(tuple),由这些超参数元组形成一个最优化模型,该模型可以将在给定的独立数据上预定义的损失函数最小化。

线性整流函数技术

线性整流函数(Rectified Linear Unit, ReLU),又称修正线性单元, 是一种人工神经网络中常用的激活函数(activation function),通常指代以斜坡函数及其变种为代表的非线性函数。比较常用的线性整流函数有斜坡函数f(x)=max(0, x),以及带泄露整流函数 (Leaky ReLU),其中x为神经元(Neuron)的输入。

张量技术

张量是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数,这些线性关系的基本例子有内积、外积、线性映射以及笛卡儿积。其坐标在 维空间内,有 个分量的一种量,其中每个分量都是坐标的函数,而在坐标变换时,这些分量也依照某些规则作线性变换。称为该张量的秩或阶(与矩阵的秩和阶均无关系)。 在数学里,张量是一种几何实体,或者说广义上的“数量”。张量概念包括标量、矢量和线性算子。张量可以用坐标系统来表达,记作标量的数组,但它是定义为“不依赖于参照系的选择的”。张量在物理和工程学中很重要。例如在扩散张量成像中,表达器官对于水的在各个方向的微分透性的张量可以用来产生大脑的扫描图。工程上最重要的例子可能就是应力张量和应变张量了,它们都是二阶张量,对于一般线性材料他们之间的关系由一个四阶弹性张量来决定。

验证集技术

验证数据集是用于调整分类器超参数(即模型结构)的一组数据集,它有时也被称为开发集(dev set)。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

卷积神经网络技术

卷积神经网路(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。卷积神经网路由一个或多个卷积层和顶端的全连通层(对应经典的神经网路)组成,同时也包括关联权重和池化层(pooling layer)。这一结构使得卷积神经网路能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网路在图像和语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比较其他深度、前馈神经网路,卷积神经网路需要考量的参数更少,使之成为一种颇具吸引力的深度学习结构。 卷积网络是一种专门用于处理具有已知的、网格状拓扑的数据的神经网络。例如时间序列数据,它可以被认为是以一定时间间隔采样的一维网格,又如图像数据,其可以被认为是二维像素网格。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

监督学习技术

监督式学习(Supervised learning),是机器学习中的一个方法,可以由标记好的训练集中学到或建立一个模式(函数 / learning model),并依此模式推测新的实例。训练集是由一系列的训练范例组成,每个训练范例则由输入对象(通常是向量)和预期输出所组成。函数的输出可以是一个连续的值(称为回归分析),或是预测一个分类标签(称作分类)。

规范化技术

规范化:将属性数据按比例缩放,使之落入一个小的特定区间,如-1.0 到1.0 或0.0 到1.0。 通过将属性数据按比例缩放,使之落入一个小的特定区间,如0.0到1.0,对属性规范化。对于距离度量分类算法,如涉及神经网络或诸如最临近分类和聚类的分类算法,规范化特别有用。如果使用神经网络后向传播算法进行分类挖掘,对于训练样本属性输入值规范化将有助于加快学习阶段的速度。对于基于距离的方法,规范化可以帮助防止具有较大初始值域的属性与具有较小初始值域的属相相比,权重过大。有许多数据规范化的方法,包括最小-最大规范化、z-score规范化和按小数定标规范化。

过拟合技术

过拟合是指为了得到一致假设而使假设变得过度严格。避免过拟合是分类器设计中的一个核心任务。通常采用增大数据量和测试样本集的方法对分类器性能进行评价。

神经元技术

(人工)神经元是一个类比于生物神经元的数学计算模型,是神经网络的基本组成单元。 对于生物神经网络,每个神经元与其他神经元相连,当它“兴奋”时会向相连的神经元发送化学物质,从而改变这些神经元的电位;神经元的“兴奋”由其电位决定,当它的电位超过一个“阈值”(threshold)便会被激活,亦即“兴奋”。 目前最常见的神经元模型是基于1943年 Warren McCulloch 和 Walter Pitts提出的“M-P 神经元模型”。 在这个模型中,神经元通过带权重的连接接处理来自n个其他神经元的输入信号,其总输入值将与神经元的阈值进行比较,最后通过“激活函数”(activation function)产生神经元的输出。

正则化技术

当模型的复杂度增大时,训练误差会逐渐减小并趋向于0;而测试误差会先减小,达到最小值后又增大。当选择的模型复杂度过大时,过拟合现象就会发生。这样,在学习时就要防止过拟合。进行最优模型的选择,即选择复杂度适当的模型,以达到使测试误差最小的学习目的。

深度神经网络技术

深度神经网络(DNN)是深度学习的一种框架,它是一种具备至少一个隐层的神经网络。与浅层神经网络类似,深度神经网络也能够为复杂非线性系统提供建模,但多出的层次为模型提供了更高的抽象层次,因而提高了模型的能力。

优化器技术

优化器基类提供了计算梯度loss的方法,并可以将梯度应用于变量。优化器里包含了实现了经典的优化算法,如梯度下降和Adagrad。 优化器是提供了一个可以使用各种优化算法的接口,可以让用户直接调用一些经典的优化算法,如梯度下降法等等。优化器(optimizers)类的基类。这个类定义了在训练模型的时候添加一个操作的API。用户基本上不会直接使用这个类,但是你会用到他的子类比如GradientDescentOptimizer, AdagradOptimizer, MomentumOptimizer(tensorflow下的优化器包)等等这些算法。

推荐文章
暂无评论
暂无评论~