# 机器学习与深度神经网络概述 ## 编程解题的两个前提 可以编程解决的问题,应该具有两个特征: 1. 人类可以(至少理论上可以)解决 2. 人类可以**说明白如何在有限步骤内解决此问题** 自计算机发明以来,人类一直在按照这个思路设计程序:直接编排指令以使计算机完成特定的任务。我们日常所使用的软件,几乎全是以这种思路编写。 ## 困境 尽管这种思路已经取得了巨大的成功,但是仍存在一些任务(有些甚至是极其简单的),在这种框架下难以完成。 {{:science:machinelearning:ml_basic_cats.png?direct|猫岛}} 图中有多少只喵? 此类对于人类而言仅需要耐心便可解决的问题,用传统思路编程解决却极为困难,因为你无法分布说清楚为何某处是一只猫而不是一只狗、为何这不是一块毯子、为何有的地方一条尾巴也算一只猫,但图上有些猫却没有露出尾巴…… 也许通过精雕细琢,使用传统方法数清楚这些猫也是可以实现的(之前有人嘲笑百度自动驾驶的核心代码堆了上万个`if`)。但若有数狗的任务,一切又要重来。这显然不是人么想要的算法。 ## 解局:机器学习 机器学习的优势,在于部分移除了“人类可以说明白”这个限制,仅需要人类可以做到,便可以以人类做出的例子为基础,通过反复训练机器学习模型而使程序自行“学会”执行该任务所需的知识。 机器学习是一类算法的统称。近年来,机器学习算法中神经网络这一分支热度较高,但神经网络不是机器学习的全部。 {{:science:machinelearning:ml_basic_classify.png?direct|机器学习与神经网络}} 除图上算法之外,发展较为成熟的机器学习还包括`SVM`分类器、`决策树`等,这里不再展开阐述。 ## 发展历史 + 1940 年代 - 神经网络被提出 + 1960 年代 - 深度神经网络被提出 + 1974 年 - 反向传播`BP`算法被提出 + 1989 年 - 识别数字的神经网(`LeNet`)出现 + 1990 年代 - 浅层神经网硬件出现(Intel ETANN) + 2011 年 - DNN 语音识别取得突破性进展(Microsoft) + 2012 年 - 用于视觉的 DNN 开始替代人工放大(`AlexNet`) + 2014 年+ - DNN 加速器研究兴起(Neuflow、DianNao 等等) + …… {{:science:machinelearning:ml_basic_imagenet_history.png?direct|ImageNet的进步}} 上图是这些年来ImageNet竞赛中每届冠军的表现。你可以看到最初算法精确度的错误率在25%或更多。2012年,多伦多大学的`AlexNet`团队通过GPU来提升其计算能力并采用深度神经网络方法,把错误率降低了近10%。他们的成功带来了深度学习风格的算法的井喷,以及图像识别技术的持续进步。 最新的`ResNet`,在此图片分类任务上的精度已经超越了人类。而对于简单的图片识别任务(如手写邮编识别),神经网络早在十几年前就全面淘汰了人类。 # 从感知器到DNN ```flow st=>start: sigmoid函数 sensor=>operation: 感知器 nn=>operation: 感知器网络 cnn=>operation: 卷积神经网络CNN dnn=>operation: 深层神经网络DNN e=>end: ...... st->sensor->nn->cnn->dnn->e ``` ## sigmoid 函数 {{:science:machinelearning:ml_basic_sigmoid.png?direct|sigmoid}} ${\sigma}(x)=\frac{1}{1+e^{-x}}$ ${\sigma}'(x)=\frac{e^{-x}}{(1+e^{-x})^2}={\sigma}(x)[1-{\sigma}(x)]$ 线性系统的组合仍然是线性系统,而图片识别这类任务显然需要处理非线性特征。`sigmoid`函数显然是一个非线性函数,它是神经网络中最基础的一种`激活函数`。 `激活函数`:是一个函数。“激活”是生物学概念,指的是单个神经元的活跃程度。函数输出值越大,表示其被“激活”的程度越高。不同神经元的不同激活程度的组合,即代表了不同的输出。 e.g. 假如有七个神经元按顺序连接于一个七段式数码管上,不同的激活状态控制数码管的亮、暗,则不同的激活状态组合就带变了不同的数字。 {{:science:machinelearning:ml_basic_7led.png?direct&600|数码管}} `sigmoid`函数有一些重要的优点,使其适合作为激活函数: + 非线性函数,可以为神经网络引入非线性特征 + 单调函数,可用于表征某个输入特征的“程度” + 在0附近区域变化较快,对于于不同的输入有不同的反应 + 在远离0的区域变化不大且有上下限,避免单个神经元输出的过大的波动影响整个网络([癫痫的发病机理](http://www.baike.com/wiki/%E7%99%AB%E7%97%AB)) + 导数的计算简单,可以简单地通过函数值的四则运算得到导数值,这在优化中非常重要 人们后面也发现了其他一些适合作为激活函数的例子: {{:science:machinelearning:ml_basic_other_activation_fun.png?direct|激活函数}} ## 感知器与感知器网络 感知器是构成神经网络的基本单元,故有时也称人工神经网络的“神经元”。大量感知器按一定结构相互连接。即可模拟生物神经系统的运作,做出有“意识”的行为。 > **人工神经网络**这一学科大大获益于生物学中神经科学的研究,时而也会反哺生物学中关于思维机理的研究。 感知器的核心是`sigmoid`函数,只是在输入上做了偏移:将自己的上一层神经元的输出做加权求和,总和再加上自己的`偏置`,结果送入激活函数,激活函数的输出作为自己的输出,送入下一层网络。 {{:science:machinelearning:ml_basic_sigmoid_in_out.png?direct|感知器}} 以使用`sigmoid`激活函数的感知器网络为例,显然每个感知器的输出都在`(0,1)`区间。但多个感知器输出的加权和可能轻易远低于0(此时神经元基本没有激活)或者远高于1(此时神经元彻底激活)。 每个感知器都有自己的一套`权重`和`偏置`,这是神经元自己的“记忆”,也是神经网络训练中被改变的部分。单个神经元的工作意义不大,但大量神经元的组合就可以作出“有意识”的行为。 **通过精心调节每个神经元的`权重`和`偏置`,理论上可以将神经网络的表现调节到最优。然而,实用神经网络中的神经元数以万计,参数数量更要比此高出若干数量级,全局寻优甚至近似全局寻优都是不可能的。目前人类的能力只能做到寻找局部最优解。量子计算机可能会为此提供一条捷径。** 大量感知器分层连接起来所形成的网络,就是感知器网络。这是最简单、最基础的神经网络。典型的感知器网络包括三层: {{:science:machinelearning:ml_basic_sensor_net.png?direct|感知器网络}} 以最简单的手写数字识别任务为例,搭建一个神经网络: 1. 图片分割、旋转、校正、灰度化,然后缩放到固定大小(如`[24,48]`) 2. 图片按行展平,成为一列`24×48`个灰度值 3. 灰度值归一化到`[0,1]`区间,作为输入层`24×48`个神经元的输出 4. 隐藏层感知器个数可以任意设定,如`2048` 5. 隐藏层每个神经元都与输入层所有神经元相连接 7. 输出层同样与隐藏层两两连接 8. 输出层有10个神经元,分别代表10个数字 9. 定义:激活程度最大的一个神经元的序号,代表网络识别出来的数字 如此定义之下,对于一张数字`1`的图片,在最佳情况下,输出层10个神经元的激活函数输出应该是:`0 1 0 0 0 0 0 0 0 0`。通过特定的优化算法,调节所有神经元的`权重`和`偏置`,使其对于这张`1`的图片恰好产生上述输出,即完成了一轮优化。使用大量样本反复优化,总能找到一个参数组合,使得对于**绝大部分**手写数字图片,网络的输出都是正确的,优化完成。 上面给出的`0 1 0 0 0 0 0 0 0 0`序列,是需要神经网络来学习的`目标`。优化器的实际目标,是要使得神经网络的`输出`与`目标`之差最小。优化器的实际目标称为`损失函数`。对于同一个任务,损失函数可以有多种选择,不同选择所能达到的效果相差可以很大。`损失函数`的选择需要推理和经验。 理论上,这种三层神经网络,只需要一直增大隐藏层的规模,足以无限逼近任意函数。但实际上这样做需要巨大的计算/储存资源,所以对待复杂问题一般不会这样做。 ## `BP`算法 `Backpropagation`(反向传播)算法,是优化神经网络的一种手段,也是当前所使用的主要手段。 上面已经说过,对于大型神经网络的全局寻优,在当前计算能力下是难以完成的。目前所使用的优化算法,主要是梯度下降法等基于微分的、只能找到局部最优解的算法。这些算法的工作依赖于被优化函数的导数。 一个结构确定的神经网络,可以看作是一个多元函数$f(\vec{x})$,但我们不知道其数学表达式(或数学表达式过于复杂,无法求导)。为了获取其导数,一般的做法是对于每一个自变量$x_i$增加一个微量$\Delta{x_i}$,然后重新计算函数值,以得到$\frac{f(x_i+\Delta{X_i})-f(x_i)}{\Delta{x_i}}$作为导数的近似。然而,当函数的输入向量$\vec{x}$具有数百万个分量的时候,这样做的计算消耗仍然是惊人的。 `BP`算法采纳了另一种思路:利用链式求导法则,将多元函数$f(\vec{x})$认为是多层小函数嵌套而成。利用`BP`算法,我们仅需要一轮运算,即可获得神经网络中每一个参数对于神经网络性能的影响程度以及方向,进而利用梯度下降法等进行优化。 `BP`算法的细节需要大量的数学推导,这里不再详述。 ## 卷积神经网络`CNN` 卷积神经网络是近年来兴起的一类神经网络,主要用于处理图片、视频等视觉数据。其特点是利用`卷积Convolution`运算代替全连接网络,在基本不影响精度的前提下大大缩小网络规模,以便训练,并减小[过拟合](https://www.zhihu.com/question/32246256)的可能性。 > 包含卷积层的神经网络叫做卷积神经网络 ^-^ ~~定义就是这么简单粗暴~~ 神经网络中的卷积运算,在数学上与微积分学中的卷积运算等价,但实际上执行的就是对某矩阵一个小区域内的数值加权求和。后有详解。 回到对人类思维的模仿。设想对于一张图片,人脑对其的处理过程一般是先整体感知(图中有很多猫在地上),再局部分析(此处有一只猫)。 1. 一旦进入`局部分析`这一过程,远离此局部的信息就*几乎*不再用到。 2. 针对一个局部进行分析所获得的规律/知识,在同一张图中的其他部分一般也是有效的 以上是对人脑分析过程的特点概括,同时也是卷积神经网络的理论基础。由于上面所说的局部性,在视觉处理任务中使用全连接网络(如上面说到的“感知器网络”一样,前后两层中所有神经元两两相连的网络),显然是一种浪费。对于后一层的某个神经元而言,它只需要与前一层中自己对应位置附近(如`5x5`个像素)的这些神经元相连即可,这已经足够获取需要的信息了。*一只猫显然大于`5x5`像素,为啥`5x5`就够了?后面讲。* 从下图容易看出,使用局部连接的思路,需要优化的参数数量降低了**一万倍**。而这还只是用到了上面说过的第一条特点(局部信息)。 {{:science:machinelearning:ml_basic_fc_net.png?direct|局部连接网络}} 第二点,规律共享。可以想象,上面讲到的局部连接网络,后层的每个神经元都可以自己捕捉到一套规律。从“规律共享”这一点出发,我们可以认为,这些神经元的运算共享同一套(或者若干套)规律就够了,即后层的`1000x1000`个神经元,共享同一套`权重`和`偏置`。 {{:science:machinelearning:ml_basic_cnn_net.png?direct|卷积神经网络}} 参数数量再次降低了**一万倍**。图中的“100 Filters”指的是分配了了100套规律用于学习。 `Filters`,又称`卷积核`,就是图像处理领域中的`过滤器`(当然不是美图秀秀中的滤镜)。实质上就是一个`N x N`的小矩阵。应用`卷积核`的过程可以想象为一个用一个格子板去“套”图片中某个`N x N`的小区域,对应位置的数值相乘,求和,结果就是卷积的结果。此结果将作为卷积神经网络中下一层某个神经元的激活函数的输入。 {{:science:machinelearning:ml_basic_convolution.gif?direct|卷积}} 卷积的输出结果还可以看作是图片。100个卷积核配合`1000x1000`个神经元,输出的是100张`1000x1000`的图片。这些图片可以继续被作为下一层卷积的输入。组合起来就是一个卷积神经网络。 {{:science:machinelearning:ml_basic_convolution_net.png?direct|CNN}} 采样指的是将相邻像素中特征明显的一个留下来,其余丢弃。一次`2x2`的采样可以将图像的长、宽各缩小为$\frac{1}{2}$。 回到上面留下的一个问题:一只猫显然大于`5x5`像素,为啥`5x5`就够了? 因为卷积网络的思路是,通过一层又一层的卷积,先提取图片的低级特征,然后再在低级特征的基础上提取高级特征。比如一个训练好的`数猫器`网络,第一层卷积核可能就是边缘检测器,检测某个像素处是不是两个物体的边界;第二层可以检测到猫鼻子、眼睛、皮毛(或者是水泥地上一块形状颜色类似的污渍);再后面一层检测猫头、猫腿、猫尾巴;再后面检测这些部件是否是按正确的逻辑、空间位置组合的。此时误检率已经很小,神经元数目也不多,再用一层或几层全连接网络执行数数任务,即可输出。 [深度卷积网络的 BUG 一例:“绝艺”最近被人类棋手找到了一个有趣的缺陷](https://zhuanlan.zhihu.com/p/25222921) 卷积神经网络的设计需要经验、技巧和运气。下图是2012年将`ImageNet`任务精度大大提高、从而引爆卷积神经网络研究的`AlexNet`. {{:science:machinelearning:ml_basic_alex_net.png?direct|AlexNet}} ## 深度神经网络`DNN` > 层数非常多的卷积神经网络叫做深度神经网络 多少层才算是深,没有明确定义。深度神经网络相比普通的卷积神经网络,可以得到更加高级特征,但难于训练。 训练信息是按照`BP`算法,从网络的后面向前传播的。每传播一层,正确的规律信息都会被削弱。按照原生的`BP`算法,实际上四、五层之后,传播的信息已经很弱,基本掩盖不了噪声。这时候再加深网络层数,精度也不会提高,因为前面层次已经得不到训练。 目前,已经有了一些数学方法用于训练深度很大的神经网络,如`BatchNormalize`.这些方法可以有效训练成百上千层的深度神经网络。