CNN

2 篇文章 0 订阅

Introduction

这是斯坦福计算机视觉大牛李菲菲最新开设的一门关于deep learning在计算机视觉领域的相关应用的课程。这个课程重点介绍了deep learning里的一种比较流行的模型:Convolutional Neural Networks,简称CNN,主要利用CNN来做visual recognition,或者说是image classification,object recognition等。我自己在学习的过程中,一边翻译一边总结,整理出这些中文版的lecture notes,英文好的同学可以直接看原文,课程的网址是:
http://cs231n.stanford.edu/
学习这门课程,需要一定的数学基础,包括线性代数,概率论,统计等,还要对传统的机器学习有一定的了解,可以参考斯坦福大学机器学习大牛Anderw的课程,另外一个前提条件是编程,这门课程没有用matlab,而是用了当下比较流行的一种语言python,课程中所有的程序都是用python写成的,所以还要学习python编程,这门课程对python有简单的介绍,并且还推荐了相应的python版本及编译器,这些信息都可以在课程网站上找到。
我在这里转译的中文lecture notes,认为大家都已经搞定了上述所需的前提条件,就是有一定的数学基础,也了解机器学习,并且安装了相应的python和IDE(推荐Eclipse+Pydev),能够利用python进行编程。所以没有这些基础知识。下面是正式的课程内容。

Image Classification

首先介绍的是计算机视觉领域一个重要而基础的问题:图像分类。简单来说,就是将一幅图像赋以一个语义标签,对这幅图像进行标识,如下图所示:
猫
图像分类的任务就是将一个给定的图像赋予一个或者一组语义标签。
我们看到的是一只猫,但是对于计算机来说,看到的只是一个三维的数组,这个图像是248个像素宽,400像素高,而且有R,G,B三个通道,所以是一个248×400×3的数组,一共有296700个像素,每个像素的值在0-255的范围内,图像分类的任务就行将这所有的像素用一个语义标签进行标识,比如“cat”。
一般来说,对于visual recognition,我们需要解决以下一些困难或挑战:
Viewpoint variation:一个物体由于照相机拍摄的视角不同,会呈现不同的方向。
Scale variation: 尺度的变化,这是比较常见的一个问题。
Deformation: 有些物体可能会发现形变。
Occlusion: 物体的局部有可能被遮挡。
Illumination conditions:光照条件的变化有可能改变图像的像素值的分布。
Background clutter: 背景纹理与物体的纹理相似的话,会对识别造成很大影响。
Intra-class variation: 即使属于同一类的物体,也有可能呈现不同的形状,比如椅子,杯子等。
困难
一个好的图像分类模型,应该能够很好地处理这些问题。
我们如何写一个算法来做这项工作呢,这个不像排序那么简单,因为我们不能直接写一个算法来确定图像里的物体。因此,一般来说,我们会先给计算机一些样本,通过这些样本让计算机了解每一类物体的性质,这种方法称为data-driven(数据驱动),因为这类方法要依赖于事先收集的一些训练数据。下图给出了一些训练数据的示例:
Example
在实际的应用中,可能会有几千个类别而每一类可能会有成千上万个样本。一个完整的图像分类模型包含以下几个步骤:

  • Input:我们的输入包括N张图像,每张图像都有相应的标签,这些标签属于K个不同的类别,这组图像称为训练集。
  • Learning: 我们的任务是通过训练集让计算机知道每一类的性质,这个过程称为训练阶段或者学习阶段。
  • Evaluation: 最后,我们要用训练好的模型来评估一些从未见过的图像,对这些图像进行分类,并将预测标签与该图像的真实标签比较。

Nearest Neighbor Classifier

我们先介绍一种很简单的分类模型:最近邻分类器,这个模型与我们将要介绍的CNN没有什么关系,而且在实际应用中,也很少用到这个模型,但是可以用这个模型来了解图像分类的处理流程。
这里我们要用到的数据库是:

CIFAR-10
,这是一个非常流行的用于图像分类的数据库,这个数据库包含10类图像,一共含有60000张图,每张图的宽和高都是32,每张图都有一个类标签,这60000万张图分成两部分,其中50000张图作为训练集,剩下的10000张图作为测试集。下图给出了该训练集的一些样图:
训练集vs测试集
左图:训练集里的一些样图。右图:第一列是测试图,其它图是与该测试图最相似的训练图。
现在,假设我们有这样一个数据库,包含属于10个类别的共50000个训练样本,每个类别有5000张图,最近邻分类器拿到一张测试图,会将该测试图与训练集的每一个 样本进行比较,挑出离该测试图最近的训练样本,并且将该训练样本的类标签赋给该测试图,换句话说,离该测试图最近的样本是什么类,那么该测试图就属于该类,
我们可以看到,利用这个分类器,上面右边的10个测试样本只有三个赋予了正确的类标签,其它7个样本都错了,比如第8个样本是一个马的头,但是离它最近的训练样本 是汽车,这样这个马头的图像就被赋予汽车的标签了。
现在我们来定义Nearest Neighbor Classifier,最简单的一种定义就是像素级的比较,我们将一张32×32×3的图看成一个高维的向量,两张图的差距 定义为L1距离:
d1(I1,I2)=pIp1IP2

还有一种常用的度量,是L2距离:
d2(I1,I2)=p(Ip1IP2)2

实验证明,利用L1,L2度量的效果并不理想,只有30%多一点,一种比较常见的改进是K-NN,我们不能只参考离测试样本最近的一个样本,我们要参考离测试样本最近的K个样本,然后利用投票策略,即,这K个样本中,哪一类的样本最多,我们就认为测试样本属于这一类。但是K-NN中的K到底要取多大?这个K可以称为hyperparameters,在机器学习中,如何选择参数也是一个需要仔细考虑的问题,一般来说test set只能用来做最后的评估,而且只能用一次,不能用test set来选择最佳的hyperparameters,一个可行的方案是将训练集分成两部分,我们将拥有绝大多数训练样本的那部分用来训练,称为training set,而只有很少一部分训练样本的那部分用来评估不同的参数对模型的影响,这部分称为validation set。
当样本总数很少的时候,我们一般会采取另外一种策略称为cross validation,将样本分为相同规模的几份,比如5份或者10份,然后,挑出一份做validation,剩下的做训练,这样循环一遍,以保证每一份都能被评估,这种策略相对来说比较耗时,因为需要循环地做训练和测试。

Pros and Cons of Nearest Neighbor classifier

接下来,我们要总结一下Nearest Neighbor classifier的优缺点,很显然,这种分类器的优点就是简单,易懂,而且不需要训练,但是它的缺点也很明显,一个是效率太低,测试的时候非常耗时,因为要和训练集
的样本逐个比较,在实际应用中,我们比较关心测试阶段的效率,因为训练可以提前做好,所以最近邻分类器不能满足实时检测,在实际应用中,很少用到这种分类器。最近邻分类器另外一个缺点是对像素亮度值的变化非常敏感,因为这个是基于像素值的比较,所以同一个物体,在不同光照,或者有遮挡的情况下,会出现很大的差距,更加合理的度量应该基于物体的语义及结构信息。如下图所示:
鲁棒性
图像的偏移,部分遮挡,光照变化会使距离度量相差很大。
最后做一点总结:
我们介绍了图像分类的概念,并且介绍了一种很简单的分类器:最近邻分类器,而且我们也介绍了如何利用validation set或者cross validation来调整hyperparameters,我们也看到最近邻分类器的效果并不是很理想,最后我们探讨了L1,L2度量的缺陷,就是对像素值的变化比较敏感,而没有基于物体的语义及结构信息来进行度量。
声明:lecture notes里的图片都来源于该课程的网站,只能用于学习,请勿作其它用途,如需转载,请说明该课程为引用来源。

Linear Classification

在上一讲里,我们介绍了图像分类问题以及一个简单的分类模型K-NN模型,我们已经知道K-NN的模型有几个严重的缺陷,第一就是要保存训练集里的所有样本,这个比较消耗存储空间;第二就是要遍历所有的训练样本,这种逐一比较的方式比较耗时而低效。
现在,我们要介绍一种更加强大的图像分类模型,这个模型会很自然地引申出神经网络和Convolutional Neural Networks(CNN),这个模型有两个重要的组成部分,一个是score function,将原始数据映射到输出变量;另外一个就是loss function,衡量预测值与真实值之间的误差。
我们先看模型的第一部分,定义一个score function,将图像的像素值,映射到一个输出变量,这个输出变量表示图像属于每一类的置信度或者说概率,我们假设有一批训练图像, xiRD ,每一个训练样本都有一个类标签yi,其中, i=1,2,...Nyi{1,2,...K} ,就是说,我们有 N个训练样本,这N个训练样本属于K个类别,我们要定义的score function就是满足如下映射: f:RDRK ,这里我们先介绍一种最简单常用的线性映射,如下所示:

f(xi,W,b)=Wxi+b

在上面的表达式中, xi 是一个高维向量,包含一幅图像的所有像素,将图像从m×n×3变成D×1,矩阵
W$(K×D)$$b(K×1)$
\mathbf{W}$$叫做权值,而$b$称为偏移向量,我们用下面的图来表示这个映射过程:
映射过程
为了能够视觉化这个过程,我们假设图像是只有四个像素(实际情况一般至少是几千个像素),将图像变成一个列向量然后与权值W相乘,在加上偏移向量b,最后得到score,从结果来看,这个分类模型将这幅图像判定为是一条狗。
下图展示了线性分类模型对图像分类的过程,因为我们不能将高维向量可视化,所以我们假设在二维平面观看这些图像,那么线性分类模型在各个类别之间的边界就有可能如下图所示:
线性分类模型
从上面可以看出, W 的每一行都相当于某一类的分类器,从几何意义上看,如果我们改变 W 中某一行的值,那么该行所对应的分类器将会发生旋转。对应权值 W 的另外一种解释就是每一行可以看成一种模板:template,一幅图像在每一类上的score可以通过template与该图像做内积获得,这种情况下,线性分类有点像是在做模板匹配,下图给出了在 CIFAR-10数据库上利用线性分类模型学习得到的template,W的每一行都相当于一个template。实际运算的时候,我们也会把偏移向量b看成是 W 的某一列,这样原有的权值 W 和b组成新的权值 W ′=[ W ;b],那么score function也可以由f(xi,W,b)变成f(xi,W)。

之前我们做运算和训练的时候,都是利用图像的原始数据,一般来说,我们需要做一些预处理,我们会将一个训练集里的所有样本做归一化。比如图像,将图像从[0,255]映射到
[-1,1]的范围,而且减去均值向量,保证训练集的均值为0。
我们已经介绍了score function,现在我们要介绍线性分类模型的另外一个重要组成部分:loss function,或者成为cost function,这个用来衡量预测值与目标值之间的误差。定义loss function的方式有很多,这里我们先介绍一种经常使用的loss function,叫做Multiclass Support Vector Machine (SVM) loss。简称 SVM loss,下面给出该函数的定义,假设训练集第i个样本的输入为xi,yi表示该样本属于第几类,利用score function f(xi,W) 我们可以计算该样本 xi 属于每一类的score,比如f(xi,W)j表示样本xi属于第j类的score,那么该loss function定义为:

Li=jyimax(0,f(xi,W)jf(xi,W)yi+Δ)

请注意,由于我们这里介绍的是线性模型f(x_i,W)=Wx_i,所以我们也可以将上式重新写成:
Li=jyimax(0,wTjxiwTyixi+Δ)

其中, wTj 表示W的第j行,如果是今后介绍的更加复杂的模型,上面这个表达式就不一定成立。上面的 max(0,) 函数称为hinge loss,这是线性的hinge loss,有的时候也会用二次的hinge loss: max(0,)2 ,下图解释了loss function的作用。 Δ 给出了其他类与某一类相差的界限,如果其他类与某一类相差的在这个界限之外,那么这些误差不会累计到loss function,反之,如果相差在界限范围内,这些误差就会累计到loss function,所以我们的目标就是寻找满足条件的参数 W ,使得训练样本都能被正确分类,并且让loss function尽可能地低。

为了进一步提升模型的稳健性,我们会引入regularization penalty,R(W),最常见的形式是二次式:$R(\mathbf{W})=\sum_{ij}W^2_{ij},所以引入R(W)之后,loss function就包含数据误差和regularization penalty两部分,如下式所示:

L=1NiLi+λR(W)

展开之后得到:

L=1Nijyi[max(0,f(xi,W)jf(xi,W)yi+Δ)]+λijW2ij

通过引入regularization penalty,可以使得权值的分布更加平衡,不会单独侧重于某些局部变量。
前面我们忽略了 Δ 值的探讨, Δ 应该选择多少比较合适?在实际应用中,我们发现把 Δ 设为1.0是非常安全的,事实上,参数 Δ,λ 都是控制loss function中数据偏差与regularization penalty之间的平衡的,因为 W 的幅值对score有直接的影响,如果我们把幅值增大,那么预测的score也会变大,反之同样成立,所以 Δ 设为1.0还是100.0对最终的数据偏差不会有太多影响,因为可以通过调整W的幅值来消除 Δ 大小带来的影响,因此,起关键作用的是 λ ,控制着 W 以多大的步幅变化。

Softmax classifier

前面介绍的SVM是线性分类器,现在我们介绍另外一种常用的非线性分类器,Softmax classifier。SVM将预测值看做是一种score,而Softmax classifier将预测值看成是一种概率,Softmax classifier的映射函数没有变化,还是 f(xi;W)=Wxi ,但是它的loss function采取了另外一种形式,称为cross-entropy loss,其定义如下:

Li=logefyijefj=fyi+logjefj

这里,我们用 fj 表示对第 j 类的预测值,与SVM一样,整个训练集的loss function将是所有样本的平均loss加上regularization误差R(W),函数 fj(z)=ezjkezk 称为softmax函数,它可以将一组实数映射到[0,1]之间,并且其和为1,从信息论的角度看,cross entropy衡量地是一个实际分布p和一个估计的分布q之间的相关性:
H(p,q)=xp(x)log(q(x))

因此,Softmax分类器是缩小预测的每一类的概率与实际概率的cross entropy。
从概率的角度来看,我们可以看到表达式:
P(yi|xi;W)=efyijefj

可以看做是给定一张图像,其属于某一类的概率,指数项给出了概率值,而分母的归一化保证概率在[0,1]之间,而且其和为1,这样我们可以引入最大似然估计去解释这个模型,如果进一步的,我们假设W是属于某一特定分布,比如高斯分布,那么我们可以用最大后验概率估计去解释这个模型,这里提到这些,只是为了让大家对此有一个 直观的了解。实际编写程序的时候,由于指数运算可能会涉及到很大的值,可能会使得模型在数值上不够稳定,所以一般会引入一个常数项C,如下所示:
efyijefj=CefyiCjefj=efyi+logCjefj+logC

C的选择没有特别地规定,可以自由选择,通常我们定义 logC=maxjfj 。下图显示了SVM与Softmax分类器做图像分类的区别:
SVM vs Softmax

Gradient Computing

前面我们介绍过分类器模型一般包含两大部分,一部分是score function,将输入的原始数据映射到每一类的score,另外一个重要组成部分是loss function,计算预测值
与实际值之间的误差,具体地,给定一个线性分类函数: f(xi;W)=Wxi ,我们定义如下的loss function:

L=1Nijyi[max(0,f(xi,W)jf(xi,W)yi+1)]+αR(W)

我们看到L与参数W有关,所以我们需要找到一个合适的W使得L尽可能小,这个过程称为优化。所以一个完整的分类模型,包括三个核心部分:score function,loss function 以及optimization(优化)。
一般来说,我们定义的loss function中,里面涉及的输入变量都是高维的向量,要让它们直接可视化是不可能的,我们可以通过低维的情况下得到一些直观的印象,让loss在直线或者平面上变化,比如我们可以先初始化一个权值矩阵W,然后让该矩阵沿着方向 W1 变化,那么可以评估 W1 不同的幅值对loss的影响,即 L(W+aW1) ,这个loss会随着不同的a生成一条曲线,同样,我们可以让L在两个方向 W1W2 变化, L(W+aW1)+bW2 不同的a,b会生成不同的loss,这个loss会形成一个平面,如下图所示:
loss plane
我们可以通过从数学的角度解释这个loss function,考虑只有一个样本的情况,我们有:
Li=jyi[max(0,wTjxiwTyixi+1)]

从这个表达式可以看出,样本的loss是W的一个线性函数,如果我们考虑一个含有三个样本(每个样本是一个一维的点)的训练集,这个训练集有三个类别,那么训练集
的loss可以表示为:
L0=[max(0,wT1x0wT0x0+1)]+[max(0,wT2x0wT0x0+1)]

L1=[max(0,wT0x1wT1x1+1)]+[max(0,wT2x1wT1x1+1)]

L2=[max(0,wT0x2wT2x2+1)]+[max(0,wT1x2wT2x2+1)]

L=(L0+L1+L2)/3

因为样本 xi 是一维的,所以系数 wi 也是一维的,它们的和L与W的关系可以由下图表示:
hinge loss
上图给出的是一维的情况,如果是高维的话,这个要复杂的多,我们希望找到一个W使得该loss最小,上图是一个凸函数,对于这类函数的优化,是一大类属于凸优化的问题,但是我们后面介绍的神经网络,其loss function是比这更复杂的一类函数,不是单纯地凸函数。上面的图形告诉我们这个loss function不是处处可导的,但是我们可以利用函数subgradient(局部可导)的性质,来优化这个函数。W的搜寻是属于一个优化问题,由于我们后面介绍的神经网络的loss function并不是凸函数,虽然我们现在看到的SVM loss function是一个凸函数,但是我们并不打算直接用凸优化的相关方法来找这个W,我们要介绍一种在后面的神经网络也能用到的优化技术来优化这个SVM loss function。
方案一:随机搜索
最简单,但是最糟糕的方案就是随机搜索,我们对W赋予一系列的随机值,然后看哪个随机值对应的loss最低,这样肯定是耗时而且低效的。
方案二:随机局部搜索
在随机搜索的基础上,加上一个局部搜索,即W+σW,我们会判断这个更新是有助于loss减小还是增大,如果是减小,那么我们就更新,反之就不更新,而继续做局部搜索。
方案三:梯度下降
最简洁高效的算法就是梯度下降法,这种方法也是神经网络优化方法中用的最多的一种方法。
一般来说,我们会Back-propagation去计算loss function对W的偏导数, 这是利用链式法则(chain-rule)来计算梯度的一种方式.

Modeling one neuron

下面我们开始介绍神经网络,我们先从最简单的一个神经元的情况开始,一个简单的神经元包括输入,激励函数以及输出。如下图所示:
神经元
一个神经元类似一个线性分类器,如果激励函数是sigmoid 函数( σ(x)=1/(1+ex) ),那么 σ(iwixi+b) 相当于是求该输入所对应的输出为1的概率, P(y=1|xi;w) ,那么该输入所对应的输出为0的概率为 P(y=0|xi;w)=1P(y=1|xi;w) 。在神经网络中,常用的激励函数一个是sigmoid函数,另一个是tanh 函数。他们的曲线如下图所示:
sigmoid and tanh
我们可以看到,sigmoid 函数的取值范围在(0,1)之间,而tanh 函数的取值范围在 (-1,1)之间。从图中可以看到,当sigmoid 函数的取值靠近0或者1时,它的梯度接近0,由于梯度在back propagation中有着非常重要的传递作用,因此如果梯度值太小,信息将无法传递。另外还有常见的几种激励函数比如Rectified Linear Unit(RLU), f(x)=max(0,x) ,这个函数相当于保证所有的输出都大于0,这个函数的优点是它收敛地比sigmoid,tanh函数要快,而且运算代价相对要低。这个函数的一个缺陷是在训练的过程中,可能导致神经元最后处于“休克”状态,基本毫无反应。因为梯度有可能为0,这样的话,信息就无法传递。为了克服这个hard threshold带来的这个问题,所以有一种激励函数称为 Leaky ReLU, f(x)=1x<0(αx)+1x>=0(x) ,对于x<0的情况,梯度不再为0,而是一个很小的常数α。有的实验证明用这种激励函数可以取得不错的分类效果,但是性能不是很稳定。还有一类激励函数称为maxout,这类激励函数用一个非线性运算 max(wT1x1+b,wT2x2+b) 来求得输出,maxout拥有RLU 的优点,而且避免了神经元“休克”的问题,不过maxout的一个缺陷是运算的参数增加了一倍。
我们将几种常见的激励函数归纳如下:

Sigmoid 函数: f(x)=1/(1+ex)
tanh 函数: f(x)=1e2x1+e2x
RLU 函数: f(x)=max(0,x)
Leak ReLU 函数: f(x)={1x<0(αx)+1x>=0(x)
maxout 函数: f(x)=max(wT1x1+b,wT2x2+b)

Neural Network architectures

下面我们开始介绍神经网络,一个完整的神经网络包括输入层,隐含层,以及输出层。最常见的一种神经网络就是 fully-connected 型。如下图所示。我们可以看到,上一层的每一个神经元与下一层的每一个神经元都相连,左边的神经网络含有一个隐含层,右边的神经网络含有两个隐含层,当我们计算神经网络的层数时,我们会忽略输入层,所以左边的神经网络是一个两层的(一个隐含层加一个输出层),右边的神经网络是一个三层的(两个隐含层加一个输出层),输出层有的时候可以含有激励函数,也可以不含有激励函数,看网络设计的需求而定。
神经网络
那么,神经网络的presentation power到底有多大呢,理论上,一个只含一层隐含层的神经网络模型可以表示任何复杂的函数。所以在机器学习领域,还在争论的一个问题就是有没有必要利用deep神经网络,既然一个隐含层的shallow神经网络已经足够应付所有复杂的函数,deep 神经网络的优势目前看来是一种经验上的观察,虽然在理论上与shallow神经网络相比没有太大优势。而且在实际使用中,三层的神经网络比两层的性能要好,但是再深一点的神经网络,比如四,五,六层的神经网络性能已经没有什么提高了,这点与Convoluational 神经网络有点不太一样,在Convoluational 神经网络结构中,deepth 是一个很重要的保证网络性能的指标。
我们在设计神经网络的时候,要根据实际的问题,选择神经网络的结构,层数,隐含层神经元的个数,因为输入层和输出层基本由问题本身决定。一般来说,随着隐含层数的增加,以及隐含层里神经元个数的增加,网络的representation power会越大。我们可以看看如下的示例图。下图表示的是一个二分类问题,红点表示一类,绿点表示另外一类,利用一个两层的神经网络去学习这些数据,我们看到,随着神经元个数的增加,网络的拟合功能越来越强,当N=20时,所有的红点与绿点都完全区分开来了,所以说,神经元越多,网络就能表示越复杂的函数,但是随之而来的另外一个问题就是overfitting,如果一个网络过于专注数据中的噪声,而忽略了数据潜在的联系,就会出现overfitting。如下图所示,当N=20时,网络可以拟合所有的红点,但是却将平面分割地支离破碎,这种情况下,虽然网络的拟合能力很好,但是generalization能力却很差,意味着测试的性能会很糟糕。从这个例子看来,当数据不是很复杂的时候,似乎小的神经网络可以更好的控制overfitting的问题,但是事实上并非如此,我们一般不会用减少神经元个数的方法来控制overfitting,我们会用很多其他的方法来控制(比如 L2 regularization, dropout, input noise),这些会在后面的课程中介绍。
分类分界面
事实上,小规模的神经网络的一个缺点在于训练的难度,因为小的神经网络representation power有限,所以训练的自由度也相对较小,用梯度下降算法训练的时候,有可能陷入局部最小值,小规模的神经网络的局部最小值相对也较少,但是可能会很快收敛到这些局部最小值,这些极值有些会使网络的性能会很好,但是有些可能让网络性能很差,而大规模的神经网络局部最小值会很多,而且这些与实际误差相关的局部最小值会使网络的性能相对稳定。一般来说,小规模的神经网络性能会有很大的起伏,有的时候严重依赖于权值的初始值,而大规模的神经网络性能相对稳定,对权值的初始值依赖较少。
事实上,我们会利用regularization 去控制大规模网络的overfitting问题,下图给出了引入regularization 之后,N=20的神经网络的训练结果:
引入正则项
我们看到,随着regularization的增加,神经网络的分界面越来越平滑。

Setting up the data and the model

前面我们介绍了一个神经元的模型,通过一个激励函数将高维的输入域权值的点积转化为一个单一的输出,而神经网络就是将神经元排列到每一层,形成一个网络结构,这种结构与我们之前介绍的线性模型不太一样,因此score function也需要重新定义,神经网络实现了一系列的线性映射与非线性映射,这一讲,我们主要介绍神经网络的数据预处理以及score function的定义。

data processing

给定一个训练集, S=xiRD|i=1,2,...m ,这个训练集含有m个样本,而且每个样本 xi 的维数为D,那么该训练集的向量均值为: μ=1mmi=1xi ,而方差为 σ2=1mmi=1(xiμ)2 σ 称为标准差。
数据的预处理有多种形式,最常见的是去均值,即 xi=xiμ ,每一个样本都减去平均值,这样可以保证新的样本均值为0。第二种预处理形式是归一化,这种处理形式将训练样本映射到统一的尺度上来,归一化可以直接用样本除以标准差,即 xi=xi/σ ;另外一种方法就是将样本的最小值与最大值分别映射到-1与1,然后其他值就取-1到1的中间值。下图给出了去均值与归一化的两种形式:
归一化
第三种数据处理形式是PCA,PCA是一种很经典的数据降维算法,可以将高维的数据映射到低维空间,同时保持原始数据的相关特性,利用上面的定义,我们可以得到去均值的训练集,设为 X ,那么协方差矩阵为:Cov=XTX,通过对协方差矩阵 Cov 做奇异值分解,我们可以得到[U,S,V]=svd(Cov),其中U是特征向量组成的矩阵,S记录的是特征值,U,S,很显然, XRN×DCovRD×D ,U中的向量相当于基础向量,我们用X和U中的前面几个列向量( MN )相乘,那么 Y=XURN×M ,所以原来的训练集X映射到一个更低维的空间,形成一个新的训练集Y,这就是PCA的降维。
最后一种数据处理方法是whiten,简单来说,就是让训练集除以协方差矩阵Cov的特征值,因为Cov是一个对称的半正定矩阵,所以S是一个D×D的矩阵,S对角线上的值就是特征值, xi=xi/(diag(S)+ε) ε 是一种程序上的技巧,防止分母为0的情况。下图给出了PCA和whiten两种形式:
PCA and Whiten
我们也可以对图像做PCA和whiten处理,如下图所示:
Image PCA和whiten
图中最左边一列是从CIFAR-10中提取的一些示意图,CIFAR-10一共有50000张图,每张图的尺寸是48×64,将其展成一个行向量,就是3072维,利用PCA,可以得到该数据库的协方差矩阵Cov为3072×3072这是非常大的一个矩阵,利用奇异值分界,可以得到3072个特征向量,上图的左边第二列给出的就是前144个特征向量,对应最大的144个特征值,我们可以看到,越靠前的特征向量看起来越平滑,意味着前面的特征向量对应的是低频信息。右边的第二列是降维重建的图像,利用 Y=XU ,可以得到降维后的数据,Y中的每一个行向量记录的是每个特征之前的系数,即: xi=Mj=1yijuj ,利用这个表达式,可以重建X,所以右边第二列就是利用降维后的数据进行重建得到的图像,可以看到图像比原图要模糊,意味着前面的特征向量记录的都是低频信息,最右边一列记录的就是whiten之后的图像,这里先用得到whiten之后的Y,然后利用这个Y对X进行重建。
在Convolutional Neural Networks 中,PCA和whiten比较少用,而取均值化和归一化两种形式比较常用,这里要注意的一个问题是我们做数据预处理的时候,只能对training set进行处理,不能对validation set 或者 test set进行处理。意味着均值和方差都只能从training set中得到。

Weight Initialization

接下来要介绍的就是权值的初始化,虽然我们不知道网络最终的权值会取什么值,但是认为它们一半大于0,一半小于0是一个合理的假设,如果因此而将权值的初始值都
设为0,却是一个错误,因为权值的初始值为0,意味着每个神经元的输出都是一样的,这样计算的梯度也是一样的,根本无法体现最开始的假设。
一般来说,我们会让权值接近于0,但不是完全等于0,所以我们会取很小的接近于0的随机数来初始化这些权值,不过神经网络是带有某种随机性的学习模型,不一定权值的初始值越小越好,权值的设定,最好是可以让梯度能够有效地传递,这是神经网络里比较关键的一点。
有的时候,对于权值的设定,还要做进一步的处理,一个神经元的输出分布的方差,会随着输入个数的增大而增大,换句话说,神经元的输出,会随着输入个数的增加抖动地更加剧烈,为了减少这种抖动,可以对权值做一个如下的处理: w=w/(n) ,其中n表示输入神经元的个数。这个可以保证网络中的每个神经元输出大致一样。
偏移量bias一般设为0。

Regularization

下面介绍几种控制神经网络overfitting的方法。L2 regularization:这大概是目前最常用的一种方法,通过在目标函数中引入 12λw2 ,其中 λ 表示regularization的强度,L2 regularization 直观上的解释就是对于出现极端分布的权值进行惩罚,而偏好于呈扩散分布的权值,这样可以保证网络里的每个输入都能发挥作用,而不至于让网络只关注少部分的输入。
L1 regularization:是另外一种常见的方法,通过在目标函数中引入 λw ,也有人考虑综合L1 和L2 regularization,这个称为Elastic net Regularization,L1 regularization 会使得权值在优化的过程中逐渐层稀疏分布,并且权值非常靠近0,这使得这种神经网络对噪声不敏感,而且会倾向于利用输入中比较重要的一些分量,一般情况下,L2 regularization的权值分布更加扩散,而且学习性能比L1 regularization要好。
Max norm constraints:这种方法是通过控制权值的上限来调整权值,一般来说,就是在正常的权值更新之后,利用一个约束条件, w2<c ,对权值进行“挤压”,这样可以保证权值不会更新的幅度不会太大。
Drop out:这是目前非常流行的一种方法,而且很有效,是对前面几种方法的一种补充,在前面几种方法的基础上,在训练阶段,通过对某些神经元进行抑制,减少神经元的个数来到达控制的目的,下图给出了drop out的示意图:
这里写图片描述
在程序的设计上,就是对该神经元的输出强制变为0,使得该神经元不再发挥作用。
但是需要注意的一点是,一般情况下,drop out只会在训练的时候执行,而在测试的时候,所有的神经元都将发挥作用,也就是训练的时候不会做drop out,但是为了保证训练与测试时神经元输出的尺度要一样,以保证输出的期望一样,一种解决方法是在测试的时候对神经元的输出乘以概率p,另外一种解决方法是在训练的时候对神经元的输出除以概率p,一般来说p=0.5,实际使用中,我们会采用第二种解决方案。
Drop out向我们展示了神经网络前向传递时的一种随机机制,这种机制可以让噪声在测试的时候被边缘化,Convolutional Neural Networks 也可以利用drop out的这一性质,采用随机pooling, fractional pooling等。
一般来不会对bias做regularization,因为bias相对于权值来说,数目要少。对于整个网络的影响没有权值那么大。而且做regularization的时候,不会每一层都做,一般来说,我们会在网络的输出层做regularization。在实际的应用中,我们会采用单一的L2 regularization,结合drop out,一般来说概率取p=0.5。

Loss function

前面我们已经讨论了目标函数的 regularization loss部分,现在我们还要探讨一下data loss,data loss我们定义为预测值与目标值之间的偏差,一个训练集整体的
data loss是每个训练样本的偏差之和的平均值,即: L=1NiLi ,其中N表示样本个数,我们用一个简单的函数表示网络的输出 f=f(xi,W) , 神经网络可以解决如下的几类问题:
第一个是分类问题,这个也是目前我们一直在讨论的问题,这里我们假设每个样本只属于某一类,即每个样本只有一个类标签,那么cost function可以写成如下的形式:

Li=jyimax(0,fjfyi+1)

或者用softmax 的形式表示:
Li=logefyijefj

这些适用于类别较少的情况,如果类别很多的话,比如有几千类,这样的话,就要考虑用hierarchical softmax。上面的两种形式都是针对样本属于一个类别的情况,还有更复杂的情况是一个样本可能属于多个类别,这样的话,一种可行的方法是为每个类别都建立一个二元分类器,用来判断某个样本是否属于该类,那么其loss function
可以表示成:
Li=jyimax(0,1yijfj)

yij 表示第i个样本是否属于第j类,如果是,则 yij=1 ,否则 yij=1 fj 表示对样本的预测,是否属于第j类。
另外一种方法是建立一个二元的logistic regression 分类器,这种分类器计算的是概率,如:
P(y=1|x;w,b)=11+e(w$Tx+b)=σ(wTx+b)

因为概率之和为1,所以 P(y=0|x;w,b)=1P(y=1|x;w,b) ,那么,利用这种分类器建立的多类别loss function为:

Li=jyijlog(σ(fj))+(1yij)log(1σ(fj))

类似地, yij 表示第i个样本是否属于第j类,如果是,则 yij=1 ,否则 yij=0 fj 表示对样本的预测,是否属于第j类。 可以证明,

Li/fj=yijσ(fj)

除了分类问题,神经网络也可以解决回归问题,回归问题的目标值和预测值都是连续的实数,而分类问题的目标值和预测值是离散的。回归问题常用的loss function是L2-norm,或者L1-norm,如下式所示:
L2-norm:
Li=fyi22

L1-norm:
Li=fyi1=j|fj(yi)j|

不过要注意的是,L2-norm的优化比起其它的分类器要困难的多,它有一个非常脆弱而特殊的性质,就是希望网络的输出与目标值要完全一样,因为预测的是连续值,而分类问题就好的多,因为只有一个值是我们需要的,其它值的分布,大小并不会影响网络的性能。所以L2-norm不太稳健,当我们面对一个回归问题的时候,尽可能将其转化为分类问题。

Learning

前面,我们介绍了神经网络的构成,数据的预处理,权值的初始化等等。这一讲,我们将要介绍神经网络参数学习的过程。

Gradient Checks

梯度的运算,在理论上是简单的,但是在实际的应用中,却非常容易出错,梯度的运算常见的有如下两种形式:
形式一:

df(x)dx=f(x+h)f(x)h

h是一个很小的常数,实际运算的时候,h大概等于1e−5,但我们通常会用下面这种形式计算梯度:
形式二:
df(x)dx=f(x+h)f(xh)2h

利用这个表达式,需要我们对loss function做两次评估,但是这样求得的梯度会更加精确。而我们在比较梯度的解析解与数值解时,会使用如下的表达式:
|f'af'n||f'a|+|f'n|

我们利用两者的相对误差,来衡量两种计算结果的接近程度。如果相对误差大于 1e2 ,意味着这个梯度的运算有问题,相对误差在 1e4 1e2 之间,可能会让你感到不适,而如果相对误差小于 1e4 对于使用非平滑的激励函数来说,这个结果是可以接受的,如果使用平滑的激励函数(tanh,softmax等)那么这个误差还是太高了,误差小于 1e7 这是一个理想的值,意味着梯度运算非常正常。当然,梯度的相对误差与网络的结构也有很大关系,对于深度网络来说,由于误差的传递性,随着网络的深度增加,误差也会变大,所以这个时候 1e2 可能就是一个不错的值了。
梯度运算不准确的另外一个隐患就是非平滑函数的引入,有些激励函数并非处处可导,比如RLU 函数,Leak ReLU 函数等,他们存在一些不可导的“拐点”,而在数值运算的时候,有可能会越过这些拐点,而导致梯度的运算出现偏差。
h的值不一定越小越好,h太小,可能会遇到数值运算的数据精度问题,一般来说我们会将h设定在 1e4 1e6 之间。同样还要注意的是,我们检查梯度的时候,可能是在某些神经元上做检查,但是某些神经元上的梯度正常,不意味着整个网络的梯度都正常,所以比较保险的方式是将网络先“预热”一段时间,即让网络先运行一段时间,然后再检查梯度。如果一开始就做梯度检查,可能未能察觉到病态的网络。

由于目标函数的loss包括两部分,一个是data loss,还有一个是regularization loss,我们需要注意,不能让regularization loss部分完全盖过了data loss,以免data loss完全不起任何作用,检查梯度的时候,可以先屏蔽掉regularization loss,先检查data loss的梯度部分,然后再反过来,检查regularization loss的梯度。做梯度检查的时候,可以先关掉drop out的功能,保证所有的神经元都处于active的状态。实际的运算中,梯度可能有几百万个变量,我们可以检查其中的一部分,并且假设剩下的部分也是正确的,而且做检查的时候,可以用少量的训练样本做检查。

在正式训练网络之前,我们对目标函数的loss要有一个大概的估计,我们可以先去掉regularization loss,让data loss的值符合我们大致的预期,如果loss未能到达我们的预期,可能权值的初始化有问题。另外一个trick就是先训练一个小的训练集,保证训练的error能到0,这个可以用来检测网络是否正常运行。

Babysitting the learning process

在训练的过程中,我们要利用一些合理的指标来检测训练是否有效,我们可以用二维图来表示这些指标,一般来说图的x坐标总是训练周期,一个周期表示每个训练样本都已经在网络中出现过一次,周期的次数,就表示训练样本在网络中出现的次数。我们不用迭代次数来表示x坐标,因为迭代次数与训练集的大小以及每个batch的大小有关。
这里写图片描述
第一个指标是loss function,它直接反应了训练的误差,如上图所示。左图给出了loss与learning rate之间的关系,并且告诉了我们什么是合适的learning rate。我们可以看到,太低的learning rate会使loss几乎层线性下降,而太高的learning rate会使loss反而上升。而learning rate稍微偏高的话,loss下降会很快,但是最后会收敛到一个较高的loss。右图给出了在CIFRA-10上的训练结果,这是一个看起来比较合理的loss,虽然有可能batch size可能偏小,因为loss看起来随机抖动的有点剧烈。一般来说,loss中的起伏和batch size有关,batch size太小,loss的起伏会很大。

第二个指标是训练与验证的正确率,如下图所示:
这里写图片描述
这个告诉了我们网络是否有可能出现overfitting的问题,根据这个指标,可以考虑调整regularization loss的比重,或者收集更多的训练样本。
最后一个指标是权重与权值更新的比率,如下图所示。神经网络的每一层都有权值,这些权值的更新幅度与learning rate有关,通过查看权值与权值更新的比率,可以看到learning rate的大小。下图给出了一个两层的神经网络中,W1的权值与权值更新随训练周期的变化,左图给出的是每个训练周期里,W1的最大值与最小值的变化,右图是最大值与最小值对应的权值更新的变化,权值的幅度在0.02左右,而权值更新的幅度在0.0002左右,所以他们的比率为0.01。
这里写图片描述

Activation / Gradient distributions per layer

一个糟糕的初始化将会导致一个很糟糕的训练结果,反映初始化最好的指标就是每一层激励函数的方差和梯度的方差,一个不合理的初始化将导致方差逐渐减少,这对梯度的传递时非常不利的,一个合理的初始化应该保证每一层的方差比较接近。如果每一层的权值都是简单的从高斯分布中随机抽取,会导致方差逐渐减少,更加有效的初始化是对每一层的权值做一个尺度变换。

最后,如果我们是处理图像,一个简单有效的方法是将图像可视化,如下图所示:左边的图表明噪声很多,说明网络可能没有收敛地很好,而右边的图看起来要平滑地多,说明网络很好地收敛了。

这里写图片描述

Parameters Updates

下面我们介绍几种参数跟新的方式,我们假设 W 是权值, ΔW 是更新的权值, α 表示learning rate,learning rate 是一个hyperparameter 也是一个常数。最常见的一种更新方式是 Vanilla update,如下所示:

Vanilla update:

W=WαΔW

Momentum update 是另外一种更新方式,而且在深度神经网络中的收敛性能很好,它在物理学上有一个直观的解释,我们可以假设将一个粒子放在一个山坡的某处,那么loss就是山坡的高度,而网络的初始化相当于将粒子放置在山坡的某处,并且让其初始速度为0,那么粒子沿着山坡滚下来的过程就类似网络的优化过程,我们假设粒子受到的力为F,粒子受到的力就相当于loss函数的梯度,因为 F=ma ,所以粒子的加速度就直接反应在梯度上面,而我们知道 v=v+at ,所以梯度会改变更新的速率,因为其表达式如下:

Momentum update: v=μvαΔW;W=W+v
这里 v 的初始值为0,μ也是一个hyperparameter,一般称为momentum,一般取值0.9,交叉验证的时候,我们会给μ取不同的值,比如(0.5,0.9,0.95,0.99)。

Nesterov Momentum与Momentum update略有不同,Nesterov Momentum的核心思想是,当权值处在某个位置时,利用上面介绍的Momentum update,我们知道权值下一步的位置会是 W+μv ,所以我们可以直接计算下一步权值的梯度,利用这个来进行更新,所以表达式如下所示:

Nesterov Momentum:

Wnew=W+μvv=μvαΔWnewW=W+v

在实际使用的时候,有人也会将Nesterov Momentum做一些改变,使得与前两种形式接近,比如:
vprev=vv=μvαΔWW=Wμvprev+(1+μ)v

在参数更新中,也可以用二阶导数做更新,就是牛顿法,但是这种方法目前并不常见,比起一阶梯度下降,二阶要复杂地多,所以这里不再详细介绍。

Annealing the learning rate

在深度神经网络的训练中,learning rate的调整是非常重要的,随着训练周期的延长,网络越来越靠近最优解,所以learning rate要随着训练能够做出调整,目前比较常用的有三种调整方法:

1:Step decay 这种方法就是每隔几个训练周期对learning rate做一次调整,比如减少一半。这些都取决于具体的问题。
2:Exponential decay 这种方法就是让learning rate以指数形式调整, α=α0ekt
3:1/t decay α=α0/1+kt
Per-parameter adaptive learning rate methods

前面介绍的参数更新都是用统一的learning rate,有学者尝试对每个参数利用不同的learning rate做更新。Adagrad 是一种自适应的参数更新方法,如下所示:

Adagrad: C=ΔW2W=WαΔW/C+δ
简单来说,Adagrad就是通过引入C使得每个参数的learning rate发生变化。

另外一种是RMSprop,形式如下:

RMSprop: C=βC+(1β)ΔW2W=WαΔW/C+δ
β也是一个hyperparameter,通常取值为 [0.9, 0.99, 0.999]。

Hyperparameter optimization

大规模的神经网络的训练是非常耗时的,需要设计到很多参数的设置,比如权值的初始化,learning rate的设定,regularization loss的比重,以及drop out的比重。下面简单介绍一下在神经网络训练中会使用到的一些技巧。

  1. 我们可以随机抽取一些数据做验证,而避免交叉验证,这样可以节省训练时间。
  2. hyperparameter 可以在一个范围内进行设定。
  3. 对hyperparameter的搜寻可以利用随机搜寻,而不用grid search。
  4. 对处在边缘的hyperparameter要谨慎,有的时候我们发现hyperparameter取某个区间靠近边界的值效果很好,意味着有可能更加好的hyperparameter在这个边界附近。
  5. hyperparameter的搜寻可以由粗到细,先在大范围寻找,然后缩小寻找范围。
  6. 利用贝叶斯对hyperparameter做优化。

Two Simple Examples

softmax classifier后,我们介绍两个简单的例子,一个是线性分类器,一个是神经网络。由于网上的讲义给出的都是代码,我们这里用公式来进行推导。首先看softmax classifier 的例子。给定输入 XRN×D ,权值 WRD×K ,偏移量 bR1×K ,我们可以得到分类器对每个样本的预测分数: f=XW+b ,我们可以用softmax 函数将预测分数转为概率: pi=efijefj pi 表示样本属于第i类的概率,fi,fj表示线性函数对样本属于第i,j类的预测分数。
我们可以建立如下的loss function:

Li=log(pyi)=logefyijefj

L=1NiLi+12λklW2k,l

下面我们推导loss对W,b的偏导数,我们可以先计算loss对f的偏导数,利用链式法则,我们可以得到:
Lifk=Lipkpkfkpifk=pi(1pi)i=kpifk=pipkikLifk=1pyipyifk=1N(pk1{yi=k})

进一步,由 f=XW+b ,可知 fW=XT,fb=1 ,我们可以得到:
ΔW=LW=1NLiW+λW=1NLippffW+λWΔb=Lb=1NLib=1NLippffpartialbW=WαΔWb=bαΔαΔb

Neural Networks

上面介绍的是softmax 分类器,下面我们介绍神经网络。神经网络与softmax分类器类似,只是多了一个隐含层。我们先考虑其前向传递。

f1=XW1+b1
h=max(0,f1)
f2=hW2+b2
pi=ef2ijef2j
L=1NiLi+12λw21+12λw22

下面我们看如何利用BP对网络中的参数进行更新:

Lf2=1NLif2=1N(pk1yi=k)ΔW2=LW2=Lf2h+λW2Δb2=Lb2=Lf2ΔW1=LW1=Lf2f2hX+λW1Δb1=Lb1=Lf2f2h

上面的表达式忽略了矩阵运算里的一些转置,实际编写代码的时候需要注意这一点,最后,我们可以得到如下的参数更新表达式:

W1=W2αΔW2b1=b2αΔb2W1=W1αΔW1b1=b1αΔb1

还有一点,上式的N表示训练集里的样本总数,如果我们要用batch模型,那么可以将整个训练集分成若干个batch,那么此时的N就是每个batch的样本数。

Convolutional Neural Networks (CNNs / ConvNets)

前面做了如此漫长的铺垫,现在终于来到了课程的重点。Convolutional Neural Networks, 简称CNN,与之前介绍的一般的神经网络类似,CNN同样是由可以学习的权值与偏移量构成,每一个神经元接收一些输入,做点积运算加上偏移量,然后选择性的通过一些非线性函数,整个网络最终还是表示成一个可导的loss function,网络的起始端是输入图像,网络的终端是每一类的预测值,通过一个full connected层,最后这些预测值会表示成SVM或者Softmax的loss function,在一般神经网络里用到的技巧在CNN中都同样适用。
那么,CNN与普通的神经网络相比,又有哪些变化呢?CNN的网络结构可以直接处理图像,换句话说CNN的输入就是直接假设为图像,这一点有助于我们设计出具备某些特性的网络结构,同时前向传递函数可以更加高效地实现,并且将网络的参数大大减少。

Architecture Overview

前面介绍的普通的神经网络,我们知道该网络接收一个输入,通过一系列的隐含层进行变换,每个隐含层都是由一些神经元组成,每一个神经元都会和前一层的所有神经元连接,这种连接方式称为 full connected,每一层的神经元的激励函数都是相互独立,没有任何共享。最后一个full connected层称为输出层,在分类问题中,它表示每一类的score。
一般来说,普通的神经网络不能很好地扩展到处理图像,特别是高维图像,因为神经元的连接是full connected的方式,导致一般的神经网络处理大图像的时候将会引入海量的参数,而这样很容易造成overfitting。
而CNN,利用了输入是图像这一事实,他们用一种更加明智的方法来设计网络结构,具体说来,不像普通的神经网络,CNN中的每一层的神经元被排列成一个三维模型:拥有width,height以及depth。这里的depth指的是CNN每一层的纵深,并非指整个CNN结构的纵深。比如,对于CIFAR-10数据库来说,输入是一个三维的volume,32×32×3,分别对应width,height和depth,我们将会看到,CNN中,每一层的神经元只跟前一层的部分神经元相连,而没有full connected,而且最后的输出层是一个1×1×10的volume,因为最后一层表示每一类的score,CNN通过这种结构,将一个输入的图像最后转化成一个表示每一类score的向量,下图给出了两种神经网络的示意图:
这里写图片描述
上图左边是一般的神经网络,这个网络有两个隐含层,右边是CNN,将每一层的神经元排列成一个三维的volume,可以将3D的输入volume转化为3D的输出volume.

Layers used to build ConvNets

上一节已经提到,CNN的每一层都将某种输入通过某些可导函数转化为另一种输出,一般来说,我们主要利用三种类型的layer去构建一个CNN,这三种类型的layer分别是convolutional layer, pooling layer 以及full connected layer,这三种类型的layer通过组合叠加从而组成一个完整的CNN网络。我们先来看一个简单的例子,以CIFAR-10数据库为例,我们要设计一个CNN网络对CIFRA-10进行分类,那么一个可能的简单结构是:[INPUT-CONV-RELU-POOL-FC],其中:
INPUT:[32×32×3] 表示输入层,是图像的像素值,这种情况下表示图像是宽为32个像素,高为32个像素,并且有R,G,B三个通道。
CONV: 是卷积层,计算输入层的局部神经元与连接到CONV层神经元的连接系数的点积,如果假设depth是12的话,那么可能的输出就是[32×32×12]。
POOL: 这一层主要执行降采样的功能,可能的输出为[16×16×12]。
FC: 这一层计算最终的每一类的score,输出为[1×1×10]。与普通的神经网络一样,这一层的神经元与上一层的所有神经元都会连接。
所以,利用这种结构,CNN通过一层一层的传递作用,将原始的图像最后映射到每一类的score。我们可以看到,有些层有参数,有些层没有参数。特别地,CONV/FC层不仅仅只是通过激励函数做转化,而且参数(权值,偏移量)也起到非常重要的作用,另一方面,POOL/RELU 层只是固定的函数在起作用,并没有涉及到参数,CONV/FC层的参数将通过梯度下降的方法训练得到,使得训练样本的预测值与目标值吻合。
下图给出了一个典型的CNN结构。
这里写图片描述
总之,CNN可以总结如下:
1):一个CNN结构是由一系列的执行不同转化功能的layers组成的,将输入的原始图像映射到最后的score。
2):整个网络结构,只有少数几类不同功能的layer (CONV/FC/RELU/POOL 是目前比较流行的几种)。
3):每一层都接收一个3-D的数据体,最后也会输出一个3-D的数据体。
4):有些层有参数(CONV/FC),有些层没有(RELU/POOL)。
5):有些层还可能有hyperparameters(CONV/POOL/FC),有些层则没有(RELU)。
接下来,我们要描述每一类layer的作用,以及相关的参数。

Convolutional Layer

Conv layer是CNN网络的核心部件,它的输出可以看成是一个3-D的数据体,CONV 层包含一系列可学的filters,这些filter的尺寸都很小,但是可以扩展到input的整个depth,前向传递的时候,filter在输入图像上滑动,产生一个2-D的关于filter的激励映射,filter只会和局部的一些像素(神经元)做点积,所以每一个输出的神经元可以看成是对输入层的局部神经元的激励,我们希望这些filter通过训练,可以提取某些有用的局部信息。我们接下来探讨到更加详细的细节。
当输入是高维的变量,比如图像等,如果采用full connected的连接是不切实际的,相反,我们会采用局部连接的方式,那么每一个局部区域我们称为receptive field,这种局部连接是针对输入层的宽,高这两个维度来说,但是对于第三个维度depth来说,依然是要完全连接,所以我们处理局部空间在宽,高维度与depth这个维度是不一样的。宽,高维度上,我们采取局部连接,但是对于depth维度,我们采用全连方式。
比如,如果一个输入图像的尺寸是[32×32×3],我们定义下一层神经元的receptive field的尺寸是5×5,那么考虑到depth这个维度,最终每一次都有5×5×3=75个神经元与CONV层的一个神经元连接,意味着有5×5×3=75个权值。
再比如,假设现在有一个输入的数据体是16×16×20,那么如果定义一个receptive field为3×3的连接方法,那么在CONV层的每一个神经元最终连接到上一层神经元的个数是3×3×20=180。
这两个例子都说明了,在宽,高维度我们采用局部连接的方式,而在depth维度,我们会全部连接。下面给出了一个简单的示意图:

前面我们介绍了CONV层的神经元与前一层的连接方式,但是CONV层本身的神经元如何排列,而且其尺寸如何,我们还没有讨论,事实上,CONV层本身的神经元如何排列以及CONV层的尺寸由三个因素决定:depth,stride,zero padding。
首先,depth决定了CONV层中有多少神经元可以与前一层相同的神经元相连,这个类似普通的神经网络,在普通的神经网络中,我们知道每一个神经元都与上一层的所有神经元相连,所有每一层的所有神经元都是与上一层相同的神经元相连。我们将会看到,所有这些神经元将通过学习从而对输入的不同特征产生应激作用,比如,如果第一个CONV层接收的是原始输入图像,那么沿着depth维度排列的神经元(注意:这些神经元连接的输入层的神经元都相同)可能对不同的特性(比如边界,颜色,斑块)等产生激励。我们将这些连接到输入层同一区域的神经元称为一个depth volume。
接下来,我们必须指定stride,这个决定了我们如何在CONV层排列depth volume,如果我们指定stride为1,那么depth volume的排列将会非常紧凑,意味着隔一个神经元就会有一个depth volume,这样会产生比较大的重叠,而且输出的尺寸也会很大,如果我们增大stride,可以减少重叠,并且可以减少输出的尺寸。
zero padding就是为了控制输出的尺寸,对输入图像的边缘进行补零操作,因为卷积可能使输出图像的尺寸减少,有的时候为了得到与输入一样的尺寸,我们可以在做卷积之前先对输入图像的边缘补零,即先增大输入图像的尺寸,这样可以使得最终的卷积结果与补零前的输入图像的尺寸一致。
我们可以看到,输出层有一个depth,一个spatial size,depth可以指定,spatial size与输入层的size(W),receptive field的size,即filter的size(F),我们定义的stride(S),还有边缘的zero padding的size(P)有关,可以看成是这些变量的一个函数,我们可以证明最终输出的spatial size为:(W−F+2P)/S+1。
我们可以看一个例子,如果输入图像的尺寸为[227×227×3],我们设计一个CONV层,每个神经元的receptive field为11,即F=11,stride为S=4,没有zero padding,那么输出的CONV层的spatial size为(227−11)/4+1=55,如果我们定义CONV层的depth为96,那么这个CONV层的最终尺寸为55×55×96, 从上面这个定义看出,这55×55×96个神经元中的每一个都和输入图像的一个11×11×3的局部区域相连,并且每一个depth volume中含有96个神经元,这96个神经元与输入图像的同一个11×11×3的局部区域相连,它们唯一的区别在于连接权值的不同。
继续看上面的例子,我们知道CONV层有55×55×96=29040个神经元,每个神经元都与输入层的11×11×3个神经元连接,那么CONV层的每一个神经元都将有11×11×3=363个权值外加一个bias,那么最终的系数将会达到29040×(363+1)=105,705,600。很明显,这个系数量太大了。
我们可以利用一个合理的假设来大大系数的数量,我们将CONV层看成一个depth volume,比如上面这个例子,CONV层是一个55×55×96的volume,其depth为96,那么每一个55×55的排列可以看成是一个slice,那么这个CONV层有96个slices,每一个slice的尺寸都为55×55,我们让每一个slice里的神经元都共享一组同样的连接系数,或者说同样的filter,那么意味着每一个slice都只有11×11×3个不同的系数,整个CONV层将只有11×11×3×96=34848,如果每个slice的神经元也共享同样的bias,那么最终的系数为34848+96=34944个,我们看到,通过这种假设,系数的总量大大减少了,每一个slice里的55×55个神经元都共享同样的连接系数,实际运算中,所有的神经元都会计算相应的梯度,但是这些梯度最终会相加,在每一个slice中只做一次更新。
如果每一个slice里的神经元都共享同样的连接系数,那么实际运算的时候可以利用卷积运算,其实这也是这个网络名称的由来,卷积在其中发挥重要的作用,所有我们有的时候把这些系数称为filter或者kernel,卷积的结果就是activation map,每一个activation map叠加,最后形成一个55×55×96的volume。
总结一下CONV的特点:
接收一个尺寸为W1×H1×D1的volume。
定义一些相关的hyperparameter,比如filter的个数K,filter的size或者称为receptive fieldF,stride S以及zero padding P,通过运算可以得到一个如下的
尺寸为:W2×H2×D2的depth volume,其中,W2=(W1−F+2P)/S+1,H2=(H1−F+2P)/S+1,D2=K,通过参数共享,每个slice
会有一个F⋅F⋅D1的kernel,一共有K个kernel,所以一共有系数(F⋅F⋅D1)⋅K,在输出的数据体中,每一个slice的尺寸都是W2×H2,一共有D2=K个slice。
CONV层的backpropagation 同样是卷积运算,这个具体的细节留到后面详细探讨。

Pooling Layer

一般来说,在两个CONV layer之间,会插入一共pooling layer,pooling layer的作用一个是减少输入的空间尺寸,从而可以降低参数的数量及运算量,同时也可以控制overfitting。Pooling layer与上一层的每一个slice是一一对应的,没有相互交叉。最常见的pooling 运算是采用max 操作,在2×2的一个空间区域内,以stride为2进行将采样,pooling操作只在宽,高维度上进行,所以不会改变depth,输出与输入的depth将会一样。总结来说,Pooling layer:接收一个尺寸为W1×H1×D1的volume。定义一些相关的hyperparameter,filter的size或者称为receptive fieldF,stride S,通过运算可以得到一个如下的尺寸为:W2×H2×D2的depth volume,其中,W2=(W1−F)/S+1,H2=(H1−F)/S+1,D2=D1,pooling layer不会又系数,也不会使用zero padding。下图给了一个pooling的示意图:

max pooling 的backpropagation,简单来说就是只对输入的最大值进行梯度运算,所以每次前向运算的时候,最好可以将最大值的位置记录下来,这样每次backward的时候就可以方便运算。

Full-connected Layer

FC layer就像普通神经网络里的隐含层一样,FC layer中的每一个神经元与上一层所有的神经元都会连接(full connected),涉及到的运算也和普通的神经网络一样。值得注意的一点是,FC与CONV layer之间的区别仅在于CONV layer里的神经元只和上一层的局部神经元相连,但是两者的运算模式是一样的,都是做点积,因此在FC与CONV之间存在相互转换的可能。
对于CONV layer,如果我们从FC的角度来看,相当于乘了一个非常大的稀疏矩阵(大部分系数为0,因为只有局部神经元的连接是有效的),而且这些非0系数在某些block中是相等的(系数共享)。反过来,任何FC layer也可以有效地转换成CONV layer,比如一个神经元个数K=4096的FC layer,接收的输入是7×7×512,我们可以等同于利用一个CONV层其hyperparameter设定为 F=7, P=0, S=1, K=4096,我们设定filter的spatial size与输入的spatial size是一样的,这样最后会得到一个1×1×4096的输出。
上面所说的两种转换,其中FC 转换为CONV 在实际运算中非常有用,考虑一个实际的CNN网络,最原始的输入为224×224×3的图像,经过一系列的转换运算,我们得到了一个尺寸为7×7×512的volume,接下来我们用两个FC layer,将这个volume转换为尺寸为4096的volume,最后连接到size为1000的输出,我们可以将这三个FC layer用CONV layer的运算模式来表示。
将第一个FC layer替换成CONV layer,其filter size 为7,我们可以得到1×1×4096的输出。将第二个FC layer替换成CONV layer,其filter size 为1,输出的volume为1×1×4096。同样,最后一个FC layer用filter size为1的CONV layer替换,最后的输出为1×1×1000。
上面所说的每一个转换都涉及到系数矩阵的reshape问题,这种转换可以让我们将CNN结构非常有效的在更大的图像上滑动。比如,如果一个224×224的图像生成了一个尺寸为7×7×512的volume,从224降到7,一共降了32倍,那么,如果输入的图像是384×384,那么我们会生成一个12×12×512的volume,那么我们利用这三层FC layer,转换成CONV layer,我们最终会得到6×6×1000的输出,意味着每一类的score不只是一个数,而是一个6×6的数组。
我们可以看到,如果图像保持不动,而CNN网络每次以32个像素的stride在图像上移动,最后得到的结果是一样的。
一般来说,利用CNN网络做一次遍历,得到一个6×6的score,比重复调用CNN结构36次计算其在图像不同位置之间的score要更加高效,因为这36次调用使用的是同一个网络结构,共享完全一样的系数及运算模式。这种实际应用中,是一种提高分类性能的技巧,比如我们将一幅图先放大,然后再利用CNN结构做遍历,最后将所有得到的score求平均。
最后一点,如果我们想将CNN网络以小于32的stride有效地应用在图像上,可以通过多次前向传递运算达到目的。比如,我们想以16个像素的stride遍历图像,可以做两次运算,第一次是直接将CNN网络在原图上做遍历,第二次,先将原图在宽,高方向分别平移16个像素,然后在平移后的图像上做遍历。
ConvNet Architectures
我们已经看到,CNN网络一般只有几种类型的layer:CONV,POOL(一般默认为max pooling)以及FC,一般我们也会把RELU单独列为一层,用来执行非线性运算的操作,我们看看这些layer如何构建一个完整的CNN网络。
比较常见的模式是先叠加几层CONV-RELU layer,后面连上POOL layer,这样将输入的图像逐渐减少到一个比较小的尺寸,接来下,就连上Full connected layer,最后的FC layer是输出,所以一般比较常见的模式如下所示:
INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
其中*表示重复叠加的意思,而POOL?表示这是可选择的,而且N>=0,一般N<=3,M>=0,K>=0,通常K<=3,下面是一些常见的CNN网络结构。
INPUT -> FC,这是最普通的线性分类器,N = M = K = 0.
INPUT -> CONV -> RELU -> FC
INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC 我们看到CONV layer后面连着Pool layer。
INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC 我们看到在连接POOL layer之前,已经有两个CONV layer叠加到一起了。
一般我们会选择小尺寸的filter,这在实际应用中的效果会更好。一般来说,输入图像的尺寸最好是2的幂次方,比如32,64,96,224,384以及512。CONV 层一般用比较小的filter,比如3×3或者5×5,stride一般设为1,为了让卷积运算之后图像的尺寸保持不变,有的时候会引入zero padding,zero padding的大小一般为P=(F-1)/2,pool layer执行降采样的功能,最常见的pool是用max pooling,在一个2×2的区域内,这样相当于将图像缩小一半,在设计CNN网络的时候,对于这些参数要小心设定,要确保每个layer的输出尺寸与设想的一致。
现在流行的CNN网络结构都是非常庞大的,比较著名的CNN结构有如下几个LeNet, AlexNet, ZF Net, Google Net, VGGNet,具体的介绍可以参考课程网站。这里不再详述。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值