################################################## 神经网络(Neural Network) ################################################## 一、深度学习是什么 ################################################## 神经网络是机器学习中的一类算法,神经网络如下图所示: .. image:: http://upload-images.jianshu.io/upload_images/2256672-c6f640c11a06ac2e.png 上图中每个圆圈都是一个神经元,每条线表示神经元之间的连接。我们可以看到,上面的神经元被分成了多层,层与层之间的神经元有连接,而层内之间的神经元 没有连接。最左边的层叫做 **输入层**,这层负责接收输入数据;最右边的层叫 **输出层**,我们可以从这层获取神经网络输出数据。输入层和输出层之间的层 叫做 **隐藏层**。 隐藏层比较多(大于2)的神经网络叫做 **深度神经网络**。而深度学习,就是使用深层架构(比如,深度神经网络)的机器学习方法。 那么深层网络和浅层网络相比有什么优势呢?简单来说深层网络能够表达力更强。事实上,一个仅有一个隐藏层的神经网络就能拟合任何一个函数,但是它需要很多很 多的神经元。而深层网络用少得多的神经元就能拟合同样的函数。也就是为了拟合一个函数,要么使用一个浅而宽的网络,要么使用一个深而窄的网络。而后者往往更 节约资源。 深层网络也有劣势,就是它不太容易训练。简单的说,你需要大量的数据,很多的技巧才能训练好一个深层网络。这是个手艺活。 感知器 ################################################## 为了理解神经网络,我们应该先理解神经网络的组成单元——**神经元**。神经元也叫做 **感知器**。感知器算法在上个世纪50-70年代很流行,也成功解决了很多问题。 感知器的定义 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 下图是一个感知器: .. image:: http://upload-images.jianshu.io/upload_images/2256672-801d65e79bfc3162.png 可以看到,一个感知器有如下组成部分: - **输入权值** 一个感知器可以接受多个输入 :math:`\left( { x }_{ 1 },{ x }_{ 2 },...,{ x }_{ n }\quad |{ \quad x }_{ i }\in R \right)`, 每个输入上有一个 **权值** :math:`{w}_{i}\in R`,此外还有一个 **偏置项** :math:`b\in R`,就是上图中的 :math:`{w}_{0}`。 - **激活函数** 感知器的激活函数有很多,比如可以选择下面的 **阶跃函数** :math:`f` 来作为激活函数: .. math:: f(z)=\begin{cases} 1\quad \quad z>0 \\ 0\quad \quad otherwise \end{cases} - **输出** 感知器的输出由下面的公式来计算 .. math:: y=f(w\cdot x+b) .. note:: 感知器可以实现and函数,和or函数,却不能实现异或 .. image:: http://upload-images.jianshu.io/upload_images/2256672-acff576747ef4259.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/360 .. image:: http://upload-images.jianshu.io/upload_images/2256672-9b651d237936781c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/360 感知器的训练 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 编程实现感知器 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 神经元 ################################################## 神经元和感知器本质上是一样的,只不过通常情况下感知器的激活函数是 **阶跃函数**;而神经元的激活函数往往是sigmoid函数或tanh函数。如下图所示: .. image:: http://upload-images.jianshu.io/upload_images/2256672-49f06e2e9d3eb29f.gif 计算一个神经元的输出的方法和计算一个感知器的输出是一样的。假设神经元的输入是向量 :math:`\overrightarrow { x }` ,权重向量是 :math:`\overrightarrow { w }` (偏置项是 :math:`{ w }_{ 0 }`),激活函数是sigmoid函数,则其输出 :math:`y`: .. math:: y=sigmoid({ \overrightarrow { w } }^{ T }\overrightarrow { x } ) sigmoid函数的定义如下: .. math:: sigmoid(x)=\frac { 1 }{ 1+{ e }^{ -x } } sigmoid函数是一个非线性函数,值域是(0,1)。函数图像如下图所示 .. image:: http://upload-images.jianshu.io/upload_images/2256672-e7e64f57dc6b1c64.jpg sigmoid函数的导数是: 令 :math:`y=sigmoid(x)` 则 :math:`{ y }^{ \prime }=y(1-y)` 可以看到,sigmoid函数的导数非常有趣,它可以用sigmoid函数自身来表示。这样,一旦计算出sigmoid函数的值,计算它的导数的值就非常方便。 神经网络的定义 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. image:: http://upload-images.jianshu.io/upload_images/2256672-92111b104ce0d571.jpeg 神经网络其实就是按照一定规则连接起来的多个神经元。上图展示了一个全连接(full connected, FC)神经网络,通过观察上面的图,我们可以发现它的规则包括: - 神经元按照层来布局。最左边的层叫做输入层,负责接收输入数据;最右边的层叫输出层,我们可以从这层获取神经网络输出数据。输入层和输出层之间的层叫做隐藏层, 因为它们对于外部来说是不可见的。 - 同一层的神经元之间没有连接。 - **第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神经元的输出就是第N层神经元的输入**。 - 每个连接都有一个权值。 上面这些规则定义了全连接神经网络的结构。事实上还存在很多其它结构的神经网络,比如卷积神经网络(CNN)、循环神经网络(RNN),他们都具有不同的连接规则。 计算神经网络的输出 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **前传** 神经网络的训练 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 现在,我们需要知道一个神经网络的每个连接上的权值是如何得到的。我们可以说神经网络是一个模型,那么这些权值就是模型的参数,也就是模型要学习的东西。 然而,一个神经网络的连接方式、网络的层数、每层的节点数这些参数,则不是学习出来的,而是人为事先设置的。对于这些人为设置的参数,我们称之为超参数(Hyper-Parameters)。 接下来,我们将要介绍神经网络的训练算法:反向传播算法。 反向传播算法(Back Propagation) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 假设神经元的激活函数f为函数sigmoid函数 设每个训练样本为 :math:`(\overrightarrow { x } ,\overrightarrow { t } )`,其中向量 :math:`\overrightarrow { x }` 是训练样本的特征, 而 :math:`\overrightarrow { t }` 是样本的目标值。 .. image:: http://upload-images.jianshu.io/upload_images/2256672-6f27ced45cf5c0d8.png 用样本的特征 :math:`\overrightarrow { x }` ,计算出神经网络中每个隐藏层节点的输出 :math:`{ a }_{ i }`,以及输出层每个节点的输出 :math:`{ y }_{ i }`。 然后,我们按照下面的方法计算每个节点的误差项 :math:`{ \delta }_{ i }`: - 对于输出层节点i, .. math:: { \delta }_{ i }={ y }_{ i }(1-{ y }_{ i })({ t }_{ i }-{ y }_{ i }) 其中, :math:`{ \delta }_{ i }` 是节点的误差项, :math:`{ y }_{ i }` 是节点的输出值, :math:`{ t }_{ i }` 是样本对应于节点 :math:`i` 的目标值。 举个例子,根据上图,对于输出层节点8来说,它的输出值是 :math:`{ y }_{ 1 }`,而样本的目标值是 :math:`{ t }_{ i }`,带入上面的公式得到 节点8的误差项 :math:`{ \delta }_{ 8 }` 应该是 .. math:: { \delta }_{ 8 }={ y }_{ 1 }(1-{ y }_{ 1 })({ t }_{ 1 }-{ y }_{ 1 }) - 对于隐藏层节点, .. math:: { \delta }_{ i }={ a }_{ i }(1-{ a }_{ i })\sum _{ k\in outputs }^{ }{ { w }_{ ki }{ \delta }_{ k } } 其中, :math:`{ a }_{ i }` 是节点 :math:`i` 的输出值, :math:`{ w }_{ ki }` 是节点到它的下一层节点 :math:`k` 的连接的 权重, :math:`{ \delta }_{ k }` 是节点的下一层节点的误差项。例如,对于隐藏层节点4来说,计算方法如下: .. math:: { \delta }_{ 4 }={ a }_{ 4 }(1-{ a }_{ 4 })({ w }_{ 84 }{ \delta }_{ 8 }+{ w }_{ 94 }{ \delta }_{ 9 }) 最后,更新每个连接上的权值: .. math:: { w }_{ ij }\leftarrow { w }_{ ij }+\eta { \delta }_{ j }{ x }_{ ij } 其中, :math:`{ w }_{ ij }` 是节点到节点 :math:`i` 的权重, :math:`\eta` 是一个成为学习速率的常数, :math:`{ \delta }_{ j }` 是节点的误差项, :math:`{ x }_{ ij }` 是节点传递给节点的输入。例如,权重 :math:`{ w }_{ 84 }` 的更新方法如下: .. math:: { w }_{ 84 }\leftarrow { w }_{ 84 }+\eta { \delta }_{ 8 }{ a }_{ 4 } 偏置项的输入值永远为1。例如,节点4的偏置项 :math:`{ w }_{ 4b }` 应该按照下面的方法计算: .. math:: { w }_{ 4b }\leftarrow { w }_{ 4b }+\eta { \delta }_{ 4 } 我们已经介绍了神经网络每个节点误差项的计算和权重更新方法。显然,计算一个节点的误差项,需要先计算每个与其相连的下一层节点的误差项。这就要求误差项的 计算顺序必须是从输出层开始,然后反向依次计算每个隐藏层的误差项,直到与输入层相连的那个隐藏层。这就是反向传播算法的名字的含义。当所有节点的误差项 计算完毕后,我们就可以来更新权重。 神经网络的实现 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 卷积神经网络 ########################################### 视觉感知 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 一、画面识别的任务是什么? 学习知识的第一步就是明确任务,清楚该知识的输入输出。卷积神经网络最初是服务于画面识别的,所以我们先来看看画面识别的实质是什么。 先观看几组动物与人类视觉的差异对比图。 1. 苍蝇的视觉和人的视觉的差异 .. image:: https://pic2.zhimg.com/80/v2-4a0ea7ba42166b62bc4f42e8b150815d_hd.png 2. 蛇的视觉和人的视觉的差异 .. image:: https://pic4.zhimg.com/80/v2-3da84b5b80ba7a0d779284566f80be93_hd.png **通过上面的两组对比图可以知道,即便是相同的图片经过不同的视觉系统,也会得到不同的感知。** 这里引出一条知识:**生物所看到的景象并非世界的原貌,而是长期进化出来的适合自己生存环境的一种感知方式**。 蛇的猎物一般是夜间行动,所以它就进化出了一种可以在夜间也能很好观察的感知系统,感热。 **任何视觉系统都是将图像反光与脑中所看到的概念进行关联**。 .. image:: https://pic4.zhimg.com/80/v2-2c82abd20c4e7c40f7f13f035b924b0b_hd.png 所以画面识别实际上并非识别这个东西客观上是什么,而是寻找人类的视觉关联方式,并再次应用。 如果我们不是人类,而是蛇类,那么画面识别所寻找的?就和现在的不一样。 二、图片被识别成什么取决于哪些因素? 1. 老妇与少女 .. image:: https://pic4.zhimg.com/80/v2-c902a9e33b0322051a5f9165e9439247_hd.jpg 请观察上面这张图片,你看到的是老妇还是少女? 2. 海豚与男女 .. image:: https://pic3.zhimg.com/80/v2-7e5bc60a9e9bd0b597e4b650fecc439e_hd.jpg 上面这张图片如果是成人观察,多半看到的会是一对亲热的男女。倘若儿童看到这张图片,看到的则会是一群海豚(男女的轮廓是由海豚构造出的) .. note:: **图片被识别成什么不仅仅取决于图片本身,还取决于图片是如何被观察的。** 图像表达 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在自然界中,通过物体反光看到物体,那么在计算机中,图像又是如何被表达和存储的呢? .. figure:: https://pic2.zhimg.com/v2-d2859e5c486ed704492ab80079e99535_b.gif 图像在计算机中是一堆按顺序排列的数字,数值为0到255。0表示最暗,255表示 **最亮**。 上图是只有黑白颜色的灰度图,而更普遍的图片表达方式是RGB颜色模型,即红(Red)、绿(Green)、蓝(Blue)三原色的色光以不同的比例相加,以产生多种多样的色光。 这样,RGB颜色模型中,单个矩阵就扩展成了有序排列的三个矩阵,也可以用三维张量去理解,其中的每一个矩阵又叫这个图片的一个channel。 在电脑中,一张图片是数字构成的“长方体”。可用 宽width, 高height, 深depth 来描述,如图。 .. image:: https://pic1.zhimg.com/80/v2-0d24890b2e0d73f4ce4ad17ebfb2d0c4_hd.png 那么如何处理这样的数字长方体。 画面不变性 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在决定如何处理“数字长方体”之前,需要清楚所建立的网络拥有什么样的特点。 我们知道一个物体不管在画面左侧还是右侧,都会被识别为同一物体,这一特点就是 **不变性(invariance)**,如下图所示。 .. image:: https://pic3.zhimg.com/80/v2-b9aed3dd68b9818561faa7d8ed24ea5a_hd.png 我们希望所建立的网络可以尽可能的满足这些不变性特点。 为了理解卷积神经网络对这些不变性特点的贡献,我们将用不具备这些不变性特点的前馈神经网络来进行比较。 图片识别--前馈神经网络 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 方便起见,我们用depth只有1的灰度图来举例。 想要完成的任务是:在宽长为4x4的图片中识别是否有下图所示的“横折”。 图中,黄色圆点表示值为0的像素, 深色圆点表示值为1的像素。 我们知道不管这个横折在图片中的什么位置,都会被认为是相同的横折。 .. image:: https://pic2.zhimg.com/80/v2-18c11c6f485e9f1bbc9a50eb3d248439_hd.png 若训练前馈神经网络来完成该任务,那么表达图像的三维张量将会被摊平成一个向量,作为网络的输入,即(width, height, depth)为(4, 4, 1)的图片会 被展成维度为16的向量作为网络的输入层。再经过几层不同节点个数的隐藏层,最终输出两个节点,分别表示“有横折的概率”和“没有横折的概率”,如下图所示。 .. image:: https://pic2.zhimg.com/80/v2-2b411af47b1cad7b727bb676c847ce59_hd.png 下面我们用数字(16进制)对图片中的每一个像素点(pixel)进行编号。 当使用右侧那种物体位于中间的训练数据来训练网络时,网络就只会对编号为5,6,9,a的 节点的权重进行调节。 若让该网络识别位于右下角的“横折”时,则无法识别。 .. image:: https://pic2.zhimg.com/80/v2-ce9919e4930c1f29241afec0538b2605_hd.png 解决办法是用大量物体位于不同位置的数据训练,同时增加网络的隐藏层个数从而扩大网络学习这些变体的能力。 然而这样做十分不效率,因为我们知道在左侧的“横折”也好,还是在右侧的“横折”也罢,大家都是“横折”。 为什么相同的东西在位置变了之后要重新学习? 有没有什么方法可以将中间所学到的规律也运用在其他的位置? 换句话说, **也就是让不同位置用相同的权重**。 图片识别--卷积神经网络 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 卷积神经网络就是让权重在不同位置共享的神经网络。 局部连接 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在卷积神经网络中,我们先选择一个局部区域,用这个局部区域去扫描整张图片。 局部区域所圈起来的所有节点会被连接到下一层的一个节点上。 为了更好的和前馈神经网络做比较,我将这些以矩阵排列的节点展成了向量。 下图展示了被红色方框所圈中编号为0,1,4,5的节点是如何通过 :math:`{w}_{1},{w}_{2},{w}_{3},{w}_{4}` 连接到下一层的节点0上的。 .. image:: https://pic1.zhimg.com/80/v2-e877b9099b1139c1a34b0bf66bf92aa4_hd.png 这个带有连接强弱的红色方框就叫做 filter 或 kernel 或 feature detector。 而filter的范围叫做filter size,这里所展示的是2x2的filter size。 .. math:: \begin{bmatrix} { w }_{ 1 } & { w }_{ 2 } \\ { w }_{ 3 } & { w }_{ 4 } \end{bmatrix} 第二层的节点0的数值就是局部区域的线性组合,即被圈中节点的数值乘以对应的权重后相加。 用x表示输入值,y表示输出值,用图中标注数字表示角标,则下面列 出了两种计算编号为0的输出值 :math:`{y}_{0}` 的表达式。 **注:** 在局部区域的线性组合后,也会和前馈神经网络一样,加上一个偏移量 :math:`{b}_{0}` 。 .. image:: image/加权求和.png 空间共享 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 当filter扫到其他位置计算输出节点 :math:`{y}_{i}` 时, :math:`{w}_{1},{w}_{2},{w}_{3},{w}_{4}` ,包括 :math:`{b}_{0}` 是共用的。 下面这张动态图展示了当filter扫过不同区域时,节点的链接方式。 动态图的最后一帧则显示了所有连接。 可以注意到,每个输出节点并非像前馈神经网络中那样 与全部的输入节点连接,而是部分连接。 这也就是为什么大家也叫前馈神经网络(feedforward neural network)为fully-connected neural network。 图中显示的是一步一步的移动filter来扫描全图,一次移动多少叫做stride。 .. figure:: https://pic1.zhimg.com/v2-4fd0400ccebc8adb2dffe24aac163e70_b.gif .. note:: **空间共享也就是卷积神经网络所引入的先验知识**。 卷积输出表达 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 如先前在图像表达中提到的,图片不用向量去表示是为了保留图片平面结构的信息。 同样的,卷积后的输出若用上图的排列方式则丢失了平面结构信息。 所以我们 依然用矩阵的方式排列它们,就得到了下图所展示的连接。 .. image:: https://pic2.zhimg.com/80/v2-e1691956fd1beb5d7a637924a1a73d91_hd.png 下面这张图。在看这张图的时候请结合上图的连接一起理解,即输入(绿色)的每九个节点连接到输出(粉红色)的一个节点上的。 .. figure:: https://pic3.zhimg.com/v2-7fce29335f9b43bce1b373daa40cccba_b.gif 经过一个feature detector计算后得到的粉红色区域也叫做一个“Feature Map”。 Depth维的处理 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 现在我们已经知道了depth维度只有1的灰度图是如何处理的。 但前文提过,图片的普遍表达方式是下图这样有3个channels的RGB颜色模型。 当depth为复数的 时候,每个feature detector是如何卷积的? .. image:: https://pic1.zhimg.com/80/v2-0d24890b2e0d73f4ce4ad17ebfb2d0c4_hd.png **现象**:2x2所表达的filter size中,一个2表示width维上的局部连接数,另一个2表示height维上的局部连接数,并却没有depth维上的局部连接数, 是因为depth维上并非局部,而是全部连接的。 也就是说, **在2D卷积中,filter在张量的width维, height维上是局部连接,在depth维上是贯串全部channels的**。 - 在输入depth为1时:被filter size为2x2所圈中的4个输入节点连接到1个输出节点上。 - 在输入depth为3时:被filter size为2x2,但是贯串3个channels后,所圈中的12个输入节点连接到1个输出节点上。 - 在输入depth为n时:2x2xn个输入节点连接到1个输出节点上。 **注意**:三个channels的权重并不共享。 即当深度变为3后,权重也跟着扩增到了三组,不同channels用的是自己的权重。 .. math:: \begin{bmatrix} { w }_{ 1 } & { w }_{ 2 } \\ { w }_{ 3 } & { w }_{ 4 } \end{bmatrix},\begin{bmatrix} { w }_{ 1 } & { w }_{ 2 } \\ { w }_{ 3 } & { w }_{ 4 } \end{bmatrix},\begin{bmatrix} { w }_{ 1 } & { w }_{ 2 } \\ { w }_{ 3 } & { w }_{ 4 } \end{bmatrix} 当filter扫到其他位置计算输出节点 :math:`{y}_{i}` 时,那12个权重在不同位置是共用的,如下面的动态图所展示。 透明黑框圈中的12个节点会连接到被白色边框选中的黄色节点上。 .. figure:: https://pic3.zhimg.com/v2-0bc83b72ef50099b70a10cc3ab528f62_b.gif 每个filter会在width维, height维上,以局部连接和空间共享,并贯串整个depth维的方式得到一个Feature Map。 Zero padding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 有个问题,4x4的图片被2x2的filter卷积后变成了3x3的图片,每次卷积后都会小一圈的话,经过若干层后岂不是变的越来越小? Zero padding就可以在这时 帮助控制Feature Map的输出尺寸,同时避免了边缘信息被一步步舍弃的问题。 形状、概念抓取 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 知道了每个filter在做什么之后,我们再来思考这样的一个filter会抓取到什么样的信息。 我们知道不同的形状都可由细小的“零件”组合而成的。比如下图中,用2x2的范围所形成的16种形状可以组合成格式各样的“更大”形状。 卷积的每个filter可以探测特定的形状。又由于Feature Map保持了抓取后的空间结构。若将探测到细小图形的Feature Map作为新的输入再次卷积后,则可以 由此探测到“更大”的形状概念。 比如下图的第一个“大”形状可由2,3,4,5基础形状拼成。第二个可由2,4,5,6组成。第三个可由6,1组成。 .. image:: https://pic1.zhimg.com/80/v2-f53f6ac43abd2555cfbbba6ea7fdc0e4_hd.png 除了基础形状之外,颜色、对比度等概念对画面的识别结果也有影响。卷积层也会根据需要去探测特定的概念。 如我们先前所提,图片被识别成什么不仅仅取决于图片本身,还取决于图片是如何被观察的。 而filter内的权重矩阵W是网络根据数据学习得到的,也就是说,我们让神经网络自己学习以什么样的方式去观察图片。 拿老妇与少女的那幅图片举例,当标签是少女时,卷积网络就会学习抓取可以成少女的形状、概念。 当标签是老妇时,卷积网络就会学习抓取可以成老妇的形状、概念。 下图展现了在人脸识别中经过层层的卷积后,所能够探测的形状、概念也变得越来越抽象和复杂。 .. image:: https://pic2.zhimg.com/80/v2-c78b8d059715bb5f42c93716a98d5a69_hd.jpg **卷积神经网络会尽可能寻找最能解释训练数据的抓取方式。** 多filters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 每个filter可以抓取探测特定的形状的存在。 假如我们要探测下图的长方框形状时,可以用4个filters去探测4个基础“零件”。 .. image:: https://pic1.zhimg.com/80/v2-6df64fccc9a8e2f696626f85233acb3c_hd.png .. image:: https://pic4.zhimg.com/80/v2-65461a21a909eca2e190c54db59a2c8f_hd.png 因此我们自然而然的会选择用多个不同的filters对同一个图片进行多次抓取。同一个图片,每增加一个filter,就意味着你想让网络多抓取一个特征。 这样卷积层的输出也不再是depth为1的一个平面,而是和输入一样是depth为复数的长方体。 **卷积层的输入是长方体,输出也是长方体。** 这样卷积后输出的长方体可以作为新的输入送入另一个卷积层中处理。 .. image:: https://pic1.zhimg.com/80/v2-a9983c3cee935b68c73965bc1abe268c_hd.png 加入非线性 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 和前馈神经网络一样,经过线性组合和偏移后,会加入非线性增强模型的拟合能力。 卷积神经网络中,激活函数往往不选择sigmoid或tanh函数,而是选择relu函数。Relu函数的定义是: f(x)=max(0,x) Relu函数图像如下图所示: .. figure:: http://upload-images.jianshu.io/upload_images/2256672-0ac9923bebd3c9dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/640 相较于sigmoid,优势如下: - **速度快** 和sigmoid函数需要计算指数和倒数相比,relu函数其实就是一个max(0,x),计算代价小很多。 - **减轻梯度消失问题** 回忆下计算梯度的公式 :math:`\nabla =\sigma \prime \delta x`。其中 :math:`\sigma \prime` 是sigmoid函数的导数。在使用反向传播算法 进行梯度计算时,每经过一层sigmoid神经元,梯度就要乘上一个 :math:`\sigma \prime`,从下图可以看出,:math:`\sigma \prime` 函数最大值是1/4。因此,乘一个 :math:`\sigma \prime` 会导致梯度越来越小,这对于深层网络的训练是个很大的问题。而relu函数的导数是1,不会导致梯度变小。当然,激活函数仅仅是导致梯度减小的一个因素,但无论如何在这方面relu的表现强于sigmoid。 使用relu激活函数可以让你训练更深的网络。 .. image:: http://upload-images.jianshu.io/upload_images/2256672-ad98d6b22f1a66ab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/360 - **稀疏性** 采用sigmoid激活函数的人工神经网络,其激活率大约是50%。有论文声称人工神经网络在15%-30%的激活率时是比较理想的。 因为relu函数在输入小于0时是完全不激活的,因此可以获得一个更低的激活率。 Max pooling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在卷积后还会有一个pooling的操作,尽管有其他的比如average pooling等,最最常用的是max pooling。 max pooling的操作如下图所示:整个图片被不重叠的分割成若干个同样大小的小块(pooling size)。每个小块内只取最大的数字,再舍弃其他节点后, 保持原有的平面结构得出output。 .. image:: https://pic1.zhimg.com/80/v2-1a4b2a3795d8f073e921d766e70ce6ec_hd.jpg max pooling在不同的depth上是分开执行的,且不需要参数控制。 那么问题就max pooling有什么作用?部分信息被舍弃后难道没有影响吗? .. image:: https://pic4.zhimg.com/80/v2-cd717414dcf32dac4df73c00f1e7c6c3_hd.jpg Max pooling的主要功能是downsamping,却不会损坏识别结果。 这意味着卷积后的Feature Map中有对于识别物体不必要的冗余信息。 那么我们就反过来思考, 这些“冗余”信息是如何产生的。 .. note:: 直觉上,我们为了探测到某个特定形状的存在,用一个filter对整个图片进行逐步扫描。但只有出现了该特定形状的区域所卷积获得的输出才是真正有用的, 用该filter卷积其他区域得出的数值就可能对该形状是否存在的判定影响较小。 比如下图中,我们还是考虑探测“横折”这个形状。 卷积后得到3x3的Feature Map中, 真正有用的就是数字为3的那个节点,其余数值对于这个任务而言都是无关的。 所以用3x3的Max pooling后,并没有对“横折”的探测产生影响。 试想在这里例子中如果不使用Max pooling,而让网络自己去学习。 网络也会去学习与Max pooling近似效果的权重。因为是近似效果,增加了更多的parameters的代价, 却还不如直接进行Max pooling。 .. image:: https://pic1.zhimg.com/80/v2-8e9d7ec0662e903e475bd93a64067554_hd.png 但是Max pooling也有不好的地方。有些周边信息对某个概念是否存在的判定也有影响。 全连接层 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 当抓取到足以用来识别图片的特征后,接下来的任务就是如何进行分类。全连接层就可以用来将最后的输出映射到线性可分的空间。所以通常卷积网络的最后会将末端得到的长方体平摊(flatten)成一个长长的向量,并送入全连接层配合输出层进行分类。 卷积神经网络大致就是convolutional layer, pooling layer, Relu layer, fully-connected layer的组合,如下图所示 .. image:: https://pic4.zhimg.com/80/v2-cf87890eb8f2358f23a1ac78eb764257_hd.png 模型将特征抓取层和分类层合在了一起。 负责特征抓取的卷积层主要是用来学习“如何观察”。 卷积层的训练 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 和全连接神经网络相比,卷积神经网络的训练要复杂一些。但训练的原理是一样的:利用链式求导计算损失函数对每个权重的偏导数(梯度),然后根据梯度下降 公式更新权重。训练算法依然是反向传播算法。 回顾下反向传播算法,分为三个步骤: - 1. 前向计算每个神经元的输出值 :math:`{ a }_{ j }` (j表示网络的第j个神经元); - 2. 反向计算每个神经元的误差项 :math:`{\delta}_{j}, {\delta}_{j}` 实际上是网络的损失函数对神经元加权输入 :math:`{ net }_{ j }` 的偏导数,即: :math:`{ \delta }_{ j }=\frac { \partial { E }_{ d } }{ \partial { net }_{ j } }` ; - 3. 计算每个神经元 :math:`{ w }_{ ij }` 连接权重的梯度 最后,根据梯度下降法则更新每个权重即可。 对于卷积神经网络,由于涉及到局部连接、下采样的等操作,影响到了第二步误差项的具体计算方法,而权值共享影响了第三步权重的梯度的计算方法。 我们先来考虑步长为1、输入的深度为1、filter个数为1的最简单的情况。 假设输入的大小为3*3,filter大小为2*2,按步长为1卷积,我们将得到2*2的feature map。如下图所示: .. image:: http://upload-images.jianshu.io/upload_images/2256672-52295dad2641037f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/640 在上图中,为了描述方便,我们为每个元素都进行了编号。用 :math:`{ \delta }_{ i,j }^{ l-1 }` 表示 :math:`l-1` 层第 :math:`j` 行第 :math:`j` 列的误差项; 用 :math:`{ w }_{ mn }` 表示filter第m行第n列权重,用 :math:`{ w }_{ b }` 表示filter的偏置项; 用 :math:`{ a }_{ i,j }^{ l-1 }` 表示第 :math:`l-1` 层第i行第j列神经元的输出; 用 :math:`{ net }_{ i,j }^{ l-1 }` 表示第l-1行神经元的加权输入; 用 :math:`{ \delta }_{ i,j }^{ l }` 表示第l层第j行第第i列的误差项; 用 :math:`{ f }^{ l-1 }` 表示第 :math:`l-1` 层的激活函数。它们之间的关系如下: .. math:: \begin{matrix} net^{ l }=conv(W^{ l },a^{ l-1 })+w_{ b } \\ a^{ l-1 }_{ i,j }=f^{ l-1 }(net^{ l-1 }_{ i,j }) \end{matrix} :math:`{net}^{l}` 、 :math:`{W}^{l}` 、 :math:`{a}^{l-1}` 都是数组, :math:`{W}^{l}` 是由 :math:`{w}_{m,n}` 组成的数组,conv表示卷积操作。 在这里,假设第l中的每个 :math:`{\delta}^{l}` 值都已经算好,我们要做的是计算第 :math:`l-1` 层每个神经元的误差项 :math:`{\delta }^{l-1}`。 根据链式求导法则: .. math:: \begin{align}\delta^{l-1}_{i,j}&=\frac{\partial{E_d}}{\partial{net^{l-1}_{i,j}}}\\&=\frac{\partial{E_d}}{\partial{a^{l-1}_{i,j}}}\frac{\partial{a^{l-1}_{i,j}}}{\partial{net^{l-1}_{i,j}}}\end{align} 先求第一项 :math:`\frac { \partial { E_{ d } } }{ \partial { a^{ l-1 }_{ i,j } } }` 例1,计算 :math:`\frac { \partial { E_{ d } } }{ \partial { a^{ l-1 }_{ 1,1 } } }`, :math:`{ a }_{ 1,1 }^{ l-1 }` 仅与 :math:`{ net }_{ 1,1 }^{ l }` 的计算有关 .. math:: net^j_{1,1}=w_{1,1}a^{l-1}_{1,1}+w_{1,2}a^{l-1}_{1,2}+w_{2,1}a^{l-1}_{2,1}+w_{2,2}a^{l-1}_{2,2}+w_b 因此: .. math:: \begin{align}\frac{\partial{E_d}}{\partial{a^{l-1}_{1,1}}}&=\frac{\partial{E_d}}{\partial{net^{l}_{1,1}}}\frac{\partial{net^{l}_{1,1}}}{\partial{a^{l-1}_{1,1}}}\\&=\delta^l_{1,1}w_{1,1}\end{align} 例2,计算 :math:`\frac { \partial { E_{ d } } }{ \partial { a^{ l-1 }_{ 1,2 } } }`, :math:`{ a }_{ 1,2 }^{ l-1 }` 与 :math:`{ net }_{ 1,1 }^{ l }、{ net }_{ 1,2 }^{ l }` 的计算都有关: .. math:: net^j_{1,1}=w_{1,1}a^{l-1}_{1,1}+w_{1,2}a^{l-1}_{1,2}+w_{2,1}a^{l-1}_{2,1}+w_{2,2}a^{l-1}_{2,2}+w_b\\net^j_{1,2}=w_{1,1}a^{l-1}_{1,2}+w_{1,2}a^{l-1}_{1,3}+w_{2,1}a^{l-1}_{2,2}+w_{2,2}a^{l-1}_{2,3}+w_b\\ 因此: .. math:: \begin{align}\frac{\partial{E_d}}{\partial{a^{l-1}_{1,2}}}&=\frac{\partial{E_d}}{\partial{net^{l}_{1,1}}}\frac{\partial{net^{l}_{1,1}}}{\partial{a^{l-1}_{1,2}}}+\frac{\partial{E_d}}{\partial{net^{l}_{1,2}}}\frac{\partial{net^{l}_{1,2}}}{\partial{a^{l-1}_{1,2}}}\\&=\delta^l_{1,1}w_{1,2}+\delta^l_{1,2}w_{1,1}\end{align} 例3,计算 :math:`\frac { \partial { E_{ d } } }{ \partial { a^{ l-1 }_{ 2,2 } } }`, :math:`{ a }_{ 2,2 }^{ l-1 }` 与 :math:`{ net }_{ 1,1 }^{ l }`、:math:`{ net }_{ 1,2 }^{ l }`、:math:`{ net }_{ 2,1 }^{ l }`、:math:`{ net }_{ 2,2 }^{ l }` 的计算都有关: .. math:: net^j_{1,1}=w_{1,1}a^{l-1}_{1,1}+w_{1,2}a^{l-1}_{1,2}+w_{2,1}a^{l-1}_{2,1}+w_{2,2}a^{l-1}_{2,2}+w_b\\ net^j_{1,2}=w_{1,1}a^{l-1}_{1,2}+w_{1,2}a^{l-1}_{1,3}+w_{2,1}a^{l-1}_{2,2}+w_{2,2}a^{l-1}_{2,3}+w_b\\ net^j_{2,1}=w_{1,1}a^{l-1}_{2,1}+w_{1,2}a^{l-1}_{2,2}+w_{2,1}a^{l-1}_{3,1}+w_{2,2}a^{l-1}_{3,2}+w_b\\ net^j_{2,2}=w_{1,1}a^{l-1}_{2,2}+w_{1,2}a^{l-1}_{2,3}+w_{2,1}a^{l-1}_{3,2}+w_{2,2}a^{l-1}_{3,3}+w_b .. note:: 总结下规律,计算 :math:`\frac { \partial { E_{ d } } }{ \partial { a^{ l-1 } } }`,相当于把第l层的sensitive map周围补一圈0,在与180度翻转 后的filter进行cross-correlation,就能得到想要的结果 .. image:: http://upload-images.jianshu.io/upload_images/2256672-2fb37b0a3ff0e1f9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/640 因为卷积相当于将filter旋转180度的cross-correlation,因此上图的计算可以用卷积公式完美的表达: .. math:: \frac{\partial{E_d}}{\partial{a_l}}=\delta^l*W^l 上式中的 :math:`{W}^{l}` 表示第层的filter的权重数组。 **现在再来求第二项** :math:`\frac{\partial{a^{l-1}_{i,j}}}{\partial{net^{l-1}_{i,j}}}`。因为: .. math:: a^{l-1}_{i,j}=f(net^{l-1}_{i,j}) 所以求激活函数f的导数就行了。 .. math:: \frac{\partial{a^{l-1}_{i,j}}}{\partial{net^{l-1}_{i,j}}}=f'(net^{l-1}_{i,j}) **将第一项和第二项组合起来,我们得到最终的公式:** .. math:: \begin{align}\delta^{l-1}_{i,j}&=\frac{\partial{E_d}}{\partial{net^{l-1}_{i,j}}}\\&=\frac{\partial{E_d}}{\partial{a^{l-1}_{i,j}}}\frac{\partial{a^{l-1}_{i,j}}}{\partial{net^{l-1}_{i,j}}}\\&=\sum_m\sum_n{w^l_{m,n}\delta^l_{i+m,j+n}}f'(net^{l-1}_{i,j})\qquad(式7)\end{align} 写成卷积的形式: .. math:: \delta^{l-1}=\delta^l*W^l\circ f'(net^{l-1})\qquad 其中,符号表示将矩阵中每个对应元素相乘。 :math:`\delta^{l-1}`、 :math:`\delta^l`、 :math:`{net}^{l-1}` 都是矩阵。 **卷积步长为S时的误差传递** .. image:: http://upload-images.jianshu.io/upload_images/2256672-754f37eb7603e99f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/640 .. note:: 如上图,上面是步长为1时的卷积结果,下面是步长为2时的卷积结果。我们可以看出,因为步长为2,得到的feature map跳过了步长为1时相应的部分。 因此,当我们反向计算误差项时,我们可以对步长为S的sensitivity map相应的位置进行补0,将其『还原』成步长为1时的sensitivity map,在求解。 **输入层深度为D时的误差传递** 当输入层深度为D时,filter的深度也必须为D,:math:`l-1` 层的 :math:`{d}_{i}` 通道只与filter的 :math:`{d}_{i}` 通道的权重进行计算。 因此,反向计算误差项时,用filter的第 :math:`{d}_{i}` 通道权重对第l层的 sensitive map进行卷积,得到第 :math:`l-1` 层 :math:`{d}_{i}` 通道的sensitivity map。如下图所示 .. image:: http://upload-images.jianshu.io/upload_images/2256672-af2da9701a03dc3c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/640 尺寸不变性与inception ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~