“AI”科普丨人工智能领域入门概述

“AI”科普丨人工智能领域入门概述
2024年03月28日 16:51 中国人工智能学会CAAI

转自 AI科技在线

AI 已经被炒得如火如荼,那么生活在这个快速变化时代的我们,不管你身处哪个行业,都不该置身事外,多多少少去了解一下,才不会和这个快速变化的时代格格不入,倍感孤独。开篇我提过两本书,如果你粗略翻看过,多少能理解个大概。为了让没有任何经验的外行能够快速的进入AI的神秘世界,今天就来好好讨论怎么开始,如何下嘴。

AI 是个很宽泛的东西,我们通常的理解,它包括机器学习,自然语言处理,视觉识别,涉及的学科如计算机科学,数学,认知学,心理学,社会学,哲学等,我们可以把一切关于计算模拟人脑思维或功能的模拟均可以认为是AI。可以看出 AI 不是一个孤立的学科领域,其实很好理解,人类智能的形成也是包含多方面的,要模拟人的智能,离不开各领域的研究。如此说来,想进入AI领域岂不是很难?这里讨论的只是AI中的某些领域,或许通过这一领域的学习,以点带面的去了解AI的全貌,或许是个比较切合实际的做法,在接下来的篇章中,各领域均会涉及,因为是入门级别的,所以浅尝则止,你可以选择你喜欢的领域去专研。

接下来把我们将要涉及的内容概述一下:

1)数据挖掘和分析:主要探讨数据的抓取,处理和分析

2)机器学习:主要探讨深度学习模型及应用

3)计算机视觉:主要介绍和视觉识别有关的库及其应用

4)自然语言分析:主要介绍自然语言的识别和合成,另外会涉及到情感分析的内容

5)深度学习算法:介绍几个常见的深度学习算法及应用

以上每一个分支都可以展开来讲,都可以作为一个独立的领域花一辈子去研究,但人生苦短,这里只是点到为止,尽可能地取其精华。

一、数据挖掘

数据挖掘就是指从数据中获取知识。

这样的定义方式比较抽象,但这也是业界认可度最高的一种解释了。对于如何开发一个大数据环境下完整的数据挖掘项目,业界至今仍没有统一的规范。说白了,大家都听说过大数据、数据挖掘等概念,在我们的商业社会里,每个人或组织的任何行为都会产生大量的数据,从表面上看这些数据是多么的繁杂无序,然而,这些数据的背后往往有某种潜在的逻辑,针对这些逻辑的挖掘探讨,往往可以发掘出非常有价值的东西。这个就是数据挖掘需要做的事情。

那么,数据挖掘通常的流程是怎么样的呢?从形式上来说,数据挖掘的开发流程是迭代式的。开发人员通过如下几个阶段对数据进行迭代式处理:

其中,

解读需求

绝大多数的数据挖掘工程都是针对具体领域的,因此数据挖掘工作人员不应该沉浸在自己的世界里YY算法模型,而应该多和具体领域的专家交流合作以正确的解读出项目需求。这种合作应当贯穿整个项目生命周期。

搜集数据

在大型公司,数据搜集大都是从其他业务系统数据库提取。很多时候我们是对数据进行抽样,在这种情况下必须理解数据的抽样过程是如何影响取样分布,以确保评估模型环节中用于训练(train)和检验(test)模型的数据来自同一个分布。

预处理数据

预处理数据可主要分为数据准备和数据归约两部分。其中前者包含了缺失值处理、异常值处理、归一化、平整化、时间序列加权等;而后者主要包含维度归约、值归约、以及案例归约。后面两篇博文将分别讲解数据准备和数据归约。

评估模型

确切来说,这一步就是在不同的模型之间做出选择,找到最优模型。很多人认为这一步是数据挖掘的全部,但显然这是以偏概全的,甚至绝大多数情况下这一步耗费的时间和精力在整个流程里是最少的。

解释模型

数据挖掘模型在大多数情况下是用来辅助决策的,人们显然不会根据"黑箱模型"来制定决策。如何针对具体环境对模型做出合理解释也是一项非常重要的任务。

二、机器学习

作为机器学习领域的先驱,Arthur Samuel在 IBM Journal of Research and Development期刊上发表了一篇名为《Some Studies in Machine Learning Using the Game of Checkers》的论文中,将机器学习非正式定义为:“在不直接针对问题进行编程的情况下,赋予计算机学习能力的一个研究领域。”

在机器学习的历史上,Arthur Samuel做了一些非常酷的事情。他曾经做了一个西洋棋程序,让计算机自己跟自己下棋,下棋速度非常快,因此Arthur Samuel让他的程序自己和自己下了成千上万盘棋,逐渐的,程序开始慢慢意识到怎样的局势能导致胜利,怎样的局势能导致失败,因此它反复的自己学习“如果让竞争对手的棋子占据了这些地方,那么我输的概率可能更大”或者“如果我的棋子占据了这些地方,那么我赢的概率可能更大”所以渐渐的,Arthur Samuel的程序掌握了哪些局面可能会输,哪些局面可能会赢,因此奇迹出现了,他的程序的棋艺甚至远远超过了他自己。ArthurSamuel让他的程序比他自己更会下棋,但是他并没有明确的教给程序具体应该怎么下,而是让它自学成材。

机器学习的类型有哪些呢?

监督学习

训练数据中,每个样本都带有正确答案。

个人理解,这种方式有正确答案的监督或者说参照,所以称为监督学习。就好像老师提供对错指示、告知最终答案的学习过程。

学习器从训练数据中学到正确答案的决策函数 y=f(x) 用于新的数据预测。

典型任务:预测数值型数据的回归、预测分类标签的分类、预测顺序的排列

应用:手写文字识别、声音处理、图像处理、垃圾邮件分类与拦截、网页检索、基因诊断、股票预测等。

无监督学习

训练数据中,每个样本都没有正确答案。

学习器自己在训练数据中找规律。就像在没有老师的情况下,学生自学的过程。所以称为无监督学习。

典型任务:聚类(相似点)、异常检测(异常点)。

应用:人造卫星故障诊断、视频分析、社交网站解析、声音信号解析、数据可视化、监督学习的前处理工具等。

半监督学习

训练数据中,少部分样本有正确答案。

学习器使用大量的没有正确答案的数据,以及同时使用有正确答案的数据,来进行模式识别工作。在有正确答案的样本帮助下,获得比只用无正确答案的样本得到的结果更好的学习效果,提高学习器的精度。是无监督学习和监督学习的结合,所以称为半监督学习。

典型任务:半监督分类,半监督回归,半监督聚类,半监督降维

强化学习

强化学习把学习看作试探评价过程,Agent选择一个动作用于环境,环境接受该动作后状态发生变化,同时产生一个强化信号(奖或惩)反馈给Agent,Agent根据强化信号和环境当前状态再选择下一个动作,选择的原则是使受到正强化(奖)的概率增大。选择的动作不仅影响立即强化值,而且影响环境下一时刻的状态及最终的强化值。

三、计算机视觉

通俗地讲,计算机视觉就是给机器赋予视觉的能力,比如装上摄像头,通过程序算法让机器通过摄像头获取的图像进行处理,模式识别,并达到理解的目的。这个比较好理解,现在我们身边就可以看到相关的应用,比如OCR技术,识别图像文字,人脸识别,指纹识别,这个很多智能手机已经内建了这些功能,而且趋于成熟。

计算机视觉学习过程中会用到不少现成的库,比如openCV, DLIB, Face++等等开源的库文件,在以后的篇幅中会详细讲解。

四、自然语言处理

一般来说,自然语言处理的目的是让机器能够执行人类所期望的某些语言功能自然语言处理是人工智能的终极发展目标,大概可以分为人类语言的处理(语言学)和机器语言的翻译.

其大致流程是语音识别与合成---语音分析、词法分析、句法分析、语义分析、语用分析

后面篇幅重点介绍第三方库的使用,实现简单的语音识别和合成,并初步涉略情感语义的分析模型。非常成熟的模型目前还没有,但这方面的研究非常的热,毕竟它是实现AI应用的很重要的一部分。

五、深度学习

深度学习,主要就是多层神经网络。而多层神经网络目前效果比较好的是卷积神经网络,目前在图像和音频信号上效果比较好,而在自然语言处理上效果没有显示出来。

深度学习从统计学的角度来说,就是在预测数据的分布,从数据中学得一个模型然后再通过这个模型去预测新的数据,这一点就要求测试数据和训练数据必须是同分布。

从Inception的角度上来看的话,其实深度学习是在模拟人脑的工作机制,但实际上,目前对于人脑的认知机制还不是很清楚,神经网络算法也只是简单模拟人脑而且,谈不上真正模拟。以下是神经网络的模型图:

定义一个深度学习模型,需要解决以下3个问题:

1)激活函数,也就是先对于输入神经元的激活值。一般的有 logistic 、tanh、以及ReLU。

2)代价函数。一般学习过程都是优化问题。代价函数一般采用欧式距离。

3)优化策略。最简单的用剃度下降。

根据剃度更新权重,进而减小代价函数。

由于多层神经网络通常模型很复杂,为此还需要解决过拟合问题,目前比较有效的是通过数据增广和dropout技术。

区别于一般的机器学习算法,深度学习更新是机器学习,之所以这么说是因为它能自动学习特征,不用人工定义特征,所以你可以不需要懂太多领域相关的知识,因为算法懂得自动学习特征。

好的,到现在为止,大家对AI涉及的这几个方面有了初步的印象,是不是很有趣,虽然有不少专业名词,听起来讳莫如深,不过不要担心,只需要你依然保持这个热情和好奇心,随我逐一展开,一起窥探AI的奥秘。

01

开发环境搭建

学习AI涉及到计算机编程,在正式进入相关主题学习之前,有必要了解一下用什么编程语言来实现。这里我大力推荐大家使用python,有句话说的好:“人生苦短,我用python”,为什么这么说呢,因为是python的特性决定的,python相对来说比较容易掌握,而且粘性强,可以方便的适应不同平台,另外有用不完的开源库可供选择,你省去了大量的开发时间,我们学习编程,目的就是快速应用,为我们的日常生活工作解决问题的,如果学习一门语言花掉我们大半生的经历,那又有什么意义呢?

毫无疑问,如果你没有任何编程经验,请你使用python吧,当然,如果你有其它编程经验,比如学过C或者JAVA,也无妨,转到python更是易如反掌。python就像是为数据分析,机器学习而生的,好的,先来看看如何配置python的开发环境。

开发环境的搭建大家可以参考网上资料,根据你所使用的平台选择,我在这里就不啰嗦了,相信大家会用度娘。这里可以提供一个参考链接:

https://www.cnblogs.com/EmptyFS/p/6184627.html

这里提醒一下,python的版本主要有2.7.6 和 3.5/3.6, 2 和3语法上有许多区别,建议你直接用3,当然,网上还有很多用旧版本写的例程,如果你想在3的环境下运行,需要做一些更改才行,为了不必要的麻烦,这里提到的例程均采用3以上的版本。如果你在搭建的时间遇到问题,可以留言。

开发环境搭建好之后,建议你抽空翻一下python入门的教程,至少懂得怎么运行一个hello world程序。可以参考网上教程:

http://www.runoob.com/python/python-tutorial.html

我估计你只要花一周,每天1个小时的时间过一遍这些内容,基本上就可以了,当然,想要进阶熟悉python编程,一周肯定是不够的,但不影响你对后面的学习,基础打好是便于你理解后面的一些代码,加上不断的练习,你一定可以边学边深入编程的精髓的,所以不用担心,也不要着急。

关于集成的开发环境IDE,这个我不作推荐,个人习惯问题,我自己一般采用windows下或者linux下的终端,运行程序或安装必需的包之类的,用Note

pad++编写程序代码,当然也可以用现在比较流行的jupyter notebook实现实时编程体验,非常直观(如下图),相关教程可以度娘,不在这里详述了。

接下来安装一些必要的第三方库,数据挖掘工作需要用到这些库,在正式开始第一个模块之前确保一下库已经安装:

1)numpy:Python科学计算的基础包。

2)scipy:是一组专门解决科学计算中各种标准问题域的包的集合。

3)matplotlib:是最流行的用于绘制数据图表的Python库。

4)pandas:主要提供快速便捷地处理结构化数据的大量数据结构和函数。

5)lxml – C语言编写高效HTML/ XML处理库。支持XPath。

6)BeautifulSoup – 低效HTML/ XML处理库,纯Python实现。

当然,以上是主要的,还有很多,碰到需要的时候再讲解。安装方法可以参考:

http://blog.csdn.net/github_35160620/article/details/52203682 这里有详细的介绍,也非常简单。

好的,到此为止,你基本完成了基础的搭建,接下来让python带我们飞,开启神奇之旅吧!

02

数据采集

谈到数据采集,我们说一切的真相的基础来自于数据,没有数据,一切盲目的下结论都是耍流氓。所以说数据的采集是多么的重要,后面我们要讲到的数据分析和挖掘,前提是要有数据,而且这个数据量越大越好,这也就是为什么大数据这么热的原因,有人比喻大数据是石油,谁掌握了大数据谁就掌握了资源,掌握未来的经济命脉。看看几大BAT就知道了,他们掌握着巨量的数据,包括现在很多的共享经济,主要目的就是收集用户数据,用户数据就是未来的金矿,有些人可能不太理解,不过没关系,知道一下就行了,只要明白数据的重要性就足够了。又扯远了。

话说回来,我们如何获取数据呢?当然获取数据的方式有很多,你可以去图书馆翻阅资料,也可以自己试验获取数据,然而很多情况是上网获取,不要忘了互联网这个宝库,今天的例程主要讲如何从网络获取数据,也就是编写一个简单的网络爬虫,帮助你自动获取你想要的数据。

编写网络爬虫有很多的方法,复杂程度也各异,考虑到大家还是初学者,今天的例子将会非常简单,所以说是小试牛刀嘛!

比如我想抓取新浪网页的科技新闻内容,用最简单的bs4库就可以轻松实现,以下是例程,运行这个例程前确保你已经安装了beautifulsoup4,安装方法很简单,打开cmd如下图:

在>头后面输入pip install BeautifulSoup4 就会自动安装了。

完整代码:

第一行from bs4 import BeautifulSoup 从BeautifulSoup库中导入bs4方法,python中导入第三方库的方式 import 库名,from xxx import xxx表示从第三方库中导入需要的方法或函数,不需要全部的方法,这样可以节省资源,上面提到的json是网络数据交互解析时需要的库,re是正侧表达式库,主要用于字符串匹配的包,两个库均属于python的标准库,requests库网页请求时需要的库,暂时大概知道这些库干嘛的就行,不必深究。

第10行requests.get(url)方法把整个网页内容获取并存入web_data变量,第11行用encoding()解析网页内容为utf-8格式,便于后续处理。第12行用bs方法提取文本,并存入soup列表,这个列表获取的是新闻标题链接。

下面的for循环就是分别把前面5条新闻打印输出。不出意外,你的窗口会输出以下内容:

恭喜你!你在自己的机子上运行了一个爬虫,是不是很酷

03

人脸识别的程序

上回讨论了一下数据收集的一点皮毛,今天我们尝试一下人脸识别吧,利用你计算机的摄像头,或者USB即插即用的外置摄像头也行。看完今天的教程,你一定也能做出一个人脸识别的程序来,而且用不了多少代码,好了,开工吧。

在正式写代码之前,确保你的计算机安装了openCV,openCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。

和之前安装第三方库一样,在终端下输入以下命令:

pip install opencv-python

等安装好了输入>import cv2 as cv 测试一下,如果没有出现错误提示,而是换行出现>>>,说明安装成功了。好的接下来我测试输入几行代码测试一下openCV, 你可以在jupyter notebook上面运行或者用其它你喜欢的IDE都可以,建议你先使用notepad++ 或者editplug专门的代码编辑器。这两个工具均可以免费下载使用。

测试代码:

确保d:\python\文件夹中含有test.jpg测试图片,代码写好之后保存到一个目录下面,比如d:\python文件夹中,保存文件名为test1.py, 当然你可以自己建一个文件夹用于存放代码。然后在命令终端进入到这个文件夹,然后用以下命令运行python脚本。

d:\python\ python test1.py 回车运行脚本。

如果不出意外,程序运行完会出现测试图片窗口。

简单解释一下上面的脚本:

第一行带#号的是注释,解释代码用的,便于程序的阅读和理解

第二行导入我们开始安装的opencv库

第四行用cv的一个.imread()方法读取一张外部图片并存入img变量

第六行用namedWindow()方法定义一个叫Image的窗口

第七行用imshow()方法把图片img通过叫Image的窗口来显示

第八行.waitKey()方法接受键盘输入,0表示任意键输入

最后一行.destroyAllWindows()方法销毁所有显示的窗体,也就是说当检测到键盘输入后,窗体关闭。也就是退出程序了。是不是很好理解,至于那些方法怎来的,你不用太细究,这些方法都是cv2模块定义好的,直接拿来用就行了。以下是我机子上测试的效果,显示一张企鹅图:

到此为止,你已经离梦想又进了一步,呵呵。

接下来,我们试试怎么调用摄像头来获取视频或图像,这个为接下来的人脸识别打下基础:

例程已经有非常详细的注解了,我就不另外说明。获取摄像头视频是不是也很简单?不到15行的代码。好了离我们的目标又进了一步,接下来怎么识别图像中的人脸呢?

要识别出人脸,必须下载haar特征分类器,如果你是直接从openCV官网下载并单独安装的话,可以在opencv目录里面找到分类器,我机子上的目录是C:\opencv\sources\data\haarcascades

下载OpenCV中的Haar特征分类器,你可以从Opencv官网下载源程序解压后获得Haar特征分类器,也可以直接下载所需的xml文件。我建议你从官网下载,解压后可以找到haar目录,下面程序目录记住相应做更改。

完整代码如下,多了几行代码,但还是很简洁的:

运行效果如图:

是不是没有你想象的这么复杂呢?当然,我们借助了好几个库,所有直接调用了一些方法,只要我们知道怎么使用这些方法就行。真正不需要你敲多少代码。保留你的好奇心,后面还有更有意思的应用等着你,我们将在后面学习了语言合成之后,让计算机真正识别出你是谁,而不只是圈出视频中的脸而已。

04

爬取动态页面数据

今天我们将实战一下,如果抓取动态页面的内容,这些内容的抓取比较麻烦一些,需要分析网站源文件才行,Javascript 脚本写的页面,我们需要利用chrome里面的开发者工具,来找到真正的信息链接,并找到页面内容加载的逻辑才行。

比例商品评论信息是我们关注的,举一个京东上的商品例子,就拿我们的产品Jabra elite sport这个产品的用户评论练手。

首先用chrome浏览器打开京东,找到这个产品,产品页面如下:

再选择评论,你会发现网络页面主题是不变的,只是动态的显示商品评论在特定区域,并且一次显示10个评论,总共有效评论有100页。

我们在选择其它其中一个页面,比如第二页,你会发现地址栏是不变的,说明这个评论信息是JS脚本动态加载的,这时我们就需要利用开发者工具进行分析找到真正的链接地址。开发者工具可以按图找到:

打开工具后,选择其中两页评论,刷新页面后,工具会重新载入详细的信息,具体如下:

分别点击‘name’栏里的‘productPageComments...’ 分析两个页面的header里面的url地址,

第一页的url:

https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv1008&productId=5308806&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&rid=0&fold=1

第二页的url:

https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv1008&productId=5308806&score=0&sortType=5&page=1&pageSize=10&isShadowSku=0&rid=0&fold=1

两者的区别就是‘page=’后面的数字,第一页是0第二页是1。我们再看看是否评论就在这个链接的页面里加载的,切换到‘preview’查看具体脚本:

红色框起来的就是页面显示的十条评论,没有问题,所以就是它了。找到确切的url地址就好办了。接下来上代码:

为了便于维护代码,把商品名,对应实际的url地址,页码总数等信息放到excel表格中,可以随时添加修改,上面代码包含了excel文件读取操作,可以适用于大部分商品的评论数据抓取。抓取后的数据包含评论ID,分数,时间,内容,设备等内容并自动存入CSV格式的文档,便于后续的数据分析处理。

程序运行后,按照提示输入excel文件名,商品行数,然后自动运行,根据数据量大小,需要抓取的时间也不同。以下是实例运行的情况:

这里说明一下:为了避免json请求操作过于频繁,招致京东服务器限制,甚至封堵IP,同时作为有道德的数据采集者,理应遵行一定的规则,所以设置间隔时间,time.sleep(), 10~15的随机间隔时间。

好了到此为止,你在数据挖掘的路上又近了一步,后续课程将对爬取得数据进行分析处理。

05

简单数据分析词云图

今天的课程讲一下简单的数据分析,词云图,当然数据分析远不止做一个词云图,这里只是从简单的开始,你会惊讶于python的强大。做出漂亮的词云图非常简单。

词云图,能直观的展示词汇的使用频率,频度越高,显示的越大,可以了解关注度情况。在数据分析和挖掘方面有一定用途,也是比较常见的一个方法。

生成词云需要用到WordCloud库,这个安装和其它库的安装一样,很简单,这里不再赘述。先导入需要的库文件。

结巴清洗库jieba主要用于生产词云前对文本文件进行清洗,把一些没有意义的词剔除。matplotlib是数据可视化常用的库,pickle是python语言的一个标准模块,安装python后已包含pickle库,不需要单独再安装。pickle模块实现了基本的数据序列化和反序列化。通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储;通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。

序列化的方法为 pickle.dump(),该方法的相关参数如下:

pickle.dump(obj, file, protocol=None,*,fix_imports=True)

该方法实现的是将序列化后的对象obj以二进制形式写入文件file中,进行保存。它的功能等同于 Pickler(file, protocol).dump(obj)。关于参数file,有一点需要注意,必须是以二进制的形式进行操作(写入)。

创建词云函数wordCloud(), 带三个参数,便于用户自定义输入:文本文件,背景图片和颜色,确保文件在同一目录下。还是以Jabra耳机的客户评论数据来做例子,前面课程已经从网站上抓取出来了。

函数定义好之后,就可以调用了:

测试一下效果,还算不错:

06

人脸识别

前面讲的人脸识别,其实谈不上真正识别,只是识别是不是人脸,然后标注出来,在现实中我们更希望机器识别出谁来,而不仅仅把脸标注出来,今天这个例子就是教你怎么识别出你是谁。

好的,要识别出人脸并标注出身份,必然需要解决一个问题,就是数据比对问题,至少要告诉机器某个人的特征,通过学习之后,机器就可以通过算法识别出图像或摄像头看到的人是谁。

这次引入一个新的库,叫face_recognition, 这个库属于第三方库,也需要安装,很简单,和之前介绍的方法一样直接安装就行了。

直接上代码,我这里用了几位同事的大头照片作为测试,呵呵。

上面代码主要就是建立人脸的特征模型,用于后面的识别对比,当然你可以根据需要建立这个特征数据库,或者可以调用外部数据,便于代码维护和可拓展性。

然后通过摄像头获取图像,并进行比对识别。应该很好理解,我就不展开解释了。

运行的效果如下:

07

卷积神经网络VGGNet

深度学习因其强大的特征表示和特征学习,可以显著提高机器学习算法的效果。与基本的机器学习算法不同,深度学习算法自动学习到特征的表示方法,不需要人工参与特征的提取,深度学习算法在语音、图像和文本方面得到广泛的应用。

深度学习里面比较流行的如卷积神经网络(CNN),在解释什么是卷积神经网络之前,先了解一下什么是神经网络。

传统的神经网络

一个神经网络最简单的结构包括输入层、隐含层和输出层,每一层网络有多个神经元,上一层的神经元通过激活函数映射到下一层神经元,每个神经元之间有相对应的权值,输出即为我们的分类类别。

其对应的公式如下:

其中,该单元也可以被称作是Logistic回归模型。当将多个单元组合起来并具有分层结构时,就形成了神经网络模型。下图展示了一个具有一个隐含层的神经网络。

其对应的公式如下:

比较类似的,可以拓展到有2,3,4,5,…个隐含层。神经网络的训练方法也同Logistic类似,不过由于其多层性,还需要利用链式求导法则对隐含层的节点进行求导,即梯度下降+链式求导法则,专业名称为反向传播,关于算法在机器学习相关资料中参考,这里不详细介绍。

卷积神经网络CNN

卷积神经网络与普通神经网络的区别在于,卷积神经网络包含了一个由卷积层和子采样层构成的特征抽取器。在卷积神经网络的卷积层中,一个神经元只与部分邻层神经元连接。在CNN的一个卷积层中,通常包含若干个特征平面(featureMap),每个特征平面由一些矩形排列的的神经元组成,同一特征平面的神经元共享权值,这里共享的权值就是卷积核。卷积核一般以随机小数矩阵的形式初始化,在网络的训练过程中卷积核将学习得到合理的权值。共享权值(卷积核)带来的直接好处是减少网络各层之间的连接,同时又降低了过拟合的风险。子采样也叫做池化(pooling),通常有均值子采样(mean pooling)和最大值子采样(max pooling)两种形式。子采样可以看作一种特殊的卷积过程。卷积和子采样大大简化了模型复杂度,减少了模型的参数。卷积神经网络的基本结构如图所示:

卷积神经网络由三部分构成。

第一部分是输入层。

第二部分由n个卷积层和池化层的组合组成。

第三部分由一个全连结的多层感知机分类器构成。

局部感受野

卷积神经网络有两种神器可以降低参数数目,第一种神器叫做局部感知野。一般认为人对外界的认知是从局部到全局的,而图像的空间联系也是局部的像素联系较为紧密,而距离较远的像素相关性则较弱。因而,每个神经元其实没有必要对全局图像进行感知,只需要对局部进行感知,然后在更高层将局部的信息综合起来就得到了全局的信息。网络部分连通的思想,也是受启发于生物学里面的视觉系统结构。视觉皮层的神经元就是局部接受信息的(即这些神经元只响应某些特定区域的刺激)。如下图所示:左图为全连接,右图为局部连接。

在上右图中,假如每个神经元只和10×10个像素值相连,那么权值数据为1000000×100个参数,减少为原来的万分之一。而那10×10个像素值对应的10×10个参数,其实就相当于卷积操作。

权值共享

但其实这样的话参数仍然过多,那么就启动第二级神器,即权值共享。在上面的局部连接中,每个神经元都对应100个参数,一共1000000个神经元,如果这1000000个神经元的100个参数都是相等的,那么参数数目就变为100了。

怎么理解权值共享呢?我们可以这100个参数(也就是卷积操作)看成是提取特征的方式,该方式与位置无关。这其中隐含的原理则是:图像的一部分的统计特性与其他部分是一样的。这也意味着我们在这一部分学习的特征也能用在另一部分上,所以对于这个图像上的所有位置,我们都能使用同样的学习特征。

更直观一些,当从一个大尺寸图像中随机选取一小块,比如说 8x8 作为样本,并且从这个小块样本中学习到了一些特征,这时我们可以把从这个 8x8 样本中学习到的特征作为探测器,应用到这个图像的任意地方中去。特别是,我们可以用从 8x8 样本中所学习到的特征跟原本的大尺寸图像作卷积,从而对这个大尺寸图像上的任一位置获得一个不同特征的激活值。

如下图所示,展示了一个3×3的卷积核在5×5的图像上做卷积的过程。每个卷积都是一种特征提取方式,就像一个筛子,将图像中符合条件(激活值越大越符合条件)的部分筛选出来。

多卷积核

上面所述只有100个参数时,表明只有1个10*10的卷积核,显然,特征提取是不充分的,我们可以添加多个卷积核,比如32个卷积核,可以学习32种特征。在有多个卷积核时,如下图所示:

上图右,不同颜色表明不同的卷积核。每个卷积核都会将图像生成为另一幅图像。比如两个卷积核就可以将生成两幅图像,这两幅图像可以看做是一张图像的不同的通道。如下图所示,下图有个小错误,即将w1改为w0,w2改为w1即可。下文中仍以w1和w2称呼它们。

下图展示了在四个通道上的卷积操作,有两个卷积核,生成两个通道。其中需要注意的是,四个通道上每个通道对应一个卷积核,先将w2忽略,只看w1,那么在w1的某位置(i,j)处的值,是由四个通道上(i,j)处的卷积结果相加然后再取激活函数值得到的。

所以,在上图由4个通道卷积得到2个通道的过程中,参数的数目为4×2×2×2个,其中4表示4个通道,第一个2表示生成2个通道,最后的2×2表示卷积核大小。

Down-pooling

在通过卷积获得了特征 (features) 之后,下一步我们希望利用这些特征去做分类。理论上讲,人们可以用所有提取得到的特征去训练分类器,例如 softmax 分类器,但这样做面临计算量的挑战。例如:对于一个 96X96 像素的图像,假设我们已经学习得到了400个定义在8X8输入上的特征,每一个特征和图像卷积都会得到一个 (96 − 8 + 1) × (96 − 8 + 1) = 7921 维的卷积特征,由于有 400 个特征,所以每个样例 (example) 都会得到一个 7921 × 400 = 3,168,400 维的卷积特征向量。学习一个拥有超过 3 百万特征输入的分类器十分不便,并且容易出现过拟合 (over-fitting)。

为了解决这个问题,首先回忆一下,我们之所以决定使用卷积后的特征是因为图像具有一种“静态性”的属性,这也就意味着在一个图像区域有用的特征极有可能在另一个区域同样适用。因此,为了描述大的图像,一个很自然的想法就是对不同位置的特征进行聚合统计,例如,人们可以计算图像一个区域上的某个特定特征的平均值 (或最大值)。这些概要统计特征不仅具有低得多的维度 (相比使用所有提取得到的特征),同时还会改善结果(不容易过拟合)。这种聚合的操作就叫做池化 (pooling),有时也称为平均池化或者最大池化 (取决于计算池化的方法)。

子采样有两种形式,一种是均值子采样(mean-pooling),一种是最大值子采样(max-pooling)。两种子采样看成特殊的卷积过程,如图下图所示:

(1)均值子采样的卷积核中每个权重都是0.25,卷积核在原图inputX上的滑动的步长为2。均值子采样的效果相当于把原图模糊缩减至原来的1/4。

(2)最大值子采样的卷积核中各权重值中只有一个为1,其余均为0,卷积核中为1的位置对应inputX被卷积核覆盖部分值最大的位置。卷积核在原图inputX上的滑动步长为2。最大值子采样的效果是把原图缩减至原来的1/4,并保留每个2*2区域的最强输入。

至此,卷积神经网络的基本结构和原理已经阐述完毕。

多卷积层

在实际应用中,往往使用多层卷积,然后再使用全连接层进行训练,多层卷积的目的是一层卷积学到的特征往往是局部的,层数越高,学到的特征就越全局化。

卷积神经网络的训练

本文的主要目的是介绍CNN参数在使用BP算法时该怎么训练,毕竟CNN中有卷积层和下采样层,虽然和MLP的bp算法本质上相同,但形式上还是有些区别的,很显然在完成CNN反向传播前了解bp算法是必须的。

Forward前向传播

前向过程的卷积为典型valid的卷积过程,即卷积核kernalW覆盖在输入图inputX上,对应位置求积再求和得到一个值并赋给输出图OutputY对应的位置。每次卷积核在inputX上移动一个位置,从上到下从左到右交叠覆盖一遍之后得到输出矩阵outputY(如图4.1与图4.3所示)。如果卷积核的输入图inputX为Mx*Nx大小,卷积核为Mw*Nw大小,那么输出图Y为(Mx-Mw+1)*(Nx-Nw+1)大小。

BackForward反向传播

在错误信号反向传播过程中,先按照神经网络的错误反传方式得到尾部分类器中各神经元的错误信号,然后错误信号由分类器向前面的特征抽取器传播。错误信号从子采样层的特征图(subFeatureMap)往前面卷积层的特征图(featureMap)传播要通过一次full卷积过程来完成。这里的卷积和上一节卷积的略有区别。如果卷积核kernalW的长度为Mw*Mw的方阵,那么subFeatureMap的错误信号矩阵Q_err需要上下左右各拓展Mw-1行或列,与此同时卷积核自身旋转180度。subFeatureMap的错误信号矩阵P_err等于featureMap的误差矩阵Q_err卷积旋转180度的卷积核W_rot180。

下图错误信号矩阵Q_err中的A,它的产生是P中左上2*2小方块导致的,该2*2的小方块的对A的责任正好可以用卷积核W表示,错误信号A通过卷积核将错误信号加权传递到与错误信号量为A的神经元所相连的神经元a、b、d、e中,所以在下图中的P_err左上角的2*2位置错误值包含A、2A、3A、4A。同理,我们可以论证错误信号B、C、D的反向传播过程。综上所述,错误信号反向传播过程可以用下图中的卷积过程表示。

权值更新过程中的卷积

卷积神经网络中卷积层的权重更新过程本质是卷积核的更新过程。由神经网络的权重修改策略我们知道一条连接权重的更新量为该条连接的前层神经元的兴奋输出乘以后层神经元的输入错误信号,卷积核的更新也是按照这个规律来进行。

在前向卷积过程中,卷积核的每个元素(链接权重)被使用过四次,所以卷积核每个元素的产生四个更新量。把前向卷积过程当做切割小图进行多个神经网络训练过程,我们得到四个4*1的神经网络的前层兴奋输入和后层输入错误信号,如图所示。

根据神经网络的权重修改策略,我们可以算出如图所示卷积核的更新量W_delta。权重更新量W_delta可由P_out和Q_err卷积得到,如图下图所示。

VGGNet

该模型是Karen Simonyan和 Andrew Zisserman提出的卷积神经网络,并获得ILSVRC 2014的第二名,现在称其为VGGNet。它主要的贡献是展示出网络的深度是算法优良性能的关键部分。他们最好的网络包含了16个卷积/全连接层。网络的结构非常一致,从头到尾全部使用的是3x3的卷积和2x2的汇聚。他们的预训练模型是可以在网络上获得并在Caffe中使用的。VGGNet不好的一点是它耗费更多计算资源,并且使用了更多的参数,导致更多的内存占用(140M)。其中绝大多数的参数都是来自于第一个全连接层。后来发现这些全连接层即使被去除,对于性能也没有什么影响,这样就显著降低了参数数量。

目前使用比较多的网络结构主要有ResNet(152-1000层),GooleNet(22层),VGGNet(19层)。大多数模型都是基于这几个模型上改进,采用新的优化算法,多模型融合等。

08

CNN手写字识别

手写字识别基于MNIST数字库,可以说是图像识别领域的“hello world!”,它是Google实验室的Corrina Cortes和纽约大学柯朗研究所的Yann LeCun联合创建的手写数字数据库,每个样本数据是一张28x28像素的灰度手写数字图片,每张图片对应一个数字,训练库有60000张手写数字图像,测试库有10000张。如果你已经安装了tensorflow,这个库就已经在文件夹了,可以直接调用。

上图简单描述了识别过程

接下来我们就来构建基于CNN网络来识别手写数字,看看效果如何。如果你不是很了解CNN,你可以阅读上一期关于卷积神经网络的介绍,不然理解下面代码可能存在问题。

先来为卷积神经网络构建一个叫CNN()的类:

当定义好卷积神经网络类CNN的初始化函数后,我们需要在卷积神经网络类中定义卷积神经网络CNN的训练过程,其具体的训练过程如下:

以上构建一个fit函数用于对卷积神经网络模型进行训练,在如上的卷积神经网络中,包含了三个卷积层和下采样层。当构建完整个卷积神经网络模型后,将卷积神经网络模型的对数据的预测值与样本的真实标签之间的交叉熵作为最终的损失函数,并求损失函数中的最小值。

接下来,我们来训练CNN模型,用构建好的类,对MNIST手写体识别的数据集进行训练。

程序运行时,由于电脑配置原因,运行完成需要一点时间,深度学习考验机器性能,卷积神经网络实际上是对经典神经网络的优化,减少了计算量而不显著牺牲精确度的深度学习模型,通过稀疏连接,共享权值,池化来简化计算的过程。如果不做卷积处理,运算时间可能需要好几倍,以下是训练过程:

可以看到训练到第6步时可以达到0.9892水平了,一般到最后在验证集上的准确率可以达到0.99以上,对于测试集,最终也可以达到0.99以上。

09

计算机视觉openCV

闲话少说,直接进入正题,当然,这个进阶实战前提是你已经配置好了python的openCV环境,以下代码运行在python3.6环境,所以确保你的系统配置好编程环境。建议你安装jupyter notebook,代码输入效率高。

例程-1通过matplotlib在图像上绘制图形:

可以看到图像上绘制了一条直线。在图像处理方面,matplotlib提供了很多方法,当然,openCV本身也有很好的处理方法。

例程-2 加载视频图像

不过需要注意的是,如果例程在jupyternotebook 中运行,视频输出是黑色的,这个有点奇怪,但是在终端运行正常。

例程-3 录制并保持视频片段

是不是非常简单,openCV提供了丰富的函数实现你需要的结果。

例程-4 openCV图形绘制函数实现图形绘制

以上例程通过openCV的绘图函数实现图像上绘制各种图形,适用于不同的源,比如视频流。

例程-5 图像像素操作

[255255 255]

[[[129138 135]

[129 138 135]

[129 138 135]

...,

[ 37 39 39]

[ 37 39 39]

[ 36 38 38]]

[[129 138 135]

[129 138 135]

[129 138 135]

...,

[ 35 37 37]

[ 34 36 36]

[ 33 35 35]]

[[128 137 134]

[128 137 134]

[128 137 134]

...,

[ 32 34 34]

[ 31 33 33]

[ 29 31 31]]

...,

[[130 141 139]

[130 141 139]

[129 140 138]

...,

[ 96 104 133]

[ 97 107 137]

[ 93 104 134]]

[[130 141 139]

[130 141 139]

[130 141 139]

...,

[ 97 108 136]

[ 98 109 141]

[ 94 107 139]]

[[130 141 139]

[130 141 139]

[129 140 138]

...,

[ 97 107 137]

[100 111 143]

[ 98 111 143]]]

(652,536, 3)

1048416

uint8

以上例程是对图像进行操作,实现特定区域的像素修改,剪切,移动操作

例程-6 相同大小的图像叠加操作

以上例程实现两张图片进行叠加操作,发现类似过曝的情况,这是因为图像的像素RGB值有一个范围0-255,超过255的均为白色显示。

例程-7 依然是图像叠加操作,对以上例程修改设置适当权重

通过设置权重,叠加后的图像正常显示了。

例程-8 大小不同的图像叠加

在大的图像上叠加另一个小一点的图像,并且以透视的方式叠加,这里需要用到阈值的概念,先看看效果。要注意的是,叠加操作确保图像的格式一致性。

在图像上叠加了python的logo,以透视的方式叠加,也就是说logo背景如果是白色的,透明显示。

例程-9 继续讨论阈值(threshold(THRESH_BINARY))

当我们需要对一张曝光很差的图像进行处理以便阅读时,这个阈值就很有效果。当然,上面这个效果还是不好,没有达到我们希望的结果,不着急。

例程-10 调整阈值,去除颜色

阅读性好了很多,但是还有大片区域黑乎乎的。

例程-11 自适应阈值

自适应阈值的使用对于文本的处理还是很好的,可阅读性好了很多,当然,最后效果和图像本身的清晰度有很大关系。本例中算是取得了比较好的效果。

例程-12 大津阈值

本例中大津阈值并没有取得很好的效果。

例程-13 颜色过滤

例程对红色部分过滤的效果。帽子部分有些缺失。这只是一个例子,以红色为目标。它的工作方式是,我们所看到的是图像范围内的任何东西,基本上是30-255,150-255和50-180.它用于红色,但可以随便尝试找到自己的颜色。HSV在这里效果最好的原因是,我们想要范围内的颜色,这里通常需要相似的颜色。很多时候,经典的红色仍然会有一些绿色和蓝色分量,所以必须允许一些绿色和蓝色,但是我们会想要几乎全红。这意味着我们会在这里获得所有颜色的低光混合。

为了确定HSV的范围,最好的方法就是试错。OpenCV内置了将BGR转换为HSV的方法。如果你想挑选单一颜色,那么BGR到HSV将会很好用。为了理解,下面是这个代码的一个例子:

Dark_red=np.uint8([[[12,22,121]]])

Dark_red=cv2.cvtColor(Dark_red,cv2.COLOR_BGR2HSV)

这里的结果是一个HSV值,与Dark_red值相同。但是,同样你遇到了颜色范围和HSV范围的基本问题,他们根本不同。你可能合理使用BGR范围,他们仍然可以工作,但是对于检测一种颜色,则无法正常工作。

回到上面例程,我们首先要把帧转换成HSV。那里没有什么特别的。接下来,为红色指定一些HSV值。使用inRange函数,为我们的特定范围创建掩码。这是真或假,黑色或白色。接下来,通过执行按位操作来恢复我们的红色,基本上,我们显示了capand mask。掩码的白色部分是红色范围,被转换为纯白色,而其他一切都变成黑色。最好我们展示所以东西。在下面例程中,我们将对图像中存在的一些噪音,比如那些颗粒感的黑点,进行处理,就需要运用到模糊和平滑来解决这个问题。

例程-14 模糊和平滑

在这个例程中,将介绍如何尝试从我们的过滤器中消除噪声,例如简单的阈值,或者使用以前特定的过滤器:

这里使用了一个简单的平滑,计算每个像素块的均值。使用15x15的正方形,意味着我们有225个总像素,进行平均化处理得到上面的效果。但是牺牲了很多粒度,接下来我们尝试一些高斯模糊:

例程-15 高斯模糊和中值模糊

例程-16 双向模糊

通过对比,选择效果较好的那个,这取决于图像本身,可能不同的模糊类型适合不同的情况。

例程-17 形态转换-腐蚀和膨胀

有些时候需要对图像进行变换操作,先介绍腐蚀和膨胀。腐蚀是对边缘操作,它的工作方式是使用滑块(核)。我们让滑块滑动,如果所有的像素是白色的,那么我们得到白色,否则是黑色。这可能有助于消除一些白色噪音。另外是膨胀,它基本上是起相反的作用,让滑块滑动,如果整个区域不是黑色的,就会转换成白色。

例程-18 形态转换-开放和关闭

开放的目标是消除假阳性。有时候在背景中,你会得到一些像素噪音。关闭的想法是消除假阴性,基本上用于检测形状,例如我么的帽子,但是物体仍然有些黑色像素。关闭将尝试清除它们。

接下来将讨论边缘检测和渐变。图像渐变可以用来测量方向的强度,边缘检测可以用来查找边缘。

首先我们来看渐变的例子:

例程-19 渐变

cv2.CV_64F是数据类型,ksize是核大小,我们使用5,所以每次查询5x5的区域。虽然可以使用这些渐变转换为纯边缘,但是也可以使用Canny边缘检测。

例程-20 边缘检测

边缘检测效果不错,本例中背景比较杂乱。

模板匹配

在下一个章节讨论模板匹配,介绍如何在其他图像中搜索和查找相同的图像模板,这个将非常有用处,尤其在特征匹配的时候。

模板匹配用于对象识别。给出一定的阈值,找到匹配我们提供的模板图像的相同区域。对于具体的对象匹配,具有精确的照明/刻度/角度的图像会表现的很好。通常会遇到这些情况的例子就是计算机上的任何GUI。按钮等东西总是相同的,所以你可以使用模板匹配,结合模板匹配和一些鼠标控制,你就可以实现一个基本web的机器人。

首先你需要一个主要图像和一个模板。你应该从你正在图像中查找的东西选取你的模板。主要图像:

匹配模板,通过这个模板看看能在主图中识别出多少来。

例程-21 模板匹配

加载两个图像,转换成灰度。保留原始的RGB图像,并创建一个灰度版本。加载模板图像并且记下尺寸。在这里用img_gray,模板和我们要使用的匹配方法调用matchTemplate并将返回值保存到res。指定一个阈值这里先试用80%匹配度,然后我们使用逻辑语句找到res大于或等于阈值的位置。最后使用灰度图像中找到的坐标标记原始图像上的所有匹配。

看来遗漏不少,再试试阈值0.5,大部分标识出来了,右边几个因为视角的问题,和模板差距较大,需要更大的容错才能识别出来,但是很难避免假阳性的问题,所以要精确识别,图像最好要有好的辨识度才行。

再调低阈值0.4

虽然找到所有的,但是出现大量假阳性,并且出现重复查找的现象。可以继续调整直到100%找到,另外一种方式就是使用另一个模板图像。有时候使用相同对象的对各图像是有用的,这样你可以使阈值足够高来确保你的结果准确。

10

openCV实战篇

上一节介绍了关于openCV的一些基本内容,虽然不多,但是多少可以感受到它的强大,先抛出一个openCV的有意思的应用,不需要加载额外太多的库,就可以实现,所以你不妨可以自己试试,你会发现,隔空操作实现起来其实并不难。好的,直接上代码,后面再讲解实现的原理。

代码大部分都有解释,看起来很多,其实去掉注释,不到60行,可谓短小精悍。这里稍微多解释一点关于cv2.findContours() 方法,这个函数是用来查找物体轮廓的,需要注意的是cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图,也就是前面提到的cv2.threshold(), 加上cv2.THRESH_OTSU. 我们举一个例子来说明。

以上就是使用不同过滤器之后的效果,你会发现高斯后使用Otsu阈值过滤得到的效果非常好,轮廓清晰。

再举例说明cv2.findContours()函数。

原图是:

应用查找后:

函数的原型cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]]) 返回两个值:contours:hierarchy。

参数

第一个参数是寻找轮廓的图像;

第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):

cv2.RETR_EXTERNAL表示只检测外轮廓

cv2.RETR_LIST检测的轮廓不建立等级关系

cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。

cv2.RETR_TREE建立一个等级树结构的轮廓。

第三个参数method为轮廓的近似办法

cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1

cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息

cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

返回值

cv2.findContours()函数返回两个值,一个是轮廓本身,还有一个是每条轮廓对应的属性。

通过上述讲解,你应该熟悉了这几个函数的用法,你可以尝试一下在其它方面的应用。好的,我们来看看例程实现的效果:

当然,结果可能没有这么理想,这和你所处的环境有关,你可以尝试通过图像优化来实现手势识别的准确性。

【免责声明】本公众号发布的内容仅供学习交流使用,内容版权归原作者所有。如有侵犯您的权益,请及时与我们联系,我们将于第一时间删除内容。内容为作者个人观点,不代表本公众号立场和对其真实性负责。

财经自媒体联盟更多自媒体作者

新浪首页 语音播报 相关新闻 返回顶部