人工智能示例第二版-全-
人工智能示例第二版(全)
原文:
annas-archive.org/md5/43719bc2b7dff02f9019e395ac4cf06e译者:飞龙
前言
《人工智能实例》第二版将带领你了解当前人工智能(AI)的主要方面,甚至超越这些内容!
本书包含了对第一版中描述的 AI 关键内容的许多修订和新增:
- 
机器学习和深度学习的理论,包括混合算法和集成算法。 
- 
主要 AI 算法的数学表示,包括自然语言解释,使其更容易理解。 
- 
真实案例研究,带领读者深入了解电子商务的核心:制造、服务、仓储和配送。 
- 
介绍将物联网、卷积神经网络(CNN)和马尔可夫决策过程(MDP)结合的 AI 解决方案。 
- 
许多开源 Python 程序,特别关注 TensorFlow 2.x、TensorBoard 和 Keras 的新功能。使用了许多模块,如 scikit-learn、pandas 等。 
- 
云平台:Google Colaboratory 及其免费的虚拟机、Google Translate、Google Dialogflow、IBM Q 量子计算平台等。 
- 
利用限制玻尔兹曼机(RBM)和主成分分析(PCA)的强大功能,生成数据以创建有意义的聊天机器人。 
- 
补偿聊天机器人情感缺陷的解决方案。 
- 
遗传算法,在特定情况下比经典算法运行更快,并且在混合深度学习神经网络中使用的遗传算法。 
- 
神经形态计算,通过选择性脉冲神经元群体的模型再现我们的大脑活动,这些模型模拟了我们的生物反应。 
- 
量子计算,将带你深入了解量子比特的巨大计算能力和认知表示实验。 
《人工智能实例》第二版将带你走在 AI 的最前沿,并通过创新提升现有解决方案。本书将使你不仅成为 AI 专家,还能成为一个有远见的人。你将发现如何作为顾问、开发人员、教授、好奇心驱动者或任何参与人工智能的人,提升你的 AI 技能。
本书适合谁阅读
本书提供了 AI 的广泛视角,AI 正在扩展到我们生活的各个领域。
主要的机器学习和深度学习算法通过来自数百个 AI 项目和实现的真实 Python 示例来讲解。
每个 AI 实现都通过一个开源程序进行说明,该程序可以在 GitHub 和 Google Colaboratory 等云平台上获取。
《人工智能实例第二版》适合那些希望构建坚实的机器学习程序的开发人员,这些程序将优化生产站点、服务、物联网等。
项目经理和顾问将学习如何构建输入数据集,帮助读者应对现实生活中的 AI 挑战。
教师和学生将全面了解 AI 的关键方面,并结合许多教育示例。
人工智能实例,第二版将帮助任何对 AI 感兴趣的人理解如何构建稳固、高效的 Python 程序。
本书内容概述
第一章,通过强化学习入门下一代人工智能,讲解了基于 MDP 的 Bellman 方程的强化学习。案例研究描述了如何解决带有人类驾驶员和自动驾驶车辆的送货路线问题。本章展示了如何在 Python 中从零开始构建 MDP。
第二章,构建奖励矩阵—设计你的数据集,展示了神经网络的架构,从 McCulloch-Pitts 神经元开始。案例研究描述了如何使用神经网络构建 Bellman 方程在仓库环境中的奖励矩阵。此过程将在 Python 中使用逻辑回归、softmax 和 one-hot 函数进行开发。
第三章,机器智能——评估函数与数值收敛,展示了机器评估能力如何超越人类决策。案例研究描述了一个国际象棋棋局,以及如何将 AI 程序的结果应用于决策优先级。Python 中决策树的介绍展示了如何管理决策过程。
第四章,通过 K-Means 聚类优化解决方案,介绍了一个基于 Lloyd 算法的 k-means 聚类程序,以及如何将其应用于自动引导车的优化。k-means 聚类程序的模型将被训练并保存。
第五章,如何使用决策树增强 K-Means 聚类,从 k-means 聚类的无监督学习开始。k-means 聚类算法的输出将为监督式决策树算法提供标签。将介绍随机森林算法。
第六章,通过 Google 翻译创新 AI,解释了革命性创新与颠覆性创新的区别。将描述 Google 翻译,并通过一个创新的基于 k 近邻的 Python 程序进行增强。
第七章,通过朴素贝叶斯优化区块链,讲述了区块链挖掘,并描述了区块链的工作原理。我们使用朴素贝叶斯方法通过预测交易来优化供应链管理(SCM)区块链的区块,以预测存储水平。
第八章,用前馈神经网络解决 XOR 问题,讲述了从零开始构建前馈神经网络(FNN)以解决 XOR 线性可分性问题。案例研究描述了如何为工厂分组订单。
第九章,使用卷积神经网络(CNN)进行抽象图像分类,详细描述了 CNN:卷积核、形状、激活函数、池化、展平和全连接层。案例研究展示了在食品加工公司中使用 Webcam 通过 CNN 进行传送带上的物品识别。
第十章,概念表示学习,解释了概念表示学习(CRL),这是一种通过 CNN 转换为CRL 元模型(CRLMM)来解决生产流程的创新方法。案例研究展示了如何利用 CRLMM 进行转移学习和领域学习,将模型扩展到其他应用。
第十一章,结合强化学习和深度学习,将 CNN 与 MDP 结合起来构建解决方案,用于自动规划和调度优化器与基于规则的系统。
这种解决方案应用于服装制造业,展示了如何将 AI 应用于现实生活系统。
第十二章,人工智能和物联网(IoT),探索了一个与 CNN 组合的支持向量机(SVM)。案例研究展示了自动驾驶车辆如何自动找到可用的停车位。
第十三章,使用 TensorFlow 2.x 和 TensorBoard 可视化网络,提取了 CNN 每一层的信息,并展示了神经网络所采取的中间步骤。每一层的输出包含了应用的转换图像。
第十四章,使用受限玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人输入,解释了如何利用 RBM 和 PCA 生成宝贵信息,将原始数据转化为聊天机器人输入数据。
第十五章,建立认知 NLP UI/CUI 聊天机器人,描述了如何从零开始构建一个 Google Dialogflow 聊天机器人,利用 RBM 和 PCA 算法提供的信息。该聊天机器人将包含实体、意图和有意义的响应。
第十六章,改进聊天机器人情感智能不足,解释了聊天机器人在处理人类情绪时的局限性。Dialogflow 的情感选项将被激活,同时结合Small Talk,使聊天机器人更加友好。
第十七章,混合神经网络中的遗传算法,深入探讨了我们的染色体,找到了我们的基因,并帮助你理解我们的繁殖过程如何工作。从这里开始,展示了如何在 Python 中实现进化算法,一个遗传算法(GA)。混合神经网络将展示如何使用遗传算法优化神经网络。
第十八章,神经形态计算,描述了神经形态计算的概念,然后探讨了 Nengo,一个独特的神经形态框架,提供了坚实的教程和文档。
这种神经形态的概述将带你进入我们大脑结构解决复杂问题的强大力量。
第十九章,量子计算,将展示量子计算机优于经典计算机,介绍了量子比特是什么,如何使用它,以及如何构建量子电路。量子门和示例程序的介绍将带你进入量子力学未来世界。
附录,问题的答案,提供了所有章节中问题部分列出的问题的答案。
要从本书中获得最大收益
人工智能项目依赖于三个因素:
- 
理解人工智能项目应用的主题。为此,可以通读一章,掌握关键思想。一旦理解了书中案例研究的关键概念,尝试思考如何将 AI 解决方案应用于你周围的现实生活例子。 
- 
AI 算法的数学基础。如果你有精力,别跳过数学公式。人工智能深深依赖数学。许多优秀的网站解释了本书中使用的数学。 
- 
开发。人工智能解决方案可以直接在 Google 等在线云平台的机器学习网站上使用。我们可以通过 API 访问这些平台。在本书中,多次使用了 Google Cloud。尝试创建你自己的帐户,探索多个云平台,了解它们的潜力和局限性。开发对于 AI 项目依然至关重要。 
即使使用云平台,脚本和服务也是必需的。此外,有时编写算法是必须的,因为现成的在线算法无法解决某些特定问题。探索本书附带的程序。它们是开源的,且免费。
技术要求
以下是运行本书代码所需的部分技术要求的非详尽列表。欲了解更详细的章节要求,请参考此链接:github.com/PacktPublishing/Artificial-Intelligence-By-Example-Second-Edition/blob/master/Technical%20Requirements.csv。
| Package | Website | 
|---|---|
| Python | www.python.org/ | 
| NumPy | pypi.org/project/numpy/ | 
| Matplotlib | pypi.org/project/matplotlib/ | 
| pandas | pypi.org/project/pandas/ | 
| SciPy | pypi.org/project/scipy/ | 
| scikit-learn | pypi.org/project/scikit-learn/ | 
| PyDotPlus | pypi.org/project/pydotplus/ | 
| Google API | developers.google.com/docs/api/quickstart/python | 
| html | pypi.org/project/html/ | 
| TensorFlow 2 | pypi.org/project/tensorflow/ | 
| Keras | pypi.org/project/Keras/ | 
| Pillow | pypi.org/project/Pillow/ | 
| Imageio | pypi.org/project/imageio/ | 
| Pathlib | pypi.org/project/pathlib/ | 
| OpenCV-Python | pypi.org/project/opencv-python/ | 
| Google Dialogflow | dialogflow.com/ | 
| DEAP | pypi.org/project/deap/ | 
| bitstring | pypi.org/project/bitstring/ | 
| nengo | pypi.org/project/nengo/ | 
| nengo-gui | pypi.org/project/nengo-gui/ | 
| IBM Q | www.research.ibm.com/ibm-q/ | 
| Quirk | algassert.com/2016/05/22/quirk.html | 
下载示例代码文件
您可以通过在www.packt.com/的账户中下载本书的示例代码文件。如果您在其他地方购买了此书,可以访问www.packtpub.com/support并注册,以便直接将文件通过电子邮件发送给您。
您可以通过以下步骤下载代码文件:
- 
登录或注册到 www.packt.com。
- 
选择支持标签。 
- 
点击代码下载。 
- 
在搜索框中输入书名并按照屏幕上的说明操作。 
下载文件后,请确保使用最新版本的以下工具解压或提取文件夹:
- 
WinRAR / 7-Zip for Windows 
- 
Zipeg / iZip / UnRarX for Mac 
- 
7-Zip / PeaZip for Linux 
本书的代码包也托管在 GitHub 上,网址是github.com/PacktPublishing/Artificial-Intelligence-By-Example-Second-Edition。如果代码有更新,它将在现有的 GitHub 仓库中更新。
我们还拥有来自我们丰富书籍和视频目录中的其他代码包,您可以在github.com/PacktPublishing/查看。快来看看吧!
下载彩色图像
我们还提供了一个 PDF 文件,里面包含了本书中使用的截图/图表的彩色图像。您可以在此下载:static.packt-cdn.com/downloads/9781839211539_ColorImages.pdf。
使用的约定
本书中使用了多种文本约定。
CodeInText:表示文本中的代码词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。例如:“决策树程序decision_tree.py读取 KMC 预测结果ckmc.csv的输出。”
代码块设置如下:
# load dataset
col_names = ['f1', 'f2','label']
df = pd.read_csv("ckmc.csv", header=None, names=col_names)
if pp==1:
    print(df.head()) 
当我们希望特别提醒您注意代码块中的某一部分时,相关的行或项会以粗体显示:
for i in range(0,1000):
    xf1=dataset.at[i,'Distance']
    xf2=dataset.at[i,'location']
    X_DL = [[xf1,xf2]]
    prediction = kmeans.predict(X_DL) 
所有命令行输入或输出按如下方式编写:
Selection: BnVYkFcRK Fittest: 0 This generation Fitness: 0 Time Difference: 0:00:00.000198 
粗体:表示一个新术语、重要的词汇,或者在屏幕上看到的词汇,例如菜单或对话框中的内容,也会以这种形式出现在文本中。例如:“当您点击保存时,情感进度条会跳动。”
警告或重要说明如下所示。
小贴士和技巧如下所示。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果您对本书的任何部分有疑问,请在邮件主题中提及书名,并通过customercare@packtpub.com与我们联系。
勘误:虽然我们已尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在本书中发现错误,感谢您向我们报告。请访问www.packtpub.com/support/errata,选择您的书籍,点击勘误提交表单链接,并填写详细信息。
盗版:如果您在互联网上遇到我们作品的任何非法副本,感谢您提供相关位置地址或网站名称。请通过copyright@packt.com与我们联系,并附上相关材料的链接。
如果您有兴趣成为作者:如果您在某个领域具有专业知识,且有兴趣撰写或参与编写书籍,请访问authors.packtpub.com。
评论
请留下评论。阅读并使用本书后,您可以在购买网站上留下评论。潜在读者可以根据您的客观意见做出购买决策,我们也可以了解您对我们产品的看法,而我们的作者则可以看到您对其书籍的反馈。谢谢!
有关 Packt 的更多信息,请访问packt.com。
第一章:通过强化学习开始学习下一代人工智能
下一代人工智能迫使我们意识到机器确实会思考。虽然机器的思维方式与我们不同,但它们的思维过程已经在许多领域证明了其效率。过去,人们认为人工智能会复制人类的思维过程。只有神经形态计算(见第十八章,神经形态计算)仍然致力于这个目标。大多数人工智能现在已经超越了人类的思维方式,正如我们将在本章中看到的那样。
马尔可夫决策过程(MDP),一种强化学习(RL)算法,完美地说明了机器是如何以其独特的方式变得智能的。人类根据经验构建决策过程。MDP 是无记忆的。人类通过逻辑和推理思考问题。MDP 则 100%时间使用随机决策。人类用语言思考,把他们感知到的每个事物都打上标签。MDP 采用无监督方法,不使用标签或训练数据。MDP 推动了自动驾驶汽车(SDC)、翻译工具、调度软件等机器思维过程的发展。这种无记忆、随机且无标签的机器思维过程标志着解决过去人类问题方式的历史性变化。
随着这一认识的到来,还有一个更令人大开眼界的事实。以物联网为基础的人工智能算法和混合解决方案已经开始在战略领域超越人类。尽管人工智能无法在每个领域取代人类,但人工智能与传统自动化结合,现在已占据了关键领域:银行、市场营销、供应链管理、调度以及许多其他关键领域。
正如你将看到的,从本章开始,你可以作为一个适应性思维者,在这个新世界中占据中心地位。你可以设计人工智能解决方案并实施它们。没有时间浪费。在本章中,我们将迅速直接地通过 MDP 深入了解强化学习。
今天,人工智能本质上是数学被转化为源代码,这使得传统开发人员很难学习。然而,我们将以务实的态度来处理这种方法。
这里的目标不是走捷径。我们努力将复杂性分解成可理解的部分,并与现实进行对比。你将从一开始就了解到如何应用适应性思维者的过程,这将引导你从一个想法到强化学习中的解决方案,并直接进入下一代人工智能的重心。
强化学习概念
人工智能在不断发展。经典方法表明:
- 
人工智能涵盖所有领域 
- 
机器学习是人工智能的一个子集,包括聚类、分类、回归和强化学习。 
- 
深度学习是机器学习的一个子集,涉及神经网络 
然而,这些领域往往存在重叠,因此很难将神经形态计算,例如其子符号方法,纳入这些类别(见第十八章,神经形态计算)。
在这一章中,强化学习(RL)显然适用于机器学习。我们将简要了解 MDP(马尔科夫决策过程)的科学基础,这是我们将要探索的强化学习算法。需要牢记的主要概念如下:
- 
最优运输:1781 年,贾斯帕·蒙奇定义了从一个位置到另一个位置的运输优化,使用最短和最具成本效益的路径;例如,开采煤矿,然后用最具成本效益的路径运送到工厂。此后,这一理论被推广到从 A 点到 B 点的任何路径形式。 
- 
玻尔兹曼方程和常数:19 世纪末,路德维希·玻尔兹曼通过他的粒子概率分布彻底改变了我们对世界的认知,他的熵公式完美地总结了这一点: S = k * log W S 代表系统的熵(能量、无序)。k 是玻尔兹曼常数,W 代表微观状态的数量。我们将在第十四章,使用限制玻尔兹曼机(RBMs)和主成分分析(PCA)准备聊天机器人的输入中进一步探讨玻尔兹曼的思想。 
- 
概率分布的进一步发展:乔西亚·威拉德·吉布斯将大量粒子的概率分布推进了一步。此时,概率信息理论正在迅速发展。在 19 世纪末,安德烈·马尔可夫将概率算法应用于语言等多个领域,信息理论的现代时代由此诞生。 
- 
当玻尔兹曼与最优运输相遇:2011 年菲尔兹奖得主塞德里克·维拉尼将玻尔兹曼方程提升到了一个新的层次。维拉尼随后将最优运输与玻尔兹曼理论结合起来。他证明了一个 19 世纪数学家直觉上已知但需要证明的命题。 
让我们把前面提到的所有概念在现实世界的一个例子中具象化,这将解释为什么使用 MDP 的强化学习,例如,是如此创新。
分析以下这杯茶将带你进入下一代人工智能的世界:

图 1.1:考虑一杯茶
你可以从两种不同的角度看待这杯茶:
- 
宏观状态:你看着这杯茶和茶水。你可以看到杯中茶的体积,并且当你拿着杯子时可以感觉到温度。 
- 
微观状态:但你能说出茶水中的分子有多少吗?哪些是热的,温暖的,还是冷的?它们的速度和方向如何?这几乎不可能对吧? 
现在,想象一下,这杯茶包含了超过 20 亿个 Facebook 账户,或者超过 1 亿个亚马逊 Prime 用户,每年进行数百万次配送。在这个层面上,我们根本放弃了控制每个单独项目的想法。我们着眼于趋势和概率。
玻尔兹曼提供了一种通过最优传输评估我们现实世界特征的概率方法。通过最优传输在物流中的应用,玻尔兹曼意味着温度可以是产品的排名,速度可以与交货距离相关,方向则是我们将在本章中研究的路径。
马尔可夫采纳了微观状态概率描述的成熟成果,并将其应用到他的 MDP 中。强化学习将大量元素(如茶杯中的粒子、交货地点、社交网络账户)进行定义,并确定它们可能的路径。
人类思维的转折点出现在我们无法分析全球化世界面临的庞大数据状态和路径时,这些数据产生的图像、声音、文字和数字超过了传统软件方法的处理能力。
有了这个前提,我们可以开始探索 MDP。
如何适应机器思维并成为一个自适应思维者
强化学习,作为机器学习的基础之一,假设通过与环境的互动,通过试错进行学习。这听起来很熟悉,不是吗?这正是我们人类一生所做的——痛苦中不断尝试!做事情、评估,然后继续;或者尝试别的东西。
在现实生活中,你是你思维过程的代理。在强化学习中,代理是通过这种试错过程随机计算的函数。机器学习中的这种思维过程函数就是 MDP 代理。这种经验学习的形式有时称为 Q 学习。
通过三步法掌握马尔可夫决策过程(MDP)的理论和实施是前提。
本章将详细介绍将你转变为 AI 专家的三步法,概括来说:
- 
通过描述解决实际问题的案例来开始 
- 
然后,建立一个考虑现实生活限制的数学模型 
- 
然后,编写源代码或使用云平台解决方案 
这是让你从一开始就以自适应的态度接近任何项目的一种方式。它表明,通过解释我们如何构建输入、运行算法并使用代码结果,AI 始终以人为中心。让我们考虑这三步法并付诸实践。
利用三步法克服现实生活中的问题
本章的关键是避免编写永远不会被使用的代码。首先,作为领域专家开始理解主题。然后,用文字和数学进行分析,确保你的推理符合主题,最重要的是,程序在现实生活中是有意义的。最后,在第三步,只有在你对整个项目有把握时才编写代码。
太多开发者在编写代码时没有停下来思考代码的结果如何在实际生活中体现出来。你可能花费数周的时间开发一个完美的解决方案,结果却发现一个外部因素使你的方案变得毫无用处。例如,如果你编写了一个太阳能驱动的机器人用来清理院子里的雪,但却发现冬季阳光不足以为机器人提供动力,这怎么办?
在本章中,我们将讨论 MDP(Q 函数),并将其应用于强化学习中的贝尔曼方程。不过,我们将以与大多数人不同的方式来接近这个问题。我们将关注实际应用,而不仅仅是代码执行。网上有大量的源代码和示例,但问题是,就像我们的雪地机器人一样,这些源代码很少考虑到现实生活中的复杂情况。假设你找到一个程序,可以为无人机配送找到最优路径。然而,问题是,它有很多限制需要克服,因为代码并没有考虑到现实生活中的实用性。你作为一个适应性思维者,将会提出一些问题:
- 
如果在一个大城市上空有 5000 架无人机同时飞行怎么办?如果它们试图直线飞行并碰撞到一起,会发生什么? 
- 
无人机干扰合法吗?城市上空的噪音呢?旅游业怎么办? 
- 
天气怎么样?天气预报很难做,那这个计划是怎么安排的? 
- 
我们如何解决协调充电和停车站使用的问题? 
只需几分钟,你就会成为那些比你更懂理论的学者和那些需要解决方案却得不到的愤怒经理们之间的焦点。你的现实生活方法将解决这些问题。为了做到这一点,你必须考虑以下三个步骤,首先要真正参与到现实生活的主题中。
为了成功实施我们现实生活中的方法,按照前一节中概述的三步骤,有几个先决条件:
- 
成为主题专家(SME):首先,你必须成为主题专家。如果一个理论极客提出了一百个 TensorFlow 函数来解决无人机轨迹问题,你现在就知道,这将是一次艰难的旅程,现实生活中的参数将限制算法的效果。SME 了解该主题,因此可以快速识别某一领域的关键因素。人工智能通常需要找到一个复杂问题的解决方案,甚至是该领域的专家也无法用数学表达出来。机器学习有时意味着找到一个问题的解决方案,而人类甚至不知道如何解释它。深度学习,涉及复杂的网络,解决了更为困难的问题。 
- 
具备足够的数学知识来理解 AI 概念:一旦你有了正确的自然语言分析,你需要迅速构建你的抽象表示。最好的方法是环顾四周,找到一个日常生活中的例子,并为其建立一个数学模型。在 AI 中,数学不是可选项,而是前提条件。付出的努力是值得的。然后,你可以开始编写一段扎实的源代码或开始实施一个云平台的机器学习解决方案。 
- 
了解源代码的内容及其潜力与局限性:MDP 是一种极好的方法,可以开始在三个维度上工作,使你具有适应性:用文字详细描述你周围的事物,将其转化为数学表示,然后将结果实现到你的源代码中。 
有了这些前提条件,让我们看看如何通过遵循我们实际的三步法成为一个问题解决型 AI 专家。不出所料,我们将从第一步开始。
第一步——描述要解决的问题:MDP 的自然语言表达
任何 AI 问题的第一步是尽可能深入理解你要表示的主题。如果是医学主题,不要仅仅看数据;去医院或研究中心。如果是私人安全应用,去那些需要使用它的地方。如果是社交媒体,确保直接与许多用户交谈。需要记住的关键概念是,你必须对该主题有一个“感觉”,就像你是真正的“用户”一样。
例如,将它转化为你日常生活中所知道的某些事物(工作或个人生活),是你在其中的专家。如果你有驾驶执照,那么你是驾驶方面的专家。你已获得认证。这是一个相当常见的认证,因此我们将其作为接下来示例的主题。如果你没有驾驶执照或从未驾驶过,你可以通过想象自己是步行出行来轻松替代开车;你是从一个地方到另一个地方的专家,不论所使用的交通工具是什么。然而,请记住,实际项目会涉及其他技术方面,比如每个国家的交通法规,因此我们的假想专家是有限的。
让我们进入这个例子,假设你是一名电子商务业务员,正在一个你不熟悉的地方送货。你是一个自动驾驶车辆的操作员。目前,你正在手动驾驶。你有一个带有漂亮彩色地图的 GPS。你周围的位置由字母A到F表示,如下图所示。你目前在F位置。你的目标是到达C位置。你很高兴,正在听广播。一切顺利,看起来你会准时到达。下图表示了你可以覆盖的地点和路线:

图 1.2:配送路线图
导航系统的状态显示了到达C的完整路径。它告诉你,你将从F经过B到D,然后到达C。看起来不错!
为了进一步解析,我们可以假设:
- 
当前状态是字母 s。s 是一个变量,不是实际的状态。它可以是L集合中的任何位置,即: L = {A, B, C, D, E, F} 我们之所以称之为当前状态,是因为在学习过程中没有序列。无记忆过程是从一个当前状态跳转到另一个当前状态。在本章的例子中,过程从位置F开始。 
- 
你的下一个动作是字母 a(动作)。这个动作 a 不是位置A。这个动作的目标是将我们带到图中的下一个可能位置。在这种情况下,只有B是可能的。动作 a 的目标是将我们从 s(当前状态)带到 s'(新状态)。 
- 
动作 a(不是位置A)是前往位置B。你查看导航系统,它告诉你没有交通,且从你当前的状态F到下一个状态B只需几分钟。假设下一个状态B就是字母B。这个下一个状态B是 s'。 
此时,你仍然相当满意,我们可以用以下事件序列总结你的情况:
s, a, s'
字母 s 是你当前的状态,你的当前情况。字母 a 是你正在决定的动作,即前往下一个位置;在那里,你将处于另一个状态 s'。我们可以说,得益于动作 a,你将从 s 转移到 s'。
现在,假设驾驶员不再是你。因为某些原因,你感到疲惫。这个时候,自驾车就派上了用场。你将车设置为自动驾驶。现在,你不再开车了;系统在操作。我们把这个系统叫做代理。在F点,你将车设置为自动驾驶,让自驾代理接管。
观察 MDP 代理的工作
自驾 AI 现在掌控着车辆。它充当着 MDP 代理。此时,它看到你要求它做的事情,并检查其映射环境,这个环境代表了之前图表中从A到F的所有位置。
与此同时,你当然感到担忧。代理是否能够成功完成任务?你在想它的策略是否与你的相符。你有自己的策略 P——你的思维方式——那就是尽量走最短的路径。代理会同意吗?它的机器大脑里究竟在想什么?你观察着,开始意识到以前从未注意到的事情。
由于这是你第一次使用这辆车和导航系统,智能体是无记忆的,这是 MDP 的一个特点。智能体不知道之前发生了什么。它似乎只对从F位置的状态s开始计算感到满意。它将使用机器能力进行尽可能多的计算,以实现其目标。
你正在观察的另一件事是从F到C的总距离,以检查情况是否正常。这意味着智能体正在计算从F到C的所有状态。
在这种情况下,状态F是状态 1,我们可以简化为写作s[1];B 是状态 2,我们可以简化为写作s[2];D 是s[3];C 是s[4]。智能体正在计算所有这些可能的状态以做出决策。
智能体知道当它到达D时,C会更好,因为前往 C 的奖励比其他地方都高。由于它不能通过吃蛋糕来奖励自己,智能体使用数字。我们的智能体是一个真正的数字计算者。当它出错时,它在这个模型中会得到一个差的奖励或什么也得不到。当它做对时,它会得到由字母R表示的奖励,我们将在第 2 步中遇到。这种行动价值(奖励)转移,通常被称为 Q 函数,是许多强化学习算法的核心。
当我们的智能体从一个状态转换到另一个状态时,它执行一次转移并获得奖励。例如,转移可以是从F到B,即从状态 1 到状态 2,或者从s[1]到s[2]。
你感觉很好,并且会准时到达。你开始理解自驾车中的机器学习智能体是如何思考的。突然,你抬头看到交通堵塞正在形成。D位置仍然很远,现在你不知道从D到C或从D到E哪个更好,因为后者可以走另一条交通较少的路到C。你准备看看智能体是怎么想的!
该智能体考虑到交通堵塞,固执己见,并增加奖励以通过最短路径到达C。它的策略是坚持初始计划。你不同意,你有另一种策略。
你停下了车。你们都必须在继续之前达成一致。你有自己的观点和策略;智能体不同意。在继续之前,你们的看法需要收敛。收敛是确保计算正确的关键,它也是评估计算质量的一种方法。
数学表示是此时表达整个过程的最佳方式,我们将在接下来的步骤中描述。
第 2 步——构建数学模型:贝尔曼方程和马尔可夫决策过程(MDP)的数学表示
数学涉及到你对问题的全新视角。你正在从文字转向函数,这是源编码的支柱。
用数学符号表达问题并不意味着陷入学术数学的困境,甚至写不出一行代码。只需利用数学有效地完成工作。跳过数学表示可以在 AI 项目的初期阶段加速某些功能的实现。然而,当所有 AI 项目中出现的真正问题浮出水面时,单靠源代码解决问题几乎是不可能的。这里的目标是掌握足够的数学知识,以便在现实公司中实施解决方案。
需要通过找到我们周围熟悉的事物来思考问题,例如本章早些时候提到的行程模型。用一些抽象的字母和符号来写下它是件好事,如前所述,其中 a 代表动作,s 代表状态。一旦你理解了问题并清晰表达出来,就可以继续前进。
现在,数学将通过更简洁的描述帮助澄清情况。掌握了主要思想后,是时候将它们转化为方程式。
从 MDP 到贝尔曼方程
在第一步中,智能体从 F(状态 1 或 s)转移到 B(状态 2 或 s')。
这个决策背后有一个策略——由 P 表示的政策。一个数学表达式包含了 MDP 状态转移函数:
Pa
P 是策略,智能体通过动作 a 从 F 转移到 B 的策略。在从 F 到 B 的过程中,这一状态转移被称为 状态转移函数:
- 
a 是动作 
- 
s 是状态 1(F),s' 是状态 2(B) 
奖励(正确或错误)矩阵遵循相同的原则:
Ra
这意味着 R 是从状态 s 转移到状态 s' 的奖励。状态之间的转移是一个随机过程。潜在地,所有状态都可以转移到其他任何状态。
示例中的矩阵每一行表示从 A 到 F 的一个字母,每一列表示从 A 到 F 的一个字母。所有可能的状态都在其中表示。1 值代表图的节点(顶点)。这些是可能的位置。例如,第 1 行表示字母 A 的可能移动,第 2 行表示字母 B,第 6 行表示字母 F。在第一行中,A 不能直接转移到 C,所以输入 0 值。但它可以转移到 E,因此加上 1 值。
一些模型从 -1 开始,表示不可能的选择,例如 B 不能直接转移到 C,而 0 值用于定义位置。这个模型从 0 和 1 值开始。有时需要数周时间来设计能够创建奖励矩阵的功能(见 第二章,构建奖励矩阵——设计你的数据集)。
我们将要处理的例子输入一个奖励矩阵,这样程序就能选择最佳的行动路线。然后,智能体将从一个状态到另一个状态,学习每个可能的起始位置点的最佳轨迹。MDP 的目标是到达C(奖励矩阵中的第 3 行,第 3 列),其初始值为 100,如下 Python 代码所示:
# Markov Decision Process (MDP) - The Bellman equations adapted to
# Reinforcement Learning
import numpy as ql
# R is The Reward Matrix for each state
R = ql.matrix([ [0,0,0,0,1,0],
                [0,0,0,1,0,1],
                [0,0,100,1,0,0],
                [0,1,1,0,1,0],
                [1,0,0,1,0,0],
                [0,1,0,0,0,0] ]) 
熟悉 Python 的人可能会想,为什么我使用ql而不是np。有人可能会说“惯例”、“主流”、“标准”。我的回答是一个问题。能有人在这个快速发展的世界中定义什么是“标准”的 AI 吗!我在这里的观点是,对于 MDP,我使用ql作为“Q-learning”的缩写,而不是 NumPy 的“标准”缩写np。当然,除了这个特殊的 MDP 程序缩写外,我会使用np。只是要记住,惯例是用来打破的,目的是让我们自由地去探索新的领域。只要确保你的程序运行良好!
这个决策过程有几个关键属性,其中包括以下内容:
- 
马尔可夫属性:这个过程不考虑过去。它是这个决策过程的无记忆特性,就像你在汽车中使用导航系统时一样。你向前移动,以达到目标。 
- 
无监督学习:从这个无记忆的马尔可夫属性来看,可以安全地说,MDP 不是监督学习。监督学习意味着我们将拥有奖励矩阵R的所有标签并从中学习。我们会知道A是什么意思,并利用这个属性做决策。我们将来会回顾过去。而 MDP 不考虑这些标签。因此,MDP 使用无监督学习进行训练。在每个状态下必须做出决策,而不知道过去的状态或它们意味着什么。这意味着汽车在每个位置上都是独立的,每个状态代表了它的一个位置。 
- 
随机过程:在步骤 1 中,当达到状态D时,控制映射系统的智能体和驾驶员在去向上没有达成一致。可以通过试错的方式做出随机选择,就像掷硬币一样。这将是一个正反两面的过程。智能体将掷硬币相当多次,并衡量结果。这正是 MDP 如何工作的,智能体就是通过这种方式学习的。 
- 
强化学习:通过反复的试错过程并获得来自环境的反馈。 
- 
马尔可夫链:从一个状态到另一个状态的过程,且没有历史,以随机的、随机的方式进行,这叫做马尔可夫链。 
总结一下,我们有三种工具:
- 
Pa: 一个策略,P,或从一个状态到另一个状态的策略 
- 
Ta: 一个T,或随机(随机的)转移,执行该动作的函数 
- 
Ra: 一个R,或该动作的奖励,可以是负的、零的或正的 
T是转移函数,它使得智能体依据策略从一个点转移到另一个点。在这个例子中,它是随机的。这就是机器能力的作用,也是强化学习通常实现的方式。
随机性
随机性是 MDP 的一个关键属性,将其定义为一个随机过程。
以下代码描述了智能体将做出的选择:
next_action = int(ql.random.choice(PossibleAction,1))
return next_action 
代码在每一轮(episode)选择一个新的随机动作(状态)。
贝尔曼方程
贝尔曼方程是编程强化学习的关键。
贝尔曼方程完成了马尔可夫决策过程(MDP)。为了计算一个状态的值,我们使用Q,表示Q的动作-奖励(或值)函数。贝尔曼方程的伪源代码可以表示如下,针对单个状态:

源代码然后将方程转化为机器表示,如下代码所示:
# The Bellman equation
    Q[current_state, action] = R[current_state, action] +
        gamma * MaxValue 
贝尔曼方程的源代码变量如下:
- 
Q(s):这是为该状态计算的值——总奖励。在第 1 步,当智能体从F移动到B时,奖励是一个数值,如 50 或 100,用来表明智能体走在正确的轨道上。 
- 
R(s):这是直到该点为止的值的总和。它是该点的总奖励。 
- 
![]() :这是提醒我们试错有代价。我们浪费了时间、金钱和精力。此外,我们甚至不知道下一步是对还是错,因为我们处于试错模式中。Gamma通常设置为 0.8。那意味着什么呢?假设你在参加考试。你努力学习,但不知道结果如何。你可能有 80%的机会(0.8)通过考试。这很痛苦,但这就是生活。Gamma惩罚或学习速率使得贝尔曼方程更加现实和高效。 :这是提醒我们试错有代价。我们浪费了时间、金钱和精力。此外,我们甚至不知道下一步是对还是错,因为我们处于试错模式中。Gamma通常设置为 0.8。那意味着什么呢?假设你在参加考试。你努力学习,但不知道结果如何。你可能有 80%的机会(0.8)通过考试。这很痛苦,但这就是生活。Gamma惩罚或学习速率使得贝尔曼方程更加现实和高效。
- 
max(s'): s'是可以通过Pa 到达的一个可能状态;max 是该状态(奖励矩阵中的位置行)上的最高值。 
到目前为止,你已经完成了三分之二的工作:理解现实生活中的(过程)并将其转化为基础数学。你已经构建了描述你学习过程的数学模型,并可以在代码中实现这个解决方案。现在,你准备好编码了!
第 3 步 – 编写源代码:在 Python 中实现解决方案
在第 1 步中,用自然语言描述了一个问题,以便能够与专家交流并理解期望的内容。在第 2 步中,建立了自然语言和源代码之间的关键数学桥梁。第 3 步是软件实现阶段。
当问题出现时——放心,它总是会出现——你可以回过头来与客户或公司团队一起回顾数学桥梁,甚至在必要时回到自然语言过程。
这种方法保证了任何项目的成功。本章中的代码是 Python 3.x 版本的。它是一个使用 Q 函数的强化学习程序,具有以下奖励矩阵:
import numpy as ql
R = ql.matrix([ [0,0,0,0,1,0],
                [0,0,0,1,0,1],
                [0,0,100,1,0,0],
                [0,1,1,0,1,0],
                [1,0,0,1,0,0],
                [0,1,0,0,0,0] ])
Q = ql.matrix(ql.zeros([6,6]))
gamma = 0.8 
R是数学分析中描述的奖励矩阵。
Q继承了与R相同的结构,但所有值都被设置为0,因为这是一个学习矩阵。它会逐步包含决策过程的结果。gamma变量是对系统学习的双重提醒,它的决策每次只有 80%的概率是正确的。正如下面的代码所示,系统在过程中探索可能的动作:
agent_s_state = 1
# The possible "a" actions when the agent is in a given state
def possible_actions(state):
    current_state_row = R[state,]
    possible_act = ql.where(current_state_row >0)[1]
    return possible_act
# Get available actions in the current state
PossibleAction = possible_actions(agent_s_state) 
例如,代理从状态 1 开始。你可以从任何你想要的地方开始,因为这是一个随机过程。注意,过程只考虑大于 0 的值,它们代表可能的动作(决策)。
当前状态会经过分析过程,以找出可能的动作(下一个可能的状态)。你会注意到,传统意义上的算法没有很多规则,它只是纯粹的随机计算,如下random.choice函数所示:
def ActionChoice(available_actions_range):
    if(sum(PossibleAction)>0):
        next_action = int(ql.random.choice(PossibleAction,1))
    if(sum(PossibleAction)<=0):
        next_action = int(ql.random.choice(5,1))
    return next_action
# Sample next action to be performed
action = ActionChoice(PossibleAction) 
现在是系统核心部分,包含了贝尔曼方程,已翻译为以下源代码:
def reward(current_state, action, gamma):
    Max_State = ql.where(Q[action,] == ql.max(Q[action,]))[1]
    if Max_State.shape[0] > 1:
        Max_State = int(ql.random.choice(Max_State, size = 1))
    else:
        Max_State = int(Max_State)
    MaxValue = Q[action, Max_State]
    # Q function
    Q[current_state, action] = R[current_state, action] +
        gamma * MaxValue
# Rewarding Q matrix
reward(agent_s_state,action,gamma) 
你可以看到,代理在随机选择的下一个可能状态中寻找最大值。
理解这一点的最佳方式是运行程序并在你的 Python 环境中使用print()输出中间值。我建议你打开一个电子表格并记录这些值,这样可以清晰地看到整个过程。
最后一部分是简单地运行学习过程 50,000 次,仅仅是为了确保系统学会了所有可以学习的内容。在每次迭代中,代理将检测其当前状态,选择一个行动方案,并更新 Q 函数矩阵:
for i in range(50000):
    current_state = ql.random.randint(0, int(Q.shape[0]))
    PossibleAction = possible_actions(current_state)
    action = ActionChoice(PossibleAction)
    reward(current_state,action,gamma)
# Displaying Q before the norm of Q phase
print("Q :")
print(Q)
# Norm of Q
print("Normed Q :")
print(Q/ql.max(Q)*100) 
该过程将持续进行,直到学习过程结束。然后,程序将打印出Q的结果以及标准化结果。标准化结果是通过将所有值除以找到的值的总和来得到的。print(Q/ql.max(Q)*100)通过将Q除以q1.max(Q)*100来标准化Q,结果会以标准化的百分比形式输出。
你可以使用mdp01.py来运行这个过程。
强化学习的经验教训
无监督强化机器学习,例如基于 MDP 的贝尔曼方程,正在逐步颠覆传统的决策软件。无记忆强化学习几乎不需要业务规则,因此也不需要人类知识来运行。
成为一名自适应的下一代 AI 思维者涉及三个前提条件:努力成为领域专家,致力于数学模型来像机器一样思考,以及理解你的源代码的潜力和限制。
机器智能和强化学习教给我们两条重要的经验:
- 
经验教训 1:通过强化学习的机器学习在许多情况下可以超越人类智能。与其抗争,不如接受!在战略领域,这项技术和解决方案已经到来。 
- 
第二课:机器没有情感,但你有。而且你身边的人也有。人类的情感和团队合作是至关重要的资产。成为你团队的领域专家(SME)。学会如何直观地理解他们想要表达的意思,并为他们将其转化为数学表达形式。即使你正在设置不需要太多开发的解决方案,如 AutoML,你的工作也永远不会消失。AutoML,或称自动化机器学习,自动化了许多任务。AutoML 自动化了数据集管道、超参数等功能。开发工作在一定程度上被抑制或完全被替代。但你仍然需要确保整个系统的设计良好。 
强化学习表明,没有人类能够像机器那样解决问题。进行 50,000 次随机搜索对人类来说不是一个选项。经验回合的数量可以通过数值收敛的梯度下降形式显著减少(见第三章,机器智能—评估函数与数值收敛)。
人类需要更加直觉化,做出几个决策并观察结果,因为人类无法尝试成千上万种做事的方式。强化学习通过超越人类在战略领域的推理能力,标志着人类思维的新时代。
另一方面,强化学习需要数学模型才能发挥作用。人类在数学抽象方面表现出色,为这些强大的机器提供了强大的智力支持。
人类与机器之间的界限已经改变。人类在构建数学模型和日益强大的云平台上的能力,将为在线机器学习服务提供支持。
了解如何使用我们刚刚研究的强化学习程序的输出,表明人类始终将处于人工智能的核心。
如何使用输出结果
我们研究的强化程序不包含传统软件中的任何特定领域的痕迹。该程序包含了贝尔曼方程,带有基于奖励矩阵的随机选择。目标是找到一条通向C(第 3 行,第 3 列)的路径,具有吸引人的奖励(100):
# Markov Decision Process (MDP) – The Bellman equations adapted to
# Reinforcement Learning with the Q action-value(reward) matrix
import numpy as ql
# R is The Reward Matrix for each state
R = ql.matrix([ [0,0,0,0,1,0],
                [0,0,0,1,0,1],
                [0,0,100,1,0,0],
                [0,1,1,0,1,0],
                [1,0,0,1,0,0],
                [0,1,0,0,0,0] ]) 
那个奖励矩阵经过贝尔曼方程处理,并在 Python 中产生结果:
Q :
[[ 0\. 0\. 0\. 0\. 258.44 0\. ]
 [ 0\. 0\. 0\. 321.8 0\. 207.752]
 [ 0\. 0\. 500\. 321.8 0\. 0\. ]
 [ 0\. 258.44 401\. 0\. 258.44 0\. ]
 [ 207.752 0\. 0\. 321.8 0\. 0\. ]
 [ 0\. 258.44 0\. 0\. 0\. 0\. ]]
Normed Q :
[[ 0\. 0\. 0\. 0\. 51.688 0\. ]
 [ 0\. 0\. 0\. 64.36 0\. 41.5504]
 [ 0\. 0\. 100\. 64.36 0\. 0\. ]
 [ 0\. 51.688 80.2 0\. 51.688 0\. ]
 [ 41.5504 0\. 0\. 64.36 0\. 0\. ]
 [ 0\. 51.688 0\. 0\. 0\. 0\. ]] 
结果包含强化学习过程中每个状态的值,并且还有一个归一化的Q(最高值与其他值的比值)。
作为 Python 极客,我们无比激动!我们完成了一项相当困难的工作,即强化学习。作为数学爱好者,我们欣喜若狂。我们知道 MDP 和贝尔曼方程是什么意思。
然而,作为自然语言思维者,我们进展甚微。没有客户或用户能够阅读这些数据并理解其中的含义。此外,我们无法解释我们是如何在机器中实现他们工作的智能版本的。实际上,我们没有做到。
我们几乎不敢说强化学习能够击败公司中的任何人,因为它要进行 50,000 次随机选择,直到找到正确答案。
此外,我们使得程序运行成功,但我们自己几乎不知道如何处理结果。项目中的顾问由于解决方案采用矩阵格式,无法提供帮助。
成为一个自适应的思考者意味着知道如何在项目的各个步骤中都做到最好。为了解决这个新问题,我们从结果回到第一步。回到第一步意味着如果你在理解结果或结果本身时遇到问题,就需要回到 SME(主题专家)级别、现实生活情境,看看哪里出了问题。
通过在 Python 中格式化结果,使用图形工具或电子表格,结果可以如下显示:
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| A | - | - | - | - | 258.44 | - | 
| B | - | - | - | 321.8 | - | 207.752 | 
| C | - | - | 500 | 321.8 | - | - | 
| D | - | 258.44 | 401. | - | 258.44 | - | 
| E | 207.752 | - | - | 321.8 | - | - | 
| F | - | 258.44 | - | - | - | - | 
现在,我们可以开始阅读解决方案:
- 
选择一个起始状态。以F为例。 
- 
F线表示状态。由于B列中的最大值是 258.44,我们转到B状态,即第二行。 
- 
第二行中的B状态的最大值引导我们到第四列的D状态。 
- 
D状态中的最高最大值(第四行)引导我们到C状态。 
注意,如果你从C状态开始,并决定不待在C,那么D状态将成为最大值,这将导致你回到C。然而,MDP(马尔可夫决策过程)永远不会自然发生这种情况,你必须强制系统执行此操作。
你现在已经得到了一个序列:F->B->D->C。通过选择其他起点,你可以通过简单地排序表格来获得其他序列。
一种有用的表达方式是保留标准化的百分比版本,如下表所示:
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| A | - | - | - | - | 51.68% | - | 
| B | - | - | - | 64.36% | - | 41.55% | 
| C | - | - | 100% | 64.36% | - | - | 
| D | - | 51.68% | 80.2% | - | 51.68% | - | 
| E | 41.55% | - | - | 64.36% | - | - | 
| F | - | 51.68% | - | - | - | - | 
现在进入非常棘手的部分。我们以一次公路旅行开始本章,但在结果分析中我没有提及它。
强化学习的一个重要特性来自于我们正在使用的数学模型,它可以应用于任何事情。无需任何人工规则。我们可以在不编写成千上万行代码的情况下,将此程序应用于其他许多领域。
可能的使用案例
有很多案例,我们可以在不改变模型任何细节的情况下,调整我们的强化学习模型。
案例 1:优化司机的配送,无论是否为人类
本模型在本章中进行了描述。
案例 2:优化仓库流程
同样的奖励矩阵可以用于从F点到C点的转移,比如在仓库中,如下图所示:

图 1.3:一个仓库流动问题的示意图
在这个仓库中,F->B->D->C的顺序具有视觉意义。如果有人从F点走到C点,那么这个物理路径是有意义的,且无需穿过墙壁。
它可以应用于视频游戏、工厂或任何形式的布局。
案例 3:自动化规划与调度(APS)
通过将系统转化为调度向量,整个场景发生了变化。我们已离开了更为舒适的物理处理字母、面孔和旅行的世界。虽然这些应用很精彩,但它们只是社交媒体的冰山一角。AI 的真正挑战始于人类思维的抽象宇宙。
每个公司、个人或系统都需要自动化规划和调度(参见第十二章,人工智能与物联网(IoT))。本章示例中的六个A到F步骤很可能是执行六个任务的顺序,这些任务由以下向量 x 表示:

奖励矩阵反映了向量 x 执行任务的约束权重。例如,在一个工厂中,你不能在制造零件之前就将它们组装成产品。
在这种情况下,得到的序列代表了制造过程的时间表。
案例 4 及以上:你的想象力
通过使用物理布局或抽象的决策向量、矩阵和张量,你可以在数学强化学习模型中构建一个解决方案的世界。当然,接下来的章节将通过许多其他概念丰富你的工具箱。
在继续之前,你可能想象一些场景,看看你能如何利用 A 到 F 字母来表达某种路径。
为了帮助你进行这些思维实验模拟,打开mdp02.py并跳到第 97 行,代码从以下内容开始,启用了模拟工具。nextc和nextci只是变量,用来记住路径的起始和结束位置。它们被设置为-1,以避免 0,0 表示一个位置。
主要目标是关注“概念代码”这个表达式。位置已变成你所希望的任何概念。A 可以是你的卧室,C 可以是你的厨房。路径从你醒来的地方到你吃早餐的地方。A 可以是你有的一个想法,F 是思考过程的终点。路径将从 A(我该如何把这张照片挂在墙上?)到 E(我需要钻个孔),经过几个阶段,到 F(我把照片挂在墙上了)。只要你定义了奖励矩阵、"概念代码"和起始点,你可以想象成千上万条这样的路径。
"""# Improving the program by introducing a decision-making process"""
nextc=-1
nextci=-1
conceptcode=["A","B","C","D","E","F"] 
这段代码接收计算结果,标记结果矩阵,并接受如下代码片段所示的输入:
origin=int(input(
    "index number origin(A=0,B=1,C=2,D=3,E=4,F=5): ")) 
输入仅接受标签数字代码:A=0,B=1 … F=5。然后,函数根据结果运行经典计算,以找到最佳路径。让我们举个例子。
当系统提示输入起始点时,例如输入5,如下所示:
index number origin(A=0,B=1,C=2,D=3,E=4,F=5): 5 
然后,程序将根据 MDP 过程的输出生成最佳路径,如下所示:
Concept Path
-> F
-> B
-> D
-> C 
尝试多种场景和可能性。想象一下你可以将其应用于哪些领域:
- 
一个电子商务网站的流程(访问、购物车、结账、购买),设想一个用户访问网站,然后稍后恢复会话。你可以使用本章中探讨的相同奖励矩阵和“概念代码”。例如,一位访客在早上 10 点访问一个网页,从你的网站 A 点开始。对产品满意后,访客将产品加入购物车,这是你网站的 E 点。然后,访客在到达购买页面 C 之前离开了网站。D 是关键点。为什么访客没有购买产品?发生了什么? 你可以决定在 24 小时后自动发送一封电子邮件,内容是:“在接下来的 48 小时内,所有购买享有 10%的折扣。”这样,你就能针对所有停留在 D 点的访客并推动他们向 C 点前进。 
- 
句子中可能的单词序列(主语、动词、宾语)。预测字母和单词是安德烈·马尔科夫 100 多年前的第一次应用!你可以想象 B 是字母表中的字母“a”。如果 D 是“t”,它比 F 为“o”更有可能,因为“o”在英语中较不常见。如果构建了一个 MDP 奖励矩阵,B 可能会转到 D 或 F,因此 B 可以走向 D 或 F。这样就有了两种可能性,D 或 F。安德烈·马尔科夫会假设,例如,B 是一个表示字母“a”的变量,D 是一个表示字母“t”的变量,而 F 是一个表示字母“o”的变量。经过深入研究语言的结构后,他会发现字母“a”更可能后跟“t”而不是“o”。如果观察英语语言,你会发现“a-t”序列比“a-o”序列更常见。在马尔科夫决策过程中,“a-t”序列将获得更高的概率,而“a-o”则获得较低的概率。如果回到变量,B-D 序列将比 B-F 序列更有可能出现。 
- 
任何你能找到的适合有效模型的内容都是很棒的! 
机器学习与传统应用的比较
基于随机(随机)过程的强化学习将超越传统方法。过去,我们会坐下来倾听未来用户的想法,以了解他们的思维方式。
然后我们将回到键盘,尝试模仿人类的思维方式。那些日子已经过去了。我们需要适当的数据集和 ML/DL 方程式来前进。应用数学已经将强化学习带到了一个新水平。在我看来,传统软件很快就会进入计算机科学博物馆。我们所面临的大量数据的复杂性在某些时候将需要 AI。
一个人工自适应思维者通过应用数学将世界转化为机器表示。
以本章提供的 Python 源代码示例为基础,以不同方式进行尝试。运行代码并尝试修改一些参数,看看会发生什么。也可以尝试调整迭代次数,将次数从 50,000 减少到你认为最合适的值。稍微调整一下奖励矩阵,看看结果如何。设计你自己的奖励矩阵轨迹。这可以是一个行程安排或决策过程。
摘要
目前,AI 主要是应用数学的一个分支,而不是神经科学的一个分支。你必须掌握线性代数和概率的基础知识。这对习惯于直觉创造力的开发者来说是个困难的任务。有了这些知识,你会明白人类无法与拥有 CPU 和数学功能的机器抗衡。你还会理解机器与周围的炒作不同,它们没有情感;尽管我们可以在聊天机器人中以一种可怕的方式表现出来(参见第十六章,改善聊天机器人的情商不足)。
多维方法是 AI/ML/DL 项目的前提条件。首先,讨论并书面表达项目,然后进行数学表示,最后进行软件生产(设置现有平台或编写代码)。在现实生活中,AI 解决方案并不会像某些炒作所说的那样自发地在公司中产生。你需要与团队沟通并合作。那部分才是项目的真正满足感——先设想它,然后与一群现实生活中的人一起实施。
MDP(马尔可夫决策过程),一个通过贝尔曼方程增强的随机动作-奖励(价值)系统,将为许多 AI 问题提供有效的解决方案。这些数学工具在企业环境中非常契合。
使用 Q 动作价值函数的强化学习是无记忆的(没有过去)和无监督的(数据未标记或分类)。MDP 为解决现实问题提供了无尽的途径,而无需花费数小时试图发明规则来使系统工作。
既然你已经处在 Google DeepMind 方法的核心,现在是时候阅读第二章,构建奖励矩阵—设计你的数据集,并通过解释和源代码发现如何首先创建奖励矩阵。
问题
问题的答案在附录 B中,附有进一步的解释:
- 
强化学习是无记忆的吗?(是 | 否) 
- 
强化学习使用随机(随机)函数吗?(是 | 否) 
- 
MDP 是否基于规则库?(是 | 否) 
- 
Q 函数是否基于 MDP?(是 | 否) 
- 
数学对于 AI 是否至关重要?(是 | 否) 
- 
本章中的 Bellman-MDP 过程是否可以应用于许多问题?(是 | 否) 
- 
机器学习程序是否不可能自行创建另一个程序?(是 | 否) 
- 
强化学习程序是否需要顾问输入业务规则?(是 | 否) 
- 
强化学习是监督学习还是无监督学习?(监督学习 | 无监督学习) 
- 
Q-learning 是否可以在没有奖励矩阵的情况下运行?(是 | 否) 
深入阅读
第二章:构建奖励矩阵 – 设计你的数据集
实验和实现是人工智能的两种主要方法。实验主要包括尝试现成的数据集和黑盒、现成的 Python 示例。实现则包括准备数据集、开发预处理算法,然后选择模型、适当的参数和超参数。
实现通常涉及白盒工作,这需要精确了解算法的工作原理,甚至能够修改它。
在第一章,通过强化学习开始使用下一代人工智能中,基于 MDP(马尔可夫决策过程)的贝尔曼方程依赖于奖励矩阵。在本章中,我们将深入探讨创建奖励矩阵的白盒过程。
MDP 过程无法在没有奖励矩阵的情况下运行。奖励矩阵决定了是否可以从一个单元移动到另一个单元,从 A 到 B。例如,它就像城市地图一样,告诉你是否可以走某条街,或者那条街是否是单行道。它还可以设定一个目标,比如在城市中你想去的某个地方。
为了实现设计奖励矩阵的目标,其他系统、软件和传感器提供的原始数据需要经过预处理。如果数据没有经过标准化处理,机器学习程序将无法提供有效的结果。
奖励矩阵,R,将使用 TensorFlow 中的 McCulloch-Pitts 神经元来构建。随着电子商务在许多市场领域的崛起,仓库管理也呈现出爆炸式增长。本章介绍了自动导引车(AGV),它是仓库中用于存取产品的相当于 SDC(自动存取设备)的系统。
本章的挑战是详细理解预处理阶段。处理后的数据集质量将直接影响任何机器学习算法的准确性。
本章涵盖以下主题:
- 
McCulloch-Pitts 神经元将处理原始数据并对其进行转换 
- 
逻辑回归分类器将启动神经网络过程 
- 
逻辑 sigmoid 将压缩这些值 
- 
softmax 函数将对值进行归一化处理 
- 
one-hot 函数将选择奖励矩阵的目标 
- 
仓库中 AGV(自动导引车)的示例 
这些主题构成了一系列工具,这些工具又形成了一个管道,将原始数据转换为奖励矩阵——一个 MDP。
设计数据集 – 梦想停止的地方,艰苦工作的开始
如同上一章所述,请记住,现实生活中的项目在某种形式下都会经历三维方法。首先,重要的是在不急于打开笔记本电脑的情况下,先思考和讨论需要解决的问题。完成这一步后,请记住,机器学习和深度学习的基础依赖于数学。最后,一旦问题被讨论并进行了数学表示,就可以开始开发解决方案。
首先,考虑一个自然语言的问题。然后,做出该问题的数学描述。只有在此之后,才应开始软件实现。
设计数据集
第一章中描述的强化学习程序可以解决多种涉及无标签分类的无监督决策问题。Q 函数可以应用于无人机、卡车或汽车配送,也可以应用于游戏或现实生活中的决策。
然而,在一个实际案例研究问题中(例如,在仓库中为 AGV 定义奖励矩阵),难点在于使用合适的 特征生成一个高效的矩阵。
例如,AGV 需要来自不同来源的信息:每日预测和实时仓库流量。
仓库管理着成千上万个位置和数十万个输入输出。将过多的特征塞入模型会适得其反。移除特征和无价值的数据需要谨慎考虑。
一个简单的神经元可以提供一种高效的方法来实现输入数据的标准化。
机器学习和深度学习常常用于预处理输入数据,以实现标准化、归一化和特征减少。
使用 McCulloch-Pitts 神经元
为了创建奖励矩阵 R,需要将仓库中处理巨大数据量的强大模型简化为有限数量的特征。
在一个模型中,例如,成千上万的输入可以描述如下:
- 
低优先级权重的预测产品到达:w[1] = 10 
- 
高优先级权重的确认到达:w[2] = 70 
- 
销售部门决定的非计划到达:w[3] = 75 
- 
高优先级权重的预测:w[4] = 60 
- 
低周转率的确认到达,因此权重较低:w[5] = 20 
权重已作为常量提供。McCulloch-Pitts 神经元不会修改权重。Perceptron 神经元会修改权重,正如我们将在第八章中看到的,通过前馈神经网络解决 XOR 问题。经验表明,修改权重并非总是必要的。
这些权重形成一个向量,如下所示:

向量的每个元素代表存储在最佳位置的产品特征的权重。该过程的最终阶段将生成一个奖励矩阵 R,用于优化 MDP 中仓库位置之间的路径。
让我们关注我们的神经元。这些权重,像这样的系统使用时,每个神经元可以达到超过 50 个权重和参数。在这个例子中,实现了 5 个权重。然而,在现实生活中,许多其他参数需要考虑,比如未确认的到达、具有高优先级的未确认到达、低优先级的已确认到达、来自可能不符合安全标准位置的到达、包含潜在危险且需要特别处理的到达等等。到那时,人类甚至经典软件也无法应对如此多样化的参数。
奖励矩阵的大小将是 6×6。它包含六个位置,A 到 F。在此示例中,六个位置,l1 到 l6,是仓库存储和取货位置。
6×6 的奖励矩阵表示为六个位置实现的 McCulloch-Pitts 层的目标。
在实验过程中,奖励矩阵 R 可以用于测试目的进行构造。在现实生活中的实现中,你需要找到从头开始构建数据集的方法。奖励矩阵将成为预处理阶段的输出。以下源代码展示了第一章中使用的强化学习程序的输入。本章的目标是描述如何生成接下来几节中将构建的奖励矩阵。
# R is The Reward Matrix for each location in a warehouse (or any other problem)
R = ql.matrix([ [0,0,0,0,1,0],
                [0,0,0,1,0,1],
                [0,0,100,1,0,0],
                [0,1,1,0,1,0],
                [1,0,0,1,0,0],
                [0,1,0,0,0,0] ]) 
对于我们正在使用的仓库示例,和任何其他领域一样,McCulloch-Pitts 神经元会对之前描述的输入向量的权重进行求和,从而填充奖励矩阵。
每个位置都需要其独立的神经元及其权重。
输入 -> 权重 -> 偏置 -> 值
- 
输入是仓库中的流量或任何形式的数据。 
- 
权重将在此模型中定义。 
- 
偏置用于稳定权重。偏置的作用正如其字面意思,它会倾斜权重。它非常有用,充当一个裁判,确保权重保持在正确的轨道上。 
- 
值将是输出。 
创建奖励矩阵的方法有很多种,只要你能想象出来。本章描述了一种有效的方法。
McCulloch-Pitts 神经元
McCulloch-Pitts 神经元可以追溯到 1943 年。它包含输入、权重和激活函数。预处理阶段的一部分是选择合适的模型。McCulloch-Pitts 神经元能够高效地表示给定的位置。
下图展示了 McCulloch-Pitts 神经元模型:

图 2.1:McCulloch-Pitts 神经元模型
该模型包含多个输入 x 权重,这些权重被求和,直到达到一个阈值,经过变换后将输出 y = 0 或 1。在此模型中,y 将以更复杂的方式计算。
使用 TensorFlow 2 编写的 MCP.py 将用于说明神经元。
在以下源代码中,TensorFlow 变量将包含输入值(x)、权重(W)和偏置(b)。变量代表图形的结构:
# The variables
x = tf.Variable([[0.0,0.0,0.0,0.0,0.0]], dtype = tf.float32)
W = tf.Variable([[0.0],[0.0],[0.0],[0.0],[0.0]], dtype =
    tf.float32)
b = tf.Variable([[0.0]]) 
在原始的 McCulloch-Pitts 人工神经元中,输入(x)与以下权重相乘:

数学函数变为一个通过神经元代码触发的逻辑激活函数(sigmoid),将在本章第二部分中解释。已添加偏置(b),使得这一神经元格式至今仍然有效,如下所示:
# The Neuron
def neuron(x, W, b):
    y1=np.multiply(x,W)+b
    y1=np.sum(y1)
    y = 1 / (1 + np.exp(-y1))
    return y 
在启动会话之前,McCulloch-Pitts 神经元(1943)需要操作员设置其权重。这是 McCulloch-Pitts 神经元与感知器(1957)之间的主要区别,后者是现代深度学习神经元的模型。感知器通过优化过程来优化其权重。第八章,使用前馈神经网络解决 XOR 问题,解释了为什么需要现代感知器。
权重现已提供,输入值的数量也已提供,这些值存储在 l[1] 的 x 向量中,l[1] 是此仓库示例中的六个位置之一:

权重值将除以 100,以表示仓库流量在给定位置的 0 到 1 之间的百分比。以下代码处理的是选择一个位置,l[1] 仅,其值和参数:
# The data
x_1 = [[10, 2, 1., 6., 2.]]
w_t = [[.1, .7, .75, .60, .20]]
b_1 = [1.0] 
调用神经元函数,并输入仓库流量的权重(w_t)和数量(x_1)。在此模型中,偏置设置为 1。无需初始化会话;只需调用神经元函数:
# Computing the value of the neuron
value=neuron(x_1,w_t,b_1) 
神经元函数 neuron 将计算神经元的值。程序返回以下值:
value for threshold calculation:0.99999 
该值表示位置 l[1] 在特定日期和特定时间的活动情况。此示例仅表示需要计算的六个位置中的一个。对于该位置,值越高,接近 1,表明该区域的饱和率越高。这意味着该位置几乎没有空间用于存储产品。这就是为什么仓库的强化学习程序在此模型中会寻找某一产品在给定时间内的最少负载区域。
每个位置都有一个可能的可用性:
A = 可用性 = 1 – 负载
给定存储点的负载概率介于 0 和 1 之间。
高可用性值接近 1,而低概率值接近 0,如下例所示:
>>> print("Availability of location x:{0:.5f}".format(
...       round(availability,5)))
Availability of location x:0.00001 
例如,l[1] 的负载可能为 0.99,且其最大可用性为 0.002。AGV 的目标是搜索并找到最近且最具可用性的地点,以优化其轨迹。在该日期和时间,l[1] 不是一个好的选择。负载是生产或服务活动中的一个关键字。资源越不可用,负载率越高。
当所有六个位置的可用性通过 McCulloch-Pitts 神经元计算完成——每个位置都有其各自的输入量、权重和偏差——该系统的结果将生成一个位置向量。然后,程序需要实现通过递归使用单一神经元模型来运行所有六个位置,而不仅仅是一个位置:
A(L) = {a(l[1]), a(l[2]), a(l[3]), a(l[4]), a(l[5]), a(l[6])}
可用性,1 – 神经元的输出值,构成一个六维向量。以下的向量,l[v],将在所有六个位置上运行之前的示例代码后获得。

如前面的公式所示,l[v] 是一个包含每个位置的值的向量,供给定 AGV 选择。向量中的值表示可用性。0.0002 表示可用性很低;0.9 表示可用性很高。通过这种选择,MDP 强化学习程序将优化 AGV 的轨迹,以到达这个特定的仓库位置。
l[v] 是 AGV 六个潜在位置的加权函数结果。它也是一个经过转换的输入向量。
Python-TensorFlow 架构
McCulloch-Pitts 神经元的实现可以最好地通过以下图表来展示:

图 2.2:McCulloch-Pitts 神经元的实现
数据流图还可以在出现问题时帮助优化程序,正如经典计算中那样。
Logistic 激活函数和分类器
现在,L = {l[1], l[2], l[3], l[4], l[5], l[6]} 中包含每个位置的可用性值,所有位置可以从最可用到最不可用的顺序进行排序。接着,可以构建用于 MDP 过程的奖励矩阵 R,该过程在 第一章《通过强化学习入门下一代人工智能》中描述。
总体架构
在这一点上,总体架构包含两个主要组件:
- 
第一章:基于值-动作 Q 函数的强化学习程序,使用奖励矩阵,该矩阵将在本章最终确定。奖励矩阵在第一章中作为实验提供,但在实现阶段,您通常需要从头开始构建它。有时,制作一个好的奖励矩阵可能需要几周的时间。 
- 
第二章:设计一组 6×1 神经元,表示在六个位置上某一时刻的产品流。输出是从 0 到 1 的可用性概率。最高值表示最高可用性,最低值表示最低可用性。 
在这一点上,我们可以通过一个示例从这两个主要功能中提取一些现实生活中的信息:
- 
一台 AGV 正在自动移动在仓库中,并等待接收下一个位置,以使用 MDP 来计算任务的最优轨迹。 
- 
一台 AGV 使用在实验阶段提供的奖励矩阵 R,但需要在实施过程中进行设计。 
- 
已计算出一个六个神经元的系统,每个神经元对应一个位置,权衡实际数量和可能数量,给出一个可用性向量 l[v]。它几乎准备好为 AGV 提供所需的奖励矩阵。 
在这个强化学习仓库模型中,为了计算奖励矩阵的输入值,缺少一个连接 l[v] 和奖励矩阵 R 的桥接函数。
该桥接函数是一个基于 n 个神经元输出的逻辑分类器,这些神经元独立或递归地执行相同的任务,且每个神经元仅执行一次。
此时,系统:
- 
获取企业数据 
- 
使用了计算过权重的 n 个神经元 
- 
应用了激活函数 
此模型中的激活函数要求使用一个常用的逻辑分类器。
逻辑分类器
逻辑分类器将应用于 l[v](六个位置值),以找到 AGV 的最佳位置。此方法可以应用于任何其他领域。它基于六个神经元的输出,如下所示:
输入 × 权重 + 偏置
逻辑函数是什么?逻辑分类器的目标是为输出向量的每个值生成一个从 0 到 1 的概率分布。正如你所看到的,人工智能应用使用的是应用数学与可能值,而不是原始输出。
主要原因是,机器学习/深度学习在标准化和归一化可操作的均匀数据分布时效果最佳。否则,算法通常会产生欠拟合或过拟合的结果。
在仓库模型中,例如,AGV 需要选择最佳的、最可能的位置 l[i]。即使在组织良好的企业仓库中,许多不确定因素(如迟到的货物、产品缺陷或一些未计划的突发问题)也会降低选择的概率。概率表示一个值,介于 0(低概率)和 1(高概率)之间。逻辑函数提供了将所有数值转换为 0 到 1 之间的概率以标准化数据的工具。
逻辑函数
逻辑 sigmoid 函数提供了标准化给定输出权重的最佳方式之一。神经元的激活函数将是逻辑 sigmoid。阈值通常是一个值,超过该值时,神经元的 y = 1;否则,y = 0。在此模型中,最小值将为 0。
逻辑函数表示如下:

- 
e 代表欧拉数,或 2.71828,自然对数。 
- 
x 是要计算的值。在这种情况下,s 是逻辑 sigmoid 函数的结果。 
代码已经在下面的示例中重新排列,以展示产生神经元输出y的推理过程:
 y1=np.multiply(x,W)+b
    y1=np.sum(y1)
    y = 1 / (1 + np.exp(-y1)) #logistic Sigmoid 
得益于逻辑 sigmoid 函数,模型中第一个位置的值被压缩到 0 和 1 之间,结果为 0.99,表示该位置将被占满的概率很高。
在考虑了 0.99 值后,要计算该位置的可用性,我们从总可用性(即 1)中减去负载,计算方法如下:
可用性 = 1 - 满载的概率(值)
或
可用性 = 1 - 值
如前所见,一旦以这种方式计算所有位置,就会得到一个最终的可用性向量,l[v]。

在分析l[v]时,处理过程中出现了问题。单独看,每一行似乎没有问题。通过对每个输出权重应用逻辑 sigmoid 并从 1 中减去,每个位置显示的可用性在 0 和 1 之间。但是,l[v]的行总和超过了 1。那是不可能的。概率不能超过 1。程序需要修正这个问题。
每一行都会产生一个[0, 1]的解,这符合有效概率的前提条件。
在这种情况下,向量l[v]包含多个值,成为一个概率分布。l[v]的总和不能超过 1,需要进行归一化。
softmax函数提供了一种很好的方法来归一化l[v]。softmax 在机器学习和深度学习中得到了广泛应用。
请记住,数学工具不是规则。只要解决方案有效,你可以根据需要将它们调整到适合你问题的形式。
Softmax
softmax 函数出现在许多人工智能模型中,用于归一化数据。softmax 可以用于分类目的和回归。在我们的示例中,我们将使用它来为 MDP 找到一个优化目标。
在仓库示例中,AGV 需要在l[v]向量中的六个位置之间做出可能的选择。然而,l[v]的总值超过了 1。l[v]需要对 softmax 函数S进行归一化。在源代码中,l[v]向量将命名为y。

以下使用的代码是SOFTMAX.py。
- 
y表示l[v]向量:# y is the vector of the scores of the lv vector in the warehouse example: y = [0.0002, 0.2, 0.9,0.0001,0.4,0.6]
- 
![]() 是 是y中的每个值(在仓库示例中是l[v])的exp(i)结果,计算如下:y_exp = [math.exp(i) for i in y]
- 
![]() 是 是![]() 的总和,如下面的代码所示: 的总和,如下面的代码所示:sum_exp_yi = sum(y_exp)
现在,通过应用以下函数来对向量的每个值进行归一化:
softmax = [round(i / sum_exp_yi, 3) for i in y_exp] 

softmax(l[v])提供了一个归一化的向量,其总和等于 1,如下面的压缩版本代码所示。得到的向量通常被描述为包含 logits。
以下代码展示了 softmax 函数的一个版本:
def softmax(x):
    return np.exp(x) / np.sum(np.exp(x), axis=0) 
l[v]现在通过 softmax(l[v])进行归一化,方法如下。

softmax 函数的最后一部分要求 softmax(l[v]) 被四舍五入为 0 或 1。softmax(l[v]) 中的值越大,其可能性越大。在明确的转换中,最高值将接近 1,其他值将接近 0。在决策过程中,需要按以下方式确定最高值:
print("7C.
Finding the highest value in the normalized y vector : ",ohot) 
输出值为 0.273,已被选为最可能的位置。然后它被设置为 1,其他较低的值被设置为 0。这叫做 one-hot 函数。这个 one-hot 函数对于编码提供的数据非常有帮助。现在得到的向量可以应用到奖励矩阵中。1 概率值将变为 R 奖励矩阵中的 100,如下所示:

softmax 函数现在已完成。位置 l[3] 或 C 是 AGV 的最佳解决方案。概率值被乘以 100,奖励矩阵 R 现在可以接收输入。
在继续之前,花些时间调整源代码中的值并运行它,以熟悉 softmax 函数。
我们现在有了奖励矩阵的数据。理解项目的数学部分的最佳方法是使用实际的仓库布局从 A 到 F 画出结果。
Locations={l1-A, l2-B, l3-C, l4-D, l5-E, l6-F} 
奖励矩阵的 C 行 ={0, 0, 100, 0, 0, 0},其中 C(第三个值)现在是自动驾驶车辆的目标,在此情况下是仓库中的 AGV。

图 2.3:仓库运输问题的示意图
我们得到了以下奖励矩阵 R,它在第一章,开始使用强化学习的下一代人工智能 中有所描述:
| State/values | A | B | C | D | E | F | 
|---|---|---|---|---|---|---|
| A | - | - | - | - | 1 | - | 
| B | - | - | - | 1 | - | 1 | 
| C | - | - | 100 | 1 | - | - | 
| D | - | 1 | 1 | - | 1 | - | 
| E | 1 | - | - | 1 | - | - | 
| F | - | 1 | - | - | - | - | 
这个奖励矩阵正是使用 Python 强化学习程序中的 Q 函数的那个矩阵,来源于第一章。因此,本章的输出正是 R 矩阵的输入。0 值是为了让代理避开这些值。1 值表示可达的单元格。C×C 单元格中的 100 是 softmax 输出的结果。该程序设计成保持接近概率标准并有正值,如以下从 第一章 的 mdp01.py 中提取的 R 矩阵所示:
R = ql.matrix([ [0,0,0,0,1,0],
                [0,0,0,1,0,1],
                [0,0,100,1,0,0],
                [0,1,1,0,1,0],
                [1,0,0,1,0,0],
                [0,1,0,0,0,0] ]) 
此时:
- 
本章中函数的输出生成了奖励矩阵 R,它是第一章,开始使用强化学习的下一代人工智能中描述的 MDP 的输入。 
- 
MDP 过程被设置为在第一章中运行 50,000 次。 
- 
MDP 的输出有多种用途,正如我们在本章和第一章中看到的。 
基础构建模块已就绪,可以开始评估强化学习程序的执行和性能,正如我们在第三章中看到的,机器智能——评估函数与数值收敛。
总结
使用带有 logistic 激活函数的 McCulloch-Pitts 神经元,在单层网络中构建强化学习的奖励矩阵,展示了一种预处理数据集的方法。
处理现实生活中的数据通常需要通过 softmax 函数对 logistic sigmoid 函数进行泛化,并且对 logits 应用 one-hot 函数来编码数据。
机器学习函数是必须理解的工具,只有理解它们,才能利用它们的全部或部分来解决问题。通过这种人工智能的实用方法,一个充满项目的世界正等着你。
这种神经元方法是多层感知器的前身,后者将在第八章中介绍,通过前馈神经网络解决 XOR 问题。
本章从实验性的黑箱机器学习和深度学习转向了白箱实现。实现需要对机器学习算法有全面的理解,这些算法通常需要微调。
然而,人工智能不仅仅是理解机器学习算法。机器学习或深度学习需要评估函数。如果没有评估函数,就无法验证性能或结果,正如在第三章中所解释的,机器智能——评估函数与数值收敛。
在下一章中,将通过一些例子展示机器智能的评估过程,这些例子展示了人类智能的局限性和机器能力的崛起。
问题
- 
原始数据可以作为神经元的输入,并通过权重进行变换。(是 | 否) 
- 
神经元是否需要一个阈值?(是 | 否) 
- 
logistic sigmoid 激活函数使得权重的总和增大。(是 | 否) 
- 
McCulloch-Pitts 神经元对其输入的权重进行加权求和。(是 | 否) 
- 
logistic sigmoid 函数是一个 log10 运算。(是 | 否) 
- 
如果对向量应用 logistic sigmoid 函数,则不需要 logistic softmax。(是 | 否) 
- 
概率是介于–1 和 1 之间的一个值。(是 | 否) 
进一步阅读
- 
原始的 McCulloch-Pitts 神经元 1943 年论文: www.cse.chalmers.se/~coquand/AUTOMATA/mcp.pdf
- 
TensorFlow 变量: www.tensorflow.org/beta/guide/variables
第三章:机器智能 – 评估函数和数值收敛
当奖励矩阵 (R) 驱动的 MDP 产生结果时,会出现两个问题。这些问题可以总结为两个原则。
原则 1:AI 算法通常在分类、预测和决策领域超越人类。
人类智能的关键执行功能——决策依赖于评估情况的能力。没有衡量利弊和考虑参数的决策是无法做出的。
人类以其评估能力为荣。然而,在许多情况下,机器能够做得更好。国际象棋代表了我们对思维能力的自豪。电影中常常出现棋盘,象征着人类智慧。
如今,没有一位棋手能够击败最强的国际象棋引擎。国际象棋引擎的一个非凡核心能力是评估函数;它比人类更精确地考虑了多个参数。
原则 2:原则 1 导致了一个非常棘手的后果。人类有时能够验证 AI 算法产生的结果,有时则无法验证,更不用说集成元算法了。
原则 1 一直很难被检测到,因为面部和物体识别的媒体炒作。人类很容易检查 ML 算法是否正确分类了应该分类的面部或物体。
然而,在涉及许多特征的决策过程中,原则 2 很快显现出来。在本章中,我们将识别要衡量的结果和收敛性,并决定如何衡量它。我们还将探索衡量和评估方法。
本章涉及以下主题:
- 
学习会话的阶段评估 
- 
数值收敛测量 
- 
数值梯度下降简介 
- 
决策树监督学习作为一种评估方法 
首先需要设定评估目标。为此,我们将决定衡量什么以及如何衡量。
跟踪需要衡量的内容并决定如何衡量
我们现在将着手解决一个棘手的任务,即找出可能导致系统出错的因素。
在前几章中构建的模型可以总结如下:

从 l[v](例如仓库中的容量)到 R,该过程从原始数据中创建奖励矩阵(第二章,构建奖励矩阵 – 设计您的数据集),这是 MD P 强化学习程序所需要的(第一章,通过强化学习开始探索下一代人工智能)。正如前一章所描述的,softmax(l[v]) 函数应用于 l[v]。接着,应用 one-hot(softmax(l[v])),然后将其转换为奖励值 R,该值将用于 Q(Q-learning)算法。
MDP 驱动的贝尔曼方程然后从读取R(奖励矩阵)到结果运行。Gamma 是学习参数,Q是 Q 学习函数,结果代表过程状态的最终值。
测量的参数如下:
- 
公司的输入数据。像 MNIST 这样的现成数据集被设计为在探索阶段高效使用。这些现成的数据集通常包含一些噪音(不可靠的数据),以使它们更真实。同样的过程必须通过原始公司数据完成。唯一的问题是你无法从某个地方下载公司数据集。你必须构建耗时的数据集。 
- 
将应用的权重和偏差。 
- 
激活函数(逻辑函数或其他)。 
- 
在单热过程后要做出的选择。 
- 
学习参数。 
- 
通过收敛进行剧集管理。 
- 
通过交互式随机检查和独立算法(如监督学习)的验证过程来控制无监督算法。 
在真实的公司项目中,一个系统在生产出数以万计的结果之前将不会被批准。在某些情况下,只有在测试了数百个数据集并有数百万数据样本的情况下,公司才会批准系统以确保所有场景都准确。每个数据集代表顾问可以使用参数脚本进行工作的一个场景。顾问引入由系统测试和测量的参数场景。在具有多达 200 个参数的决策系统中,在工业环境中,顾问将需要几个月的时间。强化学习程序将独自计算事件。然而,即便如此,顾问在管理超参数时仍然是必要的。在真实的具有高财务风险的系统中,质量控制将始终是必不可少的。
测量因此应更多地适用于泛化,而不仅仅适用于单个或少数数据集。否则,你会有一种自然倾向来控制参数,并在太好以至于不真实的场景中过拟合你的模型。
例如,假设你早上醒来,看到天空晴朗,阳光明媚,没有云。第二天你醒来,看到同样的天气。你将这些记录在数据集中,并发送给客户进行天气预测。每次客户运行程序时,它都预测天气晴朗!这就是过拟合导致的结果!这解释了为什么我们需要大量数据集来充分理解如何使用算法或说明机器学习程序的工作原理。
除了奖励矩阵之外,第一章的强化程序有一个学习参数!,在mdp03.py中显示,用于本节:
# Gamma: It's a form of penalty or uncertainty for learning
# If the value is 1, the rewards would be too high.
# This way the system knows it is learning.
gamma = 0.8 
 学习参数本身需要被密切监控,因为它为系统引入了不确定性。这意味着学习过程始终保持一种概率性,永远无法确定。有人可能会想,为什么不干脆去除这个参数。矛盾的是,这样做反而会导致更大的全局不确定性。
学习参数本身需要被密切监控,因为它为系统引入了不确定性。这意味着学习过程始终保持一种概率性,永远无法确定。有人可能会想,为什么不干脆去除这个参数。矛盾的是,这样做反而会导致更大的全局不确定性。 学习参数越接近 1,你就越有可能使结果过拟合。过拟合意味着你让系统认为它在学习得很好,实际上并非如此。就像一位老师总是给班上每个学生都打高分一样。老师实际上是在过度拟合成绩与学生表现的评估过程,结果大家都不知道学生是否真的学到了东西。
学习参数越接近 1,你就越有可能使结果过拟合。过拟合意味着你让系统认为它在学习得很好,实际上并非如此。就像一位老师总是给班上每个学生都打高分一样。老师实际上是在过度拟合成绩与学生表现的评估过程,结果大家都不知道学生是否真的学到了东西。
强化程序的结果需要在每次训练中进行衡量。学习过程本身的范围也必须被测量。
所有这些测量都将对获得的结果产生重要影响。
最好的开始方法是通过测量系统的收敛质量。
如果系统提供了良好的收敛性,你可能会避免重新检查一切的麻烦。
收敛
收敛度衡量的是训练会话当前状态与目标之间的距离。在强化学习程序中,例如在马尔可夫决策过程(MDP)中,并没有训练数据,因此也没有目标数据可以进行比较。
然而,有两种方法可以选择:
- 
隐式收敛:在这种情况下,我们运行大量的训练轮次,例如 50,000 次。通过反复试验,我们知道程序到那时会找到一个解决方案。 
- 
数值控制梯度下降:我们在每次训练中测量进展,并在安全的情况下停止训练。 
隐式收敛
在第一章的mdp01.py最后部分,实现了 50,000 的范围。在这一章中,我们将运行mdp03.py。
在mdp01.py的最后部分,设置了一个使得收敛得以保证的训练轮次。在下面的代码中,范围(50000)是一个常量:
for i in range(50000):
    current_state = ql.random.randint(0, int(Q.shape[0]))
    PossibleAction = possible_actions(current_state)
    action = ActionChoice(PossibleAction)
    reward(current_state,action,gamma) 
在这种情况下,收敛将定义为无论你运行系统多长时间,Q结果矩阵将不再发生变化。
通过设置范围为50000,你可以进行测试和验证。只要奖励矩阵保持一致性,这样的方法就有效。如果奖励矩阵在不同情境中有较大变化,这个模型将会产生不稳定的结果。
尝试使用不同的范围运行程序。逐渐降低范围,直到你发现结果不再最优。
数值控制梯度下降收敛
在这一部分中,我们将使用mdp03.py,它是mdp01.py在第一章中的修改版,并增加了一个新功能:数值控制梯度下降。
让 MDP 训练 50,000 次会得到不错的结果,但会消耗不必要的 CPU。使用数值控制的梯度下降评估函数可以节省大量轮次。让我们看看节省了多少。
首先,我们需要基于导数定义梯度下降函数。让我们快速回顾一下什么是导数。

h 是函数步长的值。想象 h 代表银行账户对账单的每一行。如果我们逐行阅读对账单,h = 1。如果我们每次读两行,h = 2。
阅读银行账户对账单的当前行 = f(x) = 某个数额。
当你阅读银行账户的下一行时,函数是 (f + h) = f(x) 后的数额。如果你的银行账户在 f(x) 时有 100 个货币单位,并且花费了 10 个货币单位,那么在下一行,x + h,你将剩下 f(x + h) = 90 个货币单位。
梯度提供了你的斜率方向:向上、向下或保持不变。在这种情况下,我们可以说斜率,即梯度,正在向下,如下图所示,图中展示了随着 x 增加(训练轮次),y(成本、损失)的值逐渐减少:

图 3.1:随着训练轮次增加,成本/损失值逐渐减少的图示
我们还需要知道你的银行账户正在发生多大的变化——导数的值是多少。在这种情况下,导数意味着在你的银行账户对账单的每一行中,余额变化了多少。在这个例子中,你在一行对账单上花费了 10 个货币单位,所以在该 x(银行账户中的行)处的导数 = –10。
在《第一章,使用强化学习开始下一代人工智能》中的贝尔曼方程代码中,循环步长也是 1:
for i in range(sec): 
由于 i = 1,h = 1,在我们的梯度下降计算中可以简化为:

我们现在在以下代码中定义 f(x):
conv=Q.sum() 
conv 是 6×6 的 Q 矩阵的总和,随着 MDP 训练的进展,它逐渐填充。因此 f(x) = conv=Q.sum() = Q 的总和。该函数将 Q 中的所有值加起来,以精确地表示系统在每个 i 时的状态。
f(x) = 系统在 i – 1 时的状态
f(x + 1) 是系统在 i 时的值:
Q.sum() 
我们必须记住,随着 MDP 训练过程的进行,Q 矩阵正在逐渐增加。我们测量两步之间的距离,h。这个距离会减小。现在我们有:
f(x + 1) – f(x) = -Q.sum()+conv
- 
首先,我们为评估函数实现额外的变量,该函数在 mdp01.py的第 83 行使用梯度下降:ci=0 # convergence counter which counts the number of episodes conv=0 # sum of Q at state 1 and then every x episodes nc=1 # numerical convergence activated to perform numerical-controlled gradient descent xi=100 # xi episode optimizer: stop as soon as convergence reached + xi-x(unknown) sec=2500 # security number of episodes for this matrix size brought down from 50,000 to 2,500 cq=ql.zeros((2500, 1))
- 
nc=1激活评估函数,ci开始计数此函数所需的轮次:for i in range(sec): current_state = ql.random.randint(0, int(Q.shape[0])) PossibleAction = possible_actions(current_state) action = ActionChoice(PossibleAction) reward(current_state,action,gamma) ci+=1 # convergence counter incremented by 1 at each state if(nc==1): # numerical convergence activated
- 
在第一次训练轮次, i==1,f(x)=Q.sum(),如预期所示:if(i==1): # at state one, conv is activated conv=Q.sum() # conv= the sum of Q
- 
f(x + 1) = -Q.sum()+conv被应用:print("Episode",i,"Local derivative:",-Q.sum()+conv,...
- 
距离,导数的绝对值,会被显示并存储,因为我们将使用它来用 Matplotlib 绘制图形: print(... "Numerical Convergence value estimator", Q.sum()-conv) cq[i][0]=Q.sum()-conv
- 
xi=100在这个数值控制的梯度下降函数中起着关键作用。每次xi,过程都会暂停检查训练过程的状态:if(ci==xi): # every 100 episodes the system checks to see...
有两种可能的情况:a) 和 b)。
情况 a) 只要每个回合的局部导数>0,MDP 就会继续训练过程:
 if(conv!=Q.sum()): # if the sum of Q changes...
                conv=Q.sum()   # ...the training isn't over, conv is updated
                ci=0           # ...the convergence counter is set to O 
输出将显示不同的局部导数:
Episode 1911 Local derivative: -9.094947017729282e-13 Numerical Convergence value estimator 9.094947017729282e-13
Episode 1912 Local derivative: -9.094947017729282e-13 Numerical Convergence value estimator 9.094947017729282e-13
Episode 1913 Local derivative: -1.3642420526593924e-12 Numerical Convergence value estimator 1.3642420526593924e-12 
情况 b) 当导数值在xi回合后达到一个常数值时,MDP 已经训练完成,训练可以停止:
 if(conv==Q.sum()):        # ...if the sum of Q has changed
                print(i,conv,Q.sum()) # ...if it hasn't the training is over
                break                 # ...the system stops training 
输出将显示一个常数导数,xi,在训练停止之前:
Episode 2096 Local derivative: 0.0 Numerical Convergence value estimator 0.0
Episode 2097 Local derivative: 0.0 Numerical Convergence value estimator 0.0
Episode 2098 Local derivative: 0.0 Numerical Convergence value estimator 0.0
Episode 2099 Local derivative: 0.0 Numerical Convergence value estimator 0.0 
当训练结束时,将显示训练回合的数量:
number of episodes: 2099 
2,099 远小于 50,000 个隐式收敛回合,这证明了该数值控制的梯度下降方法的效率。
在学习过程结束时,你可以显示一个包含我们在cq=ql.zeros((2500, 1))中存储的每个回合收敛水平的 Matplotlib 图:
 cq[i][0]=Q.sum()-conv 
该图形由几行代码显示:
import matplotlib.pyplot as plt
plt.plot(cq)
plt.xlabel('Episodes')
plt.ylabel('Convergence Distances')
plt.show() 

图 3.2:演示数值收敛性的图
该图显示了数值收敛性。如图中所示,随着训练回合数的增加,成本或损失下降,正如本章前面所解释的那样。
请注意该梯度下降方法的以下属性:
- 
回合数会因为 MDP 是一个随机过程而在不同的训练会话中有所变化。 
- 
由于训练过程的随机性,局部回合的训练曲线有时会波动。有时,曲线局部上升而非下降。最终,它会达到 0 并保持在那里。 
- 
如果训练曲线局部上升,没什么可以做的。MDP 不会进行反向传播来修改权重、参数或策略,正如我们在第八章“用前馈神经网络解决 XOR 问题”中看到的那样。MDP 过程不需要任何操作。你可以尝试更改学习率,或者回去检查你的奖励矩阵和在原始数据集上实施的预处理阶段。 
- 
如果训练曲线没有达到 0 并保持在那里,请检查学习参数、奖励矩阵和在原始数据集上实施的预处理阶段。你甚至可能需要回去检查初始数据集中的噪声(缺陷数据或缺失数据)。 
一旦 MDP 训练完成,使用第 145 行提供的功能进行一些随机测试,该功能在第一章中有所解释:
origin=int(input("index number origin(A=0,B=1,C=2,D=3,E=4,F=5): ")) 
例如,当提示输入时,输入1并查看结果是否正确,如以下输出所示:
index number origin(A=0,B=1,C=2,D=3,E=4,F=5): 1
…/…
print("Path:")
-> B
-> D
-> C 
这种随机测试验证方法在相对较小的奖励矩阵下能有效工作。
然而,对于一个 25×25 的奖励矩阵,这种方法就会变得困难。例如,机器可以轻松给出一个结果。但我们如何评估这个结果呢?在这种情况下,我们已经达到了人类分析能力的极限。在之前的代码中,我们输入了一个起始点并得到了答案。对于一个小的奖励矩阵,我们可以轻松地进行视觉检查,看看答案是否正确。然而,当分析 25×25 = 625 个格子时,需要几天时间来验证结果。值得一提的是,当安德烈·马尔可夫在 100 多年前发明他的算法时,他使用的是纸和笔!然而,今天我们有计算机,所以我们必须使用评估算法来评估我们的马尔可夫决策过程(MDP)的结果。
在全球化的世界中,数据和参数的不断增加使得人类无法超越机器日益增长的智能。
超越人类分析能力的评估
一位高效的管理者拥有较高的评估商数。在越来越多的领域中,机器往往有更高的评估商数。人类面临的问题是理解机器产生的评估结果。
有时人类会说“这是一种很好的机器思维结果”或“这是一个糟糕的结果”,但却无法解释为什么,或判断是否有更好的解决方案。
评估是所有领域中高效决策的关键之一:从国际象棋、生产管理、火箭发射、自驾车,到数据中心校准、软件开发、机场调度等。
我们将通过一个国际象棋的场景来展示人类评估的极限。
国际象棋引擎并非基于高水平深度学习的软件。它们高度依赖于评估和计算。它们的评估能力远超人类,而且从它们身上有很多值得学习的地方。现在的问题是,是否有人类能够战胜国际象棋引擎?答案是否定的。
要评估国际象棋中的局面,你需要检查所有棋子,它们的定量价值、定性价值、棋子之间的协作、谁占据了 64 个格子中的每一个、国王的安全、主教对、骑士的位置,以及许多其他因素。
在国际象棋比赛中评估一个局面,显示了为什么机器在许多决策领域超过了人类。
以下场景是在 2017 年克拉姆尼克与布鲁鲍姆对局后的第 23 步。人类无法正确评估这个局面。它包含了太多的参数和可能性,无法进行分析。

图 3.3:国际象棋示例场景
现在轮到白方走棋,经过仔细分析,发现此时两位选手都处于困境。在这样的比赛中,他们必须继续保持扑克脸。他们常常以自信的表情看着自己的棋盘,以掩饰内心的沮丧。有些人甚至缩短思考时间,让对手以为他们知道接下来的棋路。
这些对人类来说无法解决的局面,对于国际象棋引擎来说是轻松解决的,即使是智能手机上的廉价高质量国际象棋引擎也能轻松应对。这可以推广到所有日益复杂、不可预测和混乱的人类活动。决策者将越来越依赖人工智能来帮助他们做出正确的选择。
没有任何人能够像国际象棋引擎那样通过简单地计算棋子的摆放位置、自由格以及其他许多参数来评估棋局。国际象棋引擎通过数百万次计算生成评估矩阵。
以下表格是对多个位置中的一个位置(实际和潜在)进行评估的结果。
| 局面评估 | 0,3 | |||||
|---|---|---|---|---|---|---|
| 白方 | 34 | |||||
| 初始位置 | 位置 | 价值 | 质量值 | 总价值 | ||
| 兵 | a2 | a2 | 1 | a2-b2 小兵岛 | 0,05 | 1,05 | 
| 兵 | b2 | b2 | 1 | a2-b2 小兵岛 | 0,05 | 1,05 | 
| 兵 | c2 | x | 0 | 被吃掉 | 0 | 0 | 
| 兵 | d2 | d4 | 1 | 占据中心,防守 Be5 | 0,25 | 1,25 | 
| 兵 | e2 | e2 | 1 | 防守 Qf3 | 0,25 | 1,25 | 
| 兵 | f2 | x | 0 | 被吃掉 | 0 | 0 | 
| 兵 | g2 | g5 | 1 | 未受攻击,攻击 2 格 | 0,3 | 1,3 | 
| 兵 | h2 | h3 | 1 | 未受攻击,防守 g4 | 0,1 | 1,1 | 
| 车 | a1 | c1 | 5 | 占据 c 文件,攻击 b7 配合 Nd5-Be5 | 1 | 6 | 
| 骑士 | b1 | d5 | 3 | 攻击 Nb6,8 格 | 0,5 | 3,5 | 
| 主教 DS | c1 | e5 | 3 | 中央位置,10 格,攻击 c7 | 0,5 | 3,5 | 
| 皇后 | d1 | f3 | 9 | 配合 Bg2 的电池,防守 Ne5,X 射线攻击 b7 | 1 | 11 | 
| 国王 | e1 | h1 | 0 | 被 Bb6 在 a7-g1 对角线上 X 射线攻击 | -0,5 | -0,5 | 
| 主教 WS | f1 | g2 | 3 | 支援 Qf3 防守与攻击 | 0,5 | 3,5 | 
| 骑士 | g1 | x | 0 | 被吃掉 | 0 | 0 | 
| 车 | h1 | x | 0 | 被吃掉 | 0 | 0 | 
| 29 | 5 | 34 | ||||
| 白方:34 | 
白方的位置价值为 34。
| 白方 | 34 | |||||
|---|---|---|---|---|---|---|
| 黑方 | 33,7 | |||||
| 初始位置 | 位置 | 价值 | 质量值 | 总价值 | ||
| 兵 | a7 | a7 | 1 | a7-b7 小兵岛 | 0,05 | 1,05 | 
| 兵 | b7 | b7 | 1 | a7-b7 小兵岛 | 0,05 | 1,05 | 
| 兵 | c7 | x | 0 | 被吃掉 | 0 | 0 | 
| 兵 | d7 | x | 0 | 被吃掉 | 0 | 0 | 
| 兵 | e7 | f5 | 1 | 叠加,2 格 | 0 | 1 | 
| 兵 | f7 | f7 | 1 | 0 | 1 | |
| 兵 | g7 | g6 | 1 | 防守 f5 但放弃 Kg8 | 0 | 1 | 
| 兵 | h7 | h5 | 1 | 前进良好,配合 f5,g6 | 0,1 | 1,1 | 
| 车 | a8 | d8 | 5 | 半开放的 d 文件,攻击 Nd5 | 2 | 7 | 
| 骑士 | b8 | x | 0 | 被吃掉 | 0 | 0 | 
| 主教 DS | c8 | b6 | 3 | 攻击 d4,3 格 | 0,5 | 3,5 | 
| 皇后 | d8 | e6 | 9 | 攻击 d4, e5,略显拥挤 | 1,5 | 10,5 | 
| 国王 | e8 | g8 | 0 | f6,h6, g7,h8 受到攻击 | -1 | -1 | 
| 主教 WS | f8 | x | 0 | 被吃掉,白方失去主教对 | 0.5 | 0.5 | 
| 骑士 | g8 | e8 | 3 | 防守 c7,f6,g7 | 1 | 4 | 
| 车 | h8 | f8 | 5 | 退出游戏 | -2 | 3 | 
| 31 | 2,7 | 黑方:33,7 | 
黑方的价值是 33.7。
所以白方以 34 – 33.7 = 0.3 获胜。
评估系统可以通过两个麦卡洛克-皮茨神经元轻松表示,一个用于黑方,一个用于白方。每个神经元有 30 个权重 = {w[1],w[2] … w[30]},如前表所示。两个神经元的总和需要一个激活函数,将评估值转换为 1/100 的棋子,这就是国际象棋的标准计量单位。每个权重将是方格和棋子计算的输出。然后,MDP 可以应用到贝尔曼方程中,使用一个随机生成的可能位置。
现今的国际象棋引擎采用这种暴力计算的方法。它们不需要更多的东西就能击败人类。
没有任何人类,即使是世界冠军,也无法以这种精度计算这些位置。需要考虑的参数数量每次都会让他们感到不堪重负,尤其当他们面对这样的局面时。然后,他们会带着或多或少的随机想法去走棋。与国际象棋引擎对弈的成功几率有时像是买彩票一样。国际象棋专家会在与强大棋引擎对弈时发现这一点,看看游戏如何展开。玩家们现在倾向于在被问及为何做出一个有争议的走法时,暴露出自己在提供深度分析上的无能。通常需要几个小时来回顾一局棋,分析其中的组合并找出错误走法的原因。最终,玩家们通常会借助机器来帮助他们理解发生了什么。
这里分析的位置仅代表一种可能性。国际象棋引擎会测试数百万种可能性。而人类只能测试其中的一小部分。
这样的结果测量与人类的自然思维无关。只有机器才能像这样思考。国际象棋引擎不仅能解决这个问题,而且是无法被打败的。
原则 1:在某些情况下,人类面临的问题只有机器才能解决。
原则 2:有时,可以验证机器学习系统的结果,有时则不能。然而,我们必须努力找到验证结果的方法。
解决原则 2 问题的一种方法是通过随机样本使用监督算法验证无监督算法。
使用监督学习来评估超越人类分析能力的结果
更常见的是,AI 解决方案超出了人类在细节分析上的能力。人类往往很难理解机器为了得出结论所做的数百万次计算,并解释其中的过程。为了解决这个问题,另一种 AI、机器学习或深度学习算法将提供辅助 AI 能力。
假设如下情况:
- 
通过第二章,构建奖励矩阵 – 设计数据集中的神经网络方法预处理的原始数据运行良好。奖励矩阵看起来没问题。 
- 
基于 MDP 的贝尔曼方程提供了良好的强化学习训练结果。 
- 
收敛函数和数值有效。 
- 
在该数据集上的结果看起来令人满意,但结果仍然受到质疑。 
管理员或用户总会提出一个难题:如何证明这个方法在未来处理其他数据集时也有效,并且能够 100%确认结果的可靠性?
唯一能确保整个系统有效的方法是运行成千上万的数据集,涵盖数十万的产品流。
现在的想法是使用监督学习创建一种独立的方式来检查结果。一种方法是使用决策树来可视化解决方案的一些关键方面,从而能够安抚用户和自己,确保系统的可靠性。
决策树提供了一种白盒方法,具有强大的功能。在本节中,我们将限制探索为一种直观的方法。在第五章,如何使用决策树增强 K-Means 聚类中,我们将深入探讨决策树和随机树的理论,并探索更复杂的示例。
在此模型中,输入的特征将被分析,以便我们进行分类。该分析可以根据实时数据转换为决策树,创建分布表示来预测未来结果。
对于本节内容,你可以运行以下程序:
Decision_Tree_Priority_classifier.py
或者在 Google Colaboratory 上运行以下 Jupyter notebook:
DTCH03.ipynb
Google Colaboratory 可能已经安装了以下两个软件包:
import collections       # from Python library container datatypes
import pydotplus         # a Python Interface to Graphviz's Dot language.(dot-V command line 
这可以帮助你避免在本地安装它们,如果你收到 Graphviz 依赖的提示信息,这样做可能会节省一些时间。
两个程序生成相同的决策树图像:
warehouse_example_decision_tree.png
该决策树方法的直观描述分为 5 个步骤:
步骤 1:表示进入仓库存储的订单特征,例如:
features = [ 'Priority/location', 'Volume', 'Flow_optimizer' ] 
在这种情况下,我们将模型限制为三个属性:
- 
优先级/位置,这是该模型中仓库流程中最重要的属性 
- 
运输的体积 
- 
优化优先级 – 财务和客户满意度属性 
步骤 2:为学习数据集提供优先级标签:
Y = ['Low', 'Low', 'High', 'High', 'Low', 'Low'] 
步骤 3:提供数据集输入矩阵,即强化学习程序的输出矩阵。虽然数值已被近似,但足以运行模型。它们模拟了决策过程中的一些中间决策和转换(应用的比例、不确定性因子以及其他参数)。输入矩阵为 X:
X = [[256, 1,0],
     [320, 1,0],
     [500, 1,1],
     [400, 1,0],
     [320, 1,0],
     [256, 1,0]] 
步骤 1 中的特征适用于每一列。
步骤 2 中的数值适用于每一行。
第三列 [0,1] 的数值是训练会话中的离散指示符。
步骤 4:运行标准决策树分类器。此分类器将把表示(分布式表示)分为两类:
- 
高优先级订单的属性 
- 
低优先级订单的属性 
有许多类型的算法。在这种情况下,调用一个标准的sklearn函数来完成任务,如下所示的源代码:
classify = tree.DecisionTreeClassifier()
classify = classify.fit(X,Y) 
步骤 5:可视化将订单分为优先级组。可视化树是可选的,但提供了一种流行的白盒方法。你将需要使用:
- 
import collections,一个 Python 容器库。
- 
import pydotplus,一个 Python 接口,用于 Graphviz 的 dot 语言。你可以选择直接使用 Graphviz 并与其他版本的源代码结合使用。
源代码将获取决策树的节点和边,绘制它们,并将图像保存为文件,如下所示:
info = tree.export_graphviz(classify,feature_names=features,
    out_file=None, filled=True,rounded=True)
graph = pydotplus.graph_from_dot_data(info)
edges = collections.defaultdict(list)
for edge in graph.get_edge_list():
    edges[edge.get_source()].append(int(edge.get_destination()))
for edge in edges:
    edges[edge].sort()
    for i in range(2):
        dest = graph.get_node(str(edges[edge][i]))[0]
graph.write_png(<your file name here>.png) 
该文件将包含这个直观的决策树:

图 3.3:决策树
该图片生成以下信息:
- 
一个表示为图形的决策树,包含节点(框)和边(线)。 
- 
当gini=0 时,该框为叶子节点;树将不再继续生长。 
- 
gini表示基尼不纯度。从直观层面来看,基尼不纯度将集中在最高的基尼不纯度值上,以分类样本。我们将在第五章《如何使用决策树增强 K 均值聚类》中深入探讨基尼不纯度的理论。 
- 
samples = 6。训练数据集中有六个样本: - 
优先级/位置 <=360.0 是可以可视化的最大分割点: X = [[256, 1,0], [320, 1,0], [500, 1,1], [400, 1,0], [320, 1,0], [256, 1,0]]
- 
错误的箭头指出了两个不符合<=360 的值。那些被分类为 True的值被认为是低优先级值。
 
- 
几次运行后,用户将习惯于将决策过程视为一个白盒,并且信任该系统。
每个机器学习工具都适用于特定情境中的特殊需求。在下一章《通过 K 均值聚类优化解决方案》中,我们将探讨另一种机器学习算法:k 均值聚类。
总结
本章区分了机器智能和人类智能。像机器一样解决问题意味着使用一系列数学函数和属性。机器智能在许多领域超越了人类。
在机器学习和深度学习的深入探索中,你会发现许多数学函数解决了核心问题。与令人震惊的宣传相反,依赖于 CPU 的数学正在取代人类,而不是某种神秘的意识智能。
机器学习的力量超越了人类的数学推理。它使得机器学习在其他领域的推广变得更加容易。一个数学模型,不受人类情感困扰的复杂性影响,使得在多个领域部署相同的模型变得更简单。本书前三章的模型可以应用于自动驾驶汽车、无人机、仓库机器人、调度优先级等诸多领域。尽可能设想这些模型可以应用到的多个领域。
评估与测量是机器学习和深度学习的核心。关键因素是不断监测系统产生的结果与其必须达到的目标之间的收敛性。算法参数的持续适应,为达成目标打开了大门。
当一个人类被一个无监督的强化学习算法超越时,决策树可以为人类智慧提供宝贵的帮助。
下一章,通过 K-Means 聚类优化解决方案,将进一步探讨机器智能。
问题
- 
人类能够击败国际象棋引擎吗?(是 | 否) 
- 
在处理大量数据时,人类凭直觉比机器更能准确估计决策。(是 | 否) 
- 
构建一个具有 Q 函数的强化学习程序本身就是一项成就。之后使用其结果则毫无意义。(是 | 否) 
- 
有监督学习的决策树功能可以用来验证无监督学习过程的结果,确保其能产生可靠、可预测的结果。(是 | 否) 
- 
强化学习程序的结果可以通过提供优先级作为输入,应用于调度系统。(是 | 否) 
- 
人工智能软件能像人类一样思考吗?(是 | 否) 
进一步阅读
- 
欲了解更多关于决策树的内容: youtu.be/NsUqRe-9tb4
- 
欲了解更多关于国际象棋分析的内容,专家如 Zoran Petronijevic(我曾与他讨论过本章内容): chessbookreviews.wordpress.com/tag/zoran-petronijevic/,www.chess.com/fr/member/zoranp
- 
欲了解更多关于 AI 国际象棋程序的内容: deepmind.com/blog/article/alphazero-shedding-new-light-grand-games-chess-shogi-and-go
第四章:使用 K-均值聚类优化你的解决方案
无论我们知道多少,关键点是能够交付一个人工智能(AI)解决方案。实现一个机器学习(ML)或深度学习(DL)程序仍然很困难,随着技术按指数级进步,它将变得越来越复杂。
设计 AI 系统没有简单或轻松的方法。一个系统要么高效,要么不高效,而不仅仅是轻松或不轻松。设计的 AI 解决方案要么在现实生活中提供实际的用途,要么就会变成一个在超出其训练集范围的各种环境中无法工作的程序。
本章并不涉及如何构建一个尽可能复杂的系统来炫耀我们的知识和经验。它直面现实生活中的交付难题,并探讨克服障碍的方法。例如,没有合适的数据集,你的项目永远无法起步。即使是无监督的机器学习程序,也需要某种形式的可靠数据。
道路、火车、飞机、仓库,以及越来越多的外层空间的运输路线都需要经过精心调试的机器学习(ML)算法。电子商务的惊人扩展带来了巨大的仓库运输需求,需要自动引导车辆(AGV),然后是无尽的道路、火车或空运,去交付产品。距离计算和优化现已成为许多领域的核心目标。一辆优化仓库距离的 AGV,能够更快地装卸卡车,会使得存储和配送过程对那些期待他们的购买品立即到达的客户来说更为高效。
本章提供了克服日常 AI 项目障碍所需的方法论和工具,重点介绍了 K-均值聚类这一关键的机器学习算法。
本章涵盖以下主题:
- 
设计数据集 
- 
设计矩阵 
- 
降维 
- 
确定训练集的规模 
- 
K-均值聚类 
- 
无监督学习 
- 
训练数据集的数据处理管理 
- 
劳埃德算法 
- 
构建一个 Python K-均值聚类程序 
- 
超参数 
- 
测试数据集与预测 
- 
使用 Pickle 保存和使用机器学习模型 
我们将从如何优化和管理数据集开始讨论。
数据集优化与控制
在某个时刻,经理或客户不可避免地会问 AI 专家,具体需要什么数据来进行机器学习(ML)项目,以及需要的数据格式是什么。提供一个答案将需要一些深入思考和工作。
有人可能会想,为什么数据不能像我们下载现成的用于学习 AI 算法的数据集那样公开。在公司工作中,有安全规则和流程。通常,所需的数据存储在一个或多个服务器上。你不能随意做任何事情。你必须明确你的需求和请求。以 AI 所需的方式获取数据对公司来说是有成本的。你必须为你的请求提供合理的理由。
从设计数据集和选择合适的机器学习模型开始。数据集和机器学习模型将符合优化自动引导车(AGV)距离的基本要求。每个在特定仓库中的 AGV 必须减少从码头(船只可能卸货的地方)到存储区、从一个存储区到另一个区域(例如包装区),以及从存储区到码头的距离。这将降低仓库的总体成本并最大化利润。
设计数据集并选择机器学习(ML)/深度学习(DL)模型
从纸面上看,找到一个合适的 AGV 模型就是最小化它从 A 点到 B 点移动所需的距离。假设我们想将产品从仓库运送到码头。距离之和D可以作为衡量该过程的一种方式:

f(p)表示从仓库位置到码头的动作及其代表的距离。它从你在商店里拿起物品的位置(p),到你出门时商店的门口。你可以想象,如果你从那个位置直接走过去,付款后出门,那就是最短的路线。但是,如果你先拿起产品,在商店里漫游一会儿,然后再出去,那么距离(和时间)就会更长。所有人在商店里漫游的所有距离之和,例如,就是D。
任何自我引导的机器人系统中需要解决的问题可以总结为以下几个要点:
寻找漫游者
机器人如何漫游?它是自动的,通常由高效的机器学习程序引导。但机器人,就像其他任何交通工具一样,常常会遇到障碍。
当机器人遇到障碍时,要么停下,要么等待,要么选择另一条路线。
现在我们有一个范式来进行调查和实施:
- 
检测漫游者 
- 
优化机器人选择 
我们都知道,从 A 地点到 B 地点的最短路径是一条直线。对吧?然而,在仓库中,就像在生活中一样,这并不总是成立!假设你在车里直线行驶从 A 到 B,但却遇到了一场巨大的交通堵塞。可能需要很长时间才能走完相对较短的距离。如果你绕过堵塞,右转并开车绕行,可能节省大量时间。你最后会消耗更多的油,而从 A 到 B 的行驶成本也会上升。你就是一个漫游者。
在现实生活中的交通中,你几乎不能做什么。你不能决定某些路段的车辆只能在特定时段行驶,从 A 点到 B 点的路上。你不能决定让汽车走最小化交通的路线。在现实中,这就意味着告诉司机去另一个商场、餐馆或任何其他类似的地方,以避免交通堵塞。这是行不通的!
但是如果你是一个可以控制所有 AGV 的仓库经理,你能做的事情就很多了。你可以确保 AGV 在非常短的距离内快速到达目的地,然后返回为其他 AGV 腾出空间,从而减少成本。你可以检测到“迷路”的 AGV,并配置你的日程和 AGV,使它们最小化成本并最大化利润。没有利润,就没有仓库。
设计矩阵的批准
计划是首先获取尽可能多的数据,然后选择一个 ML/DL 模型。数据集必须包含 AGV(机器人)在某一天从各个位置到达码头的所有位置数据。这是一个位置到码头的分析。它们的距离会被记录在系统中,提供了一个出色设计矩阵的基础。设计矩阵中的每一行包含不同的示例,每一列是一个特征。以下格式符合需求:
| 索引 | 机器人 # (AGV) | 起始位置 时间戳: yyyy,mm,dd,hh,mm | 结束位置(码头) 时间戳: yyyy,mm,dd,hh,mm | 位置 | 码头编号 | 距离 米 | 
|---|---|---|---|---|---|---|
| 001 | 1 | 年-月-日-时-分 | 年-月-日-时-分 | 80 | 7 | 92 | 
| 002 | 2 | |||||
| 003 | 3 | |||||
| 004 | 4 | |||||
| 005 | 5 | 
设计矩阵是设计 ML 解决方案的最佳方式之一。在这种情况下:
- 
索引:机器人的任务编号 
- 
机器人 #:标识该车辆 
- 
起始时间:机器人离开位置的时间戳 
- 
结束时间:机器人到达等待装载的码头的时间戳 
- 
位置:仓库中应该取货的地方 
- 
距离:从位置到码头的距离,单位为米 
距离在公制系统中以米为单位。公制系统是世界上最可靠的计量系统,因为它采用基数为 10 的计算方式,无需进行单位换算。
一码必须除以 3 才能得到英尺。一英尺必须除以 12 才能得到英寸。为了在更小的单位上工作,可能需要 1/16 英寸。
一米等于 100 厘米,一厘米等于 10 毫米,那么我们可以用 1/100 的毫米,依此类推。
即使你需要以其他单位提供报告,也要使用公制系统进行计算。
获取设计矩阵格式的批准
现实中的实施与使用现成的可下载数据集进行实验不同。企业中的信息获取并不容易。
在这个例子中,在实际情况中,假设:
- 
机器人编号不存储在主机中,而是存储在管理 AGV 的本地系统中。 
- 
在主机中,有一个开始时间,即 AGV 在位置上提取货物的时间,和一个结束时间,即它到达码头的时间。 
- 
位置可以在主机中获得,也可以在码头获取。 
- 
不记录距离。 
必须访问 AGV 本地系统中的数据,以提取 AGV 编号,并将其与主机中的数据关联。
然而,在一个大型组织中,事情并不像看起来那么简单。例如:
- 
从 AGV 引导系统中提取数据在本财年内可能无法实现。那些车辆很昂贵,无法分配额外的预算。 
- 
没有人知道从一个位置到码头的距离。只要 AGV 能准时将正确的产品送到正确的码头,迄今为止没有人关心距离问题。 
- 
主机中的 AGV 任务代码与本地 AGV 引导系统中的代码不同,因此在没有开发的情况下无法将其合并到数据集中。 
一个 AI 项目,像任何其他项目一样,可以在短时间内失去动力。如果一个项目停滞不前,它可能就会被搁置。设计数据集需要想象力和应变能力。
让一个 AI 项目保持活力意味着要快速推进。
如果项目进展不快,它将失去动力。项目的参与者将转向其他进展更快的项目,以推动他们的公司和职业发展。
假设你的项目停滞了,因为没有人能提供你需要的距离数据来构建模型。如果你有开始时间、结束时间和速度,那么你可以绕过这个问题,自己计算距离。如果你的团队没有迅速找到这个解决方案,项目就会陷入停滞。高层管理会说,团队的成本太高,不应该继续专注于一个停滞不前的项目,无论如何,这个项目可能会马上被搁置。
降维不仅能帮助 AI 模型,它还会使信息收集变得更为容易。
降维
降维可以应用于减少图像中的特征数。例如,3D 图像的每个像素都与一个神经元相连,这个神经元通过某种函数将表示转换成 2D 视图。例如,将彩色图像转换为灰色图像的不同灰度即可完成此操作。完成后,只需将数值减少到例如 1(亮)或 0(暗),就能更轻松地进行网络处理。使用转换为 0 和 1 像素的图像可以使某些分类过程更加高效,就像我们在路上避开一辆车一样。我们只是看到了那个物体并避开它。
我们整天都在做降维。当你在同一楼层的两间办公室之间走动时,你不需要爬楼梯或乘电梯,你并不会想着地球是圆的,你正在走在一条微微弯曲的路径上。
你已经执行了降维操作。你也在执行流形操作。这意味着在本楼层的局部区域,你不需要担心地球的全球曲率。在你的降维表示中的流形视图已经足够让你从办公室走到楼层的另一间办公室。
当你拿起咖啡杯时,你会专注于不把它弄掉,并瞄准杯子的边缘。你不会思考杯子的每一个特征,比如它的大小、颜色、装饰、直径以及杯子里咖啡的确切容量。你只是识别杯子的边缘并拿起它。这就是降维。没有降维,什么也做不成。在那种情况下,你可能需要 10 分钟才能分析杯子并把它拿起来!
当你拿起那杯咖啡时,你会测试它是否过热、过冷,还是正好。你不会往杯子里放一个温度计来精确测量温度。你再次进行了降维操作,忽略了那杯咖啡的其他特征。此外,当你拿起杯子时,你通过仅观察杯子周围的小范围距离来计算一个流形表示,从而减少了周围信息的维度。你不会担心桌子的形状,或者桌子另一侧是否脏了等其他特征。
机器学习(ML)和深度学习(DL)技术,如降维,可以被视为工具,能够在任何领域中加速计算过程。
尽管我们经常将降维与机器学习和深度学习相关联,但降维的概念与数学甚至人类历史一样古老!很久以前,有人去了海滩,看到了美丽的太阳。那个人第一次在人类历史上,在沙滩上画了一个圆圈。这个圆圈不像太阳那样具有三维效果,也没有颜色,但周围的人都感到震惊:
- 
一群人正在观察太阳 
- 
有人把颜色移除 
- 
这个人还把 3D 视图移除 
- 
他们用一个圆圈在更小的维度空间中表示太阳 
- 
第一位数学家诞生了! 
k-means 聚类算法提供了一种高效的方法来表示我们在本章中处理的机器人示例。每个地点将形成一个聚类,下一节将对此进行解释。
解决缺失数据问题的一种方法是使用以下数据格式运行 k-means 聚类算法:
| 索引 | 位置 | 起始位置:时间戳:yyyy,mm,dd,hh,mm | 结束位置:时间戳:yyyy,mm,dd,hh,mm | 
|---|---|---|---|
| 001 | 
训练数据集的体量
在这个模型中,我们将专注于分析六个地点。六个地点选在主仓库内,靠近一组卡车装卸点。考虑到大约 5,000 个样本,这些样本应该代表AGI-AI公司购买的 25 辆 AGV(自动导引车)全天 24 小时运行的工作情况。
现在我们已经讨论了如何优化和控制数据集,接下来让我们来讨论实际解决方案。在下一节中,我们将讲解如何实现 k-means 聚类。
实施 k-means 聚类解决方案
数据集需要经过预处理,以便转换为一个原型,从而证明该项目的财务价值。
在企业环境中,绝对不要实施机器学习解决方案,除非你知道它代表的利润和完成工作的成本。没有利润,公司无法生存。机器学习,像任何其他投资一样,必须提供投资回报率(ROI)。在我们的案例中,机器学习将通过减少 AGV 的行驶距离来降低仓库的运输成本。
愿景
一个涉及机器人的机器学习项目的主要目标可以用一句话总结:通过优化机器人活动找到利润。实现这个目标将获得全面项目的预算。
提供的数据不包含距离。然而,可以按位置估算距离,方法如下:
距离 = (结束时间 – 开始时间)/机器人平均速度
在这个特定的仓库配置中,起始位置通常是靠近码头的装载点。
数据
提供的数据包含开始时间s[t]、结束时间end[t]和交付位置。为了计算距离,我们可以使用以下公式:
di = (end[t] – s[t])/v
- 
v = AGV 每分钟的速度 
- 
end[t] – s[t]的单位是分钟 
- 
d[i] = 估计 AGV 在给定时间内走过的距离 
一个预处理程序将读取初始文件格式和数据,并输出一个新的文件,data.csv,其格式为具有两个特征的降维格式:
| 距离 | 位置 | 
|---|---|
| 55 | 53 | 
| 18 | 17 | 
预处理管理
数据预处理意味着准备将作为系统输入的数据。差的预处理可能会产生两种结果:
- 
含有噪声的坏数据不会产生差异(大数据量和小错误) 
- 
含有噪声的坏数据会影响结果(无论数据量多大,数据都会影响最终结果) 
在这个特定的例子中,假设在提供的 5000 条数据记录中,25 个距离数据不可靠。0.005%的噪声水平不应成为问题。可接受的噪声量取决于每个项目,不能是一个随意的数字。
有时候,噪声会产生深远的影响,有时则不会。假设 5000 条记录中有 2500 条包含噪声,也许剩下的 2500 条记录提供了足够多样的样本,从而得出可靠的结果。另一方面,也许 5000 条记录中缺失了 10 个样本,这就可能导致项目无法进行,因为这 10 个样本是唯一能够影响计算结果的特殊类型。
你需要进行实验并确定给定项目的可接受噪声水平。
让我们动手分析数据吧。
位置编号从#1 开始。#1 靠近产品的装载点。机器人需要将产品带到这个位置。更准确地说,在这个仓库配置中,机器人去取一个箱子(或板条箱)并将其带回位置 1。在位置 1,人工检查产品并进行包装。之后,人工将产品小心地装载到送货卡车上。
从一个位置到下一个位置的距离大约是 1 米。例如,从位置 1 到位置 5,距离约为 5 米或 5 m。此外,由于所有位置在这个模型中都会引导 AGV 到位置 1,理论上的距离将从位置 1 开始计算。为了概括这个规则并定义位置 lj 的距离 d[i],计算可以简化如下:
di = lj
d[i] 以米为单位表示。由于位置编号从 1 到 n,因此位置编号等于从机器人出发的第一个位置的近似距离。
假设通过查看数据,我们很快发现许多距离值大于它们的定位编号。这很奇怪,因为距离应该大致等于位置。因此,通过减少维度的数量并专注于主要特征的近似值,关键概念可以得到表达。
是时候建立一个策略和程序了。
策略
就像所有机器学习项目一样,有一些关键的标准公司指南是不应忽视的:
- 
快速编写一个概念验证(POC)。POC 将证明机器学习解决方案的有效性。在这种情况下,机器人活动将被可视化。 
- 
详细检查结果。 
- 
计算通过尚未找到的解决方案优化后的潜在利润。利润将证明投资是值得的。成本可以作为一个指标。但此后,成本的降低必须足够大,以显著提高给定公司的利润。 
- 
提供充分的案例来获得批准,并为项目争取绿灯。 
现在我们的策略已经明确,我们可以选择一个模型。k-means 聚类是一个适合开始此项目的好算法。它将创建几个聚类,这些聚类几乎字面上代表了自动导引车(AGV)应当位于的位置区域。通过选择简单的维度,视觉表示足够接近现实,用户能够理解计算过程。
k-means 聚类程序
k-means 聚类是一种强大的无监督学习算法。我们在生活中经常进行 k-means 聚类。例如,假设你要为约 50 人的团队组织午餐,这个开放空间恰好能容纳这些人。
你的朋友和另一位朋友首先决定在中间设立一张桌子。你的朋友指出,房间里的人会形成一个大的聚类 k,而只有一个位于几何中心(或质心) c 的桌子,这将不切实际。靠近墙壁的人将无法接触到主桌子,如下图所示。

图 4.1:人们尝试围绕一张桌子聚集的场景
离桌子较远的人(图中间的矩形区域)将不容易接触到桌子。
你现在尝试在不同位置为两组人群 k[1] 和 k[2] 设置两个中心点(质心) c[1] 和 c[2]。
人群x[1]到x[n]构成了数据集X。当想象数据集X时,发现表格的位置不对。
最好的做法是移动表格c,然后估算人群(X的一个子集)到该表格的平均距离将在其所在的组或聚类k内大致相同。其他表格也会按相同方式处理。你可以在地板上画一条线,以确保每个组或聚类与其表格的平均距离大致相同。
这种直观的 k 均值聚类方法可以总结如下:
- 
步骤 1:你已经用粉笔画线,决定每个人x将属于哪个组(聚类k),通过查看该人到表格c的平均距离。 
- 
步骤 2:你已经根据需要调整了表格的位置,以优化步骤 1。 
一个模拟使用 k 均值聚类计算的三表模型的 Python 程序将生成以下结果:

图 4.2:通过 k 均值聚类计算出的三表模型
在提供了直观的例子之后,接下来我们讨论 k 均值聚类的数学定义。
k 均值聚类的数学定义
数据集X提供了N个数据点。这些数据点是通过将距离作为笛卡尔坐标系中的x轴、位置作为y轴来表示的。即使数据经过算法处理和转换,这种低级别的表示方式仍然是一种白盒方法。白盒方法指的是过程透明,我们可以实际看到算法在做什么。黑盒方法则是输入进入系统后,我们仅凭结果无法理解系统的操作。
然而,高级表示方法需要通过聚类表示更多特征。在这种情况下,就无法直接看到实际意义与其机器学习表示之间的联系。我们将在接下来的章节中探讨这些高维表示。
如果你的文件中第一条记录是位于位置 1 的机器人,它将通过黑点表示为x轴=1,y轴=1,如下图所示:

图 4.3:笛卡尔坐标表示
在这个例子中,5,000 条记录从data.csv中加载,文件与程序位于同一目录下。这些数据没有标签,且没有线性可分。目标是将X数据点分配到K个聚类中。聚类的数量是输入值。每个聚类将有其几何中心或质心。如果你决定使用三个聚类K,那么结果将如下所示:
- 
三个聚类K,在视觉表示中采用三种颜色 
- 
三个几何中心或质心,表示该簇中 x 数据点的距离之和的平均中心 
如果你决定有六个簇,那么你将得到六个质心,依此类推。
用数学术语描述,关于  ,
,  的公式如下:
 的公式如下:

每个 k(簇)的成员 x[i] 到 x[n] 的每个簇 K 的位置到几何中心(质心)  的所有距离之和,必须最小化。
 的所有距离之和,必须最小化。
每个成员 x 到质心  的距离越小,系统就越优化。请注意,距离每次都会平方,因为这是算法版本中的欧几里得距离。
 的距离越小,系统就越优化。请注意,距离每次都会平方,因为这是算法版本中的欧几里得距离。
在一维情况下,欧几里得距离是两个点 x 和 y 之间的距离,例如,可以表达如下:

用欧几里得距离表示的 x 和 y 之间的距离,并不是一个自动导引车(AGV)在仓库内实际行驶的距离。本章中构建的模型是为了确保距离足够现实,以便形成良好的簇并改善仓库的组织结构。这是足够的,因为 AGV 经常会从一个货位直线行驶到最近的走道,再到存储点,例如。
为了计算实际的距离,我们常常使用曼哈顿距离。曼哈顿距离是出租车的行驶距离。例如,你先沿着一个街区走,再向左走另一个街区,依此类推,沿途加总各段距离。这是因为你不能穿过建筑物。
在我们的情况下,就像说出租车只能在某个大街上大致上下行驶,像公交车一样,避免右转或左转。
我们将使用欧几里得距离的 Lloyd 算法来估算 AGV 必须保持的簇,以避免它们四处游走。
Lloyd 算法
Lloyd 算法有几种变体。但所有变体都遵循一个共同的哲学。
对于给定的 x[n](数据点),其簇中质心  与其他中心的距离必须小于去其他中心的距离,就像在午餐例子中,一个人希望靠近一张桌子,而不是因为人群拥挤而远去拿三明治。
 与其他中心的距离必须小于去其他中心的距离,就像在午餐例子中,一个人希望靠近一张桌子,而不是因为人群拥挤而远去拿三明治。
对于给定的 x[n],最佳质心  如下所示:
 如下所示:

这个计算对于所有簇 k[1] 到 K 中的所有质心  都会进行。
 都会进行。
一旦每个 x[i] 被分配到一个 K[k],算法就会重新计算  ,方法是计算每个簇中所有点的均值,并重新调整质心
,方法是计算每个簇中所有点的均值,并重新调整质心  。
。
我们现在已经涵盖了开始编码所需的所有概念。让我们开始编写 Python 程序吧!
Python 程序
k-means_clustering_1.py 这个 Python 程序使用了 sklearn 库,pandas 进行数据分析(在本程序中仅用于导入数据),以及 matplotlib 用于绘制结果,展示数据点(数据的坐标)和聚类(每个聚类中被分类的数据点及其颜色)。首先,以下模型被导入:
from sklearn.cluster import KMeans
import pandas as pd
from matplotlib import pyplot as plt 
接下来,我们将逐步介绍实现 k-means 聚类的各个阶段。
1 – 训练数据集
训练数据集包含 5000 行。第一行包含一个用于维护的标题(数据检查),但该行 不 被使用。k-means 聚类是一种 无监督学习 算法,意味着它将未标记的数据分类为带有聚类标签的数据,以进行未来预测。以下代码展示了数据集:
#I. The training Dataset
dataset = pd.read_csv('data.csv')
print(dataset.head())
print(dataset) 
print(dataset) 这一行可以在原型阶段或维护过程中用于检查训练数据(虽然不是必须的)。以下输出确认数据已正确导入:
'''Output of print(dataset)
Distance location
0 80 53
1 18 8
2 55 38
...
''' 
2 – 超参数
超参数决定了计算方法的行为。在这种情况下,需要两个超参数:
- 
k将被计算的聚类数量。这个数字可以并且将在案例研究会议中进行调整,以找出最佳的组织过程,如下节所述。经过几次运行后,我们将直观地将k设置为6。
- 
f – 将被考虑的特征数量。在这种情况下,有两个特征:距离和位置。 
程序实现了一个 k-means 函数,如下代码所示:
#II.Hyperparameters
# Features = 2
k = 6
kmeans = KMeans(n_clusters=k) 
请注意,Features 超参数已被注释。在这种情况下,特征的数量是隐式的,并且由训练数据集的格式决定,该数据集包含两列。
3 – k-means 聚类算法
sklearn 现在使用训练数据集和以下代码行中的超参数完成这项工作:
#III.k-means clustering algorithm
kmeans = kmeans.fit(dataset) #Computing k-means clustering 
gcenters 数组包含几何中心或质心,可以打印出来以进行验证,如下代码片段所示:
gcenters = kmeans.cluster_centers_
print("The geometric centers or centroids:")
print(gcenters)
'''Ouput of centroid coordinates
[[ 48.7986755 85.76688742]
[ 32.12590799 54.84866828]
[ 96.06151645 84.57939914]
[ 68.84578885 55.63226572]
[ 48.44532803 24.4333996 ]
[ 21.38965517 15.04597701]]
''' 
这些几何中心需要通过标签进行可视化,以便用于决策。
4 – 定义结果标签
初始的未标记数据现在可以被分类为聚类标签,如以下代码所示:
#IV.Defining the Result labels
labels = kmeans.labels_
colors = ['blue','red','green','black','yellow','brown','orange'] 
颜色可以用于超越简单显示标签的语义目的。例如,可以为每个主要客户或领先产品分配一种颜色。
5 – 显示结果 – 数据点和聚类
为了使团队或管理层能够理解,程序现在准备将结果显示为 数据点 和 聚类。数据将以坐标的形式表示,而聚类则以颜色表示,每个聚类都有一个 几何中心 或 质心,如以下代码所实现:
#V.Displaying the results : datapoints and clusters
y = 0
for x in labels:
    plt.scatter(dataset.iloc[y,0], dataset.iloc[y,1],color=colors[x])
    y+=1
for x in range(k):
    lines = plt.plot(gcenters[x,0],gcenters[x,1],'kx')
title = ('No of clusters (k) = {}').format(k)
plt.title(title)
plt.xlabel('Distance')
plt.ylabel('Location')
plt.show() 
数据集现在已经准备好进行分析。数据已被转换为数据点(笛卡尔坐标点)和聚类(颜色)。x 点代表几何中心或质心,如下图所示:

图 4.4:输出(数据点和集群)
测试数据集和预测
在这种情况下,测试数据集有两个主要功能。首先,一些测试数据验证了训练后并已标记数据集的预测水平。输入数据包含随机距离和位置。以下代码实现了预测数据点所属集群的输出:
#VI.Test dataset and prediction
x_test = [[40.0,67],[20.0,61],[90.0,90],
          [50.0,54],[20.0,80],[90.0,60]]
prediction = kmeans.predict(x_test)
print("The predictions:")
print (prediction)
'''
Output of the cluster number of each example
[3 3 2 3 3 4]
''' 
第二个目的,将是在未来为决策目的输入数据,如下节所述。
保存和加载模型
在本节中,k-means_clustering_1.py将使用 Pickle 保存模型。Pickle 是一个 Python 库,将模型保存在一个序列化文件中,如程序结尾所示:
# save model
filename="kmc_model.sav"
pickle.dump(kmeans, open(filename, 'wb')) 
Python 的 Pickle 模块在程序头部导入:
import pickle 
现在,模型kmeans已保存为名为kmc_model.sav的文件。
为了测试该模型,我们现在打开k-means_clustering_2.py,加载模型并进行预测,而不涉及任何训练:
#load model
filename="kmc_model.sav"
kmeans = pickle.load(open(filename, 'rb')) 
kmc_model.save被加载并插入到名为kmeans的分类器中。
x_test与k-means_clustering_1.py中的测试数据相同:
#test data
x_test = [[40.0,67],[20.0,61],[90.0,90],
          [50.0,54],[20.0,80],[90.0,60]] 
现在,我们运行并展示预测结果:
#prediction
prediction = kmeans.predict(x_test)
print("The predictions:")
print (prediction) 
预测结果与k-means_clustering_1.py中的相同:
The predictions:
[0 0 4 0 0 1] 
每个预测是一个输出集群编号,从 0 到 5,对应于作为输入的坐标。例如,[40.0,67]属于集群#0。
下一步是分析结果。
分析结果
以下图像显示了收益区。收益区是距离超过 80 的区域。

图 4.5:收益区
收益区提供了有用的信息。
根据计算结果,收益区显示了在展示位置上的损失。它考虑了可能位置的样本。总距离的 10%可能会被节省。
原因在于机器人并没有直接前往正确的位置,而是在未规划的障碍物周围徘徊。
从一个位置到另一个位置的平均距离是 1 米。自动导引车(AGV)都从位置 0 或 1 开始。因此,在这个特定示例中,距离与位置严格成正比。
要找出某个位置的收益区,您可以从位置 80 画一条红色水平线,并从距离 80 画一条垂直线(可以加上几米来考虑小的变化)。
数据可视化使得数据分析变得更加简便。通过可视化集群,管理层更容易理解输出结果并做出决策。
80 位置线上的任何数据点都不应超过最大限制。该限制为 80 米 + 几米的小偏差。在该线的右侧,公司正在损失资金,必须采取措施优化距离。这个损失区域是项目的收益区域。k 均值聚类结果显示,40 到 60 位置的一些位置超过了 80 米的距离。
作为解决方案的机器人虚拟集群
规划者预计机器人任务。他们将它们发送到可能的位置,从那里他们将不得不接收产品并将其带回卡车装载点。
在下面的示例中,我们将以分配给位置 40 到 60 区域的 AGV 为例。例如,如果 AGV 进一步到达 70 位置,那么其性能将增加 10 虚拟(估计)米的惩罚。这很容易检查。如果检测到 AGV 位于 70 位置,则它已经超出了其区域。
分配给位置 40 到 60 的 AGV 的业务规则是,它不能超过 60 位置。如果计划事件的软件运行良好,它将不会分配 AGV 到超过 60 位置的区域。因此,必须向规划者提供业务规则。
解决方案之一是提供 AGV 虚拟集群作为业务规则,如下截图所示:

图 4.6:AGV 虚拟集群
规则如下:
- 
规则 1:中间的线代表一个新的业务规则。在项目的第一阶段,用于位置 40 到 60 的 AGV 不能超过 60 米加一个小的偏差线。 
- 
规则 2:一个集群将代表 AGV 的取货区。质心现在将是其停车区。直到所有集群都遵守规则 1 为止,将优化距离。如果不遵循规则 1,则 AGV 将行驶不必要的距离,增加了仓库中货物运输的总成本。 
k 均值聚类算法的实施限制
在本章中,探索了一个示例。随着体积的增加,特征达到高级抽象表示,并且噪声污染数据,人类面临几个问题:
- 
如何分析超出人类分析能力的结果? 
- 
对于可能包含被忽视的特征的更大数据集,该算法是否可靠? 
在第五章《如何使用决策树增强 k 均值聚类》中,我们将探讨这些问题并找到解决方案。
总结
到目前为止,我们已经使用了 Python 的 NumPy、TensorFlow、scikit-learn、pandas 和 Matplotlib 库进行了探索。本书将使用更多的平台和库。在未来的几个月和几年里,市场上将出现更多的语言、库、框架和平台。
然而,AI 不仅仅是关于开发技术。从零开始构建一个 k-means 聚类程序需要仔细的规划。该程序依赖于我们期望的、但往往难以获得的数据。这时,我们的想象力就显得格外重要,用来为我们的数据集找到合适的特征。
一旦数据集被定义,数据条件不良可能会危及项目。一些数据的小变化会导致错误的结果。
从零开始准备训练数据集比我们最初预期的要花费更多时间。AI 的设计初衷是为了让生活更轻松,但那是在项目成功实施之后。问题在于,构建一个解决方案需要大量的数据集工作和持续的监控。
然后就到了编写 k-means 聚类解决方案的艰苦工作,这需要向团队解释。Lloyd 算法通过减少开发时间在这方面非常有用。
在下一章,何时以及如何使用人工智能,我们将通过数据集技术寻找解决 k-means 聚类问题的方案。我们还将探索随机森林,并进入集成元算法的世界,这将为人类提供辅助 AI,以分析机器思维。
问题
- 
在企业环境中,是否可以使用随机数据构建原型?(是 | 否) 
- 
设计矩阵是否包含每个矩阵一个示例?(是 | 否) 
- 
AGV 永远不会普及。(是 | 否) 
- 
k-means 聚类能应用于无人机交通吗?(是 | 否) 
- 
k-means 聚类能应用于预测吗?(是 | 否) 
- 
Lloyd 算法是一种两步走的方法。(是 | 否) 
- 
超参数是否控制算法的行为?(是 | 否) 
- 
一旦程序可以运行,展示方式就不再重要。(是 | 否) 
- 
k-means 聚类仅仅是一个分类算法。它不是预测算法。(是 | 否) 
进一步阅读
- 
scikit-learn 网站提供了关于 k-means 聚类的更多信息: scikitlearn.org/stable/modules/generated/sklearn.cluster.KMeans.html
- 
你可以在这里找到 Python 的数据分析库: pandas.pydata.org/
第五章:如何使用决策树增强 K 均值聚类
本章讨论了两个关键问题。首先,我们将探索如何在数据集超出给定算法处理能力时实现 k-means 聚类。其次,我们将实现决策树,验证超越人类分析能力的机器学习算法的结果。我们还将探索随机森林的使用。
在面对这样复杂的问题时,选择适合任务的模型往往是机器学习中最具挑战性的任务。当我们面对一组陌生的特征来表示时,这可能会让人感到困惑。然后我们必须亲自动手,尝试不同的模型。一个高效的估算器需要良好的数据集,这可能会改变项目的方向。
本章基于第四章《使用 K 均值聚类优化你的解决方案》中开发的 k-means 聚类(或 KMC)程序。我们将解决大数据集的问题。这次探索将带领我们进入大数法则(LLN)、中心极限定理(CLT)、蒙特卡罗估计器、决策树和随机森林的世界。
在本章所描述的过程中,人工干预不仅是多余的,而且是不可能的。机器智能在许多情况下超越了人类,而且由于现实生活系统的复杂性和不断变化的特性,给定问题的复杂性往往超出了人类的能力。得益于机器智能,人类可以处理越来越多的数据,否则这些数据将是无法管理的。
使用我们的工具包,我们将构建一个无需人工干预的算法结果分析解决方案。
本章涉及以下主题:
- 
使用 KMC 进行无监督学习 
- 
确定是否必须使用 AI 
- 
数据量问题 
- 
定义 KMC 的 NP 难度特性 
- 
关于大数法则(LLN)、中心极限定理(CLT)和蒙特卡罗估计器的随机抽样 
- 
打乱训练数据集 
- 
使用决策树和随机森林进行有监督学习 
- 
将 KMC 与决策树连接起来 
本章从无监督学习与 KMC 开始。我们将探索避免通过随机抽样运行大数据集的方法。KMC 算法的输出将为有监督的决策树算法提供标签。决策树将验证 KMC 过程的结果,这是人类在处理大量数据时无法做到的任务。
本章中的所有 Python 程序和文件都可以在github.com/PacktPublishing/Artificial-Intelligence-By-Example-Second-Edition/tree/master/CH05中找到。
还有一个名为COLAB_CH05.ipynb的 Jupyter notebook,其中包含所有 Python 程序,可以一次性运行。你可以直接将其上传到 Google Colaboratory(colab.research.google.com/),使用你的 Google 帐户进行操作。
使用 KMC 进行无监督学习和大数据集处理
KMC 使用未标注数据并形成数据点的聚类。这些聚类的名称(整数)为接下来运行监督学习算法(如决策树)提供了基础。
在这一节中,我们将学习如何在大数据集上使用 KMC。
当面对一个包含大量未标注数据集的项目时,第一步是评估机器学习是否可行。在一本关于人工智能的书中避免使用人工智能可能看起来有些自相矛盾。然而,在人工智能领域,就像在现实生活中一样,你应该在合适的时机使用合适的工具。如果人工智能不是解决问题的必要手段,就不要使用它。
使用概念验证(POC)方法来验证某个 AI 项目是否可行。POC 的成本远低于整个项目,且有助于建立一个相信最终成果的团队。或者,POC 可能会显示继续推进机器学习解决方案太过冒险。不可解的问题是存在的,最好避免花费数月的时间在一个无法成功的方案上。
第一步是探索数据量和将要使用的机器学习估算模型。
如果 POC 证明某个特定的机器学习算法能够解决眼前的问题,接下来的步骤就是解决数据量问题。POC 展示了模型在样本数据集上的有效性。现在,实施过程可以开始了。
任何在笔记本电脑上运行过大数据集机器学习算法的人都知道,机器学习程序需要一定的时间来训练和测试这些样本。一个机器学习程序或深度学习卷积神经网络需要消耗大量的计算机算力。即便你使用GPU(即图形处理单元)运行人工神经网络,期望能比 CPU 获得更好的性能,它仍然需要大量时间来完成所有学习周期。一个周期(epoch)意味着我们已经尝试了一组权重,例如,用来衡量结果的准确度。如果准确度不够,我们就会运行另一个周期,尝试其他权重,直到准确度足够。
如果你继续进行并希望在超过 1,000,000 个数据点的数据集上训练程序,例如,你将消耗大量本地计算机资源。
假设你需要在一个拥有数亿到数十亿条记录的公司中使用 KMC 算法,这些数据来自多个 SQL Server 实例、Oracle 数据库和大数据源。例如,假设你正在为一家领先的手机公司做电话运营活动。你必须应用 KMC 程序来分析一年中全球各地的电话通话时长。这代表着每天有数百万条记录,一年累计达到数十亿条记录。
即使 KMC 训练程序能够运行数十亿条记录,消耗的 CPU/GPU 也会非常大,并且即使成功运行也会耗费大量时间。更重要的是,十亿条记录可能只代表了不足够的特征。添加更多的特征将大大增加数据集的大小。
现在的问题是,KMC 是否能够处理如此大的数据集。KMC 问题是 NP-hard。P 代表 多项式,N 代表 非确定性。
解决我们体积问题需要一些理论上的考虑。我们需要识别我们所面临问题的难度。
识别问题的难度
我们首先需要理解我们正在处理的难度级别。一个有用的概念是 NP-hard。
NP-hard——P 的含义
NP-hard 中的 P 意味着解决或验证 P 问题的时间是多项式的(poly=多,nomial=项)。例如,x³ 是一个多项式。N 表示问题是非确定性的。
一旦 x 已知,则 x³ 会被计算出来。对于 x = 3,000,000,000,只需要 3 次基本计算,结果是:
log x³ = 28.43
计算这个特定问题需要 10^(28.43) 次计算。
这看起来很可怕,但有两个原因它并不那么可怕:
- 
在大数据的世界里,这个数字可以通过大规模的随机抽样来处理。 
- 
KMC 可以通过小批量(数据集的子集)训练来加速计算。 
多项式时间意味着此时间大致与输入的大小成正比。即使训练 KMC 算法所需的时间仍然有些模糊,只要验证解决方案所需的时间因输入的批量大小而保持成正比,问题仍然是多项式的。
指数算法随着数据量增加,而不是计算次数增加。例如,这个例子的指数函数是 f(x) = 3^x = 3^(3,000,000,000) 次计算。这样的函数通常可以拆分为多个经典算法。这类函数在企业界存在,但它们超出了本书的范围。
NP-hard——非确定性含义
非确定性问题需要启发式方法,这意味着某种形式的启发式,例如试错法。我们试一组权重,例如,评估结果,然后继续,直到找到令人满意的解决方案。
“困难”的含义
NP-hard 可以通过一些优化转化为 NP 问题。这意味着 NP-hard 与 NP 问题一样难,甚至更难。
例如,我们可以使用批量来控制输入的大小、计算时间和输出的大小。这样,我们可以将 NP-hard 问题降为 NP 问题。
创建批量以避免在数据集过大时运行算法的一种方法是使用随机抽样。
实现带有小批量的随机抽样
机器学习和深度学习的一个重要部分包含了各种形式的随机抽样。在这种情况下,训练集如果包含数十亿个元素,使用随机抽样将是不可或缺的,否则实现起来将极为困难,甚至不可能。
随机抽样在许多方法中都有应用:蒙特卡洛法、随机梯度下降、随机森林以及许多算法。无论采样方法的名称是什么,它们都有共同的概念,具体程度取决于数据集的大小。
在大数据集上进行随机抽样可以产生良好的结果,但它需要依赖大数法则(LLN),我们将在下一部分进行探讨。
使用大数法则(LLN)
在概率论中,大数法则(LLN)指出,当处理大量数据时,重要的样本足够有效,可以代表整个数据集。例如,我们都熟悉使用小数据集的民意调查。
这一原则,和所有原则一样,有其优点和局限性。但无论局限性如何,这一法则适用于日常的机器学习算法。
在机器学习中,抽样类似于民意调查。较少的个体代表了更大的总体数据集。
对小批量进行抽样并求其平均值,可以与计算整个数据集的效率相当,只要应用了科学方法:
- 
使用小批量或数据子集进行训练 
- 
使用某种形式的估计器来衡量训练过程的进展,直到达成目标为止 
你可能会惊讶地看到“直到达成目标”为止,而不是“直到达到最优解”为止。
最优解可能并不代表最佳解。所有特征和所有参数通常并未完全表达。找到一个好的解决方案通常就足以有效地进行分类或预测。
大数法则(LLN)解释了为什么随机函数在机器学习和深度学习中被广泛使用。如果随机样本遵循中心极限定理(CLT),它们将提供高效的结果。
中心极限定理(CLT)
大数法则(LLN)应用于 KMC 项目示例时,必须通过随机抽样提供一个合理的重心集合。如果重心正确,那么随机样本就是可靠的。
重心是数据集的几何中心,正如第四章中所解释的,使用 K-Means 聚类优化你的解决方案。
这种方法现在可以扩展到中心极限定理(CLT),该定理指出,当训练大型数据集时,使用小批量样本的子集就足够了。以下两个条件定义了中心极限定理(CLT)的主要特性:
- 
子集(小批量)数据点之间的方差保持在合理范围内。 
- 
带有小批量方差的正态分布模式接近整个数据集的方差。 
例如,蒙特卡洛估计器可以提供一个良好的基础,判断样本是否符合中心极限定理(CLT)。
使用蒙特卡洛估计器
“蒙特卡罗”这个名字来源于蒙特卡罗的赌场和赌博。赌博是一个很好的无记忆随机例子。无论赌徒在玩之前发生什么,先前的知识都不会提供任何洞察。例如,赌徒玩了 10 局,输了几局,赢了几局,形成了一个概率分布。
计算F(x)的分布总和。然后从数据集中提取随机样本,例如,x[1]、x[2]、x[3],...,x[n]。
f(x)可以通过以下方程进行估算:

估计量  代表了 KMC 算法或任何已实现模型的预测结果的平均值。
 代表了 KMC 算法或任何已实现模型的预测结果的平均值。
我们已经看到,数据集的一个样本可以代表完整的数据集,就像选举时,一群人可以代表整个选民群体一样。
既然我们可以放心地使用随机样本,就像在选举时对选民群体进行民意调查一样,现在我们可以直接处理整个大数据集,或者最好是使用随机样本。
尝试训练完整的训练数据集
在第四章,《通过 K 均值聚类优化解决方案》中,采用六个聚类配置的 KMC 算法生成了六个质心(几何中心),如下所示:

图 5.1:六个质心
现在的问题是,如何避免使用昂贵的机器资源来训练这个 KMC 数据集,特别是在处理大数据集时。解决方案是像选举时对选民群体进行民意调查一样,从数据集中提取随机样本。
训练训练数据集的一个随机样本
sampling/k-means_clustering_minibatch.py 程序提供了一种验证迷你批次解决方案的方法。
程序首先通过以下代码加载数据:
dataset = pd.read_csv('data.csv')
print (dataset.head())
print(dataset) 
加载数据集可能会出现两个问题:
- 
数据集太大,无法一次性加载。 在这种情况下,按批次加载数据集。使用这种方法,你可以在多个批次上测试模型,以微调解决方案。 
- 
数据集可以加载,但所选择的 KMC 算法无法处理这么大的数据量。 选择合适的迷你批次大小将解决这个问题。 
一旦数据集被加载,程序将开始训练过程。
将使用蒙特卡罗大数据量原理随机创建一个迷你批次数据集,迷你批次大小为 1,000。蒙特卡罗方法在机器学习中有许多变体。对于我们的示例,使用随机函数来创建迷你批次就足够了:
n=1000
dataset1=np.zeros(shape=(n,2))
for i in range (n):
    j=randint(0,4998)
    dataset1[i][0]=dataset.iloc[j,0]
    dataset1[i][1]=dataset.iloc[j,1] 
最后,KMC 算法按标准方式运行,如下所示:
#II.Hyperparameters
# Features = 2 :implicit through the shape of the dataset (2 columns)
k = 6
kmeans = KMeans(n_clusters=k)
#III.K-means clustering algorithm
kmeans = kmeans.fit(dataset1) #Computing k-means clustering
gcenters = kmeans.cluster_centers_ # the geometric centers or centroids
print("The geometric centers or centroids:")
print(gcenters) 
以下截图显示了生成的结果,类似于在第四章,《通过 K 均值聚类优化解决方案》中由 KMC 训练的完整数据集:

图 5.2:输出(KMC)
得到的质心是一致的,如下所示:
The geometric centers or centroids:
[[ 19.6626506 14.37349398]
 [ 49.86619718 86.54225352]
 [ 65.39306358 54.34104046]
 [ 29.69798658 54.7852349 ]
 [ 48.77202073 23.74611399]
 [ 96.14124294 82.44067797]] 
由于这是一个随机过程,输出在每次运行时会略有不同。在本节中,我们将数据集分解为随机样本以优化训练过程。另一种执行随机采样的方法是在训练前对数据集进行洗牌。
洗牌作为另一种执行随机采样的方法
sampling/k-means_clustering_minibatch_shuffling.py程序提供了另一种解决随机采样方法的方式。
KMC 是一种无监督训练算法。因此,它训练的是无标签数据。单次随机计算不会消耗大量的机器资源,但连续多个随机选择则会。
洗牌可以减少机器消耗的成本。像在扑克游戏开始前洗牌一样,在开始训练之前对数据进行适当的洗牌,可以避免重复和随机的小批量计算。在此模型中,加载数据阶段和训练阶段不变。然而,我们并不是对dataset1这个小批量数据集做一次或几次随机选择,而是在开始训练之前对整个数据集进行一次洗牌。以下代码展示了如何洗牌数据集:
sn=4999
shuffled_dataset=np.zeros(shape=(sn,2))
for i in range (sn):
    shuffled_dataset[i][0]=dataset.iloc[i,0]
    shuffled_dataset[i][1]=dataset.iloc[i,1] 
然后我们选择前 1000 个洗牌后的记录进行训练,如以下代码片段所示:
n=1000
dataset1=np.zeros(shape=(n,2))
for i in range (n):
    dataset1[i][0]=shuffled_dataset[i,0]
    dataset1[i][1]=shuffled_dataset[i,1] 
以下截图中的结果对应于完整数据集和随机小批量数据集样本的结果:

图 5.3:完整与随机小批量数据集样本
产生的质心可以提供第一层结果,以确认模型,如以下输出所示。
几何中心或质心:
[[ 29.51298701 62.77922078]
 [ 57.07894737 84.21052632]
 [ 20.34337349 15.48795181]
 [ 45.19900498 23.95024876]
 [ 96.72262774 83.27737226]
 [ 63.54210526 51.53157895]] 
使用洗牌代替随机小批量有两个优点:限制小批量计算的次数并防止训练相同的样本两次。如果你的洗牌算法有效,你只需要对数据集进行一次洗牌。如果无效,你可能需要返回并使用随机采样,正如前一节所解释的那样。
随机采样和洗牌帮助解决了数据集体积问题的一个方面。
然而,现在我们必须探讨实现大数据集机器学习算法的另一个方面:验证结果。
链接监督学习以验证无监督学习
本节探讨如何使用监督算法验证无监督 KMC 算法的输出:决策树。
KMC 接收没有标签的输入并输出带标签的结果。无监督过程使杂乱的输入数据变得有意义。
本章中的示例集中在两个相关特征上:位置和距离。生成的聚类是数据集中位置-距离的子集。输入文件包含两列:距离和位置。输出文件包含三列:距离、位置和标签(聚类编号)。
因此,输出文件可以连接到监督学习算法,例如决策树。决策树将使用标记的数据生成可视化的白盒机器思维过程。此外,决策树还可以被训练来验证 KMC 算法的结果。该过程从预处理原始数据开始。
预处理原始数据
如前所述,对于大数据集,迷你批次是必要的。将数十亿条记录加载到内存中是不现实的。在sampling/k-means_clustering_minibatch.py中应用了随机选择作为 KMC 算法的一部分。
然而,由于我们将算法串联在一个管道中,并且我们并未训练模型,因此我们可以从sampling/k-means_clustering_minibatch.py中提取随机采样函数并将其隔离:
n=1000
dataset1=np.zeros(shape=(n,2))
li=0
for i in range (n):
    j=randint(0,4999)
    dataset1[li][0]=dataset.iloc[j,0]
    dataset1[li][1]=dataset.iloc[j,1]
    li+=1 
代码可以应用于从大数据环境中提取的数据集,这些数据集经过预处理阶段提取。例如,预处理阶段将循环执行。现在,我们将探索从原始数据到串联的 ML 算法输出的管道。
脚本和 ML 算法的管道
一个 ML 管道将接受原始数据,并执行降维或其他预处理任务,这些任务不在本书的范围内。预处理数据有时需要不仅仅是 ML 算法,比如 SQL 脚本。我们的探索从 ML 算法(如 KMC)接管后开始。然而,管道也可以通过经典的非 AI 脚本来运行,从原始数据到 ML。
以下章节描述的管道可以分解为三个主要步骤,前面是经典的预处理脚本:
- 
步骤 0:一个标准过程在运行 KMC 程序之前,使用经典的预处理脚本对训练数据集进行随机采样。这个过程超出了 ML 过程和本书的范围。这样做的目的是避免过载 ML Python 程序。训练数据将首先通过 KMC 算法处理,并发送给决策树程序。 
- 
步骤 1:KMC 多 ML 程序 kmc2dt_chaining.py使用保存的模型,读取步骤 0 产生的训练数据集,该模型来自第四章,通过 K-Means 聚类优化解决方案。KMC 程序接收未标记的数据,进行预测,并生成标记输出,保存在名为ckmc.csv的文件中。输出标签是数据集中包含距离和位置的一行的聚类编号。
- 
步骤 2:决策树程序 decision_tree.py读取 KMC 预测的输出文件ckmc.csv。决策树算法训练其模型,并将训练好的模型保存在名为dt.sav的文件中。- 
第 2.1 步:训练阶段已经结束。现在管道接收由连续相等大小的数据集检索的原始数据。这个批处理过程将提供固定数量的数据。可以计划和掌控计算时间。这一步骤超出了机器学习过程和本书的范围。 
- 
第 2.2 步:一个随机抽样脚本处理批处理,并为预测生成预测数据集。 
 
- 
- 
第三步: kmc2dt_chaining.py现在将运行一个 KMC 算法,该算法与决策树链接,将验证 KMC 的结果。KMC 算法生成预测。决策树对这些预测进行进一步的预测。决策树还将为用户和管理员提供一个 PNG 格式的可视化图表。
步骤 2.1 到 3 可以在二十四小时,七天不间断地运行。
需要注意的是,随机森林是决策树组件的一种有趣的替代方案。它可以取代kmc2dt_chaining.py中的决策树算法。在接下来的部分,我们将探讨随机森林在这个背景下的应用,使用random_forest.py。
第 1 步 - 从无监督机器学习算法中训练并导出数据
kmc2dt_chaining.py可以被视为将 KMC 程序与将验证结果的决策树程序链接起来的链条。每个程序形成链条的一个链接。
从决策树项目的角度来看,kmc2dt_chaining.py可以被视为一个管道,用于接收未标记的数据并为监督决策树程序进行标记。管道接收原始数据,并使用多个机器学习程序进行转换。
在链接模型的训练阶段,kmc2dt_chaining.py运行以为决策树的训练提供数据集。参数adt=0限制了链条中第一个链接的 KMC 功能。因此,在这个阶段,该程序中的决策树不会被激活。
kmc2dt_chaining.py将加载数据集,加载保存的 KMC 模型,进行预测,并导出标记结果:
- 
加载数据集: data.csv,即章节 4 中使用的数据集文件,加载两个特征location和distance:dataset = pd.read_csv('data.csv')
- 
加载 KMC 模型:k 均值聚类模型 kmc_model.sav是由章节 4 中的k-means_clustering_2.py保存的。现在使用pickle模块加载它:kmeans = pickle.load(open('kmc_model.sav', 'rb'))
- 
进行预测:此时不需要对 KMC 模型进行进一步的训练。模型可以对接收到的小批量数据进行预测。我们可以使用增量过程来在大规模上验证结果。 如果数据没有经过足够的缩放,可以应用其他算法。在这种情况下,数据集不需要额外的缩放。KMC 算法将对样本进行预测,并为决策树生成一个输出文件。 对于这个示例,预测将逐行生成: for i in range(0,1000): xf1=dataset.at[i,'Distance'] xf2=dataset.at[i,'location'] X_DL = [[xf1,xf2]] prediction = kmeans.predict(X_DL)结果存储在 NumPy 数组中: p=str(prediction).strip('[]') p=int(p) kmcpred[i][0]=int(xf1) kmcpred[i][1]=int(xf2) kmcpred[i][2]=p;
- 
导出标记数据:预测结果保存在一个文件中: np.savetxt('ckmc.csv', kmcpred, delimiter=',', fmt='%d')这个输出文件很特别;它现在已被标记: 80,53,5 18,8,2 55,38,0输出文件包含三列: - 
第 1 列 = 特征 1 = 位置;例如,第一行的 80
- 
第 2 列 = 特征 2 = 距离;例如,第一行的 53
- 
第 3 列 = 标签 = 计算的聚类;例如,第一行的 5
 在我们的链式机器学习算法中,这个输出数据将成为下一个机器学习算法——决策树——的输入数据。 
- 
第 2 步——训练决策树
在第三章,机器智能——评估函数与数值收敛中,描述了决策树并用它来可视化优先级处理。Decision_Tree_Priority.py生成了如下图表:

图 5.4:决策树优先级
树从一个高基尼值的节点开始。该节点被分成两个,每个节点下的部分是“叶子”,因为基尼=0。
本书中实现的决策树算法使用基尼不纯度。
基尼不纯度表示数据点被错误分类的概率。
决策树将从最高的不纯度开始。它将在计算出一个阈值后,将概率分成两个分支。
当一个分支达到基尼不纯度为 0 时,它达到了叶子。
假设k是数据点被错误分类的概率。
来自第三章的X数据集,机器智能——评估函数与数值收敛,包含六个数据点。四个数据点是低值,两个数据点是高值:
X = {低,低,高,高,低,低}
基尼不纯度的公式计算了每个特征出现的概率,并将结果乘以 1——每个特征在剩余值中的出现概率,如下所示的公式:

应用于X数据集,其中六个数据点中有四个是低值,两个是高值,结果将是:
G(k) = (4/6) * (1 – 4/6) + (2/6) * (1 – 2/6)
G(k)=(0.66 * 0.33) + (0.33 * 0.66)
G(k)=0.222 + 0.222=0.444
数据点被错误预测的概率为 0.444,如图所示。
决策树基于特征的信息增益构建,选择包含最高基尼不纯度值的特征。
我们现在将探索决策树的 Python 实现,为将其链入 KMC 程序做准备。
训练决策树
为了训练决策树,decision_tree.py将加载数据集,训练模型,做出预测,并保存模型:
- 
加载数据集:在加载数据集之前,你需要导入以下模块: import pandas as pd #data processing from sklearn.tree import DecisionTreeClassifier #the dt classifier from sklearn.model_selection import train_test_split #split the data into training data and testing data from sklearn import metrics #measure prediction performance import pickle #save and load estimator models
模块的版本会随着编辑者的发布而变化,并且还取决于您更新版本和代码的频率。例如,当您尝试从 0.20.3 版本解压 KMC 模型时,如果使用的是 0.21.2 版本,可能会收到警告。只要它能够正常工作,在教育用途上是没问题的。然而,在生产环境中,管理员应该有一个数据库,其中列出所使用的包及其版本。
数据集被加载、标注,并分为训练数据集和测试数据集:
#loading dataset
col_names = ['f1', 'f2','label']
df = pd.read_csv("ckmc.csv", header=None, names=col_names)
print(df.head())
#defining features and label (classes)
feature_cols = ['f1', 'f2']
X = df[feature_cols] # Features
y = df.label # Target variable
print(X)
print(y)
# splitting df (dataset) into training and testing data
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=1) # 70% training and 30% test 
本例中的数据将包含两个特征(位置和距离)以及一个标签(聚类编号),该标签由 KMC 算法的输出提供。以下标题展示了数据集的结构:
 f1  f2  label
0  80  53      5
1  18   8      2
2  55  38      0
3  74  74      5
4  17   4      2 
- 
训练模型:一旦数据集准备好,决策树分类器就会被创建,模型将进行训练: # create the decision tree classifier dtc = DecisionTreeClassifier() # train the decision tree dtc = dtc.fit(X_train,y_train)
- 
进行预测:一旦模型训练完成,就在测试数据集上进行预测: #predictions on X_test print("prediction") y_pred = dtc.predict(X_test) print(y_pred)预测使用特征来预测测试数据集中的聚类编号,如以下输出所示: prediction [4 2 0 5 0...]
- 
使用度量衡量结果:过程的关键部分是使用度量来衡量结果。如果准确度接近 1,那么 KMC 输出链式到决策树算法是可靠的: # model accuracy print("Accuracy:",metrics.accuracy_score(y_test, y_pred))在这个例子中,准确度为 0.97。该模型可以以 0.97 的概率预测一个距离和位置的聚类,证明了其高效性。链式机器学习解决方案的训练已结束,预测周期开始。 
您可以使用decision_tree.py生成决策树的 PNG 文件。取消注释程序的最后一段,其中包含导出功能:
from sklearn import tree
import pydotplus
graph=1
if(graph==1):
    # Creating the graph and exporting it
    dot_data = tree.export_graphviz(dtc, out_file=None,
                                    filled=True, rounded=True,
                                    feature_names=feature_cols,
                                    class_names=['0','1','2',
                                                 '3','4','5'])
    #creating graph
    graph = pydotplus.graph_from_dot_data(dot_data)
    #save graph
    image=graph.create_png()
    graph.write_png("kmc_dt.png") 
请注意,一旦实现了这个功能,您可以通过graph参数来激活或停用它。
以下图像是为这个例子生成的,帮助您理解整个链式解决方案(KMC 和决策树)的思路。

图 5.5:代码示例的图像输出
图像文件dt_kmc.png可以在 GitHub 的CH05目录中找到。
第 3 步 – KMC 链式到决策树的持续循环
链式 KMC 算法与决策树算法的训练已完成。
使用经典的大数据批量检索方法的预处理阶段将持续提供带有脚本的随机采样数据集。
kmc2dt_chaining.py可以专注于运行 KMC 预测并将其传递给决策树预测进行白盒检查。这个持续过程导入数据集,加载保存的模型,进行预测并在决策树级别衡量结果。
链式过程如果需要可以 24 小时七天运行。
训练程序中使用的模块是 KMC 和决策树所必需的:
from sklearn.cluster import KMeans
import pandas as pd
from matplotlib import pyplot as plt
import pickle
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn import metrics 
让我们一起回顾这个过程:
- 
加载 KMC 数据集和模型:KMC 数据集已在预处理阶段准备好。经过训练的模型已被保存。数据集通过 pandas 加载,模型通过 pickle加载:#I.KMC. The prediction dataset and model dataset = pd.read_csv('data.csv') kmeans = pickle.load(open('kmc_model.sav', 'rb'))
- 
预测和保存:目标是逐行预测批量数据集,并以白盒方式将结果保存到数组中,管理员可以验证该方式: for i in range(0,1000): xf1=dataset.at[i,'Distance'] xf2=dataset.at[i,'location'] X_DL = [[xf1,xf2]] prediction = kmeans.predict(X_DL) #print (i+1, "The prediction for",X_DL," is:", str(prediction).strip('[]')) #print (i+1, "The prediction for", str(X_DL).strip('[]'), " is:", str(prediction).strip('[]')) p=str(prediction).strip('[]') p=int(p) kmcpred[i][0]=int(xf1) kmcpred[i][1]=int(xf2) kmcpred[i][2]=p np.savetxt('ckmc.csv', kmcpred, delimiter=',', fmt='%d')生成的 ckmc.csv文件是下一个链环的入口:决策树。包含 print指令的两行代码已注释,供标准运行使用。然而,如果代码需要维护,你可能希望详细查看输出。这就是为什么我建议在代码中添加维护行的原因。
- 
加载决策树的数据集:决策树的数据集与 decision_tree.py中的方法相同加载。一个参数激活决策树部分的代码:adt=1。因此,可以激活或停用白盒质量控制方法。程序加载数据集,加载模型,并进行数据分割: if adt==1: #I.DT. The prediction dataset and model col_names = ['f1', 'f2','label'] # load dataset ds = pd.read_csv('ckmc.csv', header=None, names=col_names) #split dataset in features and target variable feature_cols = ['f1', 'f2'] X = ds[feature_cols] # Features y = ds.label # Target variable # Split dataset into training set and test set X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=1) # 70% training and 30% test # Load model dt = pickle.load(open('dt.sav', 'rb'))尽管数据集已经分割,只有测试数据被用来验证决策树的预测和 KMC 输出的质量。 
- 
预测和衡量结果:做出决策树预测,并衡量结果的准确性: #Predict the response for the test dataset y_pred = dt.predict(X_test) # Model Accuracy acc=metrics.accuracy_score(y_test, y_pred) print("Accuracy:",round(acc,3))再次说明,在这个例子中,和 decision_tree.py一样,准确率是 0.97。
- 
再次检查预测准确性:在项目的初期阶段或进行维护时,建议进行再次检查。此功能通过名为 doublecheck的参数激活或停用。预测结果逐行与原始标签进行对比,并进行衡量: #Double Check the Model's Accuracy doublecheck=1 #0 deactivated, 1 activated if doublecheck==1: t=0 f=0 for i in range(0,1000): xf1=ds.at[i,'f1'] xf2=ds.at[i,'f2'] xclass=ds.at[i,'label'] X_DL = [[xf1,xf2]] prediction =clf.predict(X_DL) e=False if(prediction==xclass): e=True t+=1 if(prediction!=xclass): e=False f+=1 print (i+1,"The prediction for",X_DL," is:", str(prediction).strip('[]'), "the class is",xclass,"acc.:",e) print("true:", t, "false", f, "accuracy", round(t/(t+f),3))程序将逐行打印出预测结果,并指明其是 True还是False:995 The prediction for [[85, 79]] is: 4 the class is 4 acc.: True 996 The prediction for [[103, 100]] is: 4 the class is 4 acc.: True 997 The prediction for [[71, 82]] is: 5 the class is 1 acc.: False 998 The prediction for [[50, 44]] is: 0 the class is 0 acc.: True 999 The prediction for [[62, 51]] is: 5 the class is 5 acc.: True
在这个例子中,准确率为 0.99,较高。1,000 次预测中仅有 9 次是False。这个结果不同于指标函数,因为它是一个简单的计算,没有考虑均值误差或其他因素。然而,它展示了 KMC 在这个问题上的良好表现。
决策树为 KMC 提供了一个良好的方法。然而,随机森林将机器学习提升到了一个新的水平,提供了一个有趣的替代方案,若需要,可以替代决策树的使用。
随机森林作为决策树的替代方案
随机森林开辟了令人震惊的机器学习新天地。它们是集成元算法。作为集成算法,它们包含了多个决策树。作为元算法,它们超越了一个决策树做出预测的方式。
要运行一个集成(多个决策树)作为一个元算法(多个算法训练并预测相同数据),需要以下模块:
from sklearn.ensemble import RandomForestClassifier 
为了理解随机森林作为元算法如何工作,让我们专注于以下分类器中的三个关键参数:
clf = RandomForestClassifier(n_estimators=25, random_state=None, bootstrap=True) 
- 
n_estimators=25:此参数表示 森林 中的 树木 数量。每棵树都会运行其预测。最终预测结果是通过平均每棵树的预测值获得的。在每棵树的每次分割时,特征会被随机排列。每棵树使用不同的特征方法。 
- 
bootstrap=True:当启用 bootstrap 时,从提供的样本中生成一个较小的样本。每棵树都将生成自己的样本,从而增加多样性。
- 
random_state=None:当random_state=None被激活时,随机函数使用np.random。你还可以参考 scikit-learn 文档使用其他方法(见本章末尾的 进一步阅读)。我个人更倾向于使用 np.random。请注意,拆分训练集时,我使用了 scikit-learn 默认的随机生成器示例,random_state=0。这显示了参数小变化的重要性。经过多次测试后,这是我偏好的配置。但在其他情况下,可能其他 random_state值更为适用。
除了这些关键概念和参数外,random_forest.py 可以以清晰、直接的方式构建。
random_forest.py 的结构与 KMC 或决策树程序相同。它加载数据集,准备特征和目标变量,将数据集拆分为训练集和测试集,进行预测并进行评估。random_forest.py 还包含一个自定义的双重检查函数,该函数将显示每个预测结果、其状态(True 或 False),并提供独立的准确率。
- 
加载数据集: ckmc.csv是由前述的 KMC 程序生成的。这次,它将由random_forest.py读取,而不是decision_tree.py。数据集被加载,并且特征和目标变量被识别。请注意pp变量,它将决定是否触发print函数。这在通过一个变量的更改从生产模式切换到维护模式时非常有用。如果你希望切换到维护模式,只需将pp=0更改为pp=1。在这种情况下,pp被激活:pp=1 # print information # load dataset col_names = ['f1', 'f2','label'] df = pd.read_csv("ckmc.csv", header=None, names=col_names) if pp==1: print(df.head()) #loading features and label (classes) feature_cols = ['f1', 'f2'] X = df[feature_cols] # Features y = df.label # Target variable if pp==1: print(X) print(y)程序打印标记数据: f1 f2 label 0 80 53 5 1 18 8 2 2 55 38 0 3 74 74 5 4 17 4 2程序打印目标簇编号以进行预测: [1 5 5 5 2 1 3 3…]
- 
数据分割、创建分类器和训练模型:数据集被分为训练数据和测试数据。随机森林分类器使用 25 个估算器进行创建。然后,模型被训练: #Divide the data into training and testing sets X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=0) #Creating Random Forest Classifier and training clf = RandomForestClassifier(n_estimators=25, random_state=0) clf.fit(X_train, y_train)程序已准备好进行预测。 
- 
预测和测量训练模型的准确性: #Predictions y_pred = clf.predict(X_test) if pp==1: print(y_pred) #Metrics ae=metrics.mean_absolute_error(y_test, y_pred) print('Mean Absolute Error:', round(ae,3))输出结果和度量是令人满意的: predictions: [1 5 5 5 2 1 3 3 0 5 3 5 3 2 2 4 3 1 3 2 2 …] Mean Absolute Error: 0.165平均误差接近 0 是一个高效的结果。 
- 
双重检查:在 ML 项目的早期阶段和维护过程中,建议使用双重检查函数。通过 doublecheck参数激活该函数,如同在kmc2dt_chaining.py中一样。如果你希望激活维护模式,请设置doublecheck=1。它实际上是相同的模板:#Double Check the Model's Accuracy doublecheck=0 # 1=yes, 0=no if doublecheck==1: t=0 f=0 for i in range(0,1000): xf1=df.at[i,'f1'] xf2=df.at[i,'f2'] xclass=df.at[i,'label'] X_DL = [[xf1,xf2]] prediction =clf.predict(X_DL) e=False if(prediction==xclass): e=True t+=1 if(prediction!=xclass): e=False f+=1 if pp==1: print (i+1,"The prediction for",X_DL," is:", str(prediction).strip('[]'),"the class is", xclass,"acc.:",e) acc=round(t/(t+f),3) print("true:",t,"false",f,"accuracy",acc) print("Absolute Error",round(1-acc,3))
随机森林的准确性很高。测量结果输出如下:
Mean Absolute Error: 0.085
true: 994 false 6 accuracy 0.994
Absolute Error 0.006 
绝对误差是一种简单的算术方法,不考虑均值误差或其他因素。由于算法的随机性质,分数在不同运行之间会有所不同。然而,在这种情况下,每千次预测中有 6 个错误是一个不错的结果。
像随机森林这样的集成元算法可以用几行代码替换kmc2dt_chaining.py中的决策树,就像我们在这一节中看到的那样,极大地提升了整个链式机器学习过程。
使用集成元算法的链式机器学习算法非常强大且高效。在本章中,我们使用链式机器学习解决方案处理大数据集,并对机器智能预测进行自动质量控制。
总结
尽管看起来可能有些矛盾,但在开始涉及数百万到数十亿条数据记录的项目(如 SQL、Oracle 和大数据)之前,尝试避免使用 AI。可以尝试更简单的经典解决方案,比如大数据方法。如果 AI 项目通过,LLN 将引导通过中央极限定理进行数据集上的随机抽样。
经典和机器学习流程的管道将解决数据量问题,以及人工分析限制问题。随机抽样功能无需在 KMC 程序中运行迷你批处理功能。批次可以作为预处理阶段,通过经典程序生成。这些程序将生成与 KMC NP 难问题等大小的随机批次,将其转化为一个 NP 问题。
KMC,一种无监督训练算法,将把未标记数据转化为包含聚类编号作为标签的标记数据输出。
反过来,决策树链入 KMC 程序,将使用 KMC 的输出训练其模型。该模型将像保存 KMC 模型一样被保存。如果在管道的训练阶段,随机森林算法提供了更好的结果,它可以替代决策树算法。
在生产模式下,包含 KMC 训练模型和决策树训练模型的链式机器学习程序可以对固定随机抽样批次进行分类预测。实时指标将监控过程的质量。由于链式程序是连续的,它可以全天候运行,提供可靠的实时结果,而无需人工干预。
下一章将探讨另一个机器学习挑战:全球商业和社会沟通中生成的语言翻译数量日益增加。
问题
- 
聚类的数量 k 并不是那么重要。(是 | 否) 
- 
迷你批次和批次包含相同数量的数据。(是 | 否) 
- 
K 均值可以在没有迷你批次的情况下运行。(是 | 否) 
- 
必须优化质心以便结果被接受吗?(是 | 否) 
- 
优化超参数并不需要很长时间。(是 | 否) 
- 
训练大数据集有时需要几周时间。(是 | 否) 
- 
决策树和随机森林是无监督算法。(是 | 否) 
进一步阅读
第六章:用 Google 翻译创新 AI
在本章中,我们将说明如何通过 Google 翻译创新现有的 AI。首先,我们将从理解发明、创新、颠覆、高价产品和革命之间的区别开始,并探讨如何在 AI 创新中创造影响。
有时,开发者会将发明与创新混淆,导致关键 AI 项目的重大失败。一些 AI 设计师将革命理解为颠覆,导致早期销售,但之后就一无所获。
一旦我们定义了创新的关键概念,我们将使用 Google 翻译来理解围绕自然语言处理(NLP)的语言学原理。
Google 翻译于 2006 年进入市场,并在 2016 年通过神经网络得到了增强,但它仍然经常给出错误的答案。这是好消息还是坏消息?我们将在 Python 程序中实现 Google 的 API,找出如何揭示从一种语言到另一种语言的错误翻译。
一旦我们找到了 Google 翻译的局限性,我们最终将发现如何通过我们的自定义适配突破这些局限,方法是通过探索 Google 的 API 在 Python 程序中添加k-近邻(KNN)算法,并进行统计测量。
与媒体炒作相反,人工智能仅刚刚开始创新人类流程。还有大量的工作需要完成。为了取得进展,大家都必须参与其中,正如我们将在本章中讨论的那样。即使 Google、亚马逊、微软、IBM 等公司提供了解决方案,这也不意味着第三方不能通过附加到现有解决方案或新的独立产品来改进它。毕竟,一百多年前,福特发明了 Model T,但这并不排除更好的汽车的开发。相反,看看你周围!
为了利用 AI 的冒险之旅,我们将从理解 AI 中的颠覆开始,进入 Google 翻译,然后进行创新。
本章将涵盖以下主题:
- 
在开始实现 Google 翻译之前,了解 AI 创新的关键概念 
- 
发明与创新的区别 
- 
革命性 AI 与颠覆性 AI 的区别 
- 
在 Python 中实现 Google 翻译 API 
- 
将语言学引入作为构建任何自然语言处理(NLP)算法的前提 
- 
KNN 算法 
- 
如何在 Python 中使用 KNN 定制 Google 翻译 
我们将从探索 AI 创新和颠覆的关键概念开始。
本章中所有的 Python 程序和文件都可以在 github.com/PacktPublishing/Artificial-Intelligence-By-Example-Second-Edition/tree/master/CH06 获取。
还有一个名为COLAB_Translate.ipynb的 Jupyter 笔记本,其中包含所有 Python 程序的一次运行。您可以使用您的 Google 帐户直接将其上传到 Google Colaboratory:colab.research.google.com/。
在人工智能中理解创新和颠覆
当我们启动诸如翻译解决方案等项目时,我们必须首先问自己的第一个问题是我们身处何方。我们要做的是发明还是创新?我们的工作是否具有颠覆性或革命性?我们将在本章探讨这些概念,以在进一步进行之前了解广阔的实用图景。
人工智能是否具有颠覆性?
“颠覆性”一词常常与人工智能联系在一起。媒体炒作告诉我们,AI 机器人很快将在全球范围内取代人类。尽管媒体炒作使得获取 AI 预算变得更加容易,但如果我们想要实施 AI 解决方案,我们需要知道自己的立场。如果我们想要创新,我们需要找到前沿并从那里构建新的想法。
为什么不直接投入工具,看看会发生什么?这是个好主意还是冒险的主意?与拥有巨额预算的公司不同,一个人的资源有限。如果你在错误的方向上花费时间学习,将需要几个月的时间在另一个更好的方向上积累足够的经验以达到你的目标。例如,假设你在第四章中探讨了大量数据分类的问题,使用 K 均值聚类优化你的解决方案。你会在公司项目上花费数月时间并失败。这可能会让你失去工作。相反,如果你找到正确的模型并学习关键概念,你的项目几天内就能起飞。
在深入项目之前,请了解我们在创新和颠覆方面的立场。这在项目开始时似乎并不重要,但在生产和分发阶段会有很大影响。本节将阐明这些概念。
太阳底下无新事,即使是考虑到人工智能。大多数人工智能理论和数学工具已经存在几十年,甚至几个世纪了。我们经常倾向于认为,某些事物对我们来说似乎是新的,就是刚刚发明或发现的。这种错误在许多项目中可能致命。如果你知道某个理论或函数存在几十年或几个世纪,你可以进行深入研究,并利用 100 多年前找到的解决方案来解决当前的问题。如果你这样做了,你将节省大量时间,使用经过验证且可靠的方程式。如果你不这样做,你可能会花费宝贵的时间重新发明已经存在的方程式。
弄清楚什么是新的,什么不是,将在你的个人或专业人工智能项目中产生重大影响。
AI 基于并非新的数学理论
当前,人工智能的理论在很大程度上依赖于应用数学。在第一章,通过强化学习启动下一代人工智能中,描述了马尔科夫决策过程(MDP),这是一种强化学习(RL)方法。谷歌已成功地将强化学习与神经网络结合应用于 AlphaGo Zero。
安德烈·马尔科夫(Andrey Markov)是 1856 年出生的俄罗斯数学家,他发明了马尔科夫决策过程。他成功地将这一算法应用于给定语言中的单词序列字母预测。例如,理查德·贝尔曼(Richard Bellman)在 1957 年发布了马尔科夫决策过程的改进版本。
贝尔曼还创造了“维度灾难”这一表述,并出版了在今天的人工智能中广泛使用的数学工具书籍。现在大家普遍知道,可以通过降维来避免在算法中面对成千上万的维度(例如特征)。
逻辑函数(见第二章,构建奖励矩阵—设计数据集)可以追溯到比利时数学家皮埃尔·弗朗索瓦·维尔赫斯特(Pierre François Verhulst,1844-1845)。逻辑函数使用e,即自然对数的底数,也被称为欧拉数。莱昂哈德·欧拉(Leonhard Euler,1707-1783)是瑞士数学家,他研究了这个自然对数。
托马斯·贝叶斯(1701-1761)发明了以他名字命名的定理:贝叶斯定理。它在人工智能中被广泛应用。我们将在第七章,通过朴素贝叶斯优化区块链中使用它。
几乎所有应用于人工智能、机器学习和深度学习的数学,都可以追溯到 17 世纪至 20 世纪的数学家。我们必须寻找 21 世纪人工智能创新的真正来源。我们需要找到人工智能中真正的新鲜元素,这也是它在 21 世纪初快速扩展的原因。
神经网络并不新颖
正如当代专家所描述的,神经网络可以追溯到 1940 年代和 1950 年代。即使是卷积神经网络(CNNs)也追溯到 20 世纪。法国计算机科学家扬·勒昆(Yann LeCun)在 1980 年代奠定了卷积神经网络的基础(见第九章,利用卷积神经网络(CNNs)进行抽象图像分类);他在 1990 年代成功地将其应用为今天我们所知的形式。
我们必须再次寻找 21 世纪人工智能创新的来源。
如果神经网络本身并不新颖,那么我们必须在我们当前的环境中找到真正促成现代人工智能成功的全新因素。
从颠覆性的角度看—使人工智能具有颠覆性的因素
尽管人工智能的基础源远流长,甚至在计算机出现之前或广泛普及之前就已存在,但只有最近我们才真正看到了人工智能在社会中开始产生波动。在接下来的章节中,我们将探讨导致人工智能在近年来成为强大颠覆性力量的各种因素。
21 世纪初的云服务器算力、数据量以及网络共享
了解近年来人工智能的崛起因素非常重要。
数据量推动了 21 世纪人工智能的崛起。没有人工智能推动整个计算机科学市场,处理数据、分类数据以及做出预测和决策将变得不可能。
如果你放下围绕人工智能的幻想,牢记人工智能的这一关键需求,你将完全理解为什么人工智能会出现并且会长期存在。
人工智能创新性颠覆的第一个迹象出现在 2000 年至 2010 年间。在此之前,互联网和服务器已经存在。但从大约 2005 年开始,云服务器被广泛提供。有了这样的计算能力,世界各地的开发者可以尝试使用机器学习和深度学习所需的高度贪婪资源。他们终于能够利用人工智能解决那些原本无法解决的大数据问题。
同时,随着强大的服务器变得可用,互联网提供了人类历史上最大的知识库。
除此之外,社交网络的广泛使用也成为现实。分享发现和源代码变得司空见惯。万维网(WWW)促进了开源软件的传播,推动了本地研发。
从 21 世纪第一个十年中期开始,当地专家才有可能进入人工智能时代。
使人工智能今天看起来像一种创新的,是更强大的机器和知识资源的可用性相结合。
公众意识
在 1995 年到 2005 年间的云架构革命发生后,人工智能的公众认知仍然在几年的时间里保持低迷。
到 2015 年左右,人工智能给我们带来了强烈冲击,我们都意识到人工智能可能大规模替代人类,并在历史上前所未有的程度上造成工作岗位的替代。
更糟糕的是,我们意识到机器可以在我们引以为豪的领域击败我们,例如国际象棋(第三章,机器智能—评估函数和数值收敛)、围棋以及视频游戏。我们看到越来越多的制造业工作由机器人完成,办公室工作由机器人完成,更多的领域每天都在出现。
人类历史上第一次,人类物种可能会被一种新的“物种”——智能机器人超越。作为开发者,我们以为自己是安全的,直到谷歌推出了 AutoML,这一解决方案能够创造出比人类更优秀的机器学习方案。与此同时,现成的机器学习平台已经广泛传播,可以减少甚至取代人工智能软件开发。
人工智能既让人敬畏又让人恐惧。机器会走多远?我们会仅仅经历工作岗位的替代,还是它会走向物种的替代?
这会是许多人得到机会的时刻吗?谁知道呢?无论如何,本章提供了一些指导,帮助你以一种推动你不断创新和有用的方式进行思考。在大数据时代,我们经常面临巨大的数据集,人工智能已经来临,它将长期存在;没有它我们将无法应对。让我们充分利用它吧!
在我们开始深入了解人工智能带来的惊人机遇之前,让我们首先在脑海中澄清一下,究竟发明与创新的区别是什么,然后是革命与颠覆的区别。理解我们正在开发和实施的东西对人工智能市场的影响非常重要。
发明与创新
一些人工智能程序,特别是深度学习算法,直到 Google 和其他大玩家大规模使用它们时,才从发明变成了创新。
如果你发明了一个比 Google 更好的算法用于某些应用,它依然是一个发明,直到它真正改变了你公司的某些东西或在网上产生了影响。
假设你通过优化神经元数量和一种新的激活函数,找到了一种更快的图像识别方法。如果没有人使用它,那么无论它看起来多么优秀,这项发明依然只是个人的理论发现。
当其他人开始使用这个新算法时,它就变成了创新。发明只有在它改变了公司内的某个过程,或者有足够多的私人用户使用时,才会成为创新。
革命性与颠覆性解决方案
假设一个新的图像识别算法在一家大公司中成为了创新。这个新算法已经从发明(未使用)变成了创新(一个改变现状的解决方案)。
该公司现在广泛使用该算法。每个子公司都可以使用它。对这家公司而言,这个新的图像识别算法已达到了革命性的地位。公司销售额和利润率都有所上升。
但也许这家公司并没有主导市场,并且没有人跟随它的例子。这个创新依然是革命性的,但尚未成为颠覆性的。
然后,假设创建算法的人决定离开公司并用该算法创业。它出现在 GitHub 上,作为一个开源程序。每个人都想要它,下载量每天都在增加,直到 1,000,000+ 用户开始实施它。公司网站上提供了一些非常低价的附加组件。不到一年,这个算法就成为了一种新的图像识别方式。所有公司必须跟进,否则就会落后。这一解决方案变得具有颠覆性,因为它已经在全球范围内改变了市场。
从哪里开始?
我们现在已经探索了创建人工智能的基本概念。在使用 Google Translate 进行翻译项目的第一步是尽可能通过 Google 的 API 使用该算法。正如我们将在下一节中看到的,我们将探索 Google Translate 的极限。一旦找到这些极限,我们就可以通过人工智能定制 Google Translate,发挥创造力。
我们将发现,即使一个解决方案已经存在,它仍然有其局限性,可以改进、定制、包装和销售。有局限性,就有市场。
永远不要批评你在人工智能解决方案中发现的缺陷;它们是金矿!
哪里有局限,哪里就有机会。
让我们走在最前沿,然后越过边界进入未知领域,使用 Google Translate 来进行说明。
通过 Google Translate 探索一个充满机会的世界
从 Google Translate 开始探索 NLP 是为在 web 解决方案中使用 NLP 做准备的一个好方法。任何颠覆性的基于 Web 的解决方案必须至少能支持几种语言。你需要掌握多种语言的 NLP,才能实现一个聊天机器人、翻译解决方案以及像 Wikipedia 这样的在线信息网站。
Google 提供了许多资源来使用、探索或改善 Google Translate。运行 Python 代码并评估结果的质量,在将其用于公司中的重要翻译之前是至关重要的。让我们开始运行 Google Translate。
入门
Google 开发者 API 客户端库页面如下:developers.google.com/api-client-library/。在这个页面上,你将看到许多语言的库:Java、PHP、.NET、JavaScript、Objective-C、Dart、Ruby 等。
然后,进入 Python 资源并按照说明进行注册,在 Google API 控制台中创建一个项目并安装库。
如果你在做这一部分时遇到问题,或者暂时不想安装任何东西,这一章是独立的。源代码在这一章中有描述。
无论你是否安装了工具,你现在都可以开始了。
程序
本节的目标是实现 Google Translate 功能。你可以实现并运行程序,或者首先仅阅读这一独立章节。
头部
Google 提供的标准头部应足以使 API 工作,如以下代码所示:
from googleapiclient.discovery import build 
考虑到 Google 管理的多种语言,特殊字符是需要处理的主要问题。许多论坛和示例程序在使用 Google Translate 时都面临 UTF-8 头部的问题。很多解决方案被提出,以下是一个建议的源代码头部。
# -*- coding: utf-8 -*- 
然后,当 Google Translate 返回结果时,会发生更多问题,许多人开发了自己的函数。它们运行得很好,但我在寻找一种简单的单行解决方案。这里的目标不是写很多行代码,而是专注于 Google Translate 的限制,以发现 AI 中前沿的语言翻译技术。
所以,我没有使用 UTF-8 头部,而是使用 HTML 库来实现。
import html 
面对一个结果时,以下这行 HTML 解析器代码完成了任务。
print("result:", html.unescape(result)) 
它运行良好,因为 Google 会根据你实现的选项返回一个 HTML 字符串或文本字符串。这意味着 HTML 模块可以完成任务。
实现 Google 的翻译服务
Google 的翻译服务需要至少三个值才能返回结果:
- 
developerKey:这是在前面描述的入门过程结束时获得的 API 密钥。
- 
q="text to translate":在我的代码中,我使用了source。
- 
target="translated text abbreviation":en表示英语,fr表示法语,依此类推。
如下节所述,提供了更多的选项。
有了这个考虑,翻译功能将按如下方式工作:
def g_translate(source,targetl):
    service = build('translate', 'v2',developerKey='your Key')
    request = service.translations().list(q=source,
        target=targetl)
    response = request.execute()
    return response['translations'][0]['translatedText'] 
在 Google_translate.py 程序中,q 和 target 将被发送到函数中,以获取解析结果:
source="your text"
targetl="abbreviation of the target language"
result = g_translate(source,targetl)
print(result) 
总结一下程序,让我们将 Google 翻译翻译成法语,其中包含通过 HTML 解析器解析出的重音:
from googleapiclient.discovery import build
import html
def g_translate(source,targetl):
    service = build('translate', 'v2',developerKey='your key')
    request = service.translations().list(q=source,
        target=targetl)
    response = request.execute()
    return response['translations'][0]['translatedText']
source='Google Translate is great!'
targetl="fr"
result = g_translate(source,targetl)
print("result:", html.unescape(result)) 
Google_Translate.py 工作正常。结果将输出正确的答案,并解析出重音:
Google Translate est génial! 
在这一点上,Google 翻译满足了黑箱探索方法。它具有颠覆性,改变了世界,并且可以在许多公司中替代翻译员,处理所有企业需求。
事实上,我们可以在这里结束本章,去我们最喜欢的社交网络上制造一些关于翻译项目的热度。
幸福的结局?
哦,还没有!
我们需要从语言学家的角度来探索 Google 翻译。
从语言学家的角度看 Google 翻译
语言学家对该程序的分析将涉及更深层次的白箱式探索。这个方法将揭示出许多改进的领域。
等到这本书出版时,也许 Google 已经改进了本章中的示例。但别担心,在这种情况下,你会很快发现成百上千个其他不正确的示例。旅程才刚刚开始!
玩转这个工具
玩转一个包含随机示例的工具,可能会得到令人惊讶的结果。这个探索性的源代码保存为 Google_translate_a_few_test_expressions.py。
程序模拟了由一个名叫 Usty 的人创建的对话,如下所示:
source='Hello. My name is Usty!'
 >>>result:Bonjour. Je m'appelle Usty!
source='The weather is nice today'
 >>>result: Le temps est beau aujourd'hui
source='Ce professor me chercher des poux.'
 >>>result: This professor is looking for lice! 
前两个示例在法语中看起来很好,尽管第二个翻译有点奇怪。但在第三个测试中,表达式 chercher des poux 意味着英语中的 looking for trouble(寻找麻烦),而不是翻译成法语的寻找虱子。
现在将对 Google 翻译进行语言评估。
对 Google 翻译的语言学评估
正确评估 Google 翻译将直接导致发现其局限性。
限制是研究人员渴望的边界!我们是拓荒者!
专家级评估将引领项目团队走向前沿,甚至超越它。为了做到这一点,我们将首先探索一些语言学方法。
词汇场理论
词汇场描述的是词汇的领域。只有在特定语境中,词语才能获得其完整的含义。这个语境往往不仅仅局限于几个其他词汇或甚至是一个句子。
Chercher des poux 翻译过来意味着 look for lice(寻找虱子)。但在法语中,它可以意味着 looking for trouble(寻找麻烦)或者字面意义上的 looking for lice(寻找虱子)。Google 翻译得出的结果包含了三个基本问题。
source='chercher des poux'
>>result: look for lice 
问题 1 – 词汇场:如果没有上下文,就无法知道这意味着寻找虱子还是寻找麻烦。
问题 2 – 比喻或习惯表达:假设你需要翻译this is giving you a headache。你无法知道这是否是一个物理上的问题,还是指代比喻意义上的this is driving you crazy。这两个习惯表达在翻译成法语时恰好使用了相同的比喻。然而,法语中的lice(虱子)比喻在英语中没有意义。
问题 3:chercher在法语中是一个不定式,结果应该是英语中的looking for lice(寻找虱子)。但是输入chercher des limites est intéressant给出的正确动词形式是looking for:
source='Chercher des limites est intéressant.'
>>>result:Looking for boundaries is interesting. 
答案是正确的,因为is将句子分成了两部分,这使得 Google Translate 能够更容易地识别chercher是句子的第一部分,从而在英语中使用looking。
词汇领域在不同语言间存在差异,行话也是如此。
行话
行话是在专业领域中产生的。在人工智能领域,hidden neurons(隐藏神经元)就是行话。这个表达对律师来说毫无意义。例如,律师可能认为你在某个领域拥有隐藏的智慧,或者你在某种名为隐藏神经元的加密货币中藏了钱。
同样地,如果有人要求 AI 专家解释filing a motion的确切含义,那将是一个困难的任务。
在企业法律环境中,除了将 Google Translate 作为字典使用外,翻译句子可能存在风险,尤其是当只有随机的结果是正确时。
如果我们将术语变化与语言间的词汇变化结合起来,我们会发现当一个词处于某种上下文中时,逐词翻译是行不通的。因此,翻译不仅仅是找到目标语言中最相似的词汇。
翻译不仅仅是翻译,而是解读。
有时候,翻译需要解读,如下句所示,它取自法国商业法的标准描述:
source='Une SAS ne dispense pas de suivre les recommandations en vigueur autour des pratiques commerciales.'
>>>result:An SAS does not exempt from following the recommendations in force around commercial practices. 
法语句子指的是一种公司类型;SAS 类似于英文中的 inc.、ltd.等公司类型。然而在英语中,SAS 是指特别空勤团。接着是语法问题,听起来不太对。
翻译者会写出更好的英语,并且明确说明 SAS 是什么:
An SAS(法国的一种公司)必须遵循涵盖商业实践的建议。
翻译通常意味着解读,而不仅仅是翻译词语。
在这种情况下,法律翻译者可能会解读合同中的文本,并且可能会写道:
The COMPANY must respect the legal obligation to treat all customers fairly.
法律翻译者会建议在合同开始时定义COMPANY,以避免像 Google Translate 刚刚做出的混淆。
当阅读关于自然语言处理、聊天机器人和翻译的文章时,一切似乎都很简单。然而,使用 Google Translate 却很容易变成一场噩梦!
让我们再举一个最后的例子:
The project team is all ears 
Google Translate 给出的法语输出:
source:"The project team is all ears".
>>>result: L'équipe de projet est tout ouïe. 
在法语中,像在英语中一样,更好地说 project team,而不是使用 of 来表示 team of the project。在法语中,我们使用 équipe projet(团队(équipe)在项目(projet)之前)。
从目前的例子来看,我们可以看到谷歌翻译是:
- 
有时正确 
- 
有时错误 
- 
有时部分正确,部分错误 
现在的问题是,如何知道某个翻译属于哪种类别。
如何判断翻译是否准确
如果你不懂某种语言,怎么检查翻译是否准确?
小心。如果谷歌翻译提供的另一种语言的答案偶尔是正确的,那么你无法判断这个翻译是否可靠。
如果你不能确信谷歌翻译会是正确的,你可能会陷入困境,甚至把与你重要的人说反了话。你可能会误解你正在试图理解的句子。
比如在一家运输公司,你可能会写一封电子邮件,表示大巴停了下来,人们正在抱怨:
source='The coach stopped and everybody was complaining.' 
谷歌翻译由于词汇场的原因,将 coach 错误地翻译成法语中的体育教练,这会给句子带来完全不同的意义:
result: L'entraîneur s'est arrêté et tout le monde se plaignait.. 
现在,情况可能变得更糟。为了帮助谷歌翻译,我们来添加一些上下文。
source='The coach broke down and stopped and everybody was complaining.' 
这个答案更糟糕。谷歌翻译正确地将 broke down 翻译成法语表达 en panne,但仍然将 coach 翻译成法语中的 entraineur(教练),这意味着是 教练 出故障,而不是 大巴(coach)。
result: L'entraîneur est tombé en panne et s'est arrêté et tout le monde se plaignait. 
毫无疑问,谷歌会继续改进这个程序,就像自 2006 年以来所做的那样。然而,就目前而言,人类翻译员会发现谷歌翻译无法处理的成百上千个表达方式。
当一个词或表达有多个意思时,理解你母语中的一句话可能会变得困难。加入翻译功能后,这个问题变得更加复杂,很难给出可靠的答案。
这就是我们到达前沿的地方,超越了最前沿,因为我们已经确立了谷歌翻译的局限。
在下一部分,我们将探讨一些改进标准谷歌翻译结果的方法。虽然没有灵丹妙药可以验证翻译,但我们将探索改善翻译过程的方法。我们将找到一种改进谷歌翻译的方法,并付诸实践。
人工智能作为新前沿
谷歌有一个出色,但有限的翻译程序。利用这些缺陷进行创新!人工智能的研究和开发才刚刚开始,未来的创新才刚刚起步。
首先,实施一个 AI 解决方案。然后,用它来解决实际问题。但不要接受它的局限性。不要对它持负面态度。创新!想出新点子或倾听你喜欢的其他想法,并在团队中构建解决方案!谷歌甚至可能会发布你的解决方案!
改进 Google 翻译的任何翻译都是不可能的。一个现实的方法是专注于根据特定领域定制 Google 翻译,例如本例中的交通公司。在下一部分中,我们将重点讨论如何定制 Google 翻译。
词汇领域与多义性
Google_Translate_Customized.py 将提供如何在特定领域改善 Google 翻译的思路。本节集中在 Google 翻译在交通词汇上所犯的错误。再次强调,Google 可能会迅速纠正这个错误,但这个方法可以应用于许多剩余的错误。
词汇领域包含构成集合和子集的单词,它们在不同语言中有所不同。一种语言本身构成一个集合,并包含词汇领域的子集。
寒冷国家描述冰冻状态下水的单词比热带国家更多,因为热带国家几乎不下雪。寒冷的词汇领域可以是 C 的一个子集:
C = {ice(冰),hail(冰雹),snowflakes(雪花),snowman(雪人),slushy(泥泞的),powder(粉雪),flake(薄片),snowball(雪球),blizzard(暴风雪),melting(融化),crunch(咔嚓声)……n}
这里适用维度诅咒(curse of dimensionality)。词语包含着极为丰富的维度和定义。为了翻译某些表达,Google 翻译压缩了它们的维度并进行了简化。
Google 翻译常常使用 n-grams 来翻译。n-grams 是固定长度的词语序列。词语(token)可以是一个单词、一个字符,甚至是单词和字符的数值表示。
令牌 n 的意义是根据前后 n – x 或 n + x 个令牌计算得出的。x 是一个变量,取决于所应用的算法。
例如,slushy 在表达 slushy snow 时有特殊含义。雪开始部分融化,呈现出水状,走过时会发出 slushing 声音。融化只是 slush 含义的一个组成部分。
此时,Google 翻译只会将 slushy snow 翻译成法语为:
neige(雪) fondante(融化)
Google 翻译也会将 melting snow 翻译为:
neige(雪) fondante(融化)
要将 slushy 翻译成法语,你必须使用一个短语。要找到这个短语,你需要一些想象力,或者查看一些已经解析过的(搜索过的)小说或其他语言表达形式。这需要时间和资源。Google 翻译可能要经过多年,才能在所有公开的语言中达到一个可接受的母语水平。
另一个需要考虑的维度是多义性。
多义性意味着一个词在一种语言中可以有多个非常不同的含义。另一种语言中对应的词可能只有一个意思,或者有其他完全不同的意思。
英语中的"Go + over"可以表示走过一座桥或复习一些笔记。在这一点上(希望你阅读本书时它会有所改进),它在法语中两种情况都被翻译为aller sur。这意味着走上去(而不是走过),在这两种情况下都是不正确的。英语中的介词构成了一个独立的领域,同一个单词可以产生许多不同的意思。动词go有很多意思:go up(楼上),go up(股市),go down(楼下),go down(崩溃),还有很多其他可能性。
原型定制程序从定义X开始。一个小数据集来翻译,足以让事情开始运转:
X=['Eating fatty food can be unhealthy.',
   'This was a catch-22 situation.',
   'She would not lend me her tote bag',
   'He had a chip on his shoulder',
   'The market was bearish yesterday',
   'That was definitely wrong',
   'The project was compromised but he pulled a rabit out of his hat',
   'So just let the chips fall where they may',
   'She went the extra mile to satisfy the customer',
   'She bailed out when it became unbearable',
   'The term person includes one or more individuals, labor unions, partnerships, associations, corporations, legal representatives, mutual companies, joint-stock companies, trusts, unincorporated organizations, trustees, trustees in bankruptcy, or receivers.',
   'The coach broke down, stopped and everybody was complaining'] 
如果你发现拼写错误或小错误,请在训练阶段不要纠正它们。一定程度的噪声是必要的,以便复制人类和机器错误,避免过拟合。
Google 翻译将自动翻译这些句子。
X1,如以下代码所示,定义了一些与句子统计相关的关键词;它应用了前面描述的 n-gram 概率理论。
X1=['grasse',
    'insoluble',
    'sac',
    'aggressif',
    'marché',
    'certainement',
    'chapeau',
    'advienne',
    'supplémentaire',
    'parti',
    'personne',
    'bus'] 
X1中的每一行都对应X中的一行。如前所述,这只是一个概率,可能不正确。
我们此时并不追求完美,而是寻求改进。
让我们探索如何通过在 Python 程序中实现 KNN 来定制翻译,进而改善 Google 翻译。
探索前沿——用 Python 程序定制 Google 翻译
现在是时候添加一些定制的新内容了。本节中向量的使用将在下一节中通过使用它们的源代码进行解释。
一个触发向量将迫使程序尝试另一种方法来翻译一个误翻的句子。当句子被识别出来时,如果它在X2中的值等于1,则触发一个更深层次的翻译功能,如下所示:
X2=[0,0,0,1,0,0,0,0,0,0,0,1] 
0和1是标记。每个值代表X中的一行。
开发者注意:要正确使用此方法,所有这些向量的值应设置为1。这将自动触发多种替代方法来翻译 Google 翻译错误。这里还有很多工作要做!
示例取自运输业务。应该建立一个运输短语词典。在这种情况下,已经实现了一个通用的phrase_translation词典,包含一个表达式,如下数组所示。
phrase_translation=['','','','Il est agressif','','','','','','','',''] 
为了填充这个词典,还需要做什么?
- 
扫描公司所有的文件——电子邮件、信件、合同和所有形式的书面文件。 
- 
存储嵌入的单词和句子。 
- 
训练团队使用该程序,通过在学习界面中提供反馈(正确答案)来改进它,当系统返回错误答案时。 
Google 翻译无法在全球范围内做到的,你可以在本地范围内实施,以显著改进系统。
现在我们已经定义了一个方法,我们将深入研究 KNN 算法。
k 最近邻算法
无论你如何解决语言学问题,最终都归结为语境的概念。当某人无法理解另一个人时,他们会说:“你把我的话断章取义了”或“那不是我的意思,让我解释一下。”
如前所述,在许多情况下,你无法在没有词汇场域的情况下翻译一个词或表达。困难程度与多义性属性成正比,正如程序所展示的那样。
使用 KNN 算法作为分类方法非常有用。任何语言解释(翻译或聊天机器人)都必须使用面向语境的算法。
通过找到彼此最接近的词语(邻居),KNN 将创建解释语言所需的词汇场域。更棒的是,当提供适当的数据集时,它将解决多义性问题,如接下来的章节所示。
实现 KNN 算法
通常,一个词需要语境才能有意义。寻找“邻居”词汇是一种有效的方式来确定该词属于哪个类别。
KNN 是有监督的,因为它使用提供的数据标签来训练其算法。在这种情况下,KNN 用于分类目的。对于给定的点p,KNN 将计算到所有其他点的距离。然后,k表示需要考虑的 k 个最近邻居。
通过一个例子来澄清这个问题。在英语中,词语“coach”可以指足球场上的教练、一辆公交车或铁路的客车车厢。在交通公司中,“coach”通常指的是一辆公交车,不应与教练混淆:
- 
步骤 1:详细解析文本中的“coach”作为公交车和“coach”作为教练的含义。因此,程序正在搜索三个目标词:教练、公交车和教练员。 
- 
步骤 2:找到与我们要寻找的目标词语接近的词语。按照建议,执行以下操作: - 
使用标准程序解析所有可以使用的公司文档。 
- 
使用如 if(n-gram in the source)的 Python 函数,然后存储数据。
 
- 
在这种情况下,以下输出摘录中提供的V1.csv文件包含了该解析函数的结果:
broke,road,stopped,shouted,class
1,3.5,6.4,9,trainer
1,3.0,5.4,9,trainer
1,3.2,6.3,9,trainer
...
6.4,6.2,9.5,1.5,bus
2,3.2,9,1,bus
6.4,6.2,9.5,1.5,bus
...
3.3,7.3,3.0,2.5,coach
4.7,5.7,3.1,3.7,coach
2.0,6.0,2.7,3.1,coach 
生成如V1.csv之类的文件不在本章或本书的范围内。然而,你可以从探索 scikit-learn 的文本文档功能开始,网址如下:
scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html
程序解析了电子邮件、文档和合同。每一行代表解析一个文档的结果。数字代表出现的次数(词汇的出现频率)。这些数字已经被“压缩”(反复除以相同的数字),使其保持小而易于处理。欲了解如何处理文本数据,请点击前文中的 scikit-learn 链接。
逐步来看,和 "trainer" 一起出现的词汇更多的是 "shouted",而不是 "stopped"。对于公交车,"broke"(指“故障”),"road" 和 "stopped" 出现的频率高于 "shout"。
"Coach" 平均出现在 "shouted"、"stopped"、"road" 和 "broke" 这些词汇上,因为它可以既是训练师也可以是公交车,因此我们在翻译这个词时会遇到问题。"Coach" 的多义性(有多个含义)可能导致翻译不准确。
KNN 算法加载了包含训练数据的 V1.csv 文件,并得出了以下结果:

图 6.1:KNN 算法的结果
knn_polysemy.py 程序得出了以下结论:
- 
蓝色的动词 "broke" 更有可能适用于公交车(x 轴值 > 6),而不是适用于训练师(x 轴值 < 4)。然而,“coach”仍然位于“trainer”之上和“bus”之下,因为它既可以是训练师也可以是公交车。 
- 
"road" 这个词遵循与蓝色图表相同的逻辑。 
- 
动词 "stopped" 更适用于训练师,也更适用于公交车。"Coach" 仍然无法决定。 
- 
动词 "shouted" 更明确地适用于训练师,而不是公交车。"Coach" 仍然无法决定。 
注意,这些图表中每个点的坐标如下:
- 
y 轴:公交车 = 1,教练车 = 2,训练师 = 3。 
- 
x 轴:该值代表“压缩”后的出现频率(即词汇出现的次数)。 
这是在多个来源中搜索这些词汇的结果。
当一个新的点,即名为 P[n] 的数据点被引入系统时,它将根据 k 的值找到其最近的邻居。
KNN 算法将计算 P[n] 和从 P[1] 到 P[n] [– 1] 之间所有其他点的欧几里得距离,使用欧几里得距离公式。KNN 中的 k 代表算法在分类时会考虑的“最近邻”数量。例如,Pn 和 P1 之间的欧几里得距离 (d[1]) 为:

考虑到计算距离的数量,使用如 sklearn.neighbors 提供的函数是必要的。
knn_polysemy.py 程序
程序导入了之前描述的 V1.csv 文件,打印出几行数据,并将标签准备到正确的数组中,分别对应 x 轴和 y 轴,如下面的源代码示例所示:
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
# Import data
df = pd.read_csv('V1.csv')
print (df.head())
# KNN Classification labels
X = df.loc[:,'broke':'shouted']
Y = df.loc[:,'class'] 
然后,模型进行训练,如下所示的代码:
# Trains the model
knn = KNeighborsClassifier()
knn.fit(X,Y) 
模型训练完成后,发出预测请求,并由以下代码提供预测:
# Requesting a prediction
#broke and stopped are
#activated to see the best choice of words to fit these features.
# brock and stopped were found in the sentence to be interpreted.
# In X_DL as in X, the labels are : broke, road, stopped,shouted.
X_DL = [[9,0,9,0]]
prediction = knn.predict(X_DL)
print ("The prediction is:",str(prediction).strip('[]')) 
显示的结果如下:
The prediction is: 'bus' 
初始数据已绘制以便可视化,具体实现如以下代码所示:
#Uses the same V1.csv because the parsing has
# been checked and is reliable as "dataset lexical rule base".
df = pd.read_csv('V1.csv')
# Plotting the relation of each feature with each class
figure,(sub1,sub2,sub3,sub4) = plt.subplots(
    4,sharex=True,sharey=True)
plt.suptitle('k-nearest neighbors')
plt.xlabel('Feature')
plt.ylabel('Class')
X = df.loc[:,'broke']
Y = df.loc[:,'class']
sub1.scatter(X, Y,color='blue',label='broke')
sub1.legend(loc=4, prop={'size': 5})
sub1.set_title('Polysemy')
X = df.loc[:,'road']
Y = df.loc[:,'class']
sub2.scatter(X, Y,color='green',label='road')
sub2.legend(loc=4, prop={'size': 5})
X = df.loc[:,'stopped']
Y = df.loc[:,'class']
sub3.scatter(X, Y,color='red',label='stopped')
sub3.legend(loc=4, prop={'size': 5})
X = df.loc[:,'shouted']
Y = df.loc[:,'class']
sub4.scatter(X, Y,color='black',label='shouted')
sub4.legend(loc=4, prop={'size': 5})
figure.subplots_adjust(hspace=0)
plt.show() 
本程序的压缩版已在 Google_Translate_Customized.py 中引入,如下所示:
def knn(polysemy,vpolysemy,begin,end):
    df = pd.read_csv(polysemy+'.csv')
    X = df.loc[:,'broke':'shouted']
    Y = df.loc[:,'class']
    knn = KNeighborsClassifier()
    knn.fit(X,Y)
    prediction = knn.predict(vpolysemy)
    return prediction 
描述如下:
- 
polysemy是要读取的文件名,因为它可以是任何文件。
- 
vpolysemy是需要预测的向量。
- 
在未来的待办事项中, begin应替换broke,end应替换shouted,以便该功能可以预测任何向量的值。
- 
调用 KNN 分类器并返回预测结果。 
现在我们已经准备好 KNN 分类器函数,可以自定义 Google 翻译。
在 Google_Translate_Customized.py 中实现 KNN 函数
由于涉及的语言学概念,该程序需要更多的时间和研究。掌握算法的最佳方式是按顺序运行它。
Google 翻译提供了多种翻译方法。我们将在以下代码中重点介绍其中两种:
#print('Phrase-Based Machine Translation(PBMT)model:base'): #m='base'
print('Neural Machine Translation model:nmt') 
解释如下:
- 
基于短语的机器翻译(PBMT):该方法翻译整个单词序列。短语,或者更确切地说是短语(多词表达),并不总是完整的句子。 
- 
神经机器翻译(NMT):该方法使用神经网络,如循环神经网络(RNN),后续章节将详细介绍此内容。该方法超越了短语,考虑了整个句子。在本章提供的数据集方面,这种神经网络方法提供了略微更好的结果。 
这两种方法以及 Google 的其他方法都很有趣,但在许多情况下,Google 翻译仍然需要额外的自定义算法才能达到可接受的质量水平。在本章中,我们探索了使用 KNN 的一种方法,但你可以使用其他方法,只要它们有效。
如你所见,考虑到许多语言的词汇领域和结构、它们的区域性变化以及行话,主题极为复杂。
步骤 1 – 将 X 数据集逐行从英语翻译成法语
以下代码调用翻译函数:
for xi in range(len(X)):
    source=X[xi]
    targetl="fr";m='nmt'
    result = g_translate(source,targetl,m) 
代码解释如下:
- 
xi是X中的行号。
- 
source是X中的xi行。
- 
targetl是目标语言,在本例中是fr(法语)。
- 
m是方法(PBMT 或 NMT),如前所述。在这种情况下,应用的是nmt。
- 
然后,调用本章前面描述的 Google 翻译功能。结果存储在 result变量中。
步骤 2 – 反向翻译
如果 L[1] 是某人的母语,而 L[2] 是该人完全不懂的语言,那么该如何知道从语言 L[1] 到语言 L[2] 的翻译是否正确?
这是翻译人员通常使用反向翻译来检查翻译的原因之一:
翻译 = 从 L[1] 到 L[2]的初始翻译
反向翻译 = 从 L[2] 到 L[1]的翻译回传
如果未获得初始文本,那么可能存在问题。在这种情况下,可以将初始句子L[1]的长度与反向翻译回到L[1]的相同句子长度进行比较。以下代码调用反向翻译:
 back_translate=result
    back_translate = g_translate(back_translate,targetl,m)
    print("source:",source,":",len(source))
    print("result:",result)
    print("target:",back_translate,":",len(back_translate)) 
长度比较可以用于改进算法:
初始 n-gram 的长度 = 反向翻译的长度
如果它相等,则翻译可能是正确的。如果不相等,则可能是错误的。当然,在每次翻译时必须应用更多的方法。然而,任何能带来改进的方法,都是一个好的进步。在这种情况下,源句(初始句子)会与反向翻译进行比较,代码如下:
 if(source == back_translate):
        print("true")
        if((term not in words)and (xi!=4)):
            t+=1
    else:
    f+=1;print("false") 
- 
t是一个True计数器。
- 
f是一个False计数器。
X的第一行如下运行:
source: Eating fatty food can be unhealthy. : 35
result: Manger de la nourriture grasse peut être malsain.
target: Eating fat food can be unhealthy. : 33
false 
吃油腻食物被反向翻译为吃油腻食物,这有点错误。可能哪里出了问题。
法语句子也听起来不对。油腻食物不能这样翻译。通常,常见的句子是manger gras,意思是吃(manger)油腻的(gras),这不能直接翻译成英文。
本节中提到的X数组从第 8 行开始:
X=['Eating fatty food can be unhealthy.',
   'This was a catch-22 situation.',
   'She would not lend me her tote bag',
   'He had a chip on his shoulder',
....] 
有几个短语翻译错误,例如,X[4],'He had a chip on his shoulder'。我编写了一个基于短语的翻译,使用在以下代码中的False条件触发器。
 else:
        f+=1;print("false")
    if(X2[xi]>0):
        DT=deeper_translate(source,xi)
        dt+=1 
由于我并未为本书编写完整的应用程序,而只是编写了一些可扩展的示例,所以我使用X2作为触发器。如果X2[x1]>0,则激活deeper_translate函数。
第 3 步 - 使用基于短语的翻译进行更深层次的翻译
deeper_translate有两个参数:
- 
source: 初始句子待翻译
- 
x1: 目标句子
在这种情况下,问题是解决一种存在于英语中但在法语中不存在的习惯表达:
source: He had a chip on his shoulder : 29
result: Il avait une puce sur son épaule
target: He had a chip on his shoulder : 29
false 
有 chip 在肩膀上意味着对某些事物或某些人有问题。这表达了一种紧张的情绪。
Google 将chip翻译为假设是计算机芯片,或者法语中的puce,它既可以指计算机芯片,也可以指跳蚤。这个翻译没有意义。
Chip进入三个类别,应当标注为:
- 
习惯表达 
- 
行话 
- 
词义歧义 
这时,我创建的以下函数模拟了基于短语的解决方案来实现更深层次的翻译。
def deeper_translate(source,index):
    dt=source
    deeper_response=phrase_translation[index]
    if(len(deeper_response)<=0):
        print("deeper translation program result:",
            deeper_response,":Now true") 
deeper_translate函数会在以下phrase_translation数组中查找包含chip的翻译句子(列表、向量或其他必要的结构)。
phrase_translation=['','','','Il est agressif','','','','','','','',''] 
最终结果会给出翻译、反向翻译、术语搜索和短语翻译。以下是产生的结果,每一行前都有添加的注释:
Initial sentence:
source: He had a chip on his shoulder : 29
Wrong answer:
result: Il avait une puce sur son épaule
The back-translation works:
target: He had a chip on his shoulder : 29
term: aggressif
false
deeper translation program result: Il est agressif 
问题是,term来自哪里?
term来自X1,这是一个应包含在翻译中的关键词列表。X1是手动输入的,但它应该是通过对句子中被视为类别的单词进行自动搜索得到的可能性列表。这意味着待翻译的句子应该具有多个层次的意义,而不仅仅是被计算出的字面意义。
实际的True/False条件包含以下深度翻译级别的词汇进行检查:
 if(source == back_translate):
        print("true")
        if((term not in words) and (xi!=4)):
            t+=1
    else:
        f+=1;print("false")
        if(X2[xi]>0):
            DT=deeper_translate(source,xi)
            dt+=1 
在当前原型状态下,只有示例四激活短语翻译。否则,将接受True。如果是False,则深度翻译仅在该示例代码中的两个案例中被激活。该标志位在X2中(0或1)。
deeper_translate函数被调用用于短语翻译(如前所述)或 KNN 程序,如果短语翻译未能成功,则会激活 KNN 程序。
如果翻译未能成功,将为 KNN 算法准备一个 n-gram,如下代码所示:
 if(len(deeper_response)<=0):
        v1=0
        for i in range(4):
            ngram=V1[i]
            if(ngram in source):
                vpolysemy[0][i]=9
                v1=1 
V1[i]包含前面 KNN 算法中描述的运输词汇领域中的关键词(n-grams),如下面的代码所示:
V1=['broke','road','stopped','shouted','coach','bus','car',
    'truck','break','broke','roads','stop'] 
源句子(待翻译句子)会被解析为每个 n-gram。如果找到了该 n-gram,则会为该 n-gram 激活多义性向量。初始值设置为0,如下面的代码所示:
vpolysemy=[[0,0,0,0]] 
激活变量v1,它通知程序必须读取V1.csv文件来处理此案例。应自动创建无限数量的 KNN 参考,如前面 KNN 部分所述。
在这种情况下,只有v1被激活。但在为公司定制本地需求的项目中工作了几个月之后,应该创建许多其他文件。
在这种情况下,当激活v1时,它会按照如下方式填充变量。
 if(v1>0):
        polysemy='V1'
        begin=str(V1[0]).strip('[]');end=str(V1[3]).strip('[]')
        sememe=knn(polysemy,vpolysemy,begin,end) 
- 
polysemy表示需要打开的 KNN 文件。
- 
begin是V1向量的第一个标签,end是V1向量的最后一个标签。
- 
sememe是我们期望的预测结果。
现在,调用 KNN 算法的精简版本,如前面所描述的knn_polysemy.py中的代码:
def knn(polysemy,vpolysemy,begin,end):
    df = pd.read_csv(polysemy+'.csv')
    X = df.loc[:,begin:end]
    Y = df.loc[:,'class']
    knn = KNeighborsClassifier()
    knn.fit(X,Y)
    prediction = knn.predict(vpolysemy)
    return prediction 
在本例中,展示了KNN 部分中coach的多义性特征。输出将如下所示:
Source: The coach broke down, stopped and everybody was complaining : 59
result: L'entraîneur est tombé en panne, s'est arrêté et tout le monde se plaignait
target: The coach broke down, stopped, and everyone was complaining : 59
term: bus
false 
翻译错误,因为 Google 翻译返回了trainer而不是bus。
单词bus在英语和法语中是相同的。
KNN 程序返回了英语中的bus,作为在出现broke down和stopped时应该使用的正确单词,正如 KNN 部分所示。
deeper_translate函数中其余源代码的目标是替换coach—这个增加多义性特征的单词,用一个更合适的单词(限制多义性)来翻译:sememe。
sememe变量由下面代码中的 KNN 函数初始化:
 sememe=knn(polysemy,vpolysemy,begin,end)
            for i in range(2):
                if(V1_class[i] in source):
                    replace=str(V1_class[i]).strip('[]')
                    sememe=str(sememe).strip('[]')
                    dtsource = source.replace(replace,sememe)
                    targetl="fr";m='base'
                    result = g_translate(dtsource,targetl,m)
                    print('polysemy narrowed result:',result,
                        ":Now true") 
该函数通过 KNN 算法在英语句子中将coach替换为bus,然后让谷歌翻译再尝试一次。正确的答案被返回。
与其尝试翻译一个具有多重含义的词(多义词),deeper_translate函数首先用一个更合适的词(含义较少)替换该词。通常可以获得更好的结果。
第 3.1 步——添加频率学派错误概率函数
添加了一个频率学派的错误概率函数来衡量性能,具体如以下代码所示:
def frequency_p(tnumber,cnumber):
    ff=cnumber/tnumber #frequentist interpretation and probability
    return ff 
- 
cnumber是谷歌翻译返回的错误答案数量。
- 
tnumber是已翻译的句子数量。
- 
ff给出了直接的错误(翻译)概率,ETP。
当翻译错误时,或者f>0时,调用该函数,如以下代码所示:
 if(f>0):
        B1=frequency_p(xi+1,f) #error detection probability before deep translation
        B2=frequency_p(xi+1,f-dt) #error detection probability after deep translation
    if(f>0):
        print("ETP before DT",round(B1,2),
            "ETP with DT",round(B2,2))
    else:
        print('Insufficient data in probability distribution') 
- 
B1是调用deeper_translate函数之前的错误(翻译)概率(ETP)。
- 
B2是调用deeper_translate函数后的 ETP(错误翻译概率)。
程序结束时,显示总结,具体如以下输出所示:
print("------Summary------")
print('Neural Machine Translation model:nmt')
print('Google Translate:',"True:",t,"False:",f,'ETP',round(f/len(X),2))
print('Customized Google Translate:',"True:",t,"False:",f-dt,'ETP',round((f-dt)/len(X),2))
a=2.5;at=t+a;af=f-a #subjective acceptance of an approximate result
print('Google Translate acceptable:',"True:",at,"False:",af,'ETP',round(af/len(X),2))
#The error rate should decrease and be stabilized as the KNN knowledge base increases
print('Customized Google Translate acceptable:',"True:",at,"False:",af-dt,'ETP',round((af-dt)/len(X),2)) 
- 
增加了对近似结果的主观接受度,以提高真实概率。 
- 
错误率应随着 KNN 知识库质量的提高而下降。在频率概率理论中,这意味着应该达到一个稳定的预测率。 
我们已经尝试改进谷歌翻译到最后了。让我们看看实验后的一些结论。
关于谷歌翻译定制实验的结论
生成的最终错误(翻译)概率非常有趣,具体如以下输出所示:
>>------Summary------
>>Neural Machine Translation model:nmt
>>Google Translate: True: 2 False: 8 ETP 0.67
>>Customized Google Translate: True: 2 False: 7 ETP 0.58
>>Google Translate acceptable: True: 4.5 False: 5.5 ETP 0.46
>>Customized Google Translate acceptable: True: 4.5 False: 4.5 ETP 0.38 
即使拥有 NMT 模型,谷歌翻译仍然在挣扎。
这为 AI 语言学家提供了极好的机会,正如一些方法所展示的那样,可以在本地层面改进谷歌翻译,甚至可以更进一步。
通过这次对谷歌翻译的实验,可以看出谷歌只是触及了真正生活翻译的表面,而这些翻译对于接收者——本地语言使用者来说才是正确的。要使这项技术走上正轨,需要一个真正的公司项目,并对其盈利能力进行财务分析,然后再消耗资源。
颠覆性的革命性循环
如你现在所见,谷歌翻译与所有 AI 解决方案一样,都有其局限性。一旦达到这个极限,你就处于前沿地带。
跨越边界进入 AI 前沿地带;独立创新或与团队一起创新。
如果你在公司工作,可以为数百名用户创建一个革命性的定制解决方案。它不一定要公开,它可以成为公司的一项强大资产。
在某个时刻,革命性的插件将超越公司本身,其他人也会使用它。它将成为颠覆性技术。
最终,其他人会到达你现在的颠覆性解决方案的极限。然后,他们会在自己的公司中创新并定制该方案作为革命性解决方案。这就是我所说的颠覆性革命循环。它既充满挑战又令人兴奋,因为这意味着 AI 开发者在短期内不会全部被 AutoAI 机器人取代!
设计一个解决方案并不意味着它会成为发明、创新、革命性或颠覆性。但这其实并不重要。公司通过解决方案获得的收益代表了它所销售的东西的新颖性,只要它是有利可图的。这是规则一。也就是说,如果公司在市场上没有创新,它将无法在多年中生存下来。
如果一个产品因为安全原因需要保持高质量,那么它应该在发明阶段保持足够长的时间。若产品可以在市场的低端产生销售,甚至在其完全完成之前,那么公司应该开始销售该产品。公司将因创新获得声誉,获得更多资金投入,并占领竞争对手的市场份额。
总结
Google 翻译是颠覆性营销的一个好例子。如上所示,其理论、模型甚至云架构已经超过 10 年。然而,每当数以亿计的用户中的某一个偶然使用它时,它就通过将用户吸引到 Google 解决方案中而产生更多的颠覆。用户会一次又一次地回到这里查看更多广告,大家都很高兴!
人工智能才刚刚起步。Google 翻译自 2006 年推出以来,一直存在。然而,翻译结果仍然为开发人员、语言学家和数学家提供了改进的空间。Google 已经加入了神经网络,并提供了其他模型,通过分析整个句子来改进翻译。那么,什么时候它能真正可靠呢?与此同时,全球社区正在推动人工智能的进步,超越最前沿,进入新的“前沿领域”。
在本章中,我们首先仔细探讨了发明与创新之间的差异。创新对整个市场产生影响,而发明仅是创新的起点。我们看到,一项革命性的解决方案可能是技术突破。但只有当这种革命性的解决方案扩展到市场的其他部分时,它才能成为颠覆性的。
然后,我们研究了一些基本的语言学原理,帮助我们理解 Google 翻译,它的局限性以及如何改进翻译错误。
我们最终实现了一个定制的翻译工具,使用 KNN 算法来绕过 Google 翻译的错误。
在下一章,第七章,使用朴素贝叶斯优化区块链,我们将进一步探讨 AI 新前沿的研究,通过使用区块链在企业环境中进行预测。
问题
- 
是不是最好等到产品达到顶级质量再推向市场?(是 | 否) 
- 
考虑到所做的投资,新产品应始终定价较高,以进入市场的高端细分市场。(是 | 否) 
- 
发明一种新解决方案会使其自然而然地被认可。(是 | 否) 
- 
AI 可以在不使用标准非学习算法的情况下解决大多数问题。(是 | 否) 
- 
谷歌翻译可以令人满意地翻译所有语言。(是 | 否) 
- 
如果你不具备创意,尝试创新是没有用的。(是 | 否) 
- 
如果你不是语言学家,尝试改进谷歌翻译是没有意义的。(是 | 否) 
- 
翻译过于复杂,难以理解。(是 | 否) 
- 
AI 已经达到了它的极限。(是 | 否) 
进一步阅读
- 
哈佛商业评论关于颠覆性创新的文章可以在这里找到: hbr.org/2015/12/what-is-disruptive-innovation
- 
谷歌翻译文档可以在这里找到: cloud.google.com/translate/docs/
- 
谷歌 AlphaGo Zero: deepmind.com/blog/article/alphago-zero-starting-scratch
- 
KNN 文档: scikit-learn.org/stable/modules/neighbors.html#neighbors
- 
关于翻译神经网络的见解: research.googleblog.com/2016/09/a-neural-network-for-machine.html
- 
关于英法翻译的见解: www.oneskyapp.com/blog/french-translation-challenges/
- 
更多关于如何处理文本数据以构建算法数据集的内容: scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html
第七章:使用朴素贝叶斯优化区块链
在本章的三部分内容中,我们将使用区块链结合朴素贝叶斯优化供应链。为了实现这一目标,我们将首先了解如何以加密货币为例生成区块链。
区块链已进入企业,并且将长期存在。数百家大型企业已实施了 IBM Hyperledger。这些企业的供应商将逐步加入该网络。企业区块链将提供多年工作机会,因为需要维护和更新数百万行代码以增加新功能。
挖矿加密货币是区块链最为人知的应用。加密货币在全球范围内增长。本章将通过比特币的例子解释区块链的挖矿部分是如何运作的。
接下来,我们将分析如何将区块链用于不同于生成加密货币的目的。例如,企业使用区块链记录公司之间的交易。
IBM 成立于 1911 年,至今是该领域经验最丰富的公司。谷歌、亚马逊和微软也提供具有历史意义的机器学习平台。然而,IBM 提供的机器学习平台依托于公司可提供的 100 多年经验,具有独特优势。
IBM 在计算机和软件市场的多年历程并不平坦。一些糟糕的决策给公司在全球范围内带来了很多问题。IBM 从这些错误中吸取了教训,现在提供强大的解决方案,包括用于区块链解决方案的 IBM Hyperledger。IBM 提倡将区块链用于企业交易。
最后,我们将进入本章的第三部分,解释区块链对全球公司意味着什么,以及如何使用区块链中的信息为优化算法提供人工智能支持。将应用朴素贝叶斯算法对区块链样本进行优化库存水平。
本章将涵盖以下主题:
- 
区块链的背景 
- 
使用区块链挖掘比特币 
- 
将区块链用于商业交易 
- 
区块链的区块如何为公司之间共享信息提供独特的方式 
- 
将人工智能应用于区块链的区块中,以预测并建议交易 
- 
朴素贝叶斯 
- 
如何在区块链的区块上使用朴素贝叶斯来预测后续交易和区块 
让我们从简短的区块链介绍开始。
第一部分——区块链技术的背景
在本节中,我们将介绍使用区块链进行加密货币挖矿的过程。通过区块链产生比特币使得这一技术具有了颠覆性。本节的目的是在深入探讨区块链技术的后续应用之前,理解区块链冒险是如何开始的。
区块链技术将彻底改变各个领域的交易。区块链在 2008 年出现。没有人知道到底是谁发明了它们。每个区块都包含其前一个区块(前区块)的加密哈希值、日期时间(时间戳)数据,以及有关交易的信息。
在过去的 1,000 多年里,交易大多是局部的记账系统。在过去 100 年里,尽管计算机时代改变了信息管理的方式,但变化并不大。每家公司依然将其交易保持在内部,只通过繁琐的系统共享一些信息。
区块链使得交易区块对它所在的全球网络可见。
需要记住的基本概念是共享和隐私控制。这两个概念似乎产生了认知失调,似乎是不可能解决的问题。然而,它已经被解决了,并且它将改变世界。
当一个区块(任何类型的交易)被生成时,它会与整个网络共享。如果该区块的管理者希望信息保持私密,则对区块内信息的读取权限可以得到管理,从而保持隐私。
无论目标是通过区块挖掘比特币,还是使用区块进行交易,人工智能将在不久的将来增强这一创新。
在接下来的章节中,我们将详细讨论区块链及其应用。理解如何为加密货币生成区块将帮助我们掌握区块链技术。一旦我们理解了区块链技术,就能更容易地看出这种安全加密的方法如何应用于任何类型的商业交易,超越加密货币。让我们先去挖矿吧!
挖掘比特币
在区块链中创建一个区块并不一定非要生成一个比特币,这只是另一种形式的交易。但理解如何挖掘加密货币提供了一个很好的方式来理解区块链,并将其应用于许多其他领域。
挖掘比特币意味着为一个有效的交易创建一个数学区块,并将该区块添加到区块链中;即区块链:
区块链 = {区块[1],区块[2],刚刚添加的区块 …… 区块[n]}
区块链不能回到过去。它就像生活中的时间标记功能。在第m分钟,你做了一件事,在第m + 1 分钟做了另一件事,在第m + n分钟做了另一件事,以此类推。你无法回到过去。过去的事就已经做了。
当一个区块被添加到比特币链时,无法撤销该交易。
全球的比特币挖掘网络由节点组成。通过适当的软件,你可以开放端口,分配大约 150+ GB 的磁盘空间,并生成新区块。各节点相互通信,信息会传递到整个网络中的其他节点。
为了让一个节点成为矿工,它必须解答复杂的数学难题,这些难题是比特币程序的一部分。
为了解决难题,软件必须找到一个数字,这个数字与正在生成的区块中的数据结合后,能适合某个特定的范围。这个数字会通过一个哈希函数。
你可以将这个数字称为nonce,它是唯一使用一次的。例如,生成一个介于 0 和 4,294,967,296 之间的整数来代表比特币。
这个过程是随机的。软件生成一个数字,将其通过哈希函数,然后将其发送到网络中。第一个矿工生成一个位于预期范围内的数字,并通知整个网络该区块已经生成。其余的网络成员停止在该区块上工作,转而开始处理另一个区块。
挖矿者的奖励自然是以比特币的形式支付的。它代表了大量资金,但考虑到网络中的竞争以及产生正确结果所需的成本(CPU、电力、磁盘空间和时间),它并不容易获得。
必须保持挖掘比特币或任何其他加密货币的成本与挖掘所获得的回报之间的平衡。
在讲完比特币挖掘后,我们将简要讨论如何实际使用加密货币。
使用加密货币
对加密货币要非常小心。目前有 1500 多种加密货币。这个概念听起来很吸引人,但结果依然是货币。货币可能会波动,如果发生崩盘,你可能会在不到一小时内失去一生的积蓄。
黄金法则:如果你无法抗拒投资加密货币,千万不要投资超过你能承受损失的金额。
话虽如此,要使用加密货币,首先需要设置一个钱包来存储比特币。例如,钱包可以是在线的,通过某个提供商,或者甚至是离线的。
一旦完成,你就可以根据自己的意愿,用现金或通过信用卡、借记卡和转账购买比特币。
记住,你购买这些货币就像购买任何其他货币一样,拥有所有的潜力,但也承担着所有的风险。
在本节中,我们了解了区块链时代如何从比特币生产开始,进而理解如何通过比特币使用区块链来挖掘加密货币。考虑到区块链的原始创建方式,我们可以将区块链应用到许多其他领域。
在我们三部分章节的第二部分中,我们将看到如何将区块链应用于加密货币之外的领域。我们将其应用于供应链。
第二部分 – 使用区块链在供应链中共享信息
在第一部分 – 区块链技术背景中,我们了解了如何使用区块链挖掘加密货币。在进入区块链世界的先决条件已达成后,本节将展示如何在供应链中使用区块链。这不涉及加密货币。它为将区块链与人工智能结合创新开辟了道路。
供应链是一个生产和服务链条,它将产品从起点送到消费者。例如,取一卷从印度运送到突尼斯的布料。在突尼斯,这些布料被裁剪成图案并组装成衣服。然后,这些衣服被运送到法国,在那里进行包装并印上品牌。接着,它们被存储在仓库中,准备运送到实体店或直接送到在线客户。我们可以将这个供应链总结如下:
来自印度的布料 -> 在突尼斯裁剪和组装 -> 运送到法国 -> 包装 -> 存储 -> 运送到商店或直接送达消费者
如服装生产和交付系统这样的供应链过程涉及到成千上万的人:生产场地、运输人员、仓库员工以及每个环节的管理团队。
这就是现代区块链技术的优势所在,它能够在一个系统中追踪所有的交易。
在以下示例中,我们将以六家公司 A、B、C、D、E 和 F 为例。在第一章,《通过强化学习开始使用下一代人工智能》中,我们使用了一个六行六列的奖励矩阵。在那一章中,我们用 A、B、C、D、E 和 F 来表示强化学习中的马尔可夫决策过程中的位置。章节结束时,我们看到奖励矩阵可以应用于许多不同的领域。在我们的案例中,我们将把这六个项目(A、B、C、D、E 和 F)称为公司,并将它们在供应链过程中的位置(每个公司对应一个位置)进行描述。
供应链中的每个公司,A 到 F,作为区块链成员,可以优化其活动。与其每个公司都有独立的交易账本,不如使用一个中央区块链,集中所有交易(区块):
- 
布料离开印度的时间和数量 
- 
它什么时候上船,花了多长时间 
- 
当船到达突尼斯时 
- 
……直到消费者的所有中间活动 
拥有这些数据后,区块链中的区块(交易记录)已经成为了机器学习的金矿,用来发现信息并进行预测。使用该系统的一个盈利原因是减少库存水平。堆积未售出的商品以预测销售情况是昂贵的,甚至可能会毁掉公司的利润。相反,如果供应链中的每个公司都能通过区块链中的区块看到其他合作伙伴的库存水平和实际需求,他们就能根据实际需求调整库存,从而节省大量资金!
让我们以 IBM 软件为例,来看一下这个如何运作。
基于 Hyperledger Fabric 的 IBM Blockchain,为全球各公司提供了一种共享区块链交易网络的方式,避免了矿业和加密货币的使用。
该系统基于 Linux 基金会项目。Hyperledger 是由 Linux 基金会主办的一个开源合作项目。
在这一层,Hyperledger 使用区块链来保证安全的交易,而不是尝试优化加密货币方面。该软件在所有参与方共享的区块链网络中生成区块,但它们不必以货币意义上购买加密货币——只是以技术意义上购买。
在下图中,我们将使用六个节点(公司 A 到 F)来说明我们在第一章中学习的马尔可夫决策过程,通过强化学习入门下一代人工智能,如何应用于区块链:

图 7.1:马尔可夫决策过程图
每个节点代表一个公司,这些公司参与了为这六家公司设置的 IBM Hyperledger 网络,如下表所示:
| 公司 | 活动 | ML 权重 | 
|---|---|---|
| A 在这个网络中买卖服装以及其他产品。 | 向网络提供商品,但保持库存水平较低 | 库存水平 | 
| B 在这个网络中买卖布料及其他产品。 | 向网络提供商品,但保持库存水平较低 | 库存水平 | 
| C 在这个网络中买卖按钮以及其他产品。 | 向网络提供商品,但保持库存水平较低 | 库存水平 | 
| D 在这个网络中买卖印刷布料以及其他产品。 | 向网络提供商品,但保持库存水平较低 | 库存水平 | 
| E 在这个网络中买卖配件(如皮带、手链)及其他产品。 | 向网络提供商品,但保持库存水平较低 | 库存水平 | 
| F 在这个网络中买卖包装盒以及其他产品。 | 向网络提供商品,但保持库存水平较低 | 库存水平 | 
表格的结构如下:
- 
公司包含六家公司,{A、B、C、D、E、F},它们的活动各不相同。在这个示例中,每家公司只有一个地点,因此 A 到 F 也是公司位置。 
- 
活动:该公司群体的一部分成员,负责向其成员供应商品,但确保库存水平保持较低,以减少成本。 
- 
ML 权重表示通过机器学习对库存水平的分类,以进行预测。在我们的示例中,盈利的关键是追踪供应链中每个成员(A 到 F)的库存水平。例如,如果 F 公司的库存水平下降,网络中的其他成员(A 到 E)可以预见并只提供有限的必要量,以便 F 的库存水平再次达到可接受水平。 
每年有数百万的商业交易,涉及大量运输(卡车、火车、船只、飞机),如果没有像 IBM Hyperledger 这样的解决方案,管理这种类型的网络在 21 世纪将变得越来越复杂。
通过 IBM Hyperledger,企业拥有一个包含智能合约(在线)和实时追踪的在线交易账本。
交易是安全的;它们可以是私密的或在网络成员之间公开的,并且为人工智能解决方案提供实时优化信息。
在供应链网络中使用区块链
IBM Hyperledger 为人工智能开发者提供了一个独特的优势,超越任何其他数据集——一个 100%可靠、实时更新的数据集。
网络中的每个公司成员(A 到 F)都会为每个交易创建一个区块,以便 AI 分析师可以访问数据并进行预测。为了使系统正常工作,网络中的每个成员(A 到 F)将创建区块到区块链中,以便其他人可以查看记录的信息并利用这些信息做出决策。
创建区块
区块的形成方法与挖掘比特币时描述的方法类似,唯一不同的是,这次货币不是目标。目标是在必要时进行安全交易并使用智能合约。以下截图是一个标准的 IBM 界面,可以根据需要进行定制:

图 7.2:标准 IBM 界面
你可以看到构成区块链的独立且独特的区块。IBM Hyperledger 中的每个区块都有一个唯一的编号。在这个例子中,它是111,并且对区块103进行了放大显示。
我们图表中的供应链网络中的一个区块(A 到 F)可以是购买产品 X 并附带合同的交易。例如,交易可以发生在 A 公司和 B 公司之间。下一个区块可能是该产品从 A 运输到 B 的过程,在区块链网络中进行。
附加到该区块的信息存储在 Hyperledger 库中:公司名称(A 到 F)、地址、电话号码、交易描述以及网络公司所需的任何其他类型数据。每个区块可以根据附加的权限属性,由所有成员或某些成员查看。
探索区块
探索区块为人工智能程序提供了一座金矿:一个真实且 100%可靠的数据集。
对于 AI 优化来说,最有趣的部分是区块信息,如以下截图所示。当前区块与前一个区块以及交易代码一起被添加到链中:

图 7.3:探索区块链
请注意,给定区块的区块哈希(参见前面的挖掘部分)与前一个区块的哈希相关联,并拥有一个唯一的交易代码。
一旦我们拥有了一组区块数据(交易类型、日期、金额等),我们就可以开始构建 AI 预测算法。IBM 提供了通过脚本和其他工具进行数据提取的可能性。
一旦我们拥有包含区块链区块的数据集,预测的目标将是确定库存水平类别,以查看供应链网络中的某个成员(A 到 F)是否需要补充库存。
区块链的区块提供了可以用于预测网络在每个交易后将面临的库存水平类型的数据。每家公司都能运行一个预测算法,利用现有数据预测潜在的补货需求。例如,A 公司可能检测到 B 公司需要更多的布料。
考虑到数据量,像朴素贝叶斯这样的预测算法能够胜任这个工作。
第三部分 – 在区块链流程中使用朴素贝叶斯优化供应链
朴素贝叶斯将使用一些关键的信息作为特征,以优化仓库存储和产品的实时可用性。
朴素贝叶斯学习功能将根据之前的区块学习如何预测应该插入区块链中的下一个区块(为需要更多库存的其他公司提供支持)。这些区块将像其他时间戳数据一样被插入数据集中,以进行预测。
朴素贝叶斯基于贝叶斯定理。贝叶斯定理应用条件概率,定义如下:

- 
P(A|B) 是一个后验概率,即在观察到某些事件 (B) 后 A 发生的概率。它也是一个条件概率:即在 B 已经发生的情况下,A 发生的可能性。 
- 
P(B|A) 是在已知先验观察 A 后 B 发生的概率。它也是一个条件概率:即在 A 已经发生的情况下,B 发生的可能性。 
- 
P(A) 是在观察之前 A 发生的概率。 
- 
P(B) 是预测的概率。 
朴素贝叶斯虽然基于贝叶斯定理,但假设一个类别中的特征是相互独立的。在许多情况下,这使得预测更容易实施。无论特征是否相关,它们的统计存在都会产生一个预测。只要预测保持足够高效,朴素贝叶斯就提供了一个好的解决方案。
朴素贝叶斯示例
本节中,我们将先通过一个数学例子来说明朴素贝叶斯,然后再编写 Python 程序。本节的目标只是理解朴素贝叶斯中涉及的概念。
本节不是开发章节,而是帮助理解现实生活示例的基本概念以及用于预测的数学知识的章节。
本章中的区块链表示基于服装行业制造商品的库存水平信息。如需了解更多,阅读第十二章,人工智能与物联网(IoT),该章详细描述了一个人工智能优化的服装制造过程。
在本节中,我们将专注于存储。在服装行业中,缝纫工作站的负荷以存货单位(SKUs)的数量来表示。例如,一个 SKU 可以是产品 P:一条特定尺寸的牛仔裤。
一旦服装生产完成,它就会进入存储阶段。此时,区块链中的一个区块可以用于表示该交易,为机器学习算法提供两个有用的特征:
- 
衣物存储的那一天 
- 
现在存储在库存中的该 SKU 服装的总数量 
区块链中包含交易信息的日期(时间戳)和存储数量。
由于区块链包含了网络中 A、B、C、D、E 和 F 公司位置的所有存储块,一个机器学习程序可以访问数据并进行预测。
目标是在六个位置均匀分布给定产品的存储量,如下直方图所示:

图 7.4:产品在六个位置分布的存储水平直方图
此截图显示了产品 P 在六个位置分布的存储水平。这个区块链网络中的每个位置都是一个枢纽。在供应链管理(SCM)中,一个枢纽通常是一个中间存储仓库。例如,为了覆盖这六个位置的区域,同一种产品将在每个位置存储。这样,本地的货车可以来取货进行送货。
目标是在需要时在点位置 L(A 到 F)有可用的产品 P。
例如,从位置L到位置点a[1](商店或家中)的交货时间只需几个小时。如果 A 没有存储 P,那么细化的消费者就必须等待产品从 C 到 A 的运输,例如。
如果区块链网络组织良好,一个位置可以专门生产产品 P(最佳生产成本),并均匀分布存储在六个位置,包括自身的数量。
通过在所有位置均匀平衡存储量,系统将在连续的交付流程中运行。
在我们的示例中,一个公司=其位置(A 到 F)。使用这六个成员的区块链的块,我们可以预测何时需要补充给定存储点(A 到 F),以减少等待时间,例如。
使用区块链优化存储水平是一种有效降低成本并更快地向客户交付的新方法。
区块链预期的新颖性
在过去,所有这六个位置(A 到 F)的仓库都必须确保每个位置的最低存储水平。由于他们无法实时了解其供应链网络的情况,他们经常存储超过所需的产品,增加了他们的成本,或者存储不足,导致交货问题。
在实时生产和销售的世界中,分销商需要预测需求。系统需要是需求驱动的。朴素贝叶斯可以解决这个问题。
它将考虑前两个特性:
- 
DAY:该服装存储的日期 
- 
STOCK:当前存储的该 SKU 服装的总数量 
然后它将添加一个新特性——与产品 P 相关的区块数量。
在给定日期,较多的区块意味着该产品总体上有需求(生产、分销)。区块越多,交易也越多。此外,如果存储水平(STOCK 特性)正在下降,这就是一个指标;意味着存储水平必须得到补充。DAY 特性标记了产品的历史时间戳。
区块特性命名为BLOCKS。由于所有区块共享区块链,机器学习程序可以在几秒钟内访问可靠的全球数据。区块链提供的数据集可靠性本身就是优化存储水平的动机,利用区块链的区块作为数据集进行优化。
目标——利用区块链数据优化存储水平
目标是维持低水平的库存,并在产品请求时提供快速交付。为了做出决策,机器学习解决方案将实时分析区块链的区块。
程序将考虑给定产品 P 的 DAY、STOCK 和 BLOCKS(数量)特性,并生成一个结果。该结果预测该产品 P 是否有需求。如果答案是“是”(或 1),则该产品的需求需要预测。
步骤 1——定义数据集
该数据集包含来自序列中先前事件的原始数据,使其非常适合预测算法。例如,可以使用 IBM Hyperledger 的脚本提取区块。这为查看所有公司的数据提供了独特的机会,而无需建立数据库。原始数据集将如下所示:

图 7.5:原始数据集
该数据集包含以下内容:
- 
Blocks表示在第x天,扫描区块链回溯 30 天后发现的产品 P 区块。No表示没有发现显著数量的区块。Yes表示发现了显著数量的区块。如果找到区块,意味着在区块链某个地方对该产品有需求。
- 
Some_blocks表示已经找到了区块,但它们太稀疏,无法在不过拟合预测的情况下被考虑。然而,Yes也会对预测产生贡献,和No一样。
- 
No_blocks表示完全没有需求,无论是稀疏的还是其他类型的(Some_blocks),或者是大量的(Blocks)都不算。这对产品 P 来说是个麻烦。
目标是避免对稀疏的(Some_blocks)或不存在的(No_blocks)产品预测需求。此示例试图预测对此产品 P 的许多块的潜在 Yes。只有预测到 Yes,系统才能触发自动需求过程(请参见本章后面的 Python 中的朴素贝叶斯实施 部分)。
步骤 2 – 计算频率
查看以下频率表提供了额外的信息:

图 7.6:频率表
对于给定产品 P 和给定期间(过去 30 天),每个特征(Blocks、Some_blocks或No_blocks)的Yes和No状态已按频率分组。
每个No特征和Yes特征的底线总和。例如,Yes 和 No_blocks 加起来是 2。
一些额外的信息将对最终计算非常有用:
- 
样本的总数 = 10。 
- 
Yes样本的总数 = 8。
- 
No样本的总数 = 2。
步骤 3 – 计算似然
现在似然表已经计算完成,接下来将使用这些数据生成以下似然表:

图 7.7:似然表
表格包含以下统计信息:
- 
No= 2 = 20% = 0.2
- 
Yes= 8 = 80%=0.8
- 
Some_blocks= 2 = 20%=0.2
- 
No_blocks= 3 = 30%=0.3
- 
Blocks= 5 = 50%=0.5
Blocks 表示样本的重要比例,这意味着连同 Some_blocks 一起,需求看起来不错。
步骤 4 – 应用朴素贝叶斯方程
现在的目标是在朴素贝叶斯方程中表示贝叶斯定理的每个变量,以获得对产品 P 的需求的概率,并触发区块链网络的购买场景。贝叶斯定理可以表示如下:

- 
P(Yes|Blocks) = P(Blocks|Yes) * P(Yes)/P(Blocks) 
- 
P(Yes) = 8/10 = 0.8 
- 
P(Blocks) = 5/10 = 0.5 
- 
P(Blocks|Yes) = 4/8 = 0.5 
- 
P(Yes|Blocks) = (0.5*0.8)/0.5 = 0.8 
需求看起来可以接受。但是,需要进行惩罚,并且还必须考虑其他因素(通过其他块探索过程的运输可用性)。
该示例和方法展示了朴素贝叶斯方法的概念。这个示例只是贝叶斯定理哲学的简化数学解释。
通过这种从头开始的计算,我们现在知道了贝叶斯定理的基本概念:使用先验值来预测未来事件,考虑多个特征。
现在我们将从理论方法转向实施阶段。我们将使用 Python 中的朴素贝叶斯构建程序。
Python 中的朴素贝叶斯实施
本节展示了如何使用朴素贝叶斯的库存水平优化器版本。区块链为机器学习矿工提供了极其可靠的数据集,帮助他们寻找优化领域并创造利润。选择正确的模型仍然是关键挑战。
高斯朴素贝叶斯
我们将实现高斯朴素贝叶斯,因为它适用于服装行业。例如,如果你销售裙子,则目标中等尺码为S。营销部门知道,尺码S将代表大部分销售。较大的S + n尺码和较小的S – n尺码会产生较少的销售,形成一个高斯曲线。
在实施模式下,将使用来自区块链的原始数据集,而不使用朴素贝叶斯在下表中的特征解释功能:
| DAY | STOCK | BLOCKS | DEMAND | 
|---|---|---|---|
| 10 | 1455 | 78 | 1 | 
| 11 | 1666 | 67 | 1 | 
| 12 | 1254 | 57 | 1 | 
| 14 | 1563 | 45 | 1 | 
| 15 | 1674 | 89 | 1 | 
| 10 | 1465 | 89 | 1 | 
| 12 | 1646 | 76 | 1 | 
| 15 | 1746 | 87 | 2 | 
| 12 | 1435 | 78 | 2 | 
每一行代表一个区块:
- 
DAY:数据集中分析的时期中的日期。在本例中,我们分析的是某个月份的天数,这代表一个财务周期。运行计算不需要其他信息。在其他情况下,可以使用dd/mm/yyyy格式。你也可以从周期开始的第 1 天起使用计数器(1 到n),并跨越几周、几个月或几年进行分析。
- 
STOCK:在给定位置(A、B 或…F)中,区块中找到的并在当天汇总的总输入。由于这代表一个位置的输入,仅需一个位置的信息,不需要其他位置的数据。在其他情况下,可以添加位置。
- 
BLOCKS:包含产品 P 的区块数,举例来说,针对位置 A。BLOCK列中区块的数量较多,而STOCK列中的数量较少,意味着需求较高。
- 
DEMAND = 1。需求证明是一个包含过去购买的交易区块。这些交易区块提供了至关重要的信息。BLOCK列中区块的数量较少,而STOCK列中的数量较多,意味着需求较低。
- 
DEMAND = 2。证明没有找到交易。
朴素贝叶斯的极限
在某些情况下,当库存很高而区块很少时,DEMAND = 1。因此,严格的相关性并不那么有用。这将是朴素贝叶斯的极限,朴素贝叶斯只是分析统计数据并学习如何预测,忽略了实际的条件概率以及特征之间的交互作用。
在本节中,我们描述了数据集和特征,这些将被用来编写一个朴素贝叶斯程序,配有现成的算法。
Python 程序
现在我们知道区块链是什么,以及如何利用区块链的区块来优化网络中各公司位置(A 到 F)的库存水平。我们还了解了贝叶斯定理和朴素贝叶斯的基本概念。
考虑到这一点,我们可以构建一个 Python 程序来预测区块链中即将到来的区块的库存级别类别。这些预测将帮助当地管理者增加库存量,以满足他们在供应链中合作伙伴(A 到 F 公司)的需求。
Python 程序naive_bayes_blockchains.py使用了sklearn类。请参考以下代码片段:
import numpy as np
import pandas as pd
from sklearn.naive_bayes import GaussianNB 
它将数据集读取到数据结构中。以下代码将data_BC.csv读取到df中:
#Reading the data
df = pd.read_csv('data_BC.csv')
print("Blocks of the Blockchain")
print(df.head()) 
它在以下输出中打印文件顶部内容:
Blocks of the Blockchain
DAY STOCK BLOCKS DEMAND
0 10 1455 78 1
1 11 1666 67 1
2 12 1254 57 1
3 14 1563 45 1
4 15 1674 89 1 
它准备训练集,使用X来寻找并预测Y,以下是代码:
# Prepare the training set
X = df.loc[:,'DAY':'BLOCKS']
Y = df.loc[:,'DEMAND'] 
它选择类别并训练以下clfG模型:
#Choose the class
clfG = GaussianNB()
# Train the model
clfG.fit(X,Y) 
然后,程序获取一些区块,进行预测,并使用以下clfG.predict函数打印结果:
# Predict with the model(return the class)
print("Blocks for the prediction of the A-F blockchain")
blocks=[[14,1345,12],
        [29,2034,50],
        [30,7789,4],
        [31,6789,4]]
print(blocks)
prediction = clfG.predict(blocks)
for i in range(4):
    print("Block #",i+1," Gauss Naive Bayes Prediction:",
           prediction[i]) 
区块显示出来,并产生以下预测结果。2表示目前没有需求;1将触发采购区块:
Blocks for the prediction of the A-F blockchain
[[14, 1345, 12], [29, 2034, 50], [30, 7789, 4], [31, 6789, 4]]
Block # 1 Gauss Naive Bayes Prediction: 1
Block # 2 Gauss Naive Bayes Prediction: 2
Block # 3 Gauss Naive Bayes Prediction: 2
Block # 4 Gauss Naive Bayes Prediction: 2 
这是一个补货程序。它将模拟需求。当没有需求时,什么也不会发生;当有需求时,它会触发一个采购区块。一些连锁商店知道在某一天(或一周或其他时间单位)购买的衣物数量,并自动按此数量进行采购。其他商店则有不同的采购规则。寻找商业规则是项目咨询的一部分。
在本节中,我们实现了朴素贝叶斯算法来预测即将到来的区块类别。如果需求较高,那么供应链管理者将知道需要储存更多的产品。
如果需求较低,管理者将避免存储更多的产品。区块链中的区块为一个全天候扫描区块并实时生成建议的程序提供了可靠的数据集。
摘要
区块链中的可靠区块序列为无尽的机器学习算法打开了大门。朴素贝叶斯似乎是一种实践方法,可以用来开始优化区块链中的区块。它通过学习数据集的独立特征来计算相关性并进行预测,无论这些关系是否具有条件性。
这种自由风格的预测方法符合区块链的开放精神,区块链如今正以无限的资源在全球范围内传播。
IBM Hyperledger 通过 Linux 基金会项目将区块链的“前沿地区”开发提升到了另一个层次。IBM 还提供云平台和服务。
IBM、微软、亚马逊和谷歌提供的云平台配备了众多颠覆性的机器学习算法。这为你的市场或部门提供了顺畅的途径,并且可以在短时间内在线设置区块链原型。通过这种方式,你可以在模型中输入一些额外的原型数据,导出数据,或使用 API 读取区块序列。然后,你将能够将机器学习算法应用于这些可靠的数据集。唯一的限制是我们的想象力。
下一章将引领我们进入更多的人工智能力量,我们将探索神经网络的世界。
问题
- 
加密货币是当前区块链唯一的应用。(是 | 否) 
- 
挖掘区块链可以是盈利的。(是 | 否) 
- 
企业用区块链不能应用于销售。(是 | 否) 
- 
区块链的智能合约比标准的离线合同更容易编写。(是 | 否) 
- 
一旦区块进入区块链网络,网络中的每个人都可以读取其内容。(是 | 否) 
- 
区块链中的区块保证绝对不可能发生欺诈。(是 | 否) 
- 
应用贝叶斯定理的方法只有一种。(是 | 否) 
- 
训练一个朴素贝叶斯数据集需要标准的函数。(是 | 否) 
- 
机器学习算法不会改变企业业务的内在性质。(是 | 否) 
进一步阅读
- 
更多关于朴素贝叶斯的信息,请访问 scikit-learn 官网: scikit-learn.org/stable/modules/naive_bayes.html
- 
要探索 IBM 的 Hyperledger 解决方案: www.ibm.com/blockchain/hyperledger.html
第八章:用前馈神经网络解决 XOR 问题
在企业项目的过程中,总会有某一时刻,遇到一个看似无法解决的问题。此时,你会尝试所有学到的东西,但对方的要求还是无法满足。你的团队或客户开始寻找其他解决方案。是时候采取行动了。
在本章中,关于材料优化的一个无法解决的商业案例将通过手工制作的前馈神经网络(FNN)与反向传播成功解决。
前馈网络是深度学习的关键构建模块之一。围绕 XOR 函数的争论完美地说明了深度学习如何在企业环境中重新获得流行。XOR 是一种排他性“或”函数,我们将在本章后面探讨。XOR FNN 说明了神经网络的一个关键功能:分类。一旦信息被分类为子集,它就为预测和神经网络的许多其他功能打开了大门,如表征学习。
一个 XOR FNN 将从零开始构建,以从一开始就解密深度学习。我们将应用一种复古的、从头开始的方法,揭开深度学习的炒作面纱。
本章将涵盖以下主题:
- 
解释 XOR 问题 
- 
如何手动构建 FNN 
- 
用 FNN 解决 XOR 问题 
- 
分类 
- 
反向传播 
- 
成本函数 
- 
成本函数优化 
- 
错误损失 
- 
收敛 
在我们开始构建 FNN 之前,我们首先会介绍 XOR 及其在第一个人工神经模型中的局限性。
原始感知器无法解决 XOR 函数
原始感知器是在 1950 年代设计的,并在 1970 年代末期得到了改进。原始感知器包含一个神经元,无法解决 XOR 函数。
XOR 函数意味着你必须选择一个排他性的“或” (XOR)。
这可能很难理解,因为我们不习惯以我们日常生活中使用 或 的方式来思考。事实上,我们总是交替使用 或,既有包容性也有排他性。举个简单的例子:
如果一个朋友来拜访我,我可能会问他们:“你想要茶还是咖啡?”这基本上是提供茶 XOR 咖啡;我不会期望我的朋友同时要求茶和咖啡!我的朋友会选择其中之一。
我可能会跟进我的问题,问:“你想要加牛奶还是加糖?”在这种情况下,如果我的朋友想要两者,我不会感到惊讶。这是一个包容性的 或。
因此,XOR 意味着“你可以选择一个或另一个,但不能同时选择两者。”
我们将在本章通过更多示例来展开这些概念。
为了解决这个 XOR 函数,我们将构建一个 FNN。
一旦构建了解决 XOR 问题的前馈网络,它将被应用于优化示例。该优化示例将选择数十亿个维度中的最佳组合,以最小化企业资源的使用,同时实现 XOR 函数的泛化。
首先,必须明确一个感知机 XOR 限制的解决方案。
XOR 和线性可分模型
在 1960 年代末期,数学上证明了感知机不能解决 XOR 函数。幸运的是,今天感知机及其神经认知网络(neocognitron)版本形成了神经网络的核心模型。
你可能会忍不住想,那又怎样? 然而,整个神经网络领域依赖于解决类似这样的问题来进行模式分类。如果没有模式分类,图像、声音和文字对机器来说毫无意义。
线性可分模型
McCulloch-Pitts 1943 年的神经元(参见第二章,建立奖励矩阵 - 设计你的数据集)导致了 Rosenblatt 1957-59 年的感知机以及 1960 年 Widrow-Hoff 的自适应线性元件(Adaline)。
这些模型是基于f(x, w)函数的线性模型,需要一条线来分隔结果。一个感知机无法实现这一目标,因此无法对许多对象进行分类。
一个标准的线性函数可以分隔数值。线性可分性可以通过下图表示:

图 8.1:线性可分模式
想象一下,分隔前述点和其下部分的那条线代表一个需要通过机器学习或深度学习应用来表示的图像。线上方的点代表天空中的云;线下方的点代表山坡上的树。这条线代表山坡的斜率。
要实现线性可分,一个函数必须能够将云从树中分隔出来进行分类。分类的前提是某种形式的可分性,无论是线性的还是非线性的。
线性模型的 XOR 限制,如原始感知机
一个线性模型无法解决以下表格表示的 XOR 问题:
| x1 的值 | x2 的值 | 输出 | 
|---|---|---|
| 1 | 1 | 0 | 
| 0 | 0 | 0 | 
| 1 | 0 | 1 | 
| 0 | 1 | 1 | 
第 3 行和第 4 行展示了排他性或(XOR)。想象一下,你给一个孩子提供一块蛋糕或者一块糖果(1 或 1):
- 
案例 1:孩子回答:“我想要糖果或者什么都不要!”(0 或 1)。这就是排他性或(XOR)! 
- 
案例 2:孩子回答:“我想要蛋糕或者什么都不要!”(1 或 0)。这也是排他性或(XOR)! 
以下图展示了由一个感知机表示的 XOR 函数的线性不可分性:

图 8.2:线性不可分模式
表格中的值表示该图中的笛卡尔坐标。位于(1, 1)和(0, 0)的交叉圆点,无法与位于(1, 0)和(0, 1)的圆点分开。这是一个巨大的问题。它意味着弗兰克·罗森布拉特的f(x,w)感知机无法分离这些点,因此无法将它们分类成云和树。因此,在许多情况下,感知机无法识别需要线性可分的值。
弗兰克·罗森布拉特发明了二十世纪最强大的神经概念——一种可以学习的神经元——但他在 1960 年代必须忍受这个限制。
如前面用蛋糕或糖果的例子所解释的,缺乏 XOR 函数限制了你必须在两个选项之间排他选择的应用场景。在现实生活中,有许多“只能是那个,不能是别的”的情境。对于一辆自动驾驶汽车来说,它要么左转,要么右转,但不能在做决策时来回摇摆!
我们将通过一种复古的解决方案来解决这个限制,从构建开始,最终实现一个 FNN。
从零开始构建一个前馈神经网络(FNN)
让我们进行一个思维实验。想象一下,我们处在 1969 年。我们拥有今天的知识,但没有任何证据来证明它。我们知道感知机无法实现异或(XOR)功能。
我们有一个优势,因为我们现在知道解决方案存在。为了开始我们的实验,我们只有一张便签、一支铅笔、一把削笔刀和一块橡皮擦等着我们。我们已经准备好从零开始在纸上解决 XOR 问题,然后再进行编程。我们必须找到一种方法,用神经网络对这些点进行分类。
第 1 步 – 定义一个前馈神经网络(FNN)
我们必须采取非常规的方法来解决这个问题。我们必须忘记 21 世纪复杂的词汇和理论。
我们可以用高中格式写一个神经网络层。一个隐藏层将是:
h[1] = x * w
好的。现在我们有了一个层。一个层只是一个函数。这个函数可以表示为:
f(x, w)
其中 x 是输入值,w 是乘以 x 的某个值。隐藏层意味着计算过程是不可见的,就像 x = 2 和 x + 2 是导致 4 的隐藏层一样。
到目前为止,我们已经用三行定义了一个神经网络:
- 
输入 x。 
- 
有一些函数会改变它的值,比如 2 × 2 = 4,它转化了 2。这就是一个层。如果结果大于 2,比如说,那么太棒了!输出是 1,意味着“是”或“真”。由于我们看不到计算过程,这就是隐藏层。 
- 
一个输出。 
f(x, w) 是任何神经网络的构建块。“前馈”意味着我们将从第 1 层走到第 2 层,按顺序向前移动。
现在我们知道,基本上任何神经网络都是通过某个操作转化的值来生成某种输出的,我们需要一些逻辑来解决 XOR 问题。
第 2 步 – 举一个两个孩子如何每天解决 XOR 问题的例子
下面是两个孩子如何通过一个简单的日常例子来解决 XOR 问题的示例。我强烈推荐这种方法。我将非常复杂的问题分解成小部分,使其适应孩子的理解水平,通常几分钟就能解决。然后,你会得到别人讽刺的回答:“这就是你做的全部吗?”但当这个解决方案在高层次的企业项目中反复奏效时,讽刺就消失了。
首先,让我们把 XOR 问题转化为一个商店里的糖果问题。两个孩子去商店,想买糖果。但是他们只有足够的钱买一包糖果。他们必须在两包不同的糖果之间达成一致。假设一包是巧克力,另一包是口香糖。那么,在这两个孩子的讨论中,1 表示是,0 表示否。他们的预算限制了这两个孩子的选择:
- 
去商店但不买任何巧克力 或 口香糖 = (no, no) = (0, 0)。这不是这些孩子的选择!所以答案是错误的。 
- 
去商店并且购买巧克力 和 口香糖 = (是,是) = (1, 1)。那将是非常棒的,但这不可能。太贵了。所以,答案是,不幸的是,错误的。 
- 
去商店并且买巧克力 或 口香糖 = (1, 0 或 0, 1) = (是或否) 或 (否或是)。这是可能的。所以,答案是正确的。 
想象这两个孩子。长子是理智的。较小的孩子还不太会算数,想买两包糖果。
我们将其写在纸上:
- 
x[1](长子的决定,是或否,1 或 0) * w[1](长子的想法)。长子是这样想的,或者: x[1] * w[1] 或 h[1] = x[1] * w[1] 长子做出决定,就像我们每天做的那样,比如购买一辆车(x = 0 或 1)乘以成本(w[1])。 
- 
x[2](较小的孩子的决定,是或否,1 或 0) * w[3](较小的孩子的想法)。较小的孩子也在思考这个,或者: x[2] * w[3] 或 h[2] = x[2] * w[3] 
理论:x[1] 和 x[2] 是输入。h[1] 和 h[2] 是神经元(计算结果)。由于 h[1] 和 h[2] 包含在过程中的计算,且不可见,因此它们是隐藏神经元。h[1] 和 h[2] 形成了一个隐藏层。w[1] 和 w[3] 是表示我们如何“衡量”决策的权重,表明某些事情比其他事情更重要。
现在,想象这两个孩子在互相交谈。
等一下!这意味着现在,每个孩子都在和对方沟通:
- 
x[1](长子)对较小的孩子说 w[2]。因此,w[2] = 这是我想的并告诉你的: x[1] * w[2] 
- 
x[2](较小的孩子)说:“请将我的观点加入到你的决定中,”这表示为 w[4][:] x[2] * w[4] 
我们现在有了前两个方程式,以高中水平的代码表示。这就是一个人想法加上他说给另一个人听,请另一个人考虑这一点:
h1=(x1*w1)+(x2*w4) #II.A.weight of hidden neuron h1
h2=(x2*w3)+(x1*w2) #II.B.weight of hidden neuron h2 
h1总结了一个孩子的想法:个人意见 + 另一个孩子的意见。
h2总结了另一个孩子的想法和对话:个人意见 + 另一个孩子的意见。
理论:现在的计算包含两个输入值和一个隐藏层。因为在下一步中,我们将对h1和h2进行计算,所以我们处于一个前馈神经网络中。我们从输入层移动到另一个层,这将引导我们到下一个层,以此类推。从一个层到另一个层的这个过程是深度学习的基础。层数越多,网络就越深。h1和h2形成隐藏层的原因是它们的输出正是另一个层的输入。
对于这个例子,我们不需要复杂的激活函数中的数字,比如逻辑 sigmoid 函数,所以我们只是判断输出值是否小于 1:
如果 h[1] + h[2] >= 1,则 y[1] = 1
如果 h[1] + h[2] < 1,则 y[2] = 0
理论:y[1]和y[2]构成第二个隐藏层。这些变量可以是标量、向量或矩阵。它们是神经元。
现在,问题来了。谁是对的?年长的孩子还是年幼的孩子?
唯一的办法似乎是进行尝试,其中权重W代表所有的权重。神经网络中的权重就像我们日常生活中的权重。我们总是在权衡决策。例如,有两本书可以购买,我们将“权衡”我们的决策。如果一本书有趣且便宜,它在我们的决策中所占的权重就会更多或更少。
在我们的例子中,孩子们同意至少购买一些东西,因此从现在开始,w[3] = w[2],w[4] = w[1]。这样,年长的孩子和年幼的孩子将共享一些决策权重。
现在,有人得当“影响者”。让我们把这个困难的任务交给年长的孩子。年长的孩子更为理智,会不断地传达坏消息。你必须从你的选择中减去一些东西,用负号(–)表示。
每当他们到达 h[i] 时,年长的孩子就会对购买糖果包提出关键的负面看法。它是–w,以确保不会超过预算。年长孩子的看法有偏差,因此我们将变量称为偏差,b[1]。由于年幼孩子的观点也有偏差,我们也将其视为偏差,b[2]。由于年长孩子的观点始终是负面的,因此–b[1]将应用于年长孩子的所有想法。
当我们将这个决策过程应用到他们的观点时,我们得到:
h[1] = y[1] * –b[1]
h[2] = y[2] * b[2]
然后,我们只需使用相同的结果。如果结果>=1,那么阈值就达到了。阈值的计算如下所示:
y = h[1] + h[2]
我们将首先开始有效地寻找权重,从将权重和偏置设置为 0.5 开始,如下所示:
w[1] = 0.2; w[2] = 0.5; b[1] = 0.5
w[3] = w[2]; w[4] = w[1]; b[2] = b[1]
这还不是一个完整的程序,但其理论已经完成。
只有两个孩子之间的交流在起作用;我们将在第一次尝试后,专注于只修改 w[2] 和 b[1]。经过几次尝试后,这在纸面上是可行的。
我们现在写下基本的数学函数,事实上,这就是纸面上的程序本身:
#Solution to the XOR implementation with
#a feedforward neural network(FNN)
#I.Setting the first weights to start the process
w1=0.5;w2=0.5;b1=0.5
w3=w2;w4=w1;b2=b1
#II.hidden layer #1 and its output
h1=(x1*w1)+(x2*w4) #II.A.weight of hidden neuron h1
h2=(x2*w3)+(x1*w2) #II.B.weight of hidden neuron h2
#III.threshold I, hidden layer 2
if(h1>=1): h1=1
if(h1<1): h1=0
if(h2>=1): h2=1
if(h2<1): h2=0
h1= h1 * -b1
h2= h2 * b2
#IV.Threshold II and Final OUTPUT y
y=h1+h2
if(y>=1): y=1
if(y<1): y=0
#V.Change the critical weights and try again until a solution is found
w2=w2+0.5
b1=b1+0.5 
让我们从纸面上的解决方案转到 Python 代码。
为什么 1969 年没有找到这个看似简单的解决方案?因为今天看起来简单,但当时并非如此,就像所有我们天才前辈发明的东西一样。人工智能和数学中没有任何事情是容易的。
在下一部分,我们将坚持这里提出的解决方案,并在 Python 中实现它。
用 FNN 和反向传播在 Python 中实现复古 XOR 解决方案
为了保持 1969 年复古解决方案的精神,我们将不会使用 NumPy、TensorFlow、Keras 或任何其他高级库。用高中数学编写复古 FNN 和反向传播是很有趣的。
如果你将一个问题分解成非常基础的部分,你会更好地理解它,并提供对这个特定问题的解决方案。你不需要用一辆大卡车来运输一条面包。
此外,通过从孩子们的思维方式出发,我们避免了在现代 CPU 丰富的解决方案中运行 20,000 次或更多的训练来解决 XOR 问题。所使用的逻辑证明了只要一个偏置是负的(年长的、理性的批判性孩子),两者的输入就可以拥有相同的参数,从而使系统给出合理的答案。
基本的 Python 解决方案在几次迭代后快速得出结果,大约 10 次迭代(时期或回合),具体取决于我们如何思考它。一周期可以与一次尝试相关联。想象一下,看着某人在练习篮球:
- 
这个人朝着篮筐投掷篮球,但投偏了。那是一个时代(也可以用一集来描述)。 
- 
这个人思考发生了什么,并改变了投篮的方式。 这种改进就是使其成为学习周期(或回合)的原因。这不是一次简单的无记忆尝试。确实发生了一些事情,提升了性能。 
- 
这个人再次投篮(下一个周期),又一次(下一个周期)直到整体表现有所提升。这就是神经网络如何在周期中改进的方式。 
FNN_XOR_vintage_tribute.py(在代码的顶部)包含一个四列的结果矩阵。
矩阵的每个元素表示四个谓词的状态(1 = 正确,0 = 错误):
#FEEDFORWARD NEURAL NETWORK(FNN) WITH BACK PROPAGATION SOLUTION FOR XOR
result=[0,0,0,0] #trained result
train=4 #dataset size to train 
train 变量是要解决的谓词数量:(0, 0),(1, 1),(1, 0),(0, 1)。要解决的谓词变量是 pred。
程序的核心实际上是我们所写的纸面内容的一个副本,如以下代码所示:
#II hidden layer 1 and its output
def hidden_layer_y(epoch,x1,x2,w1,w2,w3,w4,b1,b2,pred,result):
    h1=(x1*w1)+(x2*w4) #II.A.weight of hidden neuron h1
    h2=(x2*w3)+(x1*w2) #II.B.weight of hidden neuron h2
#III.threshold I,a hidden layer 2 with bias
    if(h1>=1):h1=1;
    if(h1<1):h1=0;
    if(h2>=1):h2=1
    if(h2<1):h2=0
    h1= h1 * -b1
    h2= h2 * b2
#IV. threshold II and OUTPUT y
    y=h1+h2
    if(y<1 and pred>=0 and pred<2):
        result[pred]=1
    if(y>=1 and pred>=2 and pred<4):
        result[pred]=1 
pred是一个函数的参数,范围是从1到4。这四个谓词在下表中表示:
| 谓词 (pred) | x[1] | x[2] | 期望结果 | 
|---|---|---|---|
| 0 | 1 | 1 | 0 | 
| 1 | 0 | 0 | 0 | 
| 2 | 1 | 0 | 1 | 
| 3 | 0 | 1 | 1 | 
这就是为什么对于谓词 0 和 1,y必须小于 1。而对于谓词 2 和 3,y必须大于等于 1。
现在,我们需要调用以下函数,将训练限制为 50 个周期,这已经足够:
#I Forward and backpropagation
for epoch in range(50):
    if(epoch<1):
        w1=0.5;w2=0.5;b1=0.5
    w3=w2;w4=w1;b2=b1 
在第一次迭代中,所有的权重和偏差都设置为0.5。别想太多!让程序来做这件事。正如前面所解释的,x2的权重和偏差是相等的。
现在,隐藏层和y计算函数被调用四次,每次针对一个谓词进行训练,如下代码片段所示:
#I.A forward propagation on epoch 1 and IV.backpropagation starting epoch 2
    for t in range (4):
        if(t==0):x1 = 1;x2 = 1;pred=0
        if(t==1):x1 = 0;x2 = 0;pred=1
        if(t==2):x1 = 1;x2 = 0;pred=2
        if(t==3):x1 = 0;x2 = 1;pred=3
        #forward propagation on epoch 1
        hidden_layer_y(epoch,x1,x2,w1,w2,w3,w4,b1,b2,pred,result) 
现在,系统必须进行训练。为此,我们需要在每次迭代中衡量 1 到 4 的预测结果中有多少是正确的,并决定如何调整权重/偏差,直到获得合适的结果。我们将在接下来的部分中完成这项工作。
一个简化版的代价函数和梯度下降
稍微复杂一些的梯度下降将在下一章中介绍。在本章中,只有一行方程就能完成工作。作为一名非传统的思考者,你需要记住的唯一一点是:那又怎样? 梯度下降的概念是最小化当前结果与目标之间的损失或误差。
首先,需要一个代价函数。
有四个谓词(0-0,1-1,1-0,0-1)需要正确训练。我们需要找出在每个训练周期中有多少是正确训练的。
代价函数将衡量训练目标(4)与本次迭代或训练周期(result)的结果之间的差异。
当收敛为 0 时,意味着训练已经成功。
result[0,0,0,0]表示如果四个谓词都没有被正确训练,每个值都会是0。result[1,0,1,0]表示四个谓词中有两个是正确的。result[1,1,1,1]表示四个谓词都已经训练完成,训练可以停止。在这种情况下,1表示正确的训练结果已获得,它可以是0或1。result数组是结果计数器。
代价函数将通过将训练值降到4、3、2、1或0来表示这次训练,直到降到 0。
梯度下降测量下降的值,以找到坡度的方向:上坡、下坡或平坦。然后,一旦你得到了坡度及其陡峭度,你就可以优化权重。导数是了解你是否在上坡或下坡的一种方法。
每次我们沿着坡道上升或下降时,我们都会检查是否朝着正确的方向前进。我们假设我们会一步一步地走。所以,如果我们改变方向,我们会以一步的速度改变步伐。这个一步的值就是我们的学习率。我们将在每一步衡量我们的进展。然而,如果我们对结果感到满意,我们可能会一次走 10 步,只有每走 10 步才检查是否走在正确的轨道上。这样我们的学习率就增加到了 10 步。
在这种情况下,我们劫持了这个概念,并用它来设置学习率为0.05,只用了一个函数行。为什么不呢?它帮助我们用一行代码解决了梯度下降优化问题:
 if(convergence<0):w2+=training_step;b1=w2 
通过将复古的儿童买糖果逻辑应用于整个 XOR 问题,我们发现只有w2需要优化。这就是为什么b1=w2。因为b1在做一个艰难的工作——一直输出负值(-),这完全改变了最终输出的结果。
学习率设置为0.05,程序在 10 个周期内完成了训练:
epoch: 10 optimization 0 w1: 0.5 w2: 1.0 w3: 1.0 w4: 0.5 b1: -1.0 b2: 1.0 
这是一个逻辑性的是或否问题。网络的构建方式纯粹是逻辑性的。没有什么能阻止我们使用任何我们想要的训练率。实际上,这就是梯度下降的核心。有很多梯度下降方法。如果你自己发明了一种方法,并且它适用于你的解决方案,那也是可以的。
在这种情况下,这一行代码足够判断坡度是否正在下降。只要坡度为负值,函数就会朝着成本 = 0 的方向下行:
 convergence=sum(result)-train #estimating the direction of the slope
    if(convergence>=-0.00000001): break 
下图总结了整个过程:

图 8.3:前馈神经网络模型(FNN)
我们可以看到,在这个“前馈”神经网络中,所有层的箭头都是朝前的。然而,从y节点向后延伸的箭头可能会让人感到困惑。这个箭头代表了训练模型时权重的变化。这意味着我们会回到更改权重并再次运行网络进行另一个周期(或回合)。系统会在每个周期中调整其权重,直到整体结果正确为止。
太简单了吗?嗯,这个方法有效,这就是现实开发中最重要的。只要你的代码没有错误,并且完成了任务,那才是最关键的。
寻找一个简单的开发工具无非就是如此。它只是工具箱中的另一个工具。我们可以让这个 XOR 函数在神经网络中运行并产生收益。
公司关心的不是你有多聪明,而是你能多高效(有利可图)。
一家公司的生存依赖于多种约束条件:按时交付、提供合理价格、提供合理质量水平的产品等等。
当我们提出解决方案时,展示我们写了大量代码有多聪明是没有意义的。我们的公司或客户期望一个高效的解决方案,这个解决方案运行良好且易于维护。简而言之,要关注效率。一旦我们有了一个好的解决方案,我们需要证明它是有效的。在这种情况下,我们证明了线性可分性已经实现。
实现了线性可分性
请记住,这个带有反向传播和代价函数的前馈网络的全部目的是将一个线性不可分的函数转化为一个线性可分的函数,以实现对系统呈现的特征的分类。在这种情况下,这些特征的值为0或1。
神经网络中每一层的核心目标之一是使输入变得有意义,即能够将一种信息与另一种信息区分开来。
h1和h2将生成笛卡尔坐标线性可分训练轴,如以下代码实现所示:
 h1= h1 * -b1
    h2= h2 * b2
    print(h1,h2) 
运行程序时,隐藏层训练后的非线性输入值将显示出来。然后,非线性值变成线性值,成为一个线性可分的函数:
linearly separability through cartesian training -1.0000000000000004 1.0000000000000004
linearly separability through cartesian training -0.0 0.0
linearly separability through cartesian training -0.0 1.0000000000000004
linearly separability through cartesian training -0.0 1.0000000000000004
epoch: 10 optimization 0 w1: 0.5 w2: 1.0 w3: 1.0 w4: 0.5 b1: -1.0 b2: 1.0 
中间结果和目标不是一堆显示程序运行是否正常的数字。结果是一组可以通过以下线性分隔图表示的笛卡尔坐标值:

图 8.4:线性可分模式
我们现在已经在顶部值之间获得了区分,这些值代表了(1,0)和(0,1)输入的中间值,而底部值则代表(1,1)和(0,0)输入。顶部值与底部值之间通过一条清晰的线分开。我们现在在这条分隔线的顶部有云,在底部有树。
神经网络的各层将非线性值转换为线性可分的值,从而使得通过标准分隔方程(如以下代码所示)进行分类成为可能:
#IV. threshold II and OUTPUT y
    y=h1+h2 # logical separation
    if(y<1 and pred>=0 and pred<2):
        result[pred]=1
    if(y>=1 and pred>=2 and pred<4):
        result[pred]=1 
神经网络将不可分的信息转化为可分且可分类的信息,代表了深度学习的一项核心能力。基于这一技术,可以对数据执行许多操作,例如子集优化。
在下一节中,我们将探讨 FNN XOR 解决方案的实际应用。
将 FNN XOR 函数应用于优化数据子集
目前地球上有超过 75 亿人呼吸着空气。到 2050 年,可能会有 25 亿人加入我们的行列。所有这些人都需要穿衣和吃饭。这两项活动本身就涉及到将数据分类为工业用途的子集。
分组是任何生产过程中的核心概念。涉及服装和食品的生产需要分组来优化生产成本。想象一下,如果不进行分组,而是将一件 T 恤从一个大陆运送到另一个大陆,而不是将 T 恤按批次装进集装箱,并且将多个集装箱(而不仅仅是两个集装箱在一艘船上)一起运输。以服装为例,我们来进行分析。
一家连锁商店需要根据顾客购买产品的情况补充每家店的库存。在这种情况下,该公司拥有 10,000 家店。品牌例如生产牛仔裤。它们的平均产品是褪色牛仔裤。这款产品每月在每家店销售 50 件,销售速度较慢。总共是 10,000 家店 × 50 件 = 500,000 件,即每月 500,000 个库存单位(SKU)。这些单位的销售涵盖了所有尺码,分为平均码、小码和大码。每月销售的尺码是随机的。
该产品的主要工厂大约有 2,500 名员工,每天生产约 25,000 条牛仔裤。员工主要在以下领域工作:剪裁、组装、洗涤、激光处理、包装和仓储。
第一个难题出现在面料的购买和使用上。该品牌的面料并不便宜,需要大量采购。每种图案(即组装裤子的各个部件)都需要尽可能减少面料的浪费进行剪裁。
想象你有一个空箱子,想要通过优化体积来填充它。如果只放足球,箱子里会有很多空隙。如果你把网球塞进空隙里,空间会减少。如果再把剩余的空隙用乒乓球填满,你就优化了箱子里的空间。
构建优化的子集可以应用于集装箱、仓库流动和存储、货车装载优化以及几乎所有人类活动。
在服装行业中,如果制造牛仔裤时有 1%到 10%的面料浪费,企业仍能在竞争中生存。如果超过 10%,就需要解决实际问题。损失 20%的面料可能会导致公司倒闭,迫使其破产。
主要规则是将大件和小件结合起来,以制作优化的剪裁图案。
通过大件和小件优化空间的使用,可以应用于剪裁形式(例如牛仔裤的图案)。一旦剪裁完成,它们将被送往缝纫站进行组装。
问题可以总结为:
- 
创建 500,000 个 SKU 的子集,以优化接下来一个月在特定工厂的剪裁过程。 
- 
确保每个子集包含小号和大号,以通过每天选择 6 个尺码来构建 25,000 个单位的子集,从而最小化面料的浪费。 
- 
生成平均 3 到 6 个尺码的剪裁计划,每个子集每天生产 25,000 件产品。 
从数学角度来看,这意味着要在 50 万个单位中寻找特定日期的尺码子集。
任务是从 50 万个单元中找到 6 个匹配的尺码,如下所示的组合公式:

到这时,大多数人都会放弃这个想法,找到一些简单的解决办法,即使这意味着浪费面料。
我们所有人的第一反应是,这比宇宙中的星星还多,所有的炒作也是如此。然而,这根本不是正确的看法。正确的看法是要从完全相反的方向来考虑。
这个问题的关键是从微观层面观察粒子,即信息位层面。分析详细数据是获得可靠结果的必要条件。这是机器学习和深度学习的基本概念。翻译到我们的领域,它意味着要处理一张图片,ML 和 DL 处理的是像素。
因此,即使要处理的图片代表了大量数据,最终也会降至对小单位信息的分析:
| yottabyte (YB) | 10²⁴ | yobibyte (YiB) | 2⁸⁰ | 
|---|
看到这些大数字突然出现可能会让人感到惊讶!然而,当试图将成千上万的元素组合在一起时,组合的方式变得是指数级增长。当你将其扩展到大型服装品牌所需处理的大量人口时,它也会迅速呈指数增长。
今天,谷歌、Facebook、亚马逊等公司拥有 yottabyte 级的数据需要分类和理解。使用大数据这一术语其实并没有太大意义。它只是大量的数据,那又怎样呢?
你不需要分析数据集中的每个数据点的具体位置,而是要使用概率分布。
为了理解这一点,让我们去商店为一家人买些牛仔裤。家里的一个父母需要一条牛仔裤,家里的一个青少年也需要一条。两人都去寻找他们想要的牛仔裤尺码。父母找到 10 条尺码为x的牛仔裤。所有牛仔裤都是生产计划的一部分。父母随机挑选一条,青少年也做同样的事。然后他们支付并带着牛仔裤回家。
一些系统在随机选择时运作良好:粒子的随机运输(将牛仔裤从商店带回家)(牛仔裤、其他产品单元、像素或任何需要处理的物品),形成流体(一个数据集)。
翻译到我们的工厂,这意味着可以引入一个随机过程来解决这个问题。
所需的只是从 50 万个单元中随机选取大号和小号尺码进行生产。如果每天选取从 1 到 6 的 6 个尺码,那么可以按如下方式在表格中对这些尺码进行分类:
小号尺码 = S = {1, 2, 3}
大号尺码 = L = {4, 5, 6}
将其转换为数字子集名称,S = 1 和 L = 6。通过同时选择大号和小号尺码进行生产,面料将得到优化,如下表所示:
| 选择 1 的大小 | 选择 2 的大小 | 输出 | 
|---|---|---|
| 6 | 6 | 0 | 
| 1 | 1 | 0 | 
| 1 | 6 | 1 | 
| 6 | 1 | 1 | 
你会注意到前两行包含相同的值。这不会优化面料的消耗。如果你只将大号 6 尺寸的产品放在一起,图案中会有“空洞”。如果只将小号 1 尺寸的产品放在一起,它们会填满所有空间,根本没有空位给较大的产品。如果大尺寸和小尺寸的产品能同时出现在同一卷面料上,裁剪就最为优化。
这听起来是不是很熟悉?它看起来和我们的经典 FNN 完全一样,只是 1 替代了 0,6 替代了 1。
所要做的就是规定子集 S = value 0,子集 L = value 1;然后之前的代码可以进行泛化。
FFN_XOR_generalization.py 是用于泛化之前代码的程序,如下所示的代码片段。
如果这有效,那么较小和较大的尺寸将被选择并发送到裁剪计划部门,面料将得到优化。通过应用贝尔曼方程的随机性概念,采用随机过程,随机选择客户的单位订单(每个订单是一个尺寸,数量为 1):
 w1=0.5;w2=1;b1=1
    w3=w2;w4=w1;b2=b1
    s1=random.randint(1,500000)#choice in one set s1
    s2=random.randint(1,500000)#choice in one set s2 
现在,权重和偏差是通过 XOR 训练 FNN 得到的常数。训练已经结束;FNN 现在用于提供结果。请记住,机器学习和深度学习中的“学习”一词并不意味着你必须永远训练系统。在稳定的环境中,只有在数据集发生变化时才需要运行训练。在项目的某个阶段,你希望使用的是经过深度训练的系统,而不是仅仅在探索深度学习过程的训练阶段。目标不是将所有企业资源都投入到学习中,而是将资源用于使用已经训练好的模型。
深度学习架构必须迅速转变为深度训练的模型,以产生利润。
对于这个原型验证,给定订单的尺寸是随机的。0 表示该订单符合 S 子集;1 表示该订单符合 L 子集。数据生成函数反映了消费者行为在以下六种尺寸牛仔裤消费模型中的随机性:
 x1=random.randint(0, 1)#property of choice:size smaller=0
    x2=random.randint(0, 1)#property of choice :size bigger=1
    hidden_layer_y(x1,x2,w1,w2,w3,w4,b1,b2,result) 
一旦在正确的尺寸类别中随机选择了两个客户订单,FNN 就会激活并像之前的示例一样运行。只改变了 result 数组,因为我们使用的是相同的核心程序。只需期望返回一个“是”(1)或“否”(0),如下所示的代码:
#II hidden layer 1 and its output
def hidden_layer_y(x1,x2,w1,w2,w3,w4,b1,b2,result):
    h1=(x1*w1)+(x2*w4) #II.A.weight of hidden neuron h1
    h2=(x2*w3)+(x1*w2) #II.B.weight of hidden neuron h2
#III.threshold I,a hidden layer 2 with bias
    if(h1>=1):h1=1
    if(h1<1):h1=0
    if(h2>=1):h2=1
    if(h2<1):h2=0
    h1= h1 * -b1
    h2= h2 * b2
#IV. threshold II and OUTPUT y
    y=h1+h2
    if(y<1):
        result[0]=0
    if(y>=1):
        result[0]=1 
需要计算出要生产的子集数量,以确定所需的正面结果的数量。
选择是从 500,000 个单位中挑选出 6 种尺寸。然而,要求是为工厂制定每日生产计划。每日生产目标是 25,000。此外,每个子集可以使用约 20 次。平均而言,在一条牛仔裤中,每种尺寸总会有大约 20 次相同的尺寸。
为了获得良好的面料优化,需要六种尺寸。这意味着,在做出三次选择后,结果代表了潜在优化选择的一个子集:
R = 120 × 3 个两尺寸的子集 = 360
找到了魔数。对于每 3 个选择,通过 20 次重复生成 6 个尺寸的目标将会达成。
每天的生产请求为 25,000:
请求的子集数量 = 25000/3 = 8333. 333
系统可以运行 8,333 个产品,直到生成所需子集的数量。在这种情况下,范围设置为 1,000,000 个产品的样本。根据需要可以扩展或缩减。系统通过以下函数筛选正确的子集:
for element in range(1000000):
    ...(a block of code is here in the program)...
    if(result[0]>0):
        subsets+=1
        print("Subset:",subsets,"size subset #",x1," and ","size subset #",x2,"result:",result[0],"order #"," and ",s1,"order #",s2)
    if(subsets>=8333):
        break 
当找到了符合较小-较大尺寸分布的 8,333 个子集时,系统停止运行,如下输出所示:
Subset: 8330 size subset # 1 and size subset # 0 result: 1 order # and 53154 order # 14310
Subset: 8331 size subset # 1 and size subset # 0 result: 1 order # and 473411 order # 196256
Subset: 8332 size subset # 1 and size subset # 0 result: 1 order # and 133112 order # 34827
Subset: 8333 size subset # 0 and size subset # 1 result: 1 order # and 470291 order # 327392 
此示例证明了这一点。简单的解决方案可以解决非常复杂的问题。
必须添加两个主要功能,以及一些次要功能:
- 
每次选择后,必须从 500,000 订单数据集中删除选择的订单。当选择了一个订单后,再次处理它将会在全局结果中生成错误。这将排除两次选择相同订单的可能性,并减少要做出的选择次数。 
- 
例如,优化函数用于重新组织生产目的的结果。其思想不是随机遍历记录,而是按组织成集合进行控制。这样每个集合可以独立控制。 
应用信息:
- 
应用程序的核心计算部分不超过 50 行。 
- 
通过少数控制功能和数组,程序最多可能达到 200 行。控制功能的目标是检查结果是否达到总体目标。例如,每 1,000 条记录,可以检查本地结果是否符合总体目标。 
- 
这样可以轻松维护团队。 
优化代码行数以创建强大的应用程序,对于许多业务问题来说,这可能非常高效。
总结
从头开始构建一个小型神经网络提供了神经元基本属性的实际视图。我们看到神经元需要一个可能包含许多变量的输入。然后,将权重应用于带有偏差的值。接着,激活函数转换结果并生成输出。
在企业环境中,即使是一层或两层的神经网络,也可以提供现实生活中的解决方案。使用复杂理论分解成小函数实施了一个真实的业务案例。然后,这些组件被组装成尽可能简单和有利可图的形式。
把问题分解成基本部分,并找到简单而强大的解决方案需要才智。这比仅仅输入数百到数千行代码更需要努力来使事情运行。一个经过深思熟虑的算法将始终更有利可图,软件维护也将更加经济实惠。
客户期望快速解决方案。人工智能提供了多种工具,能够满足这一目标。在为客户解决问题时,不要追求最完美的理论,而是寻找最简单、最快速的方式来实施一个有利可图的解决方案,无论它看起来多么不传统。
在这个案例中,增强型 FNN 感知机解决了一个复杂的商业问题。在下一章中,我们将探索卷积神经网络(CNN)。我们将逐层使用 TensorFlow 2.x 构建一个 CNN 来分类图像。
问题
- 
感知机是否能单独解决异或问题?(是 | 否) 
- 
异或函数是线性不可分的吗?(是 | 否) 
- 
神经网络中层的主要目标之一是分类。(是 | 否) 
- 
深度学习是唯一的分类数据方式吗?(是 | 否) 
- 
成本函数显示神经网络成本的增加。(是 | 否) 
- 
简单的算术运算是否足以优化成本函数?(是 | 否) 
- 
前馈网络需要输入、层和输出。(是 | 否) 
- 
前馈网络总是需要通过反向传播进行训练。(是 | 否) 
- 
在实际应用中,解决方案往往是通过遵循现有理论找到的。(是 | 否) 
进一步阅读
第九章:使用卷积神经网络(CNN)进行抽象图像分类
卷积神经网络(CNN)在视觉领域的发明,至今仍是应用数学史上最具创新性的成就之一。凭借其多层(可见层和隐藏层)结构,CNN 将人工智能从机器学习带入了深度学习的领域。
在第八章《使用前馈神经网络解决 XOR 问题》中,我们看到 f(x,w)是任何神经网络的构建块。一个函数 f 会将输入 x 和权重 w 转换为输出。这个输出可以直接使用,或者输入到另一个层中。在本章中,我们将概括这个原理并引入多个层。同时,我们将使用带有图像的数据集。我们将拥有一个训练数据集和一个验证数据集,以确认我们的模型有效。
卷积神经网络(CNN)依赖于线性代数的两大基本工具:卷积核和函数,并将它们应用于本章所述的卷积操作。这些工具在数学中已经使用了数十年。
然而,解决现实问题的突破来自于 Yann LeCun、Yoshua Bengio 等人的非凡想象力——他们构建了一个多层的数学模型,才使 CNN 能够应用于实际问题。
本章描述了卷积神经网络(CNN)的奇妙之处,它是人工神经网络(ANNs)的支柱之一。我们将从零开始构建、训练并保存一个 CNN。所描述的分类模型将用于检测食品加工生产线上的生产故障。图像检测将超越物体识别,并以概念的形式产生抽象结果。
一个 Python TensorFlow 2 程序将逐层构建并训练。附加示例程序将展示关键功能。
本章将涵盖以下主题:
- 
1D、2D 和 3D CNN 之间的区别 
- 
向卷积神经网络添加层 
- 
卷积核和滤波器 
- 
图像处理 
- 
ReLU 激活函数 
- 
核心初始化 
- 
池化 
- 
扁平化 
- 
全连接层 
- 
编译模型 
- 
交叉熵损失函数 
- 
Adam 优化器 
- 
训练模型 
- 
保存模型 
- 
可视化模型的 PNG 
我们将从介绍 CNN 开始,并定义它们是什么。
引入卷积神经网络(CNN)
本节描述了卷积神经网络的基本组件。CNN_SRATEGY_MODEL.py 将展示构建抽象图像检测模型所需的基本 CNN 组件。对于机器和人类而言,概念是认知的构建块。CNN 是深度学习的支柱之一(多层和神经元)。
本章将使用 Python 的 TensorFlow 2 版本,并通过现在已并入 TensorFlow 的 Keras 库来运行。如果你没有安装 Python 或不想进行编程练习,本章是自包含的,包含图表和解释。
定义卷积神经网络(CNN)
卷积神经网络处理信息,比如图像,并从中提取意义。
举个例子,假设你需要用一支普通铅笔和一张纸来表现太阳。那是一个阳光明媚的日子,太阳非常明亮—亮得有些过头。你戴上了一副非常厚重的太阳镜。现在你可以看太阳几秒钟。你刚刚应用了一个颜色降低滤镜,这是卷积神经网络中的第一步操作之一。
然后,你试图画出太阳。你画了一个圆圈,圆圈中间涂了一些灰色。你刚刚应用了一个边缘滤波器。最后,你多次在圆圈上描摹,使它更容易被识别,逐渐将你看到的内容转化为它的表现形式。现在,画出了一个圆圈,圆圈中间有一些灰色,周围有几条射线,任何人都能看出你画的是太阳。你微笑了;你做到了!你拍摄了一张太阳的彩色图像,并将它的数学表现形式转化为一个圆圈,这大概长得像这样:

图 9.1:圆形的数学表示
你刚刚经历了一个卷积神经网络的基本过程。
卷积这个词意味着你将你看到的太阳逐区域地转化成了一幅画。但是,你并不是一次性地看完整个天空。你进行了多次眼动,以逐区域地捕捉太阳,画画时也是如此。如果你用数学方式表示你如何将每个区域从视觉转化为纸面上的抽象,那将是一个卷积核。你可以看到,卷积操作将一个对象转换为更抽象的表现形式。这不仅限于图像,还可以应用于任何类型的数据(文字、声音和视频),我们希望从中提取模式。
有了这个概念,下面的图表展示了本章模型中的连续数学步骤,用于让机器处理图像,就像你所做的那样。卷积神经网络是一系列步骤,将把你看到的内容转化为分类状态。
在图表中,每个方框代表一个层。每个层有一个来自前一层的输入。每一层将转换输入并生成一个输出,作为下一个层的输入。在每一层,分类图像所必需的关键特征将被提取。
在你的例子中,它的作用是判断你的画作是否代表太阳。这属于一个二分类模型(是或不是,或者 1 或 0)。

图 9.2:CNN 的架构
请注意,输出的大小逐渐减少,直到输出达到 1,即二元分类状态(返回 1 或 0)。这些连续的步骤或层,代表了你从观察太阳到绘制它的过程。如果我们绘制得不好,没人认出那是太阳,这意味着我们需要回到第 1 步并更改一些参数(在这种情况下是权重)。这样,我们就能通过训练更好地表示太阳,直到有人说,“是的,那是太阳!” 那时概率 = 1。另一个人可能会说那不是太阳(概率 = 0)。在这种情况下,可能需要更多的训练。
如果你进行绘制太阳的实验,你会注意到,作为人类,你一次用眼睛和铅笔转化一个区域。你会在每个区域中重复相同的方式。你所做的数学重复就是你的卷积核。每个区域使用一个卷积核是最快的绘制方式。对我们人类来说,事实上,这也是我们唯一能绘制的方式。CNN 就是基于这个过程。
在这一部分,我们通过用绘制太阳的比喻,探讨了 CNN 模型的一些关键方面。这只是开始卷积神经网络的一种方式,实际上有成百上千种不同的方法。然而,一旦你理解了某个模型,你就具备了实现其他变体所需的理解。
在接下来的部分,我们将看到如何初始化并构建我们自己的 CNN。
初始化 CNN
CNN_SRATEGY_MODEL.py使用 TensorFlow 2 构建 CNN。TensorFlow 2 在开发方面进行了巨大的改进。Keras 的数据集、层和模型现在都是 TensorFlow 实例的一部分:
import tensorflow as tf
from tensorflow.keras import datasets, layers, models 
CNN 只需要两行代码就可以构建层!在 TensorFlow 2 中,对于每一层,我们只需调用layers.<add your layer here>,就完成了!
使用的模型是一个 Keras sequential(),通过 TensorFlow from tensorflow.keras实例调用:
classifier = models.Sequential() 
就这样,我们只用了几行代码就开始构建了自己的 CNN。TensorFlow 2 简化了整个创建 CNN 的过程,使其变得简单直观,正如我们将在本章中看到的那样。
让我们在接下来的部分开始在我们 CNN 的基础上构建,并添加一个卷积层。
添加一个二维卷积层
在本章中,我们将使用二维模型作为示例。二维关系可以是现实生活中的图像,也可以是本章中描述的其他许多物体。本章描述了一个二维网络,尽管也有其他类型的网络。
- 
一维 CNN 主要描述的是时间模式,例如,一系列声音(音素 = 词的部分)、单词、数字以及其他任何类型的序列。 
- 
体积模块是三维卷积,例如识别一个立方体或视频。例如,对于自动驾驶汽车来说,区分一张广告上人物的二维图片和一个即将横穿道路的行人三维图像是至关重要的! 
在本章中,将会对不同种类的图像应用一个二维空间卷积模块。主要程序CNN_STRATEGY_MODEL.py将描述如何构建和保存一个模型。
classifier.add将会向模型中添加一层。classifier这个名字并不代表一个函数,它只是这个特定程序中随便给这个模型起的名字。模型最终将拥有n层。请看下面这一行代码:
classifier.add(layers.Conv2D(32, (3, 3),input_shape = (64, 64, 3), activation = 'relu')) 
这行代码包含了大量信息:滤波器(应用了卷积核)、输入形状和激活函数。这个函数还包含了更多的选项。一旦你深入理解这些内容,你就可以根据自己每个项目的需要,逐一实现其他选项。
卷积核
为了开始直观地理解,我们来看一个日常模型。这个模型稍微有点数学化,且更接近于卷积神经网络(CNN)的核表示。想象一下在一栋办公楼的地板上铺满了非常小的方形瓷砖。你希望每一块瓷砖从脏变干净,例如。
你可以想象一个清洁机器,能够一次性将 3×3 的小瓷砖(像素)从脏变干净。如果看到有人拿着一台巨大的清洁机器来同时清理所有 32×32 块瓷砖(像素),你一定会笑出声来。你知道它会非常笨重、缓慢且难以使用。更何况,你还需要每一块地面大小都配一个大机器!卷积核不仅是一种高效的滤波方式,卷积核卷积还是一种节省时间的资源处理方式。那个小清洁机器就是卷积核(脏到干净的滤波器),它将帮助你节省时间,执行卷积操作(清理一个 3×3 区域的所有瓷砖),将地面从脏到干净地转变。
在这种情况下,已经添加了 32 个不同的滤波器,每个滤波器使用的是 3×3 大小的卷积核:
classifier.add(layers.Conv2D(32, (3, 3)... 
使用卷积核作为滤波器是卷积神经网络的核心。(32, (3,3))表示(滤波器数量, (卷积核大小))。
一种直观的方法
为了直观地理解卷积核,可以参考阳光和清洁瓷砖的例子。在这一节中,猫的照片将展示卷积核是如何工作的。
在一个分析猫的模型中,初始的照片应该是这样的:

图 9.3:猫的照片用于模型分析
在这个层的第一次运行中,即使没有经过训练,一个未经训练的卷积核也会转化这张照片:

图 9.4:猫的照片转化
第一层已经开始隔离猫的特征。边缘开始显现:猫的身体、耳朵、鼻子和眼睛。单单这个第一滤波器(32 个之一),使用一个 3×3 的卷积核—在没有训练的情况下—已经产生了有效的结果。卷积核的大小可以根据需要变化。例如,一个 3×3 的卷积核需要比 1×1 的卷积核更多的权重。1×1 的卷积核只有一个权重,这限制了它表示的特征的大小。规则是卷积核越小,我们需要找到的权重就越少,也会进行特征压缩。当卷积核的大小增加时,权重和特征的数量也会增加,同时所表示的特征数量也会增加。
每一层都会使特征更加突出,使用越来越小的矩阵和向量,直到程序获得清晰的数学表示。
现在我们已经有了一个直观的滤波器工作方式的理解,接下来让我们探索一下开发者的方法。
开发者的方法
开发者喜欢先看到结果,以决定如何解决问题。
让我们通过Edge_detection_Kernel.py和一个边缘检测卷积核,快速而具体地理解卷积核:
#I.An edge detection kernel
kernel_edge_detection = np.array([[0.,1.,0.],
[1.,-4.,1.],
[0.,1.,0.]]) 
卷积核是一个 3×3 的矩阵,就像猫的例子一样。但其数值是预设的,而不是通过权重进行训练的。这里没有学习过程;只是需要应用一个矩阵。与卷积神经网络(CNN)不同的是,CNN 会通过权重和偏置来自动学习如何优化卷积核。
img.bmp 被加载,3×3 的矩阵被应用到加载图像的每个区域:
#II.Load image and convolution
image=mpimg.imread('img.bmp')[:,:,0]
shape = image.shape 
卷积应用前的图像是字母A(字母识别):

图 9.5:字母“A”
现在,卷积对图像进行转换,如以下代码所示:
#III.Convolution
image_after_kernel = filter.convolve(image,kernel_edge_detection,mode='constant', cval=0) 
现在字母 A 的边缘清晰地以白色显示,如下图所示:

图 9.6:A 字母的白色边缘可见
顶部的原始图像显示了一个非常粗的 A。前面的图表展示了一个通过细边缘识别的、清晰的 A 特征,神经网络可以通过少量数学操作对其进行分类。卷积神经网络的第一层会训练找到正确的权重,从而自动生成正确的卷积核。
现在我们已经有了一个直观且实用的开发者视角来理解滤波器,接下来让我们将一些数学方法加入到我们的思路中。
一种数学方法
初始图像有一组可以显示的值,如下所示:
#II.Load image
image=mpimg.imread('img.bmp')[:,:,0]
shape = image.shape
print("image shape",shape) 
代码将打印出图像的数值输出,如下所示:
image shape (100, 100)
image before convolution
[[255 255 255 ..., 255 255 255]
 [255 255 255 ..., 255 255 255]
 [255 255 255 ..., 255 255 255]
 ..., 
卷积滤波器通过数学函数filter.convolve来应用,以变换图像并进行滤波。
卷积滤波器函数使用多个变量:
- 
3×3 核的空间索引以便应用;在这种情况下,它必须知道如何访问数据。通过空间索引* j 来执行此操作,它管理网格中的数据。数据库也使用空间索引来访问数据。这些网格的轴决定了空间索引的密度。核和图像使用j在W*(加权核)上进行卷积。 
- 
W是加权核。 
- 
I是输入图像。 
- 
k是W中心的坐标。在此情况下,默认值为 0。 
这些变量然后作为以下方程表示的filter.convolve函数的输入:

CNN 依赖于核。花足够的时间通过掌握 AI 所需的三维领域来探索卷积:直观方法、开发测试和数学表示。
现在我们已经对卷积滤波器的工作原理有了数学上的理解,接下来我们来确定卷积层的形状和激活函数。
形状
input_shape定义了图像的大小,这里是 64×64 像素(高度×宽度):
classifier.add(...input_shape = (64, 64, 3)...) 
3表示通道数。在此情况下,3表示 RGB 颜色的三个参数。每个通道的值可以在 0 到 255 之间。
ReLU
激活函数提供了影响加权数据计算转化的有用方式。它们的输出将改变分类、预测或网络所构建的其他目标的过程。此模型应用了整流线性单元(ReLU),如下代码所示:
classifier.add(..., activation = 'relu')) 
ReLU 激活函数将以下函数的变体应用于输入值:
f(x) = max{0, x}
该函数对负值返回 0;对正值返回x;对 0 值返回 0。函数的一半域将返回零。这意味着,当你提供正值时,导数将始终为 1。ReLU 避免了像逻辑 sigmoid 函数的压缩效应。然而,选择使用一个激活函数而不是另一个将取决于每个 ANN 模型的目标。
用数学术语来说,整流线性单元(ReLU)函数将所有负值变为 0,而所有正值保持不变。
ReLU.py程序提供了一些函数,包括一个 NumPy 函数,用于测试 ReLU 的工作原理。
你可以输入测试值,也可以使用源代码中的值:
import numpy as np
nx=-3
px=5 
nx期望一个负值,px期望一个正值,用于测试relu(x)和lrelu(x)函数。如果你希望在测试过程中包含零值,请使用f(x)函数。
relu(x)函数将计算 ReLU 值:
def relu(x):
    if(x<=0):ReLU=0
    if(x>0):ReLU=x
    return ReLU 
在这种情况下,程序将返回以下结果:
negative x= -3 positive x= 5
ReLU nx= 0
ReLU px= 5 
负值的结果变为 0,正值保持不变。因此,导数或斜率始终为 1,这在许多情况下是实用的,并且在调试 CNN 或其他任何 ANN 时提供了良好的可见性。
定义如下的 NumPy 函数将提供相同的结果:
def f(x):
    vfx=np.maximum(0.1,x)
    return vfx 
通过反复试验,ANN 研究提出了几种 ReLU 的变种。
一个重要的例子发生在许多输入值为负时。ReLU 会不断产生零值,使得梯度下降变得困难,甚至不可能。
通过使用泄漏 ReLU,找到了一种巧妙的解决方案。泄漏 ReLU 不会对负值返回 0,而是返回一个可以选择的小值,例如 0.1 而不是 0。见以下方程:
f(x) = max{0.1, x}
泄漏 ReLU 解决了“死亡”神经元的问题。假设你有一层在激活神经元时总是返回负值。此时,ReLU 激活将总是返回 0。这意味着这些神经元“死了”。它们将永远不会被激活。为避免这些“死亡”神经元,泄漏 ReLU 提供了之前看到的小正值(0.1),确保神经元不会“死”。
现在梯度下降会正常工作。在示例代码中,该函数的实现如下:
def lrelu(x):
    if(x<0):lReLU=0.01
    if(x>0):lReLU=x
    return lReLU 
尽管 ReLU 有许多其他变种,但有了这些,你就能了解它的作用。
输入一些自己的值,程序将显示结果,如下所示:
print("negative x=",nx,"positive x=",px)
print("ReLU nx=",relu(nx))
print("ReLU px=",relu(px))
print("Leaky ReLU nx=",lrelu(nx))
print("f(nx) ReLu=",f(nx))
print("f(px) ReLu=",f(px))
print("f(0):",f(0)) 
结果将显示如下 ReLU 结果:
negative x= -3 positive x= 5
ReLU nx= 0
ReLU px= 5
Leaky ReLU nx= 0.01 
我们已经处理了输入图像的一个大表示。现在我们需要缩小表示的大小,以便获得更好、更抽象的表示。通过池化一些像素,我们还将减少后续层的计算量。
池化
CNN 包含隐藏层。输入是可见的。然后,随着各层工作以转换数据,“隐藏”的工作在进行。输出层再次是可见的。让我们继续探索这些“隐藏”层!池化减少了输入表示的大小,在本例中是图像。最大池化是将最大池化窗口应用于图像的某一层:
classifier.add(layers.MaxPooling2D(pool_size = (2, 2))) 
这个pool_size 2×2 的窗口将首先找到图像矩阵左上角 2×2 矩阵的最大值。这个第一个最大值是 4。因此,它是右侧池化窗口的第一个值。
然后,最大池化窗口跳过 2 个格子,找到 5 是最高值。5 被写入最大池化窗口。这个跳跃动作称为步幅。步幅值为 2 将避免重叠,尽管一些 CNN 模型的步幅会有重叠。这一切都取决于你的目标。请看下面的示意图:

图 9.7:池化示例
输出大小现在从 62×62×32(滤波器数量)变为 31×31×32,如下图所示:

图 9.8:输出大小变化(池化)
还有其他池化方法,例如平均池化,它使用池化窗口的平均值,而不是最大值。这取决于模型,并展示了训练模型时需要付出的辛勤努力。
接下来的卷积和池化层
CNN 的接下来的两层与之前描述的前两层采用相同的方法,源代码实现如下:
# Step 3 Adding a second convolutional layer and pooling layer
print("Step 3a Convolution")
classifier.add(layers.Conv2D(32, (3, 3), activation = 'relu'))
print("Step 3b Pooling")
classifier.add(layers.MaxPooling2D(pool_size = (2, 2))) 
这两层将输入大幅缩小为 14×14×32,如下图所示:

图 9.9:卷积层和池化层
在卷积神经网络中,可以插入一个填充层。随着我们逐层缩小图像,卷积网络中的滤波器会对中心像素产生比对外部像素更大的影响。假设你开始在一张纸上绘画,你倾向于填充纸的中心而避开边缘。纸的边缘包含的信息较少。如果你决定对边缘应用填充,图像将更加完整。在神经网络中,填充具有相同的功能。它通过添加值确保边缘也被考虑进去。填充可以在池化之前或之后实现。例如,我们将在第十三章,使用 TensorFlow 2.x 和 TensorBoard 可视化网络中实现一个填充的例子。
下一层可以对池化部分的输出应用展平,如我们将在下一节中看到的。
展平
展平层将最大池化层的输出转换为一个大小为 x * y * z 的向量,像下面的代码所示:
# Step 4 – Flattening
print("Step 4 Flattening")
classifier.add(layers.Flatten()) 
在这种情况下,层向量将是 14 × 14 × 32 = 6,272,如下图所示:

图 9.10:展平层
该操作创建了一个标准层,具有 6,272 个非常实用的连接,用于后续的全连接操作。展平操作完成后,可以实现一个完全连接的全连接网络。
全连接层
全连接层是完全连接的。通过到目前为止计算的尺寸缩减,可以实现完全连接,如前所示。
这个顺序模型中的连续层已经将图像的大小缩小到足以使用全连接层来完成任务。dense_1是第一层,如下所示:

图 9.11:全连接层
展平层生成了一个 14×14×32 大小的 6,272 层,每个输入都有一个权重。如果没有经过前面的层,展平层会生成一个更大的层,这会减慢特征提取的速度。结果将无法有效生成任何东西。
通过连续的层和尺寸缩减,滤波器提取了主要特征,接下来的全连接操作将直接通过 ReLU 激活进行预测,然后使用逻辑 Sigmoid 函数生成最终结果:
print("Step 5 Dense")
classifier.add(layers.Dense(units = 128, activation = 'relu'))
classifier.add(layers.Dense(units = 1, activation = 'sigmoid')) 
现在我们已经有了全连接层,让我们来探讨全连接层的激活函数。
全连接层激活函数
ReLU 激活函数可以像其他层一样应用于全连接层。
ReLU 激活函数的定义域应用于第一次全连接操作的结果。ReLU 激活函数将对值>=0 的输入输出初始输入,对值<0 的输入输出 0:
f(input_value) = max{0, input_value)
如第二章《构建奖励矩阵——设计你的数据集》所述,逻辑激活函数应用于第二个全连接层操作。
它会产生一个介于 0 和 1 之间的值:
LS(x)={0,1}
现在我们已经在LS激活函数后构建了最后一个全连接层。
最后一个全连接层的大小为 1,将对初始输入进行分类——在此案例中为图像:

图 9.12:第二个全连接层
现在模型的各个层已经添加完毕,训练可以开始了。
训练一个 CNN 模型
训练 CNN 模型包括四个阶段:编译模型、加载训练数据、加载测试数据,以及通过多轮损失评估和参数更新周期运行模型。
在本节中,训练数据集的主题选择将是来自食品加工行业的一个示例。这里的思想不仅是识别物体,而是形成一个概念。我们将在第十章《概念表示学习》中进一步探讨概念学习神经网络。暂时让我们先训练我们的模型。
目标
该模型的主要目标是检测食品加工传送带上的生产效率缺陷。使用 CIFAR-10(图像)和 MNIST(手写数字数据库)有助于理解和训练一些模型。然而,在这个例子中,目标不是识别物体,而是识别概念。
以下图像展示了一个包含可接受产品数量的传送带段,这里是巧克力蛋糕的部分:

图 9.13:巧克力蛋糕部分示例
这些图像可以代表从巧克力蛋糕到道路上的汽车或任何其他类型的物体。重点是检测物体行列中是否存在“差距”或“空隙”。为了训练 CNN,我使用了包含我偶尔画的物体的图像,目的是训练系统“看”到这些差距。
然而,有时生产会放慢,输出会下降到警报级别,如下图所示:

图 9.14:巧克力蛋糕部分示例
警报级别图像显示了一个差距,这将显著减慢工厂包装部分的速度。前面的图像中有三行物体。在第一行,可以看到五个小物体(这里是蛋糕块),在第二行,只有三个。在第三行,只有两个物体。因此,第二行和第三行缺少物体。在这种情况下,这个差距是生产线上的一个真实问题。每帧中可接受物体的数量是一个参数。
现在我们已经有了目标,开始编译模型吧。
编译模型
编译一个 TensorFlow 2 模型需要至少两个选项:损失函数和优化器。你评估你损失了多少,然后优化你的参数,就像在现实生活中一样。已经增加了一个度量选项来衡量模型的表现。通过度量,你可以分析你的损失并优化你的情况,如以下代码所示:
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy']) 
让我们来看一下模型编译的一些具体方面,从损失函数开始。
损失函数
损失函数提供了模型的状态 y[1](权重和偏置)与其目标状态 y 之间的距离信息。
二次损失函数的描述在本章中应用于案例研究模型的二进制交叉熵函数之前。
二次损失函数
让我们刷新一下梯度下降的概念。假设你在一座山丘上,想要走下山。你的目标是到达 y,山谷的底部。现在你的位置是 a。谷歌地图显示你仍然需要走一段距离:
y – a
这个公式在目前是很不错的。但现在假设你几乎到了山底,而前面的人丢了一枚硬币。你现在必须放慢速度,而谷歌地图在这个缩放级别下并没有太多帮助。
然后你必须通过一个二次目标(或成本)函数来缩小到更小的距离:
O = (y – a)²
为了便于分析,O 被除以 2,得到一个标准的二次成本函数:

y 是目标。a 是应用权重、偏置,最后应用激活函数的操作结果。
通过结果的导数,可以更新权重和偏置。在我们的山丘示例中,如果每步移动一米(y),那比每步移动 0.5 米(y)要多得多。根据你在山丘上的位置,你可以看到,不能应用一个恒定的学习率(从概念上讲,就是你的步长);你需要像优化器 Adam 一样进行调整。
二进制交叉熵
当学习速度变慢时,交叉熵非常有用。在山丘的例子中,它在底部变慢了。但请记住,一条路可能会把你带到旁边,也就是说,你暂时被卡住在某个高度。交叉熵通过能够在非常小的值(山上的步伐)下正常工作来解决这个问题。
假设你有以下结构:
- 
输入 = {x[1], x[2], …, x[n]} 
- 
权重 = {w[1], w[2], …, w[n]} 
- 
偏置(或有时更多)是 b 
- 
激活函数(ReLU、逻辑 Sigmoid 或其他) 
在激活之前,z表示经典操作的总和:

现在将激活函数应用于 z,以获得模型的当前输出。
y[1] = act(z)
有了这个思路,可以解释交叉熵损失公式:

在这个函数中:
- 
n是输入训练集的总项目数,对于多类数据,选择对数的底数(2,e,10)会产生不同的效果。 
- 
y是输出目标。 
- 
y[1]是之前描述的当前值。 
这个损失函数始终为正,值前有负号,且函数以负号开始。输出产生的小数字趋向于零,随着系统的进展而变小。
损失函数使用这个基本概念,结合更多的数学输入来更新参数。
二元交叉熵损失函数是一个二项式函数,它会输出 0 或 1 的概率,而不是像标准交叉熵那样输出 0 和 1 之间的值。在二项分类模型中,输出将是 0 或 1。
在这种情况下,当M(类别数量)= 2 时,不需要求和!。二元交叉熵损失函数如下所示:
损失 = –y log y[1] + (1 – y) log (1 – y[1])
该损失函数方法的核心概念是让 CNN 网络为优化器提供信息,以便相应地自动调整权重。
Adam 优化器
在山坡示例中,你首先用大步伐通过惯性下坡(因为你朝着正确的方向走,步伐较大)。然后,你需要走得更小一步,去找到物体。你根据需要调整你的步伐,这就是自适应动量估计(Adam)的含义。
Adam 不断地将过去的平均梯度与当前梯度进行比较。在山坡示例中,它比较的是你行进的速度。
Adam 优化器是经典梯度下降方法的替代方案。Adam 进一步通过将其优化器应用于数据集的随机(随机)小批量来进行扩展。这种方法是随机梯度下降的高效版本。
然后,Adam 通过将均方根偏差(RMSprop)加入过程,进一步创新,应用每个参数的学习权重。它分析权重均值的变化速度(例如我们山坡示例中的梯度变化),并相应地调整学习权重。
度量标准
度量标准用于在训练过程中评估模型的表现。度量函数的行为像一个损失函数。然而,它并不用于训练模型。
在这种情况下,accuracy参数为:
...metrics = ['accuracy']) 
在这里,值趋向 0 表明训练是否在正确的轨道上,值升高到 1 时,表明训练需要 Adam 函数优化,以便重新调整训练轨道。
这样,我们已经编译好了我们的模型。现在我们可以考虑我们的训练数据集。
训练数据集
训练数据集可以在 GitHub 上获取。数据集包含了之前提到的用于食品加工传送带示例的图像。我创建了一个包含一些重复图像的训练数据集,用来简单地说明 CNN 的架构。在实际项目中,需要通过反复试验精心设计,创建一个合适的数据集,以涵盖 CNN 面临的所有情况。
类 A 目录包含生产线所生产的合格产品的合格级别图像。类 B 目录包含生产线所生产的不可接受产品的警报级别图像。
数据集中的图像数量有限,原因如下:
- 
在实验训练过程中,生成的图像得到了良好的结果。 
- 
训练和测试阶段运行得更快,以便研究该程序。 
模型的目标是检测警报级别,这是 CNN 的一个抽象概念应用。
数据增强
数据增强通过生成扭曲版本的图像来增加数据集的大小。
ImageDataGenerator 函数生成所有图像批次,图像以张量格式呈现。它会通过扭曲图像(例如剪切范围)进行数据增强。数据增强是一种快速利用已有图像并通过扭曲创建更多虚拟图像的方法:
train_datagen =
tf.compat.v2.keras.preprocessing.image.ImageDataGenerator(
rescale = 1./255,shear_range = 0.2,zoom_range = 0.2,
horizontal_flip = True) 
代码的描述如下:
- 
rescale将在输入图像不为0(或None)时进行缩放。在本例中,数据将乘以 1/255 后再进行其他操作。
- 
shear_range将每个值按相同的方向偏移,在本例中由0.2确定。它会在某一点略微扭曲图像,产生更多虚拟图像以进行训练。
- 
zoom_range是缩放的值。
- 
horizontal_flip设置为True。这是一个布尔值,随机地将输入水平翻转。
ImageDataGenerator 提供了更多的实时数据增强选项,如旋转范围、高度偏移等。
加载数据
加载数据通过 train_datagen 图像预处理函数(如前所述)进行,并在以下代码中实现:
print("Step 7b training set")
training_set = train_datagen.flow_from_directory(directory+'training_set',
target_size = (64, 64),
batch_size = batchs,
class_mode = 'binary') 
本程序中的流程使用了以下选项:
- 
flow_from_directory将目录 +'training_set'设置为存储两个二进制类别的路径,用于训练。
- 
target_size将图像调整为指定的尺寸。在这个例子中,是 64×64。
- 
batch_size是每批数据的大小。默认值是 32,在本例中设置为 10。
- 
class_mode决定返回的标签数组:None或'categorical'将返回二维的独热编码标签。在这种情况下,'binary'返回一维的二进制标签。
看过训练数据集后,让我们继续看测试数据集。
测试数据集
测试数据集流遵循与训练数据集流相同的结构。不过,出于测试目的,可以根据模型选择使任务更简单或更困难。为了使任务更具挑战性,可以添加带有缺陷或噪声的图像。这将迫使系统进行更多的训练,并促使项目团队更加努力地进行模型的微调。我选择使用一个小型数据集来展示 CNN 的架构。在实际项目中,选择包含 CNN 将面临的所有情况的正确数据需要时间,并且是一个反复试错的过程。
数据增强提供了一种高效的方式来生成扭曲的图像,而无需向数据集中添加图像。许多其他方法可以在必要时同时应用。
在测试数据集上的数据增强
在这个模型中,数据仅通过重缩放处理。可以添加许多其他选项来使训练任务更加复杂,例如避免过拟合,或者仅仅因为数据集较小:
print("Step 8a test")
test_datagen = tf.compat.v2.keras.preprocessing.image.ImageDataGenerator(rescale = 1./255) 
构建数据集是人工智能项目中最困难的任务之一。如果数据增强有效,它可以成为一种解决方案。如果无效,必须使用其他技术。一种技术是,在可能的情况下,收集非常大的数据集,然后仅通过数据增强稍微扭曲数据以用于训练。
加载数据
加载测试数据仅限于模型所需的部分。其他选项可以微调当前任务:
print("Step 8b testing set")
test_set = test_datagen.flow_from_directory(directory+'test_set',
target_size = (64, 64),
batch_size = batchs,
class_mode = 'binary') 
永远不要低估数据集微调。有时候,这一阶段可能会持续几周,才能找到合适的数据集和参数。
一旦数据加载完成,CNN 分类器就可以开始训练了。现在我们来看看如何进行训练。
使用分类器进行训练
分类器已构建并可以运行:
print("Step 9 training")
print("Classifier",classifier.fit_generator(training_set,
steps_per_epoch = estep,
epochs = ep,
validation_data = test_set,
validation_steps = vs,verbose=2)) 
你会注意到,在本章中,我们为训练数据和测试数据分别设置了不同的目录。在第五章,如何使用决策树增强 K 均值聚类中,我们将数据集拆分为训练子集和测试子集。这同样可以应用于 CNN 的数据集。这是一个你需要根据具体情况做出的决定。
例如,有时测试集会比训练集更具挑战性,这也证明了分开存放的目录是合理的。在其他情况下,分割数据可能是最有效的方法。
fit_generator 函数,它按批次生成模型并进行拟合,包含了通过以下参数运行训练会话的主要超参数。超参数设置决定了训练算法的行为:
- 
training_set是前面描述的训练集流。
- 
steps_per_epoch是从生成器中输出的步骤总数(样本批次)。以下代码中使用的变量是estep。
- 
epochs是对数据输入进行的总迭代次数的变量。前面代码中使用的变量是ep。
- 
validation_data=test_set是测试数据流。
- 
validation_steps=vs与生成器一起使用,定义了程序开始时在以下代码中通过vs定义的测试样本批次数量:estep=100 #10000 vs=1000 #8000->100 ep=3 #25->2
在训练过程中,会显示一些度量指标:损失、准确率、迭代次数、层结构信息,以及算法计算的步骤。
以下是显示的损失和准确率数据示例:
Epoch 1/2
 - 23s - loss: 0.1437 - acc: 0.9400 - val_loss: 0.4083 - val_acc: 0.5000
Epoch 2/2
 - 21s - loss: 1.9443e-06 - acc: 1.0000 - val_loss: 0.3464 - val_acc: 0.5500 
现在我们已经构建并训练了模型,需要保存它。保存模型将避免每次使用时都重新训练模型。
保存模型
通过保存模型,我们就不需要每次使用时重新训练它。只有在需要微调时,我们才会重新进行训练。
TensorFlow 2 提供了一种方法,通过一行代码和一个序列化文件来保存模型的结构和权重:
以下代码中保存的model3.h5包含了模型结构和权重的序列化数据。它包含了每一层的参数和选项。这些信息对微调模型非常有用:
print("Step 10: Saving the model")
classifier.save(directory+"model/model3.h5") 
模型已经构建、训练并保存。
下一步
模型已经构建并训练完成。在第十章,概念表示学习中,我们将探索如何加载并运行该模型,而无需重新训练。
摘要
构建和训练 CNN 只有通过辛勤工作、选择模型、合适的数据集和超参数才能成功。模型必须包含卷积、池化、展平、全连接层、激活函数和优化参数(权重和偏差),这些都是训练和使用模型的坚实基础。
训练 CNN 以解决现实生活中的问题可以帮助向经理或销售潜在客户推销 AI。在这种情况下,使用该模型帮助食品加工厂解决输送带生产力问题,进一步将 AI 引入日常企业生活。
一个能够识别图像中抽象概念的 CNN 将深度学习推向更强大的机器思维。能够检测图像中的物体并从结果中提取概念的机器代表了 AI 的真正最终水平。
一旦训练完成,保存模型提供了一种实用的方法,可以通过加载并应用它来对新图像进行分类。本章在我们训练并保存模型后结束。
第十章,概念表示学习将深入探讨如何设计符号神经网络。
问题
- 
CNN 只能处理图像。(是 | 否) 
- 
核函数是用于卷积的预设矩阵。(是 | 否) 
- 
池化是否有池化矩阵,还是随机的? 
- 
数据集的大小总是需要很大。(是 | 否) 
- 
在网络上,所有可用的图像库使得找到数据集不再是问题。(是 | 否) 
- 
一旦构建了 CNN,训练它不会花费太多时间。(是 | 否) 
- 
训练好的 CNN 模型只适用于一种类型的图像。(是 | 否) 
- 
相比于交叉熵函数,二次损失函数的效率较低。(是 | 否) 
- 
现代 CPU 和 GPU 的性能下,深度学习 CNN 的表现不再是一个实际问题。(是 | 否) 
进一步阅读和参考资料
- TensorFlow 2: www.tensorflow.org/beta
第十章:概念表征学习
理解前沿的机器学习和深度学习理论仅标志着你冒险的开始。你所获得的知识应该帮助你成为 AI 的远见者。把你所看到的一切都当作机会,看看 AI 如何融入你的项目。挑战极限并超越它们。
本章侧重于通过视觉表征进行决策,并解释导致概念表征学习(CRL)和元模型(MM)的动机,二者共同构成了CRLMMs。
概念学习是我们人类将世界从混乱分割为类别、类、集合和子集的能力。作为一个孩子和年轻人,我们获取了许多事物和概念的类别。例如,一旦我们理解了“洞”是什么,我们就可以将其应用于任何我们看到的某种空洞的事物:黑洞、墙上的洞、银行账户中的洞(如果钱丢失或透支了),以及数百种其他情况。
通过进行概念学习,我们人类不必在每种情况中反复学习相同的概念。例如,洞就是洞。所以当我们看到一个新的情况,比如火山口时,我们知道它只是一个“大的”洞。我在职业生涯初期就注册了一个 word2vector 专利。然后,我迅速将其应用到 concept2vector 算法中。随后,我成功设计并开发了 CRLMM 方法,用于自动规划和调度(APS)软件、认知聊天机器人等,正如我们将在接下来的章节中看到的那样。元模型一词意味着我将一个单一模型应用于多个不同领域,就像我们人类做的那样。
概念表征还提供了概念的视觉图像。为了进行规划,人类需要可视化必要的信息(事件、位置等)以及更关键的视觉维度,比如图像概念。人类思维通过心理图像进行。当我们思考时,心理图像与数字、声音、气味和感觉一起流经我们的思维,将我们的环境转化为类似视频片段的奇妙多维表征。
本章将涉及以下主题:
- 
CRLMM 方法的三步法: - 
转移学习以避免为每个类似案例的变化开发新程序 
- 
域学习,以避免每次域发生变化时都开发一个新程序 
- 
使用 CRLMM 的动机 
 多年来,我已经成功地在 C++、Java 和逻辑编程(Prolog)中以多种形式在企业网站上实现了 CRL。在本章中,我将使用 Python 通过 TensorFlow 2.x 来说明这一方法,使用在第九章,使用卷积神经网络(CNNs)进行抽象图像分类中构建的卷积神经网络(CNN)。 
- 
- 
使用 CNN 模型的转移学习来泛化图像识别 
- 
域学习,将在一个领域训练的图像识别扩展到另一个领域 
我们将从本章开始,探讨迁移学习的好处,以及概念学习如何促进这一过程。
通过迁移学习创造利润
迁移学习意味着我们可以在另一个类似的案例中使用我们设计和训练过的模型。这会使模型非常有利可图,因为我们不需要为每个新案例设计一个新模型或编写一个新的程序。这样,你就能通过降低新实现你训练过的模型的成本,为公司或客户创造利润。把一个好的 AI 模型看作是一个在类似案例中可以重复使用的工具。这就是为什么概念学习更具普遍性和抽象性且有利可图的原因。这是我们人类适应的方式。
在推理和思考方面,我们通常会使用一些词语配合心象。我们的思维包含概念,我们基于这些概念构建解决方案。
来自第九章的训练模型,基于卷积神经网络(CNNs)的抽象图像分类,现在可以对某一类型的图像进行分类。在本节中,训练过的模型将被加载,并通过迁移学习进行泛化,以便分类类似的图像。
你会注意到,我在例子中没有使用太多的图像。我的目标是解释过程,而不是深入讨论如何构建大规模数据集,因为那本身就是一个任务。主要目标是理解CNNs 和概念学习表示。
迁移学习背后的动机
迁移学习提供了一种成本效益高的方式,可以在同一公司内部将训练好的模型用于其他目的,例如在第九章中描述的食品加工公司,基于卷积神经网络(CNNs)的抽象图像分类。
本章描述了食品加工公司如何将模型用于其他类似的目的。
成功做到这一点的公司将逐步推广解决方案的应用。通过这样做,演绎抽象将发生,并推动其他 AI 项目,这将为公司的管理层和提供解决方案的团队带来丰硕的成果。
演绎思维
演绎使用推论来得出结论。例如,食品加工传送带上缺少产品将导致包装生产力问题。如果不足够的产品到达包装环节,整个生产过程将会放慢。
通过观察公司其他领域的相似问题,管理人员会得出推论,例如如果产品流经工艺流程的数量不足,生产将会放慢。
演绎抽象
负责提升公司效率的项目团队需要找到问题的抽象表示,以通过组织或软件实施解决方案。本书主要讨论解决问题的 AI 方面。组织过程需要定义 AI 如何融入其中,并进行多次现场会议。
AI 需要解决的问题
在这个特定的例子中,工厂的每个部门都有一个每小时或每天定义的最优生产速率(OPR)。每小时的 OPR 方程可以总结如下:
OPR : min(p(s)) <= OPR <= max(p(s))
其中:
- 
p是给定部门的生产速率(工厂的不同生产部门)s。 
- 
p(s)是该部门的生产速率。 
- 
min(p(s))是历史最低值(经过几个月的反复试验和分析)。低于该水平,整个生产过程将减速。 
- 
max(p(s))是历史上的最大值。超过该水平,整个生产过程也会减速。 
- 
OPR 是最优生产速率。 
第一次看到这个方程时,它看起来很难理解。困难之处在于你需要将过程可视化,而这正是本章的目标。每个仓库、行业和服务都使用生产速率作为约束,以达到盈利水平。
可视化要求在两个层次上进行表示:
- 
确保如果包装部门没有收到足够的产品,它将不得不减慢生产速度,甚至有时停止生产。 
- 
确保如果包装部门收到过多的产品,它将无法进行包装。如果输入是没有中间存储的传送带(现代趋势),那么必须减慢速度,从而减缓或停止之前阶段的生产过程。 
在这两种情况下,减慢生产将导致糟糕的财务结果和通过延迟交付造成的严重销售问题。
在这两种情况下,OPR 差距是一个问题。为了解决这个问题,需要另一个层次的抽象。首先,让我们把 OPR 方程分成两部分:
OPR >= min(p(s))
OPR <= max(p(s))
现在,让我们通过方差变量v来找到一个更高的控制水平:
v[min] = |OPR – min(p(s))|
v[max] = |OPR – max(p(s))|
v[min]和v[max]分别是两种情况下方差的绝对值(分别是产品不足以生产和生产过多的情况)。
最终的表示是通过一个控制、检测和学习速率来完成的(希腊字母 gamma):

给定公司某一部门的最优生产速率与其最小速度(每小时产品数)之间的方差将导致下游部门的减速。例如,如果生产的蛋糕太少(v[min]),蛋糕包装部门将会等待并不得不停止生产。如果生产的蛋糕过多(v[max]),该部门将不得不减慢生产速度或停止生产。两者都会在无法轻松管理中间存储的公司中造成问题,这对于食品加工行业来说尤其如此。
通过这一单一的 概念,正如在第九章中介绍的卷积神经网络(CNN)在图像分类中的应用,TensorFlow 2.x CNN 可以开始学习一个基本的生产概念:什么是物理差距。让我们回到人类身上。一旦我们理解了“差距”是某种洞或空白空间,我们就能通过这个差距概念识别并表示数千种情况,这里我们把它转换成一个名为 gamma 的参数(
概念,正如在第九章中介绍的卷积神经网络(CNN)在图像分类中的应用,TensorFlow 2.x CNN 可以开始学习一个基本的生产概念:什么是物理差距。让我们回到人类身上。一旦我们理解了“差距”是某种洞或空白空间,我们就能通过这个差距概念识别并表示数千种情况,这里我们把它转换成一个名为 gamma 的参数( )。让我们先探索这个概念,然后进行实现。
)。让我们先探索这个概念,然后进行实现。
![]() 差距概念
差距概念
教授 CNN 差距概念将有助于它将思维能力扩展到许多领域:
- 
如前所述的生产中的空隙 
- 
自驾车可进入的车道上的空隙 
- 
任何不完整或有缺陷的区域 
- 
任何开启或窗口 
让我们教给 CNN 差距概念,或者简单来说,
差距概念,或者简单来说, 。差距的符号
。差距的符号 是希腊字母“gamma”,所以它简单地发音为“gamma”。因此,我们引导 CNN 学习如何识别一个我们称之为 gamma 的差距(
是希腊字母“gamma”,所以它简单地发音为“gamma”。因此,我们引导 CNN 学习如何识别一个我们称之为 gamma 的差距( )。目标是让 CNN 理解抽象概念——一个空白空间或洞,表示为gap(差距)和希腊字母 gamma(
)。目标是让 CNN 理解抽象概念——一个空白空间或洞,表示为gap(差距)和希腊字母 gamma( )。
)。
为了实现这个目标,第九章中训练并保存的 CNN 模型——卷积神经网络(CNN)在图像分类中的应用——现在需要被加载并使用。为了理解 概念的含义,可以想象一下,如果没有足够的客户订单,或者到处堆满了未完成的产品,所带来的成本。物理差距的财务转化表现为设定目标上的利润差异。我们都知道,这些差异会带来多么大的痛苦。
概念的含义,可以想象一下,如果没有足够的客户订单,或者到处堆满了未完成的产品,所带来的成本。物理差距的财务转化表现为设定目标上的利润差异。我们都知道,这些差异会带来多么大的痛苦。
加载训练好的 TensorFlow 2.x 模型
技术目标是加载并使用训练好的 CNN 模型,然后将相同的模型应用于其他类似的领域。实践目标是教会 CNN 如何使用 概念来增强调度、聊天机器人及其他应用程序的思维能力。
 概念来增强调度、聊天机器人及其他应用程序的思维能力。
加载模型有两个主要功能:
- 
加载模型以编译并分类新的图像,而不进行模型训练 
- 
层层显示所用的参数,并展示在学习和训练阶段达到的权重 
在接下来的部分中,我们将加载并显示模型,而不进行训练。
加载并显示模型
使用READ_MODEL.py读取保存的模型时,只需要有限数量的头文件,如下所示:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
import numpy as np
from PIL import Image
#Directory
directory='dataset/'
print("directory",directory) 
现在从文件中加载已保存的model3.h5模型,如下所示:
#____________________LOAD MODEL____________________________
loaded_model = keras.models.load_model(directory+"model/model3.h5")
print(loaded_model.summary()) 
加载的模型需要进行编译:
# __________________compile loaded model
loaded_model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy']) 
读取并显示模型并非一项形式主义操作。
打印结构提供了有用的信息:
print("GLOBAL MODEL STRUCTURE")
print(loaded_model.summary()) 
训练后的模型可能在所有数据集上都能或不能正常工作。在这种情况下,以下输出将指示可以通过其结构修复的问题,例如如下所示:
MODEL STRUCTURE
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 62, 62, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 31, 31, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 29, 29, 32)        9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 14, 32)        0         
_________________________________________________________________
flatten (Flatten)            (None, 6272)              0         
_________________________________________________________________
dense (Dense)                (None, 128)               802944    
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 129       
=================================================================
Total params: 813,217
Trainable params: 813,217
Non-trainable params: 0 
一旦展示了全局结构,就可以查看每一层的结构。例如,我们可以查看conv2d层:
DETAILED MODEL STRUCTURE
{'name': 'conv2d', 'trainable': True, 'batch_input_shape': (None, 64, 64, 3), 'dtype': 'float32', 'filters': 32, 'kernel_size': (3, 3), 'strides': (1, 1), 'padding': 'valid', 'data_format': 'channels_last', 'dilation_rate': (1, 1), 'activation': 'relu', 'use_bias': True, 'kernel_initializer': {'class_name': 'GlorotUniform', 'config': {'seed': None}}, 'bias_initializer': {'class_name': 'Zeros', 'config': {}}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}
{'name': 'max_pooling2d', 'trainable': True, 'dtype': 'float32', 'pool_size': (2, 2), 'padding': 'valid', 'strides': (2, 2), 'data_format': 'channels_last'} 
每个参数都包含非常有用的信息。例如,'padding':'valid'表示未应用填充。在此模型中,卷积核的数量和大小在没有填充的情况下提供了令人满意的结果,形状逐渐减小直到最终的状态层(分类),如下所示:
initial shape (570, 597, 4)
lay: 1 filters shape (568, 595, 3)
lay: 2 Pooling shape (113, 119, 3)
lay: 3 filters shape (111, 117, 3)
lay: 4 pooling shape (22, 23, 3)
lay: 5 flatten shape (1518,)
lay: 6 dense shape (128,)
lay: 7 dense shape (1,) 
然而,假设你想控制某一层的输出形状,以便空间维度不会比必要的更快地减小。一个原因可能是下一层将探索图像的边缘,我们需要使用适合形状的卷积核来进行探索。
在这种情况下,可以通过0值添加大小为 1 的填充,如以下矩阵所示:
| 0 | 0 | 0 | 0 | 0 | 0 | 
|---|---|---|---|---|---|
| 0 | 1 | 3 | 24 | 4 | 0 | 
| 0 | 3 | 7 | 8 | 5 | 0 | 
| 0 | 6 | 4 | 5 | 4 | 0 | 
| 0 | 5 | 4 | 3 | 1 | 0 | 
| 0 | 0 | 0 | 0 | 0 | 0 | 
大小为 2 的填充会在初始形状的周围添加两行和两列。
考虑到这一点,通过添加尽可能多的选项来微调训练模型,将提高结果的质量。可以通过逐层提取已保存模型文件中的权重来查看权重,如以下代码片段所示:
print("WEIGHTS")
for layer in loaded_model.layers:
    weights = layer.get_weights() # list of numpy arrays
    print(weights) 
分析程序使用的权重将提供有关优化过程如何进行的有用信息。有时,程序可能会卡住,权重看起来可能不太对劲。毕竟,CNN 和其他程序一样,可能包含一些不完美的地方。
查看以下输出,例如,可以帮助理解系统出错的地方:
WEIGHTS
[array([[ 6.25981949e-03,  2.35006157e-02, -1.28920656e-02, ...,
        -8.34930502e-03,  2.00010985e-02, -1.84428487e-02],
       [-1.01672988e-02,  1.87084991e-02,  2.49958578e-02, ...,
        -2.92361379e-02, -2.33592112e-02, -1.64737436e-03],
       [-2.71108598e-02,  2.53492035e-03, -2.90711448e-02, ..., 
现在我们可以使用已加载并检查过的模型。
加载模型以便使用
使用CNN_CONCEPT_STRATEGY.py加载模型需要有限数量的头文件,如下所示:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
import numpy as np
from PIL import Image 
加载模型是通过使用与之前描述的READ_MODEL.py相同的代码完成的。一旦加载模型,使用model.compile函数编译模型,如下所示:
# __________________compile loaded model
loaded_model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy']) 
用于此示例的模型和图像识别功能已分为两部分实现。首先,我们使用以下函数加载和调整图像的大小,例如:
def identify(target_image):
    filename = target_image
    original = load_img(filename, target_size=(64, 64))
    #print('PIL image size',original.size)
    if(display==1):
        plt.imshow(original)
        plt.show()
    numpy_image = img_to_array(original)
    inputarray = numpy_image[np.newaxis,...] # extra dimension to fit model
    arrayresized=np.resize(inputarray,(64,64))
    #print('Resized',arrayresized) 
模型期望输入数组中有一个额外的维度来进行预测,因此需要添加一个维度以适应模型。在此示例中,需要一次识别一张图像。
我添加了以下两个预测方法,并返回其中一个:
#___PREDICTION___
    prediction = loaded_model.predict_proba(inputarray)
    return prediction 
有两种预测方法,因为基本上,在项目实施阶段,CNN 中的每个组件都需要进行检查,以选择最佳和最快的组件。要测试prediction2,只需更改return指令。
一旦 CNN 开始运行,可能会很难发现问题所在。在构建网络时检查每一层和组件的输出,可以在完整模型生成成千上万的结果后节省微调时间。
以下示例检测了食品加工厂中传送带上的产品  空隙。该程序加载存储在
 空隙。该程序加载存储在classify目录中的第一张图像并预测其值。程序描述了预测结果:
MS1='productive'
MS2='gap'
s=identify(directory+'classify/img1.jpg')
if (int(s)==0):
    print('Classified in class A')
    print(MS1) 
该程序显示(可选)如下所示的形状图像,表示传送带在该点上有足够数量的产品:

图 10.1:输出(形状图像)
程序随后做出并显示预测0,这意味着在该生产线的传送带上没有发现实际的空隙:
directory dataset/
Strategy model loaded from training repository.
image dataset/classify/img1.jpg predict_proba: [[ 0.]] predict: [[ 0.]]
Classified in class A
Productive
Seeking... 
Seeking...表示程序将在分类方向分析第二张图像。它加载、显示并预测其值,如下所示:

图 10.2:输出(形状图像)
预测(值 = 1)正确检测到了传送带上的空隙,如下所示的输出:
image dataset/classify/img2.jpg predict_proba: [[ 1.]] predict: [[ 1.]]
Classified in class B
gap 
现在,CNN 的预测结果已被验证,实施策略需要获得批准。CNN 包含了应用数学的奇迹。CNN 本身就是深度学习的代表。研究人员可能会花费数百小时研究它们。
然而,商业世界中的应用数学需要考虑盈利。因此,CNN 的各个组件似乎是不断发展的概念。添加的卷积核、激活函数、池化、扁平化、全连接层以及编译和训练方法,作为架构的起点,而非最终结果。
使用迁移学习实现盈利或看到一个项目被停止
在某些时刻,公司将要求成果,并可能在未能交付这些成果时搁置项目。如果电子表格能够提供更快速且足够的解决方案,深度学习项目将面临潜在的竞争和拒绝。许多学习人工智能的工程师在接触真正的 AI 项目之前,必须先担任标准 SQL 报告专家的角色。迁移学习是一个有利可图的解决方案,可以提高 IT 部门的可信度。
迁移学习似乎是目前构建和训练 CNN 程序的成本问题的解决方案。你的模型可能通过这种方式带来回报。其思想是让一个基础的 AI 模型为你的客户和管理层快速带来利润。然后,你将获得大家的关注。为此,你必须定义一个策略。
定义策略
如果一位深度学习 CNN 专家对高级经理说这个 CNN 模型可以分类 CIFAR-10 图像中的狗、猫、汽车、植物等,那么答案可能是,那又怎样?我的三岁孩子也能做到。事实上,我的狗也能!
会议中的 IT 经理甚至可能脱口而出,“我们现在已经拥有所有决策工具了,而且我们的利润在增长。为什么还要投资 CNN?”
向现实世界公司营销 AI 的核心问题在于,它首先依赖于对 CNN 必要性的信仰。电子表格、SQL 查询、标准自动化和软件完成了 99%的工作。大多数时候,许多工作并不需要 CNN 来替代;仅仅是自动化的电子表格、查询或标准的软件就足够了。几十年来,工作已经被分解成足够简单的部分,可以用基础软件取代人类。
在展示 CNN 之前,数据科学家必须先了解公司通过使用 CNN 能够赚取多少利润。
理解、设计、构建和运行 CNN(卷积神经网络)与业务并没有太大关系。我们在理解和运行这些复杂程序上投入的所有努力,如果不能证明解决方案能产生利润,最终将毫无意义。没有利润,实施成本无法回收,没人会听一个关于即使是非常优秀的程序的演示。
高效应用模型意味着先在公司一个领域实施,然后再扩展到其他领域,以实现良好的投资回报。
应用模型
以食品加工公司为例,其中一个包装生产线存在性能问题。有时,随机地,传送带上会缺少一些蛋糕,如下图所示:

图 10.3:食品加工公司示例
为了启动一个具有成本效益的项目,可以在传送带上方安装一个便宜的网络摄像头。它每 10 秒钟拍摄一张随机样本图片,并处理它,以找出图像中央区域内的空隙。我们可以清楚地看到一个空白、缝隙或洞。如果检测到孔洞,意味着有些蛋糕未能成功进入传送带(生产错误)。
通过在某些蛋糕缺失时自动向生产机器人发送信号,可以提高 2%到 5%的生产率。生产机器人随后会向生产线发送信号,实时增加生产以弥补缺失的单位。这种类型的自动控制在各种自动化食品生产线上已有应用。然而,这为在生产线实施这一方法提供了一个低成本的起点。
通过将模型用于其他问题来实现盈利
假设食品加工实验在传送带上使用数据集类型d[1]和 CNN 模型M运作良好,这足以鼓励在同一公司中将其推广到另一个数据集d[2]。
迁移学习是指通过有限且具有成本效益的附加训练,从M(d[1])到M(d[2]),使用相同的 CNN 模型M。虽然会出现一些变化,但可以通过调整几个参数并根据一些基本的数据集准备规则处理输入数据来解决:
- 
过拟合:当模型迅速适应训练数据,并且准确率达到 100%时,这可能是问题也可能不是问题。在传送带上分类孔的情况下,过拟合可能不会造成严重影响。形状总是相同的,环境保持稳定。然而,在不稳定的情况下,面对各种不同的图像或产品,过拟合会限制系统的有效性。 
- 
欠拟合:如果准确率降到较低的水平,例如 20%,那么 CNN 将无法工作。数据集和参数需要优化。也许需要增加M(d[2])的样本数量,或减少,或者将其分成不同的组。 
- 
正则化:正则化通常涉及到解决M(d[2])的泛化问题,而不是M(d[2])的训练误差。可能需要改进激活函数,或者实现权重的方式需要关注。 
你可以应用任意数量的方法来找到解决方案,就像标准软件程序的改进一样。
迁移学习的结束和领域学习的开始
迁移学习可以用于此示例中的类似类型的物体或图像,如上所述。在同一公司内,使用相同模型训练越多相似的图像,将产生越高的投资回报率(ROI),并且这家公司会要求你提供更多的 AI 创新。
领域学习以第九章中描述的模型为基础,卷积神经网络(CNNs)在抽象图像分类中的应用,并能够对其进行泛化。泛化过程将引领我们进入领域学习。
领域学习
本节关于领域学习的内容架起了经典迁移学习(如前所述)与我在企业项目中发现的另一种领域学习应用之间的桥梁:教机器学习一个概念(CRLMM)。本章重点讲述的是如何教机器识别除食品加工公司外的其他情况中的空缺。
如何使用这些程序
你可以先阅读本章内容以理解概念,或先尝试运行程序。按你觉得最适合的方式进行。无论如何,CNN_TDC_STRATEGY.py加载训练好的模型(你无需在本章中重新训练),而CNN_CONCEPT_STRATEGY.py则用于训练模型。
本节中使用的训练好的模型
本节使用CNN_TDC_STRATEGY.py将训练好的模型应用于目标概念图像。READ_MODEL.py(如前所示)通过添加变量目录路径(用于model3.h5文件和图像)以及分类消息,已转换为CNN_TDC_STRATEGY.py,如下所示的代码:
#loads,traffic,food processing
A=['dataset_O/','dataset_traffic/','dataset/']
MS1=['loaded','jammed','productive']
MS2=['unloaded','change','gap']
#____________________LOAD MODEL____________________________
loaded_model = keras.models.load_model(directory+"model/model3.h5")....") 
加载的模型现在针对待分类的图像:
s=identify(directory+'classify/img1.jpg') 
模型的每个子目录包含四个子目录:
- 
classify: 包含待分类的图像
- 
model: 用于分类图像的训练好的model3.h5模型
- 
test_set: 概念图像的测试集
- 
training_set:概念图像的训练集
现在我们已经探讨了模型的目录结构,接下来让我们看看如何在不同情况下使用它。
训练后的模型程序
对于本章,你不需要训练模型。它已经在第九章《使用卷积神经网络(CNN)进行抽象图像分类》中训练好。目录路径已经变成了变量,可以访问之前描述的子目录。路径可以像下面的代码那样调用:
A=['dataset_O/','dataset_traffic/','dataset/']
scenario=3 #reference to A
directory=A[scenario] #transfer learning parameter (choice of images)
print("directory",directory) 
你无需为本章运行训练。模型已经在第九章《使用卷积神经网络(CNN)进行抽象图像分类》中训练好,并自动存储在书中提供的虚拟机的各自子目录中。这意味着当你需要检测各种类型图像的空隙时,你只需更改场景以适应你将从摄像头帧接收的图像类型:蛋糕、汽车、面料或抽象符号。
本章的重点是理解概念。你可以在不运行程序的情况下阅读本章,或者可以打开程序而不运行它们,或者运行它们——只要你觉得舒服。主要目标是掌握这些概念,为后续章节做准备。
我们已经加载了模型和场景。接下来,我们将使用训练好的模型来检测生产线是加载还是未加载。
空隙 – 已加载或未加载
空隙概念刚刚变成了一个多义性图像概念(多义性意味着不同的含义,如第六章《使用谷歌翻译创新 AI》所解释的那样)。
在蛋糕的情况下, 空隙在其 g[1] 子集的意义和概念中是负面的,并且应用于卷积神经网络(CNN),将其与负面图像 n + g[1] 联系起来:
 空隙在其 g[1] 子集的意义和概念中是负面的,并且应用于卷积神经网络(CNN),将其与负面图像 n + g[1] 联系起来:
ng[1] = {缺失、不足、降低生产效率...不好}
充满产品的图像是正面的,p + g[2]:
pg[2] = {良好的生产流,无空隙}
在这个例子中,CNN 学会了如何区分抽象表示,而不仅仅是像蛋糕那样的图像。另一个  (概念空隙数据集)子集是已加载/未加载的。“空隙”不是一个特定的对象,而是一个可以应用于数百种不同情况的普遍概念。这就是我使用“概念空隙数据集”一词的原因。
(概念空隙数据集)子集是已加载/未加载的。“空隙”不是一个特定的对象,而是一个可以应用于数百种不同情况的普遍概念。这就是我使用“概念空隙数据集”一词的原因。
以下是已加载的抽象图像。方框代表生产机器,箭头表示加载时间。
这意味着 x 轴代表时间,y 轴代表机器生产资源:

图 10.4:抽象图像 1
CNN 模型运行并产生以下结果:
directory dataset_O/
Strategy model loaded from training repository.
image dataset_O/classify/img1.jpg predict_proba: [[ 0.]] predict: [[ 0.]]
Classified in class A
loaded
Seeking... 
CNN 将其识别为正确加载的模型。任务超出了简单的分类。系统需要识别它以做出决策。
另一张图像产生了不同的结果。在这种情况下,以下截图中出现了一个负载不足的空隙:

图 10.5:抽象图像 2
并且 CNN 输出不同的结果,如下所示:
Seeking...
image dataset_O/classify/img2.jpg predict_proba: [[ 1.]] predict: [[ 1.]]
Classified in class
unloaded 
将“未装载”视为“欠载”。无论如何,未装载或欠载代表空的空间。空隙概念 已将g[3]和g[4]添加到其数据集中。现在我们有:
已将g[3]和g[4]添加到其数据集中。现在我们有:

 中的四个g[1]到g[4]子集是:
中的四个g[1]到g[4]子集是:
ng[1] = {缺失、不足、生产缓慢……不好}
pg[2] = pg[2] = {良好的生产流动,无空隙}
g[3] = {已装载}
g[4] = {未装载}
剩下的问题将需要一些时间才能解决。g[4](空隙)有时可以代表一个机器的机会,尤其是当它的工作负载不佳时,可能会有更多生产空间。在某些情况下,g[4]会变成pg[4](p = 正面)。在其他情况下,如果生产速度下降,它将变成ng[4](n = 负面)。
在本节中,我们了解了如何识别生产线中的“空隙”。如前所述,“空隙”是一个通用概念,指的是任何地方的空白区域。接下来,我们将探索堵塞或“畅通”交通车道。
空隙 – 堵塞或畅通车道
本章中的模型可以扩展到其他领域。自动驾驶汽车需要识别自己是否处于交通堵塞中。此外,自动驾驶汽车还必须知道在检测到足够空间(空隙)时,如何变换车道。
这会生成两个新的子集:
g[5] = {交通堵塞、交通繁忙……交通过多}
g[6] = {畅通车道、交通轻微……正常交通}
该模型现在能够检测到g[5](交通堵塞),如下图所示:

图 10.6:交通堵塞示例
以下输出显示正确:
directory dataset_traffic/
Strategy model loaded from training repository.
image dataset_traffic/classify/img1.jpg predict_proba: [[ 0.]] predict: [[ 0.]]
Classified in class A
jammed 
g[6]也显示正确,如下图所示:

图 10.7:交通堵塞示例
潜在的车道变换已经变得可能,如下代码所示:
Seeking...
image dataset_traffic/classify/img2.jpg predict_proba: [[ 1.]] predict: [[ 1.]]
Classified in class B
change 
我们已经将 CNN“空隙”检测模型应用于几种类型的图像。现在,我们可以更深入地探讨使用“空隙”作为示例的概念数据集理论。
空隙数据集和子集
此时, (空隙概念数据集)已经开始学习多个子集:
(空隙概念数据集)已经开始学习多个子集:

在其中:
ng[1] = {缺失、不足、生产缓慢……不好}
pg[2] = pg[2] = {良好的生产流动,无空隙}
g[2] = {已装载}
g[3] = {未装载}
pg[4] = {交通堵塞、交通繁忙……交通过多}
ng[5] = {畅通车道、交通轻微……正常交通}
请注意,g[2]和g[3]尚未有标签。食品加工上下文提供了这些标签。概念检测需要一个上下文,CRLMM 将提供这一点。
一般化![]() (空隙概念数据集)
(空隙概念数据集)
 (空隙概念数据集)的一般化将为元模型提供一个概念工具。
(空隙概念数据集)的一般化将为元模型提供一个概念工具。
 (空隙概念数据集)指的是两元素(对象、位置或生产线上的产品)之间的负面、正面或未确定空间。
(空隙概念数据集)指的是两元素(对象、位置或生产线上的产品)之间的负面、正面或未确定空间。
 (gamma)也指时间中的空隙:过长、不过长、过短或不够短。
(gamma)也指时间中的空隙:过长、不过长、过短或不够短。
 代表两个位置之间的距离:过远或过近。
代表两个位置之间的距离:过远或过近。
 可以表示两方之间的误解或理解:意见的分歧或趋同。
可以表示两方之间的误解或理解:意见的分歧或趋同。
所有这些示例都指的是将空间和时间视为空间的空隙。
应用于维度的概念表示学习元模型的动机
CRLMM 将图像转换为概念。这些抽象概念随后会嵌入到向量中,成为 softmax 函数的 logits,进而转化为复杂人工智能程序的自动调度、认知聊天机器人等的参数。
概念的优势在于它可以应用于许多不同的领域。仅凭一个概念,“空隙”(一个洞,空白空间,等等),你就可以描述成百上千的情况。
在一些人工智能项目中,降维根本无法产生良好的结果。例如,在飞机、火箭和卫星发射器的维修调度中,成千上万的特征进入系统,没有任何遗漏。在火箭上,某个地方一个遗漏的螺丝可能导致灾难;在飞机的引擎中,一次错误可能引发事故;卫星的单一部件故障会影响其精度。
必须考虑维度问题。有些人使用“维度灾难”这个表达,而我更倾向于称之为“维度的祝福”。让我们来看看这两种方式。
维度灾难
给定项目的特征数可能达到非常大的数量。以下示例包含 1,024 个维度:

图 10.8:维度灾难
上述表示中的每个点代表一个维度,比如图像中的特征。
比如,要求 CNN 分析图像中的成千上万个特征,可能会导致无法得到准确的结果。由于每一层本应减少分析数据的规模以提取重要特征,过多的维度可能会使模型的训练变得不可能。记住,每个维度都可以包含需要训练的特征权重。如果维度过多,训练将变得既漫长又难以计算。
遵循标准的 CNN 设计提供了一个良好的起点。这种方法的局限性出现在结果未达到预期时,例如在接下来的章节中我们将要探讨的一些案例中。在这些情况下,CRLMMs 将提高解决方案的生产力,提供一个有用的抽象模型。
当一个解决方案需要大量未减少的维度时,卷积核、池化和其他维度减少方法无法应用,CRLMM 将为系统提供一副眼镜。这时,维度的“福音”就变得非常有用。
维度的福音
在一些项目中,当模型达到项目的极限时,维度性反而是一种福音。
让我们以使用我们的 CNN 模型制造火箭为例。我们想要识别表面上的裂缝。这些表面上有瓦片,用于保护火箭在穿越大气层时免于过热。瓦片之间的裂缝可能导致致命事故。
如果我们取出几块瓦片,拍一张照片并通过我们的 CNN 模型处理,它可能会检测到裂缝。这个概率与错误之间的差异可能意味着火箭的严重故障。
这意味着我们可能不希望减少特征的数量,这样就需要权重,并增加维度的高数字。
我们可以决定不使用池化(如我们所见,将多个维度合并为一个)。这可能会导致计算问题,正如我们在上一段所见。要么会有过多的权重需要计算,要么计算可能会花费太长时间。
在这种情况下,我们可以将框架的大小缩小到我们正在检查的火箭部件的最小部分。我们可以决定让我们的相机一次只扫描最小的表面,将最小尺寸的框架发送给我们的 CNN。
在这种情况下,即使没有池化,层中也会包含更多的数据,但计算仍然是合理的。
在这种情况下,维度的“福音”在于,避免池化(分组)后,我们检查更多的细节,这可以使我们的模型在检测微小裂缝时更加可靠,因为我们将其训练成能够看到非常小的裂缝。
维度的诅咒通常导致维度减少。但正如我们刚才看到的,情况不一定是这样。
总结
在本章中,第九章中构建的 CNN 架构,使用卷积神经网络(CNN)进行抽象图像分类,被加载用于分类食品加工公司中的物理裂缝。该模型使用图像概念,将 CNN 推向另一个层次。神经网络可以发挥其巨大的认知潜力,开启人工智能未来的大门。
然后,训练好的模型通过识别相似类型的图像来应用迁移学习。其中一些图像代表了导致训练好的 CNN 识别概念差距的概念。图像概念代表了一种创新潜力的途径,将认知引入神经网络中。
 概念差距被应用到不同领域,使用 CNN 作为训练和分类工具进行领域学习。
 概念差距被应用到不同领域,使用 CNN 作为训练和分类工具进行领域学习。
 概念差距有两个主要特征:负 n 差距和正 p 差距。为了区分这两者,CRLMM 提供了一个有用的附加工具。在食品加工公司中,在右侧的食品加工输送带上安装网络摄像头,为系统提供了判断差距是正向还是负向的背景。
 概念差距有两个主要特征:负 n 差距和正 p 差距。为了区分这两者,CRLMM 提供了一个有用的附加工具。在食品加工公司中,在右侧的食品加工输送带上安装网络摄像头,为系统提供了判断差距是正向还是负向的背景。
牢记这些概念,让我们在下一章构建高级规划与调度(APS)的解决方案。
问题
- 
维度灾难导致在机器学习算法中减少维度和特征。(是 | 否) 
- 
迁移学习决定了一个项目的盈利能力。(是 | 否) 
- 
读取 model.h5并不会提供太多信息。(是 | 否)
- 
没有意义的数字足以取代人类。(是 | 否) 
- 
聊天机器人证明了肢体语言并没有那么重要。(是 | 否) 
- 
目前的人工神经网络提供了足够的理论来解决所有的 AI 需求。(是 | 否) 
- 
聊天机器人现在可以在所有情况下取代人类。(是 | 否) 
- 
自动驾驶汽车已获得批准,不需要概念训练。(是 | 否) 
- 
各行业可以实现 AI 算法来满足他们的所有需求。(是 | 否) 
进一步阅读
- 
更多关于 Keras 层的内容: keras.io/layers/about-keras-layers/
- 
更多关于概念学习的内容: www.sciencedirect.com/topics/psychology/concept-learning
- 
更多关于认知科学、大脑和思维的概念模型: catalog.mit.edu/schools/science/brain-cognitive-sciences/,symsys.stanford.edu/undergraduatesconcentrations/cognitive-science-cogsci-concentration
第十一章:结合强化学习与深度学习
亚马逊是全球领先的电子零售商之一,销售额超过 2500 亿美元。亚马逊的电子商店销售额超过了其其他所有业务,如 AWS 订阅服务(例如高级服务)、零售第三方卖家服务以及实体店。
本章聚焦于服装生产活动,这是亚马逊最近为其市场之一注册的专利。Prime Wardrobe 甚至提供试穿并轻松退货的服务。这一新活动需要进行规划和调度。亚马逊对此十分重视,并为服装制造系统控制其服装产品的生产过程注册了专利。
人工智能已经在服装行业的自动化规划和调度中发挥作用,从客户订单到交付全过程都涵盖在内。
谷歌成功地将深度学习与强化学习(Q 学习)结合在一个深度 Q 网络(DQN)中,该系统能够在视频游戏和其他任务中超越人类。谷歌的 AlphaGo DQN 取得了令人印象深刻的成绩。
本章不仅仅描述亚马逊的流程或特别是谷歌的流程。我还加入了我在现实生活中的实施案例,这些内容我们将从头开始使用 Python 进行探索和构建。因此,我们将结合多个系统(亚马逊、谷歌和我的实现)中的一些思想。
我们将通过将概念表示学习元模型(CRLMM)添加到强化学习中,为服装制造业带来创新。
我们将从零开始,逐步构建一个可以在现场实施的原型,基础设施正在为接下来的章节中的更多应用奠定基础。
本章将涵盖以下主题:
- 
今天和明天的规划与调度 
- 
进一步概括第10 章中描述的 CRLMM,应用于服装生产过程中的概念表示学习 
- 
为 CRLMM 的卷积神经网络(CNN)提供来自生产线摄像头的帧的模拟输入 
- 
引入一个优化器,它将使用应用于生产站点的权重,通过奖励矩阵输入到马尔可夫决策过程(MDP)中,进而更新这些权重。 
- 
构建一个将在生产线中持续运行的程序(没有开始,也没有结束),并使用之前提到的三个组件。 
我们将从今天和明天的规划与调度开始。市场正从预定的流程慢慢转向实时流程。让我们看看具体是如何做到的。
今天和明天的规划与调度
当亚马逊决定推出 Prime Wardrobe 时,它为客户带来了一个新服务,使他们能够订购、试穿并购买衣物、鞋子和其他配饰。客户可以建立一个购买计划。购买计划是一个在特定时间内需要完成的任务清单。购买计划的一个例子可能是:
- 
将衣物放入箱子中 
- 
在家试穿衣物 
- 
如果衣物不合身,则退货 
- 
购买保留的商品 
一旦客户同意按照这个计划进行,时间顺序变得至关重要:
- 
首先,必须选择一个盒子。 
- 
然后,是一个配送期。 
- 
然后是一个试用期(你不能永远试用产品)。在此期间,客户可以选择不购买任何商品。 
- 
最终,客户确认购买。 
无论亚马逊 Prime Wardrobe 是否能在未来几年继续作为一项服务,先例已然设立;就像实体书店每年消失一样,在线购买服装将继续扩展,并占据更多市场份额。
此外,企业将继续扩展其生产基地,成为制造与分销巨头。仓库将逐步取代许多商店,正如本书某些章节中所提供的仓库示例。
供应链管理(SCM)与 APS 相结合,已成为一种必需品。SCM-APS 约束在全球市场上不断变化(取决于制造商)。APS 代表先进的计划与调度或自动化的计划与调度。我们将在接下来的部分《实时制造革命》中探讨这两个概念的区别。我们将超越亚马逊对这一主题的处理,因为实时交付已成为市场上所有参与者的一个约束。
市场的压力促使亚马逊开始生产自有品牌服装。亚马逊已经推出了自有品牌的时尚标签,涵盖全球销售的服装和配饰。
为了证明其确实有意开展业务,亚马逊注册了多个专利,包括一项用于混合现实镜子、服装制造系统等的专利。有了混合现实镜子,顾客可以直观地看到衣物的合身效果。
在接下来的部分中,我们将深入探讨亚马逊服装自营生产计划的规划与调度方面,这将对服装工厂产生与以前对实体书店和所有类型商店相同的影响。许多新的工作将会出现,如人工智能领域、网站开发以及市场营销和 SCM 相关的数十万个工作岗位。同时,也将有许多工作消失。所做的改进将促进医疗进步,并且推动国防工业的发展。社会和经济的影响超出了本书的范围,可能也超出了我们的理解,就像历史上所有的颠覆性时代一样。
我们将详细关注亚马逊专利定制服装过程的主要方面。如前所述,无论是否成功,先例已经设定。
实时制造过程
今天,客户希望尽快获得购买的产品。如果等待时间过长,客户会转向其他地方。几乎实时交付已成为任何公司营销的关键概念。亚马逊的方法一直是实时的。突破了数百年的商业物理限制,亚马逊的品牌将制造过程推向了前沿。
亚马逊必须扩展其服务以应对竞争。
如果亚马逊继续从供应商那里购买产品,而不是自己制造,可能会避免许多动荡。研究人员花费大量时间开发能够解决传送带问题的人工智能时,可以通过安装几个传感器并使用传统软件解决方案来实现。
人类本可以继续使用马匹代替汽车,使用纸张代替计算机。在短期内,我们可以避免与这些技术的要求和影响相关的大量工作和变革。然而,从长远来看,最终获胜的是进步和创新。
一旦公司成功推出了一项颠覆性创新,竞争对手要么跟随,要么消失。亚马逊需要继续参与那些仅仅将商品存储在仓库之前的流程。例如,通过参与制造,亚马逊可以缩短将产品交付给客户所需的时间。于是,亚马逊提出了这项服装制造专利,并结合 3D 打印机等创新提高其生产力。
同样,人工智能领域也需要不断推动超越其不断扩展的舒适区。研究人员必须面临艰难的行业问题,积累经验,产生能够实现更高层次机器学习和应对更大挑战的新算法。
一场实时制造革命
尽管人工智能软件非常引人注目,但它并不是唯一改变我们生活的革命性技术。在 1950 年代和 1960 年代,消费者们正在发现购买新产品的乐趣,例如洗碗机、彩色电视和时尚收音机。他们为能够获得这些产品而感到无比高兴,以至于愿意等待几天甚至几周才能得到他们梦寐以求的具体型号。供应商可以将订单积压几天,然后再慢慢开始工作。
如今,消费者已经失去了那份耐心。如果某人想在线购买一件产品,它必须在几天内送到。如果不行,消费者就会转向其他供应商。这对供应商施加了压力,迫使其立即启动交付流程。实时性就是在你收到请求通知的几秒钟内开始着手完成事情的过程。
实时性是改变全球每一个过程的强大力量。
今天,服装制造业以及一般制造业都遵循先进的规划与调度过程。“先进”既指复杂的算法,也指预见性的(提前计划的)过程。AI 算法中提前规划的方面正在经历一场革命。
亚马逊和所有制造过程一样,需要自动化规划和调度以满足缩短的交货时间。
两个系统的根本区别是时间因素,以下对比表中有所显示。先进系统和自动化系统之间的差异看似微小,但像亚马逊这样的公司将通过这些差异改变历史进程。理论上,两种系统都可以完成这两种任务。在实践中,这些方法将在未来几年里在各自的细分领域中专业化。制造飞机时,一个复杂的先进算法仍然需要提前计划(几天到几周),并且需要大量人工决策。制造基本的 T 恤时,自动化规划可以快速且自动地在实时中完成(秒到小时)。
自动化规划与调度的趋势正成为先进规划与调度的压缩版。
以下表格中的数字并不反映准确的数值,而是反映趋势:
| 功能 | 先进的规划与调度 | 自动化的规划与调度 | 
|---|---|---|
| 长期计划 | 1 个月到 5 年 | 几天到不到一个月 | 
| 短期计划 | 1 天 | 1 分钟 | 
| 生产或事件测量 | 一般每日考虑 | 实时 | 
| 调度 | 1 小时到 1 周 | 实时 | 
| 有问题时的重新规划 | 1 小时到 1 个月 | 实时 | 
| 重新调度 | 1 小时到 1 周 | 实时 | 
| 资源调整 | 1 天到 1 个月 | 实时 | 
| 负载均衡 | 1 小时到 1 周 | 实时 | 
| 规划与调度的自动化功能 | 80% | 99% | 
尽管这个表格包含的是近似信息,但背后的趋势非常强劲。我们已经看到了先进与自动化概念的区别,接下来我们也来澄清计划与调度之间的区别:
- 
计划由为未来生产做准备的过程组成:采购物料组件、调整人力资源和物理资源。例如,亚马逊有一份年度商业计划:提前整合必要资源以准备生产。这意味着要采购或建设仓库、雇佣员工,以及采购基本物料资源(如箱子、标签和其他组件)。 
- 
调度是在较短时间范围内与时间因素对照的计划。调度决定了计划中的每个部分何时开始优先生产。例如,现在仓库已经建设或采购(计划),那么下周一和接下来的几周,包装工作应该在什么时间开始(调度)? 日程可以看作是计划的放大版。 
如果有人走进杰夫·贝索斯的办公室,带着在某个地点建立仓库的计划,说明实施的成本和大致时间安排,那是可以的。那个人正在呈现一个为期两年的项目。这个项目将在 10 个月后启动,并持续两年。
然后,那个人可能(我建议不要!)说:“计划很棒,因为 10 个月后就能完成。但我担心 1 年后第二班次下午 4 点的日程安排。他们应该在早上 7:30 开始,还是 7:45?”杰夫·贝索斯将不再听。他不会关注这个细节。那个级别不在他的工作描述中。他必须专注于更高层次的事务。对于一位高层管理者来说,知道一年后下午 4 点会发生什么是毫无意义的!
一个先进的计划与排程系统通常从企业资源规划(ERP)中导入数据,以制定未来的计划。而自动化计划与排程程序则主要通过传感器检测数据,实时反应并优化。当前章节讨论的是自动化计划程序,而不是先进的计划与排程系统。
将先进的 APS 与自动化 APS 之间的演变视为应用于计划排程时间压缩的后勤 sigmoid 函数。以下是一些例子:
- 
先进的制造汽车计划跨度为 1 个月到 1 年。 
- 
自动化计划的谷歌地图行程,用于自动驾驶汽车在起点的时间:几秒到一分钟,具体取决于该地点的连接状态。 
- 
制造一辆汽车的时间表:1 天到 1 个月。 
- 
按照谷歌地图行程来驾驶自动驾驶汽车的时间表 = 实时 
总结来说,当前的趋势代表了人类过程历史上的一场革命。
亚马逊的制造专利反映了实时应用革命在各个领域的变革。
规划已转向实时规划,如下方公式所示:

其中:
- 
x 是生产的数量或任何单位事件。 
- 
t[x] 是 x 开始和结束所需的时间 (t)。 
- 
一个后勤函数会压缩 t[x]。 
- 
![]() (lambda) 是学习因子;一个任务执行得越多,它就越被优化。 (lambda) 是学习因子;一个任务执行得越多,它就越被优化。
X[t] 是在给定时间 t 下,一组 n 个任务的总权重:
X[t] = {x[1], x[2], x[3] … x[n]}
X[t] 和 Z(X[t]) 之间的差异是:
- 
X[t] 是制造产品所需的实际时间。 
- 
Z(X[t]) 不是实际所需的时间。Z(X[t]) 是一个激活函数的结果,它将时间作为 X[t] 在 RL-DL-CRLMM 网络中的输出进行压缩。Z(X[t]) 是一个权重因子。 
进一步减少权重因子的关键是物理生产过程和其他物理事件(例如输出等),我称之为 lambda: 代表了所有能够减少生产周期的现实生产改进,以及像生产输出等自然事件。
 代表了所有能够减少生产周期的现实生产改进,以及像生产输出等自然事件。
在第十章,概念表示学习中, 被引入以减少差距。在本章中,
被引入以减少差距。在本章中, 将进一步概括,以优化
将进一步概括,以优化 。
。
这意味着 RL-DL-CRLMM 系统将优化制造过程。我们现在将探索一种改变游戏规则的自动化服装制造过程,并用 Python 构建它。
将 CRLMM 应用于自动化服装制造过程
亚马逊通过自动化的计划和调度系统,而不是先进的计划和调度系统,将服装制造带得更接近消费者。
人工智能将推动现有流程。在本节中,RL-DL-CRLMM 系统将优化服装制造过程。
服装制造过程
亚马逊的服装制造专利可以总结如下:
- 
P1:按产品和尺寸对服装客户订单进行分组。这个过程自工业服装制造的起源以来就存在了。 
- 
P2:自动切割铺布。铺布是一叠布料。它就像在一叠几张纸上同时切割一个圆圈。 
- 
P3:将服装零件的包裹通过传送带移动到组装线(见第十章,概念表示学习)。 
- 
P4:根据产品的不同,执行其他操作(如包装、印刷或其他)。 
- 
P5:通过仓库和配送优化存储和分配过程,以及更多的流程(例如,跟踪和数据分析,找到迟到的配送并优化其路线)。 
以下图表示了一个服装制造公司的生产流程。首先,布料被切割,然后堆叠在一堆堆中,通过传送带送到缝纫站以组装服装:

图 11.1:服装生产流程
一个网络摄像头安装在 P3 上方,即传送带上。下图展示了安装在传送带上的网络摄像头:

图 11.2:网络摄像头在传送带上冻结帧
网络摄像头每n秒冻结一帧(在红色矩形内)。该帧是稍后描述的 CRL-CNN 的输入。
这张图片是对概念的表示。实际上,网络摄像头可能位于传送带的起点,甚至在切割过程的输出上方。对于本章中的原型,请记住,每隔n秒钟,会将一个静止帧发送给训练过的 CNN。
这个 P1 到 P5 的流程图提供了一个服装制造过程的总体概念。在实际公司中,还需要更多的过程:市场调研、设计产品、测试原型、为牛仔裤增加制造工艺(例如,用激光打孔)等。
迄今为止描述的每个过程都是 30 多年前单独发明的,包括应用于服装行业的自动切割和输送带。对于许多阅读过亚马逊相关专利的服装专家来说,这里有什么新鲜的? 这一问题跃然心头。而这正是心智陷阱!认为亚马逊的服装专利没有包含新的组件是一个错误。
时间压缩是亚马逊创新过程的核心。将制造过程与消费者的需求几乎实时对接是一场颠覆性的革命。将 3D 打印机加入到时间压缩的方程式中,你将轻松想象我们未来的消费市场。然而,人工智能也有权进入优化竞争之中。
为了说明这一点,让我们构建一个优化 P3(输送带)的 AI 模型。虽然现有很多解决方案,但一个 RL+DL 很可能会胜过它们,就像在许多领域一样。
第一步是通过训练进一步推广 第十章,概念表示学习 中描述的  模型。然后,RL-DL-CRLMM 可以被建立。我们将首先探讨 CRLMM 如何被训练来分析生产中的网页帧。
 模型。然后,RL-DL-CRLMM 可以被建立。我们将首先探讨 CRLMM 如何被训练来分析生产中的网页帧。
训练 CRLMM
第十章,概念表示学习,介绍了 CRLMM,使用  (缝隙概念)来说明一个示例。
(缝隙概念)来说明一个示例。
在前几章中,围绕  (缝隙概念)设计了概念子集,如下所示:
(缝隙概念)设计了概念子集,如下所示:
- 
![]() ,其中包含 pg[i] (p = 正向) 和 ng[i] (n = 负向子集) ,其中包含 pg[i] (p = 正向) 和 ng[i] (n = 负向子集)
- 
ng[1] 是 ![]() 的子集; ng[1] = {缺失, 不足,降低生产效率 … 不良}, 的子集; ng[1] = {缺失, 不足,降低生产效率 … 不良},
- 
pg[2] 是 ![]() 的子集; pg[2] = pg[2] = 的子集; pg[2] = pg[2] =
- 
g[2] = 
- 
g[3] = {未加载}, 
- 
pg[4] = 
- 
ng[5] = 
CNN_STRATEGY_MODEL.py 需要被训练来识别服装生产环境中的  ,并记住如何识别以前的
,并记住如何识别以前的  概念:
 概念:
- 
服装包在输送带(P3)上流动的切割段 P2(A 和 B)输出。 
- 
记住如何对食品加工公司的蛋糕进行分类,以便教模型识别更多情况。 
- 
记住如何进行交通分析(见 第十章,概念表示学习)。 
- 
学会如何分类缝隙的抽象表示。 
推广单元训练数据集
为了推广单元训练数据集,创建了六种类型的图像。每个图像表示每隔 n 秒由摄像头拍摄的一帧图像,图像展示了一个经过输送带的场景。四张图像是具象的,具有具象绘画的意义。两张图像将 CRLMM 程序提升到了更高的抽象层次。
食品输送带处理 – 正向 p![]() 和负向 n
 和负向 n![]() 缝隙
 缝隙
在食品加工行业的例子中(参见第九章,使用卷积神经网络(CNN)进行抽象图像分类),传送带上的间隙大多数时候是负的,负伽马 = n 。
。
以下画面显示第一条生产线已完成,但第二和第三条生产线尚未完成:

图 11.3:食品传送带处理框架
相反,当传送带上几乎没有间隙时,负载被视为正的,正伽马 = p 。
。
以下画面显示每条生产线的产品数量是可接受的:

图 11.4:食品传送带处理框架
如前面图像所示,无论传送带上的产品是什么,间隙始终是一个间隙,都是空的空间。我们现在将应用我们的模型来处理其他间隙,不论对象是什么。在这种情况下,我们将检测服装传送带上的间隙。
服装传送带处理 – 未确定的间隙
在服装传送带的处理中,间隙通常是未确定的。这本身构成了一个主要的优化问题。当然,如果传送带为空或已饱和,方差将引起人工操作员的注意。然而,大多数时候,优化能够解决这个问题。
以下画面展示了相对较为满载的服装包生产流,服装需要在生产线上进一步组装(通过缝制)。

图 11.5:满载的生产流
以下画面清楚地显示了一个间隙,意味着将送到缝制站的数量不会很高:

图 11.6:生产流(间隙)
为了优化这个问题,需要做几个观察:
- 
传送带的实时问题排除了高级规划和调度。 
- 
这个问题需要实时自动化的规划和调度。 
- 
自动化规划和调度解决方案将必须同时进行实时规划和调度。 
- 
它将考虑规划约束(如以下章节所解释)来预测输出。 
- 
它将考虑调度约束,以优化缝制部分。 
亚马逊等公司已经慢慢但坚定地将许多规划视野问题(更长时间的)缩短到更短的调度视野,将供应链管理(SCM)的极限推得越来越远。
间隙抽象概念的开始
显示的间隙具有负面或正面属性,具体取决于上下文。CRLMM 模型现在需要学习所有前面提到的间隙的元概念抽象表示。这些间隙都是某种类型的流动间隙。某些东西正在从一个点移动到另一个点,且是以小包的形式进行的。因此,这些包的大小通常不同,这导致了间隙的产生。
这些概念可以应用于牛群、赛马、团队运动进攻(如足球、橄榄球、篮球、手球等各类领域)、奥运比赛、马拉松、传送带等诸多场景。
当流中的包接近时,个体的心理图像浮现出来。每个人都有一个定制版本。下图展示了一个无间隙概念的泛化表示:

图 11.7:一个无间隙概念的泛化表示
然后,包中有领导者和跟随者。接着,抽象表示也随之出现。下图展示了一个概念间隙的泛化表示:

图 11.8:一个间隙概念的泛化表示
人类对于他们观察的每个事物并没有流动检测间隙的功能。人类的大脑包含了物理记忆或其他数据集,但更重要的是,他们还拥有抽象数据集。
我们每一个数十亿的思维类人双足动物都拥有极其高效的抽象数据集。前面展示的元概念意味着通过推理,人类拥有一个中心元概念,并通过经验将符合它的记忆数据集融入其中。
一个元模型使用这些数据集。dataset目录中的数据集包含了一个 CRLMM 系统的起始部分。程序将学习什么是流间隙,然后通过分析上下文将其应用于它所看到的事物。
这个数据集的目标是导向一个 CRLMM,正如以下章节所解释的那样:
- 
抽象学习到的元概念应用于一个情境;在此情况下是一个框架。 
- 
CRLMM 随后确定这是一个间隙情况还是非间隙情况。 
- 
然后,CRLMM 会做出决策,使用基于决策权重导向激活函数的思维优化器。这意味着它不仅仅是一个数学上的squash。它在权衡决策过程中的利弊。 
在本节中,我们的 CRLMM 已经学会了识别服装传送带上的间隙。如果我们要实现这一点,我们需要将项目中的传送带的多个网页框架添加到我们的数据集中进行训练。现在,让我们继续使用这个例子并运行预测程序来分类间隙。
运行预测程序
训练使用了同样的CNN_STRATEGY_MODEL.py程序,该程序在第九章,基于卷积神经网络(CNNs)的抽象图像分类中有描述,旨在为后续章节提供通用模型。
一旦上一节的数据集安装完成,模型即可在不同领域进行预测,无需进一步训练。
相同的CNN_CONCEPT_STRATEGY.py函数在第十章,概念表示学习中已进行了实现。
只修改了数据集的路径,以及需要显示的预测信息:
#II. Convolutional Neural Network (CNN)
#loads,traffic,food processing
A=['dataset_O/','dataset_traffic/','dataset/']
MS1=['loaded','jammed','productive']
MS2=['unloaded','change','gap']
display=1     #display images
scenario=2    #reference to A,MS1,MS2
directory=A[scenario] #transfer learning parameter (choice of images)
CRLMN=1       # concept learning
print("Classifier frame directory",directory) 
CRLMM 现在已经学会了表示现实生活中的记忆和与之相关的推理,在一个元概念中。我们的 CRLMM 准备好组装成 RL-DL-CRLMM 的三个组成部分之一,正如我们将在下一节中看到的那样。
构建 RL-DL-CRLMM
RL-DL-CRLMM 程序的完整代码是 RL_DL.py。它是建立在前几章和本章前几节的知识与程序基础上的。
RL-DL-CRLMM 包含三个组件:
- 
一个 CRLMM 卷积网络,将分析每一帧它从位于切割部分传送带上方的网络摄像头接收到的画面,这些画面包含着服装包的图像。 
- 
一个使用修改版 Z(X) 的优化器,实时规划装配站的加载方式。 
- 
一个 MDP,将接收优化器函数的输入,并调度装配站的工作。它还会产生修改过的 Z(X) 更新值,用于下一帧中每个装配站的权重。 
在物理世界中,传送带传输服装包,每 n 秒拍摄一张图片(帧),并且 RL-DL-CRLMM 运行。RL-DL-CRLMM 的输出将指令发送到传送带,并指导服装包进入优化后的装配站负载,如前所述。
由于 RL_DL.py 描述了一个连续的 RL-DL-CRLMM 过程,程序没有明确的开始或结束。各个组件是独立的,由输入触发,并通过输出触发其他组件。
因此,组件将按照处理顺序进行描述,而不是按代码内联顺序。这是因为通过 def + function() 定义的函数先于它们的调用。代码行号将被插入到代码行后的注释中,格式如下:# [Line 38]。
一个循环过程
一旦系统的三个主要组件(CNN、MDP、优化器)就位,这个 RL-DL-CRLMM 的循环特性就形成了一个类似流动的系统,永远没有开始也没有结束。
为了定义一个循环过程,我们以一个日常例子为例。顾客 C 去超市购买商品。该商品之前存储在我们命名为 B 的仓库中。一个名为 A 的工厂生产了这个商品。如果你观察整个供应链的某一时刻,你会发现它没有明确的起点或终点:
- 
如果你是 A,你需要监控 C 的需求,以便将产品发送给 B。 
- 
如果你是 B,你需要监控从 A 传来的信息,以满足 C 的需求。 
- 
如果你是 C,你正在为 A 创造需求,要求其向 B 交付产品。 
在现实生活中的供应链中,没有开始也没有结束。同样适用于自动化生产现场中这一几乎没有记忆的系统中的功能流。传送带的网络摄像头提供了一系列帧,迫使系统进入类似流动的循环行为。
实现一个 CNN-CRLMM 来检测间隙并进行优化
CNN-CRLMM 函数在 运行预测程序 部分和 第十章、概念表示学习 中有所描述。预测函数是后续 MDP 输出分析的一部分。CRLMM 函数按如下代码调用:
def CRLMM(Q,lr,e):    # [Line 180] 
该函数的第一部分压缩了下一节中描述的 W 向量。第二部分分析输入帧。
由于此时系统未连接任何网络摄像头(这必须在项目实施过程中完成),因此做出了随机选择一帧图像的决定。以下随机代码模拟了现实生产中随机发生的情况:
 status=random.randint(0,1) 
在现实情况中,随机数量的物品会通过传送带。当状态被确定后,CNN 模拟从直接位于传送带上的网络摄像头获取的视频流中添加一帧冻结图像。它运行前面描述的身份(图像)函数,并返回优化器的 gap 或 no gap 场景(参见优化器部分)。以下代码描述了一个缺口识别过程:
 if(status==0):
        #Add frame from video stream (connect to webcam)
        s=identify(directory+'classify/img1.jpg',e)
    if(status==1):
        #Add frame from video stream (connect to webcam)
        s=identify(directory+'classify/img2.jpg',e)
    s1=int(s[0])
    if (int(s1)==0):
        print('Classified in class A')
        print(MS1[scenario])
        print('Seeking...')
    if (int(s1)==1):
        print('Classified in class B')
        print(MS2[scenario])
    return s1 
一旦检测到 status,无论切割系统的负载输出是高还是低,都必须做出决策。这将通过 MDP 来完成。
Q-learning – MDP
通过在此 CNN-CRLMM 程序中添加 MDP Q-learning 决策功能(见 第一章,通过强化学习入门下一代人工智能),我们现在进入了认知 RL-DL 程序的世界。
在这个实时系统中,没有开始,没有结束,也没有超出几帧的真实记忆。
mdp01.py MDP 程序已经并入 RL_DL.py。因此,本章仅描述所做的更改。
MDP 参数紧跟在导入包之后。图中的每个顶点都有其字母和位置,如下代码片段所示:
L=['A','B','C','D','E','F']    # [Line 37] 
当程序运行时,以下图形将显示当前帧的红色(目标顶点)。接下来由 MDP 做出选择,具体描述如下:

图 11.9:输出(目标顶点)
注意,这是一个无向图,图中有顶点(彩色点)但没有边(线)方向。MDP 将为此模型中的每一帧提供方向。
在该模型中,每个顶点代表一个组装站。每个组装站都有高负载或低负载。由于产品不断进出并进行生产,工作负载很少保持稳定。
MDP 输入和输出
此模型中的 MDP 过程使用奖励矩阵作为输入,并生成一个权重向量。
输入是一个中立的奖励矩阵
MDP 奖励矩阵被设置为 0,除非表示可以物理访问的图形边缘的值,这些设置为 1,是一个小的中立值。
如此,MDP 无法提供令人满意的结果,超出再现这个无向图的结构。奖励矩阵现在已经初始化并复制,如以下代码所示,从第 41 行开始;在第 43 行,R(奖励矩阵)被构建,而在Ri中,R的副本被创建:
# R is The Reward Matrix for each state built on the physical graph    [Line 41]
# Ri is a memory of this initial state: no rewards and undirected
R = ql.matrix([[0,0,0,0,1,0],
               [0,0,0,1,0,1],
               [0,0,0,1,0,0],
               [0,1,1,0,1,0],
               [1,0,0,1,0,0],
               [0,1,0,0,0,0]])
Ri = ql.matrix([[0,0,0,0,1,0],
                [0,0,0,1,0,1],
                [0,0,0,1,0,0],
                [0,1,1,0,1,0],
                [1,0,0,1,0,0],
                [0,1,0,0,0,0]]) 
Ri是初始状态零奖励矩阵的副本。每当新的一帧开始时,R会被重置为Ri。MDP 以无记忆、无向图和无监督的方法训练每一帧的装配位置计划。
Q是学习矩阵,其中奖励将被学习/存储,如第 58 行代码所示:
Q = ql.matrix(ql.zeros([6,6]))    # [Line 58] 
MDP 函数的标准输出
装配站的负载不是生产的精确数量。它们是权重,在这个连续过程中不断更新,后续章节将进一步解释这一点。
在程序的初始状态下,顶点的初始权重在以下代码行(第 40 行)中被设置为0:
W=[0,0,0,0,0,0]    # [Line 40] 
权重向量(以数组表示)包含每个装配站位置或顶点的一个值。
初始状态不是一个真正的开始。它就像视频中的暂停按钮。初始状态可以来源于假期(没有生产)、维修日(没有生产)或缺少输入订单(没有生产)。初始状态只是一个权重等于0的情况,因为传送带或装配站上什么也没有。
权重向量是优化器的第一部分(见下文章节)。MDP 在优化无向图后生成一个输出矩阵。优化器将会提供一个目标。
程序包含与第一章、《通过强化学习开始使用下一代人工智能》中相同的源代码,贝尔曼方程从第 1166 行开始。MDP 生成其结果,如下输出所示:
[[ 0\. 0\. 0\. 0\. 105.352 0\. ]
[ 0\. 0\. 0\. 130.44 0\. 201\. ]
[ 0\. 0\. 0\. 130.44 0\. 0\. ]
[ 0\. 161.8 105.352 0\. 105.352 0\. ]
[ 85.2816 0\. 0\. 130.44 0\. 0\. ]
[ 0\. 0\. 0\. 0\. 0\. 250\. ]]
Normed Q :
[[ 0\. 0\. 0\. 0\. 42.1408 0\. ]
[ 0\. 0\. 0\. 52.176 0\. 80.4 ]
[ 0\. 0\. 0\. 52.176 0\. 0\. ]
[ 0\. 64.72 42.1408 0\. 42.1408 0\. ]
[ 34.11264 0\. 0\. 52.176 0\. 0\. ]
[ 0\. 0\. 0\. 0\. 0\. 100\. ]] 
请记住,整个 DQN-CRLMM 不仅基于无向无记忆 MDP 函数,而且没有真正的开始和结束,因为它是一个连续且几乎无记忆的过程。
MDP 输出矩阵的图形解释
每次运行后,MDP 矩阵还会生成路径值的图形解释,即从一个顶点到另一个顶点(字母到字母)的路径,并显示在以下输出中:
State of frame : 3 D
0 A E 161.8
1 B D 201.0
2 C D 201.0
3 D D 250.0
4 E A 130.44
4 E D 201.0
5 F B 161.8 
通过这种方式,如果从最高到最低的边(线条,进而是字母之间的值)中取值,它就能直观地展示 MDP 函数是如何通过图计算路径的。
RL是字母向量。每一帧后它为空。它将通过查找每条边的值来填充。它将包含由边(由值表示的线)连接的顶点(节点和点)的字母。
RN是边的值。以下代码展示了如何实现RL和RN并更新权重向量(W)中位置的权重:
 #Graph structure    [Line 187]
    RL=['','','','','','']
    RN=[0,0,0,0,0,0]
    print("State of frame :",lr,L[lr])
    for i in range(6):
        maxw=0
        for j in range(6):
            W[j]+=logistic_sigmoid(Q[i,j])
            if(Q[i,j]>maxw):
                RL[i]=L[j]
                RN[i]=Q[i,j]
                maxw=Q[i,j]
                print(i,L[i],RL[i],RN[i]) 
上述代码中的逻辑函数在 RL 和 RN 被更新时也在不断更新。
优化器
我为服装行业的面料优化编写了多个优化器。在这个例子中,优化器将用于调节生产流程。
术语“优化器”并不是前几章中使用的 CNN rmsprop 优化器,它在以下代码中表示:
loaded_model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])    # [Line 92] 
术语“优化器”指的是一种优化该制造站点生产的功能。它不是用于训练 CNN 的优化器。例如,这个优化器既是一个激活函数,又是一个调节器,从零开始构建,目的是优化生产。这表明,有时你需要发明所需的优化器,以为客户或公司生成一个有利可图的解决方案。
优化器作为调节器
这个实时生产的 RL-DL-CRLMM 概念应用于 P3,目的是优化 Z,使其在组装站的负载分配上达到最佳,正如之前所解释的那样。这意味着通过以下方程尽可能减少 Z:

为了实现这个优化目标,Z 需要被拆解并应用到代码的战略部分。
实现 Z – 压缩 MDP 结果矩阵
MDP 函数的输出提供了以下 Q 矩阵:
Q :
[[ 0\. 0\. 0\. 0\. 321.8 0\. ]
 [ 0\. 0\. 0\. 401\. 0\. 258.44]
 [ 0\. 0\. 0\. 401\. 0\. 0\. ]
 [ 0\. 0\. 0\. 500\. 0\. 0\. ]
 [ 258.44 0\. 0\. 401\. 0\. 0\. ]
 [ 0\. 321.8 0\. 0\. 0\. 0\. ]] 
每一行代表图中的一个顶点:A、B、C、D、E 和 F。每个获得的值需要在以下 z(x) 函数中进行压缩:

以下代码中的第一步是通过 logistic_sigmoid 函数对 MDP 过程为每一行(顶点)x 提供的权重进行压缩:
#Logistic Sigmoid function to squash the weights    [Line 118]
def logistic_sigmoid(w):
    return 1 / (1 + math.exp(-w)) 
该函数通过将 MDP Q 输出矩阵转换为每一行每一列的权重向量来调用,如以下代码所示:
 for i in range(6):    # [Line 191]
        maxw=0
        for j in range(6):
            W[j]+=logistic_sigmoid(Q[i,j]) 
在这一点上,MDP 的每个值都失去了任何现实生活中的价值。它只是一个权重,就像其他网络一样。不同之处在于,整个系统是受控制的。在实际项目中,通过报告跟踪计算是必要的,以便进行维护。即便是自动化系统,也需要质量控制。
现在,MDP 矩阵已被压平为一个权重矩阵,如下输出所示:
Vertex Weights [3.5, 3.5, 3.0, 5.0, 3.5, 3.5] 
每个顶点(图中的字母)现在都有一个权重。
实现 Z – 压缩顶点权重向量
压缩后的 W(顶点权重)在每一帧分析后增长,并且每次运行 MDP 时,W[j]+ 会持续应用,而 W 永远不会被设为零。
主要原因:
- 
一旦启动,RL-DL-CRLMM 就是一个持续的过程,只要输送带在运行,就没有开始和结束。 
- 
输送带正在将组装(主要是缝纫)工作传送到组装站,这些工作需要一些时间(t),表示为 t[x],其中 t 是时间,x 是任务,在 Z 方程和程序中的 W 向量中体现。 
- 
因此,工作在每个顶点(A 到 F)上堆积起来,这些顶点代表一个组装站。 
这就是为什么在Z方程中实现了 变量,如本章早期的初始方程所示,具体如下:
变量,如本章早期的初始方程所示,具体如下:

 实现这一点有两个原因:
 实现这一点有两个原因:
- 
缝纫或组装站将它们完成的工作发送到生产线上的下一道工序,例如包装。因此,每隔m分钟,它们的工作负荷就会减少,负载特征权重也会下降。 
- 
生产经理们不断地在组装线上的学习曲线中工作。当新产品到达时,团队需要一些时间来适应。它们的产出比平时稍慢。然而,经过良好训练的团队会定期缩短学习期。 
 将两个概念结合在一个变量中。这可能对一些项目来说足够了。如果不够,需添加更多的工作和变量。
 将两个概念结合在一个变量中。这可能对一些项目来说足够了。如果不够,需添加更多的工作和变量。
在这个模型中, 是通过以下方式激活的:
 是通过以下方式激活的:
- 
oif表示W向量![]() 更新的频率。在本例中, 更新的频率。在本例中,oif被设置为10。这意味着每 10 帧,oir将被应用。
- 
oir表示前面描述的两个原因的输出率。该变量将按给定的百分比压缩W向量。在本例中,oir=0.2。这意味着只有 20%的权重将被保留,其余的已经完成。
以下代码展示了如何实现oif和oir:
# input_output_frequency : output every n frames/ retained memory    [Line 315]
oif=10
#input_output_rate p% (memory retained)
oir=0.2
fc=0 #frequency counter : memory output
for e in range(episodes):
    print("episode:frame #",e)
    fc=fc+1
    #memory management : lambda output
    if(fc>=10):
        for fci in range(6):
            W[fci]=W[fci]*oir
            fc=0
            print("OUTPUT OPERATION - MEMORY UPDATED FOR ",L[fci],
                  " ",oir,"% retained") 
W向量再次被压缩,如下输出所示:
OUTPUT OPERATION - MEMORY UPDATED FOR A 0.2 % retained
OUTPUT OPERATION - MEMORY UPDATED FOR B 0.2 % retained
OUTPUT OPERATION - MEMORY UPDATED FOR C 0.2 % retained
OUTPUT OPERATION - MEMORY UPDATED FOR D 0.2 % retained
OUTPUT OPERATION - MEMORY UPDATED FOR E 0.2 % retained
OUTPUT OPERATION - MEMORY UPDATED FOR F 0.2 % retained 
优化器提供了每个缝纫站状态的更新信息。每个缝纫站都是 MDP 函数的一个位置。接下来,我们将看到 MDP 函数如何使用优化器提供的信息。
找到 MDP 函数的主要目标
W,权重向量,在每一帧后会更新,带有短期记忆,记住n帧的信息。这意味着每隔n帧,它的记忆就会清除无用的信息。
优化器的目标是为 MDP 函数提供一个目标。在第一次循环中,由于没有任何信息,优化器选择一个随机状态,如以下代码片段所示:
 #first episode is random
    if(e==0):
        lr=random.randint(0,5) 
这意味着在 MDP 图上将选择一个随机的组装站,代表六个组装缝纫站。一旦该周期完成,系统将进入一个循环实时周期(参见下一节)。
第二个周期有W向量可以依赖。
这会运行crlmm(前面描述过)CNN-CRLMM 网络,以确定框架是否具有间隙或无间隙特征,如以下代码所示:
 crlmm=CRLMM(Q,lr,e)    # [Line 388] 
优化器将使用W来:
- 
如果框架上的 CNN 输出结果为 no gap(概率为零),请选择具有稍微最小权重的顶点(缝纫站)。由于没有间隙,这意味着有许多部分需要缝合。因此,将工作交给负载较低的组装站比交给其他站点要好得多。
- 
如果 CNN 对画面输出的结果产生 gap(概率为 1),请选择某种程度上权重最高的顶点(缝纫站)。因为有 gap,这意味着没有太多的物品需要缝制。因此,将工作交给一个已经有较高工作量的组装站要好得多。这将平衡负载,并优化所有站点的负载分配。
- 
引入选择,在每种情况下为 MDP 功能找到一个目标组装站。它将在一种情况下寻找权重最高的站点(顶点、字母、图中的点),在另一种情况下寻找权重最低的站点。 
- 
添加之前提到的某种程度上的概念。系统必须保持相对自由,否则它将不断选择相同的最佳缝纫站,剥夺其他站点的工作。因此,每种可能性( gap或no gap)都限制为在六个位置中随机选择三个位置,针对每个权重等级(高或低)。
以下代码片段展示的优化功能,在现实工业生产线上可能非常有利可图:
 if(e>0):
        lr=0
        minw=10000000
        maxw=-1
        #no G => Finding the largest gap (most loaded resource or a distance)
        if(crlmm==0):
            for wi in range(3):
                op=random.randint(0,5)
                if(W[op]<minw):
                    lr=op;minw=W[op]
        #G => Finding the smallest gap (a least loaded resource or a distance)
        if(crlmm==1):
            for wi in range(3):
                op=random.randint(0,5)
                if(W[op]>maxw):
                    lr=op;maxw=W[op] 
lr 是为 MDP 强化学习功能选择的主要位置,如下列代码所示:
 print("LR TARGET STATE MDP number and letter:",lr,L[lr]) 
强化学习每次都必须运行,因为它面对的是传送带在自动化服装系统中不断变化的新画面。
现在,MDP 奖励矩阵已重置为其初始状态,如程序中的这些行所实现:
 #initial reward matrix set again
    for ei in range(6):
        for ej in range(6):
            Q[ei,ej]=0
            if(ei !=lr):
                R[ei,ej]=Ri[ei,ej]
            if(ei ==lr):
                R[ei,ej]=0 #to target, not from 
目标位置被初始化为一个适合程序的 gap 或 no-gap 哲学的值。如果没有 gap,值较高,最终缝纫站的负载也较大。如果有 gap,值较低,那么该站点的负载也会较低,如以下代码所示:
 #no G
    rew=100
    #G
    if(crlmm==1):
        rew=50
    R[lr,lr]=rew
    print("Initial Reward matrix with vertex locations:",R) 
我们刚刚探讨了 MDP 过程。然而,我们正在查看的整体程序是一个 24/7 不间断运行的循环过程。在任何给定时刻,我们的 AI 程序的所有组件都会同时运行。让我们看看是如何实现的。
循环模型——一个没有开始和结束的流动系统
我们已经成功地将生产的线性流(传送带、优化器和缝纫站)转化为循环过程。
由于 RL-DL-CRLMM 模型不断运行,因此它可以同时在以下所有节点运行:
- 
A = 使用网络摄像头和 CNN-CRLMM 捕捉切割部分的输出画面 
- 
B = 使用 CRLMM 分析负载(每个缝纫部分的直方图) 
- 
C = 使用 MDP 优化缝纫站 
ABC 是一个流。但由于每个过程都在不停地运行,我们可以同时看到以下所有流程:A、B、C 或 B、C、A 或 C、A、B。
以下图表表示了循环过程:

图 11.10:循环 RL-DL-CRLMM
该图描述了一个自动化过程。然而,让我们回到一步,假设我们在一个仍由人工做决策的工厂中。这个过程是循环的,意味着它不会停止或开始。它 24 小时全天候运行。我们假设车间经理是一个优化器,用蓝色条形图表示。车间经理会观察各个缝纫站,查看哪些站点有很多工作要做,哪些站点的工作量较少。然后,车间经理会观察输送带(带有包裹图像的网框),这个输送带将切割好的布料包送到缝纫站进行缝制。比如,车间经理会选择输送带上有空隙的几个包裹,分配给工作负载较少的缝纫站。一旦做出选择,车间经理将根据计算图(MDP)手动指引包裹到正确的缝纫站。
让我们更详细地探讨这些步骤。
Step X:当以下框架到达时,CRL-CNN 被激活:

图 11.11:CRL-CNN 被激活
该解决方案调用了CRLMM函数,如以下代码所示:
 crlmm=CRLMM(Q,lr,e)    # [Line 388]
    print("GAP =0 or GAP =1 status: ",crlmm) 
以下输出显示了图像的状态:gap、no gap:
image dataset/classify/img1.jpg predict_probability: [[ 0.]] prediction: [[ 0.]]
Classified in class A
Productive
Seeking...
GAP =0 or GAP =1 status: 0 
以下是各缝纫站(顶点 A 到 F)所考虑的权重:
 MDP_GRAPH(lr,e)    # [Line 390]
    print("Vertex Weights",W) 
程序以文本形式显示它们:
Vertex Weights [9.4, 11.100000000000001, 10.2, 12.0, 11.7, 10.0] 
程序还显示了各缝纫站权重的以下条形图:

图 11.12:各缝纫站权重的条形图
STEP X+1 优化器分析权重以做出决策:将少量工作分配给工作量大的缝纫站,将大量工作分配给工作量较少的缝纫站。
通过这样做,优化器确保每个缝纫站的工作负载是最优的。如果某个缝纫站的工作积压很多,那么将大量的工作分配给工作量较少的缝纫站是合理的。这样,所有缝纫站都将以最大容量运转。
 (gamma)现在已经达到一个点,它理解“空隙”是两个状态之间的比较和概念距离的推断:
(gamma)现在已经达到一个点,它理解“空隙”是两个状态之间的比较和概念距离的推断:
- 
过载:过多 
- 
欠载:不足 
 现在包含了两个抽象概念:
 现在包含了两个抽象概念:
- 
从不足到过多 
- 
不足到缺乏 
循环过程的目标是保持条形图的大致相同高度——不是精确高度,但也不是 A 没有工作要做,E 却过载的情况。
步骤 X+2:本章中描述的 MDP 接收指令来优化给定的缝纫工作站,并将工作分配给周围的工作站。这通常是一个生产约束:一个工作站缝制 T 恤的袖子。例如,附近的工作站缝制 T 恤的口袋。MDP 从目标位置开始分配工作。在这种情况下,目标位置是 A-E-D 区域中的一个缝纫工作站(运行 Python 程序时,该区域会以颜色显示),如下图所示:

图 11.13:MDP 分配工作
MDP 将结果直接发送到传送带,传送带自动遵循传送给它的路径指令。
然后,MDP 更新权重,清空奖励矩阵,并等待新的奖励矩阵。系统返回到步骤 X。
正如你可能注意到的,整个过程完全没有人工操作员参与。
摘要
将人工智能应用于亚马逊的实时销售、生产和交付,将项目推进到现实。
学习机器学习和深度学习,使用 MNIST、CIFAR 等现成数据集以及现成程序,是掌握人工智能的前提。学习数学是必须的。
构建几个可以做各种理论事情的程序是不可避免的。然而,在企业压力下管理一个实际项目将使 AI 专家提升到另一个层次。AI 专家必须将 AI 理论付诸实践。企业规格的约束使得机器学习项目变得令人兴奋。在这些项目中,专家们学习到关于 AI 解决方案如何运作以及如何改进的宝贵信息。
本章介绍了带有优化器的 RL-DL-CRLMM 模型。我们学习了市场如何从提前规划制造到实时规划具有挑战性的经典流程演变。我们看到消费者希望尽快收到购买的产品。如果该产品没有现货以满足需求,它必须几乎实时生产并交付给客户。为了自动化这个过程,我们构建了一个 Python 程序,能够扫描一个服装传送带,该传送带利用 CNN 检测裁剪过程中的空隙,使用优化函数选择最佳的缝纫工作站,然后用 MDP 构建图形来表示优化后的路径。
下一章探讨了这个解决方案的一个应用,使用 SVM 在物联网背景下应用于自动驾驶汽车情境、群体 AI 和基础 AGI。
问题
- 
CNN 可以训练来理解一个抽象概念吗?(是 | 否) 
- 
避免使用概念,仅使用现实生活中的图像更好么?(是 | 否) 
- 
规划和排程是同一回事吗?(是 | 否) 
- 
亚马逊的制造专利是一次革命吗?(是 | 否) 
- 
学习仓库如何运作没有用处。(是 | 否) 
- 
在线营销不需要人工智能。(是 | 否) 
进一步阅读
- 关于亚马逊的服装制造创新和服装市场的更多信息可以在这里找到:纽约时报,亚马逊 Prime Wardrobe
第十二章:人工智能与物联网(IoT)
有些人说,物联网(IoT)将最终成为第四次工业革命。让我们等几年,直到一切尘埃落定,再让历史学家来判断我们经历了怎样的革命。
无论如何,互联物体在过去二十年里至少已经改变了我们的生活。考虑到我们近年来所见所闻,我们可以肯定地说,物联网(IoT)已经成为一种颠覆性技术。
人工智能的刚刚开始了它在人类智慧中的漫长旅程。新的、令人难以置信的创新正等待着我们。理解前沿的机器学习和深度学习理论只是你冒险的开始。认真对待你所看到的一切,并看它如何融入到你的项目中。
你的思想必须保持开放,接受那些尚未到来的创新。例如,概念表示学习(参见前几章)将人类概念的力量添加到神经网络中。
本章将上一章的技术应用于自动驾驶汽车的例子。上一章使用了网络摄像头和程序,并向输送带发送指令。这属于物联网的范畴。现在,我们将为程序添加一个支持向量机(SVM),并将其带到城市街头看看会发生什么。
本章分为三个主要部分:公共服务项目、模型配置和模型运行。
本章将涵盖以下主题:
- 
自动驾驶解决方案 
- 
为旅行规划器引入安全路线参数 
- 
将 CNN(卷积神经网络)应用于停车场 
- 
将 SVM 应用于旅行规划中的安全性 
- 
教授一个 MDP(马尔可夫决策过程)来找到最安全的路线(不一定是最短的路线) 
让我们从概述我们将要进行的项目的问题和目标开始。
公共服务项目
这个例子中的总体项目是实现一个自动驾驶的从家庭到无家可归者庇护所的配送服务:
- 
家庭中有衣物和食物,希望将其捐赠给需要的人。 
- 
自动驾驶汽车可以远程启动,前往家庭并将货物运送到庇护所。 
- 
自动驾驶汽车不需要停车基站。它可以随时停放,随时出发,并在服务站进行自动电动充电加油。 
在本章中,我们将专注于自动驾驶汽车,当它完成配送并寻找有空位的停车场时。我们将需要这些信息来做出决策。
一些物联网项目计划在每个停车位上安装传感器,并将信息传送到控制中心。市议会觉得这样做太贵了。相反,市议会决定采用一种更具成本效益的解决方案。该项目的网格中所有可能的停车场将安装网络摄像头。这个智能网格用于将物品从家庭运送到庇护所。
我们将首先通过设置 RL-DL-CRLMM 模型来解决这个问题。
设置 RL-DL-CRLMM 模型
本节描述了如何为这个项目设置上一章的模型,并添加一些功能。
在第十一章,《结合强化学习与深度学习》中,RL-DL-CRLMM 模型分析了实时传送带上待缝制布料的网络摄像头图像。目标是确定这些布片中是否存在空隙(没有太多布片待缝制)或没有空隙(有很多布片待缝制)。然后模型选择了最佳缝纫站。如果缝纫站有大量工作要做,最好优化为少量布片进行缝制。缝纫站工作量少时,最好优化为大量布片进行缝制。通过这种方式,RL-DL-CRLMM 优化了每个缝纫站的工作负载,如下图所示:

图 12.1:服装生产流程
这将导致以下循环优化模型:

图 12.2:循环 RL-DL-CRLMM
我们在第十一章,《结合强化学习与深度学习》中探讨的 RL-DL-CRLMM 模型包含以下组件:
- 
一个 CRL-CNN 用来查看图像中是否有空隙。在本章中,我们将使用相同的模型来看是否在代表可用停车位的停车场中存在空隙。 
- 
优化器将依赖于 SVM,将安全性概念添加到行程选择中。然后它将使用优化规则做出决策,如第十一章,结合强化学习与深度学习中所述。 
- 
如第一章所述的行程的 MDP,《通过强化学习开启下一代人工智能之旅》。 
本章的 RL-DL-CRLMM 模型,专注于寻找一个有可用停车位的停车场并前往那里,模型将变为:

图 12.3:循环 RL-DL-CRLMM
本模型中的 CRL-CNN 寻找的是停车场中的空位,而不是传送带上的空隙。
RL-DL-CRLMM 模型包含一个卷积神经网络(CNN)和一个马尔可夫决策过程(MDP),通过一个优化器将它们连接起来。优化器包含一个 SVM(安全性评估)和一组规则。
该系统现在将被称为 CRLMM。
应用 CRLMM 模型
在第九章,《使用卷积神经网络(CNN)进行抽象图像分类》中,CRLMM 程序CNN_STRATEGY_MODEL.py经过训练,用来实时识别食品加工厂传送带上的切割布片的 (gamma 概念)输出。上一章的结尾把
(gamma 概念)输出。上一章的结尾把 提升到了更高的抽象层次。
提升到了更高的抽象层次。
只要 (gamma)属于
(gamma)属于 数据集中的一个未确定状态,它的泛化就包括了模棱两可但相似的概念。直到本章为止,这些就是
数据集中的一个未确定状态,它的泛化就包括了模棱两可但相似的概念。直到本章为止,这些就是 (大写 gamma)已经学习到的概念(概念表示学习)。
(大写 gamma)已经学习到的概念(概念表示学习)。
 = {间隙,非间隙,负载,无负载,负载不足,负载足够,负载过多,车道上的停车空间,传送带上高负载产品与缺失产品之间的距离,缝纫站上的重物… n}
 = {间隙,非间隙,负载,无负载,负载不足,负载足够,负载过多,车道上的停车空间,传送带上高负载产品与缺失产品之间的距离,缝纫站上的重物… n}
本章的下一步是使用前几章中构建的 CRLMM 来识别停车场中的停车位,并向自动驾驶车辆发送信号:
- 
![]() 现在将把间隙视为空间。 现在将把间隙视为空间。
- 
![]() 现在将把空间视为两个物体之间的距离(间隙)。 现在将把空间视为两个物体之间的距离(间隙)。
- 
![]() 将需要一个上下文来判断这两个物体之间的空间是正距离还是负距离。 将需要一个上下文来判断这两个物体之间的空间是正距离还是负距离。
让我们来看看我们将用来实现目标的数据集。
数据集
在第九章,卷积神经网络(CNNs)进行抽象图像分类到本章使用的数据集是示例数据集。在实际项目中,获取来自摄像头的实时帧需要一些工作。可能会有照明限制、前提条件等。然而,基本理念保持不变。
如前几章所述,本章的dataset目录在 GitHub 上包含以下内容:
- 
训练集 
- 
测试集 
- 
由 CNN_CONCEPT_STRATEGY.py训练的模型
- 
CNN_CONCEPT_STRATEGY.py使用的classify目录
如前几章所述,从配置良好的摄像头流出的完整帧流可能需要几周甚至几个月才能准备好。它们本身就是项目。
项目首先会决定使用摄像头或可以将图像发送到嵌入在 RL-DL-CRLMM 程序中的 CNN 的 IP 摄像头。CNN 将对视频流发送的每张图像进行分类,判断它是否包含间隙或可用停车空间。
摄像头通常连接到计算机,然后计算机将信息发送到远程服务器。IP 摄像头可以直接将信息发送到远程机器。这两种解决方案都是连接的物联网设备。IP 摄像头可能更贵。为了证明解决方案是可行的,实施团队可能会先从摄像头开始。一旦项目被接受,IP 摄像头可能从长远来看会更好。在本章中,我们将把摄像头当作是一个起初预算有限的研究项目。因此,我们假设图像来自摄像头。
在这个例子中, 已演变为空间(车与车之间的间隙检测),用于寻找停车位。
已演变为空间(车与车之间的间隙检测),用于寻找停车位。
以下是没有!-空间的模拟冻结帧,摄像头位于一栋建筑物上,指向停车场:

图 12.4:模拟的冻结帧
我通过转换图像来模拟一些计算机视觉技术,这些技术本可以用于简化图像:

图 12.5:停车场几乎没有空隙(停车位不足)
以下帧表示屏幕右侧一个小但足够的停车位。这些示例中的图像是为了解释系统是如何构建的。我为这个例子创建了这张图片,以显示是否有可用的停车位!。再次说明,我在计算机视觉处理后模拟了一张图像,这很容易做到,但超出了本书的范围。它展示了停车场中几种可用停车位的更高级别表示:

图 12.6:停车场几乎没有空隙(停车位不足)
使用训练好的模型
该模型是通过使用与第九章《卷积神经网络(CNN)的抽象图像分类》相同的CNN_STRATEGY_MODEL.py程序训练的。
只需确保以下程序头部中的目录指向dataset/,这是情境 2:
A=['dataset_O/','dataset_traffic/','dataset/']
scenario=2 #reference to A
directory=A[scenario] #transfer learning parameter (choice of images)
print("directory",directory) 
模型存储在/dataset/model中。要测试模型,使用了前一章中改进的CNN_CONCEPT_STRATEGY.py。只需更改消息并将帧分类循环限制为2,如下所示的代码片段:
MS1='available'
MS2='space'
I=['1','2','3','4','5','6'] 
以下加载的图像在应用 CNN 模型之前已经调整过大小:

图 12.7:调整大小后的图像
对停车场进行分类
我们已经展示了模型的工作效果。然而,在接下来的章节中,我们将使用随机函数模拟发送的图像,而不是实际图像。
现在,CRLMM 已经训练好了,可以区分满的停车场和有空位的停车场。一旦找到有空位的停车场,SVM 会作为中间步骤接管,正如我们将在下一节看到的那样。
添加 SVM 功能
自动驾驶汽车已经将包裹送到了避难所。现在它必须找到一个停车场并停在那里。与许多其他系统不同,它没有一个基地,这节省了城市许多无用的行程成本。
动机——使用 SVM 提高安全性
支持向量系统为行程计算添加了一个新功能——安全性。
大多数系统,如 Google Maps,关注的是:
- 
最短行程 
- 
最快的行程 
- 
交通 
然而,自动驾驶汽车必须采取额外的预防措施。许多人在某些道路上感到不安全。无论如何,安全第一。一旦找到合适的停车场,SVM 必须避免交通。
目标是找到一条穿过交通的路径,即使距离较长。一个p参数允许距离有p%的偏差。例如,10%允许距离延长 10%,并且会提供安全通行,如下所示的 SVM 结果所示:

图 12.8:交通路径
需要注意的是,数据点不是实际坐标,而是一个更高维度中的表示,具体解释见下节。
支持向量机的定义
SVM 通过将数据转换为更高维度来对数据进行分类。然后,它会将数据分类为两类,例如。
在本节中,将使用 SVM 来区分有风险的驾驶位置和安全的驾驶位置:
代码中的示例是随机的(就像真实生活中的交通一样),但该模型可以进一步发展。
安全性是该模型的关键,因此每个驾驶位置(道路、交叉口)都具有与此目标相关的特征:
- 
该位置的事故数量 
- 
该位置的交通状况 
- 
在该位置的驾驶经验(近乎发生事故且没有问题) 
所有这些数据都可以输入到 SVM 程序中。该程序将转换数据,使其线性可分(参见第八章,通过前馈神经网络解决 XOR 问题)。
左侧的蓝点代表良好的位置,而右侧的棕色点代表有风险的位置。一个函数将读取另一个表格中的数据点的纬度和经度特征,并将其转换回 GPS 格式。
例如,左侧的蓝点可能是:
- 
位置 A 
- 
过去十年中的一次事故 
- 
一年内通过该点没有问题 
一个棕色点可能是:
- 
位置 D(距离 A 几街区) 
- 
十年内发生 74 起事故 
- 
一年内通过该点发生了 15 次问题 
因此,蓝点和棕色点与前面图表中的实际位置无关。它们是标签。它们的特征已按预期分开。
为了将数据发送到 GPS 导航系统,只需要找到初始数据集中的位置的 GPS 坐标即可。
例如,会选择位置 A,而不是位置 D。因此,程序会查看数据集并找到其 GPS 位置。
让我们给以下 SVM 图加上些文字说明:

图 12.10:SVM 图
- 
点划线之间的空间是边界。它有点像橄榄球或足球队之间的边界。当球员(数据点)排成队时,一个看不见的空间或边界将它们分开。 
- 
与这些边界接触的点是关键的,因为它们决定了边界最初的位置。正如橄榄球或足球运动员排成队形一样,SVM 会计算这一点(参见以下 Python 函数)。这些特殊的数据点被称为支持点。它们也被称为支持向量。 
- 
在边界中间的垂直线是决策线。 
- 
由于一条直线将这些点分开,因此数据集是线性可分的。这意味着可以在数据点之间画一条直线,并将它们分成不同的类别。在这种情况下,系统希望获取安全位置(蓝点)并避免不安全的位置(棕色点)。 
现在我们定义了什么是 SVM,接下来我们将在 Python 中实现它。
Python 函数
sklearn包提供了以下的svm函数:
from sklearn import svm
from sklearn.datasets import make_blobs 
make_blobs函数为本例生成各个方向上均匀的数据。因此,它是一个各向同性分布(iso = 相等,tropy = 方式)的随机数据。一个blob包含数据点。这些数据点代表特定区域内汽车的集中度,计算方式是根据它们的经纬度得出的。
scikit-learn 包含一个高斯因子用于生成函数。高斯核应用从均值开始的标准差。想象你在沙盒中玩耍,做了一个小土丘。然后,你用手将土堆切成两半。均值就是你切割沙堆的位置;标准差则通过两侧下坡的坡度来表示。
收集一个好的数据集可能需要几天,甚至几周的时间。但使用 scikit-learn,你可以通过一行代码完成,如下代码片段所示:
 #100 cars clusters(concentration of cars) represented   [Line 323]
    X, y = make_blobs(n_samples=100, centers=2, random_state=7) 
这个函数提供了许多参数。使用的参数如下:
- 
n_samples表示在集群之间分布的点的数量。在这个例子中,100已经代表了一个区域内汽车集中度的子集群。
- 
Centers是生成数据的中心数量。在本例中,2表示接近当前自动驾驶汽车位置和未来目的地的区域。
- 
random_state是随机数生成器的种子。这是随机数序列的起始点。因为我们认为是随机的,其实是伪随机的,所以它有一个确定性的基础。
在这个例子中,使用了线性核来拟合模型,如下代码所示:
 # the model is directly fitted. The goal is a global estimate    [Line 326]
    clf = svm.SVC(kernel='linear', C=1000)
    clf.fit(X, y) 
scikit-learn 的 SVM 包含一个惩罚参数,这就是svm.SVC中的C。还有许多其他选项,但关键的选项是核。线性核会产生线性分割,如前面的截图所示。
一个 RBF 核会产生不同的结果。结构看起来更具正则化。如以下截图所示,RBF 核作为一种高效的结构正则化函数:

图 12.11:正则化结构路径
请记住,SVM 可用于 MNIST 和 CIFAR 数据集上的图像识别。例如,人工智能提供了多种解决给定问题的方法。选择合适的工具取决于你灵活的试错方法。
绘图行指令从第 300 行开始。需要考虑的主要代码行是那个用于找到并使用决策线的函数(参见前面的定义),并在边界两侧分散数据点。这个通过使用以下decision_function来实现:
 Z = clf.decision_function(xy).reshape(XX.shape) 
结果将如之前所示显示。现在,SVM 已成为这个自动驾驶汽车(SDC)模型中 CRLMM 的一部分。我们准备好运行 CRLMM,以寻找自动驾驶汽车的可用停车位。
运行 CRLMM
自动驾驶汽车的任务是一个循环任务(没有开始,也没有结束),就像前一章中描述的 CRLMM 一样:
- 
如果它处于一个停车场,可以通过家或避难所来激活。 
- 
如果它在某个家中,它会前往避难所。 
- 
如果它处于一个避难所,可以去一个家或一个停车位。 
- 
如果需要充电,可以在充电空间(或者更可能是在停车空间)进行充电,这在一些城市已经实现。 
在某一时刻,自动驾驶汽车必须从一个特定的家出发,前往一个停车位。其行程的这一部分是以下章节的主题。
寻找停车位
CRL-MM-IoT_SVM.py使用了前一章中描述的精调版RL_DL.py。
一个无- (无伽玛,无间隙,无空位)结果是不可接受的。我们寻找的结果是带有间隙的图像。
(无伽玛,无间隙,无空位)结果是不可接受的。我们寻找的结果是带有间隙的图像。
如果crlmm函数(该函数将停车场图像分类为已满或可用空间)返回0,程序将检测到并显示一条消息。代码样本包含以下代码片段的行号:
 if(crlmm==0):    # [Line 392]
                full = load_img("FULL.JPG")
                plt.subplot(111)
                plt.imshow(full)
                plt.title('PARKING LOT STATUS : This parking lot is full.' + '\n' + 'Another webcam is consulted', fontname='Arial', fontsize=10)
                #plt.text(0.1,2, "The frame is the input of a trained CNN")
                plt.show()
                '''
                plt.show(block=False)
                time.sleep(5)
                plt.close()
                '''
                print("This parking lot is full, searching...") 
程序显示以下完整的标志,并在几秒钟后关闭:

图 12.12:停车场状态
程序必须找到一个停车位。因此,它将尝试搜索好的停车场,如以下代码片段所示:
 for search in range(1000):    # [Line 391]
            if(crlmm==0): 
一千次搜索看起来很多,但对于机器学习程序来说并不困难。
此外,在大城市寻找可用停车位可能非常痛苦。往往情况下,它不适用:可能没有足够的空闲停车位来确保你能够在到达目的地的时间内找到一个。
对于这个原型,最佳搜索次数限制为2。超过该值时,将激活以下CRLMM函数:
 if(search>2):    # [Line 405]
                    a=1
                crlmm=CRLMM(Q,lr,e,a) 
在两次无果的搜索后,程序激活了a,这是CRLMM函数的标志。
CRLMM函数现在包含一个随机搜索功能,模拟选择一个停车场并提供一个一级状态:
 status=random.randint(0,10)    # [Line 199]
    if(status>5):
        status=1
    if(status<=5):
        status=0 
状态表示对停车场可用性的概率估计。a标志模拟一个尚未添加的程序,该程序将扫描所有停车场并运行此函数以找到一个可用的停车位。
在初次会议上展示原型时,你总是需要足够的材料来说服别人,但如果做得过头,成本将成为一种风险,尤其是在你的想法被拒绝的情况下。
因此,如果激活了a,系统会模拟扫描(待开发)并将状态强制设为1,如以下代码片段所示:
 if(a>0 and status==0):    # [Line 204]
        #add an available search function here that scans all the
        #webcams of then network until it finds one that suits the model (not too far parameter and available)
        status=1 
程序接着继续运行,并使用训练好的 CNN 来识别一个可用的停车场(参考以下截图),如前面的配置部分所解释:

图 12.13:网络摄像头冻结停车场的一帧
现在,已经找到一个有空车位的停车场(画面左上角的空白区域),搜索功能停止,接下来的 break 指令被激活:
 if(crlmm==1):    # [Line 408]
                    a=0
                    break 
一旦找到停车位,就会达到 break 指令。一旦检测到可用停车位,我们就可以决定如何到达停车场。
决定如何到达停车场
当 crlmm==1 时,CRLMM 程序找到了一个合适的停车场,如以下代码所示:
 if(crlmm==1):    # [Line 412]
            available = load_img("AVAILABLE.JPG")
            plt.subplot(111)
            plt.imshow(available)
            plt.title('PARKING LOT STATUS : This parking lot has available space.' + '\n' + 'Now an SVM will suggest a safe route ', fontname='Arial', fontsize=10)
            #plt.text(0.1,2, "The frame is the input of a trained CNN"
            plt.show()
            '''
            plt.show(block=False)
            time.sleep(5)
            plt.close()
            '''
            print("This parking lot has available space...") 
它显示以下信息和一个标志:

图 12.14:停车场状态
现在我们找到了一个可用的停车位,我们需要为自动驾驶车辆找到一条安全的路线。这意味着自动驾驶系统将避开交通,以便更容易进行自主机器学习程序。现在是时候激活该功能了。
支持向量机
CRLMM 现在要求选择一条安全的路线,即使这意味着需要更长的时间(或距离)。自动驾驶车辆需要严格遵循安全优先的政策。
程序达到了以下的 SVM 功能:
 print("This parking lot has available space...")    # [Line 424]
            SAFE_SVM() 
配置部分中描述的 SVM 提供了穿越交通的安全路径,如下图所示:

图 12.15:交通图
例如,在这个随机的案例中(大多数情况下交通是随机的),左边的蓝点表示交通较稀疏的区域,棕色的点表示交通较密集的区域。现实中的目标是为程序中的 MDP 提供信息,使其能够找到通过稀疏交通的路径,以确保安全,减少自动驾驶系统在密集交通中可能出现的错误。过去事故的统计权重和车辆经验也可以被加以利用,创建一个更深层次的安全模型旅行规划器。
假设自动驾驶车辆需要前往棕色区域的一个点,SVM 将:
- 
建议尽量走过蓝点区域,只在棕色区域中行驶。 
- 
将信息发送到 Google Maps。这将需要一个额外的脚本,用来读取一个包含每个数据点 GPS 坐标的数据集。 
许多驾驶员在繁忙的高速公路或密集的城市中感到不安全。将最安全路线功能加入到地图软件中将会有所帮助。
SVM 将数据点提升到更高的层级(请参考本章配置部分的解释)。
SVM 功能中表示的点不是实际的位置,而是一个抽象的表示。分割线需要通过一个功能,将这些信息转化为实际位置的数据点。
一旦 SVM 边界被转换为位置数据点,行程或旅行图就会被激活。
行程图
原型展示了一个基于 SVM 推荐和权重向量的行程图仿真,通过以下功能调用:
 print("SAFE PASSAGE SUGGESTED")    # [Line 426]
            MDP_GRAPH(lr,e) 
以下图表显示了最安全的路线(用红色表示),即使这意味着需要更长的时间(或距离):

图 12.16:优化器选择了最安全的行程
出于原型的目的,SVM 并未直接连接到图中,这将需要昂贵的时间成本。
相反,插入了以下random.randint函数,模拟了任何情况下停车位的随机可用性:
 for wi in range(6):    [Line 430]
                op=random.randint(0,5)
                if(W[op]>maxw):
                    lr=op;maxw=W[op] 
请记住,对于向潜在客户或经理的初步展示,进一步开发原型是没有意义的。
这种原型比幻灯片展示更强大,因为它证明了你的合法性。幻灯片是静态的,无法证明你在特定主题上的能力。一个原型将展示你的专业知识。一旦我们获得了最安全的位置,就可以像上一章那样更新 MDP 的权重向量。
权重向量
权重向量被显示出来。在这个模型中,权重代表位置,就像在上一章中一样。然而,在本章中,权重是一个评级:
- 
当某个区域在过去n年内发生过少量事故时,每个权重都会有一个较高的安全排名。这就是安全排名。这个排名应当成为我们行程软件的一部分,我们应该被告知。 
- 
自动驾驶汽车的经验将根据每个权重进行定制。这是其自身的驾驶记录。由于软件故障导致的差点事故会降低权重。良好的行驶记录将提升权重。对人类来说看似简单的事情,可能对软件来说是困难的,反之亦然。 
现在,系统显示了使用的权重,并将在原型通过后开发一个内部更新程序。以下代码调用了一个管理自动驾驶汽车最安全路线权重的函数,并显示了一个直方图:
 print("Vertex Weights",W)    # [Line 428]
            MDP_CRL_graph(W,lr) 

图 12.17:更新后的权重顶点的直方图(最安全的路线)
我们检测到了一个可用的停车位,要求 SVM 提供通往该停车位的最安全路径,更新了每个区域的权重,并将信息发送给 MDP 计算安全路径。
总结
本章与上一章一样,描述了一个没有人工参与的物联网连接过程。这一趋势将在未来几年扩展到各个领域。
这也表明,掌握如何使用工具需要努力,尤其是在学习人工智能时。为特定市场构思解决方案不仅仅需要努力工作。创造力不是靠工作获得的,它是在摆脱任何形式约束的过程中培养出来的。
一旦解决方案被构思出来,就面临着一个微妙的界限:是为展示开发过多,还是展示不足。CRLMM 提供了一种框架,帮助构建技术解决方案(CNN、MDP、SVM 和优化器),同时考虑到他人理解的日常概念。
本章还展示了一个人工智能模型可以包含一组算法,包括 RL、DL、SVM 和 CRL 认知方法等。
下一章将带我们更深入地了解神经网络和 TensorFlow 2,窥视人工神经网络(ANN)的内部过程。
问题
- 
在任何情况下,快速到达目的地总比安全更重要。(是 | 否) 
- 
自动驾驶汽车永远无法真正取代人类司机。(是 | 否) 
- 
未来是否会有带机器人灭火的自动驾驶消防车?(是 | 否) 
- 
大城市是否需要投资自动驾驶汽车,还是应该避免它们?(投资 | 避免) 
- 
你会信任自动驾驶公交车带孩子上学放学吗?(是 | 否) 
- 
你能在高速公路上的自动驾驶汽车里睡觉吗?(是 | 否) 
- 
你想为一个城市的项目开发一个自动驾驶程序吗?(是 | 否) 
深入阅读
- 欲了解更多关于支持向量机(SVM)的信息,请参考以下链接:scikit-learn.org/stable/modules/svm.html,scikit-learn.org/stable/auto_examples/svm/plot_separating_hyperplane.html#sphx-glr-auto-examples-svm-plot-separating-hyperplane-py
第十三章:使用 TensorFlow 2.x 和 TensorBoard 可视化网络
在本章中,我们将窥视机器在“思考”过程中,如何通过深度学习神经网络的各层进行处理。使用 TensorFlow 2 构建卷积神经网络(CNN)的顺序分类器所需的代码行数大大减少。运行分类器只需点击一下。然而,当程序出现问题时,理解程序的运行逻辑变得更加困难,而可视化各层的输出可以大有裨益。
可视化 CNN 各层的输出可以深入了解组成整个过程的每个独立步骤。
在本章中,和前几章一样,我们将定义 CNN 的各层。这一次,我们将增加更多层并提取每一层的输出,生成输出图像。我们将从头开始,采用从下到上的方法,使用 Python 中的 TensorFlow 2 构建此过程。
一旦输出被定义,我们将显示卷积层、池化层、丢弃层、扁平化层和全连接层的输出。
查看各层的输出提供了对各层功能的直观理解。能够可视化模型的全局图使得 CNN 的架构得以显现。
我们将使用 TensorBoard 来探索概念模型、训练轮次与准确度的关系,以及数学函数操作的细节。这些图表和测量将通过从上到下的方法,使用 Google Colaboratory 构建。
Google Colaboratory 提供了一个免费服务器,预装了可用的库和模块。我们将使用 Google Colaboratory 笔记本来探索 TensorBoard 的功能。本章分为三个主要部分。前两部分介绍如何使用 TensorFlow 2.2 构建一个顺序分类器并显示各层的输出。第三部分介绍如何使用 TensorFlow 2 版本的 TensorBoard 展示图形信息和准确度测量。
本章将介绍以下主题,并为 CNN 提供视觉上的深入理解:
- 
一层一层地构建 CNN 
- 
显示数据集 
- 
显示 CNN 各层的输出 
- 
使用 Google Colaboratory 
- 
使用 TensorBoard 可视化神经网络架构 
- 
使用 TensorBoard 可视化准确度测量 
让我们从讨论如何在 CNN 中探索各层的输出开始本章内容。
使用 TensorFlow 以两步法探索 CNN 各层的输出
许多商业智能领域的企业合同要求对任何自动化和关键决策算法进行解释过程。对于算法编辑者,无论是否为人工智能,提供解释通常是强制性的要求。我们需要为此做好准备。
此外,一旦人工智能在生产环境中运行,维护变得至关重要。开发人员经常从一个部门转到另一个部门,从一个公司转到另一个公司。必须维护程序的人需要详细了解它。
探索和可视化 CNN 是一个很好的方式,让我们亲自实践,打开跑车的引擎盖,看看引擎是如何运作的!
- 
首先,我们将逐层构建 CNN。我们将使用 TensorFlow 2 从底到顶构建顺序分类器。 我们不会直接使用 Keras 模型;我们将使用 TensorFlow 集成的 Keras 模块,这样将标题的行数减少到只有两行: import tensorflow as tf from tensorflow.keras import datasets, layers, models
- 
然后我们将探索各层的可视化输出,以深入了解它是如何“思考”的。 
好的,现在让我们开始构建吧!
构建 CNN 的各层
在第九章中描述了 CNN,使用卷积神经网络(CNN)进行抽象图像分类。在接下来的示例中,CNN 将包含更多层,以便逐步可视化神经网络如何提取特征。
我们将使用一个数据集,通过一个图像探索 CNN 的各层。该图像在训练数据集中重复多次,而测试数据集足够用来构建和运行模型以可视化神经网络的各层。
数据集中包含一张重复多次的花朵图像——一朵虹膜花。

图 13.1:我们在本章中探索的图像
目标不是让图像有很多变化,而是简单地看看 CNN 是如何逐层表示虹膜的。数据集中包含了一张重复的图像。然而,你可以更改这些图像,使用你自己的数据集,然后使用相同的代码如下所示展示图像:
cv_img=[]
images = []
for img_path in glob.glob('dataset/training_set/img/*.png'):
    images.append(mpimg.imread(img_path))
plt.figure(figsize=(20,20)) #20,10
columns = 5
for i, image in enumerate(images):
    plt.subplot(len(images) / columns + 1, columns, i + 1)
    plt.imshow(image) 
结果将是一个包含来自数据集的图像行的图形:

图 13.2:显示数据集
我们将首先导入神经网络模块:
import tensorflow as tf
from tensorflow.keras import datasets, layers, models 
构建 CNN 只需要几行代码。这看起来非常简单,因为它似乎是一个黑箱。在我们的例子中,第九章中描述的结构,使用卷积神经网络(CNN)进行抽象图像分类,在这里的增强版,只需几分钟就能从第 30 行到第 68 行创建:
#initializing the Tensorflow 2 classifier
classifier = models.Sequential()
#adding the convolution layers to the layers
classifier.add(layers.Conv2D(32, (3, 3), padding='same', input_shape = (28, 28, 3), activation = 'relu'))
classifier.add(layers.Conv2D(32, (3, 3), activation='relu'))
...
#adding dense-dropout-dense layers
classifier.add(layers.Dense(units = 512, activation = 'relu')) 
当我们探索各层的输出时,我们将在下一节回到这些层。这里需要关注的主要点是代码的简洁性。虽然在几分钟内构建一个 CNN 作为一个黑箱可能行得通,但当问题出现时,要理解每一层需要对各层的表示有更深入的理解。
在探索这些层之前,程序会打印分类器(CNN)的结构:
#Printing the model summary
print("Model Summary",classifier.summary()) 
模型包含相当数量的层来进行探索:
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 28, 28, 32)        896       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 26, 26, 32)        9248      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32)        0         
_________________________________________________________________
dropout (Dropout)            (None, 13, 13, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 13, 13, 64)        18496     
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 11, 11, 64)        36928     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64)          0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 5, 5, 64)          0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 5, 5, 64)          36928     
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 3, 3, 64)          36928     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 1, 1, 64)          0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 1, 1, 64)          0         
_________________________________________________________________
flatten (Flatten)            (None, 64)                0         
_________________________________________________________________
dense (Dense)                (None, 512)               33280     
_________________________________________________________________
dropout_3 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 3)                 1539      
=============================================================== 
请注意这个总结。当选择你想要探索的层数以可视化输出时,它将非常有用。
然后,模型被编译:
# Compiling the convolutional neural network (CNN)
classifier.compile(optimizer = 'rmsprop',
    loss = 'categorical_crossentropy',metrics = ['accuracy']) 
然后处理(重新缩放)并定义训练和测试数据集:
train_datagen = ImageDataGenerator(rescale = 1./255)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory(
                                  'dataset/training_set',
                                  target_size = (28, 28),
                                  batch_size = 16,
                                  class_mode =
                                  'categorical')
test_set = test_datagen.flow_from_directory('dataset/test_set',
                                           target_size = (28, 28),
                                           batch_size = 16,
                                           class_mode =
                                           'categorical') 
如果我们在这里停下来,CNN 就能正常工作。但我们真正理解了这个模型吗?我觉得不是。当然,安装好一个现成的数据集后,只需点击几下即可运行 CNN。这种黑盒子的方法固然可行,但是探索一层的视觉输出能更好地代表网络。接下来我们来看看这个。
处理 CNN 层的视觉输出
关键在于专注于一幅图像,实际上 看见 CNN 逐层计算的“心理”、视觉表示。
为了处理这些层,程序首先选择一个图像供激活模型使用:
#Selecting an image for the activation model
img_path = 'dataset/test_set/img/img1.png'
img1 = image.load_img('dataset/test_set/img/img1.png', target_size=(28, 28))
img = image.img_to_array(img1)
img = np.expand_dims(img, axis=0)
img /= 255.
plt.imshow(img[0])
plt.show()
print("img tensor shape",img.shape) 
然后可视化过程分几步进行,这将带领我们深入 CNN:
- 
选择要可视化的层数量使用 e变量:回到之前显示的模型摘要,你可以选择要停在哪一层。在这个例子中,我们选择停在e=12。你可以选择从e=4开始可视化第一卷积和池化层:#Selecting the number of layers to display e=12 #last layer displayed layer_outputs = [layer.output for layer in classifier.layers[0:e]]如果 e=3,程序会在max_pooling2d处停止:Displaying layer: conv2d Displaying layer: conv2d_1 Displaying layer: max_pooling2d
- 
选择要探索的前 n 个层:程序参考 layer_outputs提取它需要可视化目标层的信息:# Extracting the information of the top n layers activation_model = models.Model(inputs=classifier.input, outputs=layer_outputs)
- 
应用激活模型来提取请求的层:激活模型迫使分类器开始工作并通过层。这样,我们可以窥探其“思考”过程,看看它如何表示输入: # Activating the model activations = activation_model.predict(img)
- 
检索层名称以及层的视觉表示以显示:层名称帮助我们理解我们正在观察什么。使用我们之前打印的模型摘要作为地图,查看当显示层名称时所处的位置,以及该层输出的表示: #layer names layer_names = [] for layer in classifier.layers[:12]: layer_names.append(layer.name)
- 
处理层输出并将其组织成网格:为了避免观看给定层表示的变化的顺序显示,我们将它们组织成一个网格图像: # Processing the layer outputs for layer_name, layer_activation in zip(layer_names, activations): #getting the layer_names and their activations n_features = layer_activation.shape[-1] #features in the layer size = layer_activation.shape[1] #shape of the feature map n_cols = n_features // images_per_row #number of images per row display_grid = np.zeros((size * n_cols, images_per_row * size)) #size of the display grid for col in range(n_cols): #organizing the columns for row in range(images_per_row): #...and rows to display image = layer_activation[0,:, :, col * images_per_row + row] #retrieving the image... image -= image.mean() #...and processing it in the... if(image.std()>0): # ...following lines to display it image /= image.std() image *= 64 image += 128 image = np.clip(image, 0, 255).astype('uint8') display_grid[col * size : (col + 1) * size, row * size : (row + 1) * size] = image
- 
显示处理后的层输出:现在工作已经完成,我们只需显示层名称以及相应的网格: #displaying the layer names and processed grids print("Displaying layer:",layer_name) scale = 1\. / size plt.figure(figsize=(scale * display_grid.shape[1], scale * display_grid.shape[0])) plt.title(layer_name) plt.grid(False) plt.imshow(display_grid, aspect='auto', cmap='viridis') plt.savefig("dataset/output/"+layer_name) plt.show()
注意,这些图像是通过 plt.savefig 保存在输出目录中以便后续使用。
你将获得一个图层名称列表,其中包含你选择可视化的图层。例如,你可以查看前七个图层的图像。你可以通过以下图表或运行程序查看它们。无论如何,分析层的最佳方法是仔细观察第一层,然后再观察最后一层。你会发现,CNN 正在精确地提取图像的抽象表示,并显示更高的维度。难以用人眼感知层之间差异的原因有两个因素:
- 
分析的元素数量对我们来说极为困难。通常我们的大脑会在我们不知不觉中完成这个过程! 
- 
有多个卷积层,而不是一个层,后者会迅速完成获取图像抽象表示的过程。它是逐层处理的,就像人类大脑一步步处理图像一样。 
看一下第一个层和最后一个层,然后回过头来观察各层之间的差异。

图 13.3:卷积层

图 13.4:卷积层

图 13.5:池化层

图 13.6:丢弃层

图 13.7:卷积层

图 13.8:卷积层

图 13.9:池化层
可视化 CNN 层的输出提供了一个绝佳的方式来理解和分析神经网络。让我们更进一步,分析这些层。
分析 CNN 层的视觉输出
输入图像是混乱的,直到某种形式的智能将其理清。任何形式的智能都会检测出其中的模式和结构。机器智能通过增加抽象层级来实现同样的目标,方法是通过降维。将混乱转化为有序表示的过程是当今神经网络这一伟大发明的核心。
运行 cnn_layers.py 时,层输出将会显示。让我们来探索其中的一些层。你可以通过简单地更改第 107 行中 e = <number-of-layers> 变量的值来探索其中的部分或全部层。
卷积层激活函数
卷积层的一个关键选项是激活函数。在以下的 cnn_layers.py 中使用了 relu:
#adding more convolution layers to the layers
classifier.add(layers.Conv2D(64, (3, 3), padding='same', activation = 'relu'))
classifier.add(layers.Conv2D(64, (3, 3), activation='relu')) 
关于 ReLU 的更多内容,请参阅第九章,使用卷积神经网络(CNN)进行抽象图像分类。
relu 为 Conv2d 层生成以下输出:

图 13.10:conv2d 输出 1
现在去第 33 行,将 relu 替换为 softmax,如下所示:
classifier.add(layers.Conv2D(32, (3, 3), padding='same',
    input_shape = (28, 28, 3), activation = 'softmax')) 
输出有很大不同,正如我们所看到的:

图 13.11:conv2d 输出 2
人眼需要一些时间来适应这种变化。看看每个版本。试着在闭上眼睛几秒钟后记住它,然后再看另一个版本。我们的脑海里会下意识地做这件事,这也是为什么我们需要刻意做这个练习的原因。
你应该使用哪一个?欢迎来到深度学习!对于这个问题没有确定的答案。这是一个试错的过程。一个激活函数可能适合某个模型,而不适合另一个模型。即使在训练过程中网络的准确度是可以接受的,当新数据产生不良结果时,你可能需要随着时间的推移更改激活函数。
关于 softmax 的更多信息,请回到第二章中的解释,构建奖励矩阵 - 设计你的数据集。
让我们尝试sigmoid逻辑斯谛激活函数,它也在第二章中有描述:

图 13.12:conv2d 输出 3
再次注意差异。观察每个激活函数下第 1 行的最后一张图像。这些差异非常有趣,因为它们提供了各种可能的表示。
尝试其他激活函数,感受一下人工神经网络如何通过减少需要处理的维度,将它所感知到的信息转化为更高层次的抽象。
卷积层通过各层传递的高层次表示
注意,通过以下输出,从conv2d到conv2d_5,顺序分类器所达到的惊人抽象级别,实际上这是cnn_layers.py中的第六层(0 到 5)卷积层。
网络从一个相对形象化的表示开始,逐步达到 conv2d_5 的高度抽象级别。我们实际上处于机器的“思维”中,观察它思考和学习!

图 13.13:初始 conv2d 输出

图 13.14:conv2d_1 输出

图 13.15:conv2d_2 输出

图 13.16:conv2d_3 输出

图 13.17:conv2d_4 输出

图 13.18:conv2d_5 输出
这一抽象过程在很大程度上得益于其他层次,如池化层。
池化层获取更高层次表示
池化层将减少输入的维度数量,并选择它找到的最具代表性的特征:
#adding a max pooling layer to the layers
classifier.add(layers.MaxPooling2D(pool_size=(2, 2))) 
让我们探讨一下这个例子中前两个池化层的演变:

图 13.19:max_pooling2d 输出

图 13.20:max_pooling2d_1 输出
再次,我们可以看到 CNN 所能达到的强大抽象级别。
关于池化层的更多信息,请阅读第九章中的解释,使用卷积神经网络(CNNs)进行抽象图像分类。
Dropout 层通过各层传递的高层次表示
dropout 层提供了一种放弃许多特征的方式,以达到简化的更高层次表示:
classifier.add(layers.Dropout(0.5)) # antes era 0.25 
并非总是需要添加 dropout 层,因为这取决于你正在探索的模型的生产力和架构。在这个例子中,前两个 dropout 层是非常具有指导意义的。dropout 也是一种避免过拟合的方式。模型学习如何提取关键特征以获得抽象表示,而不是字面表示。

图 13.21:dropout 输出

图 13.22:dropout_1 输出
再次观察 dropout 层如何加速抽象过程。我们可以看到 CNN 的“大脑”在运作。
推荐
我建议你尝试不同的激活函数和各种层的选项,然后运行程序,感受一下 CNN “机器思维”过程中的运作。即使它是一个纯粹的数学架构,它也能很好地展示 CNN 的“机器思维”方式,尽管它完全不是人类,但它有自己的“机器思维”方法。
现在我们已经从下到上探索了 CNN,让我们看看如何使用 TensorBoard 从上到下观察 CNN 的准确性。
使用 TensorBoard 分析 CNN 的准确性
在本节中,我们将首先开始使用免费的 Google Colaboratory 服务器,然后探索一些 TensorBoard ANN 测量功能。
开始使用 Google Colaboratory
你只需几个步骤就能获得免费的 Google Colaboratory 服务器实例:
- 
确保你有一个 Google 账户并登录。 
- 
点击以下链接,它将带你到 Google Colaboratory: colab.research.google.com/notebooks/welcome.ipynb#recent=true你将被带到以下页面: ![]() 图 13.23:Colaboratory 初始登陆页面 
- 
点击右上角的UPLOAD选项: ![]() 图 13.24:上传选项 你可以选择或拖放一个文件,然后上传它。 
- 
上传 TF_2_graphs.ipynb。你可以从这个链接下载程序并上传它: github.com/PacktPublishing/Artificial-Intelligence-By-Example-Second-Edition/blob/master/CH13/TF_2_graphs.ipynb
- 
程序打开后,你将看到以下页面: ![]() 图 13.25:一个 Colaboratory 笔记本 
- 
在菜单中点击文件并将笔记本保存到你的 Google Drive: 

图 13.26:文件菜单
文件保存后,你就准备好了!
你有许多运行时选项,例如选择使用 CPU 还是 GPU,显示选项(例如背景),以及更多使用 Google Colaboratory 的方式。我推荐阅读文档以了解可用的众多选项。
你现在在自己的免费 Colaboratory 服务器上,准备好探索你的笔记本。
定义并训练模型
我们将运行笔记本,然后分析结果。这将提供对 Google Colaboratory 以及一些 TensorBoard 功能的介绍。
首先,通过点击运行所有选项来运行程序,位于运行时菜单中:

图 13.27:运行时选项
程序将遍历其单元格并提供关于训练过程的信息。为了获取这些信息,我们将探索 TensorBoard 的一些关键功能。
我们将首先安装 TensorFlow,然后运行 TensorBoard。
- 安装 TensorFlow 并启动 TensorBoard:如你在前一节看到的,除非单元格包含错误,否则你无需逐个运行程序单元。在这种情况下,点击单元格中的运行按钮:

图 13.28:运行单元格
单元格将执行代码。在这种情况下,它将安装 TensorFlow 2.x:
# Ensure TensorFlow 2.0 is installed.
!pip install -q tf-nightly-2.0-preview
# Load the TensorBoard notebook extension.
%load_ext tensorboard 
安装完成并加载 TensorBoard 后,程序会遍历头部导入必要的模块。
小心 TensorBoard 版本!你可能安装了一个旧版本或者是用于其他项目的不同版本。在运行此程序之前,检查一下你环境中任何正在使用 TensorBoard 的应用。运行之前仔细检查配置。如果存在风险,使用另一个环境或仅查看笔记本而不运行它。
- 
程序现在定义了一个简化的模型,你现在已经熟悉:以下模型已简化,目的是展示 TensorBoard 的工作原理。当然,在探索完笔记本后,你可以添加更多的层。 # Define the model. model = keras.models.Sequential([ keras.layers.Flatten(input_shape=(28, 28)), keras.layers.Dense(32, activation='relu'), keras.layers.Dropout(0.2), keras.layers.Dense(10, activation='softmax') ])
- 
模型接着使用优化器和准确率指标进行编译:现在需要编译并运行模型,以便提供测量输出: model.compile( optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])关于 Adam 优化器和交叉熵的更多内容,参见第九章,使用卷积神经网络(CNN)进行抽象图像分类。 
模型现在已经训练完成,准备接受 TensorBoard 的度量回调。
在程序运行训练时,它将保存主要功能的日志以供展示。模型的图表可以通过一行在 TensorBoard 中显示,且有许多其他功能。
%tensorboard --logdir logs 
以下是模型的图表,包含了许多细节:

图 13.29:TensorFlow 图表
如果你想要简化视图,模型的概念性视图也已展示:

图 13.30:TensorFlow 图表的部分视图
我们已经通过 TensorBoard 图表探索了神经网络模型的架构。接下来,让我们看看如何可视化模型训练过程中的度量。
引入一些度量
在训练过程中,程序将关键信息保存在日志目录中,现在可以显示这些信息。
- Epoch 准确性:如果准确性随着 Epoch 增加而提高,说明分类器在进展,并且学习是正确的。如果准确性下降了,我们就有麻烦了!我们需要回头检查数据集、激活函数以及层的设计。

图 13.31:模型的准确性
- 基础流程,包括激活函数:TensorBoard 具有深入功能。你可以深入查看 TensorFlow 2.x 正在计算的实际操作:

图 13.32:激活函数
- 探索激活函数的细节:一旦你看到了操作的流程,你甚至可以深入查看它是如何构建的:

图 13.33:激活函数
这些 TensorBoard 图形和测量结果帮助你深入了解模型的工作原理。它们提供了对第一节中探索各层输出时所获得的见解的补充。
在本节中,我们通过多种可用的图形和工具,探讨了 TensorBoard 的架构功能,并衡量了我们模型的训练表现。
概述
在本章中,我们从内部探索了深度学习。我们看到,使用 TensorFlow 2.x 构建 CNN 现在变得容易,但深入了解其“思维”方式提供了关键的见解。
我们首先构建了一个拥有多层的 CNN。CNN 的抽象层次随着每一层的增加而提高。每层减少维度数使得模式显现。神经网络可以被描述为一个从混乱到有意义的过程。
在构建完 CNN 后,我们编写了一个程序,可以读取各层的“心智”图像。每层的输出展示了网络如何创建模式和结构。由于我们人类通常通过心智图像思考,CNN 的输出图像帮助我们理解机器是如何学习的。
最后,我们使用了 Google Colaboratory 服务器,通过在 TensorFlow 2.x 上运行的 TensorBoard 可视化了 CNN 学习过程的测量结果。衡量 CNN 训练过程的准确性至关重要。通过可视化这些测量结果,可以更容易地看出问题所在。TensorBoard 提供了一个模型图,帮助我们从源代码到人工神经网络(ANN)的心智模型进行转换。
总结这一章,我们可以说,人工智能通过数学将我们周围的混乱转化为可理解的结构和模式。
在下一章中,我们将进一步探讨并学习如何可视化神经网络的另一个方面:权重。我们将使用限制玻尔兹曼机(RBM)的权重,结合主成分分析,在 TensorBoard 中创建可视化表示。
问题
- 
一个 CNN 总是有相同数量的层。(是 | 否) 
- 
ReLU 是最佳激活函数。(是 | 否) 
- 
不需要编译一个顺序分类器。(是 | 否) 
- 
最好在不运行预测的情况下查看层的输出。(是 | 否) 
- 
查看层的输出时,层的名称没有任何意义。(是 | 否) 
- 
TensorFlow 2.x 不包括 Keras。(是 | 否) 
- 
Google Colaboratory 只是一个存储库,类似于 GitHub。(是 | 否) 
- 
Google Colaboratory 无法运行笔记本。(是 | 否) 
- 
可以在 Google Colaboratory 笔记本中运行 TensorBoard。(是 | 否) 
- 
准确度在 TensorBoard 中显示。(是 | 否) 
进一步阅读
- 
有关激活函数的更多信息,请访问 keras.io/activations/。
- 
点击此链接查看更多关于 Google Colaboratory 的信息: colab.research.google.com/notebooks/welcome.ipynb#recent=true。
第十四章:使用限制玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人的输入
在接下来的章节中,我们将探索聊天机器人框架并构建聊天机器人。你会发现,创建一个聊天机器人的结构只需几次点击。然而,任何聊天机器人都无法在没有设计输入以准备所需对话流程的情况下建立。本章的目标是展示如何从数据集中提取特征,然后使用这些特征收集基本信息,以便在第十五章,搭建认知 NLP UI/CUI 聊天机器人中构建一个聊天机器人。
对话的输入需要深入研究和设计。在本章中,我们将构建一个限制玻尔兹曼机(RBM),它将分析一个数据集。在第十三章,使用 TensorFlow 2.x 和 TensorBoard 可视化网络中,我们研究了卷积神经网络(CNN)的层并显示了它们的输出。这次,我们将探索 RBM 的权重。我们将进一步使用 RBM 的权重作为特征。RBM 的权重可以转换为特征向量,供主成分分析(PCA)算法使用。
我们将使用 RBM 生成的特征向量,利用 TensorBoard Embedding Projector 的功能构建一个 PCA 展示。然后,我们将使用获得的统计数据为聊天机器人的输入打下基础。
为了说明整个过程,我们将使用流媒体平台数据作为示例,展示这一过程是如何完成的。流媒体已成为几乎所有智能手机拥有者的核心活动。Netflix、YouTube、Amazon 或任何提供流媒体服务的平台面临的问题是如何向我们推荐合适的视频。如果观众观看了一部视频,而平台没有展示一个相关的类似视频供其观看,观众可能会选择使用另一个平台。
本章分为两部分:
- 
构建 RBM 并将其扩展为自动特征向量生成器 
- 
使用 PCA 来表示 RBM 的权重作为特征。TensorFlow 的 Embedding Projector 具有内置的 PCA 功能。生成的统计数据将为第十五章,搭建认知 NLP UI/CUI 聊天机器人中的对话结构提供基础。 
让我们首先定义我们正在使用的基本术语和目标。
定义基本术语和目标
本章的目标是准备数据,以便创建我们将在第十五章,搭建认知 NLP UI/CUI 聊天机器人中构建的聊天机器人的输入。
创建一个聊天机器人需要准备工作。我们不能在没有足够信息的情况下直接进入项目。在本案例中,我们将检查一个基于电影偏好的数据集。我没有选择下载庞大的数据集,因为我们首先需要专注于理解过程,并使用基础数据构建模型。
数据集的大小在在线平台上每天都在增加。当我们在流媒体平台上观看电影时,例如 Netflix,我们可以喜欢这部电影或点击“点踩”按钮。
当我们在在线平台上对一部电影表示赞同或不赞同时,我们的偏好会被记录下来。这些电影的特征为平台提供了宝贵的信息,平台可以根据这些信息展示我们偏好的电影:动作、冒险、浪漫、喜剧等。
在本章中,我们将首先使用 RBM 提取用户或一组用户观看过的电影的描述(例如动作片、冒险片或喜剧片)。我们将利用 RBM 生成的输出权重,创建一个反映用户偏好的特征文件。
用户偏好的特征文件可以被视为一个人的“心智数据集”。这个名称一开始可能听起来有些陌生。然而,一个人的“心智”表示超越了标准的年龄、收入和其他无关紧要的数据。像“爱情”、“暴力”和“视野”(更广阔的视野、冒险)这样的特征,能让我们比驾照上的信息更深入地了解一个人。
在本章的第二部分,我们将使用 RBM 的输出,即一个人“心智”的特征,作为 PCA 的输入。PCA 将计算这些特征之间的关联性以及它们的变化,并且我们将通过 TensorBoard 展示这些结果。
然后,我们将通过 RBM 提取的关键特征,看到一个人心智的表现。这些信息将帮助我们在第十五章中创建一个定制化的聊天机器人。
让我们进入第一阶段,构建一个 RBM。
介绍并构建 RBM
RBM 是随机且无向的图模型,通常由一个可见层和一个隐藏层构成。它们曾在 Netflix 的竞赛中被用于预测未来的用户行为。这里的目标不是预测观众将会做什么,而是确定观众是谁,并将数据存储在观众的个人档案结构化的心智数据集中。输入数据代表了要训练的特征,以了解观众 X。每一列代表 X 潜在个性和品味的特征,每一行代表 X 观看过的电影的特征。以下代码(以及本节内容)在RBM_01.py中:
np.array([[1,1,0,0,1,1],
         [1,1,0,1,1,0],
         [1,1,1,0,0,1],
         [1,1,0,1,1,0],
         [1,1,0,0,1,0],
         [1,1,1,0,1,0]]) 
该 RBM 的目标是通过计算观看过的电影特征,定义 X 的个人档案。输入数据也可以是图像、文字或其他形式的数据,和任何神经网络一样。
首先,我们将探索架构并定义什么是基于能量的神经网络。接着,我们将在 Python 中从零开始构建一个 RBM。
RBM 的架构
使用的 RBM 模型包含两层:可见层和隐藏层。存在多种类型的 RBM,但通常它们具有以下特性:
- 
可见单元之间没有连接,这就是它被称为限制性的原因。 
- 
隐藏单元之间也没有连接,进一步强化了网络的限制属性。 
- 
与前馈神经网络(FNN)不同,RBM 没有像在第八章《使用前馈神经网络解决 XOR 问题》中所探讨的那样的方向性。因此,RBM 的模型是一个无向图。 
- 
可见层和隐藏层通过一个权重矩阵和一个偏置向量连接,它们是以下图中的线条: 

图 14.1:可见单元和隐藏单元之间的连接
网络包含六个可见单元和两个隐藏单元,产生一个 2×6 的权重矩阵,我们将为其添加偏置值。
你会注意到没有输出。系统从可见单元运行到隐藏单元再返回。我们正在使用这种类型的网络进行特征提取。例如,在本章中,我们将使用权重作为特征。
通过强制网络通过一个权重矩阵将其包含在 6 个单元中的数据表示为 2 个单元,RBM 创建了特征表示。隐藏单元、权重和偏置可以用于特征提取。
一种基于能量的模型
RBM 是一种基于能量的模型。能量越高,获得正确信息的概率越低;能量越低,概率越高——换句话说,准确度越高。
为了理解这一点,我们回到在《第一章,通过强化学习开始下一代人工智能》中观察的那杯茶:

图 14.2:一杯茶的复杂性
在《第一章》中,我们通过茶杯的全局内容和温度观察了它的微观状态。然后,我们使用马尔科夫决策过程(MDP)来进行微观状态计算。
这次,我们将关注茶杯的温度。x 将是茶杯中所有分子的全球温度:
- 
如果 x = 1,这意味着温度非常高。茶刚刚沸腾。 
- 
如果 x = 0.5,这意味着温度已经下降。 
- 
如果 x = 0.1,这意味着温度还是有点暖和,但茶正在冷却。 
温度越高,分子在茶杯中越活跃,能量水平越高,感觉就越热。
然而,温度越高,越接近非常热,我们能喝下它的概率就越低。
这导致了温度 x 的概率 p:
- 
x -> 1, p -> 0 
- 
x -> 0, p -> 1 
如你所见,在一个能量驱动的系统中,我们会努力降低能量水平。假设我们有一个对热饮耐受度未知的人,我们想知道他们是否能喝下我们的这杯茶。没人愿意喝冷的(低能量)茶,当然,但是如果我们关注的是一个人能否喝下这杯茶而不觉得太烫(高能量),那么我们就希望这杯茶的能量尽可能低(也就是冷却)!
为了说明我们这杯茶的 p(x) 系统,我们将使用欧拉数 e,它的值为 2.718281。p(x) 是我们能否喝下这杯茶的概率,p 是概率,x 是温度或能量。
我们将开始引入一个简单的能量函数,其中 p(x) = e((–)x^):
- 
p(e^((–1))) = 0.36 
- 
p(e^((–0.5))) = 0.60 
- 
p(e^((–0.1))) = 0.90 
你可以看到,随着 –x(能量)减小,概率 p(x) 增加。
RBM 学习函数的目标是通过优化权重和偏置来降低能量水平。通过这样做,RBM 增加了优化隐藏单元、权重和偏置的概率。
为了计算 RBM 的能量,我们将考虑网络的完整架构。让我们再次显示我们的模型,如下所示:

图 14.3:可见单元和隐藏单元之间的连接
该 RBM 模型包含以下值:
- 
E(v, h) 是能量函数,考虑了可见单元(输入数据)和隐藏单元。 
- 
v[i] = 可见单元(输入)的状态。 
- 
a[i] = 可见单元的偏置。 
- 
h[j] = 隐藏单元的状态。 
- 
b[j] = 隐藏单元的偏置。 
- 
w[ij] = 权重矩阵。 
结合这些变量,我们可以为  、
、 和 ij(作为权重矩阵的行和列)定义 RBM 的能量函数,如下所示:
 和 ij(作为权重矩阵的行和列)定义 RBM 的能量函数,如下所示:

现在我们对 RBM 有了更好的理解,并了解了其背后的原理,让我们开始考虑如何从零开始使用 Python 构建一个 RBM。
在 Python 中构建 RBM
我们将使用 RBM_01.py 从头开始构建一个 RBM,完全手动,不依赖任何预构建的库。这样做的目的是从上到下理解一个 RBM,看看它是如何工作的。在构建机器的过程中,我们将深入探索更多的 RBM 理论。
创建类和 RBM 的结构
首先,创建 RBM 类:
class RBM:
    def __init__(self, num_visible, num_hidden):
        self.num_hidden = num_hidden
        self.num_visible = num_visible 
类的第一个函数将接收隐藏单元的数量(2)和可见单元的数量(6)。
权重矩阵在第 20 行使用随机权重值进行初始化:
 np_rng = np.random.RandomState(1234)
        self.weights = np.asarray(np_rng.uniform(
            low=-0.1 * np.sqrt(6\. / (num_hidden + num_visible)),
            high=0.1 * np.sqrt(6\. / (num_hidden + num_visible)),
            size=(num_visible, num_hidden))) 
偏置单元现在将在第 27 行插入到第一行和第一列:
 self.weights = np.insert(self.weights, 0, 0, axis = 0)
        self.weights = np.insert(self.weights, 0, 0, axis = 1) 
该模型的目标是观察权重的行为。观察权重将决定如何根据可见单元和隐藏单元之间的计算来解释该模型的结果。
第一行和第一列是偏置,如前面的代码片段所示。仅对权重进行分析,以便进行性能分析。现在,权重和偏置已就位。
在 RBM 类中创建训练函数
在第 30 行,创建了训练函数:
 def train(self, data, max_epochs, learning_rate): 
在此函数中:
- 
self是类。
- 
data是一个 6×6 的输入数组,包含 6 行电影和 6 列电影特征:np.array([[1,1,0,0,1,1], [1,1,0,1,1,0], [1,1,1,0,0,1], [1,1,0,1,1,0], [1,1,0,0,1,0], [1,1,1,0,1,0]])本章中的 RBM 模型使用的是 可见二进制单元,如输入所示,这是该模型的训练数据。RBM 将使用输入作为训练数据。 一个 RBM 可以包含其他类型的单元:softmax 单元、高斯可见单元、二项单元、修正线性单元等。我们的模型专注于二进制单元。 
- 
max_epochs是 RBM 训练的轮数。
- 
learning_rate是应用于包含权重和偏置的权重矩阵的学习率。
我们将在第 35 行的第一列插入偏置单元1:
 data = np.insert(data, 0, 1, axis = 1) 
初始化偏置的策略还有其他方法。这是一个试错过程,取决于你的项目。在这种情况下,1的偏置单元足以完成任务。
训练函数中计算隐藏单元
在第 37 行,我们通过计算隐藏单元的值,开始训练 RBM,持续max_epochs:
 for epoch in range(max_epochs): 
第一个阶段是专注于隐藏单元。我们通过点积矩阵乘法激活隐藏单元的概率:
 pos_hidden_activations = np.dot(data, self.weights) 
然后,我们应用了逻辑函数,如同在第二章中所看到的,构建奖励矩阵 - 设计你的数据集:
 pos_hidden_probs = self._logistic(
                pos_hidden_activations) 
逻辑函数在第 63 行被调用:
 def _logistic(self, x):
        return 1.0 / (1 + np.exp(-x)) 
我们将偏置设置为1:
 pos_hidden_probs[:,0] = 1 # Fix the bias unit. 
我们现在已经计算出了带有随机权重的隐藏状态概率的第一次迭代。
为重建和对比散度随机采样隐藏单元
有许多采样方法,例如吉布斯采样,它具有随机化方法,以避免确定性样本。
在这个模型中,我们将选择一个随机样本,该样本选择的隐藏概率值超过一个随机值样本的值。random.rand函数生成一个随机矩阵,值介于0和1之间,矩阵的大小为num_examples×self.num_hidden+1:
 pos_hidden_states = pos_hidden_probs >
                np.random.rand(num_examples, self.num_hidden + 1) 
这个样本将用于我们将在下一节中探讨的重建阶段。
我们还需要计算用于对比散度(更新权重矩阵的函数)阶段的关联,这是接下来所解释的:
 pos_associations = np.dot(data.T, pos_hidden_probs) 
可见数据单元v与隐藏单元h的点积可以表示如下:

现在点积已经实现,我们将构建重建阶段。
重建
RBM 使用其输入数据作为训练数据,使用随机权重矩阵计算隐藏权重,然后重建可见单元。与其他神经网络的输出层不同,RBM 重建可见单元并将其与原始数据进行比较。
以下代码应用与之前描述的隐藏单元相同的方法来生成可见单元:
 neg_visible_activations = np.dot(pos_hidden_states,
                self.weights.T)
            neg_visible_probs = self._logistic(
                neg_visible_activations)
            neg_visible_probs[:,0] = 1 # Fix the bias unit 
这些负向可见单元将用于评估 RBM 的误差水平,如此处所解释。
现在,我们已经通过隐藏单元状态样本生成了可见单元,接下来我们生成相应的隐藏状态:
 neg_hidden_activations = np.dot(neg_visible_probs,
                self.weights)
            neg_hidden_probs = self._logistic(
                neg_hidden_activations)
            neg_associations = np.dot(neg_visible_probs.T,
                neg_hidden_probs) 
请注意,neg_associations可以表示为以下形式:

这里,我们已经完成了以下操作:
- 
使用包含训练数据的可见单元计算正向隐藏状态 
- 
从这些正向隐藏状态中随机选择一个样本 
- 
重建负向(从隐藏状态生成的,而非数据)可见状态 
- 
然后,由可见状态生成的隐藏状态 
我们已经通过此过程重构了可见状态。然而,我们需要评估结果并更新权重。
对比散度
为了更新权重,我们不使用梯度下降。在这个能量模型中,我们使用对比散度,它可以表达如下:

字母 是学习率。学习率应该是一个小值,并且可以在整个训练过程中进行优化。我总共使用了一个较小的值 0.001。
是学习率。学习率应该是一个小值,并且可以在整个训练过程中进行优化。我总共使用了一个较小的值 0.001。
更新权重的源代码如下:
 self.weights += learning_rate * ((pos_associations -
                neg_associations)) 
在多个时代中,权重会进行调整,从而降低能量和误差水平,进而提高概率的准确性。
此时,我们将展示 RBM 在整个训练过程中误差水平和能量值的变化。
误差和能量函数
在第 56 行,误差函数计算数据提供的可见单元与重构的可见单元之间差异的平方和:
 error = np.sum((data - neg_visible_probs) ** 2) 
对于能量函数,我们可以使用原始的能量方程:

在我们的代码中,我们不会使用偏置,因为我们通常将其设置为1。
我们还需要一个函数来衡量 RBM 能量的演变。
能量将通过概率函数p来衡量:

Z是一个配分函数,用于确保每个x输入的概率之和不超过 1:

配分函数是每个x的所有单独概率之和:

相应的代码将计算 RBM 的能量,随着 RBM 经历多个时代,能量会逐渐降低:
 energy=-np.sum(data) - np.sum(neg_hidden_probs)-
                np.sum(pos_associations * self.weights)
            z=np.sum(data)+np.sum(neg_hidden_probs)
            if z>0: energy=np.exp(-energy)/z; 
你会注意到,误差函数和能量函数都不会影响训练过程。训练过程基于对比散度。
误差和能量值将通过提供有关 RBM 训练行为的一些见解,来衡量模型的效率。
这是在过程开始时和结束时这些测量值的示例:
Epoch 0: error is 8.936507744240409  Energy: 1586106430052073.0
...
Epoch 4999: error is 4.498343290467705  Energy: 2.426792619597097e+46 
在第 0 个时代,误差很高,能量也很高。
在第 4999 个时代,误差足够低,模型能够生成正确的特征提取值。能量显著降低。
运行时代并分析结果
一旦 RBM 为n个时代优化了权重-偏置矩阵,该矩阵将为 X 人物的分析系统提供以下信息:
[[ 0.91393138 -0.06594172 -1.1465728 ]
[ 3.01088157 1.71400554 0.57620638]
[ 2.9878015 1.73764972 0.58420333]
[ 0.96733669 0.09742497 -3.26198615]
[-1.09339128 -1.21252634 2.19432393]
[ 0.19740106 0.30175338 2.59991769]
[ 0.99232358 -0.04781768 -3.00195143]] 
一个 RBM 模型使用随机值,每次训练时都会产生稍有不同的结果。
RBM 将训练输入并显示添加到 X 个人档案中的特征。
特征的权重已经为 X 人物进行了训练。第一行是偏置,检查第 2 列和第 3 列。接下来的六行是 X 人物特征的权重:
[[ 0.913269 -0.06843517 -1.13654324]
[ 3.00969897 1.70999493 0.58441134]
[ 2.98644016 1.73355337 0.59234319]
[ 0.953465 0.08329804 -3.26016158]
[-1.10051951 -1.2227973 2.21361701]
[ 0.20618461 0.30940653 2.59980058]
[ 0.98040128 -0.06023325 -3.00127746]] 
权重(以粗体显示)是第 2 到第 6 行,第 2 到第 3 列。第一行和第一列是偏置项。
解释 RBM 权重的方式仍然是需要小心构建的策略。在这种情况下,尝试了一种创新方法来确定营销行为。RBM 还有许多其他用途,例如图像处理。在这种情况下,权重矩阵将通过汇总特征的权重行来提供 X 的个人档案,如下代码所示:
 for w in range(7):
        if(w>0):
            W=print(F[w-1],":",r.weights[w,1]+r.weights[w,2]) 
现在,特征已被标记,如下输出所示:
love : 2.25265339223
happiness : 2.28398311347
family : -3.16621250031
horizons : 0.946830830963
action : 2.88757989766
violence : -3.05188501936
A value>0 is positive, close to 0 slightly positive
A value<0 is negative, close to 0 slightly negative 
我们可以看到,除了标准的电影分类之外,X 喜欢一些广阔的视野,不喜欢暴力,并且喜欢动作片。X 认为幸福和爱情很重要,但目前并不看重家庭。
RBM 已为 X 提供了个人档案——这不是一个预测,而是通过聊天机器人准备好建议,或者只是构建 X 的机器心智数据集。
我们已从数据集中提取了主要特征,并使用 RBM 对其进行处理。接下来的步骤是将权重作为特征向量用于 PCA。
使用 RBM 的权重作为 PCA 的特征向量
在这一部分,我们将编写一个增强版的 RBM_01.py。RBM_01.py 生成了一个名为 X 的观众的特征向量。现在的目标是提取 12,000 个观众的特征向量,例如,为主成分分析(PCA)提供足够数量的特征向量。
在 RBM_01.py 中,首先在矩阵中提供了观众 X 喜欢的电影。现在的目标是生成 12,000 个观众特征向量的随机样本。
当前的任务是创建一个 RBM 启动器,运行 RBM 12,000 次,以模拟随机选择观众及其喜欢的电影,即观众喜欢的电影。然后,每个观众的特征向量将被存储。
RBM_launcher.py 首先将 RBM 导入为 rp:
import RBM as rp 
RBM_launcher.py 的主要目标是执行运行 RBM 的基本功能。一旦 RBM 被导入,特征向量的 .tsv 文件将被创建:
#Create feature files
f=open("features.tsv","w+")
f.close 
当调用导入的 RBM 函数 rp 时,它将附加特征文件。
下一步是创建包含元数据的标签文件:
g=("viewer_name"+"\t"+"primary_emotion"+"\t"+"secondary_emotion"+
    "\n")
with open("labels.tsv", "w") as f:
    f.write(g) 
你会注意到“情感”一词的使用。在这里,“情感”指的是情感分析的特征,而不是特指人类情感。在此背景下,请将“情感”理解为情感分析特征。
现在,我们准备运行 RBM 12,000 次以上,例如:
#Run the RBM feature detection program over v viewers
print("RBM start")
vn=12001
c=0
for v in range (0,vn):
    rp.main()
    c+=1
    if(c==1000):print(v+1);c=0;
print("RBM over") 
rp.main() 调用了 RBM.py 中的 main() 函数,我们将增强此函数以适应当前的过程。
我们将逐步在另一个名为 RBM.py 的文件中增强 RBM_01.py。我们将从第 65 行开始调整代码,创建一个 RBM 启动器选项:
一个名为 pt 的变量被设置为 0 或 1,取决于是否希望显示中间信息:
 # RBM_launcher option
    pt=0  #restricted printing(0), printing(1) 
由于这是一个自动化过程,pt 设置为 0。
10 部电影的元数据存储在 titles 中:
 # Part I Feature extractions from data sources
    # The titles of 10 movies
    titles=["24H in Kamba","Lost","Cube Adventures",
            "A Holiday","Jonathan Brooks",
             "The Melbourne File", "WNC Detectives",
             "Stars","Space L","Zone 77"] 
从第 71 行开始,创建了一个包含每部电影六个特征的电影特征矩阵,其特征与 RBM_01.py 中的特征相同:
 # The feature map of each of the 10 movies. Each line is a movie.
    # Each column is a feature. There are 6 features: ['love', 'happiness', 'family', 'horizons', 'action', 'violence']
    # 1= the feature is activated, 0= the feature is not activated
    movies_feature_map = np.array([[1,1,0,0,1,1],
                                   [1,1,0,1,1,1],
                                   [1,0,0,0,0,1],
                                   [1,1,0,1,1,1],
                                   [1,0,0,0,1,1],
                                   [1,1,0,1,1,0],
                                   [1,0,0,0,0,0],
                                   [1,1,0,1,1,0],
                                   [1,1,0,0,0,1],
                                   [1,0,0,1,1,1],
                                   [1,1,0,0,1,0],
                                   [1,1,0,1,1,1],
                                   [1,1,0,0,1,1]]) 
矩阵的每一行包含一部电影,每一列代表该电影的六个特征之一。如果值为0,表示该特征不存在;如果值为1,表示该特征存在。
在未来几年,每部电影的特征数量将扩展为无限数量,以进一步优化我们的偏好。
创建一个空的输出矩阵。在RBM_01.py中,结果已经给出。在这个例子中,它将被随机选择填充:
 #The output matrix is empty before the beginning of the analysis
    #The program will take the user "likes" of 6 out of the 10 movies
    dialog_output = np.array([[0,0,0,0,0,0],
                              [0,0,0,0,0,0],
                              [0,0,0,0,0,0],
                              [0,0,0,0,0,0],
                              [0,0,0,0,0,0],
                              [0,0,0,0,0,0]]) 
现在,随机电影选择器将为每部电影和每位观众生成喜欢或不喜欢的选择:
 #An extraction of viewer's first 6 liked 6 movies out n choices
    #Hundreds of movies can be added. No dialog is needed since a cloud streaming services stores the movie-likes we click on
    mc=0   #Number of choices limited to 6 in this example
    a="no" #default input value if rd==1
    #for m in range(0,10):
    if pt==1:print("Movie likes:");
    while mc<6:
        m=randint(0,9)# filter a chosen movie or allow (this case) a person can watch and like a movie twice=an indication
        b=randint(0,1)# a person can like(dislike) a movie the first time and not the second(or more) time
        if mc<6 and (a=="yes" or b==1):
            if pt==1:print("title likes: ",titles[m]);
            for i in range(0,6):dialog_output[mc,i]=
                movies_feature_map[m,i];
            mc+=1
        if mc>=6:
            break 
我们可以选择是否显示输入:
 #The dialog_input is now complete
    if pt==1:print("dialog output",dialog_output); 
对话输出是平台通过其喜欢/不喜欢界面收集的数据。RBM 正在进行训练会话:
 #dialog_output= the training data
    training_data=dialog_output
    r = RBM(num_visible = 6, num_hidden = 2)
    max_epochs=5000
    learning_rate=0.001
    r.train(training_data, max_epochs,learning_rate) 
现在,RBM 训练会话的结果从第 185 行到第 239 行被处理,用以将获得的权重转换为特征向量及相应的元数据:
###Processing the results
    # feature labels
    F=["love","happiness","family","horizons","action","violence"]
    .../...
        control=[0,0,0,0,0,0]
        for j in range(0,6):
            for i in range(0,6):
                control[i]+=dialog_output[j][i]
    ###End of processing the results 
现在的目标是选择由特定观众挑选的某部电影的主要特征。例如,这个特征可以是“爱情”或“暴力”:
 #Selection of the primary feature
    for w in range(1,7):
        if(w>0):
            if pt==1:print(F[w-1],":",r.weights[w,0]);
            tw=r.weights[w,0]+pos
            if(tw>best1):
                f1=w-1
                best1=tw
            f.write(str(r.weights[w,0]+pos)+"\t")
    f.write("\n")
    f.close() 
次要特征同样非常有趣。它通常提供比主要特征更多的信息。观众通常会倾向于观看某一类型的电影。然而,次要特征因电影而异。例如,假设一位年轻观众喜欢动作片。“暴力”可能是主要特征,但在某些情况下,次要特征可能是“爱情”,而在其他情况下则是“家庭”。次要特征存储在该观众的特征向量中:
 #secondary feature
    best2=-1000
    for w in range(1,7):
        if(w>0):
            tw=r.weights[w,0]+pos
            if(tw>best2 and w-1!=f1):
                f2=w-1
                best2=tw 
元数据保存在标签文件中:
 #saving the metadata with the labels
    u=randint(1,10000)
    vname="viewer_"+str(u)
    if(pt==1):
        print("Control",control)
        print("Principal Features: ",vname,f1,f2,"control")
    f= open("labels.tsv","a")
    f.write(vname +"\t"+F[f1]+"\t"+F[f2]+"\t")
    f.write("\n")
    f.close() 
在这个例子中,这个过程将重复 12,000 次。
特征向量features.tsv文件已经创建:

图 14.4:特征向量文件
特征向量labels.tsv元数据文件与特征向量文件匹配:
viewer_name    primary_emotion    secondary_emotion
viewer_8481    love               violence
viewer_3568    love               violence
viewer_8667    love               horizons
viewer_2730    love               violence
viewer_3970    love               horizons
viewer_1140    love               happiness 
你会注意到“爱情”和“暴力”出现得很频繁。这是因为我构建数据集时,大多数选择了包含动作和某种形式的角色之间温馨关系的电影,这在年轻一代的电影中很典型。
现在特征向量和元数据文件已创建,我们可以使用 PCA 来表示这些点。
理解 PCA
PCA 在营销中被 Facebook、Amazon、Google、Microsoft、IBM 和许多其他公司高效应用,此外,还有其他特征处理算法。
面向服装、食品、书籍、音乐、旅游、汽车及其他市场消费者群体的概率机器学习训练仍然非常高效。
然而,人类不仅仅是消费者;他们是有感情的个体。当他们联系网站或呼叫中心时,标准答案或刻板的情感语调分析方法可能会受到一个人神经状态的影响。当人类与医生、律师及其他专业服务人员接触时,若发生重大个人危机,需要一种人情味。
在这种情况下,PCA 的目标是提取关键特征来描述一个个体或一个群体。PCA 阶段将帮助我们建立 X 的心智表示,无论是与 X 沟通,还是将 X 的心智作为一个强大、深思熟虑 的聊天机器人或决策者来使用。
PCA 不是一个简单的概念,所以我们需要花些时间来正确理解它。我们将从一个直观的解释开始,然后再深入了解背后的数学原理。
PCA 将数据表示为更高层次的形式。
举个例子,假设你在你的卧室里。房间里有一些书、杂志和音乐(可能在你的智能手机上)。如果你把你的房间看作一个三维笛卡尔坐标系,房间里的物品就会有特定的 x、y、z 坐标。
为了进行实验,将你最喜欢的物品放在你的床上。将你最喜欢的物品放在一起,次喜欢的物品稍微远一些。如果你将你的床想象成一个二维笛卡尔空间,你就刚刚让你的物品改变了维度。你把你最重视的物品带入了更高的维度。现在,它们比那些对你来说价值较小的物品更为显眼。
它们不再处于原来的位置;它们现在在你的床上,并且根据你的兴趣,位于特定的坐标上。
这就是 PCA 的哲学。如果数据集中的数据点数量非常庞大,那么一个人的“心智数据集”的 PCA 总是会与另一个人的 PCA 表示不同,像 DNA 一样。“心智数据集”是一个人思想、图像、文字和情感的集合。它不仅仅是经典的年龄、性别、收入等中性特征。“心智数据集”将带我们走进某个人的内心世界。
这就是概念表示学习元模型(CRLMM)应用于一个人心智表示的方式。每个人都是不同的,每个人都值得拥有一个定制化的聊天机器人或机器人处理。
数学解释
计算 PCA 的主要步骤对于理解如何从直观方法过渡到 TensorBoard 嵌入投影仪使用 PCA 表示数据集非常重要。
方差
方差是指一个值发生变化的情况。例如,夏天太阳升起时,温度逐渐变暖。方差由某一时刻的温度和几小时后的温度之间的差异来表示。协方差是指两个变量一起变化的情况。例如,当我们在外面时,天气越来越热,我们会出更多的汗来使身体降温。
- 
步骤 1:计算数组 data1的均值。你可以通过mathfunction.py来检查这一点,如下所示的函数:data1 = [1, 2, 3, 4] M1=statistics.mean(data1) print("Mean data1",M1)答案是 2.5。均值并不是中位数(数组中的中间值)。 
- 
步骤 2:计算数组 data2的均值。均值的计算是通过以下标准函数实现的:data2 = [1, 2, 3, 5] M2=statistics.mean(data2) print("Mean data2",M2)答案是 ![]() 。X 上方的横线表示它是一个均值。 。X 上方的横线表示它是一个均值。
- 
步骤 3:使用以下方程计算方差: 

现在,NumPy 将通过计算每个 x 减去均值的绝对值,求和并将总和除以 n 来计算方差,代码示例如下:
#var = mean(abs(x - x.mean())**2).
print("Variance 1", np.var(data1))
print("Variance 2", np.var(data2)) 
一些方差根据数据集的总体来计算,使用 n - 1。
程序输出的方差结果如下所示:
Mean data1 2.5
Mean data2 2.75
Variance 1 1.25
Variance 2 2.1875 
我们已经可以看到 data2 的变化远大于 data1。它们是否匹配?它们的方差是否接近?它们是否以相同的方式变化?我们接下来要做的目标是,了解两个词语,举例来说,是否经常一起出现或靠得很近,同时考虑到嵌入程序的输出。
协方差
协方差将告诉我们这些数据集是否一起变化。该方程遵循与方差相同的理念,不过现在两个方差被结合在一起,看它们是否属于同一组:

与方差类似,分母可以是 n - 1,这取决于你的模型。此外,在这个方程中,分子被展开,以便可视化协方差的共同部分,如 mathfunction.py 中的以下数组实现:
x=np.array([[1, 2, 3, 4],
            [1, 2, 3, 5]])
a=np.cov(x)
print(a) 
NumPy 的输出是协方差矩阵 a:
[[1.66666667 2.16666667]
 [2.16666667 2.91666667]] 
如果你增加数据集中的一些值,它将增加矩阵部分的值。如果你减少数据集中的一些值,协方差矩阵的元素将会减少。
观察矩阵中某些元素的增减变化需要时间和观察。如果我们能找到一个或两个值来为我们提供这些信息呢?
特征值和特征向量
为了理解协方差矩阵,特征向量会指向协方差的方向。特征值将表达给定特征的大小或重要性。
总结来说,特征向量将提供方向,特征值则提供协方差矩阵 a 的重要性。通过这些结果,我们将能够在多维空间中使用 TensorBoard 嵌入投影器表示 PCA。
设 w 为 a 的特征值。特征值必须满足以下方程:
dot(a,v)=w * v 
必须存在一个向量 v,使得 dot(a,v) 与 w*v 相同。
NumPy 将通过以下函数来进行计算:
from numpy import linalg as LA
w, v = LA.eigh(a)
print("eigenvalue(s)",w) 
特征值(按升序排列)将在以下输出中显示:
eigenvalue(s) [0.03665681 4.54667652] 
现在,我们需要特征向量来查看这些值应该应用的方向。NumPy 提供了一个函数来同时计算特征值和特征向量。因为特征向量是通过矩阵的特征值计算的,如下代码所示:
from numpy import linalg as LA
w, v = LA.eigh(a)
print("eigenvalue(s)",w)
print("eigenvector(s)",v) 
程序的输出如下所示:
eigenvector(s) [[-0.79911221  0.6011819 ]
 [ 0.6011819   0.79911221]] 
特征值以 1D 数组的形式出现,包含 a 的特征值。
特征向量以二维方阵形式呈现,列中包含相应的值(每个特征值的值)。
创建特征向量
剩下的步骤是将特征值从最高到最低进行排序。最高的特征值将提供主成分(最重要的部分)。与其对应的特征向量将是其特征向量。你可以选择忽略最低的特征值或特征。在数据集中,将会有数百个,甚至通常是数千个特征需要表示。现在我们得到了特征向量:
特征向量 = FV = {特征向量[1],特征向量[2] … n}
n表示可能有更多特征需要转换为 PCA 特征向量。
推导数据集
最后一步是转置特征向量和原始数据集,并将行特征向量与行数据相乘:
显示的数据 = 特征向量行 * 数据行
总结
特征值的最高值是主成分。与其对应的特征向量将决定数据点在乘以该向量后将朝哪个方向排列。
使用 TensorFlow 的嵌入式投影仪表示 PCA
TensorBoard 嵌入式投影仪提供了一个内置的 PCA 功能,可以快速配置以满足我们的需求。TensorBoard 可以作为独立程序调用,也可以嵌入程序中,如我们在第十三章中看到的,使用 TensorFlow 2.x 和 TensorBoard 可视化网络。
我们将提取观众营销细分的关键信息,这些信息将用于开始构建第十五章中的聊天机器人,设置认知 NLP UI/CUI 聊天机器人。
首先,访问此链接:projector.tensorflow.org/
对于以下功能,请记住,TensorBoard 嵌入式投影仪在每个步骤中都在工作,具体时间可能根据你的机器不同而有所不同。我们通过点击加载来加载由RBM_launcher.py和RBM.py生成的数据:

图 14.5:加载按钮
当从计算机加载数据窗口出现时,我们通过点击选择文件来加载特征向量features.tsv文件:

图 14.6:加载特征向量文件
我们通过点击步骤 2(可选)中的选择文件来加载labels.tsv元数据文件:

图 14.7:加载 TSV 文件
为了获得我们 12,000 多个特征的良好表示,请点击球形化数据,默认模式下该选项未勾选:

图 14.8:球形化数据
我们现在选择标签为secondary_emotion,颜色为secondary_emotion,并按secondary_emotion进行编辑:

图 14.9:管理标签
为了获得数据的良好视图,我们激活夜间模式,以使月亮应处于活动状态:

图 14.10:激活夜间模式
此时,我们有一个漂亮的 PCA 表示法,它像地球一样旋转,或者像我们大脑中的想法,或我们正在分析的所有观众的想法,具体取决于我们如何使用这些特征。图像中的点是数据点,表示我们通过 RBM 计算的特征,然后通过 PCA 使用图像进行表示。这就像窥探内心世界:

图 14.11:特征的 PCA 表示法
给定一个人或一组人的特征的 PCA 表示法提供了创建聊天机器人对话的重要信息。让我们分析 PCA,以准备聊天机器人的数据。
分析 PCA 以获取聊天机器人的输入入口点
目标是收集一些信息,以启动我们的认知聊天机器人。我们将使用 TensorBoard 提供的过滤器。
选择secondary_emotion作为我们过滤器的基础:

图 14.12:过滤数据
我们正在分析的特征如下:
F=["love","happiness","family","horizons","action","violence"] 
我们需要查看每个特征的统计数据。
我们在 TensorBoard 的搜索选项中键入特征,如“爱情”,然后点击下拉箭头:

图 14.13:TensorBoard 的搜索选项
PCA 表示法会实时改变其视图:

图 14.14:RBM 特征的 PCA 表示法
“爱情”有 643 个点。注意,“爱情”点位聚集在一个相对令人满意的位置。它们大多集中在图像的同一区域,而不是分散在整个图像中。这种分组表明,RBM 提供的特征在本次实验的 PCA 中是足够正确的。
我们对每个特征重复该过程,以获取每个特征的点数并进行可视化。在 GitHub 上为本章提供的数据集中,我们得到了:
- 
爱情:643 
- 
幸福感:2267 
- 
Family: 0 
- 
Horizions: 1521 
- 
动作:2976 
- 
暴力:4594 重要:如果再次运行 RBM_launcher.py,该结果会发生变化,因为这是一个随机的观看者电影选择过程。
结果提供了关于我们为聊天机器人所针对的营销领域的有趣信息:
- 
暴力和动作指向动作电影。 
- 
Family=0 表示更年轻的观众;例如,青少年更感兴趣的是动作而不是创建家庭。 
- 
发现幸福感和爱情是他们正在寻找的视野的一部分。 
这通常出现在超级英雄系列和电影中。超级英雄通常是孤独的个体。
我们将在第十五章中看到如何构建聊天机器人并实现此目标,设置认知 NLP UI/CUI 聊天机器人。
总结
在本章中,我们准备了创建聊天机器人输入对话框的关键信息。使用 RBM 的权重作为特征是第一步。我们看到,可以使用神经网络从数据集中提取特征,并通过优化的权重进行表示。
处理电影观众的喜好/不喜欢可以揭示电影的特征,这些特征进一步提供了一个市场细分的心理表征。
将 PCA 与 RBM 链式连接,可以生成一个向量空间,几次点击即可在 TensorBoard 嵌入投影器中查看。
一旦设置好 TensorBoard,我们分析了统计数据,以了解数据集来源的市场细分。通过列出每个特征的点数,我们找出了驱动该市场细分的主要特征。
在发现我们分析的市场细分的一些关键特征后,我们可以进入下一章,开始为观众构建聊天机器人。同时,我们将保持后门可用,以防对话表明我们需要微调特征向量统计数据。
问题
- 
RBM 基于有向图。(是 | 否) 
- 
RBM 的隐藏单元通常是相互连接的。(是 | 否) 
- 
在 RBM 中不使用随机采样。(是 | 否) 
- 
PCA 将数据转换为更高的维度。(是 | 否) 
- 
在协方差矩阵中,特征向量显示了表示该矩阵的向量方向,而特征值显示了该向量的大小。(是 | 否) 
- 
无法在机器中表示人类大脑。(是 | 否) 
- 
机器无法学习概念,这就是为什么经典的应用数学足以为各个领域制作高效的人工智能程序。(是 | 否) 
进一步阅读
- 
想了解更多关于 RBM 的内容,请参考: skymind.ai/wiki/restricted-boltzmann-machine
- 
本章源代码的原始参考网站可以在这里找到: github.com/echen/restricted-boltzmann-machines/blob/master/README.md
- 
原始的 Geoffrey Hinton 论文可以在这里找到: www.cs.toronto.edu/~hinton/absps/guideTR.pdf
- 
想了解更多关于 PCA 的内容,请参考这个链接: www.sciencedirect.com/topics/engineering/principal-component-analysis
- 
可直接使用的 RBM 资源可以在这里找到: pypi.org/project/pydbm/
第十五章:设置一个认知 NLP UI/CUI 聊天机器人
仅 Facebook 上就有超过 30 万个聊天机器人。再加上一块砖石几乎毫无意义,除非你给你的聊天机器人一个目的,并为其提供真实的内容。认知内容代表了吸引比成千上万的竞争者和 SEO 专家更多注意力的核心目标。我们将在本章中使用 RBM-PCA 链式算法,使聊天机器人更上一层楼。我们将使用 RBM-PCA 提供的信息来设计我们的对话。
正如你将在第一部分中发现的那样,使用 Dialogflow 创建一个代理并开始一个对话几乎不需要任何努力。Google Dialogflow 提供了直观的功能,可以在短时间内启动聊天机器人。Dialogflow 的教程可以在几分钟内帮助你实现这个简单目标。理解什么是代理,教它提问并提供答案,这些都能由一个 10 岁的孩子完成。我通过让一个 5 岁和 9 岁的孩子使用这个软件进行了实验。他们甚至没有意识到这是一项工作,他们玩得很开心!
在 Dialogflow 中,你不需要知道如何编程,也不需要是语言学家或其他任何类型的专家。那么,你的市场差异化会是什么呢?内容。你的聊天机器人需要有一个目的,提供精心准备的内容,而不仅仅是问答简单问题。
除了创建你的第一个对话框,本章的目标将为你提供一种目的感和内容,这将帮助你制作有意义的聊天机器人。
话虽如此,让我们一起创建一个代理和一个简短的对话,以说明如何创建聊天机器人,同时也提供有意义的内容。
本章将涵盖以下主题:
- 
基于第十四章的准备工作,创建一个认知代理,使用限制玻尔兹曼机(RBMs)和主成分分析(PCA)准备聊天机器人的输入 
- 
学习 Dialogflow 和聊天机器人的基本概念 
- 
将聊天机器人部署到你的网站上 
我们将从基本概念开始,然后创建一个包含实体、意图、对话和履行功能的代理。我们将使用上一章中建立的准备工作。我们将通过拼写修正和对话来测试其 UI。然后,我们将通过设置机器学习语音识别和语音功能来测试聊天机器人的对话用户界面(CUI)能力。
基本概念
在创建代理之前,我们需要了解基本概念。
这不是一个 Dialogflow 课程,而是一个入门章节,帮助我们开始制作自己的 NLP CUI 聊天机器人。我们将从定义一些关键术语开始。
定义 NLU
NLU 代表 自然语言理解。NLU 是 自然语言处理(NLP)的一个子集。自然语言指的是我们日常使用的语言,无需强迫自己学习准确的词汇来从机器中获取信息。
如果我们必须学习一个仅包含能与系统兼容的词汇的字典,那么直接阅读文本会更容易。自然语言处理(NLP)涵盖了所有形式的自然语言处理,包括自然语言理解(NLU)。通过人工智能,NLU 在尝试理解给定句子的意思方面变得更加深入。
为什么我们称聊天机器人为“代理”?
聊天机器人是指至少有两方参与的对话。在我们的例子中,机器人是一个 NLU 模块。虽然这么说并不算是一个很吸引人的营销方式,它听起来像是:“你现在正在与一个 NLU 模块对话。”你不能假装一个机器人是一个人。代理 这个词传递了商务代理、体育经纪人或特工的印象,这听起来很神秘!它的含义是指一个收集信息的计算机系统。现在,它是一个具备 NLU 能力的 NLP 代理。
创建一个代理以了解 Dialogflow
学习 Dialogflow 的最快方法是从头开始创建一个对话。登录 Dialogflow 并进入控制台。以下是 Dialogflow 仪表板的一个截图,你可以看到右上角有控制台的链接:

图 15.1:访问 Dialogflow 控制台
一旦点击 转到控制台,如果你尚未登录系统,将要求你登录。拥有 Google 账号是前提条件:

图 15.2:使用 Google 账号登录
按照登录指引操作并成功登录后,你将进入 Dialogflow 控制台。
点击右上角的下拉菜单,不论当前显示的是哪个默认代理。会显示现有的或默认的代理列表:

图 15.3:代理列表
向下滚动列表,直到你看到 创建新代理(如果没有此选项,请点击 创建代理)。点击 创建新代理,你将进入以下窗口:

图 15.4:输入代理的名称
将代理命名为 Agent + <你的名字或首字母>,以确保你将拥有一个唯一的名字。我将本章的代理命名为 cogfilmdr。因此,本章中的代理将被称为 cogfilmdr。让 Google 创建一个默认的代理结构,主语言为英语。
完成后,点击左上角的设置按钮:

图 15.5:设置按钮
你将进入你的代理配置窗口。
目前,我们只有一个重要的选项需要检查。API 的版本必须是 V2 API。V1 API 将于 2020 年 3 月停止使用:

图 15.6:使用 V2 API
代理已经创建,我们可以开始创建实体。
实体
大多数聊天机器人教程首先讲解意图。我不同意这个做法。一旦你知道你的目标,在这种情况下是根据第十四章的内容,选择一部电影,使用限制玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人的输入,那么在构建结构之前,先搭建一些砖块是很有道理的。
Dialogflow(或任何聊天机器人)使用实体从用户的发言中提取有用的信息(不一定是一个句子)来理解他们的动机。
我们将使用第十四章中创建的实体。我们将首先创建一个名为movies的实体,其中包含在第十四章中使用的 10 部目标电影。
 titles=["24H in Kamba","Lost","Cube Adventures",
            "A Holiday","Jonathan Brooks",
            "The Melbourne File", "WNC Detectives",
            "Stars","Space L","Zone 77"] 
在窗口左侧点击Entities:

图 15.7:Dialogflow 菜单
然后,点击CREATE ENTITY:

图 15.8:创建一个实体
你将被要求提供一个实体名称:

图 15.9:输入实体名称
输入movies。在保存实体之前,我们必须输入我们选择的电影:

图 15.10:实体列表
你会注意到,一旦你添加了一个电影,默认的同义词会自动填充。如果你愿意,可以添加其他同义词。
一旦输入标题,点击SAVE按钮,这是必须的(这不是自动保存接口):

图 15.11:保存实体
我们现在将创建特征实体。在第十四章中的RBM.py程序中的特征如下:
# Each column is a feature. There are 6 features: ['love', 'happiness', 'family', 'horizons', 'action', 'violence'] 
我们将它命名为features,按照与movies实体相同的过程,然后点击SAVE:

图 15.12:创建一个特征实体
点击代理下方的Entities,你将看到代理的实体列表,如下图所示:

图 15.13:实体列表
如果你点击一个实体,会出现可能的选择列表。
现在你的代理已经知道了电影和特征实体,创建意图就有意义了。
意图
一个意图是明确的意图,表示要做某件事。我将代理命名为cogfilmdr。对于这个代理,用户的意图可能是请求推荐一部电影。
要触发响应,我们必须输入训练短语。
训练短语是用户通过文本或语音输入的一组词汇。你输入的句子越多,你的聊天机器人就会越智能。这就是为什么如果现有的代理满足你的需求,从一个现成的 Dialogflow 开始是有意义的。
为了创建我们的示例对话,我们将使用 GitHub 上提供的第十四章的数据集结果,使用限制玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人的输入。主要术语已经提取,并显示了其特征,这些特征我们用 TensorBoard 进行了展示。当我们从 RBM 中提取数据时,我们按照以下方式对特征进行了排序:
Love: 643
Happiness: 2267
Family: 0
Horizons: 1521
Action: 2976
Violence: 4594 
我们在 PCA 中展示了特征空间:

图 15.14:特征的 TensorBoard 表示
提醒:如果RBM_launcher.py再次运行,这个结果会自然改变,因为它是一个随机的观众-电影选择过程。
在开始聊天机器人项目时,最好非常小心,不要直接跳到自动生成对话的阶段。最好从一个简单且结构良好的聊天机器人开始,它仅执行有限数量的任务。我称之为“封闭型聊天机器人”,意味着我们控制对话的每个方面。“开放型聊天机器人”意味着信息会自动流入,从而创建自动对话。这可以作为目标,在聊天机器人作为“封闭型聊天机器人”运行一段时间后,利用 AI 算法准备的信息创建自动对话。
我们在第十四章所做的工作结果提供了关于我们为聊天机器人目标市场所针对的营销细分的有趣信息。
暴力和动作指向动作片。家庭=0 指向年轻观众,比如青少年,他们更感兴趣的是动作而不是创建一个家庭。发现幸福和爱是他们正在寻找的目标之一。这在超级英雄系列和电影中非常典型。超级英雄往往是孤独的个体。
我们现在将通过进入意图窗口来创建一个意图:

图 15.15:选择意图选项
意图窗口出现。点击创建意图:

图 15.16:创建意图
意图窗口会出现,几步之内就能创建一个问答对话:
- 
首先,输入 choose_movie作为意图名称。
- 
然后,在训练短语部分,输入:“我想看你们的一部电影。” 
到此为止,我们有了一个意图名称和一个可能的用户问题:

图 15.17:输入意图信息
现在,我们需要根据从第十四章中获取的该市场细分的统计数据来提供响应。我们将使用动作这个词来涵盖那些包含暴力和幸福结局的电影,就像典型的超级英雄电影一样。为此,请滚动到文本响应部分,添加响应并输入“你想看一部动作片吗?”,如下图所示:

图 15.18:输入文本响应
现在我们已经有了一个基本的对话,接下来保存并测试它。为此,请前往控制台窗口右上角的测试控制台:

图 15.19:测试控制台
我们可以使用 CUI 或文本:
- 
文本对话:输入用户短语:“我想看你们的一部电影。” 用户会对代理人的回答感到惊讶:“你想看一部动作片吗?” 

图 15.20:响应
这个建议对用户来说是一个惊喜,可能看起来有些奇怪。这是因为我们用来准备对话的 RBM-PCA 方法是针对一个市场细分的。
高级机器学习缩短了用户请求到满意回应的路径。它为用户节省了时间和精力。
- CUI:点击测试控制台中的麦克风图标。确保麦克风已授权,否则它将无法工作:

图 15.21:麦克风
当你点击麦克风时,这将触发对你请求的录音。说:“我想观看你的一部电影。”然后,点击停止按钮来停止录音。请求的回应将显示:

图 15.22:文本回应
为了回答这个问题,我们需要使用 Dialogflow 的上下文功能。
上下文
上下文意味着 Dialogflow 将记住对话,并使用后续交流,而不必每次从头开始。
用户请求观看一部电影,而机器人建议了一部动作片。机器人会通过上下文记住这一点,并继续对话。
点击菜单中的代理意图,然后悬停在选择电影上。你将看到添加后续意图出现。这意味着主意图的所有变量都可以存储,并且可以添加一个后续意图,记住之前说过的话,就像我们在对话中一样。
点击添加后续意图:

图 15.23:添加后续意图按钮
在这种情况下,代理已经计划了两个选项,是或否。我们将在本章探讨是的答案,而更复杂的否的答案将在第十六章,“提高聊天机器人情商缺陷”中讨论。
在第十四章中,我们创建了一个电影特征矩阵,包含了电影标题和特征:
 # Part I Feature extractions from data sources
    # The titles of 10 movies
    titles=["24H in Kamba","Lost","Cube Adventures",
            "A Holiday","Jonathan Brooks",
            "The Melbourne File", "WNC Detectives",
            "Stars","Space L","Zone 77"]
    # The feature map of each of the 10 movies. Each line is a movie.
    # Each column is a feature. There are 6 features: ['love', 'happiness', 'family', 'horizons', 'action', 'violence']
    # 1= the feature is activated, 0= the feature is not activated
    movies_feature_map = np.array([[1,1,0,0,1,1],
                                   [1,1,0,1,1,1],
                                   [1,0,0,0,0,1],
                                   [1,1,0,1,1,1],
                                   [1,0,0,0,1,1],
                                   [1,1,0,1,1,0],
                                   [1,0,0,0,0,0],
                                   [1,1,0,1,1,0],
                                   [1,1,0,0,0,1],
                                   [1,0,0,1,1,1],
                                   [1,1,0,0,1,0],
                                   [1,1,0,1,1,1],
                                   [1,1,0,0,1,1]]) 
我们现在需要将这些信息转置到一个可以用来为对话添加内容深度的图表中:
| 电影/特征 | 爱情 | 幸福 | 家庭 | 视野 | 动作 | 暴力 | 
|---|---|---|---|---|---|---|
| 24 小时在坎巴 | 1 | 1 | 0 | 0 | 1 | 1 | 
| 丢失 | 1 | 1 | 0 | 1 | 1 | 1 | 
| 立方体冒险 | 1 | 0 | 0 | 0 | 0 | 1 | 
| 假期 | 1 | 1 | 0 | 1 | 1 | 1 | 
| 乔纳森·布鲁克斯 | 1 | 0 | 0 | 0 | 1 | 1 | 
| 墨尔本档案 | 1 | 1 | 0 | 1 | 1 | 0 | 
| WNC 侦探 | 1 | 0 | 0 | 0 | 0 | 0 | 
| 星星 | 1 | 1 | 0 | 1 | 1 | 0 | 
| 太空 L | 1 | 1 | 0 | 0 | 0 | 1 | 
| 区域 77 | 1 | 0 | 0 | 1 | 1 | 1 | 
我们已经通过直接提议一部动作片来稍微惊讶了用户,而无需通过冗长的列表。我们正在使用所有通过输入、中间 AI 输出和最终输出获得的信息。
现在,我们通过使用 RBM-PCA 链式算法提取的动作-暴力-幸福特征,进一步筛选符合这些特征的电影。
图表中只有以下电影符合动作-暴力-幸福特征:
- 
24 小时在坎巴 
- 
丢失 
- 
假期 
- 
区域 77 
我们会随机选择“Zone 77”。一旦我们输入了许多可能性,可以在回应区域或通过脚本提出随机选择。这个开发超出了本章的范围。在这个例子中,我们假设观众会对我们提出的建议感到满意。我们处于对话的yes场景中。在第十六章《提高聊天机器人的情商缺陷》中,我们将探索这个对话的no场景,这需要更多的认知设计来保持满意度路径的简短。
目前,让我们建议“Zone 77”。为此:
- 
点击添加后续意图。 
- 
选择yes。 
现在,你有了一个与对话关联的后续意图:

图 15.24:后续意图
点击choose_movie - yes。意图将会出现。你会注意到,Dialogflow 已经在训练短语部分填写了几个yes的形式,如下图所示:

图 15.25:训练短语
在这种情况下,剩下的工作就是滚动到回应部分并添加我们的回答:

图 15.26:文本回应
现在,我们回到意图,并为这个后续添加一个yes后续,用来处理观众的yes回答,就像我们之前做的一样:

图 15.27:后续意图
现在,我们点击choose_movie - yes - yes,我们将看到 Dialogflow 为我们准备的yes回答:

图 15.28:后续意图的训练短语
然而,这次我们希望用脚本来回答,而不是我们手动输入的回答。
为了实现这一点,我们可以使用履行。
向代理添加履行功能
对话在日常生活中很容易变得无聊,尤其是在聊天机器人中。当我们开始猜测对方要说什么时,我们的大脑会慢慢漂移开来。我们无法控制。人类是一个好奇的物种。履行将改变对话的视角。这就是我所说的超越实用方法的目标,它表示履行将商业逻辑添加到对话中。
为了使对话具备可持续性,即使从实际角度来看,它也必须足够吸引用户,让用户想要回来,探索更多关于你的聊天机器人的内容,而不仅仅是获取业务信息。
如果你查阅字典中的fulfilling,你会发现它的意思是提供幸福或满足感,这正是你希望你的聊天机器人传达的目标感。
话虽如此,为了达到这一目标,还需要做一些工作。Dialogflow 提供了多种工具,帮助用户、设计师和开发人员实现履行。
一开始,Dialogflow 使用内置的、无缝的 Node.js 版本来实现履行功能。
定义履行
提供各种履行或附加对话功能:
- 
Webhook:Webhook 是通过 HTTP 传输的事件。它作为一个 POST发送,其中包含发送到预定 URL 的数据。它作为 HTTP 回调工作。发送到该 URL 的数据将由服务器端的脚本进行解析。一旦服务处理完信息,它将执行某个操作并将数据作为响应发送回来。我们在这个示例中不会使用 webhook。然而,需要注意的是,你可以使用 webhook 在另一个环境中创建自己的对话。你甚至可以生成自动对话并从 Dialogflow 调用它们。 如果你有兴趣准备对话并上传它们,你可以转到屏幕左侧代理的训练页面并上传短语: 

图 15.29:训练窗口
你还可以上传代理,甚至是由 Google Dialogflow 设计的预构建代理。对于我们的示例,我们将使用内联编辑器。
- 
使用内联 Node.js 编辑器进行履行:定义一个 webhook URL 可能是最简单的方法。然而,使用内联编辑器提供了 Node.js 功能,带来更多潜力。 
- 
使用内联 Node.js 编辑器和 Firebase Cloud Functions 进行履行:内联 Node.js 可以在几行节省时间的代码中调用大量 Firebase Cloud Functions。 
使用履行 webhook 增强 cogfilmdr 代理
当用户回答是想观看《Zone 77》时,我们可以用回应或链接到网站来回答。要使用回应,请转到意图窗口中的 yes - yes 后续对话:

图 15.30:意图和后续意图
点击choose_movie - yes - yes并向下滚动到文本响应,然后添加类似“好的,点击电影并观看”的回应,如下图所示:

图 15.31:文本响应
我们还可以通过激活将此意图设置为对话结束选项来决定这是最终的,并且是对话的结束:

图 15.32:对话结束选项
但我们现在不会这样做;让我们继续向下滚动,激活内联 webhook 功能:

图 15.33:启用 webhook 功能
现在我们将进入履行窗口:

图 15.34:访问履行界面
首先,启用内联编辑器:

图 15.35:内联编辑器
为了给对话增添一些趣味,假设聊天机器人在一个酷炫的创业咖啡店里,并且在个人屏幕上观看电影是一项吸引顾客的服务。你可以与耳机一起观看电影(你、朋友、家人),例如。我们将这项服务添加到对话中。
我们进入脚本的intentMap并添加一个gotomovie函数:
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
intentMap.set('choose_movie-yes-yes', gotomovie); 
推荐的格式是intentMap.set(<Intent>,<function>)。
完成后,我们现在编写带有我们自己文本和网站链接的函数:
function gotomovie(agent) {
    agent.add('This message is from Coffee Shop movie fans!');
    agent.add(new Card({
    title: 'A blog for Coffee Shops with movies to watch with friends and family',
    imageUrl: 'https://www.eco-ai-horizons.com/coffeeshop.jpg',
    text: 'The button takes you to the movie selection we have\n  Great to have you here! :-)',
    buttonText: 'Click here',
    buttonUrl: 'https://www.primevideo.com/'
    })
    );
} 
现在我们要做的就是点击部署,就完成了!
我添加了一个链接到 Amazon Prime Video,表明您可以使用 IBM Watson、Google、Microsoft、Amazon 等服务来增强您的聊天机器人!
重要:您可以在此编辑器中自定义所有对话,并使用一系列 Google Cloud 函数。天空甚至都不是极限,您可以飞往火星!
以我们的示例为例,一旦脚本被部署,我们会回到对话的开头,直到我们到达这一点,这将带我们到我们希望观看的电影。在此示例中,我只是展示了一个流媒体网站。
您可以在 GitHub 上的dialogflowFulfillment.zip中的CH15获取完整的index.js脚本,并将其复制到编辑器中,而无需导入整个包。
让机器人在您的网站上运行
让我们通过几个点击,在您的网站上运行一个机器人。
- 
向下滚动到集成,选择您希望部署的代理:无论是您自己的代理还是咖啡店代理。 
- 
启用Web 演示选项。 
- 
将显示类似以下内容的嵌入代码: <iframe height="430" width="350" src="img/81298e0c-1acb-44bb-9c68-89666805342a"></iframe>
复制您希望实现它的网站页面上的代码。
要先进行测试,您可以将网址复制到浏览器中并进行测试。
注意:如果您在浏览器中启用该站点的麦克风,您可以使用语音对话。不要忘记通过https访问页面,否则麦克风可能会被阻止。此外,在没有一些额外开发的情况下,无法在此 HTML 页面中激活履行。
然而,您也可以在控制台中点击 Google Assistant,通过几个点击创建一个应用程序,然后将其部署到智能手机和 Google Home 等设备上。如果您创建了一个不错的聊天机器人,您可以让全世界在几个点击内使用它!
机器学习代理
NLP 聊天机器人如果没有机器学习来进行文本识别、语音、句子、语音实体、意图以及对话的其他许多方面,是无法正常工作的。
在本节中,我们将探讨以下内容:
- 
语音转文本 
- 
文本转语音 
- 
拼写修正 
让我们看看如何在这些上下文中应用机器学习。
在聊天机器人中使用机器学习
通常,当我们听到聊天机器人中的机器学习时,我们会想到在对话过程中作为响应运行的机器学习程序。
在本节中,我们将重点介绍机器学习如何用于改进聊天机器人并使其正常工作。
语音转文本
如果没有语音转文本功能,您就无法在像 Google Home 或 Amazon Echo 这样的智能扬声器上实现聊天机器人或任何语音应用。智能扬声器将在未来几年在我们的生活中发挥越来越重要的作用。
点击代理名称旁边的设置按钮,然后点击语音:

图 15.36:语音选项
我们将重点介绍语音识别功能的主要设置:
- 
增强语音模型:这是一个高级机器学习选项,仅限企业版。它展示了语音识别技术的进步。在标准版中,系统已经能够相当不错地工作;而在高级版中,它使用数据记录功能来增强语音识别。 
- 
自动语音适应:这非常有趣,因为此功能使用创建的意图和实体来训练并适应代理对话的语音识别。在免费版中也可以按以下方式激活: 

图 15.37:启用自动语音适应
在离开此界面之前,请保存设置。
语音合成
现在,我们可以进入 语音 标签并启用 自动语音合成 功能。我有一个云账户。如果你在实验室无法激活此功能,我们将使用免费的在线网站测试机器学习算法的可能性和限制。
注意:有一个增强版语音识别模型选项,但你必须升级到企业版才能使用。
点击代理名称旁边的设置按钮,然后点击 语音:

图 15.38:语音选项
我们将首先配置语音合成的主要设置:
- 
代理语言:从 en(English)开始,以覆盖最广泛的受众。然而,值得注意的是,Dialogflow 在多种语言中都能产生不错的语音效果。
- 
语音:在尝试不同的 WaveNet 模型变体之前,先从 Automatic开始。WaveNet 模型通过神经网络从零开始构建语音。
- 
语速:你可以将其保持在 1,或者加速语速或减慢语速。例如,对于体育解说,语速可以更快。
- 
音调:你可以将语音的音高调整为高音或低音。 
- 
音量增益:你可以调整音量大小,最好的做法是初始时将其设置为 0。然后,在测试代理时,看看是否需要调整。
设置好这些参数后,保存模型:

图 15.39:语音配置
现在,通过输入一句话并点击 播放 按钮,测试你的配置或尝试不同的设置:

图 15.40:尝试不同的语音设置
一旦完成语音参数的设置,我们需要设置拼写机器学习功能。
拼写
在我们探索 Google 提供的机器学习算法的可能性和限制之前,剩下的一步是需要激活机器学习拼写功能。
为此,我们将点击 ML 设置 标签,激活 自动拼写修正,并定义一个可接受的阈值,低于此值,我们的代理将拒绝识别错误。
点击代理名称旁边的设置按钮,然后点击 ML 设置:

图 15.41:ML 设置标签
你将有多种选项来解决用户的拼写错误。它的工作方式类似于搜索引擎的拼写校正,当我们输入错误时,例如 Google 会建议正确的拼写。
选项如下:
- 
机器学习分类阈值确定一个信心分数,低于该分数时,意图将不会被触发,除非存在回退意图(一个通用响应)。 
- 
自动拼写校正使用机器学习来纠正用户的拼写错误。它应该被激活。 
- 
自动训练可能会减慢对话速度,因此建议谨慎使用此功能。 
- 
代理验证在训练过程中自动验证代理。请注意,每次保存一个意图时,训练都会被触发,例如。 
以下截图展示了你可能希望开始使用的默认值:

图 15.42:机器学习设置选项
每次更改选项时,请点击训练按钮。
为什么这些机器学习算法很重要?
如果它只是一个教育类聊天机器人,例如 cogfilmdr 代理示例,错误是可以接受的。这虽然令人不悦,但可以接受。正如我们在第十六章《提高聊天机器人的情感智能缺陷》中看到的那样,如果聊天机器人将被大量用户使用,这意味着需要多天的训练、测试以及为这些功能的机器学习限制创造解决方法。而这仅仅是针对一种语言!
如果我们部署多种语言,这意味着需要很多天,乘以语言数量!即使是机器学习,工作也非常艰难。没有机器学习的话,那就不可能完成。
机器学习不仅仅重要,它是至关重要的:
- 
如果聊天机器人无法识别因为简单拼写错误而出现的书面话语,我们会收到投诉、差评,搜索引擎优化的船也会沉没。 
- 
如果聊天机器人无法识别你在 Google Home 或任何智能音响上的语音,那就意味着很多麻烦,甚至可能需要退款。 
- 
如果聊天机器人的回答听起来像一个 20 世纪的机器人假声音,那么没有人会愿意使用它。 
聊天机器人中的机器学习将持续存在,但在情感智能方面仍有改进的空间,正如我们将在下一章中探讨的那样。
总结
Google Dialogflow 提供了一整套工具,允许你在 Google Cloud 上构建聊天机器人,为其添加服务,并通过你的认知程序进行自定义。
一个好的聊天机器人符合需求。在开发之前思考架构,避免模型的欠拟合(功能不足)或过拟合(不会使用的功能)。
精心准备的人工智能,如第十四章《使用限制玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人输入》中所展示的,为聊天机器人提供了坚实的基础,通过使对话从开始到目标的路径更短且高效。
确定正确的意图(聊天机器人需要完成的任务)、确定描述意图的实体(短语和词语的子集),以及创建恰当的对话将需要相当长的时间。
如果需要,添加服务和特别定制的机器学习功能将提升系统的质量。具有语音识别、语音对话和拼写纠正功能的 CUI 使聊天机器人使用起来更加流畅。
我们在本章构建的对话基于是的答案。我们假设在第十四章中使用 RBM 和 PCA 生成的概率是正确的。然而,人类并不容易被固守在刻板印象中。
第十六章,改善聊天机器人情商不足,通过基本概念、Dialogflow 功能和认知方法来探讨情商,从而提升聊天机器人的内容。
问题
- 
聊天机器人能像人类一样沟通吗?(是 | 否) 
- 
聊天机器人一定是人工智能程序吗?(是 | 否) 
- 
聊天机器人仅需要语言进行沟通。 (是 | 否) 
- 
人类仅仅用语言聊天吗?(是 | 否) 
- 
人类只用语言和数字思考。 (是 | 否) 
- 
构建认知型聊天机器人需要精心的机器学习准备。 (是 | 否) 
- 
为了使聊天机器人发挥作用,需要规划对话流程。 (是 | 否) 
- 
聊天机器人具备通用人工智能,因此无需预先开发。 (是 | 否) 
- 
除了翻译 API 外,聊天机器人没有其他功能也能很好地进行翻译。 (是 | 否) 
- 
在大多数情况下,聊天机器人已经能够像人类一样进行对话。 (是 | 否) 
深入阅读
- 
关于 Google Dialogflow 的更多信息,请参考此链接: dialogflow.com/
- 
关于聊天机器人和 UI 开发的更多信息,请参考此链接: www.packtpub.com/application-development/hands-chatbots-and-conversational-ui-development
第十六章:提升聊天机器人的情感智能缺陷
情感依然是非理性和主观的。AI 算法从不放弃理性和客观性。由此产生的认知失调,使得生产一个高效的聊天机器人变得更加复杂。
在第十四章,使用限制玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人输入中,我们构建了一个理性的链式算法流程,结合了 RBM 和 PCA 方法。由此,我们提取了一个市场细分的关键客观数据。根据这个市场细分及其特征,我们设计了第十五章,设置认知 NLP UI/CUI 聊天机器人中的对话。该对话是理性的,我们为用户提供了一个可能的服务选择。我们是出于善意来做这一切,希望能尽可能缩短从请求到结果的路径。这是一个是的路径,一切顺利进行。
在本章中,我们将面对人性带来的意外反应。否的路径将挑战我们的对话。我们面临的问题之一是情感的多义性,用户的情感信号容易混淆。
我们将通过从第十四章,使用限制玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人输入和第十五章,设置认知 NLP UI/CUI 聊天机器人中获取的信息,来应对否的意外路径,并进入数据记录的世界。
数据记录将提供关键的背景数据,以满足用户需求。目标将是创造情感,而不仅仅是随机地对用户的情感状态做出反应。
最后,我们将开启通过 RNN-LSTM 方法自动生成文本的研究之门。这个想法是基于数据记录,未来创造自动对话。
本章将涉及以下主题:
- 
情感多义性 
- 
闲聊 
- 
数据记录 
- 
创造情感 
- 
探索 RNN-LSTM 方法 
我们将首先探讨简单地对情感做出反应与创造情感之间的区别。
从对情感的反应,到情感的创造
设计一个能够对用户表达做出反应的聊天机器人是一回事。但像人类一样在对话中创造情感则需要更深入地理解聊天机器人如何管理情感。让我们从情感的多义性开始。
解决情感多义性问题
我们将通过解决情感的多义性问题来增强聊天机器人的情感智能。我们习惯于用词语来定义多义性,而不是情感,因为多义性是指一个词可以有多个含义。在第六章,如何使用决策树增强 K 均值聚类中,我们探讨了“coach”这个词带来的困惑。“Coach”可以指巴士或体育教练,这导致了英语到法语翻译的问题。
多义性同样适用于人工智能对情感的解读。我们将通过两个例子来探索这一领域:问候语和肯定语。
然后,我们将深入探讨语音识别和面部分析作为“灵丹妙药”解决方案的谬误,这些谬误误导我们认为面部表情的情感解读很简单。
问候问题示例
要实现这一章节,请打开 Dialogflow,进入在第十五章,设置认知 NLP UI/CUI 聊天机器人中创建的名为cogfilm+<你的唯一 ID>的代理。
假设某人向聊天机器人发送"嗨"。几乎每个人都会认为这是一个好的开始。但真的如此吗?
让我们探讨一些可能的解释:
- 
"嗨"意味着这个人非常紧张和烦躁:这可能是一个高层经理,从不使用"嗨"来打招呼,不喜欢聊天机器人,或者怀疑正在测试的这个机器人是否有任何价值。 这个经理通常会说:"早上好"、"下午好"和"晚上好"。 
- 
"嗨"意味着"那又怎样?":这更像是"嗯,嗨"。这可能是一个人 P,讨厌刚刚对他说"早安"的 Q。 
- 
"嗨",意味着"我有麻烦了":这可能是一个通常很开朗、快乐的人,他们说:"大家好,今天一切还好吗?" 但是今天,他们只是简单地说了一个"嗨"。这会引起其他人的警觉反应,比如"你还好吗?" "发生了什么事吗?" 
- 
"嗨",意味着"我在试图友好":这可能是一个通常早上脾气暴躁、坐下来盯着笔记本直到咖啡因起作用的人。但今天,这个人完全精神饱满,清醒过来并说:"嗨"。这可能引发其他人的警觉反应,比如"某人昨晚过得很愉快!我错了吗?"并伴随着一些笑声。 
我可以继续列举成百上千种其他"Hi"的使用情况。为什么?因为人类有无数的行为可以反映在与他人初次见面时的那个"Hi"中。
这也适用于没有说"再见"或以多种方式说再见的情况。一个人在早晨和别人告别的方式可以有非常多的含义。
因此,这也是我们面临的挑战之一。在进一步探讨之前,让我们再看一个挑战,考虑一下确认示例。
确认示例
假设某人向聊天机器人发送或说"是的"。这真的是"是的"吗?
- 
"是的",就像"随便吧":用户讨厌这个聊天机器人。对话很无聊。用户想,如果他们不说"是的"然后赶快结束,这段对话会一直持续下去。 
- 
"是的",就像"我不敢说不一样":用户并不想说"是的"。问题可能是:"你对你的工作满意吗?" 用户可能担心答案被记录和监控。用户害怕受到制裁。尽管这个人讨厌他们的工作,回答仍然会是"是的",或者甚至可能是"我当然喜欢!" 
- 
“Yes”作为一个善意的“是”,但在之后让人后悔:一个人对购买说“是”,是因为聊天机器人中广告的压力。但几分钟后,那个同样的人会想:“我怎么会说是并买了这个?”因此,一些平台允许在产品或服务交付之前就进行退款。 
就像“Hi”一样,我可以列出数百个情感多义性的情况,涉及“Yes”。
现在,既然我们已经理解了眼前的挑战,让我们来探讨一下之前提到的银弹谬论。
语音识别的谬误
许多编辑和开发者相信,语音识别通过检测语音的语气可以解决情感智能的问题。
然而,情感多义性同样适用于语气。人类在感到威胁时往往会隐藏情绪,而在信任环境时则会敞开心扉。
让我们回到“Hi”和“Yes”的例子。
用兴奋的语气说“Hi”:例如,一个人 X 进入办公室。有人说:“哦,嗨!很高兴见到你!”人 Y 用非常开心的语气回答“Hi”。谷歌 Home 或亚马逊 Alexa 在他们的研究实验室中会生成 0.9 的概率,认为对话进行得很顺利。
这可能是真的,也可能是假的。
例如,Y 讨厌 X。X 知道这一点并故意说:“很高兴见到你!”Y 知道 X 知道他们彼此讨厌,但不会先爆发情绪。所以 Y 用非常开心的语气回答“Hi”。
在那时,许多人转向面部分析。
面部分析的谬误
情感多义性也适用于面部分析。许多人认为深度学习面部分析可以解决多义性的问题。
我最近看到一篇开发者的帖子,帖子里有一张显然是强迫微笑的照片,配文说幸福感可以通过深度学习面部分析来检测!
让我们来看看两种基本的面部表情并探讨它们:微笑和皱眉。到现在为止,你应该知道情感多义性同样适用于这两种情况。
一种微笑
如果有人微笑,并且深度学习(DL)面部分析算法检测到这个微笑,意味着这个人很高兴。这是真的吗?也许是真的,也许不是。
也许这个人真的很高兴。也许这个微笑是讽刺的,意味着“是的,当然,梦想一下,如果你愿意,但我不同意!”它也可能意味着“给我让开”或者“我很高兴因为我要伤害你”或“我很高兴见到你”。谁知道呢?
事实上,没人知道,有时甚至连微笑的人自己也不知道。有时一个人会想:“我为什么要对她/他微笑?我讨厌她/他!”
一种皱眉
如果有人皱起眉头,并且深度学习面部分析算法检测到这个皱眉,这意味着这个人感到悲伤或不高兴。这是真的吗?也许是真的,也许不是。
也许这个人那天很高兴,事情进展顺利,而这个人可能只是忘记了带一本书,比如,来到这个地点之前把书忘在了家里。也许就在下一秒,这个人会微笑,心想:“那又怎么样?今天真是个好日子,我根本不在乎!”
也许这个人不高兴。也许这个人正在愉快地看某种球赛,而他们最喜欢的球员错过了某个机会。紧接着,这个人想:“哦,那又怎样?反正我的队伍在赢,”然后笑了起来。有些人在思考时会皱眉,但这并不意味着他们不高兴。
我们现在可以看到,词语、语调和面部表情上存在成千上万种情感多义性的案例,因此没有什么神奇的解决方案可以突然克服人工智能在解读人类情感时所面临的固有困难。
我们现在将探讨一些现实的解决方案。
小对话
小对话根本不是解决聊天机器人情商问题的灵丹妙药。事实上,即使不谈论聊天机器人,我们在某种情况下都会遭遇情感困扰。小对话只会在对话中加入一些无关紧要的短语,比如“哇”,“酷”,“哎呀”,“太棒了”等。
我们不需要追求完美,而是要展示善意。每个人都知道情商和多义性的问题。有时候,如果对方在对话中展现了善意来弥补错误,人类是可以接受对话中的错误的。
小对话是弥补过错的一小步,展示了善意。
为了实现“让顾客开心”的目标,请向下滚动主菜单到小对话,点击该选项并启用,如下图所示。我们将专注于礼貌和情感:

图 16.1:菜单中的小对话
礼貌
礼貌有助于在出现问题时让对话更加顺畅。情商并不是每次都能 100%正确地回答。
情商(EI)是适应环境、纠正错误,并始终努力缓解紧张情绪。
首先,点击启用,这将在对话过程中触发小对话回应:

图 16.2:启用小对话
您会注意到礼貌的进度条显示为 0%。我们需要提升情商:

图 16.3:小对话主题
我们将仔细回答用户可能提出的第一个“问题”或他们可能表达的短语:这很糟糕。
我们现在遇到麻烦了!这是最糟糕的情况。我们得努力弥补这个问题。
情感多义性使得情形变得极其难以处理。我们最不想做的就是假装我们的机器人是聪明的。
我建议采取两种行动方案:
首先,仔细回答,表示我们需要进一步调查,可以这样说:
对此我非常抱歉。您能否请描述一下为什么这很糟糕?我们会定期检查我们的历史日志,并不断改进。您也可以通过<您的客户服务邮箱>给我们发邮件,我们会尽快回复。
您可以按以下方式输入这个回答并点击保存按钮:

图 16.4:礼貌
你会注意到,礼貌进度条已跳至 17%。我们已经覆盖了对话中的一个关键领域。当我们没有填充完整时,默认答案会被提供,但它们是随机的,因此,如果你启用此功能,最好输入自己的短语。
现在,在右上角的测试控制台中输入“That's bad”来测试对话。你会看到回应出现:

图 16.5:默认响应
如果你输入“bad”而不是“That's bad”,也能正常工作,因为 Dialogflow 的机器学习功能:

图 16.6:默认响应
数据日志记录将极大地帮助提升聊天机器人的质量。
我们将在下一节探讨数据日志记录。但是,首先让我们检查一下我们的情感。
情感
我们将处理第一个反应:哈哈哈! 如果我们回到情感多义性的问题,知道用户随时都能说出这句话,我们又陷入麻烦了!

图 16.7:管理情感
用户是高兴,还是在取笑聊天机器人?谁知道呢?即使有面部分析和语调分析,一个快速的“哈哈哈!”也很难解释。
我建议给出一个低调谨慎的回答,比如“嗯,这真是愉快啊!”。
这样可以让用户觉得聊天机器人有幽默感。当你点击保存时,情感进度条会跳升。
你会注意到,除了 Dialogflow 检测到的变体之外,你还可以直接在响应中输入变体。此外,如果用户输入的短语不在对话中,意图列表中会有一个回退意图。
闲聊可能使对话更流畅,但它只是情商的一部分,无论是在聊天机器人中还是在日常生活中。
数据日志记录将帮助我们迈出更大的一步。
数据日志记录
在第十五章,设置认知 NLP UI/CUI 聊天机器人中,我们通过后续意图考虑了对话的上下文。然而,即使是后续意图也不能提供应对用户意外答案的解决方案。
为了增强对话,数据日志记录通过记住对话中的关键方面,为聊天机器人创建长期记忆。
用户和 Dialogflow 设计者必须同意 Google Dialogflow 数据日志记录功能的条款,如本页面所述:cloud.google.com/dialogflow/docs/data-logging。
隐私是一个严肃的问题。然而,你会注意到,当你使用搜索引擎搜索某个产品时,最终你会看到或收到与搜索相关的广告。这就是数据日志记录。
做出这个决定取决于你的目标和目标受众。假设用户接受了协议条款。那么,数据日志记录将被激活,接着数据日志记录将为聊天机器人提供长期记忆。
本章的其余部分将探讨数据日志记录,假设用户已经清楚地接受了这一功能。
Google Cloud,像所有聊天机器人平台(亚马逊、微软等)一样,提供日志功能来改进聊天机器人。许多功能、接口和服务为提升对话质量提供了极大的支持。
数据日志记录可以推动认知适应性对话超越语音识别任务。
我们将通过对话历史的方式来探索一种实现方法。请转到历史:

图 16.8:菜单中的对话历史选项
您将看到过去对话的列表:

图 16.9:对话历史
注意所有平台列表,其中包含 Google Assistant 和其他平台的信息。您可以通过点击屏幕右侧的查看 Google Assistant 上的工作方式来部署聊天机器人。从那里,您可以按照指示操作,使其在智能手机、Google Home 等设备上运行。此外,您还将获得先进的日志数据,以改进聊天机器人。
如果您在礼貌部分测试了“那太糟了”,则交互历史将会出现:

图 16.10:聊天机器人交互
了解用户名的一种方式是在出现问题时询问用户他们的名字。这对于定制对话非常有用。我们可以为此人或此类人群设置特殊的对话。举例来说,我们可以要求用户在回答中提供姓名和电子邮件地址。当我们手动或通过脚本分析履行部分的数据日志时,我们可以追踪问题并在个人层面上改进聊天机器人。
完成小聊部分并激活数据日志授权后,我们可以继续创建情感。谷歌将通过我们的数据日志功能继续改进聊天机器人。
如果我们知道哪个用户说了什么,我们就可以改进对话,正如我们将在下一节中看到的那样。
创建情感
当用户输入涉及情感多义性的模糊回答时,聊天机器人很难考虑前面章节中描述的数百种可能性。
在本节中,我们将重点讨论用户尝试获取某种服务(例如在流媒体平台上观看电影)的情况。
一个高效的聊天机器人应该激发用户的情感。最有效的方法是:
- 
生成客户满意度。客户满意度是聊天机器人在无摩擦、可预期的对话中应尽力产生的最终情感。如果客户对回答不满意,紧张和沮丧情绪会积累。 
- 
使用像第十四章中 RBM-PCA 方法这样的功能,使用受限玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人的输入,建议选项以缩短对话路径,从而缩短对话持续时间,使用户“开心”。 
现在我们将探讨在第十五章,设置认知 NLP UI/CUI 聊天机器人中遇到的对话否路径。
要访问对话的否路径,请转到意图,点击choose_movie意图,然后点击添加后续意图,在下拉菜单中选择no:

图 16.11:添加后续意图
choose_movie - no选项现在应该出现:

图 16.12:后续选项
点击choose_movie - no。
谷歌已经进入了几个默认的“否”变体,如下截图所示:

图 16.13:Dialogflow 训练短语
这个“否”回应令聊天机器人感到意外。在第十四章中,这一市场细分已经被探讨过。某些事情出了问题!
聊天机器人正在处理一个特定的市场细分,即“动作”超级英雄粉丝类型的观众。回答“否”意味着我们需要检查其他可用的特性。
在第十四章中,使用限制玻尔兹曼机(RBMs)和主成分分析(PCA)准备聊天机器人的输入,在RBM.py程序中的特性是:
 # Each column is a feature. There are 6 features:
    # ['love','happiness','family','horizons','action','violence'] 
目前预测的“动作”特性组合包括以下几个特性:
动作 = {幸福,动作,暴力}
以下特性没有被考虑:
{爱情,家庭,视野}
由于我们希望保持路径简短,必须找到一种方式来提问,使得:
- 
涵盖这三个特性 
- 
可以为另一个市场细分使用现有的特性矩阵 
观众可能还具有:
- 
最近看过足够多的动作电影 
- 
从超级英雄的生活阶段逐渐成长,开始寻找其他类型的电影 
在这两种情况下,观众的市场细分可能与包含家庭-爱情价值观的另一个细分市场重叠。
正如我们在第十五章的为代理添加履行功能部分中看到的,设置认知 NLP UI/CUI 聊天机器人,我们可以使用脚本来:
- 
涵盖这三个特性 
- 
为另一个市场细分使用现有的特性矩阵 
经典的市场营销细分考虑了年龄因素。我们继续沿这个方向进行,准备好面对这样一种可能性:观众,这位年轻的超级英雄粉丝,逐渐变老并进入另一个与RBM.py中使用的年龄-电影类型细分重叠的细分市场,这发生在第十四章:
 movies_feature_map = np.array([[1,1,0,0,1,1],
                                   [1,1,0,1,1,1],
                                   [1,0,0,0,0,1],
                                   [1,1,0,1,1,1],
                                   [1,0,0,0,1,1],
    .../... 
我们应该在矩阵中加入一些爱情-家庭特性,并配上相应的电影。然后我们将获得另一个市场细分。最终,聊天机器人将管理多个市场细分,这是许多流媒体平台的标准做法。
第十五章中设置认知 NLP UI/CUI 聊天机器人的图表变体可能如下:
| 电影/特性 | 爱情 | 幸福 | 家庭 | 视野 | 动作 | 暴力 | 
|---|---|---|---|---|---|---|
| 坎巴 24 小时 | 1 | 1 | 0 | 0 | 1 | 1 | 
| 迷失 | 1 | 1 | 0 | 1 | 1 | 1 | 
| 魔方冒险 | 1 | 0 | 0 | 0 | 0 | 1 | 
| 节日 | 1 | 1 | 0 | 1 | 1 | 1 | 
| 乔纳森·布鲁克斯 | 1 | 0 | 0 | 0 | 1 | 1 | 
| 墨尔本档案 | 1 | 1 | 0 | 1 | 1 | 0 | 
| WNC 侦探 | 1 | 0 | 0 | 0 | 0 | 0 | 
| 明星 | 1 | 1 | 0 | 1 | 1 | 0 | 
| 太空 II | 1 | 1 | 1 | 0 | 1 | 0 | 
| 区域 77 | 1 | 0 | 0 | 1 | 1 | 1 | 
这个特征矩阵包含了上一矩阵中缺失特征的电影:《太空 II》。
流媒体平台包含许多营销细分:
M = {s[1], s[2], … s[n]}
许多这些营销细分包含了不同的变体、合并特征、组合等。
由于数据日志记录已被激活,从此时起我们现在可以获得以下信息:
- 
是否该观众已观看过此营销细分中提供的几部电影之一。这是另一个棘手的问题,因为某些观众可能会想重新观看某部电影。 
- 
观众的全新营销细分。 
为流媒体平台构建聊天机器人将需要数月的设计工作,并有许多构建可能性。对于这个示例,我们将专注于年龄进展场景,尽可能缩短对话路径,并提供以下响应:
"你想看《太空 II》吗?这是一个讲述一家人在太空冒险的大片。虽然有些动作场面,但它主要讲述的是一家人如何在太空中生存的故事。"
向下滚动至文本响应部分,输入如下响应,然后点击保存以触发训练过程:

图 16.14:训练过程概览
如果观众回答"是",则对话将引导至该电影的页面。要继续此方向,请返回到第十五章,设置认知 NLP UI/CUI 聊天机器人,并根据需要添加对该对话部分的"是"后续交换。
我们为代理添加了一些情感智能。接下来,我们将通过文本增强与递归神经网络(RNNs)一起探索聊天机器人架构的未来。
RNN 可以处理序列数据,例如单词序列、事件序列等。
针对未来自动对话生成的 RNN 研究
聊天机器人未来的发展方向是基于数据记录的对话、其认知意义、用户个人资料等,自动生成对话。随着 RNN 的进展,我们将越来越接近这一方法。有许多生成方法可以自动生成声音和文本序列。理解 RNN 是一个很好的起点。
RNN 模型基于序列,在此案例中是单词。它分析序列中的任何内容,包括图像。为了加速思维数据集的处理,可以在这里应用数据增强,就像在其他模型中对图像所做的那样。
初步查看其图形数据流结构显示,RNN 是一种与之前探讨过的其他神经网络类似的神经网络。以下图表展示了 RNN 的概念性视图:

图 16.15:数据流结构
y 输入(测试数据)进入损失函数(Loss_Train)。x 输入(训练数据)将通过权重和偏差转换为带有 softmax 函数的 logits。
查看图表中的 RNN 区域显示以下基本 lstm 单元:

图 16.16:基本的 lstm_cell——图中 RNN 区域
RNN 的 LSTM 单元包含“遗忘”门,当序列变得对 RNN 单元过长时,它们可以防止梯度消失。
RNN 的应用
RNN 包含一些函数,这些函数接收一层的输出,并将其反馈给输入,模拟时间的序列。这个反馈过程接受一个序列中的信息,例如:
The -> 电影 -> 很 -> 有趣 -> 但 -> 我 -> 不 -> 喜欢 -> 它
RNN 会将一堆单词展开成序列,并解析左右窗口中的单词。例如,在这句话中,RNN 可以从 interesting(加粗)开始,然后读取左右的单词(斜体)。这些是 RNN 的一些超参数。
这种序列特性为序列预测打开了大门。与其同时识别整个数据模式,不如识别数据的序列,就像这个例子一样。
一个没有 RNN 的网络会将以下向量识别为一周,这就像其他任何模式一样:
星期一
星期二
星期三
星期四
星期五
星期六
星期天
RNN 会通过展开数据流来按顺序探索相同的数据:
星期一 -> 星期二 -> 星期三 -> 星期四 -> 星期五 -> 星期六 -> 星期天
主要的区别在于,一旦训练完成,网络会预测下一个单词;如果输入是星期三,星期四可能是输出之一。这将在下一节中展示。
RNN、LSTM 和梯度消失
为了模拟序列和记忆,RNN 和 LSTM 会使用反向传播算法。在某些情况下,LSTM 是 RNN 的改进版。
RNN 在计算更深层次的网络梯度时经常会遇到问题。有时,由于序列的特性,它的梯度会消失(接近 0),就像我们在记忆序列变得太长时一样。
反向传播(就像我们在序列中一样)变得不那么高效了。有许多反向传播算法,如常用的基础反向传播。该算法执行高效的反向传播,因为它在每个训练模式后都会更新权重。
一种强制梯度不消失的方法是使用 ReLU 激活函数,f(x) = max(0, x),通过这种方式迫使模型上的值不至于停滞。
另一种方法是使用一个包含遗忘门的 LSTM 单元,该遗忘门位于输入和输出单元之间,有点像我们在记忆序列中卡住时,会说“算了”然后继续前进。
LSTM 单元将充当一个具有 0 和 1 值的记忆门,例如。这个单元会遗忘一些信息,以便对它已经展开成序列的信息有一个新的视角。在最近的 TensorFlow 版本(2.0 及以上)中,你可以选择在某一层使用 RNN 或 LSTM 单元。你的选择将取决于多个因素,关键因素是梯度的行为。如果在 RNN 单元中梯度消失,你可能需要改进你的模型,或者切换到 LSTM 单元。
需要牢记的 RNN 关键思想是,它会将信息展开为序列,记住过去的内容来预测未来。LSTM 的主要思想依赖于其“遗忘”门,避免梯度消失。在 TensorFlow 2.x 中,您可以通过几行代码选择使用 RNN 或 LSTM 单元。
让我们在 Google Colaboratory 上运行一个示例。
使用 RNN 进行文本生成
要查看程序,登录到您的 Dialogflow 账户,上传 text_generation_tf2.ipynb(该文件位于本书 GitHub 仓库的 CH16 目录中)到您的 Google Colaboratory 环境,并将其保存在您的 Google 云端硬盘中,正如 第十三章 中 Google Colaboratory 入门 部分所解释的那样,使用 TensorFlow 2.x 和 TensorBoard 可视化网络。
这款 TensorFlow 作者编写的程序设计得非常适合教学目的。程序通过设置 TensorFlow 2.x 和必要的库开始运行。
在这一节中,我们将重点关注程序的主要部分,您可以在之后探索、运行和修改它。
向量化文本
RNN 的主要输入步骤是将一系列单词(字符串)转换为 数字表示:
# Creating a mapping from unique characters to indices
char2idx = {u:i for i, u in enumerate(vocab)}
idx2char = np.array(vocab)
text_as_int = np.array([char2idx[c] for c in text]) 
我们为每个字符获得一个数字值:
{
  '\n':   0,
  ' ' :   1,
  '!' :   2,
  '$' :   3,
  '&' :   4,
  "'" :   5,
  ',' :   6,
  '-' :   7,
  '.' :   8,
  '3' :   9,
  ':' :  10,
  ';' :  11,
  '?' :  12,
  'A' :  13,
  'B' :  14,
  'C' :  15,
.../... 
您会注意到,这个“字典”可以有两种解释方式:
- 
character2number 
- 
integer2character 
RNN 会运行其计算,但预测结果将以字符的形式输出。
例如,程序可以将加载文本的第一序列提取出来,并生成对应的整数映射,如下所示:
# Show how the first 13 characters from the text are mapped to integers
print ('{} ---- characters mapped to int ---- > {}'.format(
    repr(text[:13]), text_as_int[:13])) 
在这个示例中,结果是:
'First Citizen' ---- characters mapped to int ---- > [18 47 56 57 58  1 15 47 58 47 64 43 52] 
RNN 会处理数字序列、整数片段或文本的窗口进行训练,然后做出预测。为此,程序会创建示例和目标,就像所有神经网络在训练批次中的操作一样。
构建模型
使用 TensorFlow 2 构建神经网络已经变得非常简单,几行代码就可以完成,甚至可能在示例程序中错过它们!
在进入这些几行代码之前,让我们先澄清一些基本概念:
- 
顺序模型包含一堆或一组层。 
- 
嵌入将每个字符的数字表示存储在一个向量中。 
- 
GRU 代表门控递归单元。GRU 包含一些门控,用来管理隐藏单元,保留一些信息并遗忘其他信息。当序列变长时,RNN GRU 有时会出现混乱,从而错误地处理梯度,导致梯度消失。更高效的 LSTM 单元同样是递归网络单元的一部分,具备与单元的反馈连接、输入门、输出门以及遗忘门。但最终,选择何种类型的单元始终取决于您的项目背景。无论如何,必须牢记的核心概念是递归网络用于管理数据序列,在保持过去记忆的同时忘记一些信息。 
- 
密集层,在此指的是输出层。 
- 
时间步长是预定义的序列长度。在另一个模型中,如果我们在处理时间相关的数据,它可能是真实的时间。 
一个顺序模型只建立了三个层次:
def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
    model = tf.keras.Sequential([
        tf.keras.layers.Embedding(vocab_size, embedding_dim,
                                  batch_input_shape=[batch_size,
                                                     None]),
    tf.keras.layers.GRU(rnn_units,
                        return_sequences=True,
                        stateful=True,
                        recurrent_initializer='glorot_uniform'),
    tf.keras.layers.Dense(vocab_size)
    ])
    return model 
就是这样!如果模型在训练阶段需要,你可以将基础的 rnn_units 替换为 LSTM 层。一旦模型建立,模型将:
- 
看起来像是字典中的嵌入。 
- 
执行 GRU 一个时间步。 
- 
稠密层接着会生成logits(参见第二章,构建奖励矩阵 – 设计数据集),使用似然函数,一个概率分布来进行预测。 
以下图示总结了 TensorFlow 作者程序的过程:

图 16.17:TensorFlow 模型
生成文本
在尝试和训练模型后,程序将自动生成文本,例如:
print(generate_text(model, start_string=u"ROMEO: ")) 
如你所见,ROMEO: 已被设置为起始字符串。接着显示出以下的预测来源于莎士比亚的初始文本,并在程序开始时加载:
ROMEO: Isick a tranch
It wast points for a sisten of resold thee, testement.
Petch doth my sweety beits are so of my sister.
KING RICHARD III:
Thou forget,
How did you burzenty day, 'tis oatly; heaven, for a womanous dear!
This is thy for mercy to the Kanging;
He that from the brothers of Gloucestersherding blame,
Thisble York, se me? 
你可以返回程序的开始部分并更改 URL。将莎士比亚的内容改为你自己的文本:
path_to_file = tf.keras.utils.get_file('<YOUR FILE NAME>',
    '<YOUR URL>') 
在运行程序之前,进入运行时 -> 更改运行时类型:

图 16.18:运行时类型
点击更改运行时类型:

图 16.19:笔记本设置
我建议使用 GPU。此外,如果你想在保存笔记本时保存程序运行结果,确保保存此笔记本时忽略代码单元输出未被勾选。
现在你已准备好探索并进行自己的研究,为自动文本生成的未来做出贡献!
总结
情感多义性使得人际关系丰富而充满令人兴奋的不可预测性。然而,聊天机器人仍然是机器,无法处理用户短语的广泛可能解释。
现有技术要求大量工作才能让一个认知 NPL CUI 聊天机器人正常运行。小型对话能让交流更加顺畅。它不仅仅是一个次要特性;礼貌和愉快的情感反应是使对话顺利进行的关键。
我们可以通过有意义的对话创造用户的情感,从而减少现有技术的局限性,这种对话能够带来更温暖的体验。客户满意度构成了高效聊天机器人的核心。一种实现这一目标的方法是基于数据日志的认知功能实现。当用户在我们期待“是”的时候回答“不是”,我们看到了聊天机器人需要适应,就像我们人类一样。
认知数据记录可以通过我们在第十四章中探讨的准备工作实现,通过受限玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人的输入,以及在第十五章中探讨的认知对话,搭建认知 NLP UI/CUI 聊天机器人,以及本章构建的自适应对话。在我们的例子中,观众更改了市场细分,聊天机器人记录了新的用户画像。Dialogflow-fulfillment 脚本可以管理整个自适应过程,尽管这超出了本书的讨论范围。
我们研究了通过 RNN 处理数据序列的过程,最终实现自动对话。使用认知方法的聊天机器人,例如本章中的 RBM-PCA 和自适应数据记录推理,将来能够构建自己的对话系统。
以下章节将探讨通过基因、生物神经元和量子比特来实现更高层次人工智能的方法。下一章将探讨遗传算法,并将其应用到混合神经网络中。
问题
- 
当聊天机器人无法提供正确的回应时,需要由实际的人工客服接管对话。(是 | 否) 
- 
日常生活中或与聊天机器人交互时,小谈话没有任何意义。最好直接切入主题。(是 | 否) 
- 
数据记录可以用来提高语音识别的准确性。(是 | 否) 
- 
聊天机器人代理的对话历史将包含有价值的信息。(是 | 否) 
- 
现代技术无法利用用户对话的数据记录。(是 | 否) 
- 
RNN 通过数据序列进行预测。(是 | 否) 
- 
RNN 可以自动生成聊天机器人的对话流,适用于所有应用程序。(是 | 否) 
进一步阅读
- 
关于 RNN 的更多信息: www.tensorflow.org/tutorials/recurrent
- 
关于文本生成的更多内容: www.tensorflow.org/tutorials/text/text_generation
第十七章:混合神经网络中的遗传算法
在本章及接下来的两章中,我们将探索我们体内的世界。首先,在本章中,我们将使用我们的基因模型作为优化工具。在第十八章,类脑计算中,我们将进入我们的生物大脑活动并创建类脑网络。最后,在第十九章,量子计算中,我们将更深入地利用我们体内的量子材料来构建量子力学模型以进行量子计算。
我们体内这些微小实体(基因、神经元、量子比特)中的任何细微变化都可能改变我们的整体存在。
在本章中,我们将发现如何进入我们的染色体,找到我们的基因,并了解我们的繁殖过程是如何工作的。从那里开始,我们将开始在 Python 中实现一个进化算法,即遗传算法(GA)。
查尔斯·达尔文提出了“适者生存”作为进化的模型。从某些方面来说,这个模型是有争议的。在 21 世纪的社会中,我们倾向于尽可能地为那些不是最强者的人提供支持。然而,在数学中,我们没有这种伦理问题。
在人工智能中,我们需要提供一个准确的解决方案。如果我们生成多个解决方案,我们可以将“适者生存”应用于抽象数字。
在某些情况下,遗传算法显著减少了找到问题最优解所需的组合数。通过生成数学后代、选择最适应者并产生新的、更强的抽象世代,系统通常比通过排列组合传播达到更优的解决方案。
一个设计良好的遗传算法(GA)可以优化神经网络的架构,从而生成混合神经网络。
本章将涵盖以下主题:
- 
进化算法;遗传算法 
- 
扩展遗传算法的基因以优化工具 
- 
混合神经网络 
- 
使用遗传算法优化 LSTM 
让我们首先从了解进化算法是什么开始。
了解进化算法
在这一节中,我们将从遗传到基因深入了解这个过程,然后在构建我们的 Python 程序时进行表示。
人类的连续世代激活某些基因而不激活其他基因,从而产生了人类的多样性。一个人类的生命周期是成千上万代人类中的一段经历。我们每个人都有两个父母、四个祖父母和八个曾祖父母,这一代人加起来有 2³个先祖。假设我们将这种推理扩展到每个世纪四代人,然后跨越大约 12,000 年,即上一个冰川时期结束时,地球开始变暖。我们得到:
- 
4 * 1 世纪 * 10 世纪 = 1,000 年和 40 代人 
- 
40 代人 * 12 = 480 
- 
将多达 2⁴⁸⁰个数学先祖加到今天地球上的任何人身上! 
即使我们将时间限制为 1000 年,也就是 2⁴⁰,这意味着一千年前我们的祖先有 1,099,511,627,776 个后代。但有一个问题,这个数字是不可能的!今天,我们已经达到了人类人口的峰值,仅为 7,500,000,000。因此,这意味着我们的祖先有很多子女,他们互相结婚,甚至是各个程度的表亲,形成了一个巨大的大家族,无论我们的肤色或发色是什么!
人类的遗传
首先,男性通过精子与女性的卵子结合来完成受精。受精卵开始生长,并在经过一段冒险后诞生,最终成为现在写下或阅读这本书的我们。
为了从受精卵成长为人类成年人,我们必须收集外界的许多东西,吸收并转化它们。
我们将食物和物质转化,直到成长为类似于我们祖先的模样,这个过程叫做遗传。
如果生命是平静而安静的,什么显著的变化都不会发生。然而,我们的环境已经对我们施加了持续不断的压力,直到数百万年前,当我们只是某种在海洋中漂浮的细菌时,这种压力才开始产生。这种压力促成了持续的自然选择;有用的会存活下来,而无用的则会灭绝。
这种压力一直延续到今天,迫使我们人类要么在基因上适应,要么灭绝。那些未能适应环境压力的人类已经灭绝。我们今天活着的幸存下来。
进化可以定义为一种不断冲突的状态。一方面,我们面临着无情、常常是敌对的环境;另一方面,我们同样顽强的基因;许多基因消失了,但其他基因变异、适应,并通过遗传得以延续——事实上,它们现在仍在这样做,谁知道接下来会发生什么呢?
我们的细胞
在我们的细胞中,细胞核包含个人的生物数据,形式为染色体。我们的细胞每个都有 46 条染色体,这些染色体由 23 对染色体组成。其中一对是性染色体,决定我们的性别。
在染色体内,我们拥有基因,尤其是线粒体基因组,它是存在于微小细胞中的 DNA,这些细胞将我们的食物转化为细胞的燃料。每个细胞都是一个微观的忙碌工厂,包含着成千上万个基因!
人类基因组描述了一个不可思议的序列集合,这些序列构成了我们在细胞 23 对染色体中的构建块。
遗传是如何工作的
除了性细胞外,我们从母亲那里继承了她 46 条染色体中的 23 条,从父亲那里继承了他那里的 23 条染色体。反过来,我们父母的细胞也包含他们父母——我们的祖父母——的染色体,依此类推,以不同的比例继承。
让我们通过一个例子来看看我们所面临的复杂性。我们以我们的父母之一为例,不管是母亲还是父亲。P代表该父母的染色体集合。
带有单引号的字母代表其父亲—我们祖父—的染色体,带有双引号的字母代表其母亲—我们祖母—的染色体。
我们可以为你父亲的性细胞表示如下:

对于你的母亲,第一组中的最后一个染色体将在她的性细胞中是一个X:

女性是X-X,男性是X-Y。
想象一下可能性!
如果我们只从父母的某一个细胞中取出A、B和C,我们已经获得了以下集合,C,这是我们将继承的八种组合:

如果我们将此扩展到二十三对染色体,分布将达到 2²³,即 8,388,608 种可能性。
我们的进化过程包含了适用于进化算法的潜力。
进化算法
在本节中,我们将进一步深入研究进化算法,并将其与我们的 Python 程序更加紧密地结合。进化算法可以应用于任何需要组合的领域:调度、DNA 医学研究、天气预报、神经网络架构优化以及无限多的领域。
进化计算是一组应用试错技术来重现生物进化的抽象数学版本的算法。这一数学模型并不声称已经解决了进化的难题,因为进化自然无法简化为几个方程式。
然而,我们的生物环境产生了框架,这些框架虽然是我们想象的产物,却使我们能够创造出高效的抽象算法。
进化算法属于进化计算类别。一个进化算法包含诸如变异、交叉和选择等过程。许多模型能够实现为进化过程设定的目标。
遗传算法(GA)引入了进化算法的范畴。
我们将首先定义遗传算法(GA)中涉及的概念,这些是 Python 程序的构建块。
从生物模型到算法
创建 GA 模型有多种方式。你可以复制前面部分描述的人类模型,或者简化它,甚至创建另一种视角。
我们的模型将包含染色体中的一组基因,并且包含一个与之互动的种群:

图 17.1:基因中的染色体
我们的模型是一个抽象的算法模型,而不是人类染色体(如成对出现)的实际表现形式。例如,个体染色体中的一个基因将与种群中基因集进行交互。这个过程将在接下来的部分中定义。
基本概念
让我们首先描述 Python 程序构建块的概念:
- 
目标:目标定义了我们希望在n代后获得的子代的长度和属性。 在我们的模型中,目标可以是指定的,也可以是未指定的。 一个指定的目标包含一个长度和它的值: target = "Algorithm" # No space unless specified as a character in the gene set在这种情况下,我们的环境要求精确的基因集合以保持在该环境中的适应性。请参见下面的适应度函数。 一个未指定的目标包含一个长度,但没有其实际值,这必须通过 GA 在n代后找到: target="AAAA" #unspecified target在这种情况下,我们的环境不需要精确的基因,而是需要具有维持适应环境特征的基因。请参见下面的适应度函数。 
- 
种群:种群首先定义了一个随机选择的个体,我们称之为父母,它将包含一定长度的基因字符串: def gen_parent(length)种群还定义了父母可以与之互动以产生孩子的潜在个体。在我们的基因模拟中,种群的大小由种群的基因集合表示(请参见下面的点)。 
- 
父母的基因集合:父母的基因集合将首先是一个随机基因集合。 
- 
种群的基因集合:这个父母将随机遇到种群中另一个具有随机基因选择的人。这个种群由一个基因集合表示,我们将从中随机抽取基因: geneSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-"由于一个给定的种群可以拥有这些基因中的任意一个或多个,因此我们的种群从一开始就非常庞大。 
- 
选择:我们将从我们的基因集合中随机选择基因,以模拟父母与另一个父母的相遇: index=random.randrange(0,len(parent))
- 
交叉:然后,我们将从父母和从种群中随机抽取的基因形成一个孩子,种群由基因集合表示。 在我们的模型中,一旦完成基因的随机选择,该基因将被种群中的随机基因替换,种群由基因集合表示: if(newGene!=oldGene):childGenes[index]=newGene;请注意,在我们的算法中的交叉过程中,新基因必须与旧基因不同。因此,我们的算法可以避免在繁殖阶段陷入某些局部组合。一个接一个的孩子,我们将不断产生新的世代。 
- 
突变:我们不会接受来自父母相同的基因来形成孩子。如果我们检测到这种情况,我们将随机改变一个基因,以确保每一代都是不同的。 如交叉段落中所述,我们不会接受与父母基因完全相同的孩子。正如本章的遗传学部分所示,孩子继承父母的基因时,不太可能完全相同。多样性是产生一代又一代能够适应环境的孩子的关键。 在我们的模型中,已引入强制突变的多样性规则: if(newGene==oldGene):childGenes[index]=alternate;因此,我们引入了一个备用基因,正如我们在构建 Python 程序时将看到的那样。 
- 
孩子:孩子定义了一组基因,包含与父母相同数量的基因,但具有新的基因。通过一代代的孩子基因字符串,将会产生新的世代,并完成与适应度函数的选择过程。 
- 
适应度:适应度定义了在给定模型中,后代的价值。最适应的个体将被选为下一代的父代。 在我们的模型中,我们有两个适应度函数,这些函数由情境变量来定义。 如果 scenario=1,则会激活指定的目标情境。该目标将根据周围环境进行指定,以适应环境。例如,极地熊变白是为了与周围的雪和冰融为一体,而在其他地区,熊通常是棕色的,例如为了与周围的植被融为一体。 因此,适应度函数有一个目标需要达到。例如,在程序中的某个实例中: target="FBDC"这个目标可能意味着许多事情,正如我们所看到的。对于熊来说,也许它们染色体中的某些基因会触发它们的颜色:白色或棕色。 如果我们模拟自然的程序在给定的代中没有产生正确的基因,意味着熊没有正确变异,并且将无法生存。Python 程序的适应度函数通过仅保留使后代朝正确方向进化的基因字符串,模拟自然选择。 在这种情况下,指定的目标是一个已识别的基因串,它将决定生死存亡。 def get_fitness(this_choice,scenario): if(scenario==1):正如我们稍后将看到的, scenario==1将确保达到生存所需的精确基因集合。如果 scenario=0,则会激活一个未指定的目标。目标的长度未指定。然而,特征集将定义种群的基因集的值。这个特征包含数值,能为你希望解决的任何优化问题打开大门,正如我们在 Python 程序示例中所看到的那样。这个数值集合被称为 KPI 集,因为这些值是我们将在模型中探索的系统的关键性能指标:KPIset ="0123456772012345674701234569980923456767012345671001234" #KPI setKPIset特征集与种群的基因集大小匹配。
在 Python 中构建遗传算法
我们现在将从零开始构建一个遗传算法(GA),使用GA.ipynb。
你可以使用.py版本。代码是相同的,尽管本章中的行号是指.ipynb版本的 Jupyter notebook 单元。
随时可以返回到前一部分,基本概念,查阅用于描述后续部分中 Python 程序的定义。
导入库
该程序从零开始构建,没有使用任何高级库,以便更好地理解遗传算法。三行代码足以让一切运行起来:
import math
import random
import datetime 
调用算法
在这个程序中,我们将探索三种情境。两种情境生成指定目标,一种生成未指定目标。
我们将从指定的目标开始,然后转向更高级的未指定目标,这将为我们使用遗传算法(GA)构建混合网络做准备。
我们将首先进入程序的调用算法单元。第一步是定义我们将在第 3 行使用的情境类型和适应度函数类型:
scenario=0   # 1=target provided at start, 0=no target, genetic optimizer 
如果scenario=1,程序将生成确切的基因以形成一个具有几代的随机种子父代的子代。
如果scenario=0,程序将生成一个具有一系列代的随机种子父代的基因类型的最佳特征。
在第 4 行,GA=2定义了我们正在处理的目标。
如果GA=1,则定义了种群的基因集和目标。调用主函数:
if(GA==1):
    geneSet =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-"
    # target with no space unless specified as a character in the geneSet
    target = "Algorithm"  # No space unless specified as a character in the geneSet
    print("geneSet:",geneSet,"\n","target:",target)
    ga_main() 
在这一点上,打印出了种群的基因集以及目标:
geneSet: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-
 target: Algorithm 
最后一行调用了ga_main(),即主函数。
主函数
该程序的ga_main()单元格中的代码。
ga_main()函数分为三个部分:父代生成、子代生成和总结。
父代生成过程
父代生成从第 2 行到第 7 行运行:
 startTime=datetime.datetime.now()
    print("starttime",startTime)
    alphaParent=gen_parent(len(target))
    bestFitness=get_fitness(alphaParent,scenario)
    display(alphaParent,bestFitness,bestFitness,startTime) #no childFitness for generation 1 so default value sent 
- 
startTime指示了开始时间,该时间被打印出来:starttime 2019-10-12 10:32:28.294943
- 
alphaParent是由后续的 Jupyter 笔记本单元格中描述的gen_parent函数创建的第一个父代。
- 
bestFitness是由get_fitness函数估算的适应度,在本章节中将对其进行描述。
- 
display函数描述了这个过程的结果。
现在我们有一个创建父代的过程:gen_parent,get_fitness和display。
现在,让我们在继续主函数之前探索一下父代生成函数。
生成一个父代
父代生成函数单元格以零基因和目标长度开始:
def gen_parent(length): 
length = 目标的长度。目标是"Algorithm",因此length=9。
在过程的开始阶段,由于这个函数的目标是随机产生一个包含与目标长度相等的基因字符串的父代,因此父代没有基因。
生成一个父代的基因字符串如下:
 genes=[]                        #genes array 
现在,在单元格的第 3 行开始while循环以填充genes[],直到达到目标的长度:
 while len(genes)<length:  #genes is constrained to the length
        #sampleSize: length of target constraint
        sampleSize=min(length-len(genes),len(geneSet))
        #extend genes with a random sample the size of sampleSize extracted from geneSet
        genes.extend(random.sample(geneSet,sampleSize)) 
- 
sampleSize是从基因集geneSet中需要的基因样本,用于为父代选择一个随机基因。
- 
genes.extend从geneSet中添加一个随机基因到genes数组中。
一旦父代的基因集genes[]达到了目标的长度,return函数将父代发送回主函数ga_main(),在那里它将通过display函数显示。这次随机运行中父代的输出是:
aFJPKzYBD 
自然地,每次运行时父代都会有所不同,因为这是一个随机过程。
现在,基因字符串返回到ga_main()函数:
 return ''.join(genes) 
现在,让我们探索一下适应度函数和display函数。
适应度
在ga_main()函数的这一点上,打印出了开始时间,并创建了父级:
#I PARENT GENERATION
    startTime=datetime.datetime.now()
    print("starttime",startTime)
    alphaParent=gen_parent(len(target)) 
在创建子代的多代之前,我们需要评估父代的适应度:
 bestFitness = get_fitness(alphaParent,scenario) 
在这一段中,我们将只描述指定的目标案例,这是scenario=1的一部分。我们将创建一个以给定选择为目标的适应度函数。在这种情况下,只计算正确基因的和:
def get_fitness(this_choice,scenario):
    if(scenario==1):
        fitness = sum(1 for expected,
            actual in zip(target,this_choice) if expected==actual) 
- 
this_choice是由前面的代码片段中描述的gen_parent函数生成的父代基因字符串。
- 
scenario表示该函数是计算适应基因的和,还是评估基因的特征。在本例中,计算的是正确基因的和。
- 
适应度是通过将目标(预期值)与实际值( this_choice变量)进行比较时,找到的正确基因的数量。
- 
如果 expected==actual,则和会增加。
- 
zip在 Python 中是一个高效的功能,它可以同时遍历两个列表。
一旦计算出适应度(适应基因的和),函数将返回该值到ga_main()函数:
 return fitness 
父代将通过main_ga()中的一个函数进行显示。
显示父代
此时,ga_main()已打印了开始时间,创建了一个父代,并评估了其适应度:
def ga_main():
    #I PARENT GENERATION
    startTime=datetime.datetime.now()
    print("starttime",startTime)
    alphaParent=gen_parent(len(target))
    bestFitness=get_fitness(alphaParent,scenario) 
程序现在将显示第一代的基本信息:父代调用了来自main_ga()的display函数,第 7 行:
 display(alphaParent,bestFitness,bestFitness,startTime) 
- 
alphaParent是父代的基因字符串
- 
bestFitness是其适应度
- 
由于还没有子代, bestFitness作为子代适应度的默认值被发送。
- 
startTime
在显示父代单元格中,第 2 行,display函数接收了由main_ga()发送的数据:
def display(selection,bestFitness,childFitness,startTime): 
display函数计算它所用的时间,并在几行中打印出信息:
 timeDiff=datetime.datetime.now()-startTime
    print("Selection:",selection,"Fittest:",bestFitness,
          "This generation Fitness:",childFitness,
          "Time Difference:",timeDiff) 
- 
selection是这一代的基因字符串。
- 
bestFitness是迄今为止创建的最佳基因字符串的值。
- 
childFitness是这一代的适应度值。第一代的适应度是父代的适应度,父代目前拥有最适合的基因。父代是另一个父代的子代,尽管这个父代是我们目前考虑的第一代。
- 
timeDiff是处理较大基因集时的重要值。它将有助于检测算法是否运行良好或是否已达到极限。
输出将显示父代的基因以及每一代更接近目标所定义的最适应代:
Selection: BnVYkFcRK Fittest: 0 This generation Fitness: 0 Time Difference: 0:00:00.000198 
该输出会在每次程序运行时有所变化,因为这是一个随机算法,模拟了我们自然和人工环境中发生的随机事件。
在探索创建无限代的循环之前,让我们先构建交叉函数。
交叉和变异
我们的模型包含一个带有变异规则的crossover函数,以确保多样性。
crossover函数从父代开始。
def crossover(parent): 
每一代的每一个子代将成为另一子代的父代。
如同自然界中一样,父代基因中的一个随机基因将被选中进行替换:
 index=random.randrange(0,len(parent))#producing a random position of the parent gene 
index指定将被替换的基因的确切位置:

图 17.2:基因中的染色体
我们可以看到,染色体中的基因D将被种群中个体的基因z所替代。
现在,我们模拟繁殖阶段。子代继承父代的基因:
 childGenes=list(parent) 
父代的基因串通过list函数转换为一个列表。
算法将父代的基因存储到一个变量中,以便替换:
 oldGene=childGenes[index]        # for diversity check 
oldGene将与新生成的基因进行比较,以确保多样性得到尊重,从而避免陷入局部循环。
在种群的基因集中随机选择一个新基因,模拟子代与某个个体之间的相互作用,个体数量无限:
 newGene,alternate=random.sample(geneSet,2) 
请注意,在此过程中,新的基因newGene会被随机选择,同时一个备用基因alternate也会被选择。alternate被选中来替换newGene,以避免做出错误的选择。
如果新基因newGene与旧基因oldGene不同,那么子代可以继承新基因:
 if(newGene!=oldGene):childGenes[index]=newGene;  #natural crossover 
新基因成为子代基因串的一部分。
然而,如果newGene与oldGene相同,这可能会影响整个遗传过程,导致代代相传的子代没有进化。此外,算法可能会陷入困境或浪费大量时间做出正确选择。
这里备用基因的作用开始显现,并成为子代基因串的一部分。这个交叉规则和备用规则模拟了该模型的变异过程。
 if(newGene==oldGene):childGenes[index]=alternate;  #mutation introduced to ensure diversity to avoid to get stuck in a local minima 
多样性已得到验证!
该函数现在返回子代的基因新串,以便可以计算其适应度值:
 return ''.join(childGenes) 
生成子代的多代
此时,我们已经生成了父代并探讨了基本概念和函数。
我们已准备好进入代数循环。首先,我们将查看代码,然后用流程图表示,并描述代码的各行。
一旦父代被创建,我们进入循环,模拟多代的进化过程:
 while True:
        g+=1
        child=crossover(bestParent)        #mutation
        childFitness=get_fitness(child,scenario) #number of correct genes
        if bestFitness>=childFitness:#
            continue
        display(child,bestFitness,childFitness,startTime)
        bestFitness=childFitness
        bestParent=child
        if scenario==1: goal=len(alphaParent);#number of good genes=parent length
        if scenario==0: goal=threshold;
        if childFitness>=goal:
            break 
该循环最适合用流程图表示:

图 17.3:遗传算法流程图
流程图中的过程基于 Python 的continue方法:
- 
条件之前的代码: - 增加代数计数器:
 g+=1- 调用crossover函数生成子代:
 child=crossover(bestParent)- 调用适应度函数以获取适应度值:
 childFitness=get_fitness(child,scenario) #number of correct genes
- 
判断 childFitness是否高于获得的bestFitness的条件:if bestFitness>=childFitness:- 
如果条件为 True,则进化必须继续,直到子代比父代更适应。这样就会将过程发送回while循环的顶部。
- 
如果条件为 False,则意味着子代比父代适应度更高,此时代码将跳出条件。
 
- 
- 
条件和 continue方法之外的代码:- 代码显示了子代,bestFitness变为childFitness,而bestParent现在是子代:
 display(child,bestFitness,childFitness,startTime) bestFitness=childFitness bestParent=child- 我们模型的两个场景目标已定义。scenario==1的目标是通过正确的基因达到目标长度。scenario==0的目标是达到我们将在下一节中定义的阈值:
 if scenario==1: goal=len(alphaParent); if scenario==0: goal=threshold;
- 代码显示了子代,
- 
循环的 break条件:当适应度最强的子代在多个包含满足目标基因的代之后被创建时,进化过程将停止: if childFitness>=goal: break
n代的输出将如下所示:
Genetic Algorithm
geneSet: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-
 target: Algorithm
starttime 2019-10-12 20:47:03.232931
Selection: Xe!bMSRzV Fittest: 0 This generation Fitness: 0 Time Difference: 0:00:00.000953
Selection: Xe!bMSRhV Fittest: 0 This generation Fitness: 1 Time Difference: 0:00:00.002404
Selection: Xl!bMSRhV Fittest: 1 This generation Fitness: 2 Time Difference: 0:00:00.004391
Selection: XlgbMSRhV Fittest: 2 This generation Fitness: 3 Time Difference: 0:00:00.006860
Selection: XlgoMSRhV Fittest: 3 This generation Fitness: 4 Time Difference: 0:00:00.009525
Selection: AlgoMSRhV Fittest: 4 This generation Fitness: 5 Time Difference: 0:00:00.011954
Selection: AlgorSRhV Fittest: 5 This generation Fitness: 6 Time Difference: 0:00:00.013745
Selection: AlgorSthV Fittest: 6 This generation Fitness: 7 Time Difference: 0:00:00.016339
Selection: AlgorithV Fittest: 7 This generation Fitness: 8 Time Difference: 0:00:00.019031
Selection: Algorithm Fittest: 8 This generation Fitness: 9 Time Difference: 0:00:00.022239 
我们可以看到在本章的Display parent部分中display函数所描述的所有代的展示。
汇总代码
一旦进化过程结束,汇总代码将接管:
#III. SUMMARY
    print("Summary---------------------------------------------------")
    endTime=datetime.datetime.now()
    print("endtime",endTime)
    print("geneSet:",geneSet);print("target:",target)
    print("geneSet length:",len(geneSet))
    print("target length:",len(target))
    print("generations:",g)
    print("Note: the process is stochastic so the number of generations will vary") 
进化循环的示例输出为:
Summary---------------------------------------------------
endtime 2019-10-12 20:47:03.257112
geneSet: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-
target: Algorithm
geneSet length: 55
target length: 9
generations: 782
Note: the process is stochastic so the number of generations will vary 
在继续之前,需要指出的是,对于 55 个元素中的 9 个元素使用排列时,为了达到目标,需要进行 10 ** 15.36 次计算,而不是在本示例中的 782 代。因此,遗传算法是生成排列的有效方式。
我们现在已经探讨了进化过程的核心和 Python 代码。接下来,我们将构建未指定的目标和优化代码,这将引导我们进入混合神经网络的领域。
未指定的目标用于优化神经网络的架构,采用遗传算法
在本节中,我们为通过混合神经网络优化神经网络架构奠定了基础和动机。物理神经网络的架构将通过遗传算法进行优化。
我们将研究一个物理神经网络,并通过遗传算法优化其架构。
一个物理神经网络
我们将从一个名为 S-FNN 的物理网络开始,这是一个前馈神经网络(FNN)。请仔细观察以下图像,并花足够的时间理解其架构:

图 17.4:神经网络的架构
这个物理网络具有一些重要的特定特征:
- 
这是一个前馈神经网络(FNN) 
- 
共有三层。 
- 
每一层的神经元并非与下一层的所有神经元完全连接。三层之间的连接并非基于所有的可能性,而是基于过去运行此网络时,最优连接的统计结果。 连接是通过多次运行该网络得到的,目的是确定哪些连接是最佳的。 
- 
这里表示的连接是最具生产力的连接,导致输出为 1而非0。输出为1表示成功,而输出为0表示失败。
- 
输入是数据集中的随机值,若为成功则必须分类为 1,若为失败则分类为0。
- 
经过对该网络过去运行的仔细研究,发现该网络的生产力在本示例中完全依赖于第二层中神经元的数量和质量。 
让我们利用所学知识,将其应用到足球队的架构中。
这个神秘的 S-FNN 本质是什么?
S-FNN 是一个足球队的架构!它是给定比赛前,足球队 3-4-3 阵型的表示。
像抽象神经网络一样,我们为每一层选择的神经元数量和质量至关重要。在我们这个抽象的人工神经网络(ANNs)世界中,有许多问题需要解决。我们应该保留多少个?应该通过池化层消除多少个?通过丢弃层应该放弃多少个?我们怎么知道呢?在处理大数据集和大网络时,试验和错误需要多长时间?
现在,让我们回到图表,阅读以下解释,并开始寻找解决神经网络架构复杂性的方法:
- 
输入代表基于过去比赛统计数据,输入比赛中的最佳选择目标。 
- 
第 1 层是由三个神经元表示的防守层,包含三个球员。 
- 
第 2 层是中场,是第 1 层活动的转化结果,过去比赛的统计数据展示了最适合的连接。输入的初始球已经在这些层之间流动,经过每场比赛的演变。 
- 
第 3 层是攻击层,它决定了输出的分类;1 代表成功,表示进球,0 则表示失败。第 2 层与第 3 层之间的连接展示了每场比赛中找到的最适合的结果。 
待解决的问题:在我们的例子中,第 2 层已被确定为该队的关键层。多年来,它一直是一个弱点。让我们看看我们的遗传算法如何帮助找到这一层的最适合球员。
我们可以按照如下方式运行scenario==1(指定目标),目标是ga==3:
if(scenario==1 and GA==3):
    target="FBDC"  # No space unless specified as a character in the geneSet
    print("geneSet:",geneSet,"\n","target:",target)
    ga_main() 
geneSet是足球市场上所有可用球员的种群,target是我们物理网络第 2 层所需的基因串:
Genetic Algorithm
geneSet: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-
target: FBDC 
该目标在本次运行中经过 851 代后找到。
然而,我们希望遗传算法(GA)能够根据特征自行找到球员,而不指定目标。让我们一步步地探索这一过程,每次细胞地分析。
调用算法单元
从第 7 行到第 12 行,我们定义了第 2 层网络所需的目标架构的参数:
- 
geneSet是我们网络第 2 层所有可用球员的集合,无论他们是在队内还是在市场上:geneSet="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-" #gene set
- 
KPIset,即关键绩效指标集,是每个球员在中场市场上的表现分数。该集的每个整数包含一个 0 到 9 之间的分数,基于球员在担任中场时的比赛统计数据:KPIset ="0123456772012345674701234569980923456767012345671001234" #KPI setKPI 集与基因集中的每个成员相匹配。 
- 
threshold是我们需要达到的中场球员表现总和,才能在队伍中建立强大的中场。threshold=35
我们的目标是根据基因的特征和 KPI 属性找到一串基因。
目标是达到阈值。
我们在第 23 行调用了我们的进化函数:
if(scenario==0 and GA==2):
    target="AAAA"                         #unspecified target
    print("geneSet:",geneSet,"\n","target:",target)
    ga_main() 
正如你所看到的,target被设置为一个没有意义的值,这个值将迅速演化。遗传算法(GA)将需要找到一个适应的序列。
我们可以跳过前一节中描述的中间适应度函数,集中在适应度单元中的场景上。
适应度单元
我们已经在前面的章节中描述了适应度单元的适应度函数。我们将专注于未指定目标的代码,即scenario==0。
场景的第一部分计算每个基因(潜在中场球员)的表现之和:
 if(scenario==0):
        cc=list(this_choice) # cc= this choice
        gs=list(geneSet)     # gene set
        cv=list(KPIset)      # value of each KPI in the set
        fitness=0
        for op1 in range(0,len(geneSet)): #2.first find parent gene in gene set
            for op in range(0,len(target)):
                if cc[op]==gs[op1]:       #3.gene identified in gene set
                    vc=int(cv[op1])       #4.value of critical path constraint
                    fitness+=vc 
基因序列(中场球员)的集体适应度存储在fitness变量中。
然而,我们不能接受相同的基因两次,否则就意味着我们在场上有了一个中场球员的克隆!因此,我们添加了一些安全代码,在这种情况下将fitness设置为0:
 for op in range(0,len(target)):
                for op1 in range(0,len(target)):
                    if op!=op1 and cc[op]==cc[op1]:
                        fitness=0    # no repetitions allowed, mutation enforcement 
现在,我们可以回到ga_main()并完成我们的过程。
ga_main()单元
我们已经在前面的章节中描述了适应度单元。现在,我们将专注于未指定目标的代码,即scenario==0。
在ga_main()单元中,我们只需要检查第 22 到第 24 行:
 if scenario==0: goal=threshold;
        if childFitness>=goal:
            break 
如果scenario==0,则childFitness必须>=goal(KPI 总和)。
我们已经找到了我们的中场球员!
我们现在将显示结果:
Genetic Algorithm
geneSet: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-
 target: AAAA
starttime 2019-10-13 09:08:21.043754
Selection: PNVx Fittest: 18 This generation Fitness: 18 Time Difference: 0:00:00.001252
Selection: LNVx Fittest: 18 This generation Fitness: 24 Time Difference: 0:00:00.004130
Selection: LNVq Fittest: 24 This generation Fitness: 27 Time Difference: 0:00:00.004708
Selection: LNFq Fittest: 27 This generation Fitness: 29 Time Difference: 0:00:00.010362
Selection: LBFq Fittest: 29 This generation Fitness: 31 Time Difference: 0:00:00.015797
Selection: CBFq Fittest: 31 This generation Fitness: 33 Time Difference: 0:00:00.024712
Selection: CBFt Fittest: 33 This generation Fitness: 34 Time Difference: 0:00:00.032680
Selection: CBFD Fittest: 34 This generation Fitness: 35 Time Difference: 0:00:00.048524
Summary---------------------------------------------------
endtime 2019-10-13 09:08:21.094005
geneSet: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!.-
target: AAAA
geneSet length: 55
target length: 4
generations: 154
Note: the process is stochastic so the number of generations will vary 
在这种情况下,遗传算法(GA)选择了中场球员 C、B、F 和 D。
现在我们已经掌握了理解人工混合神经网络所需的所有成分、概念和知识。
人工混合神经网络
在前一节中,我们使用遗传算法(GA)优化了一个物理神经网络。
在本节中,我们将把刚刚探索过的混合概念扩展到人工神经网络(ANNs)。原则是相同的,因此,凭借你现在掌握的概念,你将能够直观地理解我们在本节中将要优化的递归神经网络(RNN)。
人工智能在社会中的未来依赖于人类(多样性)、机器(人工智能和物联网)以及自然(可持续的生存项目)之间的集体智慧。
在人工智能领域,这种多样性体现在集成算法、元算法和混合系统中。深度学习已经证明了其有效性。我们可以在几行代码中使用 TensorFlow 2.x 创建一个神经网络。然而,往往需要花费数天、数周,甚至数月的时间来微调依赖大量数据的人工神经网络(ANN)模型,以提供可靠的模型。这就是混合神经网络必要的原因。
深度学习网络可以使用任何形式的其他类型算法来成为一个更高效的系统。在我们的案例中,我们选择了进化算法,这些算法可以用于深度学习:
- 
通过使用数据特征来提取符合我们寻找的模式的数据序列,从而改善输入,找到最适应的数据点 
- 
优化网络层的权重,以提升传统优化器的速度和性能 
- 
通过选择作为基因序列处理的最适应解决方案,来改进网络输出的分类阶段 
- 
改进定义网络架构的繁琐任务 
本节将专注于通过遗传算法优化网络架构的示例:
- 
创建 RNN 
- 
引入一个遗传算法,它将优化网络架构 
注意:有关遗传算法表示的信息,请随时返回前面的章节以刷新进化算法的过程。还请参考前面的章节查阅神经网络的结构,特别是第十六章,改进聊天机器人情感智能缺陷,其中描述了 RNN。
构建 LSTM
在 Google Colaboratory 或本地机器上的 Jupyter 中打开Genetic_Algorithm_LSTM.ipynb,或打开genetic_algorithm_lstm.py。
本教育示例的模型是 LSTM。
目标是使用 GA 生成的窗口大小并以此窗口大小运行 LSTM。均方根误差(RMSE)将用于衡量配置的适应度。
简而言之,RMSE 首先计算训练数据和测试数据之间差异的平方,就像许多类似的公式一样。然后,计算结果的平方根。只需记住,RMSE 将比较我们期望得到的结果与实际得到的结果,并生成一个值。
现在让我们来探索程序的主要单元:
- 
导入所需包单元: Genetic_Algorithm_LSTM.ipynb首先安装 DEAP,一个进化计算框架:!pip install deap我们在前面章节中从零开始构建了一个遗传算法。这次我们不需要从头开始,因为这个程序使用了一个框架。 然后,程序安装了 bitstring,它有助于处理二进制数据。
- 
加载数据单元:数据中的风力预测数据来自 train.csv,数据源为www.kaggle.com/c/GEF2012-wind-forecasting/data。wp1到wp7列提供了从七个风电场收集的风力发电测量的归一化数据。LSTM 的目标是接收这一数据序列并进行风力发电预测。
- 
定义基本函数单元:该单元准备数据集并以标准过程训练模型。我们将重点关注第 14 行: window_size = window_size_bits.uint
- 
进化模型单元:该模型使用 DEAP 框架函数,但我们可以轻松识别我们在前面章节中探讨过的概念,并按如下方式初始化: population_size = 4 num_generations = 2 gene_length = 10
代码已经设置好,配备了一个现成的遗传算法来优化我们网络的窗口大小。
模型的目标
与我们之前的章节一样,目标是为这个网络找到最佳窗口大小,就像我们在早些章节中寻找最佳的第 2 层一样。
该模型已完成以下任务:
- 
安装了包,加载了数据,并找到了 LSTM 的窗口大小 
- 
然后,运行遗传算法模型来测试 LSTM 的可能窗口大小 
- 
每一代和每个训练周期都会提供一个 RMSE 测量值 
程序需要一些时间运行,但我运行的结果保存在笔记本中,供你查看。这里有一个结果,供你查看系统是如何工作的:
Epoch 1/5
17200/17200 [==============================] - 207s 12ms/sample - loss: 0.0096
Epoch 2/5
17200/17200 [==============================] - 202s 12ms/sample - loss: 0.0059
Epoch 3/5
17200/17200 [==============================] - 202s 12ms/sample - loss: 0.0058
Epoch 4/5
17200/17200 [==============================] - 200s 12ms/sample - loss: 0.0057
Epoch 5/5
17200/17200 [==============================] - 200s 12ms/sample - loss: 0.0057
Test RMSE: 0.0926447226146452 
如同上一节所述,遗传算法优化了人工神经网络(ANN)的一个部分。你可以使用遗传算法优化人工神经网络的其他部分。天高地远!事实上,没有限制。使用遗传算法或其他算法优化架构或过程的混合神经网络将把你的项目带到另一个层次!
总结
进化算法为人工智能(AI)的优化潜力带来了新的光辉。本章中,我们研究了遗传如何深刻影响种群分布。环境的影响可以通过基因突变来衡量。
进一步深入,我们重点研究了一类遗传算法(GA),通过多代实现遗传变换的模拟。我们探讨了父母如何传递一些基因,以及从代际种群中选择多样基因如何产生变异。染色体会遗传一些基因,但不遗传其他基因。
自然和环境的压力将会主导。一种适应度函数评估基因串,只有最强的基因才能存活。最强的基因物质将产生交叉和突变,创造出更适应环境的后代。
遗传算法可以用于表示任何类型的数据串,以及该数据的特征。优化过程可以应用于仓储、运输和神经网络。
混合网络无疑将在未来几年中扩展,将深度学习(DL)带到新的高度。使用遗传算法优化递归神经网络(RNN)的架构,为优化任何深度学习(DL)、机器学习(ML)或自动机器学习(AutoML)架构奠定了基础。例如,混合神经网络可以使用遗传算法优化输入,进行特征降维,或作为网络的权重优化函数。
大自然为我们提供了无价的工具,可以应用于我们的人工神经网络模型。本章讨论了我们体内的隐形构建模块。在下一章《神经形态计算》中,我们将探索使我们能够适应环境的其他组件:神经元。我们将探讨如何利用生物模型的神经网络来解决复杂问题。
问题
- 
一个人体细胞含有 42 条染色体。(是 | 否) 
- 
遗传算法是确定性的,不是随机的。(是 | 否) 
- 
进化算法意味着程序代码会进化。(是 | 否) 
- 
即使经过多代,孩子最好也能继承父母之一的基因。(是 | 否) 
- 
多样性使得基因集变得更弱。(是 | 否) 
- 
构建一个神经网络只需要几行代码,而且架构总是能正常工作。(是 | 否) 
- 
使用遗传算法构建神经网络有助于优化层的架构。(是 | 否) 
- 
混合神经网络是无用的,因为深度学习将不断进步。(是 | 否) 
- 
你会信任遗传算法为你做决策吗?(是 | 否) 
- 
你会信任一个混合神经网络来优化你的网络架构吗?(是 | 否) 
深入阅读
第十八章:神经形态计算
我们的大脑在必要时会激活成千上万甚至数十亿个神经元,使我们的身体随时准备好应对任何情况。正如我们在第十七章中看到的,混合神经网络中的遗传算法,进化已经在数千代、数百万年的时间里精细调整了生物能力。
本章将深入探讨我们体内的认知能力。我们将从前一章的染色体出发,了解使我们成为智慧生物的生物神经元。这些神经元以数十亿种方式相互作用,产生认知模式,形成心智结构。
神经形态计算利用我们大脑的强大优化能力,令人惊讶的是,它消耗的能量非常少。平均而言,我们仅消耗几瓦特的能量,比灯泡还少,用来解决非常复杂的问题。这本身就表明,我们大脑的神经结构具有一种独特的架构,而我们还未能在物理上再现它。
将神经形态计算引入现实世界需要硬件和软件,就像所有计算机科学模型一样。在本章中,我们将重点讨论软件,尽管提及英特尔在神经形态研究中涉及的硬件同样重要。这些硬件以一个名为 Loihi 的芯片的形式出现,Loihi 的名字来源于即将崛起的夏威夷水下火山,最终将突破海面。Loihi 包含成千上万的神经元及其突触、树突和轴突,模拟我们的大脑活动。IBM 和其他公司也在这一领域开展了研究。
我们大约有 1000 亿个神经元。这些芯片目前只能达到数十万个神经元。然而,通过将这些芯片连接成物理网络,神经形态计算将在不久的将来成为我们必须考虑的领域。
我们将首先定义什么是神经形态计算,然后探讨 Nengo,一个独特的神经形态框架,具有坚实的教程和文档。Nengo 是众多超出本书范围的方法之一。本章不是神经形态课程,而是一个概览,邀请你挖掘我们大脑结构的强大力量,以解决复杂问题。我们将探索的问题将使我们更接近理解大脑是如何运作的。
本章将涵盖以下主题:
- 
什么是神经形态计算 
- 
开始使用 Nengo 
- 
Nengo 基本概念 
- 
探索 Nengo 教程和界面 
- 
Nengo 与经典人工智能的区别 
- 
将 Nengo 独特的语义指针架构(SPA)模型应用于关键研究领域 
让我们从基础开始——什么是神经形态计算?
神经形态计算
让我们直接进入思维过程的核心,理解神经形态计算。对于人工智能专家,我希望用一句话总结从经典模型到前沿神经形态模型的历程:
从思想到大脑
如果我们进一步推进,M 是我们所有心理表征的集合,B 是导致思维模式的物理反应的世界。
从这个角度看,M 是我们到目前为止在本书中探索的所有内容的集合:
M = {基于规则的系统,机器学习,深度学习,进化算法… m}
m 是我们周围世界的任何数学心理表征。例如,在深度学习中,一个人工神经网络会试图通过搜索它能在图像中找到的模式,来理解图像中的混乱,这些模式跨越低维和更高层次的抽象。
然而,无论一个心理构建看起来多么高效,它仍然是一个表征,而非物理现实。
现在,让我们观察 B = 大脑构建:
B = 现象/事件(在我们内部或外部世界)-> 物理刺激 -> 大脑中的物理神经活动 -> 目标区域的更高活动 -> 物理电学习反应 -> 人类行为
B 的架构将我们带得更接近现实!心理表征被最小化,从而减少了人工构建的扭曲,无论它们的效率如何。
经典的人工智能是关于构建我们认知活动的心理表征。
类脑计算是关于构建一个可以编码现实、像人类大脑一样处理它并解码结果的大脑。
请记住,像英特尔这样的公司正在提供芯片,以通过类脑计算实现令人惊叹的成果,正如我们在本章中将会发现的那样。
现在我们对类脑计算有了一些了解,让我们来看看类脑框架 Nengo。
开始使用 Nengo
简而言之,Nengo 构建的是大脑,而不是像经典机器学习和深度学习中的那样构建心理表征。
Nengo 代表 神经工程对象。它既具备 Nengo 的脚本能力,也具备 Nengo GUI 的图形能力。我们将使用 NEF,即 Nengo 的神经工程框架 (NEF)。
Nengo 是由滑铁卢大学(加拿大安大略省)的理论神经科学中心创建的。Chris Eliasmith 在这个项目中发挥了重要作用。
在前面的章节中,我们探讨了许多认知建模的方法。Nengo 使用 NEF 来实现 SPA。
语义指针 是生物系统中的神经表征,它携带结构,将引导到更高层次的认知表征。
指针一词指的是我们在 C++ 中所熟知的指针,因为它们可以访问它们所不包含的数据。
语义 这个术语指的是它们不仅仅是像 C++ 中那样的数学工具,因为它们通过它们之间的距离包含了虚拟表征。
如果我们将这两个概念结合起来,就会得到一个令人震惊的概念:意义是通过生物学指针活动在我们大脑中以不同距离和状态相互作用生成的。让我们通过首先安装 Nengo 来深入了解类脑计算。
安装 Nengo 和 Nengo GUI
本章中,我使用了与 NumPy 和 Matplotlib 库的 Python 接口,正如我们从本书开始时所做的那样。接下来,只需通过 pip 安装 Nengo,例如:
pip install nengo 
你也可以使用其他方法安装它。有关更多信息,请访问 github.com/nengo/nengo。
让我们安装这个不错的 HTML 5 可视化工具,并通过我使用 pip 安装的 GUI 与 Nengo 进行交互:
pip install nengo-gui 
你也可以使用其他方法安装它。有关更多信息,请访问:github.com/nengo/nengo-gui/。
一旦两个程序都安装完成,如果你遇到任何问题,请参考包含大量信息的链接,或者联系 Nengo 的支持团队,他们提供了出色的反馈。
有许多方法可以使用 Nengo。本章描述了一种快速入门的方法,使用 Python。
设置完成后,打开浏览器,比如 Chrome,然后在命令行控制台中输入 nengo,它应该会在浏览器中打开 Nengo 图形用户界面(GUI),并打开一个 default.py Python 程序:

图 18.1:Nengo Python 代码
点击左上角的文件夹图标,然后点击 built-in examples:

图 18.2:Nengo 示例
一个列表将会出现。点击 tutorial:

图 18.3:Nengo 示例列表
一份令人着迷的教育示例列表将会出现:

图 18.4:教程部分中的示例
教程程序位于安装程序写入的目录中。
你可以在浏览器地址栏中查看教程中 Python 示例的 URL。
创建 Python 程序
现在,让我们通过几个步骤创建一个 Python 程序并保存文件:
- 
打开一个空的 Python 文件,但暂时不要保存它 
- 
编写以下代码以导入 nengo库并创建一个模型:import nengo model = nengo.Network() with model: #<your code here>
现在,将 Python 文件保存在教程中其他程序的路径下。你可以在打开 Nengo 示例时看到这个路径。只需导航到该路径以保存程序。我们将其命名为 00-myintro.py,以便与教程中的程序列表匹配:

图 18.5:保存 Python 程序
我们将像之前一样回到 tutorial 目录,并打开它以添加基本的 Nengo 对象。
Nengo 对象是 Nengo 模型的构建模块,用于创建神经元群体,将其连接到刺激函数,并管理输出。
对于我们的 Python 程序,我们将使用一些关键的 Nengo 对象,相关细节将在接下来的章节中介绍。
一个 Nengo 集群
一个 Nengo 集合是一组神经元。它可以被视为一个包含实数的神经元群体。
一个集合是通过以下方式创建的:
nengo.Ensemble 
一个集合可以在一行代码中创建:
ensemblex = nengo.Ensemble(n_neurons=5, dimensions=1) 
一旦我们向00-myintro.py添加了一行代码,集合的表示将在 Nengo 界面的左侧窗格中出现:

图 18.6:神经元集合
在右侧的代码编辑器中编写 Python 代码时,您可以在可视化界面窗格中查看模型的可视化流动。
一个集合可以包含一个个体的群体,一个单一的神经元。这个神经元是我们生物神经元的表现:
- 
突触后电流(PSCs)通过我们的树突流动 
- 
然后电流到达神经元的核心(细胞体)。 
- 
如果在轴突初段(轴突丘)处的电流超过阈值,那么会产生一个尖峰 
- 
当离子通道打开时,PSCs 会在接收细胞中产生。 
让我们更详细地了解一下 Nengo 的神经元类型。
Nengo 神经元类型
我们在我们的集合中创建了 50 个神经元:
ens = nengo.Ensemble(n_neurons=50... 
有多种神经元类型。然而,在我们的示例中,我们将使用默认的神经元,即泄漏积分与放电(LIF)神经元。
神经元动力学基于一个叫做积分的求和过程。这个积分与一个机制相关联,该机制将在电压超过临界值时触发(放电)。
线性微分方程与阈值结合,这些阈值将触发文件的尖峰,这是构成默认 LIF 神经元的最后组件,除非另有指定。
欲了解更多关于 Nengo 神经元类型的信息,请参见www.nengo.ai/nengo-extras/neurons.html。
Nengo 神经元维度
在我们的示例中,dimensions设置为1;这意味着集合由一个数字(或维度)表示:
ens = nengo.Ensemble(..., dimensions=1) 
一个 Nengo 节点
现在我们已经定义了神经元集合及其输出维度,我们将定义输出:
node_number = nengo.Node(output=0.5) 
刺激将是恒定的,并将在滑块上显示如下:

图 18.7:Nengo 滑块
在某些情况下,带有数字的输出可能不够用。这个数字可以被一个导入 NumPy 的函数替代。例如,可以使用正弦波函数:
node_function = nengo.Node(output=np.sin) 
一旦我们输入了节点功能,它将显示在界面上,并且除了先前显示的信息外,还会有新的信息:

图 18.8:界面上的节点功能
node_function提供了一种将非神经输入发送到 Nengo 对象的方法。
我们将在本章的15-lorenz.py示例中探讨这样的实现,该示例位于教程部分的 Nengo 示例中。
如果您右击node_function图像并选择一个值,您将看到一条表示正弦波刺激实时值的曲线:

图 18.9:节点功能
更多关于 Nengo 对象的信息,请访问 www.nengo.ai/nengo/getting_started.html#creating-nengo-objects。
连接 Nengo 对象
我们现在需要连接群体和节点,以使我们的系统工作。通过这种方式,群体将具备某种功能。
此时,我们有一个群体和一个节点功能,如下图所示:

图 18.10:群体和节点功能
为了连接它们,我们将添加一个 Nengo 连接:
nengo.Connection(node_function, ens) 
更多 Nengo 前端 API 定义,请参见 www.nengo.ai/nengo/frontend_api.html。
现在,让我们探索这个激动人心的视觉界面。
数据可视化
第一步是点击屏幕右下角的播放按钮:

图 18.11:播放按钮
这将使时间开始流动,模拟我们的大脑活动。时间是神经形态计算的独特特点之一。我们不会将一层层静态的数学堆叠成一个心理表征。使用 Nengo,我们一步一步、秒秒钟地模拟大脑活动!
一旦你点击播放按钮,就感觉像是在看我们大脑内部的运作!
我们在前一节中看到如何可视化滑块的活动,这些活动产生了刺激。我们将在本节中关注我们的群体。
如果我们右键点击群体可视化,几个选项将会出现:值、放电、电压、发放模式和详细信息...:

图 18.12:群体选项
- 值:我们的群体的值将在 –1 到 1 之间显示,例如:

图 18.13:群体的值
- 放电:放电活动产生了美丽的颜色,显示了我们的神经元如何响应正弦波刺激:

图 18.14:放电模式
你会注意到每个神经元都有自己的放电通道。群体的这一特性产生了各种各样的响应。
- 
电压:电压提供了关于流经我们神经元的电流的有趣信息,这些电流来自其他神经元的刺激,进而来自更多从外部世界获取信息的神经元。 在以下截图中,群体包含了五个神经元的群体,颜色通道提供了更多信息: 

图 18.15:带有颜色模式的神经元活动
- 发放模式:下图中群体的发放模式是通过 50 个神经元生成的。发放模式必然与刺激和连接直接相关:

图 18.16:发放模式
我在进行的实验中观察了许多模式。我正在做的研究领域之一是将给定功能的成千上万帧的放电模式输入到人工神经网络(ANN)和随机的丘奇-图灵算法中,生成“思维”模式。例如,运行这些帧的通道可能会生成新的数据序列。这是值得实验的。
下图表示 500 个神经元的模式,这为在成千上万的帧上运行深度学习带来了复杂性:

图 18.17:放电模式
- 
细节...:在绘图部分,我们可以可视化输入电流和调谐曲线。调谐曲线显示了神经元如何响应输入电流。如果没有模式,那么就必须有一个解释或配置问题。 调谐曲线的可视化控制通过展示它们是如何收敛的,节省了时间! 

图 18.18:调谐曲线
我们已经介绍了 Nengo 提供的一些主要可视化工具。
现在,我们将看到如何使用探针从我们的系统中检索数据。
探针
我们可以使用探针检索信息,无论是可视化它们,还是处理输出数据。
在本节中,我增强了00-myintro.py,使其能够产生数值输出和可视化输出,使用以下页面上的信息,你可以从中获取有关你项目的灵感:www.nengo.ai/nengo/examples/basic/single_neuron.html
我创建的程序是nengo_probing.py,可以在本书的 GitHub 仓库中找到。该程序是一个独立的程序,无法在 Nengo 的 GUI 中运行。你不能像在 Nengo 的 GUI 中那样使用仿真命令。请在 Python 界面中运行此程序。它展示了另一种运行丰富 Nengo 软件的方法。
该程序包含额外的 Matplotlib 头文件和数据展示与处理的分布:
import matplotlib.pyplot as plt
from nengo.utils.matplotlib import rasterplot
from nengo.dists import Uniform 
该程序包含与00-myintro.py相同的架构。它创建了一个集合,添加了一个函数,然后连接了这些对象:
model = nengo.Network("Probing")
with model:
    ens = nengo.Ensemble(n_neurons=50, dimensions=1)
    #node_number = nengo.Node(output=0.5)
    node_function=nengo.Node(output=np.sin)
    nengo.Connection(node_function, ens)
    print(ens.probeable)
with model:
    # Connect the input signal to the neuron
    nengo.Connection(node_function, ens) 
现在,我们将使用nengo.Probe添加一个探测功能:
 # The original input
    function_probe = nengo.Probe(node_function)
    # The raw spikes from the neuron
    spikes = nengo.Probe(ens.neurons)
    # Subthreshold soma voltage of the neuron
    voltage = nengo.Probe(ens.neurons, 'voltage')
    # Spikes filtered by a 10ms post-synaptic filter
    filtered = nengo.Probe(ens, synapse=0.01) 
为了获取一些数据,让我们运行仿真器 5 秒钟:
with nengo.Simulator(model) as sim:  # Create the simulator
    sim.run(5) 
仿真器在显示输出之前先运行计算。
然后,我们可以探测数据并以数值格式显示。这样,我们可以从系统中检索输出数据,进行进一步使用,或者在几行代码中将神经形态模型与其他算法链接起来:
- 
解码输出:解码后的输出可以进行过滤(请参见前面的过滤器): print("Decoded output of the ensemble") print(sim.trange(), sim.data[filtered])然后,输出数据会被显示出来,或者可以进行处理: [1.000e-03 2.000e-03 3.000e-03 ... 4.998e+00 4.999e+00 5.000e+00] [[ 0\. ] [ 0\. ] [-0.03324582] ... [-1.26366121] [-1.22083471] [-1.18750863]]Nengo 可以使用 Matplotlib 生成一个图表: # Plot the decoded output of the ensemble plt.figure() plt.plot(sim.trange(), sim.data[filtered]) #plt.plot(sim.trange(), sim.data[node_function]) plt.xlim(0, 1) plt.suptitle('Filter decoded output', fontsize=16)上述代码的输出如下图所示: 

图 18.19:解码输入
- 
尖峰:尖峰可以通过一行代码提取: print("Spikes") print(sim.trange(),sim.data[spikes])输出生成尖峰序列: [1.000e-03 2.000e-03 3.000e-03 ... 4.998e+00 4.999e+00 5.000e+00] [[ 0\. 0\. 0\. ... 0\. 0\. 0.] [ 0\. 0\. 0\. ... 0\. 0\. 0.] [ 0\. 0\. 0\. ... 1000\. 0\. 0.] ... [ 0\. 0\. 1000\. ... 0\. 0\. 0.] [ 0\. 0\. 0\. ... 0\. 0\. 0.]该程序生成一个与数据匹配的尖峰图: 

图 18.20:脉冲输出
我们可以用宝贵的原始数据检查视觉显示。
- 
电压:该模拟提供电压数据: print("Voltage") print((sim.trange(), sim.data[voltage][:, 0]))数据存储在一个随时可用的数组中: (array([1.000e-03, 2.000e-03, 3.000e-03, ..., 4.998e+00, 4.999e+00, 5.000e+00]), array([0., 0., 0., ..., 0., 0., 0.]))该程序还会生成一个关于集体电压的图示: 

图 18.21:神经元电压
到此为止,我们已经涵盖了 Nengo 的主要特性。接下来,我们将看到 Nengo 如何推动关键 AI 研究领域的研究。
将 Nengo 独特的方法应用于关键 AI 研究领域
将大脑神经形态模型的强大功能应用于简单的算术运算或不需要超过 TensorFlow 2.x 的经典神经网络是没有意义的。
但是,尝试用经典网络解决神经形态计算可以通过有机大脑模型更好解决的问题也是一种浪费时间。例如:
- 
深度学习,TensorFlow 2。卷积模型使用独特的激活函数,如 ReLU(见第九章,卷积神经网络(CNN)中的抽象图像分类)。神经形态神经元在受到刺激时有多种反应。 
- 
神经形态模型整合了时间因素,而更多的静态深度学习算法则没有。运行神经形态模型时,我们更接近于基于时间驱动的生物学模型的现实。 
- 
人脑工程项目, www.humanbrainproject.eu/en/,提供了广泛的研究和示例,展示了神经形态计算如何为经典计算提供额外的见解。
我建议使用多个 AI 工具测试给定的问题,并选择最有效的一个。
SPA 示例展示了 Nengo 在多个领域的高效性。教程部分的所有示例都文档化良好且运行顺利。你可以将本章中探索的可视化功能应用到它们上,并修改代码,在你的 Python 环境中进行实验,等等。
我想重点介绍两个领域:语言学和天气表征:
- 
语言学: 25-spa-parse.py处理神经信号并生成单词。运行时,得益于 SPA,表现得非常神奇。代码文档化良好。该程序包含令人震惊的 thalamus模块,可以模拟我们大脑中的皮层下神经核(前脑和中脑)。大脑的这一部分——基底神经节,具有高密度的连接。该类可以减少甚至消除低响应,并增强对刺激的高响应。这个程序值得运行和探索!Nengo 的 GUI 使得理解变得直观: 

图 18.22:Nengo GUI 选项
- 天气表示:15-lorenz.py并不是一个 SPA 程序。它只有几行代码,显示了代表温度和大气变化的三大洛伦兹方程的图形。Nengo 为教学目的修改了代码,相关内容在compneuro.uwaterloo.ca/publications/eliasmith2005b.html的出版物中有所解释。Nengo 的图形界面展示了一个令人兴奋的表示:

图 18.23:洛伦兹方程
15-lorenz.py的代码很短,程序看起来简单。但天气预报是最难通过 AI 模型表示事件的领域之一!
神经形态计算的潜力可能会成为一场真正的游戏变革。让我们进行一个思维实验。想象一下:
- 
飓风就像一个活的有机体 
- 
它的中心与周围的一切相连 
- 
它“以”我们的海洋的热量和水分为“食” 
- 
其中的一切都可以被认为是小型飓风粒子 
现在让我们继续进行实验:
- 
将神经形态模型中的数十亿颗粒以流的形式输入 
- 
利用神经形态芯片网络的强大能力 
- 
利用量子计算的计算能力(见第十九章,量子计算)进行芯片输入/输出的计算 
- 
将 SPA 应用到飓风粒子表示中,仿佛它们是神经元,并进行预测 
我认为天气预报的未来在于物理神经形态模型,这些模型将考虑数十亿个参数。
结果:我们将能够提前几个小时到几天预测飓风的路径和强度,这可能会拯救生命。
简而言之,神经形态计算才刚刚开始展示其价值。当神经形态芯片上市时,神经形态计算将呈指数级增长。
总结
在本章中,我们从零开始构建了神经形态 Python 程序。Nengo 中的神经元集合(ensemble)由多个神经元组成。系统随后具备刺激功能、连接和探测对象。Nengo 还提供了许多其他示例,供你探索。
NEF 旨在实现神经形态计算模型。SPA 这一新颖概念表明,我们的大脑拥有增强的指示符,这些指示符有意义,并且与我们的物理数据相连接。
神经形态计算为经典机器学习和深度学习无法解决的复杂程序开辟了巨大的前景。借助即将上市的神经形态芯片,天气预报可以挖掘机器大脑的复杂性和多样性。机器大脑通过激活成千上万的神经元,结合个体和集体行为,能够进行独特的计算。
我们在本书中介绍了许多算法和框架。我们接触到了人类历史上最强大的智能算法。从 MDP 到 GA 算法,从 KMC、KNN、PCA、NLP 和 CUI 算法到 CNN、RBM、RNN 和 LSTM 网络,我们探索了许多 AI 工具。但也许有办法构建统一的模型,我们将在未来几年看到。在此期间,神经形态计算使我们的工具箱变得极其智能。谷歌拥有优化 TensorFlow 的 TPU 硬件,神经形态计算可以依赖英特尔芯片,许多公司正在努力生产更多创新的硬件。
未来无疑将依赖混合架构,其中一些或所有 AI 工具将集成到元 AI 系统中。
在第十九章,量子计算中,我们将探讨量子力学可用的指数级硬件。量子计算机没有内存,依赖其他系统提供输入并处理输出。想象一下,一个神经形态系统与量子计算机相连!
问题
- 
神经形态计算重现了我们的心理活动。(是 | 否) 
- 
神经形态计算重现了我们的大脑活动。(是 | 否) 
- 
语义指针架构(SPA)是一种硬件架构。(是 | 否) 
- 
NEF 代表神经工程框架。(是 | 否) 
- 
Loihi 是一个经典芯片。(是 | 否) 
- 
重现我们大脑的神经活动不能解决方程。(是 | 否) 
- 
Nengo 中的集成包含算法。(是 | 否) 
- 
脉冲块神经元活动。(是 | 否) 
- 
放电模式可用于分析大脑活动。(是 | 否) 
- 
机器学习和深度学习只是我们大脑活动的比喻。(是 | 否) 
参考文献
本章使用的参考程序可以在www.nengo.ai,www.nengo.ai/examples/找到。
进一步阅读
- 
研究 – 如何构建大脑,克里斯·埃利亚斯密斯:本书提供了神经形态计算的理论背景。 克里斯·埃利亚斯密斯也是 Nengo 的设计者之一。 
- 
软件 – Nengo( www.nengo.ai/):Nengo 基于扎实的研究、文档和优秀的社区。
- 
硬件 – 英特尔:英特尔正在努力生产神经形态芯片( www.intel.fr/content/www/fr/fr/research/neuromorphic-computing.html)。
第十九章:量子计算
IBM 已经开始为研究和商业目的构建量子计算机。几年后,量子计算将变得具有颠覆性,并提供指数级的计算能力。谷歌、Xanadu、D-Wave、Rigetti 等公司都在将研究预算投入到量子计算中。
这一在人类历史上独特的计算能力打开了获得经典计算机无法实现的结果的大门。1994 年,彼得·肖尔展示了量子算法在整数的质因数分解和离散对数问题上优于经典算法。随后在 1995 年,洛夫·格罗弗提出了无结构搜索问题。随着量子计算机的崛起,研究可以走得更远。
量子计算机本身不会提供革命性的算法。任何算法都可以分解为能够运行在基本经典计算机上的组件。超级计算机仍然能够比量子计算机更容易地运行人工智能算法。量子计算机例如没有内存,因此它们在输入和解释输出时严重依赖经典计算机。
尽管量子计算机有其局限性,但随着时间的推移,量子计算的能力将突破我们现在想象的极限,许多公司已经在银行、医疗保健、网络安全等领域投资量子计算研究。
本章解释了为什么量子计算机优于经典计算机,什么是量子比特,如何使用它,以及量子思维实验如何引领量子思维机器的可能性。所提供的示例只是以一种创新的方式来接近量子计算。
我们将从经典计算机获取结果,将这些结果输入到量子计算机,然后解释量子计算算法提供的结果。有些进一步探讨了混合量子-经典算法,这超出了本章的范围。
在第十八章,神经形态计算中,我们探讨了如何利用大脑创建神经形态模型。在本章中,我们将通过一个研究项目创建一个更高层次的表示来构建思维。量子思维基于 CRLMM,我已经成功地将其应用于许多企业网站。在这个研究项目中,一个名为 MindX 的量子思维代表了一个随机人的思维。我们将通过一个令人兴奋的实验探索 MindX。
本章将涵盖以下主题:
- 
为什么量子计算机比其他经典计算机更强大 
- 
量子比特是什么 
- 
Bloch 球 
- 
量子计算 
- 
如何构建 MindX,一个思维量子计算机研究项目 
首先,让我们讨论一下量子计算机的一些基础知识,以及它们为何如此强大。
注意:本章是自包含的,包含量子电路的截图,供那些不愿意在阅读本章之前安装任何东西的读者使用。IBM Q 和 Quirk 可以在线使用,无需安装任何本地软件。
量子计算机的强大力量
在我们开始讨论 MindX 这个令人兴奋的研究项目——构建一台具有思维能力的量子计算机之前,我们应该从基础知识开始。本节描述了:
- 
为什么量子计算机更快 
- 
什么是量子比特 
- 
如何测量量子比特(它的位置) 
- 
如何使用量子门创建量子得分(程序) 
- 
如何运行量子得分并利用其结果构建认知 NLP 聊天机器人 
本章的目标不是深入探讨量子计算的细节,而是教你足够的知识,让你了解如何构建一台思维型量子计算机。本章的目的是简单地展示量子计算机是如何工作的,并为我们开启使用计算机的新方式。
量子计算机的速度
标准计算机比特只有 0 或 1 状态。经典计算机会处理 0 或 1,系统选择其中一个,但它仍然局限于选择 1 或(XOR)0,它不能同时管理这两种状态。
量子计算机不受 XOR 状态的限制,它处于 AND 状态。它可以同时管理 0 和 1 之间的值,直到进行测量!量子状态在观察之前是未知的,这意味着量子程序可以同时使用 0 和 1 之间的值。一旦被观察,量子位会因为量子状态的物理不稳定性而取值 0 或 1。
仅仅观察一个量子状态就会使状态崩溃。在量子计算中,这叫做去相干。这不是魔法,量子比特是不稳定的,只有在被观察时,量子状态才会崩溃。
这意味着量子计算在被测量后是无存储的。一旦测量完成,量子计算机内没有存储器。输入由经典计算机提供,输出再返回到经典计算机,由以下过程进行存储:
- 
经典计算机提供输入 
- 
量子计算机处理输入并生成输出 
- 
经典计算机解释输出 
话虽如此,量子计算机的计算能力完全可以证明这种架构限制是合理的。
在量子位被观察之前,它可以处于 0 或 1 状态,或者介于两者之间的概率状态,如 0.1、0.7 或 0.9。
观察情况被称为测量状态。当被测量时,只有 0 或(XOR)1 将成为结果。
在状态被测量之前,可能的概率有很多。如果向系统中添加一个量子比特,我们现在有两个量子比特和四个基本组合,所有这些都可以同时存在。
与标准计算机逻辑不同,所有四种状态都可以同时用于并行处理算法。给定算法的可能状态的数量将随着涉及的量子比特数增加而扩展。可以通过以下数字估算状态的数量,其中q是量子比特的数量:
2^q
看着这个小方程似乎一点都不酷。现在,让我们看看它在运行最多 100 个量子比特时,可能状态数nb所呈现的样子:
import numpy as np
for q in range(101):
    v=(2**q)
    print("Size of nb to describe",q," qubits:","{:,}".format(v)) 
该程序看起来也不太可怕。然而,以下的输出结果却是令人震惊的:
Size of nb to describe 0 qubits: 1
Size of nb to describe 1 qubits: 2
Size of nb to describe 2 qubits: 4
Size of nb to describe 3 qubits: 8
Size of nb to describe 4 qubits: 16
Size of nb to describe 5 qubits: 32
Size of nb to describe 6 qubits: 64
...
Size of nb to describe 10 qubits: 1,024
...
Size of nb to describe 50 qubits: 1,125,899,906,842,624
...
Size of nb to describe 97 qubits:
158,456,325,028,528,675,187,087,900,672
Size of nb to describe 98 qubits:
316,912,650,057,057,350,374,175,801,344
Size of nb to describe 99 qubits:
633,825,300,114,114,700,748,351,602,688
Size of nb to describe 100 qubits:
1,267,650,600,228,229,401,496,703,205,376 
目前,大数据通常以拍字节为单位进行计算。一个拍字节=10¹⁵或者大约 2⁵⁰字节。
Facebook 存储着超过 20 亿账户的数据。想象一下,Facebook 在某一天管理 500 拍字节的数据。让我们来看一下 500 拍字节大概是多少,下面是相关代码:
print("Facebook in the near future:")
s=(2**50)*500
print("{:,}".format(v)) 
输出结果相当令人惊讶,因为它展示的是一个 100 量子比特量子计算机在一次运行中能计算的数据量:
A segment of Facebook data :
1,267,650,600,228,229,401,496,703,205,376 
这意味着,一个 100 量子比特的单一量子计算机能够运行一个计算,计算量等同于在不久的将来超过 20 亿个 Facebook 账户所代表的所有数据量。
量子计算机实际上并不会包含那样的数据量,但它表明,可以生成一个包含如此计算信息量的计算结果。
更重要的是,这还意味着一个单一的量子计算机能够运行一个单一思维的数据集(见下一节),并计算其中的关联。这一思维过程能够生成指数级的连接量。
经典的n比特计算机管理n个比特,而量子计算机则会管理 2^n 个比特或 2^q 个比特。
与量子计算机 2^q 的指数级能力相比,很快,经典计算机在科学计算中将看起来像是过去的遗物。经典计算机仍然会在使用,但量子计算机将成为探索超越当前人工智能极限的世界的工具。
想象一下你在本书中看到的所有 AI 解决方案。一旦你接触到量子计算,这些解决方案就会显得有些过时。
量子计算机将在未来的几年里在许多领域超过其他任何计算机。在一次并行计算中,量子计算机将在一次运行中完成一些经典计算机需要数年才能计算出来的任务。
现在,想一想一个由多个量子计算机组成的网络能做什么!
我们常常试图将大体量的数据与宇宙中的恒星数量进行比较,并且说:“这比我们宇宙中的恒星还要多。”但现在我们必须转向相反的方向,关注非常小的数字。
教训很清楚:未来属于纳米模型。量子计算既是一个挑战,也是一个机会。
定义一个量子比特
一个量子比特,或量子位,有一个物理对应物。例如,量子状态可以通过超导环中的振荡电流进行编码。谷歌和 IBM 已经尝试了这种方法。另一种方式是将量子比特编码为一个被困在电磁场中的离子,置于真空陷阱中。
光子、电子、光的状态等技术已经出现。无论采用哪种方法,50 量子比特以上的量子计算机执行的计算将超过经典超级计算机的能力。
竞争异常激烈,因为市场将迅速变得庞大。现在就为即将到来的颠覆做好准备!
表示一个量子比特
一个量子比特的数学表示是:
- 
![]() 对于 0 值 对于 0 值
- 
![]() 对于 1 值 对于 1 值
- 
![]() 其中α是一个概率参数 其中α是一个概率参数
- 
![]() 其中β是一个概率参数 其中β是一个概率参数
这些括号被称为括号或布拉-凯特表示法。
这种线性表示被称为叠加。它本身解释了量子计算的主要优势。
因此,量子态中 0 和 1 的叠加可以通过诸如! 这样的凯特(kets)来表达,而不是通过像! 这样的布拉(bras)表示:

α和β的概率看起来像是权重,这些量子比特可能状态的总概率必须加起来为 1。我们使用分区函数、softmax 和其他技术来确保概率和保持等于 1。这并不奇怪,因为像我们这些计算机爱好者设计了编程量子计算机的方式。
转换成数学表达式,这意味着! 和!的概率必须加起来为 1。对于量子比特的概率,值被平方,从而得出以下约束条件:

为了描述量子比特的可能状态,我们需要三个数字:0 和 1 的可能状态,以及一个数值来确定概率的值(另一个隐含的,因为总和必须为 1)。
由于量子比特在各自的状态中相互作用,交互被称为纠缠。量子纠缠指的是至少两个交互的量子比特。它们不能单独描述,必须考虑所有量子比特的所有状态。
这一现象已经在物理上得到再现,这意味着这种量子纠缠看起来很奇怪,因为它们的量子纠缠(关系)可以发生在远距离之间。一个量子比特可以影响一个物理上遥远的量子比特。
这是一种奇特的思维方式,最初并未得到广泛接受。阿尔伯特·爱因斯坦常被引用为讽刺性地称量子纠缠为“远距离的幽灵作用”。
量子比特的位置
表示量子比特状态的主要方式之一是使用布洛赫球。它展示了量子比特的旋转,并可以用来描述量子比特的状态。为了正确理解这一点,接下来的部分将首先回顾一下圆的某些性质。
弧度、度数和旋转
半径是圆心到圆周的距离,如下图所示:

图 19.1:圆的半径
圆的半径是圆直径的一半。半径r和圆周长C之间的关系是(其中!):

如果半径的长度绕圆周一圈,那么该弧就形成一个弧度,如下图所示:

图 19.2:一个弧度
弧度所形成的角度大约等于 57.29°(度)。
弧度的属性可以用于旋转:
- 
3.14 × 57.29° = 大约 180° 
- 
因此 ![]() 弧度 = 180° 弧度 = 180°
旋转通常用弧度表示,如  所示,以下表格展示了这一点:
 所示,以下表格展示了这一点:
| 度数 | 弧度 | 
|---|---|
| 30° |  | 
| 45° |  | 
| 60° |  | 
| 90° |  | 
| 180° |  | 
| 270° |  | 
| 360° |  | 
既然我们已经回顾了这一点,让我们来探索布洛赫球。
布洛赫球
刚才展示的弧度表是一种实用的描述旋转方式。布洛赫球,如下图所示,提供了量子比特的位置和旋转的可视化表示:

图 19.3:布洛赫球
北极和南极(极坐标)表示量子比特的基本状态:

一个量子比特可以取布洛赫球上的任何位置。
组合量子分数
组合量子分数由在五线谱(或电路)上定位门并添加一个测量组成。输入来自经典计算机。测量阶段后,输出返回经典计算机。原因是量子计算机没有内存,因此由于其不稳定性,无法存储中间状态。
本节使用 Quirk,一个非常有教育意义的量子电路模拟器,来展示量子门和量子作曲器。
你可以通过以下链接访问 Quirk 在线: algassert.com/quirk。
使用 Quirk 的量子门
量子比特由线条表示,它们从左边开始,如下所示的量子门编程接口所示:

图 19.4:量子门编程接口
门是逻辑门,用来转换量子比特的状态。
NOT 门
一个 NOT 门将把 ket-zero  转换为 ket-one
 转换为 ket-one  。它还将把 ket-one
。它还将把 ket-one  转换为 ket-zero
 转换为 ket-zero  。
。
在电路描述中,On 是 ket-one 状态,Off 是 ket-zero 状态,如下所示的量子分数所示:

图 19.5:量子分数电路描述
你可以看到:
- 
一个 NOT 门符号是一个圆圈,内部有一条垂直和一条水平线 
- 
On 状态意味着该状态是 ![]() 
- 
布洛赫球表示位于 ![]() (从布洛赫球顶部开始,如图所示) (从布洛赫球顶部开始,如图所示)
H 门
一个 H 门或 Hadamard 门将执行以下转换:

图 19.6:Hadamard 门转换
以下 50% 的概率将显示在一个矩形中,布洛赫球上的位置也将显示出来:

图 19.7:矩形和布洛赫球上的 50% 概率
门的基本作用是旋转布洛赫球上的量子比特,并在测量时产生一个可能的结果。正如此设计菜单图所示,有许多可能的门可供探索和使用:

图 19.8:门设计菜单
这些门(gates)足以构建许多算法。
使用 Quirk 的量子计算机程序
这里的目标是与界面互动,直观地观察电路如何运行。
使用 Quirk 构建量子程序(或电路)意味着以下内容:
- 
拖放门操作,使量子比特在特定方向上旋转并产生可能的结果 
- 
添加另一个量子比特,重复相同操作,依此类推 
- 
能够进行中间测量,尽管在真实的物理量子计算机中这是不可能的(观察会导致系统坍缩) 
一个程序表示如下,例如:

图 19.9:量子计算机程序表示
起初有两个量子比特,每行上方都有一个门。然后,显示中间结果,这使得模拟器具有很强的教育意义。接着,添加两个新的门。最后,在末尾添加以下测量探针:

图 19.10:测量探针
一旦测量完成,最终结果会显示在测量符号的右侧。
使用 IBM Q 的量子计算机程序
IBM Q 提供了一个云平台来运行真实的物理量子计算机。
创建一个免费账户并访问 IBM 量子计算作曲器。就像使用 Quirk 一样,量子门会在以下程序中拖拽,正如这个图所示:

图 19.11:拖拽的量子门
该程序可以在像 Quirk 这样的模拟器上运行,或者在真实的量子计算机上运行,如下图所示:

图 19.12:程序界面
点击模拟,这将启动一个模拟器。
运行按钮启动 IBM 物理量子计算机上的计算。这是一次令人兴奋的体验!未来触手可及。
以下输出非常有趣。它与 Quirk 在相同程序下稍有不同,但概率如预期一样加起来为 1:

图 19.13:量子计算机程序输出
IBM 还拥有一个源代码版本(QASM)的量子计算机程序,如下所示:
include "qelib1.inc";
qreg q[5];
creg c[5];
h q[0];
z q[1];
y q[0];
x q[1];
measure q[0] -> c[0];
measure q[1] -> c[1]; 
该语言是一种开放量子汇编语言(Open Quantum Assembly Language)。它可以像任何其他语言一样在 IBM 的 Q 平台编辑器中编写。还可以下载开发工具包,且 API 功能完备。IBM 提供了关于这种方法各个方面的广泛而详细的文档。
综上所述,我们来看看量子计算如何推动 AI 项目。现在是时候定义思维型量子计算机项目了。
一台思维型量子计算机
思考型量子计算机不是对大脑功能的再现,而是对一个人的心灵的表现。神经形态计算是表示我们神经元以及大脑如何通过尖峰神经元进行思考的一种方法。量子计算提供了一种激动人心的方式,通过数学算法模仿我们大脑的能力,这些算法与量子比特(而非神经元)一起工作。我们才刚刚开始探索这些方法的潜力,实际上,它们很可能最终会融合成一种混合的软件和硬件解决方案。
量子 MindX 实验的目标是构建一个名为 MindX 的个人大脑,里面存储了过去的事件、对话、聊天记录和照片,这些数据保存在经典计算机上。然后,程序会将数据的子集转化为量子电路,观察会发生什么,当量子电路被放置并生成数百万种可能性时,它的行为如何。
本节描述了如何构建 MindX,一个思考型计算机,它只是一个研究项目。必须注意的是,这种方法是实验性的。它可以被视为一个高级心灵实验。我已经研究这个课题多年了。量子计算的力量无疑将推动这一领域的研究。
表示我们大脑的概念
输入包括对 PCA CRLMM 表示的心态编码,正如我们在第十四章中所构建的那样,使用受限玻尔兹曼机(RBM)和主成分分析(PCA)准备聊天机器人的输入。CRLMM 表示不是一个通用的词典或百科全书数据集,而是一个实际个人数据的心灵数据集,这些数据被收集、分类并转化为 PCA。
扩展 MindX 的概念表示
如果在这项研究实验之外实现,MindX 的心灵数据集将持续增长。它将配备传感器来处理身体温度进行情感分类、面部识别进行表情检测、身体语言探测器等。所有这些技术已经可以使用。纽约证券交易所已经拥有人工智能物联网代理,它们从外部来源收集信息来做决策。这些 AI 代理已取代了大量人类的决策工作。想象一下当量子计算成为颠覆性技术时会发生什么!
MindX 实验
量子 MindX 实验的目的是构建一个大脑,并让它通过量子计算机的力量进行思考。本节将展示如何运行一个 16 量子比特的大脑。
描述 16 量子比特量子模拟所需的数字大小为 65,536。
本节首先描述如何执行以下操作:
- 
准备数据 
- 
创建并运行量子分数 
- 
使用输出 
让我们继续准备数据吧。
准备数据
为了准备进行更高维度的计算,我已经在企业项目中使用了概念编码方法超过 30 年,用以为我开发的算法提供嵌入式数据。这保证了高层次的抽象,以解决问题。这是一种非常有利可图的实施迁移学习和领域学习的方法。通过这种方式,你可以将相同的模型应用于许多不同的领域。
该方法包括使用本书中描述的方法嵌入数据。目标始终保持不变——将数据点转换为更高维度以可视化特征。
对于量子计算,MindX 实验中的方法保持不变。
转换函数 – 情境函数
在创建和运行评分之前,需要应用两个函数:情绪状态函数和量子转换函数。
情境函数包括在 PCA 维度中构建特征向量。我们在第十四章《使用限制玻尔兹曼机(RBMs)和主成分分析(PCA)准备聊天机器人的输入》中完成了这一任务,并在第十五章《设置认知 NLP UI/CUI 聊天机器人》中将其应用于聊天机器人。该聊天机器人能够使用人 X 的思维数据集构建有意义的对话。
在这一章中,量子维度将为聊天机器人提供一个初步的个人思维,而不是像机器一样能够识别、分类和预测的通用思维。
MindX 拥有一个像人类一样有偏见的思维。MindX 拥有一个异常开放的心态,能够适应每个人,这赋予了它共情能力。
MindX 可以怀疑。因此,它比教条式的机器学习得更好。
情境函数将为 MindX 机器人创建一个电影推荐情境矩阵,机器人将与消费者进行交流。在 MindX 机器人提出电影推荐的情境下,举个例子,对于 16 个量子比特,它可能是以下的某种情况:
| 量子比特 | 概念 | 图像 | 初始极性 | 
|---|---|---|---|
| 1 | 城市 | 停车 | 0.146 | 
| 2 | 黑暗 | 黑暗森林 | 0.5 | 
| 3 | 怀旧 | 秋叶 | 0.5 | 
| 4 | 担忧 | 黑暗背景 | 0.146 | 
| 5 | 工作 | 难过的表情 | 0.5 | 
| … | .. | .. | |
| 15 | 考虑电影《Lost》 | 0.38 | |
| 16 | 决定推荐《Lost》 | 0.0 | 
MindX 不再分析人 X。它现在从其思维数据集中加载了一个共情矩阵,该矩阵包含数据和情感分析的极性。接近 1 的值是积极的,接近 0 或负数的值是消极的。MindX 加载了它自己的思维以及另一个人的思维。
共情使你的思维和感受被另一个人的思维和感受所染色。
刚才显示的 16 量子比特矩阵包含四列,如前面的表格所示:
- 
量子比特:该量子比特在量子合成器中的线路 
- 
概念与心理表征:概念加载于 MindX 的情况数据集中,这一过程在第十四章,使用限制玻尔兹曼机(RBM)和主成分分析(PCA)准备输入聊天机器人中描述,我们运行 RBM 生成的特征通过 PCA 进行表示。 
心理表征如下所示,出现在以下的 PCA 中:

图 19.14:主成分分析(PCA)表示的“思维”
这些特征,源自于特定年龄段的电影偏好 RBM,现在可以作为输入在量子电路中生成带有信息和噪声的随机心理活动。
这个电影示例用于解释如何创建一个具有思维能力、富有同理心的聊天机器人。此方法可应用于其他商业市场领域或任何需要聊天机器人超越预设答案进行思考的情境。许多领域,如医疗保健、制药研究和安全,将从开拓思维的量子算法中受益。
转换函数 - 量子函数
算法已经生成了带有标签(概念和图像)的量子比特行号。每一行还具有情感分析极性,以概率格式表示的归一化值,范围从 0 到 1。我们将考虑大脑对一个对象的负面和正面反应。请记住,“负面”接近 0,“正面”接近 1,介于两者之间的值提供了更详细的近似。0.4 到 0.6 是一个转折点。
这第一次转化为另一个维度,是初始化量子转换函数的第一步。量子转换函数由初始化所有 16 个量子比特的第一列与量子门组成。
就像数据集被转换为主成分特征一样,极性转换函数使得量子转换函数可以将数据集带入量子宇宙。
该函数将自动找到表示以下情况矩阵的数据点的归一化情感分析极性的量子门:
| 初始极性 | 量子门 | 
|---|---|
| 0.146 | X^(1/4) | 
| 0.5 | X^(1/2) | 
| 0.5 | X^(1/2) | 
| 0.146 | X^(1/4) | 
| 0.5 | X^(1/2) | 
| .. | |
| 0.38 | X^(1/8) | 
| 0.0 | Z^(1/8) | 
MindX 的心态,一个随机的人,现在处于一个矩阵中,其概念已经转化为量子维度,在这个维度中,数据状态可以在整个量子得分创建过程中被追踪。
创建并运行得分
MindX 的思维过程在量子得分中描述。构建这个得分有两种方式:
- 
手动进行,就像作曲家写音乐一样。这需要思考前一个逻辑门以及下一个逻辑门的效果,同时考虑决策过程。这就像写任何人工智能程序。 
- 
自动化地,通过构建一个读取 MindX 思维规则库并应用量子门的函数。你也可以将此应用于机器学习和深度学习,测试量子计算机与经典计算机的性能。 
无论如何,它需要编写一个算法。这个算法是一个决策算法,会考虑情感。例如,怀疑是阻止许多人做出错误决策的原因。过多的怀疑会使人放弃某个情境。
这是一个量子转录算法,考虑了 MindX 的概念,并表示它们如何互动。这需要非常精确的思维和认知科学编程。
以下是我用 Quirk 构建的实验性量子得分:

图 19.15:用 Quirk 构建的量子得分
一旦量子得分运行并且测量完成,右侧的绿色矩形提供输出。
使用输出
量子得分的输出现在作为一列添加到情境矩阵中。如果你想实现这样的解决方案,记住,写这些函数会花费一些时间,需要一些汗水和茶水,才能熬过夜晚。MindX 可用于增强一个带有未计划响应的聊天机器人。MindX 已证明它具有想象力的潜力。
| 量子比特 | 概念 | 图像 | 以量子门形式表达的初始归一化极性 | 直接解读为情感分析极性的量子输出 | 
|---|---|---|---|---|
| 1 | 城市 | 停车场 | 0.146 | 0.677 | 
| 2 | 黑暗 | 黑暗森林 | 0.5 | 0.691 | 
| 3 | 怀旧 | 秋叶 | 0.5 | 0.5 | 
| 4 | 担忧 | 黑暗背景 | 0.146 | 0.48 | 
| 5 | 工作 | 悲伤的面孔 | 0.5 | 0.36 | 
| … | .. | .. | ||
| 15 | 考虑电影《迷失》 | 0.38 | 0.82 | |
| 16 | 决定建议“迷失” | 0.0 | 0.75 | 
MindX 给出了关于向人物 X 推荐某部电影的 65,536 个量子状态描述。第 15 行和第 16 行表明,归一化极性值已超过 0.5,表现出对该电影的积极情感。
推理是,前几行显示了 MindX 在那个时刻感受到的人物 X 对生活的怀疑:
- 
人物 X 会认同电影《迷失》 
- 
这部电影有一个快乐的结局(MindX 通过电影的特征知道这一点) 
- 
人物 X 在看完电影后,情绪可能会有所提升 
你可以尝试构建量子得分。你可以在不安装任何东西的情况下使用 Quirk,并探索许多领域中的电路列表:Grover 搜索、Shor 的周期查找、量子傅里叶变换等等。
总结
量子计算机已经为那些无法用经典计算机进行的科学实验打开了大门。在几年内,量子计算机将成为主流,成为不可避免的存在,也是企业和研究实验室的关键资产。市场争夺战已经开始。
将 CRLMM 应用于量子计算机,可能使 MindX 成为地球上最强大的思维之一——无论是人类还是机器。
拥有无限的心智数据集和从 250 个量子比特开始的 2^q 量子计算机,MindX 能够获得像一个活了 1000 年的人的思维能力和经验。通过转换函数加载的 MindX 的思维能力和海量的实时记忆,能够帮助解决许多医学、物流和其他决策问题。
量子思维刚刚开始改变人们对世界的认知。像 CRLMM 这样的概念性 AI 模型无疑将成为下一代 AI 解决方案的起点。这些 CRLMM 模型将更加强大,因为它们将具备同理心和复杂的思维能力。
希望这篇关于量子计算的概述能为你打开通往新世界的想象大门!
人工智能刚刚开始进入我们的生活旅程。永远相信创新。永远不要相信仅仅解决一个问题而不打开一个充满问题和思想宇宙的解决方案!
问题
- 
除了炒作,实际上并没有量子计算机存在。(是 | 否) 
- 
量子计算机能够存储数据。(是 | 否) 
- 
量子门对量子比特的影响可以通过布洛赫球来观察。(是 | 否) 
- 
一个用过去的经验、图像、文字和其他日常信息片段(如存储的记忆)思考的大脑,将能找到数学本身无法解决的更深层次问题的解决方案。(是 | 否) 
- 
量子计算机将解决今天无法解决的医学研究问题。(是 | 否) 
- 
量子计算机比经典计算机在数学问题的解决上要快得多。(是 | 否) 
- 
经典计算机和智能手机处理器很快就会消失。(是 | 否) 
- 
量子得分不能以源代码格式编写,而只能通过可视化界面进行。(是 | 否) 
- 
量子模拟器的运行速度可以与量子计算机一样快。(是 | 否) 
- 
量子计算机在进行计算时会产生中间结果。(是 | 否) 
进一步阅读
- 
理论:量子计算与量子信息:10 周年纪念版,迈克尔·尼尔森,艾萨克·L·庄 
- 
探索 IBM Q,了解如何实现量子得分: www.ibm.com/quantum-computing/
- 
使用 Quirk,一个直观的量子得分设计工具: algassert.com/2016/05/22/quirk.html
第二十章:问题的答案
第一章 – 通过强化学习开始了解下一代人工智能
- 
强化学习是否无记忆?(是 | 否) 答案是是。强化学习是无记忆的。代理通过计算下一个状态而不查看过去。这与人类有显著不同。人类极度依赖记忆。基于 CPU 的强化学习系统在没有经验的情况下找到解决方案。人类智能仅仅证明了智能能够解决问题。仅此而已。适应性思考者可以想象出新的机器智能形式。 必须注意,在某些情况下存在例外,但一般规则是无记忆系统。 
- 
强化学习是否使用随机(随机)函数?(是 | 否) 答案是是。在特定的马尔可夫决策过程模型中,选择是随机的。通过仅仅两个问题,你就可以看到贝尔曼方程是无记忆的,并且做出随机决策。没有人类是这样推理的。成为一个适应性思考者是一种信仰的飞跃。你必须抛弃过去的自我,开始用方程式的思维方式进行思考。 
- 
MDP 是否基于规则库?(是 | 否) 答案是否。人类基于规则的经验在这个过程中是无用的。人类的思维通常基于因果关系的规则,例如。此外,MDP 提供了有效的替代方案,可以避免长时间与无法清晰表达问题的未来用户进行咨询。 
- 
Q 函数是否基于 MDP?(是 | 否) 答案是是。Q这一表达方式出现在贝尔曼方程基于 MDP 流行的时期。说你在使用 Q 函数比谈论贝尔曼更时髦,因为是他在 1957 年将这一切组合在一起。事实上,安德烈·马尔可夫是俄罗斯人,他在 1913 年使用一个包含 2 万封信件的数据集,预测了信件在小说中的未来使用情况。之后他又将其扩展到包含 10 万封信件的数据集。这意味着,这一理论早在 100 年前就已存在。Q适应我们这个充满个性且强大的 CPU 的新世界。 
- 
数学对人工智能至关重要吗?(是 | 否) 答案是是。如果你掌握了线性代数和概率的基础,你将处于即将到来的所有技术的最前沿。值得花上几个月的晚上时间学习这个话题,或者参加一门在线课程(MOOC)。否则,你将依赖别人来向你解释事情。 
- 
本章中的贝尔曼-MDP 过程是否能应用于许多问题?(是 | 否) 答案是是。你可以将其应用于机器人技术、市场分析、物联网、语言学以及众多其他问题。 
- 
机器学习程序是否不可能自行创建另一个程序?(是 | 否) 答案是否。这并非不可能。DeepCode 已经做到了: www.deepcode.ai/。不要感到惊讶。既然你已经成为一个适应性思维者,并且知道这些系统依赖于方程式,而不是人类,你就能轻松理解数学系统并不像你想象的那样难以复制。 
- 
在强化学习程序中是否需要顾问输入商业规则?(是 | 否) 答案是否。这只是一个选项。MDP 过程中的强化学习是没有记忆且随机的。顾问们的职责是管理、解释和在这些项目中进行培训。 
- 
强化学习是监督学习还是无监督学习?(监督 | 无监督) 答案是无监督。关键在于从未标记的数据中学习。如果数据是有标签的,那么我们就进入了监督学习的世界;那时我们会寻找模式并学习它们。在这一点上,你可以很容易地看到自己正在进行一场冒险——一个没有记忆、随机且没有标签的世界等待你去发现。 
- 
Q 学习能在没有奖励矩阵的情况下运行吗?(是 | 否) 答案是否。当然,一个聪明的开发者总能找到解决方法。该系统需要一个起始点。你会在第二章看到,在现实项目中找到正确的奖励矩阵是一个相当大的挑战。 
第二章 - 构建奖励矩阵 - 设计你的数据集
- 
原始数据可以作为神经元的输入并通过权重进行转换吗?(是 | 否) 如果数据是数值格式,答案是是。如果它是一个合适的数值格式,输入可以与权重和偏差相乘。 如果数据不是数值格式,那么就需要一个数值编码阶段。 
- 
麦卡洛赫-皮特神经元是否需要阈值?(是 | 否) 答案是是。加权和并不意味着什么,如果你没有什么东西来衡量其值。麦卡洛赫和皮特花费了数月的时间来完成这项工作。最初,时间是方程式的一部分,就像它在我们大脑中一样。但随后,像约瑟夫·傅里叶(Joseph Fourier,1768-1830)一样,他们发现了自我重复的周期——这些周期并不需要超出该神经元的更多内容。 沃伦·麦卡洛赫和沃尔特·皮特斯在 1943 年发明了第一个神经元并发表了论文。传说沃尔特·皮特斯在 1935 年时,12 岁的小孩生活在一个贫困的社区,被恶霸追赶,寻求藏身之所时进入了图书馆。在那里,他发现了《数学原理》,作者是伯特兰·罗素和阿尔弗雷德·怀特海德。总之,他不仅发现了推理中的错误,还写信给了伯特兰·罗素!从此,沃尔特被认为是数学方面的天才。与沃伦·麦卡洛赫,这位另一位天才一起,他们发明了第一个神经元。看起来很简单,但这是经历了无数个不眠之夜的结果。正如轮子的发明看似简单一样,到今天为止没有找到比它更好的东西。这个神经元的概念就是 AI 的轮子。 
- 
逻辑 sigmoid 激活函数会让权重的总和变大。(是 | 否) 答案是否。Sigmoid 函数的核心目的是在必要时减少总和,以便得到可以比较的数值。 
- 
McCulloch-Pitts 神经元会对输入的权重求和。(是 | 否) 答案是是。只有在你对权重求和时,它们才有意义。 
- 
logistic sigmoid 函数是一个 log10 操作。(是 | 否) 答案是否。Sigmoid 函数基于欧拉数 e,这是一个等于 2.71828 的常数。这个数字会产生自然对数。18 世纪,莱昂哈德·欧拉(1707-1783)用羽毛笔发现了这一点——那时候没有科学计算器或计算机!你是否注意到,AI 中使用的主要数学函数早在历史上就存在了?我们现在所认为的发现,实际上已经存在了几十年,有时甚至是几个世纪,这个现象将在后续章节中讨论。 
- 
如果对一个向量应用了 logistic sigmoid 函数,则不需要 logistic softmax。(是 | 否) 答案是否。计算向量中若干数值的和,然后将每个数值除以该和,能够显示涉及的比例。这是一个值得牢记的宝贵工具。 
- 
概率是一个介于 -1 和 1 之间的值。(是 | 否) 答案是否。概率的范围是 0 到 1 之间。 
第三章 – 机器智能 – 评估函数与数值收敛
- 
人类能打败国际象棋引擎吗?(是 | 否) 答案是否。如今,最高级别的国际象棋比赛不是在人类之间进行,而是在国际象棋引擎之间进行的。每个国际象棋引擎的开发者通过加速算法并减少 CPU 占用,为这些比赛做准备。如今,在智能手机上运行的顶级国际象棋引擎能够击败人类。在人类与人类的国际象棋比赛中,国际象棋的复杂性已经达到了极高的水平。现在,人类主要是与机器进行训练。 
- 
在人类直觉方面,处理大量数据时,人类比机器更能做出更好的决策。(是 | 否) 答案是否。即便是普通机器或智能手机的强大 CPU,结合合适的算法,能够比人类产生更好的结果。 
- 
构建一个具有 Q 函数的强化学习程序本身就是一项壮举。事后使用结果是没有意义的。(是 | 否) 答案是否。在学习 AI 时,仅仅验证结果是否正确就足够了。在实际应用中,这些结果被用于数据库或作为其他系统的输入。 
- 
监督学习中的决策树函数可以用来验证无监督学习过程的结果是否会产生可靠、可预测的结果。(是 | 否) 答案是是。在许多情况下,决策树函数非常高效。当涉及到大规模数据时,决策树函数可以用于分析机器学习过程的结果,并有助于预测过程。 
- 
强化学习程序的结果可以通过提供优先级作为输入,应用到调度系统中。(是 | 否) 答案是是。强化学习的 Q 函数输出可以作为输入注入到另一个 Q 函数中。几个结果可以在第一阶段合并,并成为第二阶段强化学习会话的奖励矩阵。 
- 
人工智能软件能像人类一样思考吗?(是 | 否) 答案是是,也是否。在早期,这种方法曾尝试使用基于神经科学的模型。然而,目前应用数学模型要高效得多。 谁知道未来的神经形态计算研究会有什么发展呢?但就目前而言,深度学习作为主流,依赖于数学函数。 
第四章 – 使用 K-means 聚类优化您的解决方案
- 
可以在企业环境中使用随机数据构建原型吗?(是 | 否) 答案是是,也是否。为了开始开发一个原型,使用随机数据可以帮助确保基本算法按计划工作。 然而,一旦原型得到了提升,使用设计良好的数据集将更加可靠。然后,一旦训练完成,随机数据可以再次帮助你观察系统在各种情况下的表现。 
- 
设计矩阵每个矩阵包含一个示例吗?(是 | 否) 答案是否。一个好的设计矩阵在每一行或每一列包含一个示例,具体取决于你希望它具有的形状。但要小心;一个包含过于高效数据的设计矩阵可能会过拟合。这意味着学习算法对这些数据非常有效,但无法适应新数据。另一方面,如果数据集包含过多错误,那么算法可能会欠拟合,也就是说它无法正确学习。一个好的设计矩阵应该包含可靠数据,一些不精确数据,以及一些噪音(一些能以不可靠方式影响算法的数据)。 
- 
自动引导车(AGVs)永远无法广泛应用。(是 | 否) 答案是否。这句话是不正确的。自动引导车(AGVs)将从现在开始不断扩展:无人机、汽车、飞机、仓储车辆、工业车辆等等。AGVs,加上 AI 和物联网,构成了第四次工业革命。 
- 
K-means 聚类能否应用于无人机交通?(是 | 否) 答案是是。看到交通积压的位置可以防止无人机堵塞(无人机盘旋等待)。 
- 
K-means 聚类能否应用于预测?(是 | 否) 答案是是。K-means 聚类可以用于预测。 
- 
Lloyd 算法是一个两步法吗?(是 | 否) 是,Lloyd 算法首先将每个数据点分类到最佳簇中。然后,一旦完成,它计算该簇的几何中心或质心。当没有数据点再更改簇时,算法就已经训练完成。 
- 
超参数控制算法的行为吗?(是 | 否) 答案是是的。超参数决定了计算的过程:聚类的数量、特征、批量大小等。 
- 
一旦程序运行成功,展示方式就不重要了。(是 | 否) 答案是不是。如果没有清晰的结果展示,整个训练过程最多是混乱,最差则是毫无用处的。 
- 
K 均值聚类仅仅是一个分类算法。它不是一个预测算法。(是 | 否) 答案是不是。K 均值聚类也可以作为一种预测算法使用。 
第五章 – 如何使用决策树增强 K 均值聚类
问题将集中在超参数上。
- 
k 聚类的数量并不那么重要。(是 | 否) 答案是不是。聚类的数量需要仔细选择,可能需要试错的方法。每个项目都会导致不同的聚类结果。 
- 
小批量和批量包含相同数量的数据。(是 | 否) 答案是不是。"批量"通常指的是数据集,而"小批量"代表数据的"子集"。 
- 
K 均值可以在没有小批量的情况下运行。(是 | 否) 答案是是的,也不是。如果数据量保持较小,训练周期可以在整个数据集上运行。如果数据量超出了合理的计算能力(CPU 或 GPU),则必须创建小批量来优化训练计算。 
- 
质心是否必须经过优化才能接受结果?(是 | 否) 答案是是的,也不是。假设你想把一把钥匙放进钥匙孔。钥匙孔代表你的视觉聚类的质心。你必须非常精确。如果你只是把一张纸扔进垃圾桶,你不需要瞄准聚类的完美中心(由垃圾桶的边缘标记)来实现目标。质心的精确度取决于算法的要求。 
- 
优化超参数不会花费太长时间。(是 | 否) 答案是是的,也不是。如果是一个简单的项目,时间不会很长。如果你面对的是一个大数据集,找到最优超参数会需要一些时间。 
- 
训练一个大数据集有时需要数周时间。(是 | 否) 答案是是的。媒体炒作和艰苦的工作是两个完全不同的领域。机器学习和深度学习仍然是艰难的实现项目。 
- 
决策树和随机森林是无监督算法。(是 | 否) 答案是是的,也不是。决策树既可以用于监督学习,也可以用于无监督学习。决策树可以从目标值开始,这使得它们成为监督学习算法。随机森林也可以以相同的方式使用。 
第六章 – 利用谷歌翻译创新 AI
- 
在将产品投放市场之前,是否更好等到你拥有顶级的产品?(是 | 否) 答案是是的,也是不。上下文才是关键。在 21 世纪初,空客公司正为完成 A380——有史以来最大的客机——而努力。工程师们在运送商业乘客之前,进行了数百项改进。我们对他们的期望一点也不低! 就谷歌翻译而言,答案是一个巨大的“不”。通过将谷歌翻译上线并提供 API,谷歌鼓励了成千上万的 AI 开发者、语言学家、顾问和用户提供反馈和改进。此外,谷歌再次占据了网络市场的较大份额。 
- 
考虑到所做的投资,新产品应始终定价较高,以达到市场的顶端。 (是的 | 不) 答案是是的,也是不。同样,上下文决定了答案。当法拉利将新车推向市场时,价格必须高,原因有二;一是车的质量,二是生产成本,这使得高价才能确保创新的盈利性。同时,法拉利避免大规模生产,以保持其质量的高水平。 当亚马逊网络服务(AWS)通过 SageMaker 将机器学习推向市场时,它实施了一项“按需付费”政策,从市场的低端开始。这个产品有其局限性,但亚马逊现在收到了大量反馈,并持续改进该产品。 
- 
发明一种新解决方案会使其自身被知晓。 (是的 | 不) 是的。一个发明社会准备接受的发明将会自行成功,无论如何。你可能会惊讶地发现,通过绘制投影图像来保存相机的图像,这一做法追溯的历史悠久,甚至没有人确切知道它是什么时候首次被使用的。没人知道它是被发明出来的,还是被发现的。无论如何,第一个暗箱(第一个“相机”)是具有革命性的。现在已经证明,著名的画家们曾经使用过这一技巧。图像被投影到纸张或画布上。“打印机”是手动的。画家就是“打印机”。然而,如我们所知,相机直到 20 世纪才真正变得具有颠覆性。 
- 
AI 能在不使用标准非学习算法的情况下解决大多数问题。 (是的 | 不) 答案是不。例如,创建数据集时需要使用非学习型的经典算法。此外,AI 依赖于云服务器、架构、所有编程语言中的标准算法(如 C++、Java、Python 等)和 Apache 服务器。即便是在自动驾驶汽车中,安装的传感器也需要进行标准的硬件工作,才能使其正常工作并解读信息,之后 AI 才介入解决一些问题。 AI 就像我们的“大脑”。没有身体,它无法运作。 
- 
谷歌翻译能令人满意地翻译所有语言。 (是的 | 不) 阅读完这一章后,你可能会惊讶地发现,答案既是是的,又是不。如果你在你最喜欢的社交网络上,或者在电子邮件中使用谷歌翻译来说“你好”,“你好吗?”“谢谢你的消息”,以及类似的友好短语,那就足够了。 但是当处理更详细的短语和句子时,Google Translate 会提供随机的令人满意的结果。从用户的角度来看,这是坏消息。对于开发者来说,这是一个宝藏! 
- 
如果你没有创造力,试图创新是没有用的。(是 | 否) 答案是一个巨大的不。你完全不需要富有想象力或创造力才能创新。不要让任何人让你相信这种胡说八道。如果你正在设计一个解决方案并发现缺少某个组件,去网上寻找一些替代组件,讨论一下,找到可以帮忙的人。然后通过团队合作完成它。每次都有效! 即使是伟大的比尔·盖茨也足够聪明,向 Tim Patterson 求助来开发 MS-DOS,之后他成了亿万富翁。 
- 
如果你不是语言学家,试图改进 Google Translate 是没有用的。(是 | 否) 答案是不!再说一遍,绝对不要让任何人让你相信这种胡说八道。创新是团队合作。如果你喜欢 Google Translate 并且理解这一章的内容,并且有一些想法,和身边的语言学家合作,或者通过社交网络找到他们。这个世界是你用来改进的! 
- 
翻译太复杂,难以理解。(是 | 否) 不。一些人解释的方式过于复杂。如果你会说某种语言,你就是把自己的思想转化为语言的专家。通过努力,你可以进入翻译行业。 
- 
人工智能已经达到了它的极限。(是 | 否) 当然不是!我们只是刚刚触及了理论和应用的表面。 
第七章 – 使用朴素贝叶斯优化区块链
- 
加密货币是区块链今天唯一的用途。(是 | 否) 不。例如,IBM HyperLedger 使用区块链来组织供应链环境中的安全交易。 
- 
开采区块链可能是有利可图的。(是 | 否) 是的。但这是一种风险,就像任何其他的矿业操作或任何投机性努力一样。一些公司拥有巨大的资源来开采加密货币,这意味着他们能够击败小型竞争者来创建一个区块。 
- 
公司用区块链不能应用于销售。(是 | 否) 不。区块链云平台提供智能合约和在销售过程中管理交易的安全方式。 
- 
区块链的智能合约比标准的离线合同更容易编写。(是 | 否) 是的,如果它们是标准合同,这将加快交易速度。 另一方面,不。如果交易复杂且需要定制,律师将不得不编写合同,然后只能在区块链云平台上使用。 
- 
一旦一个区块进入区块链网络,网络中的每个人都可以读取其内容。(是 | 否) 是的,如果没有强制执行隐私规则。 不,如果强制执行了隐私规则。例如,IBM Hyperledger 提供隐私功能。 
- 
一个区块在区块链中可以保证绝对不可能发生欺诈。(是 | 否) 是的和不是。区块链中的一个区块一旦生成就无法再修改,从而避免了欺诈行为。没有人能篡改数据。然而,如果交易本身是非法的,那么该区块也会是欺诈性的。 
- 
应用贝叶斯定理只有一种方式。(是 | 否) 不。贝叶斯定理有很多变种。例如,使用朴素贝叶斯算法可以避免条件概率的约束。但另一种方法可能会使用条件概率。 
- 
训练朴素贝叶斯数据集需要一个标准函数。(是 | 否) 不。例如,高斯函数可以用于计算朴素贝叶斯算法等。 
- 
机器学习算法不会改变企业业务的本质。(是 | 否) 不。精心设计的机器学习将通过算法在公司内部传播,优化流程,进而颠覆各个业务领域。 
第八章 – 使用前馈神经网络解决 XOR 问题
- 
感知机单独能解决 XOR 问题吗?(是 | 否) 是的。1969 年时答案是“否”。解决这个问题需要一个神经网络或其他数学过程。值得一提的是,这是电路中常见的问题,尤其是在“前馈”电流的电路中,这个问题早已得到解决。 
- 
XOR 函数是线性不可分的吗?(是 | 否) 如果你使用一个神经元,那么答案是否;如果你使用至少两个神经元的隐藏层,那么答案是是。这是深度学习中需要解决的一个主要问题。例如,如果你无法在图片中区分一个面部的特征,那么识别这个面部将变得非常困难。想象一下,图片中一半的面部处于阴影中,另一半处于强烈的阳光下。由于一半眼睛和特征在阴影中,一个糟糕的深度学习程序可能只能捕捉到面部的一半,并且错误地分隔面部,造成边缘检测不佳。因此,线性可分性是机器学习的一个关键方面。 
- 
神经网络中层的主要目标之一是分类。(是 | 否) 答案是是的。一旦数据能够与给定的神经网络架构相匹配,预测和许多其他功能便成为可能。深度学习的关键在于能够将数据转化为通过各层获得的抽象理解后可以理解的信息片段。 
- 
深度学习是分类数据的唯一方法吗?(是 | 否) 答案是否。你可以通过 SQL 查询、电子表格、AI、机器学习以及标准源代码来分类数据。当分类涉及多个维度时,深度学习变得至关重要:首先要找到图片中的物体边缘,然后是形状,最后确定物体代表什么。要处理数百万张图片,这已经超出了标准编程或早期 AI 和机器学习程序的范畴。 
- 
成本函数显示神经网络的成本增加。(是 | 否) 答案是否。成本函数决定了训练的花费。运行 100,000 个 epoch 比运行 50,000 个 epoch 更昂贵。因此,在每个 epoch 中,必须估算训练成本(系统距离目标的远近)。因此,一个好的成本函数会减少运行神经网络的成本。 
- 
简单的算术运算足以优化成本函数吗? (是 | 否) 答案是是。只要你知道你的成本函数是如何增加或减少的,任何有效的方法都是可以的。 
- 
前馈网络需要输入、层和输出。 (是 | 否) 答案是是。没有层,就没有网络。 
- 
前馈网络总是需要反向传播训练。 (是 | 否) 在变化的环境中,答案通常是是。由于该领域是新的,我们往往认为一旦训练完成,工作就结束了。如果数据集在重复的环境中非常稳定,比如在商店、仓库或工厂中区分各种恒定产品,那么神经网络将完成它设计的分类任务。如果引入了新产品,则可以重新启动训练。 
- 
在实际应用中,解决方案只能通过遵循现有理论来找到。 (是 | 否) 答案是否。没有学术研究,深度学习甚至不会存在。没有大学,这些使用的理念将是如此简单,以至于永远不会有好的效果。 另一方面,研究人员需要现实世界的反馈。如果我们发现新的做法符合他们的建议,我们应该将其发布出来,帮助全球研究。这是一个双向过程。 
第九章 – 使用卷积神经网络 (CNN) 进行抽象图像分类
- 
卷积神经网络 (CNN) 只能处理图像。 (是 | 否) 答案是否。CNN 可以处理单词、声音或视频序列,用于分类和预测。 
- 
卷积核是用于卷积的预设矩阵。 (是 | 否) 答案是是,并且是否。有许多预设矩阵用于处理图像,比如本章中 Edge_detection_Kernel.py中使用的矩阵。然而,在本章中,卷积核是随机创建的,然后网络训练它们的权重以适应目标图像。
- 
池化有池化矩阵吗,还是随机的? 在某些情况下,当将池化层添加到模型中时,池化矩阵的大小是一个可选项,例如 2×2 的池化窗口。然而,在 AutoML 神经网络中,我们可以尝试运行优化算法,测试不同的大小,看看哪种大小能提供最佳性能。 
- 
数据集的大小必须总是很大。 (是 | 否) 不。数据集没有标准大小。它取决于训练模型。如果目标图像没有复杂的特征,例如,数据集将比具有复杂特征的数据集要小。此外, ImageDataGenerator函数将通过扭曲数据并使用提供的选项来扩展数据集。
- 
在网络上有众多的图像库可供选择,找到一个数据集并不是问题。 (是 | 否) 答案是是,也是否。是的,因为如果模型仍然是标准的学术模型,那么现有的图像(CIFAR,MNIST 或其他)就足够了。 不,因为在实际的企业环境中,你必须构建自己的数据集,并添加包含噪声的图像。噪声需要更多的精细调优,才能使模型变得可靠且具有广泛的适应性。 
- 
一旦 CNN 建立,训练它并不需要太多时间。 (是 | 否) 答案是否。无论模型是什么样的,如果你希望它可靠,训练仍然是一个耗时的过程。正如本章所示,一个模型需要许多选项和数学思维。 
- 
训练好的 CNN 模型只适用于一种类型的图像。 (是 | 否) 是与否。过拟合主要有三种类型: - 
对某一类图像的过拟合,几乎没有实施后果。在这种情况下,模型足够分类和预测,能够满足设定的目标。假设你使用的是一种非常高定义的图像。CNN 将检测到我们可能试图检测的细小细节。然而,当应用程序进入生产阶段时,低质量的图像可能会导致模型无法准确识别它以前在高质量图像中检测到的内容。 
- 
模型过拟合会产生实现问题,因为它无法同时适应不同类型的图像。然后,该模型将经历更多的训练。 
- 
模型过拟合对某一类图像训练得很好,但在需要时无法适应类似类型的图像。 
 每种情况都有其限制。只要模型有效,就没有通用规则适用。最终决定权在于你。 
- 
- 
与交叉熵函数相比,二次损失函数效率不高。 (是 | 否) 答案是否。每个模型都有其限制。二次损失函数在某些模型上效果很好,但在其他模型上可能无法提供良好的结果。这代表了训练模型的主要问题。没有通用的规则可以帮助你,你必须动用你的神经元,或者编写一个程序来自动修改模型。 
- 
现代 CPU 和 GPU 并不会使深度学习 CNN 的性能成为一个真正的问题。 (是 | 否) 答案是是,也是否。如果模型足够快满足你的需求,那么性能就不会限制你项目的结果。然而,在许多情况下,性能仍然是一个问题。减少特征,专注于最好的特征,是层次结构逐层缩小分析规模的原因之一。 
第十章 – 概念表示学习
- 
维度的诅咒导致了机器学习算法中对维度和特征的缩减。(是 | 否) 是的。数据和特征的体量使得必须提取观测事件的主要特征(如图像、声音和文字)才能理解它。 过拟合和欠拟合同样适用于降维。将特征减少到系统在实验室中能够工作的程度(过拟合),一旦面对实际数据,可能会毫无用处。尝试使用所有特征可能会导致欠拟合,因为应用根本解决不了任何问题。 正则化不仅适用于数据,还适用于项目的各个方面。 
- 
迁移学习决定了项目的盈利性。(是 | 否) 是的,如果一个 AI 模型的应用第一次没有盈利,但如果用于类似类型的学习,可能会带来利润。重用某些功能无疑会产生利润。 不是,如果第一次应用非常有利可图,但却“过拟合”以符合特定项目的要求。 
- 
读取 model.h5 并不能提供太多信息。(是 | 否) 不是。在这种情况下,“不是”意味着句子的断言是错误的。保存的模型确实提供了有用的信息。例如,保存 TensorFlow 模型的权重在训练过程中至关重要,有助于控制数值。此外,训练过的模型通常使用 HDF 文件( .h5)来加载训练的权重。层次数据格式(HDF)包含多维科学数据数组。
- 
没有意义的数字足以替代人类。(是 | 否) 是的,在许多情况下,数学提供了足够的工具来替代人类执行许多任务(如游戏、优化算法和图像识别)。 不是,在数学无法解决需要概念性问题的情况下,例如自然语言处理中的许多方面。 
- 
聊天机器人证明了肢体语言并没有那么重要。(是 | 否) 是的,在许多应用中,肢体语言并没有提供额外的信息。如果只需要一个“是”或“否”的答案,肢体语言不会为对话增加太多内容。 不是,在需要情感智能来理解用户语气的情况下,检测肢体语言的网络摄像头可以提供有用的信息。 
- 
现代人工神经网络(ANNs)提供了足够的理论来解决所有的 AI 需求。(是 | 否) 不是。人工神经网络(ANNs)无法解决成千上万的问题,例如翻译诗歌小说或识别形态不断变化的图像。 
- 
聊天机器人现在可以在所有情况下替代人类。(是 | 否) 不是。需要添加概念。市场提供了所有必要的工具。要有效地与聊天机器人对话可能需要几年时间。 
- 
自动驾驶汽车已经获得批准,并且不需要概念性训练。(是 | 否) 是和否;这个领域存在一些争论。一方面,传感器和数学(线性代数、概率论)可能在几年内成功地在大多数驾驶条件下有效地导航道路。 然而,某些问题在关键情况下会需要更多的概念(以及更多的机器人技术)。比如,当一辆自动驾驶汽车遇到躺在路上的伤员时,最佳的应对方式是什么?可以选择呼叫援助、如果援助到达太晚则寻找其他人、救起伤者、将其送往医院(机器人技术)等等。 
- 
各行各业可以为所有需求实现人工智能算法。(是 | 否) 是和否。在许多情况下,所有必要的工具都可以使用。如果合适的团队决定用人工智能和机器人技术解决一个问题,那是可以做到的。 然而,当面临特定情况时,有些工具仍然缺失;例如,在面对突发事件时,缺少实时管理决策工具。如果系统发生故障,人类仍然能够更快地适应并找到替代解决方案来继续生产。 
第十一章 – 结合强化学习与深度学习
- 
卷积神经网络(CNN)可以被训练来理解抽象概念吗?(是 | 否) 是。卷积神经网络(CNN)可以分类图像并进行预测。但 CNN 可以分析任何类型的物体或表现形式。例如,一张图像可以与一个词或短语相连接。这样,图像本身就成了一个信息。 
- 
避免使用概念,只使用现实生活中的图像更好吗?(是 | 否) 不。图像提供了许多实际应用,但在某些情况下,例如解决规划问题时,仍然需要更多的东西。 规划所需的数据集远远不止这些。 
- 
规划和调度是同一个意思吗?(是 | 否) 不。规划描述了必须执行的任务。调度则加入了时间因素。规划告诉我们做什么,调度告诉我们什么时候做。 
- 
亚马逊的制造专利是一次革命吗?(是 | 否) 不。全球的工厂已经掌握了服装制造技术。如果过程中某个部分是全新的,那才算得上是革命。然 而,服装行业的自动化已经存在超过 20 年。这个专利是现有元素的一个特殊案例,就像一款新品牌的汽车。 是。凭借如此广泛的分布,亚马逊已经非常接近最终用户。最终用户可以选择一件新衣服,它会根据需求直接制造。这种互联性将改变服装制造过程,并迫使其竞争对手寻找新的生产和销售方式。 
- 
学习仓库如何运作没有用。(是 | 否) 不。在线购物需要越来越多的仓库空间和流程。仓库的数量将比商店增长得更快。仓库中的 AI 应用有许多机会。 
- 
在线营销不需要人工智能。(是 | 否) 不。相反,人工智能每天都被用于在线营销应用,而且这种情况将在未来几十年继续。 
第十二章 – 人工智能与物联网
- 
在任何情况下,快速到达目的地比安全更重要。(是 | 否) 是的和不。 自动驾驶汽车面临与人类驾驶汽车相同的困难:按时到达目的地、遵守限速规定、或者尽可能安全地驾驶。自动驾驶汽车就像人类一样,通过经验不断提升其驾驶能力。 是的。有时候,自动驾驶汽车在交通较少的高速公路上表现会更好。 不行。有时,如果高速公路由于天气条件和交通拥堵变得危险,自动驾驶汽车应该选择一条更安全的道路,速度较慢且几乎没有交通。这样,如果发生困难,自动驾驶汽车能够比在高速公路上更容易减速甚至停车。 
- 
自动驾驶汽车永远无法真正取代人类司机。(是 | 否) 没有人能回答这个问题。随着自动驾驶汽车不断积累能力和经验,它们很可能会比人类驾驶得更好。 在非常不可预测的情况下,人类可以通过驶离道路来避开其他汽车,或者稍微倒退一点。例如,要让自动驾驶汽车做到这一点会更加困难。 然而,有一件事是可以肯定的。如果一个人整晚驾驶并且打瞌睡,自动驾驶汽车会检测到头部下垂的动作,接管驾驶并拯救生命。如果人在驾驶过程中发生健康问题,自动驾驶汽车也可以拯救生命。 
- 
自动驾驶消防车搭载机器人有一天能扑灭火灾吗?(是 | 否) 是的。将自动驾驶消防车与机器人结合,当消防部门面临难以扑灭的火灾时,肯定会拯救许多生命。这些被拯救的生命包括那些冒着生命危险的消防员。它可能有助于消防员专注于帮助人们,而机器人则处理更艰难的工作。这种机器人-人类团队无疑将在未来拯救成千上万的生命。 
- 
大城市需要投资自动驾驶汽车还是避免投资它们?(投资 | 避免) 投资。通过缓慢但安全的自动驾驶汽车,通勤者可以共享公共的、免费的或非常便宜的电动自动驾驶汽车,而无需自己开车。这就像有了个人司机一样。 
- 
你会相信一辆自动驾驶公交车能安全地送孩子们上下学吗?(是 | 否) 这个答案会随着时间推移而变化,因为技术在不断发展。 不。在现有的自动驾驶车辆技术状态下,你不应该完全信任自动驾驶汽车! 是的,当自动驾驶汽车、公交车和卡车证明它们能够超越人类时,自动驾驶车辆将不会犯和人类一样的错误:在驾驶时使用智能手机、与乘客交谈而不看路等。 
- 
你能在高速公路上睡在自动驾驶汽车里吗?(是 | 否) 不,在现有的自动驾驶技术状态下不行。 是的,当可靠性替代了怀疑。 
- 
你想为一个城市的项目开发一个自动驾驶程序吗?(是 | 否) 那个问题留给你自己思考!你还可以通过直接联系公司或 AGV 制造商,将这项技术应用到仓库中的 AGV。 
第十三章 – 使用 TensorFlow 2.x 和 TensorBoard 可视化网络
- 
CNN 总是有相同数量的层次。(是 | 否) 不是。CNN 没有相同数量的层,甚至没有相同类型的层。层数是优化人工神经网络的一部分工作。 
- 
ReLU 是最好的激活函数。(是 | 否) 不是。ReLU 是一个有效的激活函数,但还有其他的,如 leaky ReLU、softmax、sigmoid 和 tanh。 
- 
不必编译顺序分类器。(是 | 否) 不是。这个断言应该是肯定的——这是必须的。 
- 
一个层的输出最好在不运行预测的情况下查看。(是 | 否) 不是。层的输出和预测是无关的。层的输出可以是层的变换(卷积、池化、丢弃、展平等),也可以是预测。 
- 
查看层的输出时,层的名称没有意义。(是 | 否) 不是。层次结构意味着一切!池化层和丢弃层是完全不同的。 
- 
TensorFlow 2.x 不包含 Keras。(是 | 否) 不是。TensorFlow 现在已集成 Keras,帮助构建无缝的神经网络。 
- 
Google Colaboratory 只是一个代码库,像 GitHub 一样。(是 | 否) 不是。Google Colaboratory 提供一个小型但免费的服务器,用于在线创建和运行程序。 
- 
Google Colaboratory 不能运行笔记本。(是 | 否) 不是。它可以运行笔记本。 
- 
可以在 Google Colaboratory 笔记本中运行 TensorBoard。(是 | 否) 是的。这是一个有用的功能。 
- 
TensorBoard 中显示了准确性。(是 | 否) 是的。这是一种有效的评估 ANN 效率的方法,例如。 
第十四章 – 使用限制玻尔兹曼机(RBMs)和主成分分析(PCA)准备聊天机器人的输入
- 
RBMs 基于有向图。(是 | 否) 不是。RBM 图是无向的、无监督的、无记忆的,决策是基于随机计算的。 
- 
RBM 的隐藏单元通常相互连接。(是 | 否) 不是。RBM 的隐藏单元通常不会互相连接。 
- 
随机采样在 RBM 中没有使用。(是 | 否) 不是。错误。吉布斯随机采样通常应用于 RBMs。 
- 
PCA 将数据转换为更高的维度。(是 | 否) 是的。PCA 的核心目的是将数据转换为较低维度,在更高抽象维度(关键维度隔离)中找到主成分(协方差矩阵的最大特征值),然后是第二大特征值,依此类推,直到最小值。 
- 
在协方差矩阵中,特征向量表示该矩阵的方向,而特征值表示该向量的大小。(是 | 否) 是。特征值表示一个特征的重要性,而特征向量提供一个方向。 
- 
不可能 在机器中表示一个人类的思维。(是 | 否) 否。在一定程度上,通过传感器并在有限的范围内是可能的。 
- 
机器无法学习概念,这就是为什么经典应用数学足以为各个领域制作高效的人工智能程序。(是 | 否) 否。绝不要相信这一点。进展正在取得,并且将永不停歇,直到思维机器成为主流。 
第十五章 – 设置认知 NLP UI/CUI 聊天机器人
- 
聊天机器人能像人类一样交流吗?(是 | 否) 否。像人类一样交流意味着成为人类:拥有身体、肢体语言、感觉、气味、恐惧激素等等。聊天机器人只是模仿这些行为。 
- 
聊天机器人一定是人工智能程序吗?(是 | 否) 否。许多呼叫中心使用“按 1、按 2...按n”的方法,这需要精心组织,但不需要人工智能。 
- 
聊天机器人只需要用语言进行交流。(是 | 否) 答案并非绝对明确。 是。简单的聊天机器人在受控的情况下可以通过语言进行交流。 否。当涉及到多义词(同一个词或情境有多个意义)时,象形符号等可以提供更加高效的维度。 
- 
人类仅通过语言聊天吗?(是 | 否) 否。人类通过声音的语调、肢体语言或音乐等方式表达自己。 
- 
人类仅通过语言和数字思考。(是 | 否) 否。当然不是。人类通过图像、声音、气味和感觉进行思考。 
- 
构建认知聊天机器人需要仔细的机器学习准备。(是 | 否) 答案取决于具体情境。 否。在有限的“按 1 或按 2”情境下,聊天机器人凭借有限的认知能力可以表现良好。 是。与人类进行真实对话的关键是通过心理图像来提供富有同理心的交流。 
- 
为了使聊天机器人正常工作,需要规划对话流程。(是 | 否) 这取决于你希望聊天机器人做什么。 是。它在商业环境中将提供更好的结果。 否。如果你希望聊天机器人自由地交流,你需要稍微解放它。这仍然需要对对话的规划,但会更加灵活。 
- 
聊天机器人拥有通用人工智能,因此无需提前开发。(是 | 否) 否。目前这是不可能的。现实生活中只存在狭窄的(特定于一两个领域的)人工智能,与科幻电影和媒体炒作相反。 
- 
聊天机器人在没有任何其他功能(除了翻译 API)的情况下,能够完成翻译吗?(是 | 否) 否。在目前的翻译机器人历史阶段,没有额外的定制,翻译结果并不可靠。 
- 
聊天机器人在大多数情况下已经能够像人类一样聊天。(是 | 否) 否。解释语言需要更多的挑战性工作和贡献。 
第十六章 – 改进聊天机器人情商的不足
- 
当聊天机器人未能提供正确的回应时,需要由人工热线接管对话。 (是 | 否) 这取决于上下文和实用性。 是。这是最佳解决方案。需要有一个互动聊天服务介入。 否。在许多情况下,这将是太昂贵了。一块好的支持屏幕就可以完成工作,并向支持团队发送电子邮件。 
- 
闲聊在日常生活或与聊天机器人交互时没有任何意义。最好直接进入正题。 (是 | 否) 再次,这取决于具体的上下文。 是。如果是紧急情况的机器人,当然! 否。如果聊天机器人的任务是执行繁琐的行政功能,适度的闲聊会让系统更加耐受。 
- 
数据日志记录可以用于改善语音识别。 (是 | 否) 是。完全正确。更多的数据意味着更好的机器学习训练。 
- 
聊天机器人代理的对话历史将包含有价值的信息。 (是 | 否) 是。完全正确。更多的反馈意味着更多的机器学习进展。 
- 
现今技术无法利用用户对话的数据记录。 (是 | 否) 否。我们当然可以解析数据记录并提取有价值的信息。 
- 
RNN 使用数据序列来做出预测。 (是 | 否) 是,它是这样。 
- 
RNN 可以自动生成聊天机器人的对话流程,适用于所有应用。 (是 | 否) 是和否。它能做到,但在自动对话流程的历史阶段,这个质量仍然有时很差! 
第十七章 – 混合神经网络中的遗传算法
- 
细胞含有 42 条染色体。 (是 | 否) 否。每个细胞有 46 条染色体。 
- 
遗传算法是确定性的,而非随机的。 (是 | 否) 否。遗传算法是随机的,这使它比许多确定性算法更高效。 
- 
进化算法意味着程序代码会进化。 (是 | 否) 这没有一个明确的答案。 否。程序就像其他程序一样运行。 是。在某些情况下,当它被用于优化混合神经网络中的神经网络时,它会改变系统的参数。此外,也可以使用遗传算法向 CNN 中添加或移除层。 
- 
即使经过多代,孩子最好继承父母之一的基因。 (是 | 否) 否。当然不是!我们需要多样化的基因才能保持适应性的基因群体。 
- 
多样性使得基因集变弱。 (是 | 否) 否。多样性越大,基因池越丰富,更能适应并保持适应性。 
- 
建立神经网络只需几行代码,而且架构总是有效的。 (是 | 否) 这取决于你所说的“工作”是什么意思。 是。例如,使用 TensorFlow 2.x 构建神经网络只需要几行代码,它就能工作。 否。神经网络可以运行,但在其架构和超参数经过微调之前,它很可能不会高效。 
- 
用遗传算法构建神经网络有助于优化层的架构。 (是 | 否) 是。有可能将遗传算法扩展到层优化中。每一层可以是一个基因,然后可以运行各种替代方案以检查它们的准确性。 
- 
混合神经网络是没用的,因为深度学习将不断进步。 (是 | 否) 否。深度学习会达到一个渐近线,正如所有系统一样。到那时,可以向深度学习架构中添加新的维度,比如遗传算法。 
- 
你会信任遗传算法为你做决策吗? (是 | 否) 是,如果系统设计得当。如果你不信任遗传算法,那就否! 
- 
你会信任一个混合神经网络来优化你网络的架构吗? (是 | 否) 是,如果系统设计得当。否,如果它不可靠或有偏差。 
第十八章 – 类脑计算
- 
类脑计算再现了我们的心理活动。 (是 | 否) 否。这正是关键。类脑计算始于低层次的、非符号的神经元大脑活动刺激,这些刺激尚未形成高级的心理活动。我们的心理活动已经使用符号,并且包含以词语、图像、数字以及各种构建形式的表示。 然而,如果我们指的是转换为心理活动的输出结果,我们可以说是。我的意思是,"是"和"否"的回答限制了我们对人工智能的看法。 
- 
类脑计算再现了我们的大脑活动。 (是 | 否) 是。这正是关键!核心概念是从大脑活动到由神经元尖峰形成的结构。 
- 
语义指针架构(SPA)是一种硬件架构。 (是 | 否) 否。语义指针就像计算机程序指针,例如 C++ 指针。不同之处在于,它们携带的是部分表示意义,因此叫做“语义”。 
- 
NEF 代表神经工程框架。 (是 | 否) 是,这是正确的。 
- 
Loihi 是一个经典芯片。 (是 | 否) 否。绝对不是!Loihi 是英特尔的类脑计算芯片,包含大量的神经元。人类大脑大约有 1000 亿个神经元。想象一下,快的话,你将拥有一个由类脑计算芯片(英特尔或其他厂商)构成的网络,达到了这个数量。再想象一下,通过类脑计算可以做什么,尤其是语义指针。 
- 
再现我们大脑的神经活动不能解决方程。 (是 | 否) 否。当然,我们可以使用类脑计算通过 SPA 方法来求解方程。 
- 
Nengo 中的一个集成包含算法。 (是 | 否) 不是。但是这个问题很棘手!基本上,Nengo 使用如前所述的非符号化方法。然而,它包含许多通过神经计算解决的算法的 Python 教程,形成了一个完整的问题解决方案。 
- 
尖峰阻止神经元活动。(是的 | 不是) 不是。但这又是一个棘手的问题。尖峰反映了神经元活动的水平。所以,在这个方面,答案是“不是”。但一个尖峰神经元可以抑制另一个神经元,从而间接地阻止它。 
- 
放电模式可以用来分析大脑活动。(是的 | 不是) 是的。在神经计算中,放电模式会随时间变化,提供有关神经元如何到达给定状态的有用信息。 
- 
机器学习和深度学习只是我们大脑活动的隐喻。(是的 | 不是) 是的。这就是深度学习所面临的核心问题。它们是我们大脑神经活动的高级表现。 
第十九章 – 量子计算
- 
超越炒作,目前还没有量子计算机存在。(是的 | 不是) 不是。错误。你现在已经可以在 IBM Q 的云平台上运行量子计算机: www.research.ibm.com/ibm-q/。以下截图是我在量子得分上运行的一个真实量子计算机(IBM)计算结果,详细解释在章节中: ![]() 图 A.1:IBM 量子计算机计算 
- 
量子计算机能存储数据。(是的 | 不是) 不是。不稳定性目前阻止了任何形式的存储。 
- 
量子门对量子比特的影响可以通过布洛赫球体来观察。(是的 | 不是) 是的。布洛赫球体将显示量子比特的状态。 
- 
一个通过过去经验、图像、词语和其他日常信息(如存储的记忆)思考的大脑,将会找到数学单独无法解决的问题的更深层次解决方案。(是的 | 不是) 这个问题没有单一普遍接受的答案。就像量子比特一样,答案介于“是”(1)和“不是”(0)之间! 不是。错误。许多研究人员认为仅凭数学无法解决所有人类问题。 是的。正确。仅凭数学无法替代深入思考。即使计算机拥有惊人的计算能力,并且能够在国际象棋中击败人类选手,例如,它们仍然不能在没有经过设计和训练的过程中适应新情况。概念需要被添加并且经历(包括记忆)。 我敢打赌,机器思维的概念将会逐渐成为主流,用于解决深度思维问题。 
- 
量子计算机将解决今天无法解决的医学研究问题。(是的 | 不是) 是的。这一点毫无疑问。量子计算机的强大计算能力能够为表观遗传学研究提供指数级的 DNA 测序程序。 
- 
量子计算机能比经典计算机更快地指数级解决数学问题。(是的 | 不是) 是的。经典计算机以 2 × n(位数)运行,而量子计算机则以 2^n(n 为量子比特的数量)运行! 
- 
经典计算机和智能手机处理器很快会消失。(是 | 否) 不是的。量子计算机需要非常大的空间和物理稳定性,因此这一点短期内不会发生。而且,经典计算机和智能手机可以存储数据,但量子计算机不能。 
- 
量子得分无法以源代码格式编写,只能通过可视化界面实现。(是 | 否) 不是的。错误。例如,IBM 可以将量子得分从量子代码转换为 QASM 界面或同时显示两者,如下所示: ![]() 图 A.2:QASM 界面 
- 
量子模拟器可以运行得和量子计算机一样快。(是 | 否) 不是的。绝对不行!模拟器展示了量子得分在真实量子计算机上会如何表现。虽然模拟器可以帮助构建得分,但量子计算机的运行速度会比模拟器快得多。 
- 
量子计算机在运行计算时会产生中间结果。(是 | 否) 不是的。这是不可能的。量子比特太不稳定了。对其进行观察会导致系统崩溃。然而,像 Quirk 这样的模拟器非常有用。由于它们不是实际的量子计算机,因此可以显示中间结果来设计量子得分。 
第二十一章:你可能喜欢的其他书籍
如果你喜欢这本书,可能会对 Packt 出版的其他书籍感兴趣:
Python 人工智能
阿尔贝托·阿塔桑切斯(Alberto Artasanchez),普拉提克·约希(Prateek Joshi)
ISBN: 978-1-83921-953-5
- 
了解什么是人工智能、机器学习和数据科学 
- 
探索最常见的人工智能应用场景 
- 
学习如何构建机器学习管道 
- 
理解特征选择和特征工程的基础 
- 
识别有监督学习和无监督学习之间的区别 
- 
探索最新的人工智能发展进展和云计算中提供的工具 
- 
开发自动语音识别系统和聊天机器人 
- 
将人工智能算法应用于时间序列数据 
人工智能速成课程
哈德林·德·庞特维斯(Hadelin de Ponteves)
ISBN: 978-1-83864-535-9
- 
掌握深度学习、强化学习和深度强化学习的关键技能 
- 
了解 Q 学习和深度 Q 学习 
- 
从友好、简单的英语解释和实用活动中学习 
- 
构建有趣的项目,包括虚拟自动驾驶汽车 
- 
使用人工智能解决现实世界的商业问题并赢得经典视频游戏 
- 
构建一个智能虚拟机器人仓库工人 
留下评论 - 告诉其他读者你对这本书的看法
请通过在购买该书的网站上留下评论与他人分享你对这本书的想法。如果你是在亚马逊购买的书籍,请在这本书的亚马逊页面上留下真实的评论。这对于其他潜在读者了解你的公正意见,帮助他们做出购买决策至关重要,同时帮助我们了解客户对我们产品的看法,并让我们的作者看到你对他们与 Packt 合作创作的书籍的反馈。仅需几分钟时间,但对其他潜在客户、我们的作者以及 Packt 非常有价值。谢谢!

 
                    
                
 :这是提醒我们试错有代价。我们浪费了时间、金钱和精力。此外,我们甚至不知道下一步是对还是错,因为我们处于试错模式中。Gamma通常设置为 0.8。那意味着什么呢?假设你在参加考试。你努力学习,但不知道结果如何。你可能有 80%的机会(0.8)通过考试。这很痛苦,但这就是生活。Gamma惩罚或学习速率使得贝尔曼方程更加现实和高效。
:这是提醒我们试错有代价。我们浪费了时间、金钱和精力。此外,我们甚至不知道下一步是对还是错,因为我们处于试错模式中。Gamma通常设置为 0.8。那意味着什么呢?假设你在参加考试。你努力学习,但不知道结果如何。你可能有 80%的机会(0.8)通过考试。这很痛苦,但这就是生活。Gamma惩罚或学习速率使得贝尔曼方程更加现实和高效。 是
是 是
是 的总和,如下面的代码所示:
的总和,如下面的代码所示: 差距概念
差距概念 (空隙概念数据集)
(空隙概念数据集) (lambda) 是学习因子;一个任务执行得越多,它就越被优化。
 (lambda) 是学习因子;一个任务执行得越多,它就越被优化。 ,其中包含 pg[i] (p = 正向) 和 ng[i] (n = 负向子集)
,其中包含 pg[i] (p = 正向) 和 ng[i] (n = 负向子集) 的子集; ng[1] = {缺失, 不足,降低生产效率 … 不良},
 的子集; ng[1] = {缺失, 不足,降低生产效率 … 不良}, 和负向 n
 和负向 n 缝隙
 缝隙 更新的频率。在本例中,
 更新的频率。在本例中,


 。X 上方的横线表示它是一个均值。
。X 上方的横线表示它是一个均值。 对于 0 值
 对于 0 值 对于 1 值
 对于 1 值 其中α是一个概率参数
 其中α是一个概率参数 其中β是一个概率参数
 其中β是一个概率参数
 (从布洛赫球顶部开始,如图所示)
(从布洛赫球顶部开始,如图所示)

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号