######################### 卷积神经网络实践应用 ######################### 数据扩充及预处理 ######################### 深度卷积网络自身拥有强大的表达能力,不过正因如此,网络本身需要大量甚至海量数据来驱动模型训练,否则便有极大可能陷入 **过拟合** 的窘境。因此,在实践中 **数据扩充** (data augmentation)便成为深度模型训练的第一步。有效的数据扩充不仅能扩充训练样本数量,还能增加训练样本的多样性,一方面可避免过拟合,另一方面又会带来模型性能的提升。 简单的数据扩充方式 ====================================== 在数据扩充方面,简单的方法有图像 **水平翻转** (horizontally flipping)和 **随机截取** (random crops)。水平翻转操作会使原数据集扩充一倍;随机截取操作一般用较大(约0.8至0.9倍原图大小)的正方形在原图的随机位置处抠取图像块,每张图像随机抠取的次数决定了数据集扩充的倍数。 .. figure:: _static/1.jpg 除此,其他简单的数据扩充方式还有 **尺度变换** (scaling)、 **旋转** (rotating)、 **色彩抖动** (color jittering)等,从而增加卷积神经网络对物体尺度和方向上的鲁棒性。尺度变换一般是将图像分辨率变为原图的0.8、0.9、1.1、1.2、1.3等倍数,旋转操作将原图旋转一定角度,如-30度、-15度、15度、30度等。色彩抖动是在RGB颜色空间对原有RGB色彩分布进行轻微的扰动,也可在HSV颜色空间尝试随机改变图像原有的饱和度和明度(即,改变S和V通道的值)或对色调进行微调(小范围改变该通道的值)。 .. warning:: OpenCV读取图片的颜色通道为BGR而非RGB,python的图像库Image读取图片的颜色通道为RGB,可以通过命令cv2.COLOR_BGR2RGB进行颜色通道的转化。 特殊的数据扩充方式 ====================================== Fancy PCA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 首先对所有训练数据的R,G,B像素值进行 **主成分分析** (Principal Component Analysis,简称PCA)操作,得到对应的特征向量 :math:`{ p }_{ i }` 和特征值 :math:`{ \lambda }_{ i }\left( i=1,2,3 \right)` ,然后根据特征向量和特征值可以计算一组随机值 :math:`{ \left[ { p }_{ 1 },{ p }_{ 2 },{ p }_{ 3 } \right] \left[ { \alpha }_{ 1 }{ \lambda }_{ 1 },{ \alpha }_{ 2 }{ \lambda }_{ 2 },{ \alpha }_{ 3 }{ \lambda }_{ 3 } \right] }^{ T }` ,将其作为扰动加到原像素值中即可。其中, :math:`{ \alpha }_{ i }` 为取自以0为均值,标准差为0.1高斯分布的随机值。在每经过一轮训练(一个epoch)后, :math:`{ \alpha }_{ i }` 将重新随机选取并重复上述操作对原像素值进行扰动。Fancy PCA可以近似的捕获自然图像的一个重要特性,即物体特质与光照强度和颜色变化无关。比如图片呈现紫色,即主要含有红色和蓝色,少量绿色,Fancy PCA就会对R和B通道增减很多,G通道相对较少一些。 **其本质是一种更加平滑且合理的色彩抖动操作** 。 .. hint:: **PCA** ,是一种使用广泛的数据降维算法。将数据从高维空间映射至低维空间,使得数据的方差尽可能大,即保留更多的信息。特征值越大,对应的特征向量所指示方向的方差越大。 .. figure:: _static/2.jpg :align: center :height: 228 监督式数据扩充 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 监督式数据扩充,是一种利用图像标记信息的新型数据扩充方式。有时采用随机截取等简单的数据扩充方式会丢失图片的重要信息,不免会造成标记混乱,势必影响模型的分类精度。 .. figure:: _static/3.jpg :align: center :width: 304 :height: 228 首先根据原数据训练一个分类的初始模型。而后利用该模型,对每张图生成对应的 **特征图** (feature map)或 **热力图** (heat map)。这张特征图可指示图像区域与样本标签间的相关概率。之后可根据此概率映射回原图选择较强相关的图像区域作为扣取的图像块。 **其本质是一种添加先验信息的随机截取** 。 .. figure:: _static/4.jpg 数据预处理 ====================================== 训练前,数据预处理操作是必不可少的一步。机器学习中,对于输入特征做 **归一化** (normalization)预处理操作是常见的步骤。类似的,在图像处理中,图像的每个像素信息同样可以看做一种特征。在实践中,对每个特征减去平均值来中心化数据是非常重要的,这种归一化处理方式被称作 **"中心式归一化"** (mean normalization)。卷积神经网络中的数据预处理通常是计算训练集图像像素均值,之后在处理训练集、验证集和测试集图像时需要分别减去该均值。这样做的动机是,我们默认自然图像是一类平稳的数据分布(即数据每一个维度的统计都服从相同分布),此时,在每个样本上减去数据的统计平均值(逐样本计算)可以移除共同部分,凸显个体差异。 .. figure:: _static/5.jpg 网络参数初始化 ######################### 神经网络模型一般依靠 **随机梯度下降法** 进行模型训练和参数更新,网络的最终性能与收敛得到的最优解直接相关,而收敛效果实际上又很大程度取决于网络参数最开始的初始化。理想的网络参数初始化使模型训练事半功倍,相反,糟糕的初始化方案不仅会影响网络收敛甚至会导致 **"梯度弥散"** 或 **"爆炸"** 致使训练失败。 举个例子,如网络使用 **Sigmoid** 函数作为非线性激活函数,若参数初始化为过大值,前向运算时经过Sigmoid函数后的输出结果几乎全为0或1的二值,而导致在反向运算时的对应梯度全部接近为0。这时便发生了"梯度弥散"现象。无独有偶,不理想的初始化对于 **ReLU** 函数也会产生问题。若使用了糟糕的参数初始化,前向运算时的输出结果会有可能全部为负,经过ReLU函数后此部分变为全0,在反向运算时则毫无响应。这便是ReLU函数的"死区"现象。 .. hint:: **梯度弥散** ,在神经网络反向传播求解各个参数相对于误差的梯度时,由于使用梯度求解的连锁规则,越靠前的网络层的参数梯度中有大量激活函数导数的连乘。如果这些激活函数导数比较小,就会使得整体梯度接近于0,对应参数在反向传播过程中几乎不变,这部分网络失去了对数据的拟合能力。 全零初始化 ====================================== 通过合理的数据预处理和规范化,当网络收敛到稳定状态时,参数(权值)在理想情况下应基本保持正负各半的状态(此时期望为0)。因此,一种简单且听起来合理的参数初始化做法是,干脆将所有参数都初始化为0,因为这样可使得初始化全零时参数的期望与网络稳定时参数的期望一致为零。 不过,如果参数全初始化为0时网络不同神经元的输出必然相同,相同输出则导致梯度更新完全一样,这样便会令更新后的参数仍然保持一样的状态。换句话说,如若参数进行了全零初始化,那么网络同一层神经元的激活值将完全一样,等价于网络每层神经元的数量均为1,网络出现大量的冗余,模型泛化能力大大降低。 随机初始化 ====================================== 基于全零初始化的弊端,我们可将参数值随机设定为接近0的一个很小的随机数(有正有负)。在实际应用中,随机参数服从 **高斯分布** (Gaussian distribution)或 **均匀分布** (uniform distribution)都是较有效的初始化方式。 但是,随机初始化并没有考虑到神经元数量对输出数据分布方差的影响。 Xavier和MSRA初始化 ====================================== .. important:: 假设有随机变量 :math:`x` 和 :math:`\omega`,它们服从均值为0,方差为 :math:`{ \sigma }` 的分布,则 :math:`{ \omega \ast x }` 服从均值为0,方差为 :math:`{ \sigma }^{ 2 }` 的分布; :math:`{ \omega \ast x }+{ \omega \ast x }` 服从均值为0,方差为 :math:`2\ast { \sigma }^{ 2 }` 的分布。 **前向传播** 过程,假设参数 :math:`\omega` 以均值为0,方差为 :math:`{ \sigma }_{ \omega }` 的方式进行初始化,而输入 :math:`x` 的均值为0,方差为 :math:`{ \sigma }_{ x }`。 对于卷积层(全连接层一样),有 :math:`n` 个参数( :math:`n=channel\ast kernel\_ h\ast kernel\_ w` ),则 :math:`{ z }_{ j }=\sum _{ i }^{ n }{ { \omega }_{ i }\ast { x }_{ i } }`,那 :math:`{ z }_{ j }` 的方差就为 :math:`n\ast { \sigma }_{ \omega }\ast { \sigma }_{ x }` 。 为了更好的表达,将层号写在上标处,同时忽略非线性激活过程,则 .. math:: { \sigma }_{ x }^{ 1 }={ \sigma }_{ x } .. math:: { \sigma }_{ x }^{ 2 }={ n }^{ 1 }\ast { \sigma }_{ x }^{ 1 }\ast { \sigma }_{ \omega }^{ 1 } .. math:: { \sigma }_{ x }^{ 3 }={ n }^{ 2 }\ast { \sigma }_{ x }^{ 2 }\ast { \sigma }_{ \omega }^{ 2 } .. math:: { \sigma }_{ x }^{ k }={ n }^{ k-1 }\ast { \sigma }_{ x }^{ k-1 }\ast { \sigma }_{ \omega }^{ k-1 } .. math:: { \sigma }_{ x }^{ k }={ n }^{ k-1 }\ast { \sigma }_{ x }^{ k-1 }\ast { \sigma }_{ \omega }^{ k-1 }={ n }^{ k-1 }\ast \left( { n }^{ k-2 }\ast { \sigma }_{ x }^{ k-2 }\ast { \sigma }_{ \omega }^{ k-2 } \right) \ast { \sigma }_{ \omega }^{ k-1 }={ \sigma }_{ x }^{ 1 }\ast \prod _{ i=1 }^{ k-1 }{ \left( { n }^{ i }\ast { \sigma }_{ \omega }^{ i } \right) } 分析:若 :math:`{ n }^{ i }\ast { \sigma }_{ \omega }^{ i }` 总是大于1,则随着层数增加,数值方差变大,就容易导致溢出,"爆炸";若 :math:`{ n }^{ i }\ast { \sigma }_{ \omega }^{ i }` 总是小于1,则随着层数增加,数值方差变小,就容易导致数据差异小而不易产生有力的梯度。 因此可以使得每层 :math:`{ n }^{ i }\ast { \sigma }_{ \omega }^{ i }` 等于或接近于1,即 :math:`{ \sigma }_{ \omega }^{ i }=\frac { 1 }{ { n }^{ i } }`。 **反向传播** 过程,同样忽略非线性激活过程,第 :math:`k` 层的梯度 :math:`\frac { \partial Loss }{ \partial { x }^{ k } }`,则第 :math:`k-1` 层的输入梯度为 :math:`\frac { \partial Loss }{ \partial { x }_{ j }^{ k-1 } } =\sum _{ i=1 }^{ n }{ \frac { \partial Loss }{ \partial { x }_{ j }^{ k } } } { \omega }_{ j }^{ k }`, .. math:: Var\left( \frac { \partial Loss }{ \partial { x }_{ j }^{ k-1 } } \right) ={ n }^{ k }\ast Var\left( \frac { \partial Loss }{ \partial { x }_{ i }^{ k } } \right) \ast { \sigma }_{ \omega }^{ k } .. math:: Var\left( \frac { \partial Loss }{ \partial { x }_{ j }^{ 1 } } \right) =Var\left( \frac { \partial Loss }{ \partial { x }_{ i }^{ k } } \right) \coprod _{ i=1 }^{ k-1 }{ { n }^{ i } } \ast { \sigma }_{ \omega }^{ i } .. math:: Var\left( \frac { \partial Loss }{ \partial { x }_{ j }^{ k-1 } } \right) =Var\left( \frac { \partial Loss }{ \partial { x }_{ i }^{ k } } \right) \Rightarrow { \sigma }_{ \omega }^{ k }=\frac { 1 }{ { n }^{ k } } 对于前、后向传播所得结果,前向中 :math:`n` 表示输入维度,后向中 :math:`n` 表示输出维度,则需同时满足 .. math:: { \sigma }_{ \omega }^{ i }=\frac { 1 }{ { n }^{ i } } \quad \quad { \sigma }_{ \omega }^{ i }=\frac { 1 }{ { n }^{ i+1 } } 于是为了均衡考量,最终我们的权重方差应满足: .. math:: { \sigma }_{ \omega }^{ i }=\frac { 2 }{ { n }^{ i+1 }+{ n }^{ i } } 接下来用均匀分布具体实施,假定初始化范围 :math:`\left[ -a,a \right]`,对于均与分布有 :math:`Var\left( x \right) =\frac { { \left( a-\left( -a \right) \right) }^{ 2 } }{ 12 } =\frac { { a }^{ 2 } }{ 3 }`,令它等于 :math:`{ \sigma }_{ \omega }^{ k }` 即可,即 :math:`{ \sigma }_{ \omega }^{ k }=\frac { { a }^{ 2 } }{ 3 }`。又因为 :math:`{ \sigma }_{ \omega }^{ i }=\frac { 2 }{ { n }^{ i+1 }+{ n }^{ i } }`,因此 :math:`{ a }^{ 2 }=\frac { 6 }{ { n }^{ k+1 }+{ n }^{ k } }`。 Xavier初始化方法即为把参数初始化成 :math:`\left[ -\sqrt { \frac { 6 }{ { n }^{ k+1 }+{ n }^{ k } } } ,\sqrt { \frac { 6 }{ { n }^{ k+1 }+{ n }^{ k } } } \right]` 范围的均匀分布。 Xavier推导时假设激活函数是线性的,因为S形激活函数在 :math:`x=0` 附近近似于线性。但目前常用的激活函数是ReLU函数及其扩展,因此需要考虑非线性变换。 MSRA初始化推导过程和Xavier类似,只考虑输入维度 :math:`n` 时,那么权重参数将服从于均值为0,方差为 :math:`\frac { 2 }{ n }` 的高斯分布,即 :math:`\omega \sim G\left[ 0,\frac { 2 }{ n } \right]`。 迁移学习(???????) ====================================== 除了直接初始化网络参数,一种简便易行且十分有效的方式则是利用预训练模型(pre-trained model),将预训练模型的参数作为新任务上模型的参数初始化。由于预训练模型已经在原先任务上收敛到较理想的局部最优解,加上很容易获得这些预训练模型,用此最优解作为新任务的参数初始化无疑是一个优质首选。 激活函数 ######################### 激活函数是种非线性变换,它使得模型的表达能力更加的丰富。在深度模型的前提下,加入非线性变换可以使得模型的表达能力更加的丰富。没有激活函数的神经网络,完全可以等价于单层的神经网络,深度学习就无从体现。激活函数的设计是一个比较活跃的研究领域,并没有明确的理论性指导。 阶跃函数 ====================================== 阶跃函数是一种特殊的连续时间函数,是一个从0跳变到1的过程,属于奇异函数。形式为 .. math:: f(x)=\begin{cases} 0,\quad \quad x\le 0 \\ 1,\quad \quad otherwise \end{cases} 它在信号处理、积分变换等领域都有着重要的作用。神经网络又被称为多层感知机(MLP),顾名思义它是由多个感知机算法串联而成的。感知机的激活函数为阶跃函数,因此理所当然阶跃函数成为神经网络激活函数的重要选择之一。但是由于阶跃函数的数学性质不好,因而在现实工程中基本忽略阶跃函数,选择一些阶跃函数的变形作为神经网络的激活函数。 S形函数 ====================================== S形函数是一类函数的统称,因为这类函数形状类似于"S",例如Sigmoid函数和Tanh函数。它们都是阶跃函数的近似,同时也避免了阶跃函数数学性质上的不足。Sigmoid函数和Tanh函数形式为 .. math:: Sigmoid\left( x \right) \quad =\quad \frac { 1 }{ 1+{ e }^{ -x } } \\ Tanh\left( x \right) \quad =\quad \frac { 1-{ e }^{ -2x } }{ 1+{ e }^{ -2x } } Sigmoid函数,将一个实数也压缩至0到1之间,且输入值越小,输出值越接近于0;输入值越大,输出值越接近于1。可以近似认为这种输出值是二分类类别为1的概率。这与人脑中神经元工作机理非常相似,输出为0相当于神经元抑制,输出为1相当于神经元激活。Tanh函数是由Sigmoid函数变形得到的,做伸缩和平移变换。S形函数的一个重大弊端就是,左右软饱和性,即当输入稍微远离坐标原点时,函数的梯度就变得很小,深度学习的多层神经网络在反向传播时,层数越靠前的梯度就会变得越来越小,几乎为0。这就导致了权重参数对损失函数的影响几乎为0,权重参数在反向传播时无法更新,模型无法正常学习,这就是梯度弥散制约深层网络训练学习的问题之一。 ReLU函数及其扩展 ====================================== **线性修正单元** (ReLU)及其扩展是目前激活函数选择的最佳对象。形式为 .. math:: f(x)=\begin{cases} x,\quad \quad x\ge 0 \\ 0,\quad \quad otherwise \end{cases} 使用ReLU的神经网络收敛速度更快,因为它是部分线性的。ReLU只需要一个阈值就可以得到激活值,不需要复杂的计算,同时它的梯度计算也是非常的方便。ReLU激活函数为神经网络提供了一种稀疏表达能力,可以减少权重参数的相互依赖关系,从而缓解过拟合的发生。因为当传入的参数不大于0时,其激活值均为0,这就使得部分的神经元节点被抑制,网络稀疏。对于ReLU激活函数,当传入的参数大于0时,其梯度就恒为1,使得梯度弥散的问题得以缓解,为深度学习的有效训练提供了可能。 其次ReLU激活函数也存在一些问题,使得我们不得不对ReLU激活函数进行一些扩展。与Sigmoid激活函数类似,其激活均值恒大于0,那么对于 :math:`z=\omega x+b`,每个 :math:`x` 均大于0,在反向传播算法中关于 :math:`\omega` 的梯度要么均为正,要么均为负。这会导致在梯度下降权值参数更新的过程中出现"Z"字型下降,使得更新效率比较低。同时使用ReLU激活函数的网络在训练时比较容易崩溃。比如,在反向传播梯度更新时,神经元节点更新可能会使得在之后的激活过程中一直抑制为0,这就是神经元节点"死亡"。当学习速率较大时,网络中的大部分神经元节点都可能出现这种情况,使得神经网络的学习崩溃。 **L-ReLU** 激活函数形式为 .. math:: f(x)=\begin{cases} x,\quad \quad x\ge 0 \\ \alpha x,\quad otherwise \end{cases} 当传入的参数大于0时,线性输出激活值;当传入的参数不大于0时,不再使得神经元节点抑制为0,给它一个较小的常数值,以常数值倍数线性输出激活值,这样就保留了一些负轴的信息。使得其输出的激活值均值向0靠近,同时也在一定程度上缓解训练过程中因为学习速率过大而造成的神经元节点"死亡"。P-ReLU,与L-ReLU类似,将其中的常数值作为一个可训练的参数值。这里只是多增加了一个可训练的参数,因此不必担心过拟合问题的困扰。让参数值通过训练得到,能够使得模型更加贴合不同任务的数据集,也避免了因经验不足选择参数不合理的问题。R-ReLU,与L-ReLU类似,将其中的常数值作为一个随机的参数值。因此R-ReLU是一种非确定性的激活函数,这种随机性类似于一种噪声,能够使得模型在一定程度上起到正则化的效果。 **ELU** 激活函数形式为 .. math:: f(x)=\begin{cases} x,\quad \quad \quad \quad \quad \quad \quad x\ge 0 \\ \alpha \left( exp\left( x \right) -1 \right) ,\quad otherwise \end{cases} 它融合了Sigmoid和ReLU激活函数,具有左软饱和性。ELU左侧软饱和性能够让模型对输入的变化或者噪声更加的鲁棒,右侧线性部分使得模型能够缓解梯度弥散的问题。同时由于ELU的输出激活值均值接近于0,因此收敛速度更快。 下面着重介绍下 **Maxout**,它是ReLU的一般形式。Maxout激活函数相当于在原始神经网络两层中间新添加了一层。通俗理解,传统多层感知机(MLP)网络在第 :math:`i` 层到第 :math:`i+1` 层,参数只有一组,即 :math:`{ z }_{ i }={ x }^{ \top }{ \omega }_{ ...i }+{ b }_{ i }` ,再通过激活函数输出激活值。但在Maxout网络中,参数则有 :math:`k` 组,即有 :math:`k` 个 :math:`z` 值, :math:`{ z }_{ ij }={ x }^{ \top }{ \omega }_{ ...ij }+{ b }_{ ij }`,然后取其中最大值作为输出的激活值。这中间出现了一个超参数 :math:`k`。这里可以看出Maxout的缺点,即权重参数个数成 :math:`k` 倍增加。不过我们应该更加关注Maxout函数的优点,它并非是一个固定的函数,而是一类函数的统称,可以退化成ReLU。它是一种可学习的激活函数,因为Maxout函数中的参数是可学习变化的,使得它更加契合某个具体的实验数据。它是一种分段线性函数,只要 :math:`k` 足够大,可以以任意精度近似逼近任何的凸函数。大部分的Maxout函数在某一端饱和都不可能,因此可以有效的缓解梯度弥散问题。虽然它产生的表示不再是稀疏的(ReLU除外),但是它的梯度是稀疏的同时使用Dropout可以将它稀疏化。综上,正因为Maxout函数可以近似逼近任意凸函数,则Maxout网络就可以与传统MLP一样拟合任意连续函数。只要Maxout单元含有任意多个中间层神经元节点,则只要有两个隐层的Maxout网络就可以实现任意连续函数的近似了。 .. figure:: _static/6.jpg 网络正则化 ######################### 机器学习中,泛化能力是模型最终能力的体现,而不仅仅局限于在训练集上的预测能力。当模型的预测能力在训练集和测试集上均不佳时,称之为欠拟合;而当模型的预测能力在训练集的表现远远优于测试集时,称之为过拟合。欠拟合问题相对比较容易解决,增加模型的复杂度即可。过拟合的问题是无法彻底避免的,只能在一定程度上缓解。在机器学习中,许多策略技巧被设计用来增大训练集的误差来减少测试集的误差,称之为正则化技巧。它在深度学习中的作用尤为明显,因此过拟合问题是深度学习的难点之一。 范数约束 ====================================== 以多项式曲线拟合为例,假设有 :math:`N` 个数据点的训练集,通过如下方式获得。首先计算函数 :math:`\sin { 2\pi x }` 的对应值,然后给每个点增加一个小的高斯随机噪声,得到每个 :math:`x` 对应的 :math:`y` 值。我们希望通过这些数据的训练,对于每个新的输入的 :math:`x` 值预测出相对应的 :math:`y` 值。由于这些数据比较有限,且受到随机噪声的干扰,任务比较困难。由于不知道数据产生的方式,我们可以假设用多项式曲线来拟合这组训练数据。我们分别选择0阶、1阶、3阶和9阶多项式来拟合这组训练数据。显然0阶和1阶多项式的拟合效果较差,属于欠拟合。3阶多项式则能很好的拟合这组训练数据。而9阶多项式能完美的拟合这组训练数据。但是得到的9阶多项式曲线剧烈震荡,相比较数据的产生函数 :math:`\sin { 2\pi x }` 而言,过拟合的问题比较严重。通过 **泰勒公式** 可知,阶数越高的多项式越能更好地拟合 :math:`\sin { 2\pi x }` ,且它的自由度高于3阶多项式,更加灵活,理应比3阶多项式的效果更好。查看不同阶数多项式的系数值,发现随着多项式阶数的增加,系数大小变化越剧烈。因此可以考虑引入一种先验,来抑制系数的剧烈变化,即加入正则项来缓解过拟合问题。通过贝叶斯思想可以这样理解,即引入一种先验,使得多项式的系数满足均值为0且单位方差的高斯分布(二范数),使得最大似然估计,变化为最大后验概率估计,即结构风险最小化。正则化技巧符合奥卡姆剃刀原理,在所有可能选择的模型中,能够很好地解释已知数据且十分简单的模型才是最佳模型。这种方法又叫权值衰减。 .. figure:: _static/7.jpg .. figure:: _static/8.jpg :align: center :width: 304 :height: 228 二范数约束 .. math:: \tilde { E } \left( \omega \right) =E\left( \omega \right) +\frac { \lambda }{ 2 } { \omega }^{ T }\omega .. hint:: 泰勒公式是一个用函数在某点的信息描述其附近取值的公式。如果函数足够平滑的话,在已知函数在某一点的各阶导数值的情况之下,泰勒公式可以用这些导数值做系数构建一个多项式来近似函数在这一点的邻域中的值。泰勒公式还给出了这个多项式和实际的函数值之间的偏差。 .. math:: f\left( x \right) =\frac { f\left( { x }_{ 0 } \right) }{ 0! } +\frac { f^{ 1 }\left( { x }_{ 0 } \right) }{ 1! } \left( x-{ x }_{ 0 } \right) +\frac { f^{ 2 }\left( { x }_{ 0 } \right) }{ 2! } { \left( x-{ x }_{ 0 } \right) }^{ 2 }+\cdots +\frac { f^{ n }\left( { x }_{ 0 } \right) }{ n! } { \left( x-{ x }_{ 0 } \right) }^{ n }+{ R }_{ n }\left( x \right) 数据扩充 ====================================== 极大似然估计的最大局限性在于极大似然估计低估了分布的方差,而这与过拟合问题密切相关。 .. figure:: _static/9.jpg :align: center :width: 550 直观解释,极大似然估计的方差是相对于估计的均值进行的测量,虽然均值估计无偏,但是每次估计都会与真实的均值有差异,这就导致了方差估计的偏移。当 :math:`N` 与 :math:`N-1` 越接近时,估计的偏差会越来越小,因此增加数据集的数量可以有效的缓解过拟合问题。但是由于 :math:`N` 与 :math:`N-1` 永远存在着差异,所以过拟合问题只能部分缓解而无法彻底解决。 .. figure:: _static/10.jpg :align: center :width: 304 噪声鲁棒性 ====================================== 就某些模型而言,在模型的输入加上方差较小的噪声时,其实等价于加入正则项,对权重参数施加范数惩罚(?????????)。 .. figure:: _static/11.jpg :align: center :width: 550 比如在输入中引入高斯噪声起到的正则化效果等同于 :math:`L2` 权值衰减正则化项。其本质也是一种数据扩充操作。 多任务学习 ====================================== 多任务学习可以视为是对权重参数施加的一种软约束,这和权值衰减正则化项对权重参数直接施加的约束有着异曲同工之妙。它是通过合并多个任务中的样例来降低泛化误差提高泛化能力的一种方式。因为共享权重参数,使得模型的统计强度大大提高。在这几个任务的训练过程中,权重参数是实时共享的,它们共同约束着这些权重参数的学习,向着更优的方向进行更新。如果我们将其中的某一个任务视为主任务的话,那么其他任务的学习就等价于间接地给模型施加一个较强的先验,这和权值衰减正则化项的思想有些类似。 .. figure:: _static/12.jpg :align: center :width: 300 提前终止 ====================================== 随着神经网络训练的进行,训练集的误差会越来越小,而测试集的误差会先变小再变大,因此并非训练次数越多越好,这样可能出现严重的过拟合问题。此时人为的提前停止训练就尤为重要,那么训练多少次才更合理,对于不同的任务和数据集而言并没有统一的规则。通过绘制测试集误差随训练次数的曲线变化图来确定训练次数显然是一个最有效且直接的办法。在训练过程中,每迭代 :math:`n` 次,我们就需要在测试集中对模型的泛化能力进行计算预估。当测试集误差不再减小或者减小的幅度很小,又或者测试集误差开始变大时,就需要及时停止训练,此时模型的泛化能力才更佳,过拟合的问题才能最大程度的缓解。目前为止,我们只是说明了提前停止训练是种正则化技巧,且能有效缓解过拟合问题。 .. figure:: _static/15.jpg :align: center :width: 500 接下来,我们可以从数学角度更加正式地说明它是如何一种正则化机制。其实提前停止训练本质上就是加入正则项,也就是权值衰减。假设迭代次数为 :math:`\tau`,学习速率为 :math:`\eta`,那么 :math:`\tau \eta` 这个量就相当于正则化参数λ的倒数。提前停止训练,使得 :math:`\tau` 减小,就等价于 :math:`\lambda` 变大,加大正则化项的权重比例,使得权值衰减的更厉害。 .. figure:: _static/13.jpg :align: center :width: 300 模型平均 ====================================== 所谓的Bagging思想,即通过一种模型平均的思想来组合几个模型达到缓解过拟合减少方差。使用Bagging集成思路核心就是,不同的模型在测试集上的误差不会完全相同,因此模型平均的方法就能使得误差某种程度上相互抵消。模型期望损失即泛化误差等于偏差的平方加上方差以及一个小的常数噪声项。偏差,即预测值与真实值之间的差异;方差,即预测值之间的波动情况;而常数噪声项,即在当前任务上任何学习算法所能达到的期望泛化误差的下界,它刻画了问题本身的难度。对于复杂的模型,容易过拟合,此时偏差较小而方差较大;对于简单的模型,容易欠拟合,此时偏差较大而方差较小。Bagging思想就是让几个模型充分训练达到过拟合,此时偏差小而方差大,再通过模型平均的方法给出最终的预测值,这样可以有效的降低方差,整体就使得偏差小而方差小,即可以有效降低整个模型的泛化误差,缓解过拟合问题。其中Dropout技巧就是Bagging集成思路的一种体现。使用Dropout的深度神经网络可以使得网络尽量的伸展,这就使得模型过拟合。但是网络在训练过程中,随机使得某些神经元节点暂时不工作,因此每次训练过程这些网络都是有很大差异的,可以将每次训练的网络看成一个单独的模型,随机性使得这些网络有着较大的差异,最终在网络预测时所有神经元节点均恢复工作,这就是模型平均的体现,从而能有效的缓解深层神经网络过拟合的问题。 .. figure:: _static/14.jpg :align: center :width: 500 超参数设定和网络训练 ######################### 网络超参数设定 ====================================== 网络输入设定 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 使用卷积神经网络处理图像问题时,对不同输入图像为得到同规格输出,同时便于GPU设备并行,会统一将图像压缩到 :math:`{ 2 }^{ n }` 大小,一些经典案例如:CIFAR-10数据的 32 × 32 像素,STL数据集的 96 × 96 像素,ImageNet数据集常用的 224 × 224 像素。另外,若不考虑硬件设备限制(通常是GPU显存大小),更高分辨率图像作为输入数据(如 448 × 448、672 × 672 等)一般均有助于网络性能的提升。不过,高分辨率图像会增加模型计算消耗而导致网络整体训练时间延长。此外,需指出的是,由于一般卷积神经网络采用全连接层作为最后分类层,若直接改变原始网络模型的输入图像分辨率,会导致原始模型卷积层的最终输出无法输入全连接层的状况,此时须重新改变全连接层输入滤波器的大小或重新指定其他相关参数。 卷积层参数的设定 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 卷积层的超参数主要包括卷积核大小、卷积操作的步长和卷积核个数。关于卷积核大小,小卷积核相比大卷积核有两项优势: (1)增强网络容量和模型复杂度; (2)减少卷积参数个数。因此,实践中推荐使用 3 × 3 及 5 × 5 这样的小卷积核,其对应卷积操作步长建议设为1。 此外,卷积操作前还可搭配填充操作(padding)。该操作有两层功效: (1)可充分利用和处理输入图像(或输入数据)的边缘信息; (2)搭配合适的卷积层参数可保持输出与输入同等大小,而避免随着网络深度增加,输入大小的急剧减小。 例如当卷积核大小为 3 × 3、步长为1时,可将输入数据上下左右各填充1单位大小的黑色像素(值为0,故该方法也被称为"zeros-padding"),便可保持输出结果与原输入同等大小,此时 :math:`p=1`;当卷积核为 5 × 5、步长为1时,可指定 :math:`p=2`,也可保持输出与输入等大。泛化来讲,对卷积核大小 f × f 、步长为1的卷积操作,当 :math:`p=(f-1)/2` 时,便可维持输出与原输入等大。最后,为了硬件字节级存储管理的方便,卷积核个数通常设置为2的次幂,如64,128,512 和 1024 等等。这样的设定有利于硬件计算过程中划分数据矩阵和参数矩阵,尤其在利用显卡计算时更为明显。 .. figure:: _static/16.jpg :align: center :width: 500 池化层参数的设定 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 同卷积核大小类似,池化层的核大小一般也设为较小的值,如 2 × 2,3 × 3 等。 常用的参数设定为 2 × 2、池化步长为2。在此设定下,输出结果大小仅为输入数据长宽大小的四分之一,也就是说输入数据中有75%的响应值(activation values)被丢弃,这也就起到了"下采样"的作用。为了不丢弃过多输入响应而损失网络性能,极少使用超过 3 × 3 大小的池化操作。 训练技巧 ====================================== 训练数据随机打乱 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 信息论(information theory)中曾提到:"从不相似的事件中学习总是比从相似事件中学习更具信息量"。在训练卷积神经网络时,尽管训练数据固定,但由于采用了随机批处理(mini-batch)的训练机制,因此我们可在模型每轮(epoch)训练进行前将训练数据集随机打乱(shuffle),确保模型不同轮数相同批次"看到"的数据是不同的。这样的处理不仅会提高模型收敛速率,同时,相对固定次序训练的模型,此操作会略微提升模型在测试集上的预测结果。 学习率的设定 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 模型训练时另一关键设定便是模型学习率(learning rate),一个理想的学习率会促进模型收敛,而不理想的学习率甚至会直接导致模型直接目标函数损失值"爆炸"无法完成训练。学习率设定时可遵循下列两项原则: (1)模型训练开始时的初始学习率不宜过大,以0.01和0.001为宜;如发现刚开始训练没几个批次(mini-batch)模型目标函数损失值就急剧上升,这便说明模型训练的学习率过大,此时应减小学习率从头训练; (2)模型训练过程中,学习率应随轮数增加而减缓。减缓机制可有不同,一般为如下三种方式: a.轮数减缓(step decay),如五轮训练后学习率减半,下一个五轮后再次减半; b.指数减缓(exponential decay),即学习率按训练轮数增长指数递减等,若原始学习率为 :math:`{ lr }_{ 0 }`,学习率按照下式递减 :math:`{ lr }_{ t }={ lr }_{ 0 }{ e }^{ -kt }`,其中 :math:`k` 为超参数用来控制学习率减缓幅度, :math:`t` 为训练轮数(epoch); c.分数减缓(1/t decay)。若原始学习率为 :math:`{ lr }_{ 0 }`,学习率按照下式递减 :math:`{ lr }_{ t }={ lr }_{ 0 }/\left( 1+kt \right)`,其中 :math:`k` 为超参数用来控制学习率减缓幅度, :math:`t` 为训练轮数(epoch)。 除此之外,寻找理想学习率或诊断模型训练学习率是否合适时可借助模型训练曲线(learning curve)的帮助。训练深度网络时不妨将每轮训练后模型在目标函数上的损失值保存。可将自己的训练曲线与图中曲线"对号入座":若模型损失值在模型训练刚开始的几个批次直接"爆炸"(黄色曲线),则学习率过大,此时应大幅减小学习率从头训练网络;若模型一开始损失值下降明显,但"后劲不足"(绿色曲线),此时应使用较小学习率从头训练,或在后几轮改小学习率仅重新训练后几轮即可;若模型损失值一直下降缓慢(蓝色曲线),此时应稍微加大学习率,然后继续观察训练曲线;直至模型呈现红色曲线所示的理想学习率下的训练曲线为止。 .. figure:: _static/17.jpg :align: center :width: 500 批规范化操作 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 批规范化操作(batch normalization,简称BN),不仅加快了模型收敛速度,而且更重要的是在一定程度缓解了深层网络的一个难题“梯度弥散”, 从而使得训练深层网络模型更加容易和稳定。另外,批规范化操作不光适用于深层网络,对传统的较浅层网络而言,批规范化也能对网络泛化性能起到一定提升作用。 目前批规范化已经成为了几乎所有卷积神经网络的标配。在模型每次随机梯度下降训练时,通过mini-batch来对相应的网络响应(activation)做规范化操作, 使得结果(输出信号各个维度)的均值为0,方差为1。 至于BN奏效的原因,需要首先来说说"内部协变量偏移"(internal covariate shift)。 我们应该知道在统计机器学习中的一个经典假设是"源空间(source domain)和目标空间(target domain)的数据分布(distribution)是一致的"。 如果不一致,那么就出现了新的机器学习问题,如,迁移学习等。而协变量偏移(covariate shift)就是分布不一致假设之下的一个分支问题,它是指源空间和目标空间的条件概率是一致的, 但是其边缘概率不同,即:对所有 x ∈ X ,Ps(Y |X = x) = Pt(Y |X = x),但 Ps(x) ̸= Pt(x)。各位细想便会发现:对于神经网络的各层输出,由于它们经过了层内操作作用, 其分布显然与各层对应的输入信号分布不同,而且差异会随着网络深度增大越来越大,不过它们所"指示"的样本标记(label)仍然保持不变,这便符合了协变量偏移的定义。 由于是对层间信号的分析,也即是"内部"(internal)一称的由来。在实验中,发现可通过BN来规范化某些层或所有层的输入,从而可以固定每层输入信号的均值与方差。 这样一来,即使网络模型较深层的响应或梯度很小,也可通过BN的规范化作用将其的尺度变大,以此便可解决深层网络训练很可能带来的"梯度弥散"问题。 关于BN的使用位置,在卷积神经网络中BN一般应作用在非线性映射函数前。另外,若神经网络训练时遇到收敛速度较慢,或"梯度爆炸"等无法训练的状况发生时也可以尝试用BN来解决。 同时,常规使用情况下同样可加入BN来加快模型的训练速度,甚至提高模型精度。 优化算法 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 网络模型优化算法选择,深度卷积神经网络通常采用随机梯度下降类型的优化算法进行模型训练和参数求解。随机梯度下降法,基于动量的随机梯度下降法,Nesterov型动量随机下降法,Adagrad法,Adadelta法,RMSProp法,Adam法以及与二阶优化算法结合的优化算法。 网络微调 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 微调神经网络,在参数初始化一节层提到,除了从头训练自己的网络,一种更有效、高效的方式是微调已预训练好的网络模型。微调预训练模型简单来说, 就是用目标任务数据在原先预训练模型上继续进行训练过程。这一过程中需注意以下细节: 1.由于网络已在原始数据上收敛,因此应设置较小的学习率在目标数据上微调,如 :math:`{ 10 }^{ -4 }` 数量级或以下; 2.卷积神经网络浅层拥有更泛化的特征(如边缘、纹理等),深层特征则更抽象对应高层语义。因此,在新数据上微调时泛化特征更新变化程度较小,高层语义特征更新变化程度较大,故可根据层深对不同层设置不同学习率:即网络深层的学习率可稍大于浅层学习率; 3.卷积神经网络的卷积层一般提取的是图像的共性基本特征,而后面的全连接层一般是根据不通任务提取的个性特征。因此,在微调卷积神经网络时,基本重新初始化全连接层参数而保持卷积层参数不变,同时使得全连接层的学习率大于卷积层(极端情况,比如数据较少任务较简单,可以固定卷积层参数只微调全连接层参数); 4.根据目标任务数据与原始数据相似程度采用不同微调策略:当目标数据较少且目标数据与原始数据非常相似时,可仅微调网络靠近目标函数的后几层;当目标数据充足且相似时,可微调更多网络层,也可全部微调;当目标数据充足但与原始数据差异较大,此时须多调节一些网络层,直至微调全部;当目标数据极少,同时还与原始数据有较大差异时,这种情形比较麻烦,微调成功与否要具体问题具体对待,不过仍可尝试首先微调网络后几层后再微调整个网络模型; 5.此外,针对第四点中提到的"目标数据极少,同时还与原始数据有较大差异"的情况,目前一种有效方式是借助部分原始数据与目标数据协同训练。因预训练模型的浅层网络特征更具泛化性,故可在浅层特征空间(shallow fearure space)选择目标数据的近邻(nearest neighbor)作为原始数据子集。之后,将微调阶段改造为多目标学习任务(multi-task learning):一者将目标任务基于原始数据子集,二者将目标任务基于全部目标数据。实验证实,这样的微调策略可大幅改善"目标数据极少,同时还与原始数据有较大差异"情况下的模型微调结果。 .. figure:: _static/18.jpg :align: center