人工智能基础教程

人工智能基础教程-龙跃AI
人工智能基础教程
此内容为付费阅读,请付费后查看
510
付费阅读

第一章人工智能的发展

这是一个快速发展的时代。身处这个时代洪流中的人们,无论是襁褓之中呱呱坠地的孩童,还是社区里颐养天年的耄耋老者,每一个普通个体都能感受到生活的便利和舒适。在这一切美好变迁的背后,是一场正在深刻改变我们生活与社会的科技浪潮——人工智能。 人工智能是通过机器来模拟人类认知能力的技术。人工智能涉及很广,涵盖了感知、学习、推理与决策等方面的能力。从实际应用的角度说,人工智能最核心的能力就是根据给定的输入做出判断或预测。 例如,在人脸识别应用中,它是根据输入的照片,判断照片中的人是谁。在语音识别中,它可以根据人说话的音频信号,判断说话的内容。在医疗诊断中,它可以根据输入的医疗影像图像,划分出异常区域,判断疾病的成因和性质。在电子商务网站中,它可以根据一个用户浏览和购买记录,预测该用户对什么商品感兴趣,并作出相应的推荐,提升企业销售额。在金融应用中,它可以根据一只股票过去的价格和交易信息,预测它未来的价格走势。在围棋对弈中,它可以根据当前的盘面形势,选择胜率最大的落子策略。 9f012875fa20b34d50abd0bed3800247jpg-1

#1.人工智能的发展介绍

人工智能能有如今广阔的应用,它的发展并非一帆风顺,20世纪四五十年代,数学家和计算机工程师就已经开始探讨使用机器模拟智能的可能。1950年,Alan Turing 在他的论文《计算机器与智能》中提出了著名的图灵测试。 2c9dfcdba2a5c5c943cb7aee4afdc34ejpg 在图灵测试中,一位人类测试员会通过文字与密室里的一台机器和一个人自由对话。如果测试员无法分辨与之对话的两个实体谁是人谁是机器,则参与对话的机器就被认为通过测试。虽然图灵测试的科学性受到过质疑,但是它在过去数十年一直被广泛认为是测试机器智能的重要标准,对人工智能的发展产生了极为深远的影响。 1951年夏天,当时普林斯顿大学数学系的一位24岁的研究生,Marvin Minsky建立了世界上第1个神经网络机器,SANARC(Stochastic Neural Analog Reinforcement Calculator)。在这个只有40个神经元的小网络里,人们第1次模拟了神经信号的传递,这项开创性的工作为人工智能奠定了深远的基础,Minsky由于它在人工智能领域的一系列奠基性的贡献,在1969年获得计算机科学领域的最高奖图灵奖。 daec6547c849b6f836b83b226bde2afdjpg 1955年,Allen Newell、Herbert Simon 和 Cliff Shaw 建立了一个名为“逻辑理论家”的计算机程序来模拟人类解决问题的技能。这个程序成功证明了一部大学数学教科书里面52个定理中的38个,甚至还找到了比教科书里更优美的证明,这项工作开创了一种日后被广泛应用的方法:搜索推理。 1956年,Minsky、John McCarthy、Claude Shannon 和 Nathan Rochester在美国的达特茅斯学院组织了一次讨论会。会议中提出:“学习和智能的每一个方面都能被精确的描述,使得人们可以制造一台机器来模拟它。” 这次会议为这个致力于通过机器来模拟人类智能的新领域定下了名字——“人工智能”Artificial Intelligence AI,从而正式宣告了人工智能作为一门学科的诞生。

#1.1人工智能的第一次浪潮(1956-1974)

人工智能的诞生震动了全世界,人们第1次看到了智慧通过机器产生的可能。当时有人乐观地预测,一台完全智能的机器将在20年内诞生。虽然到现在我们还没有完成这样的目标, 但是它的诞生所点燃的热情确实为这个新生领域的发展注入了无穷的活力。 1963年,当时刚成立的美国高等研究计划局( ARPA)投入了两百万美元给麻省理工学院,开启了新项目 Project MAC(The Project on Mathematics and Computation)。不久后,当时最著名的人工智能科学家闵斯基和麦卡锡加入了这个项目,并推动了在视觉和语言理解等领域的一系列研究。Project MAC 培养了一大批最早期的计算机科学和人工智能人才,对这些领域的发展产生了非常深远的影响。这个项目也是现在赫赫有名的麻省理工学院计算机科学与人工智能实验室(MIT CSAIL)的前身。 ba9a316b8192e0809047c2a343f70a08jpg

在巨大的热情和投资的驱动下,一系列新成果在这个时期应运而生。麻省理工学院的约瑟夫·维森鲍姆(Joseph Weizenbaum )教授在 1964 年到 1966 年间建立了世界上第一个自然语言对话程序 ELIZA。 ELIZA通过简单的模式匹配和对话规则与人聊天。虽然从今天的眼光来看这个对话程序显得有点简陋,但是当它第一次展露在世人面前的时候,确实令世人惊叹。日本早稻田大学也在 1967 年到 1972 年间发明了世界上第一个人形机器人,它不仅能对话,还能在视觉系统的引导下在室内走动和抓取物体。

期望越高,失望越大。虽然人工智能领域在诞生之初的成果层出不穷,但还是难以满足社会对这个领域不切实际的期待。由于先驱科学家们的乐观估计一直无法实现,从70 年代开始,对人工智能的批评越来越多。在领域内,百花齐放的背后各种问题也逐步显露出来。一方面,有限的计算能力和快速增长的计算需求之间形成了尖锐的矛盾;另一方面,视觉和自然语言理解中巨大的可变性与模糊性等问题在当时的条件下构成了难以逾越的障碍。随着公众热情的消退和投资的大幅度削减,人工智能在 70 年代中期进入了第一个冬天。

#1.2第二次浪潮(1980-1987):专家系统的兴衰

进入 80 年代,由于专家系统(expert system)和人工神经网络(artificial neural network)等技术的新进展,人工智能的浪潮再度兴起。 f396c3eb9e973cb5403fcc655bde4c9cjpg 专家系统是一种基于一组特定规则来回答特定领域问题的程序系统。早在20世纪60年代,爱德华·费根鲍姆(Edward Feigenbaum)已经开始了对专家系统的早期研究。他因此被称为“专家系统之父”。在70年代,斯坦福大学的科学家们开发了一套名为 MYCIN 的系统,它可以基于 600 条人工编写的规则来诊断血液中的感染。到了1980 年,卡耐基梅隆大学为迪吉多公司(DEC)开发了一套名为 XCON的专家系统,它可以帮助迪吉多公司根据客户需求自动选择计算机部件的组合。这套系统当时每年可以为迪吉多公司节省 4000 万美元。XCON 的巨大商业价值极大激发了工业界对人工智能尤其是专家系统的热情。 此外,专家系统的成功也逐步改变了人工智能发展的方向。科学家们开始专注于通过智能系统来解决具体领域的实际问题,尽管这和他们建立通用智能的初衷并不完全一致。 与此同时,人工神经网络的研究也取得了重要进展。1982年,约翰·霍普菲尔德(John Hopfield)提出了一种新型的网络形式,即霍普菲尔德神经网络(Hopfield net),在其中引人了相联存储(associative memory)的机制。1986 年,大卫·鲁梅尔哈特(David Rumelhart)、杰弗里·辛顿(Geoffrey Hinton)和罗纳德·威廉姆斯(Ronald Williams)联合发表了有里程碑意义的经典论文:《通过误差反向传播学习表示》(Learning representations by back-propagating errors)。在这篇论文中,他们通过实验展示,反向传播算法(backpropagation)可以在神经网络的隐藏层中学习到对输入数据的有效表达。从此,反向传播算法被广泛用于人工神经网络的训练。 055f9619569b3048ba888b92505302fdjpg 在新一次人工智能浪潮兴起的同时,日本通商产业省在1982 年雄心勃勃地开始了旨在建造“第五代计算机”的大型研究计划。这个计划的目标是通过大规模的并行计算来达到类似超级计算机的性能并为未来的人工智能发展提供平台。遗憾的是,经过了10 年研发,耗费了500 亿日元,这个项目未能达成预期的目标。 运用专家系统的缺陷也很明显,泛化推广能力弱,输入到数据库中的信息才能输出,数据库中没有的,它就束手无策了,而让计算机长知识的手段只能是人类专家更新数据库。 到了80 年代后期,产业界对专家系统的巨大投入和过高期望开始显现出负面的效果。人们发现这类系统开发与维护的成本高昂,而商业价值有限。在失望情绪的影响下,对人工智能的投人被大幅度削减,人工智能的发展再度步入冬天。

#1.3第三次浪潮(2011 年至今)现代人工智能的兴起

时间到了 90 年代,历经潮起潮落的人工智能已经发展了40多年。虽然年轻时气吞天下的雄心遭遇了挫折,但这个领域也变得愈发坚韧。科学家们放下了不切实际的目标,开始专注于发展能解决具体问题的智能技术。 在这段时期里,研究人工智能的学者开始引人不同学科的数学工具,比如高等代数、概率统计与优化理论,这为人工智能打造了更坚实的数学基础。数学语言的广泛运用,打开了人工智能和其他学科交流合作的渠道,也使得成果能得到更为严谨的检验。在数学的驱动下,一大批新的数学模型和算法被发展起来,比如,统计学习理论( statistical learning theory)、支持向量机(support vector machine)、概率图模型(probabilistic graphical model)等。新发展的智能算法被逐步应用于解决实际问题,比如安防监控、语音识别、网页搜索、购物推荐、自动化算法交易等等。 7c21560ccfa0e0ccd641f0956d8736f7jpg 新算法在具体场景的成功应用,让科学家们看到了人工智能再度兴起的曙光。进入了21 世纪,全球化的加速以及互联网的蓬勃发展带来全球范围电子数据的爆炸性增长。人类迈入了“大数据”时代。与此同时,电脑芯片的计算能力持续高速增长。当前一块NVIDIA Tesla V100 图形处理器的计算能力已经突破了每秒 10 万亿次浮点运算,超过了 2001 年全球最快的超级计算机。 c86a0f34c66c9b7004dac16a61369d30jpg 在数据和计算能力指数式增长的支持下,人工智能算法也取得了重大突破。在2012年一次全球范围的图像识别算法竞赛ILSVRC(也称为 Image Net 挑战赛)中,多伦多大学开发的一个多层神经网络 Alex Net 取得了冠军,并大幅度超越了使用传统机器学习算法的第二名。这次比赛的成果在人工智能学界引起了广泛的震动。从此,以多层神经网络为基础的深度学习被推广到多个应用领域,在语音识别、图像分析、视频理解等诸多领域取得成功。2016年,谷歌(Google)通过深度学习训练的阿尔法狗(AlphaGo)程序在一场举世瞩目的比赛中以4 比1 战胜了曾经的围棋世界冠军李世石。它的改进版更在 2017 年战胜了当时世界排名第一的中国棋手柯洁。 006a994c5d703c86b853376f2caf5ed3jpg 这一系列让世人震惊的成就再一次点燃了全世界对人工智能的热情。世界各国政府和商业机构都纷纷把人工智能列为未来发展战略的重要部分。由此,人工智能的发展迎来了第三次热潮。 随着硬件的发展以及国家之间的科技布局,世界人工智能的发展已进入到快车道,人工智能的应用将渗透到我们生活的方方面面,我们也会感受到科技带来的便捷。

#2.人工智能的其他应用

安防领域:通过人工智能算法实时从视频中检测出行人和车辆,自动找到视频中的异常行为,如醉酒的行人和逆行的车辆,未佩戴口罩的个人,自动判断人群密度和人流的方向,提前发现过密人群带来的潜在风险,帮助工作人员引导和管理人流。 69f19f498e04d87d81de996af3a5be52jpg 医疗领域:人工智能在医疗中的应用为解决“看病难”的问题提供了新的思路。目前,世界各国的诸多研究机构都投入很大的力量开发对医学影像进行自动分析的技术。这些技术可以自动找到医学影像中的重点部位,并进行对比分析。人工智能分析的结果可以为医生诊断提供参考信息,从而有效地减少误诊或者漏诊。除此以外,有些新技术还能通过多张医疗影像重建出人体内器官的三维模型,帮助医生设计手术,确保手术更加精准。随着智能医疗技术的进步,我们相信人工智能不仅能为医生提供更直接更精准的诊断和治疗建议,而且可以为我们每个人提供健康建议和疾病风险预警,从而让我们生活得更加健康。 7e746bc7e4aa1b94b7476f1c7b71f418jpg 工业制造领域:我国是工业大国,随着各种产品的快速迭代以及现代人对于定制化产品的强烈需求,工业制造系统必须变得更加“聪明”,而人工智能则是提升工业制造系统的最强动力。比如,品质监控是生产过程中的重要环节,一个质量不过关的零件如果流向市场,不仅会使消费体验大打折扣。更有可能导致严重的安全事故。因此传统生产线上都安排大量的检测工人用肉眼进行质量检测。这种人工检测方式不仅容易漏检和误判,更会给质检工人造成疲劳伤害。因此很多工业产品公司开发使用人工智能的视觉工具,帮助工厂自动检测出形态各异的缺陷。 2011年汉诺威工业博览会(Hannover Messe)上,德国提出了工业4.0概念,其中最重要的就是在工业环境中使用大量的传感器采集海量的数据。人工智能则成为分析这些海量数据并从中挖掘有价值信息的强大武器。西门子(Siemens)和通用电气(GE)等工业巨头纷纷开发了人工智能系统,用来预测生产环节的风险、降低材料浪费和能源消耗,并同时提升生产效率。 5669504ddb59cbda58d813ee080187fbjpg

#3.总结

人工智能的功能越来越强大,同时也影响我们生活的方方面面,现在,让我们一起走近人工智能,更深入地理解其运行逻辑,感受它的魅力。首先了解一些机器学习的基础知识,随后基于主流框架之一TensorFlow来感受实际的开发过程。

第二章软件安装语环境配置

1.Anaconda安装

Conda是一个开源的包、环境管理器,可以用于在同一个机器上安装不同版本的软件包及其依赖,并能够在不同的环境之间切换。Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。 该版本为免费个人版,适合于个人从业者、学生和研究人员。 官网下载软件:Anaconda | Individual Edition (opens new window)下载对应版本的安装包。这里演示Windows_64版本软件的安装。 双击安装包,开始安装: ac4202ebba8288f277b06b391bf8b880 bb9a30b6c09c561cd5b4c0253530524d fedf735af7c34353c21812e0e3873ddd da75846af1e32f4af2f7aadacb70a1a4 设置安装目录: 61c946220d54a718cfce0fc668a9be1f c4fe442eda3a9692e263727bd60b7147 d59f542177107ebeb806a5d0ee7f6ef9 b2bf28f7982f3616aede0febe6eeb697 52cc510c0262af8fff60f704fcd86782 完成Anaconda的安装。 762e039d31b419a7b45c3c39b60b72cf 2e58c1afa61d7fb723f72ef6516e43e2 32d0e9aa777eea5c965cc487bb012748 输入:(注意,tensorflow2是个人创建的环境名称,因人而异)

conda activate tensorflow2
1

98e0e426ddd3154d485e172717538bae#1.1安装机器学习包(sklearn)

输入:

pip install sklearn
1

#1.2安装TensorFlow

348a26c61343f6ce228788f526e9ce66 50e442893bc3e10badd685da82cd09a6 a5036ce0e475a5f73e879f45cecf767f 3efc7a64be6941704dc1371ff27c0da6

#2.PyCharm安装

#2.1下载软件

下载地址:下载 PyCharm community (opens new window)06d62187b2656da6bb99ac38073f2403 双击下载的应用文件 pycharm-community-2021.2.exebe820bf3dc0346bfa5755472639b61dd d013850e4347b1688656b44088a56496 0f5957b853a708e7b5066da96c190f0d 56f0a96a4287ae3dcc2acd16e0f79d51 b0749ff6621613d3b770c2391e943b90 fb2f209b97d049a003dc103e73e3563a  完成安装,双击桌面的快捷图标,开始汉化以及配置环境。 a98a2868ab573a85eae852ca653e2d70

#2.2汉化PyCharm

f0eb54b4f1a9d7988b934289a2805f8c#2.3配置PyCharm环境

创建项目,或者打开现有项目,设置项目的编译配置,如下图,请按顺序操作。 502eb90b802b7e2bd59d4143dbb3cc92 ce67a6cd6f36c3ec6582657df8dba702 882a61921f5cc2213f0ac4788da0a1bb 输入测试代码,测试安装配置是否成功:

import tensorflow as tf

print(tf.__version__)
1
2
3

9050c9ed3031135987123afef4f53330 至此,TensorFlow环境配置完成。

第三章简单的线性实例

1.人工智能与机器学习

人工智能是一个很庞大的研究领域,虽然人们对于人工智能相关的理论研究和算法开发达到了一定高度,迄今为止我们掌握的能力仍然非常有限。人工智能的范畴包括机器学习,机器学习是研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。机器学习是人工智能的核心组成部分,它是使计算机具有智能的根本途径,其应用遍及人工智能的各个领域。深度学习是机器学习中的一个研究方向,深度学习通过多层处理,逐渐将初始的“低层”特征表示转化为“高层”特征表示后,用“简单模型”即可完成复杂的分类等学习任务。

#2.机器学习中的深度学习

深度学习(deep learning)是机器学习的分支,是一种以人工神经网络为架构,对资料进行特征学习的算法。这里解释一下特征学习,特征学习是学习一个特征的技术的集合:将原始数据转换成为能够被机器学习来有效开发的一种形式。它避免了手动提取特征的麻烦,允许计算机学习使用特征的同时,也学习如何提取特征。简而言之,就是学习如何学习。 深度学习的好处是低成本高效率的获取信息特征。至今已有数种深度学习框架,如深度神经网络、卷积神经网络和深度置信网络和循环神经网络已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

#3.走近人工智能

每年的英语四六级考试成绩总能牵动一些小伙伴的心情,如果请你判断小飞同学的成绩是否合格,那么应该难不倒你,因为我们很清楚其中的判断逻辑,分数大于等于425分就合格,424分就“杯具”了。若是让你来完成这一段代码,你会怎么做呢? d6f13ed3b3e67f9eee2b5c7491f7f88ajpg 如果你稍有编程基础,一定难不倒你。几个条件判断搭配使用,轻轻松松完成任务。下一题: 如果让你读出下列图片中的数字,即使有个别数字比较扭曲但仍然难不倒你,可是,如果我们的任务是让计算机把这些数字辨别出来,可能就不那么轻松了。 d3ee0bab13cc11930fa37d7d6f0015bcjpg 一个比较好的思路是,制作0~9的数字图像模板,把每一张手写数字图片的像素值与模板进行匹配,把最接近模板数值的那个数字作为输出。这是传统思路,用深度学习的方法可以提升识别精度哦。 场景三,你能不能判断出女朋友说的“没事”是真没事还是在生气呢?如果你的判断非常准确,请问是如何做到的呢?是经验丰富还是天赋异禀呢? fa369e34332493272274836a2391d735jpg 假如我们的任务是让计算机完成类似人类的情绪判断任务,可行吗?如果你有任何编码的经验,就会明白这是很困难的事,可能得写成千上万条代码才能做到,那么有没有一种方法教会电脑自己来判别呢?这便是机器学习,也是迈向AI的途径。 我们从一个简单的线性实例出发,逐步迈向人工智能。请观察以下数字:

X = 1234567
Y = 2468101214
1
2

这些数字当中的各个X值,它们和Y值之间存在着一种关系,你能找出其中的规律吗? 很简单,Y = 2X 你是怎么得出这个规律的呢? 你可能注意到当X = 1时,Y 是 X 的 2 倍,再看看第二组,X = 2时,Y = 4,现在很可能就是 Y = 2X 的关系,我们想验证一下猜想,于是又看了X = 3,4,5,6,7时 Y 的对应值是否和我们的猜测吻合,发现是的,于是我们得出 Y = 2X 的规律。这样的思考过程正是所有机器学习运算的方式。下面,我们用机器学习的思路去实现这一过程。

#4.代码讲解

8ab7dd42db08dc41a8e3f7d69a5f075bjpg 很复杂?别害怕,你会掌握的。 我们先了解一下上述任务的机器学习模型需要哪些组成部分。

#4.1数据部分

首先是数据,数据包括输入数据(X)以及对应的标签(Y),这里数据和标签是一起交给计算机进行学习的。 77ccd5c3d8565d00842541c03c142d4ejpg

#4.2模型部分

再来是网络模型构造,我们需要根据任务挑选不同的模型进行学习,例如线性模型Y=kX + b ,或者复杂的神经网络模型。 0c90af32de120e2cfb902007141a4868jpg

#4.3损失函数和优化器

训练时,模型会以损失函数来衡量猜测结果的准度 146619fac5df49055ca5d262bed2d395jpg 你也许是第一次听说它们,我们的任务是让机器找到解决问题的规则,机器并不知道数据与标签之间有什么关系,所以它必须要做一个猜测,然后查看数据,对猜测结果进行评估。 损失函数是一种评估猜测结果优劣程度的方法。 31d8810670afe1469170d611a5b9a5fdjpg 优化器会基于损失函数反馈的结果进行下一轮猜测,然后再次使用损失函数来评估猜测结果。 其中的逻辑是,优化器可以提高猜测准确度,数据被传递给优化器进行下一轮猜测,以此类推,这就是神经网络的训练过程。(这里我们用的优化器是SGD随机梯度下降法,损失函数用的是MSE均方误差)

#4.4训练模型

1d56d0688dc25c97ffbc35efdac2b372jpg 训练时,以X值和Y值相互适配,并循环500次,训练结束后,我们就得到了一个机器自己推断出来的公式,它就隐含在模型之中。

#4.5评价模型

c7b1aba7942c50774d9252a7828c9d56jpg 我们对模型输入8,期待它能给出16的反馈结果。输出的结果很接近16,但还不到16,为什么会这样? 这是因为计算机接受的训练是匹配这7组数字,而这7组数字间似乎存在一种线性关系,但这7组数字之外的其他值,直线关系未必成立,直线关系的可能性很大,但我们仍不能确定,而这样的可能性考量已融入预测模型中,所以得出的值会非常接近16,但可能不会恰好等于16。 在这个简单的样例中,大致的训练流程如图所示,让计算机通过已有的数据信息主动习得数据的内在规律。我们利用优化器和损失函数等各种手段,让计算机习得的规律更贴近理想状态。 74fd9abdbbbb01d04e1a2021d37bcaa5jpg

#5.小结

传统的编码模式,是程序员写好规则,有输入就有预定的输出。机器学习呢,是程序员写好框架,让机器学习到一个比较好的规则,能够对数据输出靠谱的结果。可能在这个例子中,感觉机器学习也不过如此,其实在很多复杂的问题上机器学习往往能发挥出极大的使用价值。 57a21200a3fa8c008305b022cca694cbjpg 在本课程的学习中,我们将采用TensorFlow框架,在TensorFlow框架下构建机器学习流程,让我们一起来学习吧。

#完整代码:

import tensorflow as tf
import numpy as np
from tensorflow import keras
model = tf.keras.Sequential([keras.layers.Dense(units=1, input_shape=[1])])
model.compile(optimizer='sgd', loss='mean_squared_error')
xs = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], dtype=float)
ys = np.array([2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14], dtype=float)
model.fit(xs, ys, epochs=500)
print(model.predict([8.0]))
1
2
3
4
5
6
7
8
9

#6.课堂练习

1、还记得人工智能的层次结构吗,左右两边哪个图标识的是正确的?不记得了就再看看本文吧。 8ede703e7d03235656308ebf22b21a8ajpg 2、“优化器的功能是——评测网络模型的优劣程度”,这样的说法正确吗?如果不正确,请你补充说明优化器的作用。

第四章房价预测案例

1.简单的线性案例——房价预测

在本节课中,我们将再次熟悉机器学习的线性模型,利用TensorFlow框架搭建网络模型,掌握建立模型的方法,逐步实现网络的预测功能。在此基础之上,我们将接触更高维度的特征输入,学会在众多的输入信息中寻找到有效的区分维度,从而提升预测效果。先来看一个单一维度的简单案例。 486077c97c0f54d2449e34fd1c296869jpg

想象一下,如果房子的定价很简单,带一间卧室的房子价格是5万+5万,那么一间卧室的房子要花10万元;两间卧室的房子就要花15万元,如此类推。 如何创建一个神经网络,来学习这种关系,让它会预测一个7间卧室的房子,价格接近40万。让我们开始吧。

#1.1代码讲解

导入使用到的库:

import tensorflow as tf
import numpy as np
from rensorflow import keras
1
2
3

准备好数据:

data = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], dtype=float)
labels = np.array([1.0, 1.5, 2.0, 2.5, 3.0, 3.5], dtype=float)
1
2

构建网络模型:

model = tf.keras.Sequential([keras.layers.Dense(units=1, input_shape=[1])])
model.compile(optimizer='sgd', loss='mean_squared_error')
1
2

训练模型:

model.fit(data, labels, epochs=1000)
1

预测模型:

print(model.predict([7.0]))
1

#1.2完整代码

import tensorflow as tf
import numpy as np
from tensorflow import keras

data = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], dtype=float)
labels = np.array([1.0, 1.5, 2.0, 2.5, 3.0, 3.5], dtype=float)

model = tf.keras.Sequential([keras.layers.Dense(units=1, input_shape=[1])])
model.compile(optimizer='sgd', loss='mean_squared_error')
model.fit(data, labels, epochs=1000)
print(model.predict([7.0]))
1
2
3
4
5
6
7
8
9
10
11

#2.波士顿房价预测(多维度)

81c038a0e3741835111f68c8cfbdded5jpg 下面来看一个真实的案例,波士顿房价分析。波士顿房价数据集包括506条样本数据,每条样本数据均包含13个特征变量以及该地区的平均房价。 之前简化的例子房价只和卧室数目有关,卧室越多房价越高。波士顿案例中的房价更为复杂,它有13个相关变量如下表所示: ba4dfb4f4088adf98592288bd0b8c796jpg 上表中 MEDV 对应上个单卧室房价预测的标签值,前面的13个指标对应着卧室数量。波士顿房价预测和之前卧室预测房价的差异你看出来了吗? 影响房价的因素数量变多了,在这个案例中,我们有13个影响因素(特征维度),现在我们让计算机去学习这些数据,看看效果怎么样。

#2.1代码讲解

#2.1.1数据准备

导入相关库文件:

import tensorflow as tf
import numpy as np
import sklearn.datasets as datasets
from tensorflow import keras
1
2
3
4

读取波士顿房价数据:

data = datasets.load_boston()
1

最终的价格作为标签数据,将特征变量和标签数据分开读取:

x_data = data.data			#特征数据
x_labels = data.target		#标签数据
1
2

#2.1.2模型构造

创建网络模型,units = 1 表示设置1个神经元,这里的13对应的是13个特征变量输入。想一想,之前的input_shape数值是多少? 如果我们得到的特征变量更多或更少,这里的input_shape也要相应地做出变化。

model = tf.keras.Sequential([tf.keras.layers.Dense(units=1,input_shape=[13])])
1

接下来设置优化器,还记得优化器是做什么的吗? 回顾一下,优化器是构建模型参数的策略,优化器会在现有模型的基础上对参数进行优化,使得模型的预测结果更加准确。它通常和损失函数搭配使用。 设置优化器,采用随机梯度下降法(SGD),学习率设为0.000001

optimizer = tf.keras.optimizers.SGD(
    learning_rate=0.000001,  nesterov=False
)
1
2
3

构建损失函数:

model2.compile(optimizer, loss='mean_squared_error')
1

#2.1.3训练模型

model2.fit(x_data,x_labels,epochs=300)
1

#2.1.4评估模型

训练结束后接下来应该做模型预测评估,但我们的数据集数量较少,在数据准备阶段并没有对数据集进行分割,因此在本节中不进行模型评估。在后面的章节中会有这个步骤。好奇心旺盛的伙伴可以在学习了后续课程后,再来看看这个案例,通过改动模型提升模型的预测能力。

#2.2完整代码

import tensorflow as tf
import numpy as np
import sklearn.datasets as datasets
from tensorflow import keras

#读取数据
data = datasets.load_boston()  #载入数据集
x_data = data.data			#特征数据
x_labels = data.target		#标签数据

model = tf.keras.Sequential([keras.layers.Dense(units=1, input_shape=[1])])
model.compile(optimizer='sgd', loss='mean_squared_error')
model2 = tf.keras.Sequential([tf.keras.layers.Dense(units=1,input_shape=[13])])
optimizer = tf.keras.optimizers.SGD(
    learning_rate=0.000001, momentum=0.0001, nesterov=False
)

model2.compile(optimizer, loss='mean_squared_error')
model2.fit(x_data,x_labels,epochs=300)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#3.补充阅读

特征(feature):可以对事物的某些方面的特点进行刻画的数字或者属性。它是所有人工智能系统中非常重要的概念。对于同样的事物我们可以提取出不同的特征,比如上述第一个样例的卧室个数,比如第二个样例的13个不同维度指标,它们都是特征。但高质量的特征对分类器的准确性会起到很大的影响。我们要根据事物本身具备的特点设计出最有效的特征。 特征向量:把一个事物的特征数值组织在一起,可以形成特征向量。比如第二个样例中的13个数,我们把13个特征的数值拼在一条数据中,那么这条数据形成的向量就称为特征向量。 396310d2cfe5aa9ade36ab9ee74c1b1djpg 特征点:特征向量化表示后,每一个样本数据均可视为一个特征点。如上图的特征向量即为一个特征点。 特征空间:所有特征点构成的空间称之为特征空间。在第二个样例中,506个样本形成的13维度空间分布,即为房价预测模型的特征空间。

目标:把特征向量在特征空间中进行分类。

第五章鸢尾花分类实例

我们在之前的课程中学习了线性模型的搭建和训练,它们的训练数据呈现出这样的特点:一组特征对应一个标签。例如一个卧室的房子卖10万,波士顿房子在13个因素的影响下给出了房屋报价。在实际的场景中,我们的数据集可能没有如此完整的对应关系,可能我们只有卧室的数量,而其他的信息不完整。针对数据不全或标注成本高昂的情景,这节课介绍一种新的方法,无监督学习。我们利用鸢尾花的数据集进行训练,人为制造无标签数据进行演示,一起来学习吧。

#1.鸢尾花问题背景

鸢尾花数据集可不是无名之辈,它是由大名鼎鼎的费舍(Ronald Fisher)提出,1890年出生于英国伦敦,是著名的统计学家和遗传学家。也是他发明了最大似然估计和方差分析!鸢尾花数据集最初由Edgar Anderson 测量得到,而后费舍于1936年发表的文章《The use of multiple measurements in taxonomic problems》中被使用,用其作为线性判别分析(Linear Discriminant Analysis)的一个例子,证明分类的统计方法,从此而被众人所知,尤其是在机器学习这个领域。 6cc8579e4e9845fd74c9cb40edd44e24jpg 鸢尾花分类是一个经典的机器学习样例,鸢尾花数据集包含花朵四个维度的信息,分别是花瓣、花萼的长度和宽度测量的记录。这个数据集一共包括150条记录,每一条记录对应一种鸢尾花,鸢尾花共有三个类别,分别是:山鸢尾(Serosa)、变色鸢尾(Versicolor)和维吉尼亚鸢尾(Virginica),每个类别都有50条记录。 61b4c4eb4bd77c514c9fcaf1e7b0a033jpg 我们的任务是,将采集好的鸢尾花数据,利用机器学习方法,分成三类。我们来看看原始数据是什么样的: a85f1ed6bcb2a68cc4d15311aca382bcjpg 山鸢尾Serosa对应类别号:0;变色鸢尾Versicolor对应:1;维吉尼亚鸢尾Virginica对应:2

#2.代码示例(线性模型)

导入必要的库

import numpy as np
import tensorflow as tf
from sklearn import datasets
1
2
3

#2.1数据准备

x_train = datasets.load_iris().data
x_label = datasets.load_iris().target
1
2

#2.2设置模型

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(3, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2())
    ])
1
2
3

设置损失函数和优化器

model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False)
              )
1
2
3

#2.3训练模型

model.fit(x_train, x_label,  epochs=300, validation_split=0.2, validation_freq=20)
1

至此,模型已训练完成,我们来测试下效果。这是计算机没有见过的一条数据:[5.1, 3.5, 1.4, 0.2] ,根据该数据的花瓣和花萼的长宽,它的类别属于山鸢尾,类别号为0 。

#2.4测试评估

mydata = np.array([[5.1,3.6,1.31,0.4]])
print(model.predict(mydata))
1
2

#2.5完整代码示例(线性模型)

import numpy as np
import tensorflow as tf
from sklearn import datasets

 
x_train = datasets.load_iris().data
x_label = datasets.load_iris().target

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(3, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2())
    ])
 
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1),
              loss=tf.keras.losses.SparseCategoricalCrossentropy()
              )
model.fit(x_train, x_label,  epochs=300, validation_split=0.2, validation_freq=20)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

预测时会打印3个分类的概率,每个概率分别对应分类编号0、1、2,得分最高的那一类即为模型预测的分类。

#3.无监督学习

现实生活中常常会有这样的问题:缺乏足够的先验知识,因此难以人工标注类别或进行人工类别标注的成本太高。很自然地,我们希望计算机能代我们完成这些工作,或至少提供一些帮助。根据类别未知(没有被标记)的训练样本解决模式识别中的各种问题,称之为无监督学习。 现在如果我们只有三类花朵的各种尺寸,缺乏标签数据,可以利用某种手段达到分类目的吗?答案是肯定的,我们用到了无监督学习的技巧,无监督学习目标不是告诉计算机怎么做,而是让它(计算机)自己去学习怎样做事情。

#4.代码示例(无监督)

引入必要的机器学习库文件

from sklearn import datasets
import pandas as pd
from sklearn.mixture import GaussianMixture
from sklearn.metrics import calinski_harabasz_score
1
2
3
4

数据准备,这里的数据是源自sklearn库,可直接加载,加载方法如下:

ds = datasets.load_iris()
df_ds = pd.DataFrame(ds.data, columns=ds.feature_names)
1
2

使用的分类模型为高斯混合模型,使用最大期望算法 (Expectation Maximization Algorithm)进行迭代:

gmm = GaussianMixture(n_components=3)
1

其中的n_components参数可以简单理解为将样本分为3个类别。 这里简要介绍下最大期望算法(简称:EM),它用于表明给定具有缺失数据的参数估计问题,EM算法可以通过生成对丢失数据的可能猜测来迭代地解决该问题,然后通过使用这些猜测来最大化观察的可能性。 迭代训练模型:

gmm.fit(df_ds)
1

在训练过程中,模型的停止迭代阈值默认值为0.001,可以理解为当模型训练到满足默认要求的时候自动退出计算,默认计算次数为100次,如果计算了100次仍然没有触发自动终止的条件,那么模型也会退出计算,返回最后一次的计算结果。 预测模型:

label=gmm.predict(df_ds)
1

这里我们用的预测数据与训练数据相同,之所以可以这么用,是因为在训练的过程中我们没有为数据打标签,就是说我们没有告诉计算机每条数据对应的是什么种类的花。

#完整代码实现(无监督)

from sklearn import datasets
import pandas as pd
from sklearn.mixture import GaussianMixture
from sklearn.metrics import calinski_harabasz_score

ds = datasets.load_iris()
df_ds = pd.DataFrame(ds.data, columns=ds.feature_names)

gmm = GaussianMixture(n_components=3)
gmm.fit(df_ds)
label=gmm.predict(df_ds)
print("准确率:{:.2%}".format(len(label[label==ds.target])/len(label)))
print("得分:{:}".format(calinski_harabasz_score(df_ds, label)))
1
2
3
4
5
6
7
8
9
10
11
12
13

绘图查看:

import matplotlib.pyplot as plt
plt.scatter([i for i in range(len(ds.target))], ds.target, color='black', marker='v')
plt.scatter([i for i in range(len(label))], label, color='red', marker='.')
plt.yticks([0, 1, 2])
plt.xlabel('samples')
plt.ylabel('category')
plt.legend(['actual', 'predict'])
plt.savefig('predict.jpg', dpi=800)
1
2
3
4
5
6
7
8

你得到了什么样的预测图呢?是33%、67%、96%,亦或是0%的正确率?都有可能。 3e4d36d6e3bd2d6aec39c43be752a158jpg 上图红色的点是模型预测的类别,黑色的点是花朵真实类别,当红色和黑色部分重叠时说明预测正确。我们看一下右侧预测正确率为零的图,模型完全预测错了,为什么会发生这样的情况?是不是我们训练失败了?不是哦,因为我们采用的是无监督学习,计算机没有看过样本的分类,它根据数据的特点把数据分成了三类,但是对应关系计算机不知道,所以在最极端的情况下,会出现右图中完全错分的情况。

#5.拓展阅读

无监督学习有很多应用场景,比如它可以发现异常行为,比如人们可以对金融市场的操作行为进行分类,虽然开始的时候我们并不知道计算机分出的类别代表什么含义,但人们拿到一类的数据稍加分析就能得出结论,一些违规的操作会被区分出来,甄别起来就容易了很多。 60a21e355fef3197e4124683879977e5jpg 第二个应用场景是推荐系统,商家总会根据你的浏览行为推荐一些相关的商品,有些商品就是无监督学习通过聚类来推荐出来的。系统会发现一些购买行为相似的用户,推荐这类用户最“喜欢”的商品。 3c152166a096689bd82bcc2ff9fd8473jpg 第三个应用场景是构建用户画像,我们不仅把用户按照性别、年龄、地理位置等维度进行用户细分,还可以通过用户行为对用户进行分类,全方位地挖掘用户行为特征,也许大数据比客户更了解自己,这项技术能减少广告投放以及营销策略的成本。

第六章图片分类

之前的课程我们熟悉了用TensorFlow对简单数据进行线性预测,现在我们尝试利用新模型对图片完成分类预测。我们开始吧。请问下图片中你看到了几只鞋? 3830b1dcc93c7bfc73ad59196fac6181jpg 2只对吗?你是怎么知道它们是鞋子的? 想象一下,如果一个人他从未见过鞋子,我们怎样教会他识别鞋子?尽管高跟鞋和平底鞋外表很不一样,但它们都是鞋子,有共同的特征。 也许他会认为:红色的就是鞋子,因为他看到的就这两只,还都是红色的。当然并非如此简单,但你是怎么知道它们是鞋子的。因为你在生活中见到过许多鞋子。 73e8891793104d14e92fa22eb51a8825jpg 而你也明白了鞋子的特质,所以遵循这样的逻辑,如果我们向计算机展示很多鞋子,那么它就能够学会识别鞋子。大量优秀的数据能够为计算机提供“长见识”的机会。接下来我们将训练一个能够识别图片分类的神经网络模型,过程中我们使用Fashion-MNIST数据集。

#1.Fashion-MNIST 数据集

Fashion-MNIST是由德国电商平台(Zalando)发布的数据集。数据集中包含了10个类别的图像,分别是:T恤、牛仔裤、套衫、裙子、外套、凉鞋、衬衫、运动鞋、包、短靴。 d84258839bde7521599845c37b7c2ca9jpg 他有70000张图片,分属10个类别,每个类别有7000张图片,也就是说我们可以让计算机学习7000张鞋子,我们希望它在观察7000只鞋子之后可以认出一张它没有见过的鞋子。 Fashion MNIST中的图片像素为28*28的灰度图,非常的小。图片小也有好处,需要计算的参数相应减少,计算机处理速度也更快。 68e699f855f823b9b920c093a16d6e39jpg 这里看到的是一双鞋子,接下来我们一起来学习一段代码,看看如何基于这些资料图片让计算机学习的,从而让计算机具备辨识能力。还记得编写代码的大体环节吗,数据准备、模型构建、优化器和损失函数选择、训练模型、评估模型。让我们开始吧。

#1.1代码讲解:

#1.1.1数据准备

导入必要的包:

import tensorflow as tf
from tensorflow import keras
1
2

Fashion MNIST 是内置于TensoFlow的,所以很容易用这样的代码来加载。

fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
1
2

训练图组包含60000张图片,像是这样的灰度图片。 a09aa3051f8848a8da5d28d1beb1c3c2jpg 剩下的10000张图片是测试图组,可以用来检测神经网络的表现,标签是用来指定图片类别的数字,本案例中,09表示短靴。为什么使用数字“09”标注标签,而非“短靴”呢? 有两个原因,第一是:计算机更擅长处理数字。第二是:避免出现其他方面的偏见,比如语言偏见,而使用数字,则可以避免这样的问题。进行神经网络的设计时,要优先考虑输入和输出值,这里我们可以看到检测图片的神经网络比之前的要复杂一些。

#1.1.2构造模型

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dense(10, activation=tf.nn.softmax)
])
1
2
3
4
5

在第一层的网络中,我们的输入形状是28*28,这里的形状就是图片的长度和宽度。

keras.layers.Flatten(input_shape=(28, 28))
1

最后一层是10,是数据集中各种类别的代号,数据集总共有10类,这里就是10 。

keras.layers.Dense(10, activation=tf.nn.softmax),
1

所以神经网络有点像滤波器(过滤装置),输入一组28*28像素的图片后,输出10个类别的判断结果。那这个128的数字是做什么用的呢?

keras.layers.Dense(128, activation=tf.nn.relu),
1

我们可以这样想象,神经网络中有128个函数,每个函数都有自己的参数。 a959c332a35b24bde614a0856008a13djpg 我们给这些函数进行一个编号,f0,f1…f127 ,我们想的是当鞋子的像素一一带入这128个函数后,这些函数的组合最终输出一个标签值,在这个样例中,我们希望它输出09 。为了得到这个结果,计算机必须要搞清楚这128个函数的具体参数,之后才能计算各个图片的标签。这里的逻辑是,一旦计算机搞清楚了这些参数,那它就能够认出不同的10个类别的事物了。 这里设置了神经网络的优化器和损失函数。

model.compile(optimizer=tf.train.AdamOptimizer(),
			loss='sparse_categorical_crossentropy')
1
2

神经网络会对这些参数随机地初始化一些数值,损失函数会衡量结果精准与否。然后通过优化函数,各个函数会产生新的参数,去检查是否还有进步空间。你可能对这些函数感到好奇,它们叫做激活函数。

keras.layers.Dense(128, activation=tf.nn.relu),
  
keras.layers.Dense(10, activation=tf.nn.softmax)
1
2
3

第一个激活函数, activation=tf.nn.relu 在128层函数的这层,叫RelU,也叫线性整流函数,它的左右就是当函数值大于零时,把数值传递下去,函数值小于零时丢弃(赋值为零)。 a571b85e0b8e982f49dcf73b321f10fcjpg 所以当函数值为负数时就把该数值筛选剔除。第二个激活函数Softmax函数: c174b6bb5e832c53dd7e99a03b539f38jpg 它能够挑出一组数值中的最大值,这个神经网络中有10个项目,代表着一张图片属于某一个类别的概率大小。 所以如此看来,上示图片属于09号类别的概率分值最高,而09代表的是靴子,因此与其说是搜出最大值,softmax在此的作用是将该项目设为1,其它设为0。 99d77f08c6e69ddcd3e7b7eafc7688d9jpg 所以我们要做的就是找出数值1。 145fc7ae0461e9257dd7db0f6bd27297jpg 接下来的训练非常简单,我们将训练图像与训练标签相匹配。

#1.1.3训练、评估模型

model.fit(train_images, train_labels, epochs=5)
1

这次我们只训练5遍,还记得之前我们还有1万张图片和对应的标签没有用于训练吗?这些是模型“还没见过”的图像。所以可以用来测试模型的效能,测试方法就是将图像传递给评估方法,就像这样:

test_loss, test_acc = model.evaluate(test_images, test_labels)
1

#1.1.4模型预测

最后我们可以用 model.predict 来预测新图像:

predictions = model.predict(my_images)
1

这就是电脑查看和识别图像的一套方法,赶紧去试试吧!

#1.2完整代码

import tensorflow as tf
from tensorflow import keras

fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dense(10, activation=tf.nn.softmax)
])

model.compile(optimizer=tf.train.AdamOptimizer(),
              loss='sparse_categorical_crossentropy')

model.fit(train_images, train_labels, epochs=5)

predictions = model.predict(test_images)
print(predictions[0])		#打印网络预测结果
print(test_labels[0])		#打印答案(标签label)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#2.拓展阅读

#2.1为什么要使用激活函数?

答:为了对网络模型提供非线性。 追问:为什么网络模型需要具备非线性分类的能力? 答:因为线性分类是用直线进行分类,而现实的问题往往是非线性的。

ce909b10f81a60fa3525387f9445bde5jpg

 

第七章卷积模型分类图片

在之前的线性样例中,不论是简单的y = 2x,亦或房价预测模型,使用的都是全连接式的网络结构,这样的结构特点是可以拟合任意复杂模型,但计算相对缓慢。本节课我们学习一种全连接的特殊方式——卷积层。利用卷积层提取数据的特征,通过对特征的处理从而达到图片分类的目的。一起来揭开卷积的面纱。

#1.什么是卷积

卷积层是一组平行的特征图(feature map),它通过在输入图像上滑动不同的卷积核并运行一定的运算而组成。此外,在每一个滑动的位置上,卷积核与输入图像之间会运行一个元素对应乘积并求和的运算以将感受野内的信息投影到特征图中的一个元素。这一滑动的过程可称为步幅 ,步幅是控制输出特征图尺寸的一个因素。卷积核的尺寸要比输入图像小得多,且重叠或平行地作用于输入图像中,一张特征图中的所有元素都是通过一个卷积核计算得出的,也即一张特征图共享了相同的权重和偏置项。 举个例子,有一张3*3的特征图,与2*2的卷积核进行卷积运算,得到的结果为一张2*2的特征图,运算过程如下图所示: 232f418d17f677ea39af87f44461dd83jpg 请问,你能将矩形框中的“?”补齐吗,答案是多少,动手算一算。

#2.卷积有什么用

卷积可以强调某些特征,然后将特征强化后提取出来,不同的卷积核关注图片上不同的特征,比如有的更关注边缘而有的更关注中心地带等等,可以设计不同的卷积核,实现我们想要的效果,如下图: ce93267fd4856a07ab3c234f5bc9aad8jpg 通过卷积,我们可以实现对原始图像的信息浓缩,以便于后续的处理。这也是为什么要使用卷积的原因之一。

#2.1通道的概念

在RGB色彩模式下,一张彩色的图片的通道数是3。分别为红色通道,绿色通道,和蓝色通道。卷积神经网络运算的中间阶段,一张图片的通道可能有很多,来看看下面这个例子: 16dbd3b04c37aa700f9329df9259147ejpg 第一个红色框内通道数为3,它和我们常见的彩色图片通道数相同。第二个框的通道数为5,第三个蓝色框内特征图的通道数是多少呢?

#2.2理解滤波器(filter)的概念

卷积的时候是用多个‎filter‎完成的,一般经过卷积之后的输出(output shape )的输入通道为filter的数量,下图为输入深度为2的操作,会发现一个filter的输出最终会相加,将它的深度压为1,而不是一开始的输入通道。这是一个filter,多个filter最后放在一起,最后的深度就是filter的数量了。 ff80befc8c9981b2385adfecb2fade24jpg 卷积核中的每一个参数,可以理解为连接神经元的权重。我们通过训练数据集让这些参数变得更加合理,从而使得模型的泛化预测能力更强。而为了实现这一过程,随着数据的增加,计算机的运算负荷也将增大,将计算数量控制在计算机可以承受的范围之内就需要对参数量有个大体的估计。具体的计算方法,感兴趣的小伙伴可以查阅相关资料,具体的计算方式不在此处展开。接下来我们搭建一个神经网络模型,对图片进行分类预测。

#3.卷积神经网络实例——图片10分类代码讲解

#3.1数据准备

导入相关库:

import tensorflow as tf

from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
1
2
3
4

下载数据集:

(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

# 将像素的值标准化至0到1的区间内。
train_images, test_images = train_images / 255.0, test_images / 255.0
1
2
3
4

查看下载的数据集:

class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck']

plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    # 由于 CIFAR 的标签是 array, 
    # 因此您需要额外的索引(index)。
    plt.xlabel(class_names[train_labels[i][0]])
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

构建神经网络:

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
1
2
3
4
5
6

创建 密集层(Dense)/全连接层(Full Connected Layer)

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))
1
2
3

#3.2选择优化器和损失函数:

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
1
2
3

#3.3训练模型:

history = model.fit(train_images, train_labels, epochs=10, 
                    validation_data=(test_images, test_labels))
1
2

#3.4评估模型:

plt.plot(history.history['accuracy'], label='accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.ylim([0.5, 1])
plt.legend(loc='lower right')
plt.show()

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)
1
2
3
4
5
6
7
8
9

b6094af2d2ea70d5c7acd0fabf1f1066jpg

#4.拓展阅读

#4.1什么是过拟合

当存在少量训练示例时,模型有时会从训练示例中的噪声或不需要的细节中学习,从而对新示例的模型性能产生负面影响。这种现象被称为过度拟合。这意味着该模型将很难在新数据集上推广。 具体表现为:当训练精度随时间线性增加,而验证精度在训练过程中停滞。在训练过程中,有多种方法可以防止过度拟合。下面介绍2种常见的方法,数据增广和Dropout操作。

#4.2数据增广 (data argumentation)

数据增广采用从现有示例生成额外训练数据的方法,方法是使用随机变换对其进行扩充,从而生成外观可信的图像。这有助于将模型学习到数据的更多方面,并更好地概括。

#4.3Dropout 操作

Dropout是Google提出的一种正则化技术,用以在人工神经网络中对抗过拟合。Dropout有效的原因,是它能够避免在训练数据上产生复杂的相互适应。Dropout这个术语代指在神经网络中丢弃部分神经元(包括隐藏神经元和可见神经元)。在训练阶段,dropout使得每次只有部分网络结构得到更新,因而是一种高效的神经网络模型平均化的方法。 f25195d464850dcd75556e9c3742b11bjpg

第八章迁移学习——猫狗识别

如果模型已经学会了“骑自行车”,那么让它学会“骑摩托车”是不是更容易一些呢?像这样,借鉴之前的学习经验,产生举一反三的效果,这就是迁移学习的思想。当然,实际操作上会更复杂一些,我们先对迁移学习有个大致的感觉。

#1.什么是迁移学习

迁移学习,是把已训练好的模型(预训练模型)参数迁移到新的模型来帮助新模型训练。考虑到大部分数据或任务都是存在相关性的,所以通过迁移学习我们可以将已经学到的模型参数(也可理解为模型学到的知识)通过某种方式来分享给新模型从而加快并优化模型的学习效率,不用像大多数网络那样从零学习。 我们来学习一个迁移学习的模型。

#2.实例应用:猫狗识别

工作流程如下: a5533deb754318237a92fa6aadfc41d4jpg

#2.1数据准备

导入所需要的库:

import matplotlib.pyplot as plt
import numpy as np
import os
import tensorflow as tf

from tensorflow.keras.preprocessing import image_dataset_from_directory
1
2
3
4
5
6

数据下载,从指定的网址下载训练集和验证集。

_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')

train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')

BATCH_SIZE = 32
IMG_SIZE = (160, 160)

train_dataset = image_dataset_from_directory(train_dir,
                                             shuffle=True,
                                             batch_size=BATCH_SIZE,
                                             image_size=IMG_SIZE)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

验证集数据:

validation_dataset = image_dataset_from_directory(validation_dir,
                                                  shuffle=True,
                                                  batch_size=BATCH_SIZE,
                                                  image_size=IMG_SIZE)
1
2
3
4

至此,我们已经准备好了数据集。让我们来看看它是什么样子的,我们打开训练集的9张图片,并且显示对应的标签值:

class_names = train_dataset.class_names

plt.figure(figsize=(10, 10))
for images, labels in train_dataset.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")
1
2
3
4
5
6
7
8
9

应该得到类似下面的结果,可能我们显示的图片不尽相同,这是因为我们将数据集中的数据进行了打乱(shuffle)。 972e34be0842c06dd3913fb637401499jpg 因为原始数据不包含测试集,我们手动制作一个测试集,用于检测模型的预测效果。第一句中的tf.data.experimental.cardinality是为了查看验证集中有多少数据,接下来我们在验证集中抽取20%作为测试集数据:

val_batches = tf.data.experimental.cardinality(validation_dataset)
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)
1
2
3

可以查看验证集和测试集各有多少数据:

print('Number of validation batches: %d' % tf.data.experimental.cardinality(validation_dataset))
print('Number of test batches: %d' % tf.data.experimental.cardinality(test_dataset))
1
2

#2.2数据增广(data augmentation):

一般来说,数据集越大训练效果越好。有时候训练集数量不够多,我们可以通过数据增广的方法来提升数据集,从而达到提升训练效果的目的,通过对训练图像应用随机但真实的变换(如旋转和水平翻转),人为引入样本多样性是一种很好的做法。这有助于让模型学习训练数据的不同方面,并减少过度拟合

data_augmentation = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal'),
  tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),
])
1
2
3
4

查看一下数据增广的效果:

for image, _ in train_dataset.take(1):
  plt.figure(figsize=(10, 10))
  first_image = image[0]
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    augmented_image = data_augmentation(tf.expand_dims(first_image, 0))
    plt.imshow(augmented_image[0] / 255)
    plt.axis('off')
1
2
3
4
5
6
7
8

5ff4fccd2ac313a35877954222aa8a3fjpg 下载预训练模型,tf.keras.applications.mobilenetw2作为基础模型:

preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
1

此模型要求像素值为[-1,1],但这时,图像中的像素值为[0,255]。要重新缩放它们,放缩的方法如下,offset参数是偏移量,当原始像素除以127.5之后,图像从[0,255]放缩到了[0,2],此时只需要将坐标轴向左方平移一个单位即可得到[-1,1],这就是offset参数设置为 -1 的意义。

rescale = tf.keras.layers.experimental.preprocessing.Rescaling(1./127.5, offset= -1)
1

从预先训练的模型基础上,创建新的基础模型,我们将从谷歌开发的MobileNet V2模型创建基础模型。这是在ImageNet数据集上预先训练的,这是一个由140万张图像和1000个类组成的大型数据集。ImageNet是一个研究培训数据集,包含多种类别。这个知识库将帮助我们从特定的数据集中对猫和狗进行分类。 首先,我们需要选择将用于特征提取的哪一层。最后一个分类层不是很有用。取而代之的是,展平操作之前的最后一层。该层称为“瓶颈层”。与头部相比,瓶颈层功能保留了更多的通用性。 随后,实例化一个MobileNet V2模型,该模型预先加载了在ImageNet上训练的权重。通过指定include_top=False参数,可以加载顶部不包含分类层的网络,这对于特征提取非常理想。 如果你对以上的解释比较困惑,没关系,通俗的说,我们通过一系列“厉害”的操作让一个小白模型学会了骑自行车,接下来就是让它通过现有数据自己再学会骑摩托车。

# Create the base model from the pre-trained model MobileNet V2
IMG_SHAPE = IMG_SIZE + (3,)		# (160,160)→(160,160,3)
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                               include_top=False,
                                               weights='imagenet')
1
2
3
4
5

该功能提取器将每个160x160x3图像转换为5x5x1280特征图。可以这么理解:1280个5×5的特征图是3个160×160原始图片的信息浓缩。让我们看看它对一批示例图像的作用:

image_batch, label_batch = next(iter(train_dataset))
feature_batch = base_model(image_batch)
print(feature_batch.shape)
1
2
3

base_model是之前模型训练好的特征提取部分,这部分模型已经得到很好的优化,我们想要借用它。在训练的过程中,为了避免我们的数据对这部分模型产生破坏,因此我们把它冻结住。

base_model.trainable = False
1

可以看看现在模型是什么样子的:

base_model.summary()
1

dbc44969d006fd5dc5e92b68e92099cbjpg 构造分类器,这里生成了一层全局平均池化层,它的功能类似全连接层,功能是为最终的分类效果做准备。

global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
feature_batch_average = global_average_layer(feature_batch)
print(feature_batch_average.shape)
1
2
3

应用 tf.keras.layers.Dense 将这些特征转换为每个图像的单个预测。这里不需要激活函数,输出正数预测类别1,负数预测类别0。

prediction_layer = tf.keras.layers.Dense(1)
prediction_batch = prediction_layer(feature_batch_average)
print(prediction_batch.shape)
1
2
3

#2.3构建模型

创建模型的过程中,将数据增广、基础模型、剪枝操作串连起来。

inputs = tf.keras.Input(shape=(160, 160, 3))
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x, training=False)
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = prediction_layer(x)
model = tf.keras.Model(inputs, outputs)
1
2
3
4
5
6
7
8

编译模型,设置学习率,选择优化器和损失函数,设置评价策略。

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])
1
2
3
4

评估模型,在这里模型是有基础模型的权重的,因此可以在训练之前对模型进行评估。

initial_epochs = 10
loss0, accuracy0 = model.evaluate(validation_dataset)
1
2

看看模型的准确率

print("initial loss: {:.2f}".format(loss0))
print("initial accuracy: {:.2f}".format(accuracy0))
1
2

#2.4训练模型:

history = model.fit(train_dataset,
                    epochs=initial_epochs,
                    validation_data=validation_dataset)
1
2
3

3a80a883d6de292494d098c6c6a8fd5cjpg

#2.5绘制学习曲线:

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.ylim([0,1.0])
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

3eecd78b8ec8ebde293ac5dc08ff3d89jpg

#2.6完整代码:

import matplotlib.pyplot as plt
import numpy as np
import os
import tensorflow as tf

from tensorflow.keras.preprocessing import image_dataset_from_directory

_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')

train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')

BATCH_SIZE = 32
IMG_SIZE = (160, 160)

train_dataset = image_dataset_from_directory(train_dir,
                                             shuffle=True,
                                             batch_size=BATCH_SIZE,
                                             image_size=IMG_SIZE)
validation_dataset = image_dataset_from_directory(validation_dir,
                                                  shuffle=True,
                                                  batch_size=BATCH_SIZE,
                                                  image_size=IMG_SIZE)


val_batches = tf.data.experimental.cardinality(validation_dataset)
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)

data_augmentation = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal'),
  tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),
])

preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
rescale = tf.keras.layers.experimental.preprocessing.Rescaling(1./127.5, offset= -1)

# Create the base model from the pre-trained model MobileNet V2
IMG_SHAPE = IMG_SIZE + (3,)		# (160,160)→(160,160,3)
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                               include_top=False,
                                               weights='imagenet')
image_batch, label_batch = next(iter(train_dataset))
feature_batch = base_model(image_batch)
print('48\n')
base_model.trainable = False

global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
feature_batch_average = global_average_layer(feature_batch)
# print(feature_batch_average.shape)
prediction_layer = tf.keras.layers.Dense(1)
prediction_batch = prediction_layer(feature_batch_average)
#print(prediction_batch.shape)

inputs = tf.keras.Input(shape=(160, 160, 3))
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x, training=False)
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = prediction_layer(x)
model = tf.keras.Model(inputs, outputs)

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])
initial_epochs = 10

history = model.fit(train_dataset,
                    epochs=initial_epochs,
                    validation_data=validation_dataset)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

#3.拓展阅读

#3.1为什么数据集要进行打乱操作(shuffle)

假设我们的猫狗识别训练集呈现如下分布:

Dog,Dog,Dog,... ,Dog,Dog,Dog,Cat,Cat,Cat,Cat,... ,Cat,Cat
1

如果不进行打乱操作,那么模型在训练的一段时间内只看到了Dog,必然会过拟合于Dog,一段时间内又只能看到Cat,必然又过拟合于Cat,这样的模型泛化能力(举一反三能力)必然很差。

第九章文本处理

在之前的章节中,我们学习了有关离散数据、图片信息的回归和分类方法。本节课,我们想利用深度学习模型,对电影评论这样的文本信息进行分类,判断观影者是喜欢还是不喜欢该电影。 e2c992dc62429e2b91657a4c79e880a8jpg 让计算机处理、理解文本信息,其中涉及到自然语言处理(NLP)技术,什么是自然语言处理呢,它又有什么样的应用场景?

#1.自然语言处理(Natural Langunge Processing, NLP )

简单的描述,NLP是用计算机来处理、理解以及运用人类语言(如中文、英文等),它属于人工智能的一个分支,是计算机科学与语言学的交叉学科,又常被称为计算语言学,同时也是现在关注度较高的领域。 3bbdbebd3511e46c5b011c66c475004cjpg 接下来,我们看一个文本处理的例子,我们有一批影视评论文本数据,通过我们的努力,希望得到一个可以自动判断影视评论情感的分类器(只区分正面和负面评价)。在正式开始之前,我们先了解一下文本信息的预处理,毕竟计算机没有我们“聪明”,若是直接把文本给它,它会很懵~所以要预先进行数字化处理。

#2.用数字表示文本

机器学习模型将向量(数字数组)作为输入。在处理文本时,我们必须先想出一种策略,将字符串转换为数字(或将文本“向量化”),然后再把它输入模型。我们来看一下几种处理方式:One-hot、唯一数字编码、Word Embedding、Word2vec 、Elmo、BERT等,我们介绍前三种基础的编码方式。

#2.1独热编码(One-hot encodings)

我们可以对词汇表中的每个单词进行“独热”编码。考虑这样一句话:“The cat sat on the mat”。这句话中的词汇(或唯一单词)是(cat、mat、on、sat、the)。为了表示每个单词,我们将创建一个长度等于词汇量的零向量,然后在与该单词对应的索引中放置一个 1。下图显示了这种方法。 0678d5692fba567d4a9a8888b9de28dbjpg 为了创建一个包含句子编码的向量,我们可以将每个单词的独热向量连接起来。 然而,这种方法效率低下。一个独热编码向量十分稀疏(这意味着大多数索引为零)。假设我们的词汇表中有 10,000 个单词。为了对每个单词进行独热编码,我们将创建一个其中 99.99% 的元素都为零的向量。

#2.2用一个唯一的数字编码每个单词

efdea488c6e7fd5432ca89d3c93bb649jpg 我们可以尝试的第二种方法是使用唯一的数字来编码每个单词。继续上面的示例,我们可以将 1 分配给“cat”,将 2 分配给“mat”,依此类推。然后,我们可以将句子“The cat sat on the mat”编码为一个密集向量,例如 [5, 1, 4, 3, 5, 2]。这种方法是高效的。现在,我们有了一个密集向量(所有元素均已满),而不是稀疏向量。 但是,这种方法有两个缺点: 1、整数编码不能够体现单词之间的联系 2、对于要解释的模型而言,整数编码颇具挑战。例如,线性分类器针对每个特征学习一个权重。由于任何两个单词的相似性与其编码的相似性之间都没有关系,因此这种特征权重组合没有意义。

#2.3单词嵌入向量(Word Embedding)

单词嵌入(Word Embedding)或者分布式向量(Distributional Vectors)是将自然语言表示的单词转换为计算机能够理解的向量或矩阵形式的技术。由于要考虑多种因素比如词的语义(同义词近义词)、语料中词之间的关系(上下文)和向量的维度(处理复杂度)等等,我们希望近义词或者表示同类事物的单词之间的距离可以理想地近,只有拿到很理想的单词表示形式,我们才更容易地去做翻译、问答、信息抽取等进一步的工作。 0753e3074ef174754db3c3225721d181jpg 接下来,我们用代码实操阶段,从单词编码到把文本的情感进行分类。

#3.代码讲解

导入相关库:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

import tensorflow_datasets as tfds
tfds.disable_progress_bar()
1
2
3
4
5
6

使用嵌入向量层,可以将嵌入向量层理解为一个从整数索引(代表特定单词)映射到密集向量(其嵌入向量)的查找表。嵌入向量的维数(或宽度)是一个参数,可以试验它的数值,以了解多少维度适合我们的问题,这与试验密集层中神经元数量的方式非常相似。

embedding_layer = layers.Embedding(1000, 5)
1

创建嵌入向量层时,嵌入向量的权重会随机初始化(就像其他任何层一样)。在训练过程中,通过反向传播来逐渐调整这些权重。训练后,学习到的单词嵌入向量将粗略地编码单词之间的相似性(因为它们是针对训练模型的特定问题而学习的)。如果将整数传递给嵌入向量层,结果会将每个整数替换为嵌入向量表中的向量:

result = embedding_layer(tf.constant([1,2,3]))
result.numpy()
1
2

对于文本或序列问题,嵌入向量层采用整数组成的 2D 张量,其形状为 (samples, sequence_length),其中每个条目都是一个整数序列。它可以嵌入可变长度的序列。您可以在形状为 (32, 10)(32 个长度为 10 的序列组成的批次)或 (64, 15)(64 个长度为 15 的序列组成的批次)的批次上方馈入嵌入向量层。返回的张量比输入多一个轴,嵌入向量沿新的最后一个轴对齐。向其传递 (2, 3) 输入批次,输出为 (2, 3, N)

result = embedding_layer(tf.constant([[0,1,2],[3,4,5]]))
result.shape
1
2

当给定一个序列批次作为输入时,嵌入向量层将返回形状为 (samples, sequence_length, embedding_dimensionality) 的 3D 浮点张量,本样例使用池化,因为它最简单。我们将基于 IMDB 电影评论来训练情感分类器。在此过程中,模型将从头开始学习嵌入向量。我们将使用经过预处理的数据集。

(train_data, test_data), info = tfds.load(
    'imdb_reviews/subwords8k', 
    split = (tfds.Split.TRAIN, tfds.Split.TEST), 
    with_info=True, as_supervised=True)
1
2
3
4

获取编码器 (tfds.features.text.SubwordTextEncoder),并快速浏览词汇表:

encoder = info.features['text'].encoder
encoder.subwords[:20]
1
2

电影评论的长度可以不同。我们将使用 padded_batch 方法来标准化评论的长度。

train_batches = train_data.shuffle(1000).padded_batch(10)
test_batches = test_data.shuffle(1000).padded_batch(10)
1
2

导入时,评论的文本是整数编码的(每个整数代表词汇表中的特定单词或单词部分)。请注意尾随零,因为批次会填充为最长的示例。

train_batch, train_labels = next(iter(train_batches))
train_batch.numpy()
1
2

创建一个“连续词袋”样式的模型,嵌入向量层将采用整数编码的词汇表,并查找每个单词索引的嵌入向量。在模型训练时会学习这些向量。向量会向输出数组添加维度。得到的维度为:(batch, sequence, embedding)。接下来,通过对序列维度求平均值,GlobalAveragePooling1D 层会返回每个样本的固定长度输出向量。这让模型能够以最简单的方式处理可变长度的输入。此固定长度输出向量通过一个包含 16 个隐藏单元的完全连接(密集)层进行流水线传输。最后一层与单个输出节点密集连接。利用 Sigmoid 激活函数,得出此值是 0 到 1 之间的浮点数,表示评论为正面的概率(或置信度)。

embedding_dim=16

model = keras.Sequential([
  layers.Embedding(encoder.vocab_size, embedding_dim),
  layers.GlobalAveragePooling1D(),
  layers.Dense(16, activation='relu'),
  layers.Dense(1)
])

model.summary()
1
2
3
4
5
6
7
8
9
10

编译和训练模型

model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

history = model.fit(
    train_batches,
    epochs=10,
    validation_data=test_batches, validation_steps=20)
1
2
3
4
5
6
7
8

绘制学习曲线:

import matplotlib.pyplot as plt

history_dict = history.history

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss=history_dict['loss']
val_loss=history_dict['val_loss']

epochs = range(1, len(acc) + 1)

plt.figure(figsize=(12,9))
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

plt.figure(figsize=(12,9))
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim((0.5,1))
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

9328507e5dc8695942919aacf707ea44jpg 至此,我们体验了文本情感分类模型的训练流程。有关文本分析它是一个比较庞大的学科分支,限于篇幅,文中的代码示例没有向读者一一解释参数含义,若读者希望进一步进修人工智能的课程,鼓励大家自己查阅相关资料(官方文档是一个非常好的学习途径)。也欢迎读者在我们的交流群内分享学习进度与困惑。

#3.1完整代码

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

import tensorflow_datasets as tfds
tfds.disable_progress_bar()

embedding_layer = layers.Embedding(1000, 5)
(train_data, test_data), info = tfds.load(
    'imdb_reviews/subwords8k', 
    split = (tfds.Split.TRAIN, tfds.Split.TEST), 
    with_info=True, as_supervised=True)
encoder = info.features['text'].encoder
encoder.subwords[:20]
train_batches = train_data.shuffle(1000).padded_batch(10)
test_batches = test_data.shuffle(1000).padded_batch(10)
train_batch, train_labels = next(iter(train_batches))
train_batch.numpy()
embedding_dim=16

model = keras.Sequential([
  layers.Embedding(encoder.vocab_size, embedding_dim),
  layers.GlobalAveragePooling1D(),
  layers.Dense(16, activation='relu'),
  layers.Dense(1)
])
model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

history = model.fit(
    train_batches,
    epochs=10,
    validation_data=test_batches, validation_steps=20)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#4.练习题

以下属于NLP任务的有?(多选):

A. 词性标注

B. 文本分类

C. 问答对话系统

D. 机器翻译

第十章神奇的语言识别

1.喧嚣的世界

声音由物体振动产生,经过介质传播到达人耳被人类感知。原始的声波信号经过外耳收集之后,经一系列结构的传导到达耳蜗,耳蜗内有丰富的听觉感受器,将声波信号转化为生物电信号,传导到听觉神经从而引起听觉。 a15d598d2e02c5bdae6b525c0476f2afjpg 由于人耳听觉系统非常复杂,迄今为止人类对它的生理结构和听觉特性还不能从生理解剖角度完全解释清楚。所以,对人耳听觉特性的研究目前仅限于在心理声学和语言声学。 人耳对不同强度、不同频率声音的听觉范围称为声域。 在人耳的声域范围内,声音听觉心理的主观感受主要有响度、音调、音色等特征和掩蔽效应、高频定位等特性。其中响度、音调、音色可以在主观上用来描述具有振幅、频率和相位三个物理量的任何复杂的声音,故又称为声音“三要素”;而在多种音源场合,人耳掩蔽效应等特性更重要,它是心理声学的基础。 e53b1b28005d721fb8498393335f6e65jpg 响度(loudness):人主观上感觉声音的大小(俗称音量),由“振幅”(amplitude)和人离声源的距离决定,振幅越大响度越大,人和声源的距离越小,响度越大。 音调(pitch):声音的高低(高音、低音),由频率决定,频率越高音调越高(频率单位Hz,赫兹),人耳听觉范围20~20000Hz。20Hz以下称为次声波,20000Hz以上称为超声波)。 音色(Timbre):波形决定了声音的音调。由于不同对象材料的特点,声音具有不同的特性,音色本身就是抽象的东西,波形可以把抽象的音色直观的表达出来。波形因音调而异,不同的音调可以通过波形来区分。

#2.语音识别的应用

语音识别技术已经在现实生活中得到了广泛的应用。微信聊天中的语音转文字功能,就是典型的语音识别技术。语音输入系统,相对于键盘输入方法,它更符合人的日常习惯,也更自然、更高效;语音控制系统,即用语音来控制设备的运行,相对于手动控制来说更加快捷、方便,可以用在诸如工业控制、语音拨号系统、智能家电、声控智能玩具等许多领域;智能对话查询系统,根据客户的语音进行操作,为用户提供自然、友好的数据库检索服务,例如家庭服务、宾馆服务、旅行社服务系统、订票系统、医疗服务、银行服务、股票查询服务等等。 5d24aecf19762daca6ce9a9e7b6739a4jpg

#3.语音识别原理

语音识别是一个非常复杂的任务,想要达到实用的水准并不容易。我们也可以把语音识别理解成一个分类任务,即把人说的每一个音都找到一个文字对应。 d7f044d99c5ec2f7943fac1107867b49jpg 可以想象,这样的分类任务是非常困难的。但是语音识别也有它简单的一面, 人类的语言是很有规律的,我们在做语音识别的时候应该要考虑这些规律。第一 ,每种语言在声音上都有一定的特点,以汉语为例,我们都学过拼音,不认识的字我们通过拼音就能知道它的发音了。拼音的声母和韵母的数量比汉字的数量少很多,我们可以用汉语的声学特性提高语音识别的准确率。第二,汉语的语言表达也有一定的规律,比如我们根据声音的特性识别出来一个词“hen hao”,那么这个词更有可能是“很好”而不是“ 狠好”,因为前者在汉语的表达中具有一定的意义而且会经常出现。 ca07ce1e1cc0b2a88ff982905b4bc204jpg 语音识别会先把一段语音分成若干小段, 这个过程称为分帧。然后把每一帧识别为一个状态,再把状态组合成音素,音素一般就是我们熟知的声母和的韵母,而状态则是比音素更加细节的语音单位,一个音素通常会包含三个状态。把一系列语音帧转换为若干音素的过程利用了语言的声学特性,因而这一部分被称为声学模型(acoustic mode)。从音素到文字的过程需要用到语言表达的特点,这样才能从同音字中挑选出正确的文字,组成意义明确的语句,这部分被称为语言模型(language model)。

#3.1经典的声学特征:梅尔频率倒谱系数(Mel-Frequency Cepstral Coefficients, MFCC)

我们要实现对声音的分类,理论上也可以直接把声音的频谱数据作为评判标准,但这么做很困难,我们需要一种维度更低的特征来表示声音,梅尔频率倒谱系数就是优秀的特征之一。 梅尔频率倒谱系数(MFCC)被广泛应用于语音识别。它由Davis和Mermelstein在1980年提出。MFCC可以粗略地刻画出频谱的形状,因而可以大致描述出不同频率声音的能量高低。此外,MFCC也能够大致反映出声音的共振峰(声音频谱上能量相对集中的区域)。 5bb6b784b5cf92bf49112f67ea7f500cjpg

#3.2MFCC特征提取过程

MFCC特征提取过程分为两个步骤,首先对输入的音频信号,我们用梅尔频率对频谱进行处理得到一组26维的特征,然后再计算它的倒谱得到最终的13维MFCC特征。具体的计算过程比较复杂,这里不做展开。我们需要了解的是,音频在提取特征的过程中会被划分成若干等间隔的小段,它们可以相互有重叠,我们对每一小段进行MFCC特征提取。在切分音频的时候有窗口宽度和窗口间隔两个参数,这些参数可以根据音频的特点进行调节,一种常用的参数是窗口宽度25毫秒,窗口间隔10毫秒。 9edb7a68fc24784b3be666eb50938b78jpg 经过了上述准备知识,有兴趣的小伙伴可以一起来看一段语音识别的案例。

#4.拓展阅读:代码讲解

导入相关支持文件

import os
import pathlib

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import tensorflow as tf

from tensorflow.keras.layers.experimental import preprocessing
from tensorflow.keras import layers
from tensorflow.keras import models
from IPython import display
1
2
3
4
5
6
7
8
9
10
11
12

设置随机种子

seed = 42
tf.random.set_seed(seed)
np.random.seed(seed)
1
2
3

#4.1准备数据

data_dir = pathlib.Path('data/mini_speech_commands')
if not data_dir.exists():
  tf.keras.utils.get_file(
      'mini_speech_commands.zip',
      origin="http://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip",
      extract=True,
      cache_dir='.', cache_subdir='data')
1
2
3
4
5
6
7

查看音频对应的文字内容:’no’、 ‘stop’、 ‘go’、 ‘yes’、 ‘down’、 ‘right’、 ‘up’、 ‘left’

commands = np.array(tf.io.gfile.listdir(str(data_dir)))
commands = commands[commands != 'README.md']
print('Commands:', commands)
1
2
3

将音频文件提取到列表中并进行打乱

filenames = tf.io.gfile.glob(str(data_dir) + '/*/*')
filenames = tf.random.shuffle(filenames)
num_samples = len(filenames)
print('Number of total examples:', num_samples)
print('Number of examples per label:',
      len(tf.io.gfile.listdir(str(data_dir/commands[0]))))
print('Example file tensor:', filenames[0])
1
2
3
4
5
6
7

划分数据集,共有8000个音频样本,按照8:1:1的比例划分训练集、验证集、测试集

train_files = filenames[:6400]
val_files = filenames[6400: 6400 + 800]
test_files = filenames[-800:]

print('Training set size', len(train_files))
print('Validation set size', len(val_files))
print('Test set size', len(test_files))
1
2
3
4
5
6
7

#4.2查看音频和标签

设置读取音频文件方法

def decode_audio(audio_binary):
  audio, _ = tf.audio.decode_wav(audio_binary)
  return tf.squeeze(audio, axis=-1)
def get_label(file_path):
  parts = tf.strings.split(file_path, os.path.sep)
  return parts[-2]
1
2
3
4
5
6

设置获取音频标签的方法

def get_waveform_and_label(file_path):
  label = get_label(file_path)
  audio_binary = tf.io.read_file(file_path)
  waveform = decode_audio(audio_binary)
  return waveform, label
1
2
3
4
5
# AUTOTUNE = tf.data.AUTOTUNE 			# 高版本(2.5)tensorflow使用该语法
AUTOTUNE = tf.data.experimental.AUTOTUNE
files_ds = tf.data.Dataset.from_tensor_slices(train_files)
waveform_ds = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTOTUNE)
1
2
3
4

测试部分音频文件以及其对应的标签,训练过程中不需要添加此代码

rows = 3
cols = 3
n = rows*cols
fig, axes = plt.subplots(rows, cols, figsize=(10, 12))
for i, (audio, label) in enumerate(waveform_ds.take(n)):
  r = i // cols
  c = i % cols
  ax = axes[r][c]
  ax.plot(audio.numpy())
  ax.set_yticks(np.arange(-1.2, 1.2, 0.2))
  label = label.numpy().decode('utf-8')
  ax.set_title(label)

plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

设置获取音频声谱图方法

def get_spectrogram(waveform):
  # Padding for files with less than 16000 samples
  zero_padding = tf.zeros([16000] - tf.shape(waveform), dtype=tf.float32)

  # Concatenate audio with padding so that all audio clips will be of the 
  # same length
  waveform = tf.cast(waveform, tf.float32)
  equal_length = tf.concat([waveform, zero_padding], 0)
  spectrogram = tf.signal.stft(
      equal_length, frame_length=255, frame_step=128)

  spectrogram = tf.abs(spectrogram)

  return spectrogram
1
2
3
4
5
6
7
8
9
10
11
12
13
14

接下来,我们看一看数据中的一条音频,查看它的音频、标签、音谱

for waveform, label in waveform_ds.take(1):
  label = label.numpy().decode('utf-8')
  spectrogram = get_spectrogram(waveform)

print('Label:', label)
print('Waveform shape:', waveform.shape)
print('Spectrogram shape:', spectrogram.shape)
print('Audio playback')
display.display(display.Audio(waveform, rate=16000))
1
2
3
4
5
6
7
8
9

绘制样例的波形图和声谱图

def plot_spectrogram(spectrogram, ax):
  # Convert to frequencies to log scale and transpose so that the time is
  # represented in the x-axis (columns).
  log_spec = np.log(spectrogram.T)
  height = log_spec.shape[0]
  width = log_spec.shape[1]
  X = np.linspace(0, np.size(spectrogram), num=width, dtype=int)
  Y = range(height)
  ax.pcolormesh(X, Y, log_spec)


fig, axes = plt.subplots(2, figsize=(12, 8))
timescale = np.arange(waveform.shape[0])
axes[0].plot(timescale, waveform.numpy())
axes[0].set_title('Waveform')
axes[0].set_xlim([0, 16000])
plot_spectrogram(spectrogram.numpy(), axes[1])
axes[1].set_title('Spectrogram')
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#4.3声谱

现在,将波形数据集转换为具有谱图图像及其对应标签的整数ID。

def get_spectrogram_and_label_id(audio, label):
  spectrogram = get_spectrogram(audio)
  spectrogram = tf.expand_dims(spectrogram, -1)
  label_id = tf.argmax(label == commands)
  return spectrogram, label_id

spectrogram_ds = waveform_ds.map(
    get_spectrogram_and_label_id, num_parallel_calls=AUTOTUNE)
1
2
3
4
5
6
7
8

查看数据集中不同音频的声谱图

rows = 3
cols = 3
n = rows*cols
fig, axes = plt.subplots(rows, cols, figsize=(10, 10))
for i, (spectrogram, label_id) in enumerate(spectrogram_ds.take(n)):
  r = i // cols
  c = i % cols
  ax = axes[r][c]
  plot_spectrogram(np.squeeze(spectrogram.numpy()), ax)
  ax.set_title(commands[label_id.numpy()])
  ax.axis('off')

plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13

#4.4创建和训练模型

将训练集、验证集、测试集格式进行规整,以备正式开始训练

def preprocess_dataset(files):
  files_ds = tf.data.Dataset.from_tensor_slices(files)
  output_ds = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTOTUNE)
  output_ds = output_ds.map(
      get_spectrogram_and_label_id,  num_parallel_calls=AUTOTUNE)
  return output_ds
train_ds = spectrogram_ds
val_ds = preprocess_dataset(val_files)
test_ds = preprocess_dataset(test_files)
1
2
3
4
5
6
7
8
9

设置批量训练的参数

batch_size = 64
train_ds = train_ds.batch(batch_size)
val_ds = val_ds.batch(batch_size)
1
2
3

运用 dataset cache() 和 prefetch() 方法,以减少训练模型时的读取延迟

train_ds = train_ds.cache().prefetch(AUTOTUNE)
val_ds = val_ds.cache().prefetch(AUTOTUNE)
1
2

设置模型,这里模型我们使用卷积神经网络(CNN),你可能会疑惑,CNN不是擅长处理图像信息吗,为什么对于音频的识别分类也使用CNN呢?这是因为我们对音频进行特征处理时,将音频文件转化成了声谱图,使得声音信息涵盖于图像之中,因此使用CNN做模型也会有不错的效果。

for spectrogram, _ in spectrogram_ds.take(1):
  input_shape = spectrogram.shape
print('Input shape:', input_shape)
num_labels = len(commands)

norm_layer = preprocessing.Normalization()
norm_layer.adapt(spectrogram_ds.map(lambda x, _: x))

model = models.Sequential([
    layers.Input(shape=input_shape),
    preprocessing.Resizing(32, 32), 
    norm_layer,
    layers.Conv2D(32, 3, activation='relu'),
    layers.Conv2D(64, 3, activation='relu'),
    layers.MaxPooling2D(),
    layers.Dropout(0.25),
    layers.Flatten(),
    layers.Dense(128, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(num_labels),
])

model.summary()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

设置优化器和损失函数

model.compile(
    optimizer=tf.keras.optimizers.Adam(),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy'],
)
1
2
3
4
5

开始训练,循环训练10次

EPOCHS = 10
history = model.fit(
    train_ds, 
    validation_data=val_ds,  
    epochs=EPOCHS,
    callbacks=tf.keras.callbacks.EarlyStopping(verbose=1, patience=2),
)
1
2
3
4
5
6
7

绘制图表,查看训练结果

metrics = history.history
plt.plot(history.epoch, metrics['loss'], metrics['val_loss'])
plt.legend(['loss', 'val_loss'])
plt.show()
1
2
3
4

#4.5完整代码

import os
import pathlib

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import tensorflow as tf

from tensorflow.keras.layers.experimental import preprocessing
from tensorflow.keras import layers
from tensorflow.keras import models
from IPython import display


# Set seed for experiment reproducibility
seed = 42
tf.random.set_seed(seed)
np.random.seed(seed)

data_dir = pathlib.Path('data/mini_speech_commands')
if not data_dir.exists():
  tf.keras.utils.get_file(
      'mini_speech_commands.zip',
      origin="http://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip",
      extract=True,
      cache_dir='.', cache_subdir='data')
commands = np.array(tf.io.gfile.listdir(str(data_dir)))
commands = commands[commands != 'README.md']

def decode_audio(audio_binary):
  audio, _ = tf.audio.decode_wav(audio_binary)
  return tf.squeeze(audio, axis=-1)
def get_label(file_path):
  parts = tf.strings.split(file_path, os.path.sep)
  return parts[-2]
def get_waveform_and_label(file_path):
  label = get_label(file_path)
  audio_binary = tf.io.read_file(file_path)
  waveform = decode_audio(audio_binary)
  return waveform, label
AUTOTUNE = tf.data.experimental.AUTOTUNE
files_ds = tf.data.Dataset.from_tensor_slices(train_files)
waveform_ds = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTOTUNE)
def get_spectrogram(waveform):
  # Padding for files with less than 16000 samples
  zero_padding = tf.zeros([16000] - tf.shape(waveform), dtype=tf.float32)

  # Concatenate audio with padding so that all audio clips will be of the 
  # same length
  waveform = tf.cast(waveform, tf.float32)
  equal_length = tf.concat([waveform, zero_padding], 0)
  spectrogram = tf.signal.stft(
      equal_length, frame_length=255, frame_step=128)

  spectrogram = tf.abs(spectrogram)

  return spectrogram
def plot_spectrogram(spectrogram, ax):
  # Convert to frequencies to log scale and transpose so that the time is
  # represented in the x-axis (columns).
  log_spec = np.log(spectrogram.T)
  height = log_spec.shape[0]
  width = log_spec.shape[1]
  X = np.linspace(0, np.size(spectrogram), num=width, dtype=int)
  Y = range(height)
  ax.pcolormesh(X, Y, log_spec)

def get_spectrogram_and_label_id(audio, label):
  spectrogram = get_spectrogram(audio)
  spectrogram = tf.expand_dims(spectrogram, -1)
  label_id = tf.argmax(label == commands)
  return spectrogram, label_id

spectrogram_ds = waveform_ds.map(
    get_spectrogram_and_label_id, num_parallel_calls=AUTOTUNE)

def preprocess_dataset(files):
  files_ds = tf.data.Dataset.from_tensor_slices(files)
  output_ds = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTOTUNE)
  output_ds = output_ds.map(
      get_spectrogram_and_label_id,  num_parallel_calls=AUTOTUNE)
  return output_ds

train_ds = spectrogram_ds
val_ds = preprocess_dataset(val_files)
test_ds = preprocess_dataset(test_files)

batch_size = 64
train_ds = train_ds.batch(batch_size)
val_ds = val_ds.batch(batch_size)

train_ds = train_ds.cache().prefetch(AUTOTUNE)
val_ds = val_ds.cache().prefetch(AUTOTUNE)

for spectrogram, _ in spectrogram_ds.take(1):
  input_shape = spectrogram.shape
print('Input shape:', input_shape)
num_labels = len(commands)

norm_layer = preprocessing.Normalization()
norm_layer.adapt(spectrogram_ds.map(lambda x, _: x))

model = models.Sequential([
    layers.Input(shape=input_shape),
    preprocessing.Resizing(32, 32), 
    norm_layer,
    layers.Conv2D(32, 3, activation='relu'),
    layers.Conv2D(64, 3, activation='relu'),
    layers.MaxPooling2D(),
    layers.Dropout(0.25),
    layers.Flatten(),
    layers.Dense(128, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(num_labels),
])

model.compile(
    optimizer=tf.keras.optimizers.Adam(),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy'],
)
EPOCHS = 10
history = model.fit(
    train_ds, 
    validation_data=val_ds,  
    epochs=EPOCHS,
    callbacks=tf.keras.callbacks.EarlyStopping(verbose=1, patience=2),
)
metrics = history.history
plt.plot(history.epoch, metrics['loss'], metrics['val_loss'])
plt.legend(['loss', 'val_loss'])
plt.show()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容