深刻理解CNN的细节

数据预处理(Data Preprocessing)

零均值化(Mean subtraction)

为何要零均值化?python

  1. 人们对图像信息的摄取一般不是来自于像素色值的高低,而是来自于像素之间的相对色差。零均值化并无消除像素之间的相对差别(交流信息),仅仅是去掉了直流信息的影响。web

  2. 数据有过大的均值也可能致使参数的梯度过大。网络

  3. 若是有后续的处理,可能要求数据零均值,好比PCA。dom

假设数据存放在一个矩阵 X 中,X 的形状为(N,D),N 是样本个数,D 是样本维度,零均值化操做可用 python 的 numpy 来实现:
函数

X -= numpy.mean(X, axis=0)

即 X 的每一列都减去该列的均值。学习

对于灰度图像,也能够减去整张图片的均值:
优化

X -= numpy.mean(X)

对于彩色图像,将以上操做在3个颜色通道内分别进行便可。spa

归一化(Normalization)

为何要归一化?code

归一化是为了让不一样纬度的数据具备相同的分布规模。orm

假如二维数据数据(x1,x2)两个维度都服从均值为零的正态分布,可是x1方差为100,x2方差为1。能够想像对(x1,x2)进行随机采样并在而为坐标系中标记后的图像,应该是一个很是狭长的椭圆形。

对这些数据作特征提取会用到如下形式的表达式:

S = w1*x1 + w2*x2 + b

那么:

dS / dw1 = x1

dS / dw2 = x2

因为x1与x2在分布规模上的巨大差别,w1与w2的导数也会差别巨大。此时绘制目标函数(不是S)的曲面图,就像一个深邃的峡谷,沿着峡谷方向变化的是w2,坡度很小;在峡谷垂直方向变化的是w1,坡度很是陡峭。

由于咱们指望的目标函数是这样的:

而如今的目标函数多是这样的:

咱们知道这样的目标函数是很是难以优化的。由于w1与w2的梯度差别太大,在两个维度上须要不一样的迭代方案。可是在实际操做中,为了简便,咱们一般为全部维度设置相同的步长,随着迭代的进行,步长的缩减在不一样维度间也是同步的。这就要求W不一样维度的分布规模大体相同,而这一切都始于数据的归一化。

一个典型的归一化实现:

X /= numpy.std(X, axis = 0)

在天然图像上进行训练时,能够不进行归一化操做,由于(理论上)图像任一部分的统计性质都应该和其它部分相同,图像的这种特性被称做平稳性(stationarity)。(注意是同分布,不是独立同分布)

PCA & Whitening

白化至关于在零均值化与归一化操做之间插入一个旋转操做,将数据投影在主轴上。一张图片在通过白化后,能够认为各个像素之间是统计独立的。

然而白化不多在卷积神经网络中使用。我猜想是由于图像信息原本就是依靠像素之间的相对差别来体现的,白化让像素间去相关,让这种差别变得不肯定,抹掉了不少信息。

数据扩充(Data Augmentation)

大型模型每每须要大量数据来训练。一些数据扩充方法所以被发明出来,以天然图像为例:

能够对图片作水平翻转、进行必定程度的位移或者剪裁,还能够对它的颜色作必定程度的调整。在不改变图像类别的状况下,增长数据量,还能提升模型的泛化能力。


参数初始化

零初始化

不要将参数所有初始化为零。

几乎全部的CNN网络都是对称结构,将参数零初始化会致使流过网络的数据也是对称的(都是零),而且没有办法在不受扰动的状况下打破这种数据对称,从而致使网络没法学习。

随机初始化

打破对称性的思路很简单,给每一个参数随机赋予一个接近零的值就行了:

W = 0.01* numpy.random.randn(D,H)

randn 方法生成一个均值为零,方差为1的服从正态分布的随机数。

把 W 应用到以前的表达式 S ,S 就是多个随机变量的加权和。独立随机变量和的方差为:

Var(A+B+C) = Var(A)+Var(B)+Var(C)

假设 W 各元素之间相互独立,随着数据维度的增加,S 的方差将会线性累积。根据任务的不一样,数据的维度从小到大跨度很是大,是不可控的,因此咱们但愿将 S 的方差作归一化,这只须要对 W 动动手脚就能够了:

W = numpy.random.randn(n) / sqrt(n)

其中 n 就是数据的维度。

推导过程以下:

令 n*Var(W) = 1,就获得 std(W) = 1 / sqrt(n)。

在实际使用中,若是结合 ReLU,这篇文章推荐:

w = numpy.random.randn(n) * sqrt(2.0/n)


激活函数(Activation Function)

激活函数用于在模型中引入非线性。

sigmoid 与 tanh 曾经很流行,但如今不多用于视觉模型了,主要缘由在于当输入的绝对值较大时,其导数接近于零,梯度的反向传播过程将被中断,出现梯度消散的现象。

ReLU 是一个很好的替代:

相比于 sigmoid 与 tanh,它有两个优点:

  1. 没有饱和问题,大大缓解了梯度消散的现象,加快了收敛速度。

  2. 实现起来很是简单,加速了计算过程。

ReLU 有一个缺陷,就是它可能会永远“死”掉:

假若有一组二维数据 X(x1, x2)分布在 x1:[0,1],  x2:[0,1] 的区域内,有一组参数 W(w1, w2)对 X 作线性变换,并将结果输入到 ReLU。

F = w1*x1 + w2*x2

若是 w1 = w2 = -1,那么不管 X 如何取值,F 必然小于等于零。那么 ReLU 函数对 F 的导数将永远为零。这个 ReLU 节点将永远不参与整个模型的学习过程。

形成上述现象的缘由是 ReLU 在负区间的导数为零,为了解决这一问题,人们发明了 Leaky ReLU, Parametric ReLU,  Randomized ReLU 等变体。他们的中心思想都是为 ReLU 函数在负区间赋予必定的斜率,从而让其导数不为零(这里设斜率为 alpha)。

Leaky ReLU 就是直接给 alpha 指定一个值,整个模型都用这个斜率:

Parametric ReLU 将 alpha 做为一个参数,经过学习获取它的最优值。Randomized ReLU 为 alpha 规定一个区间,而后在区间内随机选取 alpha 的值。

在实践中, Parametric ReLU 和 Randomized ReLU 都是可取的。


总结

仅仅理解 CNN 的结构是不够的,在实践中,特别是训练大规模网络的时候,有不少技巧性或经验性的细节。不只要会用它们,更要理解这些技巧背后的规律。我认为合理的学习过程是:

实践-》总结-》再实践    循环往复

一开始看不懂论文,能够利用一些公开课或者教程,理解基本概念,并跟随教程完整的实现一些简单模型,找到最初始也是最重要的感受。

而后总结在该领域内的一些最佳实践,并理解为何这么作,渐渐对该领域造成体系化的认识。

在有了体系化的理解以后,你发现你有了触类旁通的能力,能够尝试实现更复杂的模型,以印证本身的想法。还能够去阅读专业人士的论文,巩固和完善本身的认知体系。

此时你已经熬过了最痛苦的积累期,具备了创造的能力。关于CNN的细节,我还会再作补充讨论。

相关文章
相关标签/搜索