IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    数学不行还学AI – 神经网络平话演义(上)

    Hunter发表于 2017-05-07 23:00:32
    love 0

    原文:Learning AI if You Suck at Math — P5 — Deep Learning and Convolutional Neural Nets in Plain English!

    作者:Daniel Jeffries

    翻译:Kaiser(王司图)

    今天,我们要来写一个自己的Python图像识别程序。

    为此我们要了解一个强大的深度学习架构——深度卷积神经网络(Deep Convolutional Neural Network, DCNN)。

    卷积神经网络可谓计算机视觉界的劳模,从无人汽车到Google图片搜索,背后都有其功劳。在TensorFlow 2017 峰会上,一位研究者展示了用手机里的卷积神经网络诊断皮肤癌。

    为什么卷积神经网络如此强劲呢?一个关键原因在于:

    自动模式识别

    那模式识别又是什么?自动了又如何?

    模式可能以很多种形式存在,这里只看两个最重要的例子:

    定义物理形式的特征

    完成特定任务的步骤

    计算机视觉

    在图像处理的模式识别中,又叫作特征提取。

    当你看一张照片或者实物的时候,你会选择性地拎出关键特征来进行认识,这是无意识中发生的。

    当你看到我家猫Dove的照片,会想到“猫”或者“铲屎官”,但是你并不知道自己是如何想到的,而只是单纯地那样去做了,这都是自动而且无意识发生的

    听起来非常简单,每时每刻都在经历,但这是因为真正的复杂性隐藏在深处。大脑是个黑盒,我们谁也没有说明书。哪怕只是一个微小的动作,也包含了巨量的步骤,表面上看似简单,实则无比复杂。

    转动眼珠。

    接收并分解光线。再传递信号给大脑。

    大脑开始工作,将光信号转换为电化学信号。

    信号在我们内置的神经网络中传播,激活不同的区块——记忆、联想、感觉等等。

    大脑首先感知了低阶模式(耳朵,胡须,尾巴),再组成高阶模式(动物)。

    最后,我们进行了分类,转换成词汇,也就是对真实事物的象征表达,这里就是“猫”。

    以上种种,全部发生在一瞬之间。

    如果你想要教电脑来执行这些,你会如何开始?

    如何找到耳朵?

    什么是耳朵?

    如何描述耳朵?

    为什么猫耳不同于人耳、蝙蝠耳(或蝙蝠侠的耳朵)?

    耳朵从不同角度看都是什么样?

    所有的猫耳朵都一样吗?(当然不,看看苏格兰折耳猫)

    类似问题无穷无尽。如果你想不出如何用C++或Python教会电脑的好方法,也不要灰心,因为这已经困扰了计算机科学家们50多年了!

    你自然而然完成的,正式深度学习神经网络的关键应用之一——分类器,这里是图像分类器。

    起初,AI研究者想做的跟我们刚才一样。他们希望事无巨细,手动定义每一个步骤,比如对于自然语言处理(NLP),他们召集了最顶尖的语言学专家,让他们总结出语言的所有规律,这也是为什么早期的AI又叫“专家系统”。

    语言学家坐成一圈开始琢磨了,然后一个接一个,目不暇接的判断语句冒了出来:

    鸟会飞吗?

    会。否则:

    鸟死了

    鸟残了

    没翅膀

    企鹅

    这样下去就没完了,而且还不一定靠谱,花很长时间创造这些判断,最后只剩下无尽的争论、表述的偏差、定义的模糊。

    深度神经网络代表着真正的突破,因为你不再需要知晓所有细节,而是让机器自动提取出猫的特征。

    这里的关键是“自动”,因为每个复杂的行为背后都有数以百万计的隐藏步骤,是不可能去全部明确的,只能选择绕过,然后让电脑自己领悟。

    万物的无尽步骤

    来看第二个例子:计算任务的步骤。

    今天我们手动为计算机定义好了每一个步骤,这就是编程。比如你想找到硬盘上所有的图片文件,然后移动到新文件夹。对绝大多任务而言,程序员就是神经网络,就是智能。他学习任务,分解成步骤,再用符号表示(编程语言)告诉计算机。这里是一个Python的小例子,来自Stack Exchange上的Jolly Jumper:

    1

    Jolly Jumper为计算机定义好了每一个步骤:

    我们需要知道源路径和目标路径

    需要分类方法选出目标文件格式,这里是”jpg”

    进入路径,搜索jpg并移动到目标路径

    对于简单的,甚至一般复杂的问题,这都是可行的。操作系统由上亿行代码组成,可以算是地球上最复杂的软件了,每一行都在显式地知道计算机该做什么(绘图,存储,更新),也帮助人完成任务(复制文件,输入文本,收发邮件,浏览照片等)。

    但是随着问题复杂度的增加,我们手动定义问题步骤的能力,也遇到了瓶颈。举个例子,如何开车?这种想想就很复杂的任务,包含数以百万计的小步骤:

    沿直线行驶

    知道什么是直线,并认出来

    从某地行驶到另一地

    识别障碍物如墙,人,渣渣

    区分有益物(交通号志)还是危险物(作死的人)

    实时掌握周边车辆状况

    决定下一个动作

    在机器学习里,这就是决策制定问题,复杂的该类问题例如:

    机器人的运动与感知

    语言翻译系统

    自动驾驶汽车

    股票交易系统

    神经网络的秘密花园

    来看深度学习如何通过自动特征提取,来帮助我们解决那些复杂到令人发狂的问题。

    如果读过V.Anton Spraul的经典书籍像程序员一样思考(强烈推荐阅读),就会知道编程是有关解决问题的。程序员化大为小,分而治之,临阵画策,写码执行。

    而深度学习是代替我们解决问题,但是目前AI还是需要人类(万幸)设计测试AI架构的。让我们对神经网络也分而治之,再创建程序认出我家Dove是只猫。

    故能成其深

    深度学习是机器学习的子学科,我们把许多不同的层堆叠起来,学习数据中更有意义的表征,因而得名。其中每一个“层”就是神经网络,由人工神经元连接而成。

    在强大的GPU帮我们做计算之前,只能建立一些很小的“玩具”神经网络,也做不了多少事情。而现在我们可以堆叠多层,故能成其深。

    “神经网络”是在1950年代受人脑研究启发而来,研究者们创造了神经元的数学表达如下(感谢斯坦福大学的优秀公开课件和维基百科):

    生物的神经元生物的神经元

    神经元的数学模型神经元的数学模型

    忘掉所有复杂的数学符号,因为你不需要它们。

    基础非常简单,X0代表数据,在神经元的连接当中流动,连接的强度由权重(W0X0, W1X1)代表。如果信号足够强,就会通过“激励函数”激活神经元。

    这里是一个三层神经网络的例子:

    有些神经元被激活,有些神经元之间的连接被增强,由此系统学习到了那些才是重要的。


    建立并训练神经网络

    接下来我们边写代码,边深入理解深度学习。系统的必要特性有:

    训练

    输入数据

    层

    权重

    目标

    损失函数

    优化函数

    预测

    训练

    训练就是我们如何教会神经网络要学什么,分为五个步骤:

    建立训练集, 记作x,并导入标签为目标y

    前馈数据给网络,得到预测结果y’

    定义网络的“损失”,即预测y’和真实目标y之差

    计算损失的“梯度”,即我们接近或远离正确目标的速度

    沿着梯度的反方向来调整网络权重,并周而复始

    输入数据

    在本例中,DCNN的输入数据是一组图片,图片越多越好。与人类不同,计算机需要大量的图片才能学会分类。AI研究者正致力于用尽可能少的数据达到学习目的,但这仍是个前沿问题。

    一个著名例子就是ImageNet数据集,由很多手动标注过的图片组成。换句话说就是预先让人类用他们内置的神经网络把图片全部看一遍,然后给数据赋予意义。人们上传照片,并打上标签,比如“狗”,或者某个品种的狗“猎兔犬”。标签代表了网络的准确预测,网络的预测输出(y’)与手动标记数据(y)越接近,就说明其越准确。

    数据被分为两部分,训练集和测试集。训练集就是我们给神经网络的输入,根据它们学习多种物体的关键特征,再与测试集中的随机数据相比较以衡量准确性。

    在我们的程序中,将用到的是著名的CIFAR-10数据集,由加拿大高等研究所提供。CIFAR10有60000张32×32的彩色图片,共分为10类,每类6000个。其中50000个作为训练集,10000个充当测试集。

    当我第一次使用CIFAR的时候,我误以为这会比ImageNet的大尺寸图片更简单。而事实却是,CIFAR10更具挑战性,因为图片尺寸小、数量少,可供神经网络识别的特征也少。

    一些最大也是最差的DCNN架构如ResNet可以在ImageNet上达到97%的准确率,但在CIFAR 10却只有87%。根据我的经验,目前处理CIFAR 10的业界标杆是DenseNet,准确率可达95%。但是需要足足250层和1500万个参数!我把这些框架附在了文末,可供参考,但是开始阶段最好还是先关注些简单的问题。

    理论已经讲的差不多了,是时候放码过来了。如果你对Python还不是很熟悉,我热烈,强烈,猛烈,剧烈地推荐Fabrizio Romano的Learning Python,此书把每个点都解释得特别好。我从未见过如此优秀的Python书,反而被很多耽误了不少时间。

    代码基于Github上的Keras示例代码,我个人的修改可见这里。

    我已经调整了架构和参数,并加入了TensorBoard来辅助可视化。首先初始化我们的Python程序,导入数据集和建立DCNN所需的类。所幸,Keras已经集成了很多,所以十分方便。

    2

    现在来添加层。大多数神经网络使用全连接层,也就是每个神经元都连接着其他所有神经元。全连接层对各种问题都表现良好,但不幸的是对图像识别的尺度缩放问题解决不到位。所以我们用卷积层来搭建系统,其独到之处就在于,不是所有神经元都相互连接。

    斯坦福计算机视觉课程谈卷积神经网络:

    “在CIFAR-10中,图片只有32x32x3(32像素宽,32像素高,3个色彩通道),所以常规神经网络的第一个隐藏层上的全连接神经元就有32323=3072个权重值。这个数量看起来还可以,但很明显全连接结构无法应对大图片。比如,生活中常见的图片尺寸,200x200x3,就会使神经元拥有120,000个权重值。不仅如此,我们还希望更多的神经元,所以参数的数量会迅速暴涨!显然,全连接层有些浪费,而大量的参数又很容易导致过拟合。”

    过拟合就是把训练集学得炉火纯青,却对没见过的图片束手无措,派不上实际用场。就像你不断地玩着同一局棋,对棋谱都倒背如流,但是对手一旦变招,你就无计可施了,之后我们还会详谈过拟合。

    下图表现了数据在DCNN里的流动情况,每次只关注很小一部分数据,探寻模式,基于观察建立高层认知。

    卷积神经网络可视化,来自MIT计算机视觉组开发的mNeuron插件卷积神经网络可视化,来自MIT计算机视觉组开发的mNeuron插件

    注意,前面的几层是简单的模式,比如边缘,颜色,基本形状。随着信息在层间流淌,系统逐渐摸清了更复杂的模式,比如纹理,最终导出物体的类别。

    这一思路来自一个生物实验:研究表明猫对于不同的刺激(边缘,颜色),有不同的视觉细胞响应。

    来自牛津大学深度学习公开课

    来自牛津大学深度学习公开课

    人类也是一样,我们的每个视觉细胞只能感受特定的特征。

    这一个典型的DCNN架构示意图:

    你会注意到这里还有第三种层,池化层,在牛津课程和斯坦福课程中可以获得更多细节。这里我们会跳过很多细节,因为大部分人难以理解,我第一次学的时候就是这样的体会。

    对于池化层你需要了解如下内容:它的目的很简单,就是下采样,也就是压缩输入图片,从而降低计算负担和内存消耗。信息少了,工作起来就轻便了。池化同样有助于减少过拟合,就是网络聚焦在了训练集的个别现象上,而忽略了挑选出猫狗鸟。比如有的图片上可能会存在坏点或镜头光晕,网络可能会把光晕和狗当成一体的,而实际上根本风马牛不相及。

    最后,多数DCNN会添加几个密集连层接,也即全连接层 来映射前面几层的特征并做出预测。所以现在给我们的卷积网络也加几层。

    首先定义些许输入变量。

    3

    卷积核与池化面积定义了卷积网络如何处理图片挖掘特征。最小的卷积核可以是1X1,也就是我们认为关键特征只有1像素大小。比较典型的核尺寸有3像素,再将特征池化为2X2网格。

    2X2网格从图片中抽取特征,并像炉石卡组一样堆叠起来,这就把它们从原图的特定位置剥离了出来,以便让系统寻找各处的直线或圆圈,而不仅限于最早被发现的位置。

    很多教程将这一过程描述为处理“平移不变性”。

    什么是平移不变性?好问题。

    再看下面这张图:

    如层1和层2所示,系统并不是一下子就把特征的本质给抓出来了,而是可能觉得猫鼻子的圆圈只有在图像正中(第一次发现该圆圈处)时,才是重要特征。

    以我家Dove为例,如果系统最开始在她的眼睛上发现了一个圈,那么系统可能会错误的认为,这个圈在图中的位置与辨认猫也是相关的。而实际上,系统应该同等重视任何可能出现圆圈的地方:

    在给神经网络添加层之前,我们先载入并处理数据:

    4

    OK,现在我们终于准备好给神经网络添加一些层了:

    5

    神经网络中堆叠起来的层依次有:

    卷积

    激励

    卷积

    激励

    池化

    Dropout

    多数类型已经介绍过了,除了两个:dropout和激励。

    Dropout更容易理解些,本质上就是模型会按比例丢弃一些信息,就像Netflix的Chaos Monkey,它会按照脚本随机关闭一些服务节点以保证鲁棒性和荣誉度。这里也是一样道理,我们希望神经网络不要过度依赖于某一个特征。

    激励层就是决定神经元是否被“激活”的标准,可供选择的激励函数有很多,ReLU是其中最成功的一种,这得益于它较高的计算效率。这里有Keras中可选的不同激励函数列表。

    我们还添加了第二个卷积网络与第一个互成镜像,如果我们追求编程效率的话,可以创建一个模型生成器以循环叠加神经网络层。不过这里我们就简单地复制粘贴一下,为图个方便,其实是有违Python之禅的。

    最后,我们再添加一些全连接层,已经另一个Dropout层,再把所有特征映射扁平化:

    6

    在最后一层,我们使用了不同的激励函数:softmax,因为这定义了每个类的概率分布。

    预知以上代码究竟几个意思,且听下回分解。



沪ICP备19023445号-2号
友情链接