训练/开发/测试集
创建高质量的训练开发测试集有助于探究适合网络的超参。
我们常常会将数据划分成以下几部分
- 训练集
- 简单交叉验证集
- 测试集
开始时先使用训练集进行训练,然后使用验证集选择最好的模型。经过一段时间的选择后再使用测试机对最终选定的模型进行测试评估。
数据的划分
在早期的机器学习中,我们常常将原始数据集三七分。或者六二二划分成,训练集验证集测试集。
上述的划分方式一般使用在100~1000~10000这样大小的数据集。
但如果你有百万级别的原始数据集。那么可以减小验证集和测试集占数据总的比例。验证集的目标是验证不同的算法。那么可能不需要拿百万数据中的两成,取一万条数据便足以进行评估。测试集可能也只需要一万条的数据即可。
所以百万级别的划分的比例为98% 1% 1%。
过百万的数据集可能使用的比例为 99.5% 0.4% 0.1%。
需要注意的点需要保证训练集和测试集的分布的均匀的。
比如你想训练一个网络寻找出用户上传的图片中是否有猫。
但是你的训练集是来自网络,而验证集才是来自用户上传的真实数据。结果许多网页上的图片分辨率更高。而用户上传的图片是手机随手拍的,较为模糊。这两种数据有不同之处。所以最终训练出来的网络可能会不尽人意。
此外如果没有测试集是可行的。注意不要将验证集数据拟合到测试集中。
偏差(bias)与方差(variance)
如果给第一个数据集拟合一条直线,可能得到一个逻辑回归拟合。但是不能很好的拟合该数据集。我们称为欠拟合。
假如我们训练一个非常复杂的分类器。比如深度神经网络或者含有隐藏层的神经网络。可能就会出现图三的情况。分类器的方差较高,过度拟合数据。当然还有会中间这种复杂程度适中,数据拟合适度的分类器这个数据拟合看起来更加的合理。
像图中这种低维度的数据,我们可以通过绘制图片将偏差和方差可视化。在多维度数据中绘制数据和可视化分割边界无法实现。但是我们可以通过几个参数来研究偏差和方差。
我们沿用猫咪分类的例子。理解偏差和方差的两个关键数据是:训练集误差和验证集误差。
我们假设以下几种情况:
- 我们假设第一种情况: 训练集的误差为1%,验证集的误差11%。我们可以得知在训练集上表现很好,但是在验证集的表现较差。此时可能过度拟合了训练集。某种程度上说,验证集并没有充分利用交叉验证集的作用。如果处于上述的情况,我们称之为“高方差”。
假设另一种情况:训练集的误差为15%,验证集的误差16%。算法并没有在训练集中表现得很好,训练数据的拟合度不高就是数据欠拟合。所以相应的偏差比较高。但它对验证集产生的结果却是合理的。验证集的错误率只比训练集多了1%
再看另一种情况: 训练集的误差为15%,验证集的误差30%。这种情况下可以认为偏差较高,因为在训练集上结果不理想。同样方差也很高。
- 最后一种情况: 训练集的误差为0.5%,验证集的误差1%。方差与偏差都很低。
以上的情况都是在假设人眼辨别错误率接近0%。一般来说最优误差也被称之为贝叶斯误差。所以最优误差接近于0%。
假如在第二种情况下,最优误差是15%,那么15%的错误率对训练集来说也是非常合理的。
在之前的图中并没有给出相关高偏差、高方差的图,所以如下所示:
高偏差是因为几乎是一条直线,没有拟合大部分数据。
高方差是因为过度拟合了部分数据导致了方差偏高。
调整的基本思路
当在调优网络时,首先解决的是高偏差,再解决高方差
当偏差过高时,需要检查训练数据。使用更大的网络(更多隐藏层或者隐藏单元),或是花费更多的时间训练网络,或者使用更加先进的优化算法。或者使用更加先进的网络结构。直到可以拟合训练数据。
当方差过高时,需要检查测试集数据。使用更多的数据可以解决,但大多数情况下没有更多的数据。所以我们使用正则化来减少过拟合,或者使用更加先进的网络结构。
不过有两点需要注意
- 高偏差和高方差是两种不同的情况,处理的方式可能完全不同
- 现如今有许多工具或者方法是可以做到改进一方的同时对另一方不会造成过多影响。
训练一个更大的网络几乎没有任何负面影响,主要代价也只是计算时间。但前提是网络时比较规范的。
正则化
当你的方差过高时,你可以准备更多的数据,但大多数情况下因为成本或者其他因素不能满足这个条件。所以我们可以使用正则化进行解决网络过度拟合或网络误差。
我们先使用逻辑回归进行讨论:
来看损失函数:
我们在损失函数后加上这个其中
也就是W参数的欧几里德范数平方,这个方法叫L2正则化,因为此处使用了欧几里德法线又称L2范数。
为什么只正则化W参数而不管b,实际上你可以这样做。只是不经常这样做而已,因为W常常是一个高维参数矢量,已经可以表达高偏差问题。
在神经网络中W的占比b高很多。b几乎只是单个数字,正则化后的影响不大。
除了L2正则化外还有L2正则化
使用了L1正则化之后W最终会是稀疏的,也就是说W中会有很多0,有人说这样有助于压缩模型存储模型所占的空间更少了。
实际上L1正则化之后W最终会是稀疏的,但却不会降低太多存储空间,所以L1正则化的目的我认为不是这个。至少不是为了压缩模型。
现在人们越来越倾向使用L2正则化进行处理W参数。
在公式中$\lambda$是正则化参数,是一个超参,用于使W的值保持较小值,避免网络过拟合。
那在神经网络是怎么实现的呢
神经网络中你的损失函数是这样的
该矩阵范数被称为弗罗贝尼乌斯范数(Frobenius norm)
相应的反向传播公式中dw的计算需要改变$dW^{[L]} = \frac{1}{m} dz^{[L]}a^{[L - 1]T} + {\lambda \over m}W^{[L]}$
因为新得$dW$含有对W的操作,所以L2正则化有时被称为“权重衰减”(weight decay),因为W更新时会多减去${\alpha\lambda \over m}W^{[L]}$
为什么正则化可以减少过拟合
我们通过两个直观的例子进行解释
这几张图我们在之前的课程看见过,分别是高偏置,拟合,高方差。
现在我们假设这个网络已经过拟合了
我们的损失函数是这个
当$ \lambda $足够大时,因为Loss函数需要保持小,矩阵W会被更新成接近于0的值。这样就会消除许多隐藏单元所带来的影响(因为权重降低了)
这样的话,深层的网络就被极大的简化,变成一个很小的网络,几乎等同与逻辑回归。但是深度却很大。这样会使高方差的网络变成更接近作图的高偏差。但是在这个过程中会有一个时刻$\lambda$的值会使网络接近于拟合的状态。
直观理解就是当$\lambda$增加到足够大时W会接近于0,会消除或者减少许多隐藏单元的影响,最终这个网络会变得简单。神经网络会越来越接近逻辑回归。
另一种直观的例子是,假如我们使用的激活函数是tanh(z)。当$ \lambda $足够大时,W的值会减小,计算后的z也变小了,在tanh(z)的位置是接近线性的状态。导致激活函数几乎约等于线性函数。如果每层都是线性的那么整个网络就是一个线性网络。即使是一个非常深的网络,因为有着线性激活函数的特征最终我们只能计算线性函数,因此就不能适用于非常复杂的决策。以及过度拟合数据集的非线性决策边界。
Drop正则化
除了L2正则化,还有一个非常实用的正则化方法—dropout(随机失活)
假设你在训练如下图这样的神经网络。它存在过拟合的问题。这正是Dropout所要处理的问题。
dropout会遍历网络的每一层,并设置消除神经网络中节点的概率.假设网络中的每一层的每个节点都以抛硬币的方式设置概率。每个节点得以保留和消除的概率都是0.5设置完概率后,我们可能会消除一些节点。然后删掉从该节点进出的连线。最后得到一个节点更少,规模更小的网络。然后再使用反向传播的方式进行训练。对于其他样本也是如此。虽然看起来很疯狂,但是这是有效的。
不过可想而知,我们针对每个样本训练规模较小的网络。最后可能会让你明白为什么使用正则化进行处理网络。
不过如何实施dropout呢。方法有好几种接下来介绍最为常用的也就是inverted dropout(反向随机失活),接下来我们使用一个三层网络进行说明。
首先我们定义向量表示一个三层的dropout向量
上式的keep.prob
是一个具体的数字,相当于前面所说的0.5,本次我们将它的值设置为0.8,它表示保留某个隐藏单元的概率。表示消除任意一个隐藏单元的概率为0.2。它的作用就是生成随机矩阵。这边指的是d3中的对应值为1的概率。下一步将第三层经过激活函数计算的激活值a3。将a3乘以d3.这样就能将a3对应d3位置为0的值变为0。(虽然单独看d3时会是true和false的矩阵,但是python会将布尔值转为int值)。然后再将得到的a3除以keep.prob
。
让我解释为什么要这样做,假设我们第三层有50个神经元,那么a3的shape将为(50,m)因为我们有可能将keep.prob
比例的神经元去掉,那么就会消掉大约10个神经元。因为a4的计算是依赖于a3的,因为a3预计是将20%置为0。所以为了不影响a4,我们才除以keep.prob
,以便修正弥补所需的20%。
这种方式实现的Dropout使测试阶段变得容易。数据扩展问题变少。
早期的一些Dropout方法都没有除以keep-prob,所以在测试的阶段,平均值会变得越来越复杂,不过那些版本都不再使用了。
不过你会发现对于不同的样本,你所清除的隐藏单元也不同。
在测试以及做预测的时候我们不期望输出结果是随机的,所以我们会关掉Dropout。
理解Dropout
因为使用了 Dropout 之后, 神经元输入的内容可能在训练时被 drop, 所以它在进行输出时不能依赖于任意一个特征. 所以就会将权重分散开, 收缩了权重平方差.
不同层的 keep_prob 可以设置成不同的值, 在神经元多的层, 或许可以使用较低的 keep_prob 以防止拟合
Dropout 主要是在计算机视觉中使用.
建议使用的场景是当网络过拟合后, 再对网络进行处理
其他正则化的方式
- 可以通过将图片进行翻转/旋转裁剪扩充训练集
- early stopping: 尽早停止训练防止过拟合
在深度学习的过程中, 主要是两个步骤, 一个是选择一个算法优化代价函数(例如: 梯度下降, Momentuum, RMSprop, Adam). 二是对过拟合进行处理, 比如使用正则化, 扩充数据集.
这两个步骤通常使用不同的工具进行(正交化: Orthogonalization), 而 early stopping 的主要缺点是, 不能独立的处理这两个步骤.
正则化输入
- 怎么操作
假设我们有一个二维的数据集,我们需要以下两个步骤- 零均值化: 将数据集的每一个值减去均值(将数据的中心对齐0,0)
- 归一方差: 将数据集的每一个值除以平均平方值(使数据展开)
需要注意的点是测试集也需要对数据做同样的事.
- 为什么需要
因为没有进行正则化, 代价函数可能就像上图中左侧图片一样, w1的访问在 1..1000, 而 w2 的范围在 0..1 之间. 这就导致你必须使用一个较小的学习率, 因为会导致 w2 无法更新到最低点(低点附近来回震荡), 但是又会导致 w1 无法更早的到达低点(每次更新的步伐太短)
而正则化后的数据, 进行参数更新时, 多个维度上的数据都比较均匀, 到达损失函数的底端也相对容易
梯度消失和梯度爆炸
在多层次的深度学习网络中, 当参数 W 的值 大于或者小于1时, 经过多层的计算(指数级的放大和缩小), 会让值变得非常大或者非常小.
为了预防梯度消失和爆炸, 所以我们需要对 W 的初始值进行特殊处理.
我们可以从上图看出, z 的值是 n 个 W 与 X 相乘得到的. 那么我们不想让 Z 过大的一种直观方式就是将每个 w 初始化时 除以
使用 Relu 时, 可能设置成 更加合适
使用 tanh 时, 可能设置成 或者 更加合适
双边差公式
为了计算一个地方的斜率, 我们通常只会取, 当前点和另外一个点进行计算.
而双边差是以要计算的点为中心, 取前后一个 ,然后通过这两个点进行计算斜率, 这能更加接近实际的斜率, 误差在 内, 而使用简单的斜率计算, 误差可能在 内