KNIME-无代码深度学习-全-
KNIME 无代码深度学习(全)
原文:
annas-archive.org/md5/3fb5edd9b2e990d054f2bfb606f7000f译者:飞龙
前言
本书旨在向你介绍深度学习网络的概念和实践。书中研究了多个基于深度学习解决方案的案例研究。在每个案例研究中,我们通过无代码的 KNIME 分析平台工具解释并实现了神经网络架构。我们首先简要介绍深度学习的基本概念和可视化编程工具 KNIME 分析平台。基本概念明确后,我们继续通过案例研究探讨使用深度学习架构解决特定任务:使用神经自编码器进行欺诈检测,使用递归神经网络进行需求预测和自然语言处理,使用编码器-解码器架构进行神经机器翻译,以及使用卷积神经网络进行图像分类。书籍最后,介绍了训练好的网络的部署选项,并提供了一些训练和成功应用深度学习网络的小技巧和窍门。
本书适用对象
如果你一直想开发基于深度学习网络的解决方案,但又不想花时间学习如何编写代码,这本书非常适合你。它教你深度学习背后的算法基础,以及如何无代码地构建、训练和评估深度学习网络。尽管无代码工具大大降低了入门门槛,但深度学习网络背后的复杂性依然存在。理解数据处理和操作以及算法背后的数学原理,仍然需要一定的数学背景。
本书涵盖内容
第一章,使用 KNIME 分析平台的深度学习简介,是一本准备性章节,帮助你熟悉这个工具以及近年来深度学习技术的流行。
第二章,使用 KNIME 分析平台的数据访问与预处理,深入探讨了 KNIME 分析平台的基础和高级功能:从数据访问到工作流参数化。
第三章,神经网络入门,是本书唯一的理论章节。它概述了神经网络和深度学习网络的基本概念,以及用于训练这些网络的算法。
第四章,构建与训练前馈神经网络,是我们实践在第三章,神经网络入门中所描述内容的章节;我们将在此构建、训练并评估我们的第一个简单前馈神经网络,用于分类任务。
第五章,用于欺诈检测的自编码器,介绍了如何使用神经自编码器解决信用卡交易中的欺诈检测问题,开始了基于深度学习解决方案的案例研究系列。
第六章,用于需求预测的递归神经网络,介绍了长短期记忆(LSTM)模型在递归神经网络中的应用。确实,凭借其动态行为,它们在解决时间序列问题方面特别有效,例如经典的需求预测问题。
第七章,实现 NLP 应用程序,介绍了基于 LSTM 的递归神经网络如何常用于实现自然语言处理任务的解决方案。在本章中,我们讨论了几个案例研究,包括自由文本生成、自由命名生成和情感分析。
第八章,神经机器翻译,探讨了用于自动翻译的编码器-解码器架构。
第九章,用于图像分类的卷积神经网络,涵盖了图像分类的一个案例研究,这是我们不能错过的。我们使用卷积神经网络对病理图像进行癌症诊断分类。
第十章,部署深度学习网络,开始描述部署阶段。详细解释了部署工作流的一个简单示例。
第十一章,最佳实践与其他部署选项,在前一章关于部署的内容基础上,扩展了更多部署选项,例如 Web 应用程序和 REST 服务,我们以一些小贴士和技巧结束本书。
要充分利用本书
KNIME 分析平台是一个非常易于使用的工具。不需要任何编程知识。
然而,需要一些基础的数学知识来处理数据转换并理解训练算法。

KNIME 分析平台是开源的,可以免费下载、安装并使用。请从www.knime.com/downloads下载。
KNIME Server 仅在第十一章,最佳实践与其他部署选项中需要,用于在 REST 服务或 Web 应用程序中运行训练好的网络。KNIME Server 不是开源的,不能免费使用,需要购买年度许可证。如需测试许可证,请填写www.knime.com/contact上的联系表格。
下载示例工作流
您可以从 KNIME Hub 下载本书的示例工作流,网址为hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/,或者从 GitHub 下载,网址为github.com/PacktPublishing/Codeless-Deep-Learning-with-KNIME。如果工作流有更新,将会在现有的 KNIME Hub 和 GitHub 仓库中更新。
我们还提供其他代码包,来自我们丰富的书籍和视频目录,您可以在github.com/PacktPublishing/找到。赶紧去看看吧!
下载彩色图片
我们还提供了一份 PDF 文件,其中包含本书中使用的截图/图表的彩色图片。您可以在这里下载:static.packt-cdn.com/downloads/9781800566613_ColorImages.pdf。
使用的约定
本书中使用了一些文本约定。
文本中的代码:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。例如:“我们将Demographics.csv文件从Example Workflows/TheData/Misc拖放到工作流编辑器中。”
粗体:表示新术语、重要单词或屏幕上显示的词汇。例如,菜单或对话框中的单词在文本中会以这种方式显示。示例:“配置完成后,我们点击确定;节点状态变为黄色,节点现在可以执行。”
提示或重要注意事项
通过文件拖放自动创建节点并配置其设置,仅适用于特定的文件扩展名:.csv用于文件读取器,.table用于表格读取器,.xls和.xlsx用于 Excel 读取器,等等。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果您对本书的任何方面有疑问,请在邮件的主题中提及书名,并通过 customercare@packtpub.com 与我们联系。
勘误表:尽管我们已经尽最大努力确保内容的准确性,但错误难免。如果您在本书中发现错误,我们将非常感激您能向我们报告。请访问www.packtpub.com/support/errata,选择您的书籍,点击勘误表提交表单链接,并输入详细信息。
盗版:如果您在互联网上发现我们作品的非法复制版本,我们将非常感激您能提供相关的地址或网站名称。请通过版权@packt.com 与我们联系,并提供相关的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识并且有兴趣编写或参与编写一本书,请访问authors.packtpub.com。
评论
请留下评论。在您阅读并使用本书之后,为什么不在您购买书籍的网站上留下评论呢?潜在读者可以看到并参考您公正的意见,以便做出购买决策,我们在 Packt 也能了解您对我们产品的看法,而我们的作者也能看到您对他们书籍的反馈。谢谢!
想了解更多关于 Packt 的信息,请访问packt.com。
第一部分:前馈神经网络与 KNIME 深度学习扩展
本节为导言部分,旨在帮助你了解神经网络的世界以及所使用的工具——KNIME 分析平台。
本节包括以下章节:
-
第一章**,使用 KNIME 分析平台的深度学习简介
-
第二章**,使用 KNIME 分析平台进行数据访问与预处理
-
第三章**,神经网络入门
-
第四章**,构建和训练前馈神经网络
第一章:第一章: 使用 KNIME Analytics Platform 入门深度学习
我们将通过探索 KNIME Analytics Platform 来开始我们的深度学习(DL)范式之旅。如果你一直对神经网络和深度学习架构感兴趣,并且总觉得编码部分会成为你快速学习曲线的障碍,那么这本书就是为你而写的。
深度学习可能相当复杂,我们必须确保这一旅程值得获得的结果。因此,我们将再次从阐述深度学习技术在成功实施数据科学应用中的重要性开始本章内容。
接下来,我们将简要介绍本书所选工具——KNIME 软件,并重点讲解它如何与 KNIME Analytics Platform 和 KNIME Server 相辅相成。
本书中所做的工作将通过 KNIME Analytics Platform 实现,该平台是开源的,且可以免费使用。我们将专门有一部分介绍如何下载、安装和使用 KNIME Analytics Platform,尽管在接下来的章节中会提供更多细节。
KNIME Analytics Platform 的一个优势,当然是它无代码的深度学习 - Keras 集成扩展,我们将在本书中广泛使用该扩展。在本章中,我们将专注于该 KNIME 扩展的基本概念和要求。
最后,我们将通过阐明本书的目标和结构来结束本章。我们希望让本书更具实践性,因此大多数章节将围绕一个包括真实数据的实际案例研究展开。在每一章中,我们将有机会深入探讨所需的神经网络架构、数据准备、部署及其他使案例研究成功的要素。
本章将涉及以下主题:
-
深度学习的重要性
-
探索 KNIME 软件
-
探索 KNIME Analytics Platform
-
安装 KNIME 深度学习 - Keras 集成
-
本书的目标与结构
我们将从阐述深度学习在成功的数据科学应用中的重要性开始。
深度学习的重要性
如果你在数据科学——或者如今所说的人工智能(AI)——领域工作了几年,你可能注意到最近关于基于深度学习技术的成功解决方案的学术与实践文章激增。
重大突破发生在 2012 年,当时基于深度学习的 AlexNet 网络以空前的优势赢得了 ImageNet 挑战赛。这一胜利引发了深度学习网络应用的激增。自那时以来,深度学习已扩展到许多不同的领域和任务。
那么,当我们谈论深度学习时,究竟指的是什么呢?深度学习涵盖了一部分机器学习(ML)算法,其中大多数来源于神经网络。深度学习确实是传统神经网络的现代演进。除了经典的前馈、全连接、反向传播训练和多层感知机架构之外,还增加了更深的架构。更深意味着更多的隐藏层以及一些新的神经网络范式,包括递归神经网络(RNNs)、长短期记忆网络(LSTM)、卷积神经网络(CNNs)、生成对抗网络(GANs)等。
这些新型神经网络最近的成功有多个原因。首先,现代机器计算能力的提升有利于新范式和更复杂神经架构的引入与发展。在几分钟内训练一个复杂的神经网络,相较于将相同网络训练数小时或数天,留下了更多的实验空间。另一个原因是它们的灵活性。神经网络是通用的函数逼近器,这意味着只要它们的架构足够复杂,它们几乎可以逼近任何事物。
对这些算法的数学知识、对最有效的范式和架构的经验以及领域智慧,都是任何数据科学项目成功的基本、重要且必要的要素。然而,还有其他更多的偶然因素——例如学习的易用性、原型设计的速度、调试和测试选项以确保解决方案的正确性、实验的灵活性、外部专家帮助的可用性,以及自动化和安全功能——这些也会影响项目的最终结果。
在本书中,我们将展示可以通过开源、基于可视化编程、免费使用的工具 KNIME Analytics Platform 实现的深度学习解决方案。这些解决方案的某些部署阶段也使用了 KNIME Server 提供的一些功能。
接下来,我们将了解 KNIME Analytics Platform 和 KNIME Server 如何相互补充,以及它们各自适用于哪些任务。
探索 KNIME 软件
我们将主要使用两款 KNIME 产品:KNIME Analytics Platform 和 KNIME Server。KNIME Analytics Platform 包含数据科学项目所需的 ML 和深度学习算法及数据操作。另一方面,KNIME Server 提供了 IT 基础设施,便于安全部署以及随时间对模型进行监控。
我们将首先集中介绍 KNIME Analytics Platform,并概述它能完成的工作。
KNIME Analytics Platform
KNIME 分析平台是一款满足所有数据需求的开源软件。它可以从 KNIME 官网(www.knime.com/downloads)免费下载并使用。它涵盖了撰写时所有主要的数据清洗和机器学习技术,并且基于可视化编程。
可视化编程是 KNIME 分析平台的一个关键特性,用于快速原型开发。它使得该工具非常易于使用。在可视化编程中,图形用户界面(GUI)引导您完成构建专用模块(节点)流水线(工作流)的所有必要步骤。每个节点执行一个特定任务;每个节点的工作流将数据从起点处理到设计的终点。一个工作流替代了脚本,一个节点替代了一行或多行脚本。
如果没有广泛涵盖常用的数据清洗技术、机器学习算法、数据类型和格式,也没有与大多数常见的数据库软件、数据源、报告工具、外部脚本和编程语言的集成,软件的易用性将受到限制。因此,KNIME 分析平台被设计成支持不同数据格式、数据类型、数据源和数据平台的开放性,并且可以与 Python 和 R 等外部工具集成。
我们将从一些机器学习算法开始。KNIME 分析平台涵盖了大多数机器学习算法:从决策树到随机森林和梯度提升树,从推荐引擎到多种聚类技术,从朴素贝叶斯到线性回归和逻辑回归,从神经网络到深度学习。大多数算法原生支持 KNIME 分析平台,虽然一些算法可以通过集成其他开源工具(如 Python 和 R)来使用。
为了训练不同的深度学习架构,例如 RNN、自动编码器和 CNN,KNIME 分析平台通过KNIME 深度学习 - Keras 集成扩展集成了Keras深度学习库(www.knime.com/deeplearning/keras)。通过这个扩展,您可以拖放节点来定义复杂的神经网络架构,并训练最终的网络,而无需编写任何代码。
然而,定义网络只是必须采取的众多步骤之一。确保数据以正确的形式用于训练网络是另一个至关重要的步骤。为此,提供了大量的节点,以便我们可以实现各种数据清洗技术。通过结合专注于小任务的节点,您可以实现非常复杂的数据转换操作。
KNIME 分析平台还连接到大多数所需的数据源:从数据库到云存储库,从大数据平台到文件。
但是如果这些还不够呢?如果你需要一个针对特定领域的具体过程呢?如果你需要从 Python 中获取一个特定的网络操作功能呢?当 KNIME Analytics Platform 及其扩展无法满足需求时,你可以与其他脚本语言和编程语言进行集成,例如 Python、R、Java 和 Javascript,仅举几个例子。此外,KNIME Analytics Platform 与 BIRT(一款商业智能和报表工具)具有无缝集成。还可以与其他报表平台如 Tableau、QlickView、PowerBI 和 Spotfire 进行集成。
几个基于 JavaScript 的节点专门用于实现数据可视化的图表和图形:从简单的散点图到更复杂的旭日图,从简单的直方图到并行坐标图,等等。这些节点看似简单,但可能非常强大。如果你将它们组合在一个 组件 中,你可以跨多个图表交互选择数据点。通过这种方式,组件继承并结合了包含节点中的所有视图,并以一种方式将它们连接起来,使得如果在一个图表中选择并可视化数据点,它们也可以在组件的复合视图中的其他图表中选择并可视化。
图 1.1 显示了一个复合视图的示例:

图 1.1 – 包含散点图、条形图和并行坐标图的组件复合视图
图 1.1 显示了一个复合视图,包含散点图、条形图和并行坐标图。三个图表可视化相同的数据,并以一种方式连接,使得通过在条形图中选择数据,可以选择并在其他两个图表中可视化所选数据。
在创建数据科学解决方案时,KNIME Analytics Platform 提供了你所需的一切。然而,KNIME Server 提供了一些额外功能,以帮助你将解决方案投入生产环境。
KNIME 企业版服务器
数据科学周期中的最后一步是将解决方案部署到生产环境中——对于企业来说,这意味着提供一个轻松、舒适且安全的部署方式。
将应用程序推向现实世界的过程称为 投入生产。将训练好的模型包含在最终应用程序中的过程称为 部署。这两个阶段紧密相关,并且可能会出现问题,因为在应用程序设计过程中出现的所有错误都将在这一阶段显现出来。
尽管有限,但使用 KNIME Analytics Platform 将应用程序投入生产是可能的。如果你是一个独立的数据科学家或数据科学学生,通常不需要定期部署应用程序和模型,那么 KNIME Analytics Platform 可能足够满足你的需求。然而,如果你在企业环境中工作,涉及调度、版本控制、访问权限、灾难恢复、Web 应用和 REST 服务等典型的生产服务器功能,那么仅使用 KNIME Analytics Platform 进行生产可能会显得繁琐。
在这种情况下,KNIME Server(需要年度许可费用)可以让你的工作更轻松。首先,它能够更好地适应企业 IT 环境的治理需求。它还为你的团队和整个数据科学实验室提供了一个受保护的协作环境。当然,它的主要优势在于简化和更安全的模型部署过程,因为它使用了集成部署功能,并允许你通过一键部署将模型投入生产。最终用户可以通过 KNIME Analytics Platform 客户端运行应用程序,或者——更好的是——通过 Web 浏览器运行。
还记得那些提供选定点的交互式互联视图的复合视图吗?当应用程序通过KNIME Server 的 WebPortal在 Web 浏览器中执行时,这些视图将变成完整的网页。
利用组件作为工作流中的接触点,我们可以在 Web 浏览器中获得一个引导分析()应用程序。引导分析将接触点插入到应用程序流中,供最终用户从 Web 浏览器中使用。最终用户可以利用这些接触点插入知识或偏好,并引导分析朝着期望的方向发展。
现在,让我们下载 KNIME Analytics Platform 并试试看!
探索 KNIME Analytics Platform
要安装 KNIME Analytics Platform,请按照这些步骤:
-
前往。
-
提供一些关于你的详细信息(图 1.2中的第 1 步)。
-
下载适合你操作系统的版本(图 1.2中的第 2 步)。
-
当你等待适当版本的下载时,浏览一下不同的入门步骤(图 1.2中的第 3 步):

图 1.2 – 下载 KNIME Analytics Platform 包的步骤
下载完成后,找到安装包,启动它,并按照屏幕上显示的说明将其安装到任何你有写权限的目录中。
安装完成后,找到你安装的 KNIME Analytics Platform 实例——无论是从相应的文件夹、桌面链接、应用程序,还是开始菜单中的链接——并启动它。
当启动画面出现时,会弹出一个窗口要求你选择工作区的位置(图 1.3)。这个工作区是你计算机上的一个文件夹,用来存储你的所有工作。默认的工作区文件夹名为knime-workspace:

图 1.3 – KNIME Analytics Platform 启动窗口要求选择工作区文件夹
点击启动后,KNIME Analytics Platform的工作台将会打开。
KNIME Analytics Platform 的工作台如图 1.4所示组织:

图 1.4 – KNIME Analytics Platform 工作台
KNIME 工作台由不同的面板组成,可以通过点击视图菜单进行调整大小或移除。让我们来看看这些面板:
-
KNIME Explorer:位于左上角的KNIME Explorer面板显示了所选(LOCAL)工作区中的所有工作流、可能连接的 KNIME 服务器、与EXAMPLES服务器的连接以及与My-KNIME-Hub空间的连接。
LOCAL工作区显示了在启动 KNIME Analytics Platform 时所选工作区文件夹中保存的所有工作流。第一次打开平台时,LOCAL 工作区仅包含示例工作流文件夹中的工作流和数据。这些是可以作为你项目起点的示例应用程序。
EXAMPLES服务器是一个只读的 KNIME 托管服务器,包含了更多按类别组织的示例工作流。只需双击它即可自动以只读模式登录。完成此操作后,你可以浏览、打开、探索并下载所有可用的示例工作流。一旦找到一个工作流,双击它进行探索,或将其拖放到LOCAL中创建一个本地可编辑副本。
My-KNIME-Hub提供了访问 KNIME 社区共享库(KNIME Hub)的途径,可以选择公共或私有模式。你可以使用My-KNIME-Hub/Public与 KNIME 社区共享你的工作,或者使用My-KNIME-Hub/Private作为你当前工作的空间。
-
工作流教练:工作流教练是一个节点推荐引擎,可以在你构建工作流时提供帮助。基于全球用户统计数据或你自己的私人统计数据,它会为你提供使用哪些节点的建议,以完成你的工作流。
-
节点库:节点库包含了你当前安装的所有 KNIME 节点,并按类别进行组织。为了帮助你进行定位,节点库面板的顶部有一个搜索框。搜索框左侧的放大镜图标可以切换精确匹配和模糊搜索选项。
-
工作流编辑器:工作流编辑器是页面中央的画布,你可以在这里组装工作流、配置和执行节点、检查结果并探索数据。节点可以从节点库面板通过拖放或双击的方式添加到工作流编辑器中。启动 KNIME Analytics Platform 后,工作流编辑器将在欢迎页面面板中打开,那里有许多有用的提示,告诉你如何找到帮助、课程、活动以及关于软件的最新资讯。
-
大纲:大纲视图显示整个工作流,即使在工作流编辑器中只有一小部分可见。这部分在大纲视图中以灰色标出。移动大纲视图中的灰色矩形会改变工作流编辑器中可见的工作流部分。
-
控制台和节点监视器:控制台和节点监视器共享一个面板,分为两个标签页。控制台标签页输出可能的错误和警告信息。相同的信息会写入日志文件,位置在工作空间目录中。节点监视器标签页显示你在工作流编辑器中选择执行节点的输出端口可用的数据。如果一个节点有多个输出端口,你可以从下拉菜单中选择感兴趣的数据。默认情况下,顶部输出端口的数据会显示出来。链接
-
KNIME Hub: The KNIME Hub (
hub.knime.com/) 是一个外部空间,KNIME 用户可以在其中分享他们的工作。此面板允许你搜索由 KNIME 社区成员分享的工作流、节点和组件。 -
描述:描述面板显示有关所选节点或类别的信息。特别是,对于节点,它解释了节点的任务、背后的算法(如果有的话)、对话框选项、可用的视图、预期的输入数据以及产生的输出数据。对于类别,它显示所有包含的节点。
最后,在页面顶部,你可以找到顶部菜单,它包括文件管理和首选项设置、工作流编辑选项、附加视图、节点命令和帮助文档的菜单。
除了核心软件外,KNIME Analytics Platform 还受益于 KNIME 社区提供的外部扩展。在文件菜单中提供的安装 KNIME 扩展和更新 KNIME命令,允许你通过外部扩展扩展当前实例或将其更新到更新版本。
在顶部菜单下,提供了一个工具栏。当工作流打开时,工具栏提供工作流编辑、节点执行和自定义的命令。
通过从节点库面板将节点拖放到工作流编辑器窗口中,或者直接双击它们,可以构建一个工作流。节点是任何工作流的基本处理单元。每个节点都有多个输入和/或输出端口。数据通过连接从输出端口流向其他节点的输入端口。通过点击第一个节点的输出端口,并将鼠标释放到下一个节点的输入端口,两个节点就被连接起来——数据流也随之建立。由这样的一系列节点构成的数据处理流程便是一个工作流。
在图 1.5中,每个节点下方会看到一个状态灯:红色、黄色或绿色:

图 1.5 – 节点结构和状态灯
当创建一个新节点时,状态灯通常是红色的,这意味着节点的设置仍需要配置,才能执行任务。
要配置一个节点,右键点击它并选择配置,或者直接双击它。然后,在节点的对话框中调整必要的设置。当按下确定按钮关闭对话框时,节点就被配置好了,状态灯变为黄色;这意味着节点已准备好执行。再次右键点击节点时,会显示一个启用的执行选项;点击它将执行该节点。
左侧的端口是输入端口,来自前置节点输出端口的数据将通过它输入到节点中。右侧的端口是输出端口。节点对数据的操作结果通过后续节点的输出端口提供。当你将鼠标悬停在端口上时,会显示一个工具提示,提供节点输出维度的信息。
重要提示
只有相同类型的端口才能连接!
数据端口(黑色三角形)是最常见的节点端口类型,用于在节点之间传输平面数据表。数据库端口(棕色方块)用于在节点之间传输 SQL 查询。还有许多其他类型的节点端口,传输不同的对象。
执行成功后,节点的状态灯变为绿色,表示处理后的数据现在可以在输出端口中使用。结果可以通过查看输出端口视图来检查:右键菜单中的最后一项会打开它们。
到此为止,我们已经完成了 KNIME Analytics Platform 工作台的快速游览。
现在,让我们看看在哪里可以找到起始示例和帮助。
有用的链接和材料
此时,我们已经查看了 read file,你将获得一个示例工作流列表,展示如何读取 CSV 文件、.table 文件、Excel 文件等。(图 1.6):

图 1.6 – 在 KNIME Hub 上搜索 "read file" 后得到的工作流列表
本书中描述的所有工作流也可以在 KNIME Hub 上找到,供你使用:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/。
一旦你找到了感兴趣的工作流,点击它以打开其页面,然后下载或在 KNIME Analytics Platform 中打开它,以根据你的需要进行自定义。
另一方面,要在 KNIME Hub 上分享你的工作,只需将你的工作流从本地工作区复制到 KNIME Explorer 面板中的 My-KNIME-Hub/Public 文件夹中。这样,它将自动对所有 KNIME 社区成员可用。
KNIME 社区也非常活跃,KNIME 论坛(forum.knime.com/)上有许多技巧和窍门。在这里,你可以提问或查找答案。
最后,社区的贡献可以通过KNIME 博客(www.knime.com/blog)上的帖子、KNIME Press(www.knime.com/knimepress)出版的书籍,或者通过KNIME TV () 频道在 YouTube 上观看。
两本书《KNIME 初学者的幸运》和《KNIME 高级幸运》为那些刚开始使用 KNIME Analytics Platform 从事数据科学的用户提供了教程。
现在,让我们构建我们的第一个工作流,好吗?
构建并执行你的第一个工作流
在本节中,我们将构建我们的第一个简单的小型工作流。我们将从一些基础的内容开始:从 ASCII 文件读取数据,进行一些过滤,并在条形图中显示结果。
在 KNIME Explorer 中,按以下步骤操作:
-
通过以下步骤创建一个新的空文件夹:
a) 右键点击
第一章。 -
点击完成。然后你应该能在KNIME Explorer面板中看到一个新文件夹,名称就是你刚刚设置的名称。
重要提示
在 KNIME Explorer 中,文件夹被称为工作流组。
同样,你可以按照以下步骤创建一个新的工作流:
-
通过以下步骤创建一个新的工作流:
a) 右键点击
第一章文件夹(或者在你希望放置工作流的地方)。b) 选择
My_first_workflow。 -
点击完成。然后你应该能在KNIME Explorer面板中看到一个新工作流,名称就是你刚刚设置的名称。
点击完成后,工作流编辑器将打开空工作流的画布。
提示
默认情况下,新工作流的画布会显示网格;若要关闭它,请点击工具栏中打开工作流编辑器设置对话框按钮(倒数第二个按钮)。此按钮会打开一个窗口,你可以在其中自定义工作流的外观(例如,允许弯曲的连接线)并进行编辑(打开/关闭网格)。
图 1.7 显示了 新工作流组... 选项,在 KNIME Explorer 的上下文菜单中。它允许你创建一个新的空文件夹:

图 1.7 – 在 KNIME Explorer 中创建新文件夹和新工作流的上下文菜单
在我们的工作流中,首先需要读取包含数据的 ASCII 文件。让我们读取安装 KNIME Analytics Platform 时提供的adult.csv文件。它位于Example Workflows/The Data/Basics下。adult.csv 是一个美国人口普查公共文件,描述了 30K 人群体的年龄、性别、来源、职业和私人生活。
让我们创建该节点,以便能够读取adult.csv ASCII 文件:
a) 在Node Repository中,搜索File Reader节点(它实际上位于IO/Read类别中)。
b) 将File Reader节点拖放到Workflow Editor面板中。
c) 或者,直接双击File Reader节点,这将在Workflow Editor面板中自动创建它。
在图 1.8中,查看Node Repository中位于IO/Read下的File Reader节点:

图 1.8 – Node Repository中IO/Read下的 File Reader 节点
现在,让我们在 Workflow Editor 中使用File Reader节点,并手动配置文件路径以读取adult.csv文件。或者,直接将adult.csv文件从KNIME Explorer面板(或你计算机上的任何位置)拖放到Workflow Editor窗口中。你可以在图 1.9中看到这一操作:

图 1.9 – 将 adult.csv 文件拖放到 Workflow Editor 面板中。
这将自动生成一个 File Reader 节点,其中包含读取文件的大部分正确配置设置。
小贴士
在 File Reader 配置窗口中的Advanced按钮将引导你到更多高级设置:读取包含特殊字符(如引号)的文件;允许长度不同的行;使用不同的编码方式;等等。
要执行该节点,只需右键单击它,并从上下文菜单中选择Execute;或者,点击工具栏中可用的Execute按钮(绿色背景上的单白箭头和双白箭头)。
要检查由该节点执行生成的输出数据表,右键单击该节点并选择上下文菜单中的最后一个选项。这将打开作为读取adult.csv文件结果的数据表。你将看到Age、Workclass等列。
重要说明
KNIME Analytics Platform 中的数据是以表格形式组织的。每个单元格通过列标题和行 ID唯一标识。因此,列标题和行 ID 需要具有唯一的值。
fnlwgt是一个我们一直不确定其含义的列。因此,使用Column Filter节点将其从进一步分析中移除。
为此,搜索 File Reader 节点并将其连接到 Column Filter 节点的输入端口。或者,我们可以在节点库中选择 Column Filter 节点中的 File Reader 节点。这会自动在工作流编辑器中创建节点及其连接。
Column Filter 节点及其配置窗口如 图 1.10 所示:

图 1.10 – 配置 Column Filter 节点以从输入数据表中删除名为 fnlwgt 的列
同样,双击或右击节点,然后选择 配置 进行配置。该配置窗口包含三个选项,可以通过三个单选按钮选择:手动选择、通配符/正则表达式选择 和 类型选择。让我们更详细地了解这些选项:
-
手动选择 提供了一个包含/排除框架,您可以通过框架之间的按钮手动将列从 包含 集合转移到 排除 集合,反之亦然。
-
通配符/正则表达式选择 根据通配符(使用 ***** 作为通配符)或正则表达式提取您希望保留的列。
-
类型选择 根据列所包含的数据类型来保留列。
由于这是我们的第一个工作流,我们将选择最简单的方法;也就是手动选择。通过框架之间的按钮,将 fnlwgt 列移到 排除 集合中(这些按钮可以在 图 1.10 中看到)。
执行 Column Filter 节点后,如果我们检查输出数据表(右击并选择上下文菜单中的最后一个选项),我们会看到一个不包含 fnlwgt 列的表格。
现在,让我们提取所有每周工作超过 20 小时的人的记录。hours-per-week 是包含相关数据的列。
为此,我们需要创建一个 Row Filter 节点,并实现所需的条件:
IF hours-per-week > 20 THEN Keep data row.
再次,定位 Column Filter 节点到其输入端口,并打开其配置窗口。
在 Row Filter 节点的配置窗口中(图 1.11),我们将看到三个默认的过滤条件:使用模式匹配、使用范围检查 和 仅缺失值匹配。让我们来看一下它们的作用:
-
使用模式匹配 将给定的模式与 测试列 字段中选定列的内容进行匹配,并保留匹配的行。
-
使用范围检查 仅保留在 测试列 中值位于 下限 和 上限 之间的数据行。
-
仅缺失值匹配 只保留选定列中存在缺失值的数据行。
默认行为是将匹配的数据行包含在输出数据表中。然而,您可以通过配置窗口左侧的单选按钮启用 按属性值排除行 来更改此行为。
替代的过滤条件可以通过行号或行 ID 完成。也可以通过配置窗口左侧的单选按钮启用:

图 1.11 – 配置行过滤器节点,以仅保留输入数据表中每周工作小时数大于 20 的行
执行后,打开输出数据表(图 1.12)时,不应出现 每周工作小时数 < 20 的数据行:

图 1.12 – 右键点击成功执行的节点并选择最后一个选项,显示由该节点生成的数据表
现在,让我们来看一些非常基础的可视化。我们将可视化这个数据集中男性与女性的数量,该数据集包含每周工作超过 20 小时的人:

图 1.13 – 条形图节点及其配置窗口
为此,找到 Row Filter 节点,并打开其配置窗口(图 1.13)。这里有四个标签可以用于配置:选项 涵盖所有数据设置,常规绘图选项 涵盖所有绘图设置,控制选项 涵盖所有控制设置,交互性 涵盖所有与其他图表、视图和图形交互时的订阅事件。由于这是一个初学者的工作流,我们将采用所有默认设置,只设置以下内容:
-
从
sex中,确保它出现在 x 轴上。然后,选择 出现次数 以按性别统计行数。 -
从 常规绘图选项 标签中,设置标题、副标题和轴标签。
该节点不会生成数据,而是生成条形图的视图。因此,要检查该节点执行后的结果,右键点击它并选择中央选项,即 交互视图:分组条形图(图 1.14):

图 1.14 – 右键点击成功执行的可视化节点并选择交互视图:分组条形图选项,以查看生成的图表/图形
注意 图 1.14 右侧视图的右上角有三个按钮。这三个按钮分别启用 缩放、切换到全屏 和 节点设置。在视图本身中,您可以探索选择不同设置后的图表效果,例如选择不同的类别列或标题。
重要提示
大多数数据可视化节点生成的是视图,而不是数据表。要查看相应的视图,右键点击成功执行的节点并选择交互视图:...选项。
条形图节点的第二个下输入端口是可选的(一个白色三角形),用于读取颜色映射,这样你就可以给条形图中的条形上色。
重要提示
请注意,节点库中提供了多种不同的数据可视化节点:JavaScript、本地(Swing)、Plotly 等。在节点库面板中,可以找到来自 JavaScript 类别的 条形图 节点。
现在,我们将添加一些注释以记录工作流。你可以在节点级别或整个工作流级别添加注释。
工作流中的每个节点默认都会创建一个名为节点 xx的标签。双击它后,节点标签编辑器将出现。你可以自定义文本、字体、颜色、背景以及节点的其他类似属性(图 1.15)。我们需要在每个节点下写上一些简短的注释,明确它们正在执行的任务:

图 1.15 – 自定义每个节点下标签的编辑器
你还可以在工作流级别写注释。只需右键点击工作流编辑器中的任意位置,然后选择新建工作流注释。在编辑模式下,黄色框架将出现。在这里,你可以添加文本并自定义它以及其框架。要关闭注释编辑器,只需在工作流编辑器中的其他地方单击。要重新打开注释编辑器,双击注释的左上角(图 1.16):

图 1.16 – 创建和编辑工作流注释
恭喜!你刚刚使用 KNIME 分析平台构建了你的第一个工作流。它应该看起来像图 1.17中的样子:

图 1.17 – 我的第一个工作流
这只是 KNIME 分析平台使用的简要介绍。
现在,让我们确保已安装并正常运行 KNIME 深度学习 – Keras 集成。
安装 KNIME 深度学习 – Keras 集成
在本节中,你将学习如何安装和设置KNIME 深度学习 - Keras 集成,以便在 KNIME 分析平台中训练神经网络。
KNIME 分析平台由软件核心和若干提供的扩展及集成组成。这些扩展和集成由 KNIME 社区提供,并通过多种数据科学功能扩展原始软件核心,包括用于人工智能的高级算法。
这里感兴趣的 KNIME 扩展叫做 KNIME 深度学习 - Keras 集成。它提供了一个基于图形用户界面的无代码集成 Keras 库,同时使用 TensorFlow 作为其后端。这意味着 Keras 库中的许多功能已被封装到 KNIME 节点中,并通过 KNIME 经典的、易于使用的视觉对话框窗口进行操作。由于这种集成,您可以在不编写代码的情况下读取、写入、创建、训练和执行深度学习网络。
另一种可用的深度学习集成是 KNIME 深度学习 - TensorFlow 集成。该扩展允许您将 Keras 模型转换为 TensorFlow 模型,还可以读取、执行和写入 TensorFlow 模型。
TensorFlow 是由谷歌提供的开源库,包含了多种深度学习范式。TensorFlow 函数可以在单个设备上运行,也可以在多个 CPU 和多个 GPU 上运行。这种并行计算功能是加速深度学习网络所需的计算密集型训练的关键。
然而,在 Python 中使用 TensorFlow 库可能会相当复杂,即使是经验丰富的 Python 程序员或深度学习专家也不例外。因此,开发了一些简化的接口,基于 TensorFlow,暴露了其部分功能和参数。最成功的 TensorFlow 基于库之一是 Keras。然而,甚至 Keras 仍然需要一定的编程技能。KNIME 深度学习 - Keras 集成 将 KNIME GUI 放置在 Keras 库之上,基本消除了编写代码的需求。
为了让 KNIME 深度学习 - Keras 集成 正常工作,需要安装几个必要的组件:
-
Keras 和 TensorFlow 节点
-
Python 环境
让我们从第一步开始:安装 Keras 和 TensorFlow 节点。
安装 Keras 和 TensorFlow 节点
要向节点库添加节点,您必须安装一些扩展和集成。
您可以通过点击 KNIME Analytics Platform 顶部菜单中的 文件,选择 安装 KNIME 扩展… 来安装它们。这将打开如 图 1.18 所示的对话框:

图 1.18 – 安装扩展的对话框
在这个新对话框中,您可以选择要安装的扩展和集成。使用顶部的搜索栏有助于过滤可用的扩展和集成。
提示
您还可以通过从 KNIME Hub 拖放扩展来安装它们。
为了安装将在本书案例研究中使用的 Keras 和 TensorFlow 节点,您需要选择以下内容:
-
KNIME 深度学习 - Keras 集成
-
KNIME 深度学习 - TensorFlow 集成
然后,按下 下一步 按钮,接受条款和条件,并点击 完成。安装完成后,您需要重新启动 KNIME Analytics Platform。
此时,你应该在节点库中看到 Keras 和 TensorFlow 节点(图 1.19):

图 1.19 – 节点库中已安装的深度学习节点
很多节点实现了神经网络层:输入层和丢弃层的节点可以在 Core 子类别中找到,LSTM 层的节点可以在 Recurrent 中找到,嵌入层的节点可以在 Embedding 中找到。然后,还有用于训练、加载和存储网络的学习器(Learner)、读取器(Reader)和写入器(Writer)节点。这些节点都有配置窗口,并且不需要编写代码。Python 深度学习节点允许你使用 Python 代码定义、训练、执行和编辑网络。最后一个子类别包含基于 TensorFlow 的节点。
接下来,我们需要设置 Python 环境。
设置 Python 环境
KNIME Keras 集成和 KNIME TensorFlow 集成依赖于现有的 Python 安装,这需要安装一些 Python 依赖项。
与 KNIME Python 集成类似,KNIME 深度学习集成使用 Anaconda 来管理 Python 环境。如果你已经为 KNIME Python 集成安装了 Anaconda(例如),你可以跳过第一步。
让我们开始吧:
-
首先,从
www.anaconda.com/products/individual获取并安装最新版本的 Anaconda(Anaconda ≥ 2019.03,conda ≥ 4.6.2)。在 Anaconda 下载页面,你可以选择 Python 3.x 或 Python 2.x 的版本。两者都可以使用(如果不确定,建议选择 Python 3)。 -
接下来,我们需要创建一个包含正确库的环境。为此,在 KNIME Analytics Platform 中打开 Python 深度学习偏好设置。然后,执行以下操作:
-
首先,从顶部菜单中选择 文件 -> 偏好设置。这将打开一个新对话框,左侧会列出相关选项。
-
在对话框中,选择 KNIME -> Python Deep Learning。
你现在应该会看到一个像 图 1.20 中那样的对话框:
![图 1.20 – Python 深度学习偏好页面]()
图 1.20 – Python 深度学习偏好页面
从此页面,可以创建一些 Conda 环境,并安装适用于 Keras 或 TensorFlow 2 的正确包。对于本书中的案例研究,设置一个适用于 Keras 的环境就足够了。
-
要创建并设置新环境,启用 使用特殊的深度学习配置,并将 Keras 设置为 用于 DL Python 的库。接下来,启用 Conda 并提供 Conda 安装目录的路径。
-
此外,要为 Keras 创建新环境,点击 Keras 框架中的 新建环境… 按钮。
这将打开一个新的对话框,如 图 1.21 所示,你可以在此设置新环境的名称:
![图 1.21 – 设置新环境名称的对话框]()
图 1.21 – 设置新环境名称的对话框
-
单击创建新的 CPU 环境或创建新的 GPU 环境按钮,可以为使用 CPU 或 GPU(如果有的话)创建一个新环境。
现在,您可以开始了。在本节中,您已经介绍了设置 Python 环境的最便捷方式。其他选项可以在 KNIME 文档中找到:docs.knime.com/2019-06/deep_learning_installation_guide/index.html#keras-integration。
本书的目标与结构
在本书中,我们的目标是为您提供关于深度学习架构和训练范式的坚实理论基础,以及一些基于真实世界数据解决实际案例研究的详细无代码体验。
对于这一旅程,我们采用了无代码工具 KNIME Analytics 平台。KNIME Analytics 平台基于可视化编程,并利用用户友好的 GUI,使数据分析成为一项更经济的任务,无需编程障碍。与许多其他外部扩展一样,KNIME Analytics 平台在相同的 GUI 下集成了 Keras 库,从而将深度学习纳入其无代码扩展列表。在 KNIME Analytics 平台内,您只需拖放几下和鼠标几次点击,即可构建、训练和测试深度学习架构。我们在本章中对该工具进行了简要介绍,但在第二章中,我们将提供更详细的信息,使用 KNIME Analytics 平台进行数据访问和预处理。
之后,在第三章,开始使用神经网络,我们将快速概述神经网络和深度学习背后的基本概念。本章将绝不会完全涵盖所有涉及神经网络和深度学习的架构和范式。相反,它将为您提供一个快速概述,帮助您在继续实施之前,第一次或再次熟悉这些概念。如果您想了解更多关于深度学习的数学背景,请参考更专业的文献。
正如我们之前所述,我们决定以非常实际的方式讨论深度学习技术;也就是说,总是通过参考真实的案例研究,展示某种深度学习技术如何成功实施。我们将在第四章《构建与训练前馈网络》中开始这一趋势,在这一章中,我们将描述一些基本的示例应用,用以训练并应用我们在第三章《神经网络入门》中探讨的深度学习网络的基本概念。尽管这些只是简单的玩具示例,但它们仍然对于阐明如何应用我们在前一章中描述的理论概念非常有用。
在第五章《用于欺诈检测的自编码器》中,我们将开始研究真实的案例研究。我们将在本章中描述的第一个案例研究旨在通过每次检测到可疑交易时触发警报,从而防止信用卡交易中的欺诈行为。为了实现这一种异常检测子类,我们将采用基于自编码器架构的方法,以及网络输出与输入值之间计算出的距离。
在第五章《用于欺诈检测的自编码器》中,我们仍处于经典神经网络的范畴,包括前馈网络和通过反向传播训练的网络,尽管采用了原始架构。在第六章《用于需求预测的循环神经网络》中,我们将进入深度学习网络的领域,具体来说是使用 RNN,尤其是 LSTM。在这里,我们将利用此类网络的动态特性及其捕捉信号时间演变的能力来解决一个经典的时间序列分析问题:需求预测。
在介绍 RNN 后,我们将学习如何将其应用于自然语言处理(NLP)案例研究。第七章《实现 NLP 应用》中涵盖了几个这样的 NLP 用例:情感分析、自由文本生成和产品名称生成等等。所有这些用例在某种意义上是相似的,因为它们都分析文本流。它们也有所不同,因为它们解决的是不同的问题:前者的情感分析是分类任务,而后两者则是对词语或字符序列的无约束生成。然而,数据准备技术和 RNN 架构对于所有的案例研究来说都是相似的,这就是为什么它们被放在同一章中的原因。
第八章,神经机器翻译,描述了一个基于 RNN 的自由文本生成案例。在这里,网络的输出端会根据输入层中相应的词序列生成一段词序列。输出序列将以目标语言生成,而输入序列则以源语言提供。
深度学习不仅仅是 RNN 和文本挖掘的形式。实际上,深度学习网络的最初实例来源于图像处理领域。第九章,用于图像分类的卷积神经网络,专门描述了一个案例研究,其中需要将组织病理切片图像分类为三种不同类型的癌症之一。为此,我们将介绍 CNN。训练用于图像分析的网络在时间、数据量和计算资源方面并非易事。通常,为了训练一个神经网络使其能够识别图像,我们必须依赖于迁移学习的优势,正如第九章,用于图像分类的卷积神经网络中所描述的那样。
第九章,用于图像分类的卷积神经网络,总结了我们深入探讨的深度学习技术在实际案例中的应用。我们意识到,其他深度学习范式也被用于解决其他数据科学问题。然而,在此我们决定仅报告我们有实际经验的常见范式。
训练完网络后,必须进入部署阶段。由于这是所有问题都会暴露的阶段,因此部署阶段经常被忽略。这包括应用程序设计中的错误、网络训练中的错误、数据访问和准备中的错误:所有这些问题都会在此阶段显现出来。因此,本书的最后两章专门讨论了训练深度学习网络的部署阶段。
第十章,部署深度学习网络,将向你展示如何构建部署应用程序,而第十一章,最佳实践及其他部署选项,则将展示所有可用的部署选项(如网页应用或 REST 服务)。它还将为你提供一些我们自身经验中的小贴士和技巧。
每一章后都有相应的问题,帮助你测试自己对所学内容的理解。
在此,请继续阅读,了解如何使用 KNIME Analytics Platform 将各种深度学习架构应用于实际案例。
总结
本章的目的是为你提供本书内容的预备知识。
因此,我们通过提醒你深度学习的重要性以及它在第一次深度学习成功案例之后获得的广泛关注来开始本章。这种关注的激增可能正是将你吸引到这里的原因,带着对深度学习网络在实际应用中实现的更多了解的渴望。
目前,我们在学习深度学习时遇到的主要障碍是所需的编程技能。在这里,我们采用了 KNIME 软件,特别是开源的 KNIME Analytics Platform,以便我们可以查看本书中提出的案例研究。为此,我们详细描述了 KNIME 软件和 KNIME Analytics Platform。
KNIME Analytics Platform 还受益于一个名为 KNIME Deep Learning – Keras Integration 的扩展,它帮助整合 Keras 深度学习库。它通过将基于 Python 的库封装到无代码的 KNIME 图形用户界面中来实现这一点。我们专门为此安装过程提供了一个完整的章节。
最后,我们通过概述本书剩余章节的内容来结束本章。
在我们深入探讨深度学习网络的数学和应用之前,我们将在下一章中先熟悉 KNIME Analytics Platform 的基本功能。
第二章:第二章:使用 KNIME 分析平台进行数据访问和预处理
在深入学习神经网络和深度学习架构之前,可能最好先熟悉 KNIME 分析平台及其最重要的功能。
本章将涵盖 KNIME 分析平台中的一些基本操作。由于每个项目都需要数据,我们将首先讲解如何访问数据:从文件或数据库中。在 KNIME 分析平台中,您还可以从 REST 服务、云存储库、特定行业格式等获取数据。我们将把这些其他选项的探索留给您自己。
数据有多种形状和类型。在数据类型和转换部分,我们将简要探讨 KNIME 数据表示的表格特性、数据表中的基本数据类型,以及如何将一种类型转换为另一种类型。
到目前为止,我们已经将数据导入到 KNIME 工作流中,接下来我们将展示一些基本的数据操作,如过滤、连接、拼接、聚合以及其他常用的数据转换。
静态工作流的参数化将总结我们对 KNIME 分析平台进行的基本操作的快速概述。
本章将介绍以下主题:
-
访问数据
-
数据类型和转换
-
数据转换
-
工作流参数化
让我们从如何将数据导入到 KNIME 工作流开始。
访问数据
在开始展示如何访问和导入数据到 KNIME 工作流之前,让我们先创建一个工作流:
-
点击顶部菜单中的文件项,或右键点击一个文件夹,例如在KNIME Explorer中的LOCAL文件夹。
-
然后,选择新建 KNIME 工作流选项。
-
给它命名——例如,
Ch2_Workflow_Examples——并选择一个目标位置。一个空白的画布将会在 KNIME 工作台的中央打开:工作流编辑器。
对于本章内容,我们将使用安装时已经提供的示例数据。安装时会一起安装一套工作流,您可以在Example Workflows文件夹中找到它们(见图 2.1),而TheData子文件夹包含一些免费的玩具数据集:

图 2.1 - KNIME Explorer 面板中示例工作流文件夹的结构
我们将主要使用Misc子文件夹中的数据集。
提示
为了将数据上传到KNIME Explorer面板,只需将其复制到您计算机当前工作区文件夹中的一个文件夹中。然后,文件夹及其内容将在KNIME Explorer的工作流、服务器、KNIME Hub 空间和可用数据列表中出现。
从文件中读取数据
让我们从经典的方法开始:读取CSV 格式的文本文件。要读取 CSV 格式的文本文件,您需要使用文件读取器节点或其简化版本CSV 读取器节点。让我们专注于文件读取器节点,尽管它更复杂,但也更强大和灵活。现在有两种创建和配置文件读取器节点的方法。
长方法中,您可以在节点库中搜索文件读取器节点;将其拖放到工作流编辑器中;双击打开其配置窗口,或者选择右键然后选择配置;设置所需的设置,至少需要通过浏览按钮设置文件路径(图 2.2)。
短方法中,您只需将 CSV 格式的文件从文件浏览器面板拖放到工作流编辑器中。这种方式会自动创建文件读取器节点,并填充大部分配置设置,包括文件路径,并保持配置窗口打开以便进一步调整(图 2.2)。
在文件路径下方,有一些基本设置:是否将第一行读取为列标题和/或将第一列作为行 ID,一般文本文件的列分隔符,以及如何处理空格和制表符。
在文件读取器节点的配置窗口中,还要注意两件事情:数据预览和高级按钮。窗口下部的数据预览允许您查看数据集是否被正确读取。高级按钮会带您到更高级的设置,例如启用更短的行,字符编码,引号和其他类似的偏好设置。
当使用短方法创建和配置文件读取器节点时,在节点配置窗口的预览面板中(图 2.2),您可以看到自动设置是否足够或是否需要额外的定制:

图 2.2 – 文件读取器节点及其配置窗口
我们将Demographics.csv文件从示例工作流程/数据/其他拖放到工作流编辑器中。在文件读取器节点的配置窗口中,我们看到CustomerKey列被解释为数据行的行 ID,而不是其自己的列。我们需要禁用读取行 ID选项以正确读取数据。配置完成后,点击确定;节点状态变为黄色,节点现在可以执行。
提示
通过文件拖放自动创建节点并配置其设置仅适用于特定的文件扩展名:.csv用于文件读取器节点,.table用于表格读取器节点,.xls和.xlsx用于 Excel 读取器节点等。
类似地,如果我们从 KNIME 资源管理器面板中将ProductData2.xls文件拖放到工作流编辑器中,则会创建并自动配置Excel 读取器(XLS)节点(图 2.3):

图 2.3 – Excel Reader (XLS)节点及其配置窗口
配置窗口(图 2.3)与文件读取节点的配置窗口相似,但当然是定制化的,用于处理 Excel 文件。特别有三个项是不同的:
-
预览部分由刷新按钮激活。你需要点击刷新来更新预览。
-
列头和行 ID 是从电子表格单元格中提取的,通过字母(列头所在的列)和数字(行 ID 所在的行)来标识,符合 Excel 标准。
-
在 URL 路径的顶部,有一个带有默认选择的菜单,自定义 URL。此菜单允许你将文件路径表示为绝对路径(本地文件系统)、相对于挂载点的路径(Mountpoint)、相对于当前位置之一(数据、工作流或挂载点)的路径,或者自定义路径(Custom URL)。此功能很快将扩展到其他读取节点。
在我们的例子中,自动配置过程并未包含列头。从预览段可以看出这一点。因此,由于我们在第一行中有列头,我们调整1,刷新预览,然后点击确定保存更改并关闭窗口。
接下来,让我们读取SentimentAnalysis.table文件。.table文件包含以 KNIME 专有格式优化的二进制内容,旨在提高速度和减小文件大小。这些文件由表格读取节点(Table Reader node)读取。由于文件中的所有信息已经包含在文件本身,因此SentimentAnalysis.table文件的配置窗口会自动生成一个预配置 URL 的表格读取节点。
为了总结本节内容,让我们通过两个额外的文件读取节点来读取最后两个文件,SentimentRating.csv和WebDataOldSystem.csv,然后在每个节点下的注释中添加文件名。最后,将所有这些读取节点组合在一个注释中,解释从文件中读取数据(图 2.9)。
Demographics.csv包含多个客户的基本信息,如年龄和性别。每个客户通过CustomerKey值进行标识。ProductData2.xls包含每个客户购买的产品,同样通过CustomerKey值进行标识。SentimentAnalysis.table包含客户对公司和产品表达的情感(以文本形式),再次通过CustomerKey值进行标识。SentimentRating.csv包含情感评分与情感文本之间的映射。最后,WebdataOldSystem.csv包含在迁移前旧网站系统中,每个客户的旧活动指标。
当然,如果有迁移之前的数据集,我们必须拥有一个包含迁移后系统数据的更新数据集。这个数据集可以在WebActivity.sqlite SQLite 数据库中的一个数据库表中找到。
这引导我们进入下一部分,在那里我们将学习如何从数据库读取数据。
从数据库读取数据
在节点库中,有一个名为 DB 的类别,专门用于 数据库 操作。所有数据库操作都按照相同的顺序执行(图 2.4):连接数据库,选择要处理的表,构建 SQL 查询,并根据 SQL 查询导入数据。
如 图 2.4 所示,每个步骤都有相应的节点:

图 2.4 – 从数据库导入数据:连接、选择、构建 SQL 查询并导入
让我们逐一检查这些节点:
-
WebActivity.sqlite文件。配置窗口只需要数据库文件路径,因为 SQLite 是基于文件的数据库。所有其他设置已经在节点中预设。事实上,在专用连接器中预设一些设置是很常见的,因此专用连接器所需的设置比通用 DB Connector 节点少。拖放.sqlite文件会自动生成带有预加载配置设置的 SQLite DB Connector 节点。 -
选择表:DB Table Selector 节点允许你从连接的数据库中选择要操作的表。如果你是 SQL 专家,自定义查询 标志允许你为要提取的数据子集创建自己的查询。
-
构建 SQL 查询:如果你不是 SQL 专家,你仍然可以构建自己的 SQL 查询来提取数据子集。DB/Query 类别中的 DB 节点将 SQL 查询作为输入,并在其基础上添加更多 SQL 查询。该节点的图形用户界面完全不需要编码,因此无需了解任何 SQL 代码。例如,DB Row Filter 节点的配置窗口在右侧提供了一个图形编辑器,用于构建行过滤的 SQL 查询。
在下面的截图中(图 2.5),CustomerKey = 11177 的记录已被排除:

图 2.5 – DB 行过滤器节点的图形用户界面。该节点构建 SQL 查询以过滤掉没有使用任何 SQL 脚本的记录
-
导入数据:最后,DB Reader 节点根据输入的 SQL 查询从数据库连接中导入数据。DB Reader 节点没有配置窗口,因为导入数据所需的所有 SQL 设置都包含在其输入端口的 SQL 查询中。除了 DB Reader 节点外,还有许多其他节点可以在这样的序列末尾从数据库中导入数据。它们都位于节点配置面板中的 DB/读/写 类别下。
重要提示
您是否注意到图 2.4中的节点端口?我们从黑色三角形(数据)经过红色方块(连接)到棕色方块(SQL 查询)。只有相同类型的端口,传输相同类型的数据,才能连接!
为了检查结果,在成功执行 DB Reader 节点后,您可以右键点击序列中的最后一个节点——带有黑色三角形(数据)端口的节点,在此情况下是 DB Reader 节点——并选择菜单中的最后一项。这将显示输出数据表。
数据库节点只会生成一个 SQL 查询。在输出端口,您仍然可以通过右键点击节点,选择菜单中的最后一项,然后点击缓存行数按钮,在表格预览标签页中临时可视化所选数量的顶部行,以检查查询结果。
此时,我们也已经导入了最后一个数据集,包括迁移到新网站系统后的客户网页活动数据。
现在,让我们花点时间了解数据结构和数据类型。
数据类型和转换
如果您检查之前描述的任何节点的输出数据表,您将看到数据的表格化表示。在这里,每个值是通过RowID(记录的标识号)来识别的,并且通过CustomerKey 11000为M,如Gender列头所示,行 ID 为Row0。在读取节点中,行 ID 和列头可以自动生成,或者根据数据中的某列或某行的值分配。
以下是由 File Reader 节点输出的数据表的截图:

图 2.6 – 一个 KNIME 数据表。在这里,一个单元格是通过其 RowID 值和列头来识别的。
每个数据列也都有一个数据类型,正如您在图 2.6中看到的那样,可以通过列头中的图标来识别。基本数据类型有true/false和String。但是,也有更多复杂的数据类型,如Date&Time、Document、Image、Network等。我们将在接下来的章节中看到这些数据类型的一些例子。
当然,一个数据列并不是注定永远保持该数据类型。如果条件允许,它可以转换为另一种数据类型。某些节点专门用于转换,您可以在节点库中的Manipulation/Column/Convert & Replace下找到它们。
在我们读取的数据中,CustomerKey被导入为五位整数。但是,将其从整数类型表示转换为字符串类型表示可能会更方便。为此,我们使用Number to String节点。配置窗口由一个包含/排除框架组成,用于选择需要改变类型的列。相反的转换可以通过String to Number节点实现。Double to Int节点在从双精度浮点数转换为整数时也很有用。
提示
字符串操作和数学公式节点,虽然它们的主要任务是数据转换,但也提供一些转换功能。
我们希望引起你对类别转数字节点的注意。这个节点非常有用,可以将名义类别离散化,并将它们转换为数字,因为神经网络只接受数字作为目标类别。
特殊数据类型,如图像或日期和时间,提供了它们自己的转换节点。一个非常有用的节点是字符串到日期和时间节点。日期或时间对象通常被读取为字符串,而这个节点将它们转换为适当的类型对象。
在接下来的部分,我们将整合所有这些客户信息,从迁移前后的网络活动开始。在这两个数据集中,描述网络活动的列名不同:First_WebActivity_ 和 First(WebActivity)。我们将它们标准化为相同的名称:First_WebActivity_。
这正是列重命名节点的功能:

图 2.7 – 列重命名节点及其配置窗口
列重命名节点的配置窗口列出了输入数据表中所有的列名,在左侧显示。双击某一列会在右侧打开一个框架,显示当前的列名,并要求输入新的列名和/或新的类型。我们在本节中介绍的所有节点可以在图 2.13中的工作流中看到。
现在,我们准备好将两个网络活动数据集合并,并通过它们的CustomerKey值联接所有其他数据集。
数据转换
我们已经从文件和数据库中读取了数据。在本节中,我们将执行一些操作来整合、筛选、聚合和转换这些数据。我们将从整合操作开始。
联接与连接
来自旧系统的网络活动数据集来自一个 CSV 文件,经过列重命名后,包含两列数据:CustomerKey 和 First_WebActivity_。First_WebActivity_表示客户在公司网站上的活跃度:0表示不活跃,3表示非常活跃。
来自新网页系统的网络活动数据集来自 SQLite 数据库,包含三列:CustomerKey、First_WebActivity_ 和 Count。Count只是与数据行相关的递增数字,对接下来的分析不重要。我们稍后可以决定是否删除它或保留它。
如果能够将来自旧系统和新系统的网页活动排名放在同一个数据表中,那就太好了。为此,我们使用 Concatenate 节点。两个输入数据表被放置在同一个输出数据表中。属于同名列的数据单元被放置在相同的输出列中。仅存在于一个表中的数据列可以保留(列的联合)或移除(列的交集),具体取决于节点配置窗口中的设置。节点配置窗口还提供了一些策略,用于处理在两个输入表中都存在相同行 ID 的行。
我们将两个网页活动数据表进行了合并,并在输出数据表中保留了数据列的联合。
重要提示
Concatenate 节点图标的左下角显示三个点。点击这三个点,您可以添加更多的输入端口,从而连接更多的输入数据表。
现在让我们来处理情感分析数据。SentimentAnalysis.table 生成了一个包含 CustomerKey 和 SentimentAnalysis 列的数据表。SentimentAnalysis 包含客户对公司和产品的情感,表达为文本。SentimentRating.csv 生成了一个包含两列的数据表:SentimentAnalysis 和 SentimentRating。这两列都表达客户情感:一列为文本,另一列为排名序数。这是一个映射数据表,用于将文本转换为排名情感,反之亦然。根据我们要进行的分析类型,我们可能需要文本表达或排名表达。因此,为了确保安全,我们将这两个数据表连接在一起,将它们的 CustomerKey、SentimentAnalysis(文本)和 SentimentRating(序数)都放在同一个数据表中。这是通过 Joiner 节点实现的。
Joiner 节点根据键值将两个输入数据表中的数据单元合并到同一行。在我们的例子中,键值由两个输入数据表中都存在的 SentimentAnalysis 列提供。因此,每个客户(CustomerKey)将拥有 SentimentAnalysis 文本值和相应的 SentimentRating 值。Joiner 节点提供四种不同的连接模式:内连接(两个表中键值的交集)、左外连接(左/上表中的所有键值)、右外连接(右/下表中的所有键值)和 全外连接(两个表中的所有键值)。
在 图 2.8 中,您可以找到 Joiner 节点配置窗口的两个选项卡:

图 2.8 – Joiner 节点的配置窗口:Joiner 设置和列选择选项卡
连接器节点的配置窗口包含两个选项卡:连接器设置和列选择。连接器设置选项卡允许选择连接模式和包含关键值的数据列,适用于两个输入表格。列选择选项卡设置在构建最终连接数据行时,两个输入表格中要保留的列。还提供了一些附加选项,以处理两个表格中具有相同名称的列,并设置在连接执行后如何处理关键列。
重要提示
连接操作中可以有多个层级的关键列。只需在连接器设置选项卡中选择+按钮来添加更多关键列。如果有多个层级的关键列,您可以决定是否在所有关键值匹配时执行连接(匹配所有以下条件),或者仅当一个关键值匹配时执行连接(匹配以下任意条件),如左侧的单选按钮所设置(图 2.8)。
我们使用SentimentAnalysis作为两个表中的关键列,并使用左外连接将两个情感表连接在一起。左外连接包括左侧(上方)表格(客户表)中的所有关键值,因此确保所有客户的情感值都保留在输出数据表中。
在将CustomerKey与所有情感表达式连接后,我们将执行其他类似的连接操作,使用CustomerKey作为关键列,级联多次连接,以将同一客户的不同数据片段收集到一个表中(图 2.13)。
如果我们检查由Demographics.csv文件生成的输出,我们会注意到有两个数据列也由其他文件提供:WebActivity和SentimentRating。这些是旧列,应当用SentimentAnalysis.table文件和网页活动文件中的相应列替换。我们可以在连接器节点的列选择选项卡中删除这两列。或者,我们也可以通过专用节点将这两列过滤掉。
让我们来看一下如何从数据表中过滤列和行。
列和行过滤
列过滤器节点专门用于过滤输入数据表中的列。我们可以按如下方式进行操作:
-
手动选择要保留和排除的列(手动选择)。
-
使用通配符或正则表达式来匹配要排除或保留的列名(通配符/正则表达式选择)。
-
定义要包含或排除的列的数据类型(类型选择)。
这些选项都可以在列过滤器节点的配置窗口顶部找到。选择其中一个选项后,配置窗口会根据该选项的设置进行调整。以下是这些选项。
-
手动选择:提供一个包含/排除框架,用于将列从一个数据框移动到另一个数据框,以包含或排除输出数据表中的输入列(图 2.9)。
-
*表示通配符字符;例如,R*表示所有以R开头的单词,R*a表示所有以R开头并以a结尾的单词,依此类推。正则表达式(Regex)指的是正则表达式。 -
类型选择:此选项提供了一个多项选择,用于选择列的数据类型。
Column Filter 节点的配置窗口如图 2.9所示:

图 2.9 – Column Filter 节点及其配置窗口
到目前为止,我们一直是在按列过滤数据。数据过滤的另一种方式是按行过滤。在这种情况下,我们想要删除或保留表中的某些数据行。例如,在处理Demographics.csv文件中的数据时,我们可能只想保留数据集中的男性,或者删除所有CustomerKey 为 11177的记录。对于这种类型的过滤操作,有许多不同的节点:行过滤器、行过滤器(实验室版)、基于规则的行过滤器、参考行过滤器、基于日期和时间的行过滤器等:
-
行过滤器节点非常简单且非常强大:右侧是过滤条件,左侧是过滤模式。
-
过滤条件将数据列中的单元格内容与条件进行匹配。要匹配的输入数据列在顶部选择。条件可以包括模式匹配(包括通配符和正则表达式)、范围检查(对于数值列非常有用)和缺失值匹配。
过滤模式在左侧设置,确定是否包括或排除匹配的行,可以通过属性值、行号或 RowID 进行匹配:

图 2.10 – 行过滤器节点及其配置窗口
在这里,我们使用CustomerKey属性过滤掉值为11177的数据。
-
使用
11177输入到 Table Creator 节点的 Reference Row Filter 节点的下端口,也可以获得类似的结果。 -
表格创建器节点是一个非常有趣的节点,适用于临时的小数据。它充当内部电子表格的角色,可以存储几行数据。
另一组非常重要的节点是执行聚合操作的节点。
聚合
聚合是任何数据准备中非常重要的一部分。无论是用于仪表板还是机器学习算法,某些聚合操作通常是必要的。常用的聚合节点有两个:GroupBy 节点和 Pivoting 节点。
在图 2.11中,你可以看到 GroupBy 节点配置窗口中的两个标签页:

分组和手动聚合
图 2.11 – GroupBy 节点配置窗口的两个标签页:分组和手动聚合
GroupBy 节点将数据分组,并在这些组上计算一些度量,如简单计数、平均值、方差、百分比等。分组的识别发生在配置窗口中的 Groups 标签页,度量设置则发生在其他标签页中(图 2.11)。
在 Groups 标签页中,选择那些其值组合定义不同数据组的数据列。节点然后为每个组创建一行。例如,选择 Gender 列,且其不同值为 male 和 female,意味着识别出 Gender 为 male 或 female 的数据组。选择 Gender(male/female)和 MaritalStatus(single/married)列作为分组列,意味着识别出 single-female、single-male、married-female 和 married-male 数据组。
然后,我们需要选择为这些组提供的度量。我们可以通过以下方式进行:
-
手动选择列并逐一应用度量(手动聚合)
-
基于模式选择列,包括通配符或正则表达式,并为每组列应用的度量(基于模式的聚合)
-
按类型选择列并为每组列应用的度量(基于类型的聚合)
每种度量设置模式在配置窗口中都有自己的标签页(图 2.11)。在 CustomerKey 列和 Age 列中,选择 Gender 作为分组列后,我们得到输入表中女性和男性的数量以及平均年龄。
重要提示
GroupBy 节点提供了大量的度量方式。我们已经看到了 Count 和 Mean。然而,我们还可以使用百分比、中位数、方差、缺失值数量、总和、众数、最小值、最大值、首值、尾值、峰度、(不同)值的拼接、相关性等。值得花时间研究一下 GroupBy 节点中所有可用的度量方法。
类似于 Gender(MaritalStatus(CustomerKey 数据列)。最终结果是一个表格,其中 male/female 为行 ID,married/single 为列标题,每个组合的出现次数为单元格内容。
这意味着分组列中的不同值生成行,而透视列中的不同值生成列。
Pivoting 节点的配置窗口有三个标签:Groups 用于选择分组列,Pivots 用于选择透视列,Manual Aggregation 用于手动选择数据列和计算度量。如果使用多个手动聚合,则结果透视表将为每个聚合方法和透视值的组合生成一列。
此外,节点会根据仅包含组列的第二个输出端口和仅包含透视列的第三个输出端口返回总聚合。
现在,让我们继续看几个非常灵活且强大的节点,用于执行数据转换。
数学公式和字符串操作节点
KNIME 分析平台提供了许多用于数据转换的节点。我们无法在此描述所有节点。因此,我们将把发现它们的乐趣留给您,在这里我们将描述两个非常强大的节点:字符串操作节点和数学公式节点。
字符串操作节点对数据单元格中的字符串值进行转换。转换函数在节点配置窗口中的功能面板中列出(见图 2.12)。在这里,您可以看到函数及其可能的语法。如果您选择列表中的某个函数,右侧名为描述的面板将显示该函数任务和语法的完整描述。然而,转换是在窗口底部的表达式编辑器中实现的。
首先,从""或输入数据表中其他列的值中选择(双击)一个转换。通过双击左侧列列表面板中的列名称,列中的值会自动插入,且语法正确。
让我们以一个例子为例:
-
在由
M和F生成的数据表中,分别为男性(M)和女性(F)创建了一个表格,包含每组的出现次数和平均年龄(M/F)。让我们将"M"更改为"Male",将"F"更改为"Female"。 -
然后,我们将使用
replace(str, search, replace)函数,其中str表示要操作的列,search表示要在单元格值中搜索的字符串,replace表示要用作替换的字符串。双击性别列中的列列表面板,并手动完成表达式,最终得到以下表达式:replace($Gender$, "M", "Male") -
在随后的节点中,我们得到了以下结果:
replace($Gender$, "F", "Female")字符串操作节点及其配置窗口如下所示(见图 2.12):
![图 2.12 – 字符串操作节点及其配置窗口]()
replace(upperCase($Gender$), "M", "Male")我们会得到类似的表达式来替换
"F"和"Female"。 -
最后,我们通过在配置窗口的下方使用替换列选项,将原始值替换为新值,以更新
性别列。
也可以通过字符串操作(多列)节点将相同的转换应用于多个输入数据列。该节点的功能与字符串操作节点相同,只不过它将设置的表达式应用于所有选定的数据列。其配置窗口的下半部分与字符串操作节点相同,而上半部分则允许您选择应用表达式的所有列。
重要说明
在$$CURRENTCOLUMN$$常规列名称的表达式编辑器中,函数列表中大量的字符串转换使得此节点极为强大。
一个与字符串操作节点非常相似的节点,尽管它处理的是不同的任务,那就是数学公式节点。数学公式节点对输入数据执行数学表达式。此外,它的工作方式与字符串操作节点完全相同。在配置窗口中,可用的数学函数列出了中央函数面板。如果从列表中选择了某个函数,描述将在描述面板中显示。最终的表达式是在底部的表达式编辑器中编写的。可以通过双击左侧列列表面板中的列名,将列名插入到表达式编辑器中。可以嵌套使用数学函数。
数学公式(多列)节点扩展了数学公式节点,使其能够将相同的公式应用于多个选定的列。
图 2.13 显示了包含本章所描述的所有操作的最终工作流,且该工作流也可以在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%202/:

图 2.13 – 概述了在 KNIME Analytics Platform 中可用的一些数据访问、数据转换和数据转换节点
到目前为止,我们看到的是数据上的静态转换。那么,如何在不同的条件下使用不同的转换呢?以行过滤器节点为例。今天,我可能想要从数据表中过滤掉女性记录,而明天则是男性记录。我如何做到这一点,而不必在每次运行时都更改所有相关节点的配置设置呢?现在是时候向你介绍流变量了。
工作流参数化
让我们考虑一个简单的工作流:读取Demographics.csv文件,筛选出所有Gender = M 或 F的数据行,并将M或F分别替换为Male或Female。一旦我们决定是处理M还是F,工作流就变得相当简单,并且包括一个replace()函数:
-
让我们添加一个节点,允许我们选择是处理
M还是F记录:字符串配置节点。此节点生成一个流变量。流变量是一个随着数据流在工作流分支中传递的参数,它可以用来覆盖其他节点中的设置。 -
就我们而言,目前在此节点的配置窗口中,有两个设置非常重要:默认值和变量名称。暂时使用默认值
M来处理Gender = M记录,并将流变量命名为gender_variable。 -
执行节点会创建一个名为
gender_variable的流变量,其值为M:![图 2.14 – 该工作流展示了如何使用流变量]()
图 2.14 – 该工作流展示了如何使用流变量
-
现在,让我们通过V按钮使用
gender_variable的值。你注意到字符串配置节点和行过滤器节点之间的红色连接了吗?这是一条流变量连接。流变量通过这些连接注入到节点和分支中。
重要说明
所有节点都有隐藏的红色圆形端口,用于流变量的输入和输出。点击节点的流变量端口并将其释放到另一个节点上,会显示出隐藏的流变量端口并连接这些节点。或者,在每个节点的上下文菜单中,显示流变量端口选项可以使它们可见。
-
之后,我们创建一个包含两行的小表格,[
M, 男性] 和 [F, 女性]。我们选择与gender_variable流变量中的值对应的行,并旨在将M或F字符替换为文本。对于这最后一部分,我们需要将M或F字符中的硬编码字符串替换为流变量。 -
现在,我们将
Male/Female文本转换为一个新的流变量。我们通过gender_variable来实现,这个变量是由Row0生成的,取决于在$Gender$中选择了[M, Male]或[F, Female],以及流变量($$Sgender_variable$$)。此外,流变量可以自动插入并使用正确的语法,在表达式编辑器中,通过双击流变量列表面板中流变量名称(位于字符串操作节点配置窗口的左侧)来完成(图 2.12)。
使用流变量的好处显而易见。当我们决定使用F而不是M时,只需在字符串配置节点中更改设置,而不需要在每个单独的节点中检查并更改设置。
我们展示的仅是处理流变量的节点中的一小部分。你可以在工作流控制/变量类别中进一步探索这些节点,位于节点库面板中。
摘要
本书没有足够的篇幅来描述 KNIME Analytics Platform 中更多的节点。我们将这项探索性任务留给你自己。
KNIME Analytics Platform 包括超过 2,000 个节点,并涵盖各种各样的功能。然而,大多数情况下工作的通用节点数量要少得多,例如,例如,文件读取器,行过滤器,GroupBy,Join,串联,数学公式,字符串操作,规则引擎等等。我们在本章中描述了大部分节点,为您构建更复杂的深度学习工作流程提供了坚实的基础,我们将在下一章中进行深入讨论。
问题和练习
通过回答以下问题来检查您对本章节中提出的概念的理解水平:
-
如何读取变长文本文件的行?
a) 通过使用 CSV 读取节点
b) 通过使用文件读取节点
c) 通过使用文件读取节点和启用短行选项
d) 通过使用文件读取节点和启用的限制行选项
-
如何筛选记录以
Age > 42列?a) 通过使用列过滤节点并选择
Age列b) 通过使用行过滤节点和模式匹配
=42,在右侧使用 包括 选项c) 通过使用行过滤节点和范围检查,下限为 42,在右侧使用 包括 选项
d) 通过使用行过滤节点和范围检查,下限为 42,在右侧使用 排除 选项
-
如何找到单身女性的平均情感评分?
a) 通过使用 GroupBy 节点,以
Gender和MaritalStatus作为组列,并在SentimentRating列上执行均值操作b) 通过使用 GroupBy 节点,以
Gender作为组列,并在CustomerKey列上执行计数操作c) 通过使用 GroupBy 节点,以
CustomerKey作为组列,并在SentimentAnalysis列上执行连接操作d) 通过使用 GroupBy 节点,以
MaritalStatus作为组列,并在SentimentRating列上执行百分比操作 -
为什么我们需要流变量?
a) 生成新值
b) 为了提供必要的红色连接
c) 用于在配置窗口中填充流变量列表
d) 为了参数化工作流程
第三章:第三章: 神经网络入门
在深入使用 KNIME 分析平台和其与 Keras 库的集成进行深度学习网络的实际实现之前,我们将简要介绍一些神经网络和深度学习背后的理论概念。这是本书中唯一纯粹的理论性章节,它对于理解随后的实际实现的原理和原因至关重要。
在本章中,我们将覆盖以下主题:
-
神经网络与深度学习——基本概念
-
设计你的网络
-
训练神经网络
我们将从神经网络和深度学习的基本概念开始:从第一个人工神经元作为生物神经元的模拟,到使用反向传播算法训练一个全连接的前馈神经网络。
接下来,我们将讨论神经架构的设计以及最终神经网络的训练。实际上,在设计神经架构时,我们需要恰当地选择其拓扑结构、神经层和激活函数,并引入一些技术来避免过拟合。
最后,在进行训练之前,我们需要知道什么时候使用哪种损失函数,以及训练中需要设置的不同参数。这个内容将在本章的最后部分进行描述。
神经网络与深度学习——基本概念
当前你听到的几乎全是深度学习。深度学习源自传统的神经网络学科,属于机器学习领域。
神经网络领域经历了多个停滞与复兴的阶段。从 20 世纪 60 年代最初的感知机兴起,到感知机无法实现的局限性显现出来时的低谷;再到基于反向传播算法的多层前馈神经网络的重新兴起,以及训练递归网络所需的硬件能力在当时不可用时的又一低谷;直到今天,深度学习新范式、单元和架构的出现,运行在更强大的硬件上,可能还配备了 GPU。
让我们从头开始,在这一部分中,逐步了解神经网络和深度学习的基本概念。尽管这些基本概念对你来说可能并不陌生,特别是如果你已经参加过神经网络或深度学习课程,但我们仍希望在这里描述它们,作为接下来章节中关于 KNIME 深度学习功能描述的参考,并且为那些刚接触这个领域的新手提供帮助。
人工神经元与人工神经网络
人工神经网络(ANNs)始于模拟生物神经元,如 图 3.1 中左侧所示(Abbott, L.F. (1999) Lapique's introduction of the integrate-and-fire model neuron (1907): https://web.archive.org/web/20070613230629/http:/neurotheory.columbia.edu/~larry/AbbottBrResBul99.pdf. Brain Research Bulletin. 50 (5/6): 303–304)。生物神经元是由细胞体(胞体)、几个输入树突和一个或多个轴突末端组成的神经细胞。激活时,它会产生一个尖锐的电位波动。树突通过化学突触接受电信号输入,通常来自其他神经元。突触中发生的化学反应增强或减少(即加权)输入的电信号,然后传递到神经元体。如果细胞体内的总电信号足够强,神经元会沿其轴突产生一个电位波动。然后轴突末端再次通过突触中的化学反应将波动传递给其他神经元。

图 3.1 – 左侧是生物神经元,具有树突上的输入 xj 和轴突端的输出 y(图片来源:维基百科)。右侧是人工神经元(感知器),其输入 xj 与权重 wj 相连,产生输出 y。
最简单的模拟试图仅使用两个输入和一个输出重现生物神经元,如 图 3.1 中右侧所示。现在树突的输入信号称为
和
,通过两个权重
和
到达人工细胞的细胞体,模拟突触中的化学反应。如果达到细胞体的总输入信号超过给定的阈值
,模拟“足够强”的概念,将生成一个输出信号
。这种简单的人工神经元称为感知器。
这里有两个需要澄清的细节:总输入信号和阈值函数。有许多神经电输入输出电压模型(Hodgkin, A. L.; Huxley, A. F. (1952), 膜电流的定量描述及其在神经中的传导与兴奋中的应用,《生理学杂志》 117 (4):500–544)。表示总输入信号的最简单方法是使用所有输入信号的加权和,其中权重代表突触反应的作用。神经元细胞体的激发函数可以通过阶跃函数
来描述。因此,对于我们在 图 3.1 中的简化模拟,输出
的计算方式如下:

在这里,
是一个具有阈值
的阶跃函数:
,其中
。
如果推广到具有
输入信号的神经元,并且具有任何其他激活函数
,我们可以得到以下公式:

在这里,阈值
已被转化为一个与输入信号
相连的权重
,该信号始终处于开启状态——也就是说,始终设为 1。
然而,一个单独的人工神经元,就像一个单独的生物神经元一样,计算能力并不强大。它只能实现一些简单的功能,正如我们在下一个子节 理解隐藏层的需求 中看到的那样。正如生物界一样,神经元网络比单个神经元有更大的计算潜力。生物神经元网络,甚至是简单的大脑,能够学习并完成非常复杂的任务。同样,人工神经元网络也能够学习并完成非常复杂的任务。神经网络成功的关键在于其在形成复杂或简单的架构以及训练它们以执行复杂或简单任务方面的灵活性。
一个感知机网络的示例如图 3.2所示。这个网络有三层神经元:输入层接收输入信号
;第一隐含层有两个神经元,连接到输入层的输出;第二隐含层有三个神经元,连接到第一隐含层的输出;最后是输出层,只有一个神经元,由隐含层的输出供给,并产生网络的最终输出
。神经元通过一个圆圈表示,其中包含表示输入信号加权和的
符号和表示激活函数的
符号:

图 3.2 – 左侧是生物神经元网络(图片来自维基百科)。右侧是人工神经元网络(多层感知机)
请注意,在这种特定的架构中,所有连接从输入层移动到输出层:这是一个完全连接的前馈架构。当然,前馈神经网络可以有任意数量的隐含层,每个神经层也可以有任意数量的人工神经元。一个感知机的前馈网络叫做多层感知机(MLP)。
前馈神经网络中的信号传播
一个简单的完全连接的前馈神经网络可以描述为一个将输入值
转换为输出值
的函数,通过一系列中间值
:隐含层的输出。例如,对于图 3.3中的网络,我们有以下内容:


这里,
是输入值(和输入单元)的数量,
,
是具有输出值
的隐藏神经元的数量,
是最终的输出值(在此架构中唯一的一个),而
是神经元的激活函数。如果我们从输入到输出逐步编号神经层,我们将标记第 1 层为输入层,第 2 层为隐藏层,第 3 层为输出层。神经层的这种逐步编号也体现在权重和隐藏单元的表示法中。
是
神经单元在
(隐藏)层中的输出值,
是连接第
层中的神经单元与第
层中的神经单元之间的权重。
重要说明
请注意,在这种表示法中,
和
在
和
中不是指数。它们仅描述输出单元在
中的网络层,以及在
中的目标层。

图 3.3 – 具有一个隐藏层和一个输出单元的全连接前馈神经网络
有许多类型的激活函数
。我们在上一节中看到了阶跃函数,但它有一个主要缺陷:既不连续也不可导。近年来,已经引入了一些类似的激活函数,它们更容易处理,因为它们在任何地方都是连续的并且可导。常见的例子有sigmoid 函数和双曲正切,
。最近,引入了一种新的激活函数,称为修正线性单元(ReLU),它似乎在具有多个隐藏层的全连接前馈神经网络中表现更好。我们将在接下来的章节中详细描述这些激活函数。
重要说明
通常,同一层中的神经元使用相同的激活函数
,但不同层之间可以使用不同的激活函数。
网络的另一个参数是其拓扑结构或架构。我们已经看到一个完全连接的前馈网络,其中所有连接从输入流向输出,并且在这种约束下,所有单元都连接到下一层的所有单元。然而,当然这不是唯一可能的神经拓扑结构。层内的交叉连接
、从层
到层
的反向连接,以及单个神经元与自身的自连接也是可能的。
不同的连接方式和不同的架构会产生不同的数据处理函数。例如,自连接引入了时间成分,因为神经元
在时间
的当前输出将成为同一神经元
在时间
的额外输入;一个前馈神经网络,输入和输出数量相同,可以实现自编码器,并用于压缩或异常检测。我们将在本书后续内容中看到一些不同的神经架构及其可以实现的任务。目前,我们只是给你提供一个图 3.4中的神经网络拓扑的初步了解:

图 3.4 – 一些神经网络拓扑结构的例子
图 3.4中最左侧的第一个网络,其神经元完全连接,因此层的定义变得不必要。这是一个霍普菲尔德网络,通常用作关联记忆。
第二个网络是一个前馈自编码器:三层,输入单元和输出单元的数量相同,隐藏层有
个单元,通常
;这种网络架构已被用于异常检测或实现输入空间的降维。
最后,第三种网络呈现了带有自连接的单元。如前所述,自连接在网络实现的函数中引入了时间成分,因此通常用于时间序列分析。这个最后的网络属于递归神经网络。
让我们回到完全连接的前馈神经网络。既然我们已经看到了它们的结构,接下来我们试着理解它们为何以这种方式构建。
理解隐藏层的需求
现在的问题是:我们真的需要如此复杂的神经架构吗?图 3.1中的感知机能做什么,不能做什么?感知机使用阶跃函数作为激活函数,将一条线(输入信号的线性组合)作为二维空间中的判别面,其中该线的参数是感知机的权重和阈值。
经典的例子是OR和AND问题,这些问题可以通过一条直线将“1”输出与“0”输出分开来解决。因此,感知器可以实现这两个问题的解决方案。然而,它无法解决XOR问题。当两个输入不同(一个是“0”,一个是“1”)时,XOR 函数输出“1”;当两个输入相同(都为“0”或都为“1”)时,输出“0”。事实上,XOR 操作符是一个非线性可分的问题,一条直线不足以将“1”输出与“0”输出分开(图 3.5):

图 3.5 – 感知器实现了一个线性判别面,这在二维空间中是一条直线。所有线性可分的问题都可以通过单个感知器解决。而感知器无法解决非线性可分的问题
解决 XOR 问题的唯一可能方法是将一个具有两个单元的隐藏层添加到感知器架构中,从而使其成为 MLP(图 3.6)。绿色和红色的两个隐藏单元分别实现一条直线,用于分隔一些“0”和“1”。然后,输出层中的一个单元在之前两条直线的基础上构建一条新线,并实现最终的判别:

图 3.6 – 增加一个具有两个单元的隐藏层,使得 MLP 能够解决 XOR 问题
图 3.7中的示例显示了一个三层网络:一个接收输入值的输入层
和
,一个包含两个单元的隐藏层,以及只有一个单元的输出层。这两个隐藏单元实现了两条判别线:
对应红色单元,
对应橙色单元。输出线则在这两条线之上实现了一个判别线,即
,在图 3.7中显示的平面上由绿色区域标识:

图 3.7 – 左侧的网络仅在输入空间中的绿色区域的点处激活,如右侧所示
如你所见,单独添加一个隐藏层就可以使神经网络在实现可能的函数方面变得更强大。然而,还有更多内容。通用逼近定理指出,一个简单的前馈网络,拥有单一的隐藏层并且具有足够数量的神经元,能够逼近在紧凑子集上定义的任何连续函数!,前提是激活函数满足适当的假设,并且假设网络已经得到了足够的训练(Hornik K.、Stinchcombe M.、White H.(1989 年)《多层前馈网络》神经网络是通用逼近器:http://www.sciencedirect.com/science/article/pii/0893608089900208 《神经网络》,第 2 卷,第 5 期,(1989) 第 359-366 页)。这个定理证明了神经网络具有某种普适性特性。也就是说,任何函数都可以被一个足够大且训练充分的神经网络所逼近。所谓足够大,指的是前馈网络中神经元的数量。此外,引用的论文还提到网络架构只需一个隐藏层,并且神经元足够多。
因此,即使是非常简单的网络架构,也可以非常强大!当然,前提是隐藏层足够大(否则可能需要过长的训练时间),并且训练时间足够长。
一个带有单层的前馈网络足以表示任何函数,但该层可能过于庞大,且可能无法正确学习和泛化(Goodfellow I.、Bengio Y.、Courville A.(2016 年)《深度学习》,MIT 出版社)。
我们已经看到,引入一个或多个隐藏层到前馈神经网络中,使其变得极其强大。接下来我们来看看如何训练它。
训练多层感知器
神经网络包括几个自由参数:拓扑结构、权重和激活函数的参数。假设我们有一个完全连接的前馈网络,并且所有神经元都有一个预定义的激活函数,比如 sigmoid 函数。那么,唯一剩下的自由参数就是权重。
训练神经网络意味着反复展示训练集中的样本,并且每次都调整参数值(权重),以拟合基于期望输入输出行为计算的损失函数。为了找到最适合损失函数的权重,使用了梯度下降算法或随机梯度下降(SGD)的变体。其思路是通过沿着误差面最陡下降的方向更新权重。最陡下降的方向等同于梯度的负值。为了高效地计算梯度,采用了反向传播算法。让我们来看一下它是如何工作的。
反向传播背后的数学
回归问题的经典损失函数是总平方误差,定义如下:

这里,
和
分别是输出单元
的目标值和实际答案,求和在输出层的所有单元和训练集中的所有示例上进行
。
如果我们采用梯度下降策略以达到损失函数表面的最小值,在每次训练迭代中,网络中的每个权重必须在权重空间中按
的偏导数的相反方向增加(Goodfellow I.,Bengio Y.,Courville A.(2016). 深度学习,MIT 出版社):

这个关于权重的误差偏导数是使用链式法则计算的:

这里,
是损失函数,
是神经元 j 的输出,
是它的总输入,
是来自前一层神经元
的输入权重:
对于连接到输出层单元的权重,偏导数将如下所示:



所以,最后:

因此,连接到输出单元的权重变化如下:

这里,
,
是输入
到输出节点
,而
是学习率。
对于连接到隐藏层单元的权重,偏导数的计算,因此权重的变化,更加复杂。虽然最后两个偏导数在提到隐藏层的神经元时保持不变,但
需要重新计算。
如果我们将损失函数
视为所有输入总和的函数,连接到神经元 j 的下一层所有神经元的输入总和为
,经过一些数学操作后,我们得到了递归表达式:

这里,以下内容适用:

所有权重的更新公式,指向输出或隐藏神经元,如下所示:

这个递归公式告诉我们,
对于隐藏层中的单位
可以通过层
中所有的
的线性组合来计算,如果这是输出层,则为
,如果这是另一个隐藏层,则为
。这意味着从输出层向输入层反向传播,我们可以计算所有的
,从
开始,然后通过所有的
,作为来自前一层的
的组合,层层相连。结合
,我们还可以计算所有的权重更新
。
反向传播背后的理念
因此,前馈神经网络的训练可以视为一个两步过程:
-
所有训练向量依次呈现给网络的输入层,信号在所有网络连接(和权重)中传播,直到输出层。所有训练样本通过网络后,计算输出层的总平方误差,作为单个平方误差的总和。这就是前向传播:
![图 3.8 – 在反向传播算法的前向传播中,所有训练样本依次呈现到输入层,并通过网络正向传播直到输出层,以计算输出值]()
图 3.8 – 在反向传播算法的前向传播中,所有训练样本依次呈现到输入层,并通过网络正向传播直到输出层,以计算输出值
-
所有
在输出层的所有单位中计算。然后,
从输出层反向传播通过所有网络连接(和权重)直到输入层,所有隐藏层中的
也被计算。这就是后向传播:

图 3.9 – 在反向传播算法的后向传播中,所有
在输出层计算,并反向传播通过网络直到输入层。所有训练集的样本来回通过网络后,所有权重都会被更新
该算法被称为反向传播,因为在第二次传递过程中,误差信号沿着网络反向传播。
所有训练数据通过网络前后传递后,所有权重都会被更新。
同时注意单元激活函数的第一导数
在
中。显然,使用一个连续可导函数
有助于计算。这就是为什么
和
函数在神经网络架构中如此受欢迎的原因。
梯度下降算法无法保证到达误差函数的全局最小值,但通常会停留在局部最小值。如果局部最小值不能确保网络的满意性能,那么必须从新的初始条件开始重新训练,即网络权重的新的初始值。
神经网络在实现输入输出模型方面非常强大,并且在架构和参数方面非常灵活。通过不断增加更多的神经元和更多的隐藏层,构建庞大的神经网络变得极其容易。除了更长的训练时间外,另一个额外的风险是会迅速陷入过拟合训练数据的困境。过拟合是模型过于复杂的缺点,通常是自由参数过多,无法适应一个简单的任务。对于简单任务的过度维度化模型,结果是模型在某些时候会开始利用额外的参数来记忆训练集中的噪声和错误,从而显著降低模型的表现。神经网络的强大和灵活性使它们容易过拟合,特别是当我们处理的是小型训练集时。
重要提示
自神经网络引入以来,另一个主要的反对意见是它们的不可解释性。权重的调整与数据领域中的任何实体没有对应关系。在处理神经网络时,我们需要接受一个事实,那就是我们正在处理黑箱,我们可能无法理解其决策过程。
如果可解释性是我们项目的需求,那么神经网络可能不是我们应选择的工具。最近提出了一些技术,用于从黑箱模型中提取决策过程的知识,例如SHAPLEY值或部分依赖图(Molnar C. 可解释的机器学习,https://christophm.github.io/interpretable-ml-book/index.html,GitHub)。它们目前处于初期阶段,尚未免于批评。然而,它们是解决神经网络可解释性问题的一个有趣尝试。这些内容超出了本书的范围,因此我们不会深入探讨。
基本理论已经介绍完,接下来让我们进入网络设计的部分。
设计你的网络
在上一节中,我们学习到神经网络的特点包括拓扑结构、权重和激活函数。特别是,前馈神经网络有输入层和输出层,中间还包含若干个隐藏层。尽管网络权重的值是通过训练过程自动估算的,但网络的拓扑结构和激活函数必须在训练前的网络设计阶段预先确定。不同的网络架构和不同的激活函数实现了不同的输入输出任务。为特定任务设计合适的神经网络架构仍然是深度学习领域的一个活跃研究领域(Goodfellow I.、Bengio Y.、Courville A.(2016)。深度学习,麻省理工学院出版社)。
训练算法中还涉及其他参数,如学习率或损失函数。我们也看到,神经网络容易出现过拟合问题;这意味着其灵活性使得它们很容易遭遇过拟合问题。是否有可能在训练过程中通过控制权重增长、更改损失函数或自我限制网络结构来避免过拟合问题呢?
本节为您概述了所有剩余的参数:网络的拓扑结构、训练算法中的参数、可能的激活函数、损失函数、正则化项等,始终关注控制过拟合效应,使训练算法更加高效,并开发更强大的神经网络架构。
常用激活函数
总结来说,单个神经层有多个输入
和多个输出
。神经元输出值的计算
需要经过两步:
-
计算输入的加权和加上偏置
:
对于
和 ![]()
-
应用激活函数
或
来计算输出
,根据权重矩阵
,并且可能是
或
:

请注意,
是输入值到
号神经元的加权和,而
是所有加权输入和的向量。
网络也可以看作是一系列函数
,每个函数实现一个神经层。根据网络架构,每个神经层有不同的输入值,并使用不同的激活函数
,因此实现一个不同的函数
,并且使用前面描述的两个计算步骤。
完整网络实现的总函数的复杂度还取决于涉及的层数;也就是说,它取决于网络的深度。
所有神经元都与上一层的所有输出连接的层称为全连接层。全连接前馈网络仅仅是一系列的全连接层,每一层都有其自己的激活函数。在前馈神经网络中,函数
取决于层中神经元的数量、输入的数量以及激活函数。层之间的关键区别就是激活函数。让我们来看一下神经网络中最常用的激活函数。
Sigmoid 函数
Sigmoid 函数是一个 S 形函数,其值介于
和
之间。对于层中的第
个神经元,该函数定义如下:

它在图 3.10中左侧绘制。
对于二分类问题,这个函数是输出神经层的首选函数,因为其值范围
使我们能够将输出解释为两个类别之一的概率。在这种情况下,输出神经层仅包含一个神经元,即单元大小为 1,并且使用 Sigmoid 激活函数。当然,相同的函数也可以作为具有更大单元大小的输出层和隐藏层的激活函数。

图 3.10 – Sigmoid 函数(左侧)可以作为解决二分类问题的网络单输出神经元的激活函数(中间)。它也可以作为网络中隐藏层或输出层中神经元的激活函数(右侧)
Sigmoid 函数的最大优点之一是它在任何地方都可导,并且具有简单的导数表达式。事实上,当使用 sigmoid 激活函数时,反向传播算法的权重更新规则变得非常简单,因为激活函数的导数只是
,其中
是神经元 j 的输出。
另一方面,在更复杂或深度的神经网络架构中,使用 sigmoid 作为神经元激活函数的最大缺点之一是梯度消失问题。事实上,在计算导数以更新网络权重时,sigmoid 函数输出值(< 1)的链式乘法可能会产生非常小的值。在这种情况下,每次训练迭代时会产生过小的梯度,导致训练算法收敛缓慢。
双曲正切(Tanh)
一种类似的激活函数是双曲正切,简称tanh。它也是一个 S 型函数,不同之处在于输出值介于
和 1 之间,而不是介于
和
之间。对于
号神经元,该函数定义如下:

它在图 3.11中显示在左侧:

图 3.11 – 双曲正切函数 tanh()也常用作神经单元的激活函数。在这种情况下,神经元的输出值位于(-1, +1)之间
在这里,
函数的最大优点之一是其连续性和在任何地方都可导,这使得训练算法中权重更新的公式更为简单。
还具有以 0 为中心的优势,这有助于稳定训练过程。
再次强调,使用 tanh 作为复杂或深度神经网络架构中的激活函数的最大缺点之一是梯度消失问题。
线性函数
一种特殊的激活函数是线性激活函数,也称为恒等函数:

这种函数通常在什么情况下使用?具有线性激活函数的神经层实现了线性回归模型。有时,线性激活函数的神经层也会被引入,以保持原始网络的响应,然后再经过变换以获得所需的范围或概率得分。在这种情况下,网络的最后一层被分为两层:一层使用线性激活函数保留原始输出,另一层则应用另一种激活函数以获得所需的输出格式。
在第七章中,实现 NLP 应用,我们描述了生成产品名称的案例研究,在该方法中,在线性激活函数层之后引入了一个新参数,称为温度。
修正线性单元
我们已经看到,使用 sigmoid 或 tanh 激活函数的深度神经网络通常会遭遇梯度消失问题。
一种有助于克服梯度消失问题的激活函数是修正线性单元函数,简称ReLU。ReLU 函数从 0 起像线性函数一样工作。实际上,ReLU 函数对于负值的
是
,而对于正值的
,它是恒等函数:
。
图 3.12 显示了 ReLU 函数的图形:

图 3.12 – ReLU 激活函数
ReLU 激活函数虽然能帮助解决梯度消失问题,但对于
是不可微分的。实际上,在训练神经网络时,这通常不是问题,因为通常使用的是单边导数,而不是报告导数未定义。
Softmax 函数
到目前为止介绍的所有激活函数都是具有单一输出值的函数。这意味着仅使用加权和
来计算第
个神经元的输出值,而与加权和
无关,后者用于计算同一层中其他神经元的输出值。而softmax 函数则作用于整个输出向量
,而不仅仅是单一的值
。
一般来说,softmax 函数将大小为
的向量
转换为大小为
的向量
,该向量的值介于
和
之间,并且所有值
的和为
:

这个额外的约束使我们能够将向量
的各个分量解释为不同类别的概率。因此,softmax 激活函数通常是多类分类问题中最后一个神经层的函数选择。输出向量的
位置的元素通过以下方式计算:

图 3.13 显示了一个使用 softmax 函数作为最后一层的示例网络,其中所有输出值的总和为 1:

图 3.13 – 一个简单的神经层,使用 softmax 激活函数
重要提示
softmax 函数也被逻辑回归算法用于多类分类问题。
其他支持的激活函数
自 sigmoid 函数以来,很多其他激活函数相继被提出。
ReLU 的变体包括 泄露修正线性单元 和 参数化修正线性单元 (PReLU) 。LeakyReLU 对函数的负值部分提供了一个接近零的线条 (
),而纯 ReLU 则仅为零。PReLU 用参数化的斜率 (
) 代替 LeakyReLU 中固定的斜率来处理该线。参数
成为网络必须训练的参数之一。
这里是 LeakyReLU 和 PreLU 的定义:
-
LeakyReLU:
![]()
-
PReLU:
![]()
其他 ReLU 的变体,包括为了修复死 ReLU 引入的 指数线性单元 (ELU) 和 缩放指数线性单元 (SELU)。类似于 LeakyReLU,ELU 对负值有一个小斜率。它使用对数曲线而不是直线。缩放 ELU 向 ELU 添加了一个额外的参数
,以供网络训练:
-
ELU:
![]()
-
SELU:
![]()
sigmoid 激活函数的一个近似是 硬 sigmoid 激活函数。它的计算速度比 sigmoid 快。尽管它是 sigmoid 激活函数的近似,但在分类任务中仍然能够提供合理的结果。然而,由于它只是近似,因此在回归任务中的表现较差:
- Hard-Sigmoid:
![]()
SoftPlus 激活函数也相当流行。它是 ReLU 激活函数的平滑版本:
- SoftPlus:
![]()
让我们看一下图 3.14:

图 3.14 – 一些额外流行的激活函数的图示,主要是 ReLU 和 sigmoid 函数的变体
图 3.14 中的图片显示了上述激活函数的图示。
避免过拟合的正则化技术
无论使用什么算法,目标始终是构建一个不仅在训练数据上表现良好,而且能够对新数据进行良好泛化的模型。
大型神经网络在使用过小的数据集进行训练时,常常会出现过度拟合训练数据的问题,无法对新数据进行有效的泛化。这个问题被称为过拟合。图 3.15 显示了神经网络在训练数据(满点)和测试数据(空心点)上的回归输入输出函数。在左侧,我们看到一个回归函数,甚至无法正确拟合训练数据,更不用说拟合测试数据了。这可能是由于架构规模不足或训练时间太短(欠拟合)。在中间,我们看到一个合理拟合训练数据和测试数据的回归曲线。在右侧,回归曲线完美拟合训练数据,但在拟合测试数据时失败;这就是过拟合问题:

图 3.15 – 从左到右,网络在欠拟合、拟合适当和过拟合训练数据时的回归曲线
我们如何事先知道神经网络架构的合适大小以及训练算法的合适训练轮数呢?有一些技巧可以用来解决过拟合问题,而无需过于担心网络的精确大小和训练轮数:范数正则化、丢弃法(dropout)和早停法(early stopping)。
范数正则化
过拟合的一个迹象是权重的值过高。因此,范数正则化的基本思想是通过在目标函数中添加惩罚项
来惩罚权重较大的值,即损失函数:

这里,
是真实值,
是预测值。通过添加这个惩罚项,得到一个新的损失函数
:

因此,训练算法在最小化这个新的损失函数时,会得到一个具有较小权重值的权重配置。这是一种广为人知的正则化方法,你可能已经在线性或逻辑回归算法中见过。
参数
用于控制惩罚效应。
等同于没有正则化。较高的
值实现了更强的正则化效果,并导致较小的权重值。
有两种常用的惩罚范数函数:L1 范数 和 L2 范数。L1 范数是权重绝对值的总和,而 L2 范数是权重平方的总和:

和
都是避免过拟合的常见方法,且有一个显著的区别。
正则化通常会导致较小的权重,但无法将权重减少到零。而另一方面,
正则化允许有一些较大的权重,同时将其他所有权重减小到零。在设计损失函数时,也可以同时使用
和
正则化。
此外,你还可以将正则化项应用于选定层的权重。已经设计了三种不同的范数正则化来作用于单一层:核正则化、偏置正则化和活动正则化。
核正则化惩罚权重,而不惩罚偏置;偏置正则化仅惩罚偏置;活动正则化导致选定层的输出值更小。
Dropout
另一种常见的机器学习方法来避免过拟合是引入 Dropout 技术,这也是一种正则化技术。
这个思想是,在每次训练迭代中,随机忽略(丢弃)输入层或隐含层中的一些神经元,连同其所有的输入和输出连接。在每次迭代中,丢弃的神经元不同。因此,架构中的神经元数量以及哪些神经元被训练,实际上会随着迭代而变化。通过这种方式引入的随机化有助于控制过拟合效应。
Dropout 确保每个神经元和每一层不依赖于前一层的单个神经元,从而变得更加健壮,减少过拟合的可能性:

图 3.16 – Dropout 技术在每一层选择一些神经元,并在当前训练迭代中将其从更新中排除。左侧的完整网络只在右侧描述的四个训练迭代中部分训练。
Dropout 是分别应用于网络的每一层的。这通常意味着会在我们希望进行随机化的层后插入一个临时层,即 Dropout 层。Dropout 层控制在每次训练迭代中前一层的多少神经元被丢弃。
为了控制每一层中丢弃多少神经元,引入了一个新的参数:丢弃率。丢弃率定义了每次迭代中应该丢弃的神经元在该层中的比例。
提示
这里有两个关于 Dropout 的小贴士:
首先,丢弃层会导致每层神经元减少,从而降低层的容量。建议从每层神经元数较多的设置开始。
其次,丢弃层只应用于输入层或隐藏层,而不是输出层,因为我们希望模型的响应在每次迭代中始终相同。
早停法
另一种避免过拟合的选项是在网络开始过拟合之前停止训练过程,这被称为早停法。为了检测算法开始比测试数据更好地拟合训练数据的时刻,会使用额外的验证集来提供新的数据。在训练过程中,会监控网络在训练集和验证集上的表现。在训练阶段开始时,网络在训练集和验证集上的表现都会有所提升。然而,在某个时刻,网络在训练集上的表现持续改善,而在验证集上的表现开始恶化。一旦验证集上的表现开始变差,训练便会停止。
其他常用的层
到目前为止,我们已经介绍了两种不同类型的层:用于设计具有不同激活函数的全连接神经网络的密集层和用于正则化的丢弃层。通过这些层,你可以设计一个自动编码器,正如我们在第五章中所做的,用于欺诈检测的自动编码器。但实际上,还有许多其他层可以用于各种不同的任务。
卷积层
神经网络在图像分析领域非常强大,例如图像分类。前馈神经网络在这个领域也经常使用。然而,通常,密集层的顺序并不是单独使用的,而是与另一系列卷积层结合使用。卷积层被放置在神经网络的输入后,用于提取特征,并创建一个更好的图像表示,然后将其传递到下一个密集层——前馈架构——进行分类。这些网络被称为卷积神经网络,简称CNN。
第九章,用于图像分类的卷积神经网络,详细解释了卷积层的工作原理。它还将介绍一些其他相关的神经网络层,适用于分析具有空间关系的数据,如展平层和最大池化层。
循环神经网络
一类不属于前馈神经网络的神经网络是递归神经网络,简称RNN。通过在前馈神经网络中引入自连接或反向连接(递归连接),可以得到 RNN。这使得网络能够考虑上下文,因为它记住过去的输入,从而可以捕捉信号的动态。这些网络在处理序列数据时非常强大,例如时间序列数据或文本。
过去已经介绍了不同的 RNN 层,例如长短期记忆(LSTM)层或门控循环单元(GRU)层。 第六章,需求预测的递归神经网络详细讲解了 RNN 及 LSTM 单元的架构。
训练神经网络
在网络架构和激活函数设计之后,训练神经网络前的最后一步设计是选择损失函数。
我们将首先概览回归、二分类和多分类问题的可能损失函数。然后,我们将介绍一些优化器和训练算法的额外参数。
损失函数
为了训练前馈神经网络,必须选择合适的误差函数(通常称为损失函数)和匹配的最后一层。让我们先来概览一下常用于回归问题的损失函数。
回归问题的损失函数
在回归问题中,目标是预测一个单一的数值输出,输出层应该只有一个单元,并使用线性激活函数。训练这种网络的可能损失函数必须参考数值误差度量:
- 均方误差(MSE)损失:均方误差是回归问题的默认误差度量。对于
训练样本,计算方法如下:

其中,
是真实值,
是预测值。MSE 对较大误差值赋予更多权重,并且总是为正值。一个完美的预测器将具有
值为
。
- 均方对数误差(MSLE)损失:MSLE 是一种损失函数,它对大误差的惩罚小于 MSE。它通过对预测值和真实值应用对数,然后使用 MSE 来计算。对于
训练样本,计算方法如下:

MSLE 适用于大于或等于
的数字,例如价格。为了避免出现
,1 会被加到
和
上。
如果目标值的范围较大,且较大的误差不应比较小的误差受到显著的惩罚,推荐使用此损失函数。MSLE 始终为正,完美的模型损失为
。
- 平均绝对误差 (MAE) 损失:MAE 损失函数对于离群点具有更强的鲁棒性。这意味着它对大误差的惩罚比之前的两个损失函数(MSE 和 MSLE)要小。对于
训练样本,它的计算公式如下:

总结来说,我们可以在三种回归问题的损失函数中选择:MSE、MSLE 和 MAE。接下来,我们将继续讨论二分类和多分类问题的损失函数。
二分类问题的损失函数
对于二分类问题,常见的方法是将两个类别分别编码为
和
,并训练一个网络来预测类别
的概率。在这种方法中,输出层只包含一个单元,并使用 sigmoid 激活函数。对于这种方法,推荐的默认损失函数是二元交叉熵。
在
样本的训练集上,二元交叉熵可以按如下方式计算:

这里,
是类别标签,真实值(
1)是训练集中第i个样本的真实值,
是网络对该类别预测的概率。由于这是一个二分类问题,损失函数的第二部分计算与另一类别相同的值。
是之前显示的损失函数中的预测值
。
对于二分类问题,其他可能的损失函数包括铰链损失和平方铰链损失。在这种情况下,两个类别必须分别编码为
和
,因此输出层中的单元必须使用 tanh 激活函数。
多分类问题的损失函数
在多分类问题中,通常每个类别通过一个整数值表示(类别 = 1, 2, 3, …),并使用独热编码(one-hot encoding)表示不同的类别。输出层应包含与类别数相等的神经单元,且每个单元都使用 softmax 激活函数,以便预测一个可以解释为每个类别概率的分数。
多分类问题的默认损失函数是类别交叉熵。在
样本的训练集上,类别交叉熵可以通过对二元交叉熵进行扩展来计算,扩展到 C 个类别:

这里,
是类别标签 k,真实值(
1)是训练集中的 i 样本的值,
是网络为类别 k 预测的相应概率。再者,
是输出神经元 k 为训练样本 i 预测的值
。
对于类别过多的多分类问题,例如语言建模,其中字典中的每个单词都是一个类别,稀疏类别交叉熵被使用。
另一个常用的损失函数是 Kullback-Leibler 散度。
除了前面介绍的常用损失函数,还可以定义自定义损失函数,以最好地适应当前的使用场景。
参数和训练算法的优化
现在我们的网络已经设计好,使用正确的输出层激活函数和合适的损失函数后,我们可以开始训练网络。现代训练算法通常基于 SGD 策略,利用反向传播来更新网络权重的值。在过去几年里,已经产生了不同变种的 SGD 算法(优化器),这些优化器经过优化,可以在具有不同属性的数据集上训练网络。例如,Adagrad 及其扩展 Adadelta 在稀疏数据上效果良好。Adam 涉及梯度及其平方梯度的移动平均,用于权重更新。Keras 文档页面概述了所有可用的训练算法:keras.io/optimizers/。
重要提示
反向传播通常是指计算权重梯度的算法。训练神经网络的算法通常是某种变种的 SGD,并且使用反向传播来更新网络权重。
训练算法中一个重要的角色是 学习率
。学习率定义了在学习阶段沿着误差面上的梯度下降方向所采取的步长。过小的
会产生微小的步伐,因此需要很长时间才能到达损失函数的最小值,特别是当损失函数的斜率较平坦时。过大的
会产生较大的步伐,可能会超过最小值,尤其是当损失函数较窄且斜率较陡时。选择正确的学习率值
是至关重要的。一种可能的解决方案是使用自适应学习率,初始较大,并随着训练迭代次数的增加逐渐减小。
在 图 3.17 中,展示了使用过小、过大和自适应学习率在损失函数上移动的示例:

图 3.17 – 使用过小的学习率
(左侧),过大的学习率
(中间),以及自适应学习率
在一维权重空间中的误差逐步减少
所有损失函数都定义为对所有训练样本求和。这导致了在所有训练样本通过网络后更新权重的算法。该训练策略称为批处理训练。这是正确的操作方式,但它计算开销大且通常较慢。
替代方法是使用在线训练策略,其中权重在每个训练样本通过后更新。该策略计算开销较小,但它只是原始反向传播算法的近似。它也容易出现振荡现象。在这种情况下,采用较小的学习率是良好的实践。
几乎所有现代深度学习框架都采用了批处理和在线训练的混合模式,在这种模式下,它们使用小批量的训练样本执行单次更新步骤。
动量项被添加到权重的增量中
,以增加权重更新,只要它们与前一个增量具有相同的符号。动量可以加速长时间平坦误差表面上的训练,并帮助网络通过局部最小值。此时,权重更新将包括一个额外的项:

这里,
是当前训练迭代,
是动量项。
其他训练参数
训练过程中的两个重要设置选项是训练批次大小和周期数。
-
训练批次大小:训练批次大小定义了每次训练迭代中使用的样本数量。如果训练批次大小设置为训练集中的所有样本数量,则训练将以所谓的批处理模式运行,这种模式计算开销大且慢。通常建议在小批量模式下训练模型,每次迭代只使用部分数据。建议在每个周期之前对数据进行洗牌,以便每个周期有不同的批次。
-
周期数:周期数定义了在完整训练数据集上运行的循环次数。
总结来说,算法会遍历整个训练集
次,其中
是轮次的数量。每个轮次包含多个迭代,每次迭代都会使用训练集的一个子集(即一个批次)。在每次迭代结束时,按照在线训练策略更新权重。
小结
我们已经结束了本章内容,在这一章中,我们学习了神经网络和深度学习网络背后的基本理论概念。所有这些都将有助于理解在接下来的章节中描述的深度学习网络的实际实现步骤。
我们从人工神经元开始,接着描述了如何通过梯度下降算法的变种来组装和训练一个完全连接的前馈神经网络,使用反向传播算法来计算梯度。
本章总结了设计和训练神经网络的一些提示。首先,我们描述了一些常用的网络拓扑结构、神经层和激活函数,用于设计合适的神经网络架构。
接下来我们分析了一些训练算法中涉及的参数的影响。我们介绍了更多的参数和技术,优化训练算法以适应选定的损失函数。
在下一章中,你将学习如何使用 KNIME Analytics 平台执行我们在本章介绍的所有步骤。
问题与练习
通过回答以下问题,测试你对本章概念的理解:
-
前馈神经网络是一种架构,其中:
a. 上一层的每个神经元都与下一层的每个神经元相连接。
b. 存在自连接和反向连接。
c. 输出层中只有一个单元。
d. 输入单元的数量与输出单元的数量相同。
-
为什么在前馈神经网络中需要隐藏层?
a. 提供更多的计算能力
b. 为了加速计算
c. 实现更复杂的函数
d. 为了对称性
-
反向传播算法根据以下内容按比例更新网络权重:
a. 输出误差反向传播通过网络
b. 输入值通过网络向前传播
c. 批量大小
d. 在输出层计算出的增量并反向传播通过网络
-
多类分类问题通常使用哪种损失函数?
a. 平均绝对误差(MAE)
b. 均方根误差(RMSE)
c. 类别交叉熵
d. 二元交叉熵
-
哪种类型的网络适合图像分析?
a. 循环神经网络(RNN)
b. 卷积神经网络(CNN)
c. 完全连接的前馈网络
d. 自编码器
-
在解决二分类问题时,网络的最后一层通常是如何配置的?
a. 带有 sigmoid 激活函数的两个单元
b. 一个带有线性激活函数的单元
c. 带有 ReLU 激活函数的两个单元
d. 带有 sigmoid 激活函数的单元
-
RNN(循环神经网络)什么时候使用?
a. 关于缺失值较多的数据
b. 关于图像数据
c. 关于序列数据
d. 关于稀疏数据集
第四章:第四章: 构建和训练前馈神经网络
在第三章,开始使用神经网络,您学习了神经网络和深度学习背后的基本理论。本章将这些知识付诸实践。我们将实现两个非常简单的分类示例:使用鸢尾花数据集的多类别分类,以及使用成人数据集(也称为人口普查收入数据集)的二元分类。
这两个数据集都相当小,相应的分类解决方案也相当简单。在这两个示例中,完全连接的前馈网络就足够了。然而,我们决定在这里展示它们作为玩具示例,描述使用 KNIME Analytics Platform 和 KNIME Keras Integration 构建、训练和应用全连接前馈分类网络的所有必需步骤。
这些步骤包括常用的预处理技术、神经网络架构的设计、激活函数的设置、网络的训练和应用,最后是结果的评估。
因此,本章涵盖以下主要主题:
-
准备数据
-
构建前馈神经网络架构
-
训练网络
-
测试和应用网络
准备数据
在第三章,开始使用神经网络,我们介绍了反向传播算法,它被梯度下降算法用于训练神经网络。这些算法处理数字,无法处理名义/分类输入特征或类值。因此,如果我们希望网络利用它们,名义输入特征或名义输出值必须被编码为数字值。在本节中,我们将展示几种数值编码技术及其在 KNIME Analytics Platform 中相应的节点来执行它们。
除此之外,我们还将通过许多经典的数据预处理步骤来为机器学习算法提供数据:从原始数据集创建训练、验证和测试集;归一化;以及缺失值插补。
在这个过程中,我们还将向您展示如何导入数据,如何执行一些额外的数据操作,以及 KNIME Analytics Platform 中一些常用的技巧。本章描述的工作流程可以在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%204/。
数据集和分类示例
在我们深入研究不同的预处理步骤之前,让我们快速查看两个选定的数据集和相关的分类示例:
-
基于鸢尾花数据集对三种鸢尾花进行分类
-
基于成人数据集对收入进行分类(二元类别)
我们的第一个数据集为我们提供了一个多类分类问题的示例。
鸢尾花数据集包含来自三种鸢尾植物(Iris-setosa、Iris-virginica 和 Iris-versicolor)的花朵示例。每朵花通过四个特征进行描述:花萼长度(cm)、花萼宽度(cm)、花瓣长度(cm)和花瓣宽度(cm)。这是一个小型数据集,每个品种有 50 个示例,总共有 150 个样本。图 4.1展示了数据集的概览。
目标是训练一个具有一个隐藏层(八个单元和 ReLU 激活函数)的神经网络,根据四个输入特征来区分三种花卉。
部分鸢尾花数据集显示在以下表格中:

图 4.1 – 鸢尾花数据集概述,本文用于实现多类分类
第二个示例数据集为我们提供了一个二分类问题。
成人数据集包含 32,561 个住在美国的人的样本。每条记录通过 14 个人口统计特征描述一个人,其中包括其当前的年收入(> 50K/<= 50K)。图 4.2展示了数据集中特征的概览:数值特征,如年龄和每周工作小时数,以及名义特征,如工作类别和婚姻状况。
目标是训练一个神经网络,预测一个人是否每年赚取超过 50K 美元,使用所有其他属性作为输入特征。我们希望使用的网络应该有两个隐藏层,每个层有八个单元,并采用 ReLU 激活函数。
一些显示在表格中的人口普查收入数据集如下所示:

图 4.2 – 成人数据集概述,本文用于实现二分类问题
提示
为了获得数据集的概览,你可以使用数据探索器节点。此节点以交互式视图显示输入数据的一些统计量。在图 4.1和图 4.2中,你可以看到两个示例数据集的节点视图。
总结鸢尾花数据集,它包含四个数值特征和一个鸢尾花的名义类别;成人数据集则包含 14 个混合特征,包括数值特征和名义特征。因此,数据准备的第一步是将所有名义特征转换为数值特征。接下来,我们将介绍编码技术。
名义特征的编码
名义特征,有时也称为类别特征,只能采用字符串类型的值。例如,描述发色的特征的唯一可能值可以是字符串类型,如black、brown、blond和red;描述性别的特征传统上只接受两种字符串类型的值,female和male;教育特征的可能值可以是字符串,如Doctorate、Masters、Bachelors或Some-college。这个例子来自成人数据集中名为education的列。这些值应在输入神经网络之前转换为数字。
有两种常见的方式来编码名义特征:
-
整数编码
-
独热编码
整数编码为特征的每个可能的名义值分配一个整数值。例如,"black"可以是 1,"brown"可以是 2,"blond"可以是 3,"red"可以是 4。我们选择了数字 1、2、3 和 4,但它也可以是任何其他数字组合。该方法在不同值之间引入了一种人工关系——例如,"black"比"red"更接近"brown"。这种关系可以反映有序或层次特征中的真实关系,例如教育领域,其中"Doctorate"比"Masters"更接近"Some-college"。然而,在其他情况下,例如之前提到的发色示例,它引入了一种不反映现实的新附加关系,并且可能在学习过程中对模型产生偏见。一般来说,在名义无序特征上使用整数编码方法可能会导致模型性能较差。
独热编码通过用向量表示每个特征来克服这个问题,在所有向量之间的距离始终相同。该向量由与原始特征中可能值相同数量的二进制组件组成。然后,将每个组件与其中一个值关联,并为该值设置为1;其他组件保持为0。在发色示例中,"black"变成
,"brown"变成
,"blond"变成
,"red"变成
。
重要说明
独热向量是一个只有一个1,所有其他值为0的向量。它可以用来编码不同的类别,而不会在它们之间添加任何人工距离。
现在让我们看看如何通过 KNIME 节点实现这些编码。
KNIME Analytics Platform 中的整数编码
要执行整数编码,可以使用Category to Number节点。该节点有一个数据输入端口(在下图中由黑色三角形表示)和两个输出端口:
-
数据输出端口(黑色三角形)与整数编码数据
-
PMML 模型输出端口(蓝色方块)与映射规则
图 4.3显示了该节点及其配置窗口:

图 4.3 – 类别到数字节点对选定的列执行整数编码
在配置窗口的上半部分,您可以选择字符串类型的输入列,应用整数编码。包含框架中的列将会被转换,而排除框架中的列将保持不变。您可以通过框架之间的按钮将列从一个框架移动到另一个框架。
默认情况下,原始列中的值会被整数编码值替换。然而,附加列复选框会为整数编码值创建额外的列,以免覆盖原始列。如果您启用此复选框,您还可以为新列的列头定义自定义后缀。
在配置窗口的下半部分,您可以定义编码规则:起始值、增量、允许的最大类别数以及所有缺失值的整数值。
默认的整数值会被传输到输出 PMML 转换模型中。PMML代表预测模型标记语言,是一种描述和交换预测模型的方式,可以在不同应用程序之间进行交换。输出端口的蓝色方框中的 PMML 模型包含此节点中内置的映射函数,并将应用于其他数据集。在应用此整数编码 PMML 模型时,默认值会分配给所有当前映射(如果有)未表示的输入值。如果没有默认值,则会使用缺失值代替。
提示
若要将存储在 PMML 输出端口中的相同整数编码映射应用于另一个数据集,您可以使用类别到数字(应用)节点。
类别到数字节点会自动定义映射。这意味着您无法手动定义哪个名义值应由哪个整数值表示。如果您希望手动定义,可以在 KNIME Analytics 平台中选择其他选项,我们将介绍其中两个:单元格替换器节点和规则引擎节点。
单元格替换器节点根据字典表替换列中的单元格值。它有两个输入:
-
替换值的目标列所在表格的上输入
-
字典表的下输入
图 4.4显示了单元格替换器节点的配置窗口:

图 4.4 – 单元格替换器节点根据字典实现编码映射
在配置窗口的上半部分,您可以从顶部输入端口的输入表中选择目标列;即,您希望根据字典值替换其值的列。
在配置窗口的 字典表 部分,您可以从底部输入端口的数据表中选择查找值列——即 输入(查找) 列——以及包含替换值的列——即 输出(替换) 列。
目标列(第一个输入)中任何与查找值匹配的出现都将被相应的替换值替换。结果将存储在输出列中,该列要么被添加到表中,要么替换原始目标列。
缺失值被视为普通值;也就是说,它们既可以作为查找值,也可以作为替换值。如果字典表中的查找列存在重复项,则最后一次出现(最下面的行)定义替换对。
对于整数编码示例,您需要一个字典表来映射名义值和整数值。例如,每个教育水平应映射到一个对应的整数值。然后,您可以将原始数据集输入到顶部输入端口,将此映射/字典表输入到最底部的输入端口。
提示
表创建器 节点可以帮助手动创建查找表。
如果没有字典表且不想创建,可以使用 规则引擎 节点。
规则引擎节点根据一组手动定义的规则转换输入列中的值,这些规则在其配置窗口中定义。
图 4.5 显示了规则引擎节点的配置窗口:

图 4.5 – 规则引擎节点实现来自用户定义规则的整数编码
在 => 中,以 "前提 => 结果" 的形式。结果要么插入到新列中,要么替换选定列中的值。对于输入表中的每一行数据,规则匹配过程从顶部规则开始,直到最后一行:第一个匹配的规则决定结果,然后规则过程停止。最后的默认条件,将所有剩余数据行汇总,表示为 "TRUE => 结果"。
规则的结果可以是一个字符串(用 " 或 / 符号括起来)、一个数字、一个布尔常量,或对另一个列的引用。如果没有规则匹配,则结果是缺失值。对其他列的引用通过 $ 包围列名表示。您可以手动插入列引用,或通过双击配置窗口左侧的 列列表 中的列来插入。
除了 表达式 面板,你还会看到 函数、列列表 和 流变量列表 面板。函数 面板列出了所有函数,列列表 面板列出了所有输入列,而 流变量列表 面板则包含了所有可用的流变量。双击其中的任何一个,都会将它们以正确的语法添加到 表达式 窗口中。此外,选择任何一个函数时会显示该函数的描述以及示例。
总结一下,在 KNIME Analytics Platform 中有很多种实现整数编码的方法。我们介绍了三种选项:
-
类别到数字节点提供了一种自动且简单的方法,如果你不想手动定义映射的话。
-
单元格替换器节点如果你手头有查找表会非常有用。
-
规则引擎节点在你想通过一组规则手动定义名义值与整数值之间的映射时非常有用。
接下来,让我们看一下 KNIME Analytics Platform 中的独热编码。
KNIME Analytics Platform 中的独热编码
要对名义特征执行独热编码,可以使用 One to Many 节点。该节点获取列中可用的名义值列表,构建一个包含相同数量分量的向量,并生成每个值的独热编码:一个值变成多个二进制单元格,因此得名。
在配置窗口中,你可以选择执行独热编码的字符串类型列。对于每一列,将根据不同的值创建相同数量的新列。每个新列的标题将是名义列中的原始值,其单元格的值为 0 或 1,取决于原始列中是否存在该标题值。
图 4.6 显示了该节点的配置窗口:

图 4.6 – One to Many 节点实现名义特征的独热编码
创建 one-hot 编码向量会导致非常大且稀疏的数据表,充满了大量零值。这可能会在执行过程中影响工作流性能。Keras Learner 节点确实可以接受大且稀疏的 one-hot 编码数据表。然而,它还提供了一个非常好的可选功能,避免了显式创建带有 one-hot 编码向量的数据表的整个步骤。它可以从原始列的整数编码版本内部创建 one-hot 编码向量。这样,数据的 one-hot 编码表示会被隐藏在 Keras Network Learner 节点内部,并且永远不会从节点传递到节点。在这种情况下,每个整数编码单元的值必须以集合类型单元的形式传递给 Keras Network Learner 节点。要创建集合类型单元,可以使用 Create Collection Column 节点。在本章的 Training the Network 部分,您将看到如何正确配置 Keras Network Learner 节点以利用此功能。
图 4.7 显示了 Create Collection Column 节点的配置窗口。在 Exclude-Include 框中,您可以选择一个或多个列以将其聚合为集合类型列。在配置窗口的下部,您可以决定是否移除原始列,并定义新集合类型列的名称:

图 4.7 – Create Collection Column 节点将多个列的值作为集合聚合为单一列
请注意,对于这种两步 one-hot 编码——首先进行整数编码,然后进行 one-hot 编码——您需要使用前一节中列出的节点创建整数编码列,然后仅对一个列应用 Create Collection Column 节点:我们刚刚创建的整数编码列。
类别目标变量的编码
在上一章中,我们讨论了可以用于构建网络架构并训练网络解决分类问题的不同激活函数和损失函数。当然,输出层的激活函数和损失函数必须匹配。不仅如此,类别编码还必须与所选的激活函数和损失函数匹配。这意味着,不仅名义型输入特征需要进行编码,类别值也需要进行编码。与本节中描述的相同的编码技术和节点,也可以用于类别编码。
二分类的常见方法是使用
和
对两个类别进行编码,然后训练网络预测
类别的概率。在这种情况下,Category to Number 节点或 Rule Engine 节点都可以使用。
在多分类问题中,编码类别列也有两个选择:一对多节点本身,或者是类别到数字节点后接创建集合列节点。
另一个推荐的神经网络预处理步骤是归一化。
归一化
大多数神经网络是使用带反向传播算法的随机梯度下降变体来训练的,以计算梯度。具有不可比拟范围的输入特征可能会在学习过程中造成问题,因为范围最大的输入特征可能会在计算权重更新时占据主导,甚至可能会越过局部最小值。这可能导致振荡并减慢学习过程的收敛速度。为了加速学习阶段,建议提前对数据进行归一化;例如,使用 z-score 归一化,使得每列中的值符合高斯分布,均值为 0.0,标准差为 1.0。
在图 4.8中,您可以看到Normalizer节点及其配置窗口,以及Normalizer(Apply)节点:

图 4.8 – Normalizer 节点为选定的输入列创建归一化函数。Normalizer(Apply)节点将相同的归一化函数应用于另一个数据集
Normalizer 节点在选定的输入列上创建一个归一化函数并进行归一化处理。Normalizer(Apply)节点采用一个外部预定义的归一化函数并将其应用于输入数据。这个节点对的经典应用场景是在训练集和测试集上。Normalizer 节点对训练数据进行归一化,而 Normalizer(Apply)节点则对测试数据应用相同的归一化转换。
Normalizer 节点有一个数据输入端口和两个输出端口:
-
一个数据输出端口,包含归一化后的输入数据
-
一个模型输出端口,包含归一化参数,可在 Normalizer(Apply)节点中用于另一个数据集
在 Normalizer 节点的配置窗口中,您可以选择要归一化的数值列和归一化方法。
Normalizer(Apply)节点的配置窗口非常简洁,因为所有必要的参数都包含在输入的归一化模型中。
提示
使用 Partitioning 节点,您可以在归一化数据之前创建训练集和测试集。
其他有用的预处理节点
在训练神经网络时,缺失值可能会成为问题,因为反向传播算法无法处理它们。在 KNIME 数据表中,用来表示缺失值的占位符是一个红色的问号。
一个强大的节点来填补缺失值是缺失值节点。该节点允许你从多种填补方法中进行选择,比如均值、固定值和最常见值等。
图 4.9展示了节点配置窗口的两个选项卡。在第一个选项卡,即默认选项卡中,你可以选择应用于数据集中所有同类型列的填补方法;所有除了在配置窗口第二个选项卡——列设置选项卡中设置的列。在第二个选项卡中,你可以为每个单独的列定义填补方法:

图 4.9 – 缺失值节点从多种缺失值填补方法中进行选择
大多数神经网络都是以监督方式训练的。因此,另一个必要的步骤是创建训练集和测试集,及可选的验证集。为了创建不同的不相交子集,你可以使用分区节点。
在图 4.10的分区节点配置窗口中,你可以通过绝对值或相对百分比来设置第一个分区的大小。在下面,你可以设置采样技术来创建第一个子集,可以选择根据所选列中的类别按数据分布进行随机抽取(分层抽样)、每隔n行按线性方式抽取,或者从顶部按顺序抽取。上方的输出端口生成结果分区;下方的输出端口生成所有其他剩余的数据行:

图 4.10 – 分区节点创建两个不相交的子集
对于分类问题,建议使用分层抽样选项。它确保所选列中的类别分布在两个分区中(大致)保持不变。对于时间序列分析,如果你的数据按日期升序排列,建议使用从顶部提取选项。较早的样本将进入一个分区,较新的样本进入另一个分区。
若要创建额外的验证集,需要两个分区节点的顺序操作。
我们已经讨论了类别特征的编码、数值特征的标准化、缺失值填补和数据集的分区。很可能这些并不是你为神经网络准备数据时可能需要的唯一节点。
让我们通过在前面提到的两个示例数据集上实现数据准备部分,来看数据准备在实际中是如何工作的。
鸢尾花数据集的数据准备
在图 4.11中,你可以看到工作流中用于访问和准备即将用于神经网络的数据的部分。
工作流从使用表格读取器节点读取鸢尾花数据集开始。
提示
你可以在本章的数据文件夹中找到数据集。
由于数据集只有数值型输入特征(花瓣和萼片的度量),因此不需要进行编码:

图 4.11 – 该工作流片段展示了 Iris 数据集示例中的数据预处理
然而,目标变量包含三种不同的类别:每种花卉物种的名称。这个名义型列中的类别需要通过某些编码技术转换成数字。为了避免引入不存在的关系,我们选择了独热编码。为了实现独热编码,我们选择通过节点进行整数编码,并在 Keras Learner 节点中进行独热编码。我们将在训练网络部分讨论 Keras Learner 节点内部的独热编码。在这里,我们将重点介绍如何在集合类型列中创建花卉类别的整数编码:
-
为了将物种名称转化为索引,我们使用
class列。 -
然后,我们将规则引擎节点的结果通过一个
class列传递,并在配置窗口中排除其他所有列。 -
接下来,使用分区节点创建训练集和测试集,使用 75%的数据进行训练,剩下的 25%用于测试。
-
最后,数据通过 z-score 标准化进行规范化处理。
Iris 数据集非常小且定义清晰。只有几个节点,满足最小需求,足以实现数据准备部分。
现在我们来看一下在一个更复杂(但仍然较小)的数据集上会发生什么,例如成人数据集。
成人数据集的数据准备
图 4.12中的工作流是关于收入预测示例的一部分,读取并预处理成人数据集:

图 4.12 – 该工作流片段展示了成人数据集示例中的数据预处理
和 Iris 数据集一样,你可以在本章的数据文件夹中找到工作流中使用的两个数据集:成人数据集和字典 Excel 表格。在成人数据集中,教育水平以文本形式表示。字典 Excel 文件提供了教育水平与对应标准整数编码之间的映射。我们可以使用这些整数编码作为教育输入特征的数值编码。
接下来,单元替换节点将所有教育水平替换为相应的编码。我们几乎不费力就得到了一个编码。
一些名义型列有缺失值。位于"Missing"中。
接下来,我们对所有其他名义特征(除了教育)进行编码。对于以下特征,使用整数编码,由类别转数字节点实现:婚姻状况、种族和性别。我们可以在这里使用整数编码,因为这些特征要么是二进制的,要么只有少数几个类别。
对于其余的名义特征——工作类别、职业、关系和本国——使用的是独热编码,由一对多节点实现。请记住,该节点为所选列中的每个值创建一个新列。因此,在此转换之后,数据集的特征数从原始的 14 个变为 82 个。
接下来,使用两列Income类创建训练集、验证集和测试集。
最后,Income列在所有子集上进行整数编码,且所有数据都被归一化。
提示
为了隐藏复杂性并整理您的工作流程,您可以创建元节点。元节点以灰色节点表示,并包含子工作流节点。要创建元节点,请选择您要隐藏的节点,右键单击并选择创建元节点。
我们的数据已准备好。现在让我们开始构建神经网络。
构建前馈神经网络架构
要使用 KNIME Keras 集成构建神经网络架构,您可以使用一系列 Keras 层节点。用于构建层的可用节点在节点库中的Keras->Layers文件夹中按类别分组,例如高级激活、卷积、核心、嵌入和递归等。
Keras->Layers文件夹中显示的每个层都有其特色。例如,高级激活中的层创建具有特定激活函数的单元层;卷积中的层创建用于卷积神经网络的层;核心包含所有经典层,如用于收集输入值的输入层和用于全连接前馈神经网络的密集层;等等。
我们将在本书中沿途探索这些层中的许多内容。然而,在本章中,我们将仅限于构建一个全连接前馈神经网络所需的基础层。
网络中的第一层是接收输入值的层。让我们从 Keras 输入层节点开始。
Keras 输入层节点
构建神经网络总是从定义网络的输入层开始的。Keras 输入层节点可以帮助您完成这一任务。实际上,这个节点构建了网络所需的输入,以便接受输入值。
在图 4.13的左侧,您可以看到 Keras 输入层节点,右侧是其配置窗口。如您所见,该节点没有输入端口,只有一个输出端口,其形状和颜色(红色方块)与之前遇到的节点不同:这就是Keras 网络端口:

图 4.13 – Keras 输入层节点定义了神经网络的输入层
提示
端口的颜色和形状表示哪些端口可以互相连接。通常情况下,只有相同颜色和形状的端口才能连接,但也有例外。例如,你可以将一个灰色方块(Python DL 端口)与一个 Keras 端口(红色方块)连接。
每个层节点都有一个配置窗口,其中包含该特定层所需的设置选项。与其他层节点相比,这个节点的配置窗口较为简单,只有少数设置选项。
最重要的设置是形状。形状允许你定义网络的输入形状,意味着输入层有多少个神经元。记住,输入层的神经元数量必须与预处理过的输入列的数量匹配。
Iris 数据集有四个特征,我们将作为输入使用:花萼长度、花萼宽度、花瓣长度和花瓣宽度。因此,这里的输入形状是 4。
此外,在 Keras 输入层节点的配置窗口中,你还可以设置以下内容:
-
层名称前缀,便于以后识别(可选)。
-
批量大小(可选)。请记住,批量大小是训练设置选项之一。推荐的方式是在学习器节点和执行器节点中定义批量大小。此外,你也可以选择在这里定义它。如果定义了批量大小,那么学习器和执行器节点中的批量大小选项将不可用。
-
输入的数据类型和数据格式。
你的网络现在已经有了第一个层——输入层。现在,你可以通过创建并将下一个层节点连接到 Keras 输入层节点的输出,继续构建你的网络——例如,Keras 密集层节点。
提示
若要创建一个节点并立即将其连接到现有节点,请在工作流编辑器中选择现有节点,并双击节点库中的新节点。这将创建新节点并自动将其连接到所选的现有节点。
Keras 密集层节点
Keras 密集层节点实现了一个经典的前馈全连接网络层。此处需要设置的参数是神经单元的数量和激活函数。
图 4.14 显示了此节点的配置窗口。设置选项分为两个标签:选项和高级。
选项标签包含最重要的设置,如神经元的数量,也称为单元,以及激活函数。
此外,输入张量设置定义了来自前一个节点的输入张量部分。在前馈网络中,输入张量是前一层的输出张量。然而,一些层节点——例如,Keras LSTM Layer 节点——不仅创建一个隐藏的输出张量,而是多个。在这种情况下,您必须从前一层节点产生的不同输入张量或隐藏状态中选择一个。Keras 输入层与 Keras Dense Layer 一样,只产生一个输出向量,这就是我们选择作为输入张量传递给 Keras Dense Layer 节点的内容。
在高级选项卡的上半部分,您可以选择如何随机初始化网络的权重和偏置;这意味着在学习过程的第一次迭代之前,所有权重和偏置的初始值。
高级选项卡的下半部分允许您为该层的权重添加范数正则化。范数正则化是一种避免过拟合的技术,我们在第三章《神经网络入门》中介绍过。在配置窗口中,您可以选择是否将其应用于核权重矩阵、偏置向量和/或层激活。激活相应的复选框后,您可以选择使用 L1 范数作为惩罚项、L2 范数作为惩罚项,或两者都使用。最后,您可以为正则化参数设置值,
,用于惩罚项和权重、偏置值的约束。
通过使用Keras 输入层节点和多个 Keras Dense Layer 节点,您可以为许多不同的任务构建一个前馈网络,例如,用于分类鸢尾花:

图 4.14 – Keras Dense Layer 节点允许您向神经网络添加一个全连接层,包括选择常用的激活函数。
其他层节点的配置与此处描述的密集层和输入层类似,您将在接下来的章节中学习更多内容。
由于本章中使用的两个基本示例都涉及前馈网络,我们现在已经具备了构建这两种前馈神经网络的所有必要部分。
构建用于鸢尾花分类的神经网络。
对于使用鸢尾花数据集的多类分类问题,目标是构建一个具有三层的全连接前馈神经网络:
-
一个输入层,包含四个单元,每个输入特征一个。
-
一个包含八个单元并使用 ReLU 激活函数的隐藏层。
-
一个输出层,包含三个单元,每个输出类一个,意味着每个鸢尾花品种一个,使用 softmax 激活函数。
我们选择在隐藏层使用 ReLU 激活函数,因为它在隐藏层中的表现更好,而在输出层使用 softmax 激活函数,具有较好的概率解释性。softmax 函数输出中最大值对应的单元是具有最高类别概率的单元。
图 4.15 展示了用于鸢尾花分类问题的神经网络架构:

图 4.15 – 用于鸢尾花示例的前馈网络示意图。
图 4.16 展示了带有三个层节点并构建网络的工作流片段,以及它们的配置窗口,包括单元数量和激活函数:

图 4.16 – 该工作流片段构建了图 4.15 中用于鸢尾花数据集示例的神经网络。下方的配置窗口显示了各节点的配置。
输入层有四个输入单元,Shape = 4,对应四个数值输入特征。第一个 Keras Dense Layer 节点是隐藏层,包含八个单元,并使用 ReLU 激活函数。在输出层,使用 softmax 激活函数,包含三个单元,每个类对应一个单元。
提示
在最后一层,使用了“Output”作为名称前缀。这使得在 Executor 节点中更容易识别该层,并且如果添加更多 Keras Dense Layer 节点作为隐藏层时,该层名称不会改变。
构建一个用于收入预测的神经网络
第二个示例是一个二分类问题:预测收入(每年是否大于 50K)在成人数据集中的情况。在这里,我们采用了一个包含两个隐藏层的神经网络,总共四层:
-
一个输入层,包含 81 个单元,与输入特征数量相同。
-
一个隐藏层,包含六个单元,并使用 ReLU 激活函数。
-
另一个隐藏层,包含六个单元,并使用 ReLU 激活函数。
-
一个输出层,包含一个单元,并使用 sigmoid 激活函数。
输出层使用经典的二分类实现:一个单一的单元,采用 sigmoid 激活函数。sigmoid 函数的输出范围是 0 和 1,可以通过 0 表示一个类,1 表示另一个类。因此,对于一个二分类问题,其中两个类分别编码为 0 和 1,仅使用一个 sigmoid 函数就可以生成类为 1 的概率。
图 4.17 向你展示了构建该全连接前馈神经网络的工作流片段:

图 4.17 – 这个工作流片段构建了一个完全连接的前馈神经网络,用作成人数据集示例的解决方案。
经过预处理后,成人数据集包含 82 列,其中 81 列为输入特征,1 列为目标列。因此,输入层的形状 = 81。接下来,使用两个 Keras Dense Layer 节点构建了两个隐藏层,单元 = 6,并使用 ReLU 激活函数。输出层由一个 Keras Dense Layer 节点组成,单元 = 1,并使用 sigmoid 激活函数。
在本节中,您已经学习了如何使用 KNIME Keras 集成节点构建前馈神经网络。下一步是设置网络训练所需的其他参数,例如损失函数,然后开始训练网络。
训练网络
我们已经准备好了数据,也有了网络。本节的目标是向您展示如何使用训练集中的数据来训练网络。这需要选择损失函数、设置训练参数、指定训练集和验证集,并跟踪训练进度。
网络训练和所有这些训练设置的关键节点是 Keras 网络学习器 节点。这个节点非常强大且灵活,具有许多可能的设置,分布在四个标签页中:输入数据、目标数据、选项和 高级选项。
Keras 网络学习器节点有三个输入端口:
-
顶部端口:您想要训练的神经网络
-
中间端口:训练集
-
最底端口:可选的验证集
它有一个输出端口,用于导出训练好的网络。
此外,节点还具有 学习监控器 视图,您可以使用它来监控网络的训练进度。
在继续设置训练参数之前,让我们先了解如何选择损失函数。
选择损失函数
在第三章《神经网络入门》中,我们介绍了许多损失函数,每个损失函数适用于特定任务,作为网络设计的最后选择。例如,均方误差通常用于回归问题,或者在多类分类问题中使用分类交叉熵。在 目标数据 标签页的下方,您可以选择不同的标准预打包损失函数,或者使用 Python 定义自定义损失函数(见图 4.18):

图 4.18 – 在 Keras 网络学习器节点的“目标数据”标签页中,您可以选择目标列和损失函数。
现在网络结构已定义,并且你已选择正确的损失函数,下一步是定义输入数据集中哪些列是网络的输入,哪些列包含目标值。
定义输入和输出数据
定义输入列和输出列是你可以在输入数据和目标数据选项卡中完成的操作。让我们首先关注输入数据。
输入数据是网络期望的输入数据,这意味着适合网络输入大小的列。在输入数据选项卡中,所选网络的输入神经元数及相应形状会显示在顶部:

图 4.19 – 在 Keras 网络学习节点的输入数据选项卡中,你可以选择输入列和正确的转换
接下来,你必须选择转换类型;这意味着将所选输入列转换为网络输入规范所接受的格式。可能的转换类型如下:
-
从数字集合(整数)到独热张量
-
从数字(双精度浮点)
-
从数字(整数)
-
从数字集合(双精度浮点)
-
从数字集合(整数)
-
从图像
转换类型 1,从数字集合(整数)到独热张量,是当网络需要独热向量时非常有用的转换方式。与其创建一个包含所有独热向量的矩阵(这会占用空间和资源),不如输入一系列整数编码的值,然后逐一将它们转换为独热向量。在执行过程中,节点创建独热向量并将其输入到网络中。整个过程对最终用户是透明的,并且不会创建额外的庞大稀疏数据表。
其他转换类型仅接受指定格式(双精度浮点、整数或图像)的输入列,并将其呈现给网络。
选择转换类型后,你可以通过包含-排除框选择输入列到网络。请注意,该框已预加载所有与所选转换类型匹配的输入列。
现在,让我们选择目标列。目标数据必须符合输出层的规范。这意味着,如果输出层有 20 个单元,则目标数据必须是 20 维的向量;或者,如果输出层只有一个单元,则目标数据必须包含每个训练样本或数据行的一个单一值。
在目标数据标签中,最上方显示的是网络输出层中神经元的数量和结果形状。与输入数据标签中的操作类似,在这里你可以选择多种转换选项,将输入数据集转换为网络规格。菜单中预先加载了适合网络输出层规格的所有转换类型供你选择。
对于多类分类问题,将一组数字(整数)转换为 one-hot 张量的方式非常有用。你不需要提前创建 one-hot 向量,只需编码输入集合单元中类别的位置(1)即可。
让我们继续讨论训练参数。
设置训练参数
现在网络和损失函数已经定义,下一步是设置训练参数。例如,你想使用哪种优化器?你希望训练多少个纪元?有很多参数需要定义。
所有训练参数可以在选项和高级选项标签中找到。在图 4.20中,你可以看到Keras 网络学习器节点的选项标签:

图 4.20 – 在 Keras 网络学习器节点的“选项”标签中,你可以设置所有的训练参数。
在选项标签的上部,在配置窗口中,你可以定义纪元数和批次大小。这决定了在每次训练迭代中,从训练集和验证集中按批次喂入网络的数据行数。
重要提示
如果在 Keras 输入层节点中定义了批次大小,则批次大小设置将被禁用。
在下面,有两个复选框。一个是在每个纪元之前随机打乱训练数据,另一个是设置随机种子。随机打乱训练数据通常有助于提高学习过程。实际上,使用相同的批次和相同的顺序更新网络可能会对训练的收敛速度产生不利影响。如果选中打乱数据的复选框,则随机种子的复选框会变为激活状态,并且显示的数字用于生成打乱操作的随机序列。使用随机种子可以生成可重复的随机打乱过程,从而使我们能够重复特定训练运行的结果。点击新种子按钮会生成一个新的随机种子和一个新的随机打乱过程。禁用随机种子的复选框会为每次节点执行生成新的种子。
在选项标签页的下部,您可以选择训练时使用的优化器算法及其参数。优化器算法是训练算法。例如,您可以选择RMSProp优化器,然后设置相应的学习率和学习率衰减值。当选择节点时,右侧的描述面板会显示关于该节点的详细信息。提供了优化器列表以及链接,链接指向原始 Keras 库,解释此框架中所有必需的参数。
在选项标签页的最下方,您可以限制梯度值的大小。如果选中剪辑范数,则 L2 范数超过给定范数的梯度会被剪辑到该范数。如果选中剪辑值,则绝对值超过给定值的梯度会被剪辑到该值(或其相反值)。
高级选项标签页包含一些用于特殊终止和学习率衰减的额外设置。最后一个选项允许您在有多个 GPU 的系统上指定使用哪个 GPU。
跟踪训练进度
在设置完所有训练参数后,您可以通过执行节点来开始训练网络。在执行节点时,您可以在学习监控视图中查看学习进度。您可以通过右键点击 Keras 网络学习节点并选择查看:学习监控来打开学习监控视图;参见图 4.21。
默认情况下,学习监控视图会显示训练集上每次权重更新后的准确度曲线变化,显示为红色,这意味着在数据批次通过网络后。准确度值显示在y轴上,批次的进度编号显示在x轴上。
点击上方的损失按钮可以显示训练集上的损失曲线,而不是准确度曲线。
更多关于训练进度的信息可以在Keras 日志输出视图中找到。您可以在 Keras 学习节点视图的顶部选项卡中选择它,位于准确度和损失之后的最后一个标签。

图 4.21 – 学习监控视图显示学习过程的进展
提示
学习监控视图属于 Keras 网络学习节点,您可以通过右键点击执行节点并选择查看:学习监控来打开它。
如果您正在使用验证集,准确度/损失图中会出现一条蓝色线。蓝色线显示的是训练过程在验证集上的对应进度。
在图表下方,您可以选择缩放x轴—即批次轴—以便更详细地查看每个批次后的进度。
平滑复选框引入了原始准确度或损失曲线的移动平均曲线。对数刻度复选框将曲线表示更改为对数刻度,以便更详细地评估训练运行。
最后,在视图底部,您可以看到停止学习按钮。这是一种按需提前停止训练过程的选项。如果在完成训练之前停止训练,则网络保存在当前状态。
Iris 花分类训练设置
对于基于 Iris 数据集的 Iris 花分类示例,我们在网络学习节点中使用了以下设置。
在第一个标签页,输入数据标签页中,选择四个数值输入作为输入特征。在数据准备阶段,我们对输入特征没有进行标称特征编码。因此,我们将它们原封不动地馈送到网络的输入层,使用从数字(双精度)转换类型。
在第二个标签页中,包含整数编码类作为集合的class_collection输入列,并且我们应用了从数字集合(整数)到独热张量转换。因此,在执行过程中,Keras 网络学习节点创建了三维向量的独热编码版本,以匹配网络输出。在此第二个标签页的下半部分,选择分类交叉熵损失函数。
在名为选项的第三个标签页中,定义了训练参数。网络使用 50 个 epoch 进行训练,训练批次大小为 5,并使用RMSProp优化器。
高级选项标签页中的设置默认处于未激活状态。
收入预测的训练设置
对于诸如基于成人数据集的收入预测示例之类的多类分类问题,设置略有不同。我们使用了以下设置。
在第一个标签页中,Income 在Exclude部分。在这里,在数据准备阶段,一些输入特征已经是数值的,并且没有被编码,一些已经被整数编码,并且一些已经通过 KNIME 原生节点被独热编码。因此,所有输入特征都准备好按原样馈送到网络中。请注意,由于我们决定混合整数编码、独热编码和原始特征,唯一适用于所有这些不同特征的编码是简单的从数字类型转换。
在第二个标签页中,0 或 1。这也适用于网络输出层的 Sigmoid 函数的单输出。在包含-排除框架中,只包括目标列Income。接下来,选择二元交叉熵损失函数,以适应这样的二元分类问题。
在第三个标签页,选项,我们将网络设置为训练 80 个周期,训练批次大小为 80 条数据。在此示例中,我们还使用了验证集,以便在训练过程中能够看到网络在未包含在训练集中的数据上的进展。对于验证集的处理,设置了批次大小为 40 条数据。最后,我们选择Adam作为该训练过程的优化器。
同样,最后一个标签页,高级选项中的设置默认是禁用的。
测试和应用网络
现在神经网络已经训练完成,最后一步是将网络应用于测试集并评估其性能。
执行网络
要执行训练好的网络,您可以使用Keras 网络执行器节点,如图 4.22所示。该节点有两个输入端口:一个是用于训练好的 Keras 网络的端口,另一个是用于测试集或新数据的数据输入端口。
在配置窗口的第一个标签页,名为选项,您可以在上方选择后端引擎、输入数据的批处理大小,以及是否在输出数据表中保留原始输入列。
在此下方,您可以指定输入列和所需的转换。与 Keras 网络学习器节点中的输入规格一样,神经网络的输入规格会显示在顶部。请记住,由于您使用的是相同的网络和相同的数据格式,因此输入特征的设置必须与 Keras 网络学习器节点中的设置相同。
在此标签的最后部分,您可以添加输出的设置。首先,您需要指定输出的来源;这应该是输入网络中的输出层。要添加一个输出层,请点击添加输出按钮。在新窗口中,您会看到一个包含输入网络所有层的菜单。如果您在层节点中配置了前缀,您可以在下拉菜单中看到它们,这样可以更轻松地识别感兴趣的层。选择输出层:

图 4.22 – Keras 网络执行节点在新数据上运行网络。在配置窗口中,您可以通过点击添加输出按钮来选择输出。
在本书中所有的使用案例中,网络的最后一层作为输出层。这一层很容易识别,因为它是下拉列表中唯一没有(隐藏)后缀的层。
提示
您还可以输出隐藏层的输出,例如用于调试目的。
最后,选择适当的转换类型,以便以你喜欢的格式获取输出值——例如,将值放在一个单元格中作为列表(转为数字列表(双精度)),或者为每个输出单元创建一个新列(转为数字(双精度))。在最后一种情况下,你可以定义一个前缀,附加到输出列的名称上。
高级选项(Advanced Options)部分包含设置,允许网络在支持 GPU 的机器上运行。
提取预测结果并评估网络性能
根据使用场景,网络输出可能需要一些后处理来提取预测结果。例如,在二分类问题中,若只有一个输出单元且使用了 Sigmoid 激活函数,则输出值为表示类别 1 的概率。在这种情况下,你可以在规则引擎节点中应用一个阈值来产生实际的类别分配。
最后一步是评估模型。要评估分类模型,你可以使用评分器(Scorer)节点或ROC 曲线(ROC Curve)节点。评分器节点的输出提供了常见的性能指标,如准确率、Cohen's Kappa 或混淆矩阵。
提示
另一个非常不错的节点,用于评估二分类问题的性能,是二分类检查器(Binary Classification Inspector)节点。该节点是 KNIME 机器学习可解释性扩展的一部分:hub.knime.com/knime/extensions/org.knime.features.mli/latest。
对于回归解决方案的评估,数值评分器(Numeric Scorer)节点计算一些误差指标,如均方误差、均方根误差、平均绝对误差、平均绝对百分比误差、平均符号差异和 R 平方值。
测试训练好的鸢尾花分类网络
在图 4.23中,你可以看到应用训练好的网络、提取预测结果并评估用于分类鸢尾花的网络部分:

图 4.23 – 该工作流片段应用训练好的网络,提取并评估鸢尾花示例的预测结果
在 "dense_2/Softmax:0_" 的配置窗口中,已选择转换类型:转为数字(双精度)。由于鸢尾花数据集有三种不同的类别值,节点添加了三个新列,分别表示这三类的概率。另一种转换选项是转为数字列表(双精度)。这种转换选项会导致只新增一个列,将所有类别的概率以列表形式放入一个单元格中。
接下来,使用 Rule Engine 节点提取预测结果。不同类别的概率在 $Output_1/Softmax:0_0for class 0 列中为类别 0,在 Output_1/Softmax:0_1 列中为类别 1,在 Output_1/Softmax:0_2 列中为类别 2。此处,选取具有最高概率的类别作为预测结果。
第一条规则通过将编码为 0 的类别与其他两个类别的概率进行比较,检查是否其概率最大。第二条规则对编码为 1 的类别执行相同的操作,第三条规则则检查编码为 2 的类别。最后一条规则定义了默认值。
这些规则通过以下代码应用:
$Output_1/Softmax:0_0$ > $Output_1/Softmax:0_1$ AND $Output_1/Softmax:0_0$ > $Output_1/Softmax:0_2$ => 0
$Output_1/Softmax:0_1$ > $Output_1/Softmax:0_0$ AND $Output_1/Softmax:0_1$ >$Output_1/Softmax:0_2$ => 1
$Output_1/Softmax:0_2$ > $Output_1/Softmax:0_0$ AND $Output_1/Softmax:0_2$ >$Output_1/Softmax:0_1$ => 2
TRUE => 3
最后,使用 Scorer 节点评估网络性能。
测试用于收入预测的训练网络
使用相同的节点组合,并调整设置,可以应用训练后的网络,提取预测结果,并评估成人数据集上的收入预测模型。
在 Keras Network Executor 节点的配置窗口中,将 dense_3 输出层作为输出添加。在此情况下,网络的输出为编码为 1(">50K")的类别的概率。
最后,Rule Engine 节点通过以下代码检查输出概率是否高于或低于 0.5 阈值:
$dense_3/Softmax:0_0$ < 0.5=> "<=50K"
TRUE => ">50K"
最后,使用 Scorer 节点评估网络性能。
到这里,我们已经完成了整个过程,从数据访问和数据准备,到使用 KNIME Analytics Platform 定义、训练、应用和评估神经网络。
总结
本章已接近尾声,在这里你学会了如何在 KNIME Analytics Platform 中执行训练神经网络的不同步骤。
我们从常见的预处理步骤开始,包括不同的编码、归一化和缺失值处理。接下来,你学习了如何通过使用不同的 Keras 层节点而不编写代码来定义神经网络架构。然后,我们进入了神经网络的训练,你学习了如何定义损失函数,以及如何监控学习进度、应用网络到新数据并提取预测结果。
每个部分结束时都有小的示例环节,帮助你准备独立完成所有这些步骤。
在下一章中,你将看到如何将这些步骤应用于本书的第一个用例:使用自编码器进行欺诈检测。
问题与练习
通过回答以下问题,检查你对本章中概念的理解程度:
-
如何设置损失函数来训练你的神经网络?
a) 通过使用 Keras 损失函数节点
b) 通过使用 Keras 输出层节点
c) 在 Keras Network Learner 节点的配置窗口中
d) 在 Keras Network Executor 节点的配置窗口中
-
如何对你的特征进行 one-hot 编码?
a) 通过使用 One Hot Encoding 节点
b) 通过使用 One to Many 节点
c) 通过使用 Category to Number 节点创建整数编码,然后使用 Integer to One Hot Encoding 节点。
d) 通过创建整数编码,将其转换为集合单元,并选择正确的转换。
-
如何定义网络输入层的神经元数量?
a) 通过使用 Keras 输入层节点。
b) 通过使用没有任何输入网络的 Keras 全连接层节点。
c) 输入维度根据在 Keras Network Learner 节点中选择的特征自动设置。
d) 通过使用 Keras 起始层节点。
-
如何监控神经网络在验证集上的训练过程?
a) 将验证集输入到 Keras Network Learner 节点的可选输入端口,并打开训练监视器视图。验证集的性能以红色显示。
b) 在训练监视器视图中点击应用于验证集按钮。
c) 将验证集输入到 Keras Network Learner 节点的可选输入端口,并打开训练监视器视图。验证集的性能以蓝色显示。
d) 将验证集输入到 Keras Network Learner 节点的可选输入端口,并打开训练监视器视图中的验证集标签。构建一个工作流来读取 Iris 数据集,并训练一个包含一个隐藏层(八个单元和 ReLU 激活函数)的神经网络,根据四个输入特征区分三种物种。
第二部分:深度学习网络
在这里,我们将深入探讨神经网络(深度学习)中的更高级概念,以及如何基于一些案例研究在 KNIME Analytics Platform 中实现这些概念。
本节包含以下章节:
-
第五章**,用于欺诈检测的自编码器
-
第六章**,需求预测的循环神经网络
-
第七章**,自然语言处理应用的实现
-
第八章**,神经机器翻译
-
第九章**,用于图像分类的卷积神经网络
第五章:第五章: 用于欺诈检测的自编码器
到了本书的这个阶段,你应该已经掌握了神经网络背后的基本数学和概念,以及一些深度学习范式,还了解了数据准备中最有用的 KNIME 节点,如何构建神经网络、如何训练和测试它,最后如何评估它。我们在第四章《构建和训练前馈神经网络》中共同构建了两个全连接前馈神经网络的例子:一个用于解决 Iris 数据集的多分类问题,另一个用于解决 Adult 数据集的二分类问题。
那些是使用相对较小数据集的两个简单例子,所有类别都有充分的代表性,网络中仅有几层隐藏层,并且输出类别的编码也很直接。然而,它们达到了它们的目的:教你如何在 KNIME 分析平台中组装、训练和应用神经网络。
现在,时机已经成熟,开始探索更现实的例子,并应用更复杂的神经网络架构和更先进的深度学习范式,以解决有时基于条件较差数据集的更复杂问题。在接下来的章节中,你将看到一些更具现实性的案例研究,这些案例需要比单纯使用全连接前馈网络进行分类更具创意的解决方案。
我们将从一个二分类问题开始,数据集只包含两个类别中的一个。在这里,经典的分类方法无法工作,因为训练集缺少其中一个类别。这类问题有很多,例如预测机械故障的异常检测或欺诈检测,用以区分合法和欺诈的信用卡交易。
本章探讨了一种替代的神经网络方法,用于设计解决欺诈检测中极端情况的方案:自编码器架构。
我们将涵盖以下主题:
-
介绍自编码器
-
为什么欺诈检测这么难?
-
构建和训练自编码器
-
优化自编码器策略
-
部署欺诈检测器
介绍自编码器
在前几章中,我们看到神经网络是非常强大的算法。每个网络的力量来源于其架构、激活函数、正则化项,以及一些其他特性。在各种神经网络架构中,有一种非常通用的架构,特别适用于三项任务:检测未知事件、检测意外事件,以及降低输入空间的维度。这种神经网络就是自编码器。
自编码器的架构
自编码器(或自关联器)是一个多层前馈神经网络,训练的目标是将输入向量映射到输出层。像许多神经网络一样,它使用梯度下降算法或其现代变体进行训练,针对损失函数,例如均方误差(MSE)。它可以有任意数量的隐藏层。也可以在这里应用正则化项和其他有助于避免过拟合或改善学习过程的通用参数。
架构的唯一约束是输入单元的数量必须与输出单元的数量相同,因为目标是训练自编码器将输入向量映射到输出层。
最简单的自编码器只有三层:一个输入层,一个隐藏层和一个输出层。更复杂结构的自编码器可能包含额外的隐藏层:

图 5.1 – 一个简单的自编码器
自编码器可以用于许多不同的任务。让我们首先看看自编码器如何用于降维。
使用自编码器减少输入的维度
让我们考虑一个非常简单架构的自编码器:一个输入层,包含
个单元;一个输出层,也包含
个单元;以及一个隐藏层,包含
个单元。如果
,自编码器将输入向量压缩到隐藏层,降低其维度,从
降到
。
在这种情况下,网络的第一部分,将数据从大小为
的向量转换为大小为
的向量,充当编码器的角色。网络的第二部分,将输入向量从
空间重建回
空间,充当解码器。压缩率则为
。值为
越大,值为
越小,压缩率越高:

图 5.2 – 三层自编码器中的编码器和解码器子网络
当使用自编码器进行降维时,首先训练完整的网络,将输入向量映射到输出层。然后,在部署之前,它被拆分为两部分:编码器(输入层和隐藏层)和解码器(隐藏层和输出层)。这两个子网络被分别存储。
提示
如果你对瓶颈层的输出感兴趣,可以将Keras 网络执行器节点配置为输出中间层。或者,你也可以在DL Python 网络编辑器节点中,通过编写几行 Python 代码来拆分网络。
在部署阶段,为了压缩输入记录,我们只需将其传递通过编码器,并将隐藏层的输出保存为压缩记录。然后,为了重建原始向量,我们将压缩记录通过解码器并保存输出层的输出值作为重建向量。
如果自编码器使用了更复杂的结构——例如,拥有多个隐藏层——那么其中一个隐藏层必须作为压缩器的输出,产生压缩记录并将编码器和解码器子网络分开。
现在,当我们谈论数据压缩时,问题是原始记录能否被忠实地重建?使用隐藏层的输出而非原始数据向量,会丢失多少信息?当然,这一切都取决于自编码器的表现如何以及我们的误差容忍度有多大。
在测试阶段,当我们将网络应用于新数据时,我们会对输出值进行去归一化,并计算所选的误差度量——例如,均方根误差(RMSE)——在整个测试集上计算原始输入数据与重建数据之间的差异。这个误差值为我们提供了重建数据质量的衡量标准。当然,压缩率越高,重建误差就越大。因此,问题变成了训练网络以达到根据我们的误差容忍度所能接受的性能。
让我们继续讨论自编码器的下一个应用领域:异常检测。
使用自编码器检测异常
在大多数分类/预测问题中,我们拥有一组覆盖所有事件类别的示例,并基于这个数据集训练一个模型来分类事件。然而,有时我们想要预测的事件类别是非常稀有和意外的,以至于根本没有(或几乎没有)任何示例可用。在这种情况下,我们不再谈论分类或预测,而是谈论异常检测。
异常可以是任何稀有、意外、未知的事件:心律不齐、机械故障、欺诈交易或其他稀有、意外、未知的事件。在这种情况下,由于训练集中没有异常的示例,我们需要以比传统标准分类更具创造性的方式使用神经网络。自编码器结构非常适合这种创造性使用,正如解决异常检测问题所需要的那样(例如,参见 A.G. Gebresilassie,神经网络用于异常(离群点)检测,blog.goodaudience.com/neural-networks-for-anomaly-outliers-detection-a454e3fdaae8)。
由于没有异常示例可用,自编码器仅对非异常示例进行训练。我们将这些示例称为“正常”类。在充满“正常”数据的训练集上,自编码器网络被训练以将输入特征向量重构到输出层。
这个思想是,当自编码器被要求重构“正常”类的向量时,它可能会表现得相当不错,因为这是它训练的目标。然而,当它被要求重构输出层中的异常时,它应该会失败,因为它在整个训练阶段没有见过这种类型的向量。因此,如果我们计算原始向量与重构向量之间的距离——任何一种距离——我们会发现对于“正常”类的输入向量,距离较小,而对于表示异常的输入向量,距离则大得多。
因此,通过设置一个阈值,
,我们应该能够通过以下规则检测异常:
IF
THEN
-> "正常"
IF
THEN
-> "异常"
这里,
是输入向量的重建误差,
,以及
是设定的阈值。
这种解决方案已经成功地应用于欺诈检测,正如在一篇博客文章中所描述的,使用 Keras 中的自编码器进行信用卡欺诈检测--黑客的 TensorFlow(第六部分)[I),作者是 Venelin Valkov(medium.com/@curiousily/credit-card-fraud-detection-using-autoencoders-in-keras-tensorflow-for-hackers-part-vii-20e0c85301bd))。在这一章中,我们将使用相同的思想,通过不同的自编码器结构构建类似的解决方案。
让我们来了解自编码器的思想如何用于检测欺诈交易。
为什么欺诈检测如此困难?
欺诈检测是一组旨在通过虚假手段防止财物被非法获取的活动。欺诈检测被应用于许多行业,如银行业或保险业。在银行业中,欺诈可能包括伪造支票或使用盗窃的信用卡。对于本示例,我们将重点讨论信用卡交易中的欺诈行为。
这种信用卡交易中的欺诈问题,对于信用卡发行商和最终支付方来说都是一个巨大的问题。欧洲中央银行报告称,2016 年,使用单一欧元支付区(SEPA)发行的卡的卡欺诈案件总数为 1730 万件,而使用 SEPA 发行的卡的卡交易总数为 749 亿笔(www.ecb.europa.eu/pub/cardfraud/html/ecb.cardfraudreport201809.en.html#toc1)。
然而,欺诈的数量并不是唯一的问题。从数据科学的角度来看,欺诈检测也是一个非常难解决的任务,因为关于欺诈交易的数据非常少。也就是说,我们通常有大量的合法信用卡交易数据,而关于欺诈交易的数据则寥寥无几。在这种情况下,经典的方法(训练,然后应用模型)是不可行的,因为其中一个类别的示例缺失。
然而,欺诈检测也可以看作是异常检测。异常检测是数据集中任何意外事件。欺诈交易确实是一个意外事件,因此我们可以将其视为合法正常信用卡交易数据集中的异常。
欺诈检测有几种不同的方法。
一种选择是判别方法。基于包含合法和欺诈交易的训练集,我们构建一个区分两类数据的模型。这可以是一个简单的基于阈值的规则,或者一个有监督的机器学习模型。这是基于包含两类数据的足够示例的经典方法。
或者,你可以将欺诈检测问题视为异常值检测。在这种情况下,你可以使用一种为异常值(噪声)留出空间的聚类算法,比如DBSCAN;或者使用孤立森林技术,它通过对合法数据进行少量切割来孤立异常值。然而,欺诈交易必须属于原始数据集,才能被孤立为异常值。
另一种方法,称为生成方法,在训练阶段只使用合法的交易。这使得我们能够将输入向量复制到输出层。一旦自编码器模型训练完成,我们将在部署过程中使用它来重现输入交易。然后我们计算输入值和输出值之间的距离(或误差)。如果该距离低于给定的阈值,则交易可能是合法的;否则,它将被标记为潜在欺诈交易。
在这个示例中,我们将使用Kaggle 上的信用卡数据集。该数据集包含 2013 年 9 月来自欧洲持卡人的信用卡交易记录。欺诈交易标记为1,合法交易标记为0。数据集包含 284,807 笔交易,但其中仅有 492 笔(0.2%)是欺诈交易。出于隐私原因,使用主成分代替原始的交易特征。因此,每笔信用卡交易由 30 个特征表示:28 个从原始信用卡数据中提取的主成分、交易时间和交易金额。
让我们开始构建、训练和测试自编码器。
构建和训练自编码器
让我们详细讨论一下我们将构建的特定应用,用以解决通过神经自编码器进行欺诈检测的问题。像所有的数据科学项目一样,它包括两个独立的应用:一个用于在专用数据集上训练和优化整个策略,另一个用于将其应用到实际的信用卡交易中进行分析。第一个应用通过训练工作流实现;第二个应用通过部署工作流实现。
提示
通常,训练和部署是两个独立的应用,因为它们处理的数据不同,目标也不同。
训练工作流使用实验室数据集来生成一个可接受的模型,以实现任务,有时需要进行几次不同的尝试。部署工作流则不再改变模型或策略,它只是将模型应用于真实世界的交易中,以获取欺诈警报。
在本节中,我们将重点关注训练阶段,包括以下步骤:
-
数据访问:在这里,我们从文件中读取实验室数据,包括所有 28 个主成分、交易金额和相应的时间。
-
数据准备:数据通过主成分分析(PCA)已经被清理和转换。本阶段需要做的就是创建所有训练、优化和测试神经自编码器及整个策略所需的数据子集。
-
构建神经网络:自编码器是一种前馈神经网络,输入和输出的数量相同。接下来,我们决定隐藏层的数量、每层的隐藏神经元数量以及激活函数,并据此构建网络。
-
训练神经自编码器:在这一部分,自编码器将在仅包含合法交易的训练集上进行训练,使用其中一种训练算法(优化器),根据选择的训练参数,如至少损失函数、迭代次数和批次大小等。
-
欺诈警报规则:网络训练完成后,能够在输出层复现合法交易后,我们需要通过计算输入和输出层之间的距离,并设置基于阈值的规则来触发欺诈警报,从而完成策略。
-
测试整体策略:最后一步是测试整体策略的性能。多少合法交易被正确识别?多少欺诈警报被正确触发?有多少是误报?
数据访问和数据准备
来自 Kaggle 的信用卡数据集已经经过清理和转换。现在我们需要创建所有数据子集。具体来说,我们需要一个用于自编码器训练的训练集和一个验证集。它们必须仅包含合法交易。训练集用于训练网络,验证集用于在训练期间监控自编码器在未见数据上的性能。
然后,我们需要另一个数据子集,即阈值优化集,用于优化基于规则的欺诈警报生成器中的阈值值
。这个最后的子集应包括所有欺诈交易,以及一些合法交易,具体如下:
-
所有合法交易的 2/3 都专用于自编码器。
-
那些合法交易的 90%形成训练集。
-
10%来自验证集。
-
所有合法交易中的 1/3(96K)和所有 492 笔欺诈交易形成阈值优化集,用于优化基于阈值的欺诈警报生成器的阈值值
。
所有这些转化为一个行分割器节点,将合法交易与欺诈交易分开,一个连接节点将欺诈交易重新添加到阈值优化集中,以及若干分区节点。在分区节点中,所有数据的提取都是随机进行的。

图 5.3 – 用于欺诈检测过程的数据集
重要提示
训练集、验证集和阈值优化集必须完全分离。不能在任何子集之间共享记录。这是为了确保在评估期间有意义的性能度量和独立的优化过程。
接下来,必须对每个子集中的所有数据进行归一化,以确保它们落在
范围内。归一化是在训练集上定义并应用于其他两个子集。归一化参数也会保存用于部署工作流的模型写入器节点:

图 5.4 – 实施欺诈检测数据准备的工作流程
图 5.4显示了如何在 KNIME Analytics 平台中执行不同数据集的创建和归一化。
构建自编码器
对于这个案例研究,我们构建了一个具有五个隐藏层的自编码器,分别为30-40-20-8-20-40-30个单元,并且 sigmoid 作为激活函数。
神经网络是通过以下方式构建的(参见图 5.5):
-
形状 = 30
-
使用五个Keras Dense Layer节点来实现隐藏层,使用 sigmoid 作为激活函数,分别是 40、20、8、20 和 40 个单元。
-
Keras Dense Layer节点用于输出层,具有 30 个单元和 sigmoid 作为激活函数:

图 5.5 – 训练以从输入层到输出层复制信用卡交易的神经自编码器的结构
现在我们已经构建了自编码器,让我们使用数据来训练和测试它。
训练和测试自编码器
要训练和验证网络,我们使用Keras Network Learner节点,训练集和验证集分别放置在输入端口,并使用以下设置(见图 5.6):
-
epochs 数设置为
50,训练和验证集的批次大小设置为300,并且使用了Adam(优化的反向传播的版本)训练算法,在Options标签中。 -
损失函数设置为Target标签中的 MSE。
-
输入标签和目标标签中的目标和输入特征相同,并且被接受为简单的双精度数。
在Learning Monitor视图的Loss标签中,您现在可以看到两条曲线:一条是批次中每个训练样本的平均损失(或错误)(红色),另一条是验证数据中每个样本的平均损失(蓝色)。
在训练阶段结束时,来自训练集的最终平均损失值约为[0.0012, 0.0016],来自验证集的批次约为[0.0013, 0.0018]。计算的损失是一个批次的平均重建误差,由以下公式计算:

在这里,
是批次大小,
是输出层上的单元数,
是训练样本k中第i个神经元的输出值,
是相应的目标答案。
训练后,网络应用于优化集,使用Keras Network Executor节点,并将其保存为 Keras 文件以便部署,使用Keras Network Writer节点。
图 5.6 显示了 Keras 网络执行器节点中 选项 标签的配置:所有 30 个输入特征被作为 Double 数字传递,并且输入列被保留,以便稍后计算重建误差。最后一层被选择为输出,值作为简单的 Double 数字导出:

图 5.6 – Keras 网络执行器节点及其配置窗口
下一步是计算原始特征向量和复现特征向量之间的距离,并应用阈值
,以发现欺诈候选。
侦测欺诈交易
当模型训练完成后,自编码器已经学会了如何将代表合法交易的特征向量复现到输出层。那么我们如何发现可疑交易呢?如果有一个新的交易,
,我们如何判断它是可疑的还是合法的呢?
首先,我们通过 Keras 网络执行器节点,将这个新的交易
输入到自编码器中。原始交易的复现会在输出层生成。接下来,计算重建误差
,即原始交易向量与复现向量之间的距离。根据以下规则,交易会被视为欺诈候选:
如果
那么
-> "合法交易"
如果
那么
-> "欺诈候选交易"
这里,
是交易
的重建误差值,K 是一个阈值。重建误差也采用了 MSE:

这里,
是交易
的 i 特征,
是网络输出层上对应的值。
是通过 1 来计算的,1 是欺诈候选类,0 是合法交易类。一个 1。特异性是指真正的合法交易与所有没有触发任何警报的交易之间的比例。敏感性则相反,衡量实际触发欺诈交易的欺诈警报的比例。
特异性衡量我们可能错过的欺诈,而敏感性衡量我们发现的欺诈。

图 5.7 – 在规则引擎节点中实现的规则,通过与阈值比较重建误差
现在我们的模型已经训练和测试,需要进行优化。
优化自编码器策略
最佳阈值
是多少?在最后一节中,我们根据经验采用了
。但是,对于
来说,这是否是最佳值?在这种情况下,阈值
并不会通过训练过程自动优化。它只是训练算法外部的静态参数。在 KNIME Analytics 平台上,也可以在学习者节点外部优化静态参数。
优化阈值 ![]()
阈值
定义在名为优化集的数据的一个单独子集上。在这里有两个选择:
-
如果可用带有标记的欺诈交易优化集,则阈值
根据任何欺诈检测的准确性度量进行优化。 -
如果数据集中没有可用的标记欺诈交易,则阈值
的值被定义为优化集上重建误差的高百分位数。
在数据准备阶段,我们生成了三个数据子集:用于 Keras 网络学习者节点训练和验证自编码器的训练集和验证集,以及最后一个子集,我们称之为阈值优化集。这个最终子集包括所有合法交易的三分之一和少量欺诈交易。我们可以使用这个子集来优化阈值
,以提高整个欺诈检测策略的准确性。
优化参数意味着在给定范围内找到最大化或最小化给定度量的值。根据我们的经验,我们假设 K 的值为正数(> 0),且在 0.02 以下。因此,优化阈值
的值意味着在
中找到最大化整个应用程序准确性的值。
应用程序的准确性通过一个 Scorer(JavaScript)节点计算,考虑规则引擎节点的结果作为预测,并将其与优化集中的原始类别(0 = 合法交易,1 = 欺诈交易)进行比较。
通过一个loop start节点和一个loop end节点执行值区间的跨度和最大准确性的阈值标识。在优化循环中,这两个节点分别是参数优化循环起始节点和参数优化循环结束节点。
参数优化循环起始节点在给定的区间内以给定的步长遍历参数值。区间
和步长
是根据重建误差特征的范围选择的,如数据表输出端口的下限和上限单元格所示,该表位于数学公式节点输出端,名为MSE 输入-输出距离,紧随 Keras 网络执行器节点之后。
参数优化循环结束节点将所有结果作为流变量收集,检测目标度量的最佳(最大或最小)值,并将其与生成该值的参数一起导出。在我们的案例中,目标度量是精度,通过规则引擎节点的预测进行测量,必须针对阈值
进行最大化。
循环起始和循环结束之间的所有节点构成了循环的主体——即,直到输入的参数值区间完全覆盖为止,这部分会根据需要重复多次。在循环主体内,我们增加了额外的约束条件,即只有当特异性和灵敏度接近时,才会找到最优的精度。这是名为 Coefficient 0/1 的元节点的目标。在这里,如果特异性和灵敏度相差超过 10%,系数被设置为 0,否则为 1。然后,这个系数将乘以来自评分器(JavaScript)节点的整体精度。通过这种方式,只有当特异性和灵敏度接近时,才能检测到最大精度:

图 5.8 – 优化循环
在提取最优阈值后,我们将其转化为流变量,并将其传递给最终的规则实现。
包装成一个组件
现在,这整个阈值优化部分似乎是一个逻辑上自包含的模块。为了保持我们的工作流程简洁且规范,我们可以将这个模块包装在一个元节点内。更好的是,我们可以通过一种更强类型的元节点——组件,确保包装紧密且封闭。
提示
元节点仅仅是收集和打包节点。而组件则不仅收集和打包节点,还继承了包含的 Widget 和 JavaScript 节点的视图以及包含的配置节点的配置窗口。更进一步,组件不允许外部流变量进入或内部流变量退出,除非特别定义。
组件的创建方式类似于元节点。只需选择要分组的节点,右键单击并选择创建组件…。创建组件后,其上下文(右键)菜单提供了多个命令,用于打开、展开、通过设置进行修改和共享。要查看组件的内容,只需Ctrl + 双击组件。进入后,你可以看到两个节点:组件输入和组件输出。在这两个节点的配置窗口中,你可以分别设置流变量以导入和导出组件内外的数据。
在我们创建的组件中,我们设置了组件输出节点来导出包含最优阈值的流变量。这个流变量需要从组件中输出,以便在最终的欺诈检测规则中使用。最终的规则在一个新的规则引擎节点中实现,最终的预测将在一个新的评分器(JavaScript)节点中与原始类别进行比较。
最终的工作流用于训练和测试神经自编码器,使用信用卡交易数据,并实现带有最优阈值的欺诈检测规则,详见图 5.9。该工作流名为01_Autoencoder_for_Fraud_Detection_Training,可以从 KNIME Hub 下载:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%205/:

图 5.9 – 训练和测试自编码器并找到最优阈值 K 的工作流
既然我们已经找到了最佳阈值,让我们来看看自编码器的性能。
性能指标
本节中,我们报告了应用欺诈检测规则后,在阈值优化集上该方法的性能指标。最优阈值被发现为
,准确率为 93.52%。
在图 5.10中,你可以看到混淆矩阵、基于此的类别统计以及一般的性能指标,所有这些都描述了欺诈检测器在优化集上的表现:

图 5.10 – 使用优化阈值 K 的最终欺诈检测器的性能指标
假设类别 1(欺诈)为正类。大量的假阳性(6,236)显示了这种方法的弱点:它容易产生假阳性。换句话说,它倾向于将完全合法的交易错误标记为欺诈候选交易。现在,确实有些案例研究中假阳性不是一个大问题,这就是其中之一。在假阳性的情况下,付出的代价是向信用卡持有者发送当前交易的消息。如果这条消息没有用处,与可能的风险相比,损害并不大。当然,这种容忍度并不适用于所有案例研究。在医学诊断中,假阳性比信用卡交易中的错误欺诈警报责任要大得多。
重要提示
通过在定义阈值K时引入基于专业知识的偏差,整个过程也可以被迫倾向于欺诈候选交易或合法交易。
一般来说,自动编码器能够捕获验证集中 87%的欺诈交易和 93%的合法交易,总体准确率为 85%,Cohen's kappa 值为 0.112。考虑到验证集中正常交易与欺诈交易的高度不平衡(96,668 比 492),结果仍然是有前景的。
请注意,这种容易产生假阳性的方式对于没有或几乎没有某一类别示例的案例研究来说是一个无奈的解决方案。在一个包含标注示例的训练集上,监督分类器可能会达到更好的表现。但这就是我们必须应对的数据!
我们已经训练好了自动编码器,并找到了我们规则系统的最佳阈值。在下一部分中,我们将看到如何在现实世界的实际数据上部署它。
部署欺诈检测器
到此为止,我们已经有了一个自动编码器网络和一个具有可接受性能的欺诈检测规则。在这一部分中,我们将实现部署工作流。
部署工作流(图 5.11),像所有部署工作流一样,接收新的交易数据,将其通过自动编码器,计算距离,应用欺诈检测规则,最后,将输入交易标记为欺诈或合法。
这个工作流名为02_Autoencoder_for_Fraud_Detection_Deployment,可以从 KNIME Hub 下载:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%205/:

图 5.11 – 部署工作流
让我们详细看一下工作流的不同部分。
读取网络、新交易和标准化参数
在这个工作流中,首先通过Keras 网络读取器节点,从之前保存的 Keras 文件中读取自动编码器模型。
与此同时,一些新的信用卡交易数据通过文件读取器节点从文件中读取。这个特定的文件包含了两笔新的交易。
交易数据使用与训练数据相同的参数进行标准化,这些参数之前保存在名为 normalizer model 的文件中。这些标准化参数通过模型读取器节点从文件中读取。
最后一份文件包含了优化后的阈值值,K。
应用欺诈检测器
交易数据被输入到自编码器网络中,并通过 Keras 网络执行器节点在输出层进行重建。
随后,通过数学公式节点计算每笔交易的原始特征和重建特征之间的均方误差(MSE)。
规则引擎节点应用阈值,
,这是在优化阶段定义的,用来检测可能的欺诈候选。
下表展示了两笔交易的重建误差以及随之而来的分类结果。应用(自编码器和距离规则)将第一笔交易定义为合法,第二笔交易定义为欺诈候选:

图 5.12 – 用于部署的数据集中信用卡交易的重建误差和欺诈分类结果
采取行动
在工作流的最后部分,我们需要采取行动:
-
如果交易是合法的(类别 0)=> 不做任何操作
-
如果交易是欺诈候选(类别 1)=> 向卡主发送确认消息
IF-THEN 条件和行动通过 KNIME 分析平台中的开关块实现。类似于循环,开关块有一个起始节点和一个结束节点。然而,开关块中的结束节点是可选的。开关起始节点只会激活一个输出端口,从而仅启用一个可能的数据流路径。开关结束节点收集来自不同分支的结果。最通用的开关块是CASE switch,它有多种变体:适用于数据、流变量或模型。
活动端口,然后是活动分支,通过Switch CASE Start节点的配置窗口进行控制。此配置设置通常通过流变量控制,流变量的值每次决定启用哪个输出。
在我们的案例中,我们有两个分支。上分支连接到端口 0,由类别 0 激活,不执行任何操作。第二个分支连接到端口 1,由类别 1 激活,并向信用卡持有者发送电子邮件。
在这里我们结束了基于自编码器的欺诈检测策略的实现部分。
总结
在本章中,我们讨论了在几乎没有或完全没有欺诈类别样本的情况下,构建信用卡交易欺诈检测器的方法。这一解决方案训练一个神经自编码器,将合法交易从输入重建到输出层。需要一些后处理步骤,通过重建误差为潜在欺诈行为设置警报。
在描述这个解决方案时,我们引入了训练与部署应用、组件、优化循环和开关块的概念。
在下一章,我们将讨论一种特殊类型的神经网络,即所谓的循环神经网络,以及它们如何用于训练处理序列数据的神经网络。
问题与练习
通过回答以下问题,检查你对本章概念的理解程度:
-
自编码器在训练过程中的目标是什么?
a) 将输入重建到输出
b) 学习自动编码
c) 对训练数据进行编码
d) 训练一个能够区分两个类别的网络
-
自编码器的常见应用场景有哪些?
a) 时间序列预测
b) 异常检测
c) 多类别分类问题
d) 回归问题
-
自编码器如何用于降维?
a) 通过训练一个输出层神经元数量少于输入层的网络
b) 通过训练一个自编码器并仅提取编码器
c) 通过构建一个自编码器并仅提取解码器
d) 通过构建一个隐藏神经元比输入和输出层更多的网络
第六章:第六章: 用于需求预测的递归神经网络
到目前为止,我们已经通过两种变体的全连接前馈神经网络积累了一些经验:通过将输入样本分配到一组预定义的类中来实现分类任务,或者尝试通过自编码器架构重建输入向量的形状。在这两种情况下,输出响应仅依赖于当前输入向量的值。在时刻
,输出响应,
,依赖于且仅依赖于时刻
的输入向量,
。网络没有对
之前的任何记忆,并且仅根据输入
生成
。
使用递归神经网络(RNNs),我们引入了时间组件
。我们将发现网络的输出响应,
,在时刻
依赖于当前输入样本,
,以及之前的输入样本,
,
,……
,网络对过去
样本的记忆依赖于网络架构。
我们首先介绍 RNN 的一般概念,然后在经典时间序列分析任务需求预测的领域中,介绍长短期记忆(LSTM)的具体概念。接着,我们将展示如何将网络输入不仅仅是静态向量,
,还包括向量序列,例如
,
,
,……
,这些序列跨越了
个过去输入信号的样本。这些基于训练集构建的输入向量(张量)序列将用于训练和评估基于 LSTM 的 RNN 的实际实现。
总结来说,本章将涵盖以下主题:
-
引入 RNN
-
需求预测问题
-
数据准备——创造过去
-
构建、训练和部署基于 LSTM 的 RNN
引入 RNN
让我们从 RNN 的概述开始。
RNNs是无法局限于前馈架构的神经网络家族。
重要提示
通过在前馈神经网络中引入自连接或反向连接——即递归连接——来获得 RNN。
在引入递归连接时,我们引入了时间的概念。这使得 RNN 可以考虑上下文;即通过捕捉信号的动态来记住过去的输入。
引入递归连接改变了神经网络的性质,从静态变为动态,因此适用于分析时间序列。事实上,RNNs 常用于解决涉及时间顺序序列的问题,例如时间序列分析、语言建模、自由文本生成、自动机器翻译、语音识别、图像描述等问题,这些问题都在研究给定信号的时间演化。
递归神经网络
如前一节所述,引入自连接或反向连接到前馈网络中会将其转变为 RNN。例如,考虑 图 6.1 中所示的简单前馈网络,查看其左侧的详细表示和右侧的紧凑表示:

图 6.1 – 左侧是简单的全连接前馈网络,右侧是其更紧凑的基于矩阵的表示
图 6.1 中网络的紧凑表示包括一个多维输入
、一个可能是多维的输出
、一个由包含神经元图标的框表示的隐藏层,以及从输入到隐藏层的两个权重矩阵
,以及从隐藏层到输出层的权重矩阵
。
现在我们向这个网络引入一个递归连接,将输出向量
反馈到输入层,除了原始输入向量
之外(图 6.2)。这个对网络架构的简单修改改变了网络的行为。之前,网络实现的函数仅仅是
,其中
是输入样本
被呈现给网络时的当前时间。现在,递归网络实现的函数变为
;也就是说,当前的输出不仅依赖于当前的输入,还依赖于上一步为上一个输入样本产生的输出。我们引入了时间的概念:

图 6.2 – 向前馈网络添加递归连接
多亏了这些循环连接,RNN 的输出也包含了一些输入信号的历史信息。因此我们说它们具有记忆功能。记忆跨度能追溯到多远取决于递归架构和其中包含的范式。因此,RNN 比前馈网络更适合分析序列数据,因为它们也能处理来自过去的信息。过去的输入信息通过输出反馈转化到输入层,经过循环连接。
问题现在变成了如何训练一个网络,使得其输出不仅依赖于当前输入,还依赖于先前的输出。正如你可以想象的那样,多年来已经提出了许多算法。最简单的算法,也是最常被采用的,就是反向传播通过时间(BPTT)(Goodfellow I, Bengio Y., Courville A., 深度学习,MIT 出版社,(2016))。
BPTT 的基础是展开网络的概念。为了理解展开的概念,让我们在训练过程中查看网络在不同时间点的情况,
:
-
在时刻
,我们有原始的前馈网络,具有权重矩阵
和
,输入为
和
,输出为
。 -
在时刻
,我们再次得到了原始的前馈网络,具有权重矩阵
和
,但这次的输入是
和
,输出是
。 -
在时刻
,我们再次得到了原始的前馈网络,具有权重矩阵
和
,但这次的输入是
和
,输出是
。 -
这对于输入序列中的
样本是持续进行的。
实际上,我们可以将原始前馈网络复制多次,使用静态权重矩阵
和
,复制的次数与输入序列中的样本数相同(图 6.3)。在时间
时,原始网络的每个副本将接收当前输入向量
和前一个输出向量
作为输入。更一般地,在每个时间
时,网络副本将产生一个输出
和一个相关的状态
。状态
是网络的记忆,并馈送到下一个静态网络副本,而
是每个网络副本的专用输出。在某些递归架构中,
和
是相同的。
让我们总结一下。我们有一个递归网络,具有以下特点:
-
由输入张量
提供,大小为
,由一系列
维向量组成 -
产生一个输出张量,
,大小为
,由一系列
维向量组成 -
生成一个状态张量,
,与输出张量
相关,用作网络记忆重要提示
这个递归网络也可以只是一个子网络,作为更大神经架构中的一个隐藏单元。在这种情况下,它由前一层的输出作为输入,并且它的输出构成了更大网络中下一层的输入。此时,
不是整个网络的输出,而只是这个递归单元的输出——即整个网络的中间隐藏状态。
在图 6.3中,我们提出了对图 6.2中简单递归网络的四个时间步展开:

图 6.3 – 随时间展开递归网络
到目前为止,我们已经将循环子网络转化为
个原始前馈网络的副本——也就是一个更大的静态前馈网络。尽管它可能非常庞大,但我们已经知道如何使用反向传播算法训练完全连接的前馈网络。因此,反向传播算法已经适应了展开过程,并用来训练得到的前馈网络。这就是基本的 BPTT 算法。多年来,也提出了许多 BPTT 算法的变种。
我们现在将深入了解最简单的循环网络,它由一个仅包含循环单元的单层网络组成。
循环神经单元
最简单的循环神经单元由一个仅包含单一隐藏层的网络组成,激活函数为
,并带有自连接。通过相同的时间展开过程,我们可以将这个单元表示为
个具有一个隐藏层且仅有一个单元的前馈网络的副本(图 6.4):

图 6.4 – 最简单的循环神经单元
在这种情况下,输出
也是网络的状态,它会反馈到输入中——也就是反馈到时间
时展开网络的下一个副本的输入中。
这个简单的循环单元已经展现出一些记忆功能,因为当前的输出也依赖于先前输入层呈现的样本。然而,它的架构过于简单,无法展示出显著的记忆跨度。当然,所需的记忆跨度取决于要解决的任务。一个经典的例子就是句子补全。
要完成一个句子,你需要知道句子的主题,而要知道主题,你需要了解句子中的前几个词。例如,分析句子 Cars drive on the …,我们意识到主题是 cars,然后唯一合逻辑的答案是 road。为了完成这个句子,我们只需要记住四个词。现在,我们来看看一个更复杂的句子,比如 I love the beach. My favorite sound is the crashing of the …。在这种情况下,可能的答案有很多,包括 cars、glass 或 waves。为了理解哪个是合逻辑的答案,我们需要回溯到句子中的 beach 这个词,回溯的距离是九个词。分析这个句子所需的记忆跨度是分析前一个句子所需记忆跨度的两倍多。这个简短的例子表明,有时需要更长的记忆跨度才能给出正确答案。
简单的循环神经单元提供了一些记忆,但通常不足以解决大多数需要的任务。我们需要更强大的东西,能够回溯更远的过去,而不仅仅是简单循环单元能做到的。这正是为什么引入了 LSTM 单元。
长短期记忆(LSTM)
LSTM 首次于 1997 年提出(Hochreiter, Sepp 和 Schmidhuber, Jürgen(1997),长短期记忆。神经计算,9. 1735-80。10.1162/neco.1997.9.8.1735,https://www.researchgate.net/publication/13853244_Long_Short-term_Memory)。它是一种更复杂的递归单元,使用了一个额外的隐藏向量——细胞状态或记忆状态,
,以及门的概念。
图 6.5 显示了展开的 LSTM 单元的结构(C. Olah,理解 LSTM 网络,2015,colah.github.io/posts/2015-08-Understanding-LSTMs/):

图 6.5 – LSTM 层
如你所见,不同副本的单元通过两个隐藏向量相连。顶部的那个是细胞状态向量,
,用于使信息在不同单元副本之间流动。底部的那个是单元的输出向量。
接下来,我们有三个门。门可以开启或关闭(或者部分开启/关闭),通过这种方式,它们决定了从隐藏向量中存储或删除什么内容。一个门由一个 Sigmoid 函数和逐元素相乘组成。实际上,Sigmoid 函数的输出值范围是 [0,1]。具体来说,
删除输入(即遗忘),而
让输入不变(即记住)。在
和
之间,可能会出现各种记忆和遗忘的细微差别。
这些 Sigmoid 层的权重(用于实现门)通过学习过程进行调整。也就是说,门通过反复猜测、反向传播误差,并通过梯度下降调整权重的迭代过程来学习何时允许数据进入、离开或被删除。LSTM 层的训练算法再次是反向传播算法的一个变体。
一个 LSTM 层包含三个门:遗忘门、输入门和输出门(图 6.5)。我们来仔细看看这些门。
遗忘门
最左边的第一个门,遗忘门,过滤掉细胞状态向量中的成分。基于当前输入向量中的值,
和上一单元的输出向量中的值,
,该门做出遗忘或记住的决策,如下所示:

这里,
是遗忘门的权重矩阵。
决策向量
然后与隐藏的细胞状态向量
逐元素相乘,决定从上一状态中记住什么内容(
)以及忘记什么内容(
)。
那么,现在的问题是,为什么我们要忘记呢?如果引入了 LSTM 单元来获得更长的记忆,为什么还需要忘记某些内容呢?举个例子,分析文本语料库中的一篇文档时;你可能需要忘记之前文档中的所有知识,因为这两篇文档可能没有关联。因此,对于每个新文档,记忆应该重置为 0。
即使在同一文本中,如果你移动到下一个句子并且文本的主语发生变化,并且随着新主语出现新的性别,那么你可能希望忘记之前主语的性别,为了准备接受新的性别,并相应地调整词性。
输入门
输入门的目标更为直接:它保留那些新的和有用的输入信息。这里,同样,sigmoid 门完全通过输入成分(
),完全阻止它们(
),或者根据它们对最终当前和未来输出的重要性做出某种调整。
这个决策再次通过以下方式实现:

这当然是使用新的一组权重,
,完成的。
输入门不会直接作用于先前的单元状态,
。相反,基于当前输入向量中的值,
,以及前一个单元的输出向量,
,通过一个 tanh 层创建一个新的单元状态候选,
。
结果如下:

再次使用另一组权重,
。
输入门现在决定哪些信息应添加到单元候选状态向量,
,应添加到单元状态向量,
。因此,候选状态,
,与输入门 sigmoid 层的输出,
,逐点相乘,然后添加到过滤后的单元状态向量,
。最终状态,
,就会得到如下结果:

我们在这里做了什么?我们将新的内容添加到了之前的单元状态向量中,
。假设我们要查看文本中的一个新句子,其中
是一个性别不同的主语。在遗忘门中,我们忘记了先前存储在单元状态向量中的性别。现在,我们需要填补空缺并将新的性别推入记忆中——也就是推入新的单元状态向量。
输出门
最后,输出门!我们有新的单元状态,
,将其传递到下一个单元副本;我们只需要输出当前时刻的某些内容,
。
同样,像所有其他门一样,输出门对输入向量的所有成分应用一个 Sigmoid 函数,
,以及先前的输出向量,
,以决定从新创建的状态向量,
,传递到最终输出向量,
时,应该阻止什么,传递什么。所有决策,
,然后与新创建的状态向量,
,逐点相乘,该状态向量通过
函数进行标准化,以确保其在
范围内:


这是一个新权重集,
,用于这个输出门。
在这种情况下,由 LSTM 递归单元生成的输出向量,
,和状态向量,
,是不同的,
,是
的过滤版本。
为什么我们需要单元状态与输出不同的结果呢?嗯,有时输出需要与记忆不同。例如,当单元状态应该将性别记忆传递给下一个单元副本时,输出可能需要产生主语的数量(复数或单数),而不是它的性别。
LSTM 层是一种非常强大的递归结构,能够保持大量前期输入的记忆。因此,这些层非常适合——并且常常用于解决——涉及有序数据序列的问题。如果有序数据序列是按时间排序的,那么我们就称之为时间序列。实际上,基于 LSTM 的 RNN 已被广泛应用并成功解决时间序列分析问题。时间序列分析中的经典任务之一是需求预测。在接下来的部分中,我们将探讨将基于 LSTM 的神经网络应用于需求预测问题的一个实例。
需求预测问题
那么我们继续,探讨一个需求预测问题,以及它如何被视为时间序列分析问题。
需求预测是一个与未来估计需求相关的任务。我们都同意,了解未来的情况会让生活变得更加轻松。这对于生活事件同样适用,比如洗衣机和冰箱的价格,或者整个城市的电力需求。知道客户明天或下周将需要多少瓶橄榄油,可以让零售商制定更好的补货计划。知道可能会增加对汽油或柴油的需求,可以帮助卡车公司更好地规划其财务。未来需求的这种知识在无数的实例中都能提供帮助。
需求预测
需求预测,或称需求预报,是数据科学的一个重要分支。它的目标是通过使用历史数据和可能的其他外部信息,来对未来需求进行估计。需求预测可以指任何类型的数字:餐馆的访客数、生成的千瓦时、学校的新注册人数、啤酒瓶、纸尿裤包、家电、时尚服装和配饰等等。需求预测可用于生产计划、库存管理,有时还用于评估未来的产能需求,或者在决策是否进入新市场时提供参考。
需求预测技术通常基于时间序列分析。某一特定产品、商品或服务的历史需求值被存储并按时间排序形成时间序列。当利用时间序列中的历史值来预测同一时间序列中的未来值时,我们称之为自回归分析技术。当来自其他外部时间序列的历史值也被用来预测时间序列中的未来值时,我们则称之为多元回归分析技术。
时间序列分析是数据科学的一个传统领域,它已经提供了多种经典技术。传统的预测技术源自统计学,它们的顶尖技术可以在自回归积分滑动平均(ARIMA)模型及其变种中找到。这些技术要求假设一些统计假设,难以验证,而且通常不现实。另一方面,它们对于过去数据的要求较少。
最近,随着机器学习算法的日益普及,一些基于数据的回归技术也被应用于需求预测问题。这些机器学习技术的优点是无需统计假设,且数据转换的开销较小。缺点是需要大量的数据。此外,需要注意的是,在所有必需的统计假设都得到验证的时间序列情况下,传统方法通常表现更好。
让我们尝试根据过去的
值预测时间序列中下一个
值。当使用机器学习模型进行时间序列分析时,例如线性回归或回归树,我们需要提供过去
个样本的向量作为输入,以训练模型预测下一个
值。虽然这种策略已经被广泛实施并取得了令人满意的结果,但它仍然是时间序列分析的静态方法——静态指的是每个输出响应仅依赖于对应的输入向量。输入样本的呈现顺序不会影响响应。没有输入序列的概念,只有输入向量的概念。
提示
KNIME Analytics Platform 提供了几个节点和标准组件来处理时间序列分析。这里的关键节点是后台 statsmodels Python 模块中的 EXAMPLES/00_Components/Time Series 文件夹。因此,它们需要安装 KNIME Python 集成(www.knime.com/blog/setting-up-the-knime-python-extension-revisited-for-python-30-and-20)。
在 图 6.6 中,你可以看到 KNIME Analytics Platform 中用于时间序列分析任务的可用组件列表:

图 6.6 – EXAMPLES/00_Components/Time Series 文件夹包含专门用于时间序列分析的组件
综合考虑,这些基于机器学习的策略,使用回归模型,并没有充分利用数据的顺序结构,其中!紧接着!带来了一些额外信息。正是在这里,RNN(递归神经网络),特别是 LSTM(长短时记忆网络),由于其内部的记忆,可能会在其他机器学习算法中提供优势。
现在,让我们引入本章的案例研究:预测每小时所需的 千瓦(kW)电力需求。
电力需求预测
作为需求预测的一个例子,我们想解决电力预测问题——即预测一个普通家庭消费者下一小时所需的千瓦数(kW)。
能源行业最棘手的问题之一是供需匹配。一方面,能源过度生产可能浪费资源;另一方面,生产不足可能导致人们无法获得现代生活所需的基本商品。因此,准确预测每一时刻的电力需求是数据科学中的一个重要课题。
正因为如此,几年前,能源公司开始通过智能电表监控每个家庭、商店或其他实体的电力消耗。爱尔兰能源监管委员会(CER)在 2009 年启动了一个试点项目。
智能电表电力客户行为试验(CBTs)于 2009 年到 2010 年之间进行,超过 5,000 个爱尔兰家庭和企业参与。试验的目的是评估智能电表对消费者电力消耗的影响,以便为全国推广的成本效益分析提供依据。参与试验的爱尔兰电力住宅和商业客户,以及博尔吉能源的商业客户,均在其家中或场所安装了智能电表,并同意参与研究,帮助确定智能电表如何有助于塑造不同人口群体、生活方式和家庭规模的能源使用行为。
原始数据集包含超过 5,000 个时间序列,每个时间序列测量每个安装的智能电表在略超过一年的时间内的电力使用情况。所有原始时间序列已被对齐并标准化,按小时报告能源数据。
最终目标是预测所有用户的能源需求。目前,我们面临一个困境:是为每个时间序列训练一个模型,然后将所有预测结果相加以得到下一个小时的需求,还是为所有时间序列训练一个单一模型,以获得下一个小时的全球需求?
在单一时间序列上训练一个模型较为简单,且可能更为准确。然而,训练 5,000 个模型(在实际情况中可能更多)可能会遇到一些技术问题。在所有时间序列上训练一个单一模型可能不那么准确。正如预期的那样,实施了一种折衷方案。智能电表已根据能源使用概况进行聚类,并计算出每个聚类的平均小时能源使用时间序列。现在的目标是计算每个聚类时间序列在下一个小时的能源需求,对其按聚类大小加权,然后将所有贡献加总,以得出下一个小时的总能源需求。
已经根据工作日与周末的能源使用差异、24 小时内的不同时间段以及平均小时消耗,检测到 30 个智能电表聚类。
有关此数据准备过程的更多细节,可以参考数据厨师 ETL 战斗:今天的数据可以做什么?主题:能源消耗时间序列的博客,网址为 www.knime.com/blog/EnergyConsumptionTimeSeries,以及大数据、智能能源与预测分析的白皮书,网址为 files.knime.com/sites/default/files/inline-images/knime_bigdata_energy_timeseries_whitepaper.pdf。
最终的数据集包含 30 个簇的平均能耗的 30 条时间序列。每个时间序列显示了一个给定簇的智能电表的电力使用情况:从商店(在工作日从早上 9 点到下午 5 点有较高的能耗)到夜间商业用户(每天晚上 9 点到第二天早上 6 点有较高的能耗),从家庭住户(在工作日早上 7 点到 9 点以及下午 6 点到 10 点之间有较高的能耗)到其他不明确的实体(在一周 7 天的 24 小时内均有能耗)。例如,第 26 簇指的是商店(图 6.7)。在这里,电能主要在所有工作日的早上 9 点到下午 5 点之间使用:

图 6.7 – 第 26 簇按小时划分的能耗图
相反,第 13 簇包括许多餐厅(图 6.8),其能耗主要集中在晚上,从每周的每天 6 点到午夜。

图 6.8 – 第 13 簇按小时划分的能耗图
注意,第 26 簇是时间序列分析的典型例子,具有明显的季节性特征,包括一天 24 小时和一周 7 天的周期性变化。在本章中,我们将继续对第 26 簇的时间序列进行自回归分析。我们的目标是基于过去的平均能耗来预测下一小时的平均能耗!,并且这个预测将适用于第 26 簇。
现在,我们已经有了一组描述用户簇按小时使用电能的时间序列数据,我们将尝试对每个簇的未来使用情况进行预测。首先,让我们聚焦于这个时间序列问题的数据准备工作。
数据准备 – 创建过去的数据
现在让我们实际实现一个需求预测应用,使用第 26 簇的时间序列数据。我们将有两个独立的工作流程:一个用于训练基于 LSTM 的 RNN,另一个用于将其部署到生产环境中。两个应用程序都会包括一个数据准备阶段,且该阶段在两者中必须完全相同。在本节中,我们将介绍这个数据准备阶段。
处理时间序列时,数据准备步骤与其他分类或聚类应用中的实现略有不同。让我们逐步了解这些步骤:
-
数据加载:从文件中读取 30 个已识别簇的每小时平均能耗的时间序列及相应的时间。
-
日期和时间标准化:时间通常是以字符串的形式从文件中读取的。为了确保它能够被适当地处理,最好的做法是将其转换为日期和时间对象。有许多节点可以以适当且简单的方式处理日期和时间对象,尤其是以标准化的方式。
-
时间戳对齐:一旦时间序列被加载,我们需要确保它的采样是一致的,没有时间空缺。可能的时间空缺需要用缺失值填充。我们还需要确保时间序列的数据是按时间排序的。
-
分割:在这里,我们需要创建一个训练集来训练网络,以及一个测试集来评估其性能。与分类问题不同,这里我们需要遵循时间顺序,以避免在同一数据集中混淆时间序列的过去和未来。过去的样本应保留用于训练集,未来的样本用于测试集。
-
缺失值填补:时间序列的缺失值填补与静态数据集的缺失值填补也不同。由于后续的内容依赖于之前的内容,大多数时间序列的缺失值填补技术都是基于先前和/或后续样本的值。
-
创建过去样本的输入向量:一旦时间序列准备好进行分析,我们需要构建张量以供网络使用。这些张量必须包含
过去样本,网络将使用这些样本预测下一个时间点的值。因此,我们需要为所有训练和测试记录生成
过去的
维向量(这些
过去的样本)。 -
创建供网络使用的列表:最后,过去样本的输入张量必须转换为值的列表,因为这是网络所需的输入格式。
让我们从数据加载开始。
数据加载和标准化
数据集是通过CSV文件通过文件读取器节点读取的:30 个时间序列和一个日期列。日期列由文件读取器节点作为字符串导入,必须转换为 Date&Time 对象,以确保它在接下来的步骤中被适当地处理——例如,排序。Date&Time是 KNIME Analytics 平台中表示日期和时间实体的内部标准对象。为了将字符串转换为 Date&Time 对象,我们使用字符串到日期和时间节点:

图 6.9 – 字符串到日期和时间节点及其配置窗口
在配置窗口(图 6.9)中,您必须选择包含日期和/或时间信息的字符串输入列,并定义日期/时间格式。您可以手动进行此操作,提供一个字符串格式——例如,dd.mm.yyyy,其中dd表示天,mm表示月,yyyy表示年。
例如,如果你的日期格式是day(2).month(2).year(4),你可以手动添加选项dd.MM.yyyy,如果该格式在日期格式选项中不可用。当手动添加日期/时间类型时,必须选择合适的新类型选项:日期或时间或日期&时间。
另外,你也可以通过点击自动猜测数据类型和格式按钮来自动提供日期/时间格式。选择此选项时,KNIME 分析平台会解析你的字符串以找出日期/时间格式。它通常能正常工作!如果无法识别格式,你总是可以手动输入日期/时间格式。
提示
在字符串到日期&时间节点的节点描述中,你可以找到格式结构中可能使用的占位符概述。最重要的占位符包括y表示年份,M表示年份中的月份,d表示月份中的日期,H表示一天中的小时(0 到 23 之间),m表示小时中的分钟,s表示分钟中的秒。还支持更多占位符——例如,W表示月份中的周数,D表示一年中的天数。
“字符串到日期&时间”节点只是众多处理日期&时间对象的节点之一,所有这些节点都位于其他数据类型/时间序列文件夹中,位于节点库面板内。一些节点用于操作日期&时间对象,例如计算时间差或生成时间偏移;而其他节点则用于将日期&时间对象从一种格式转换为另一种格式。
之后,插入“列过滤器”节点,以便仅隔离集群 26 的时间序列。这里唯一需要标准化的是将日期从字符串转换为日期和时间对象。我们现在可以继续进行数据清理了。
数据清理与分区
时间戳对齐组件被插入以检查时间序列中的时间空缺。此组件检查所选的时间戳列是否在选定的时间尺度上均匀采样。缺失的值将在跳过的采样时间点插入。在这种情况下,它检查包含时间戳的rowID列是否在按小时采样时存在缺失的采样时间。
时间戳对齐组件是EXAMPLES/00_Components/Time Series文件夹中专门针对时间序列的组件集合的一部分。要在工作流中创建一个实例,只需将其拖放到工作流编辑器中或双击它。
之后,我们将数据划分为训练集和测试集,用于训练基于 LSTM 的 RNN 并进行评估。这里我们没有提供额外的验证集来评估网络在训练过程中的表现。我们决定保持简单,只向 Keras 网络学习节点提供训练集,测试集用于测量时间序列预测任务的误差:

图 6.10 – 分区节点及其配置窗口。注意用于时间序列分析的从顶部提取数据模式
为了将输入数据集划分为训练集和测试集,我们再次使用分区节点。在这里,我们决定实现 80%–20%的划分:80%的输入数据将用于训练,20%用于测试。此外,我们将提取程序设置为从顶部提取(图 6.10)。在时间序列分析问题中,我们希望保持数据的固有时间顺序:我们使用过去的数据来训练网络,用未来的数据来测试网络。当使用从顶部提取的数据提取选项时,数据的顶部百分比将被分配到顶部输出端口,而底部剩余部分将分配到底部输出端口。如果数据按照时间顺序从过去到未来排列,则这种数据提取模式能够保持数据的时间顺序。
重要提示
在时间序列分析问题中,分区应该使用从顶部提取数据提取模式,以便保持数据的时间顺序,并用过去的数据进行训练,未来的数据进行测试。
对于每个数据集,缺失值插补操作都非常重要;首先,因为神经网络无法处理缺失值,其次,因为选择正确的缺失值插补技术可能会影响最终结果。
重要提示
缺失值插补必须在时间戳对齐组件之后实现,因为该组件定义上会创建缺失值。
在第四章《构建和训练前馈网络》中,我们已经介绍了缺失值节点及其不同的缺失值插补策略。这些策略中的一些在处理序列数据时特别有用,因为它们考虑了时间序列中的前后值。可能的策略如下:
-
平均/线性插值,用前后样本的平均值替代缺失值
-
移动平均,用样本窗口的均值替代缺失值
-
下一个,用下一个样本的值替代缺失值
-
前一个,用前一个样本的值替代缺失值
我们选择了在前后值之间进行线性插值来插补时间序列中的缺失值(图 6.11):

图 6.11 – 缺失值节点及其配置窗口
用于缺失值插补的公式是在训练数据上的Missing Value节点计算的,应用于测试数据时使用Missing Value (Apply)节点,并通过模型写入节点保存到文件。仅在测试集上应用定义在训练集上的公式,能够防止测试数据干扰任何模型训练所需的转换实现。
接下来,让我们关注神经网络输入张量的创建。
创建输入张量
我们已经读取了数据,将日期单元格转换为 Date&Time 对象,隔离了集群 26 的时间序列,为缺失的采样步骤分配了缺失值,将数据划分为 80% 的训练集和 20% 的测试集,使用线性插值法填补缺失值。数据已经准备好,现在是时候为神经网络创建输入张量了。
重要说明
一个在时间序列分析中经常需要创建过去样本向量的关键节点是 Lag Column 节点。
图 6.12 显示了 Lag Column 节点及其配置窗口:

图 6.12 – Lag Column 节点及其配置窗口
Lag Column 节点会生成所选列的副本,并将它们下移一个数量的单元格,
,其中
是 Lag 间隔,
是配置窗口中的Lag设置。
Lag Column 节点是一个非常简单但非常强大的节点,在很多情况下都非常有用。如果输入列已经按时间排序,那么下移单元格的操作就相当于将数据移动到过去或未来,具体取决于时间顺序。
在图 6.13中,我们解释了这个概念:

图 6.13 – Lag Column 节点根据 Lag 和 Lag 间隔设置,在不同时间拍摄同一列的快照
考虑 Lag = 4 和 Lag 间隔 = 2,Lag Column 节点会生成四个所选列的副本,每个副本按 2 的步长向后移动。也就是说,除了当前时间 t 的所选列外,我们还将拥有四个快照,分别是在时间 t-2、t-4、t-6 和 t-8 时的同一列(图 6.13)。
对于我们的需求预测问题,我们使用了过去 200 小时内集群 26 平均能耗的值来预测当前小时的平均能耗。也就是说,我们构建了一个包含过去 200 个小时样本的输入向量,使用了 Lag Column 节点,Lag=200 和 Lag 间隔=1(图 6.12)。
出于空间考虑,我们将单元格向量转换为单元格集合,使用Column Aggregator节点,因为它是通过 Keras Network Learner 节点将数据馈送到神经网络的可能格式之一。Column Aggregator 节点是另一种生成列表数据单元格的方式。该节点按行对选定列进行分组,并使用选定的聚合方法对其单元格进行聚合。在本例中,选择并应用了List聚合方法,将其应用于通过 Lag Column 节点创建的群集 26 的 200 个过去值。
实现数据准备部分,以便为即将到来的 RNN 进行需求预测任务的工作流片段,如图 6.14所示:

图 6.14 – 需求预测的数据准备:日期和时间标准化、时间对齐、缺失值填补、创建过去样本的输入向量以及数据分割
数据已经准备好。现在让我们构建、训练并测试基于 LSTM 的 RNN,以预测群集 26 在当前小时的电能平均需求,给定群集 26 在过去 200 小时的平均能耗。
构建、训练和部署基于 LSTM 的 RNN
让我们继续下一步:构建一个简单的基于 LSTM 的 RNN 进行需求预测。首先,我们将训练网络,然后测试它,最后部署它。在这个案例研究中,我们没有为网络使用验证集,并且没有对网络的静态超参数进行优化,例如 LSTM 层的大小。
一个相对简单的网络已经在我们的需求预测任务的测试集上取得了良好的误差度量,因此,我们决定将本节重点放在如何测试时间序列预测模型,而不是如何优化神经网络的静态参数。我们查看了第五章,用于欺诈检测的自编码器中的优化循环。通常,这个优化循环也可以应用于优化网络的超参数。现在,让我们开始构建基于 LSTM 的 RNN。
构建基于 LSTM 的 RNN
对于这个案例研究,我们选择了最简单的基于 LSTM 的 RNN:一个只有一个隐藏 LSTM 层的 RNN。因此,最终的网络包括以下内容:
-
一个输入层,接收 200 个过去的向量的张量——每个过去的向量仅为前一个样本,即大小为 1——通过 Keras 输入层节点获取,形状为 200, 1。
-
一个具有 100 个 LSTM 单元的隐藏层,通过Keras LSTM Layer节点接受先前的张量作为唯一输入
-
一个经典的全连接层作为输出,只有一个神经元生成预测的下一个时间序列样本的值,该值是通过使用带有 ReLU 激活函数的 Keras 全连接层节点得到的。
用于构建此神经网络架构的节点如图 6.15所示:

图 6.15 – 构建一个非常基础、非常简单的基于 LSTM 的 RNN
重要提示
输入张量的大小为[200,1],这是一个包含 200 个大小为 1 的向量的序列。如果输入序列的长度未知,我们可以使用?表示未知的序列长度。下一章的 NLP 案例研究将向你展示一些相关的示例。
我们在之前的章节中已经描述了 Keras 输入层节点和 Keras 全连接层节点。在这一节中,我们将专门探讨 Keras LSTM 层节点。
重要提示
到目前为止,我们谈到输入、细胞状态和输出时使用了“向量”这个术语。张量是一种更广义的形式,表示沿着k维度拉伸的向量。秩为 0 的张量等于标量值,秩为 1 的张量等于向量,秩为 2 的张量等于矩阵。
请注意,Keras LSTM 层节点最多接受三个输入张量:一个是序列的输入值,两个用于初始化隐藏状态张量,
和
。
如果前一层神经网络输出多个张量,在当前 LSTM 层的配置窗口中,你可以通过下拉菜单选择哪个张量作为输入或用于初始化隐藏状态。
我们将在接下来的章节中探讨更复杂的神经网络架构。在这里,我们将架构限制为最简单的经典 LSTM 层配置,只接受来自输入层的一个输入张量。可以在图 6.16的 LSTM 层节点配置窗口中看到该输入张量:

图 6.16 – Keras LSTM 层节点及其配置窗口
对于 LSTM 层,我们可以设置两个激活函数,分别称为激活和递归激活。递归激活函数由门控机制用来过滤输入的成分。选定的激活函数用于创建细胞状态的候选值,
,并在应用输出门之前对新的细胞状态进行标准化,
。这意味着,对于我们在本章介绍的标准 LSTM 单元,激活的设置为 tanh 函数,递归激活的设置为 sigmoid 函数。
我们设置了该层为 LSTM 单元的不同层添加偏置,但决定不使用 dropout。
实现和展开设置选项不会影响结果,但可以根据硬件和序列长度提高性能。当激活展开复选框时,网络将在训练之前被展开,这可以加速学习过程,但它占用大量内存,只适合短输入序列。如果未选中,则会在 TensorFlow 后端使用所谓的符号循环。
你可以选择是否将中间输出张量
作为完整序列返回,还是只返回最后一个输出张量
(返回序列选项)。此外,你还可以选择将隐藏单元状态张量作为输出(返回状态选项)。在能源需求预测的案例研究中,仅使用 LSTM 单元的最终输出张量来馈送下一层具有 ReLU 激活函数的全连接层。因此,这两个复选框没有被激活。
节点配置窗口中的其他三个标签设置了正则化项、初始化策略和学习算法的约束条件。在这一层中,我们没有设置正则化和约束条件。现在开始训练这个网络。
训练基于 LSTM 的 RNN
然后,Keras 网络学习器节点继续在训练集上训练这个基于 LSTM 的 RNN。我们已经了解过这个节点。这里总结一下该案例研究中其配置窗口的规格:
-
输入张量通过转换为从数字集合(双精度)来接收。
-
输出向量通过转换为数字(双精度)生成。
-
损失函数在目标标签页中设置为均方误差(MSE)。
-
训练的迭代次数设置为
50,训练批次大小设置为256,训练算法设置为Adam——一种反向传播的优化版本——在选项标签页中。 -
学习率设置为
0.001,没有学习率衰减。
对于这个网络,输出层只有一个神经元时,MSE 损失函数在训练批次中的形式变得更简单,变为以下形式:

这里,
是批次大小,
是训练样本
的输出值,而
是对应的目标答案。
由于我们讨论的是数字预测,并且使用均方误差(MSE)作为损失函数,学习监控器视图中的损失标签页中的图表是用来评估学习过程的。由于我们尝试预测精确的数字,因此在这种情况下,准确度并不具备实际意义。图 6.17展示了此需求预测示例中 Keras 网络学习器节点的学习监控器视图:

图 6.17 – 在学习监视器视图的损失标签中,训练轮次期间 MSE 损失函数的绘图
图 6.17中的截图显示,经过几次批量训练迭代后,我们在训练集上至少达到了一个可接受的预测误差。训练完成后,应将网络应用于测试集,使用Keras 网络执行器节点,并使用Keras 网络写入器节点将其保存为 Keras 文件以供部署。
现在,让我们将训练好的 LSTM 网络应用到测试集上。
测试基于 LSTM 的 RNN
理论上,要测试网络的性能,我们只需将网络应用于测试集中的输入张量。这可以通过Keras 网络执行器节点轻松完成。
图 6.18展示了样本内测试组件内部:

图 6.18 – 样本内测试组件内部
样本内测试组件选择要测试的输入序列的数量(行过滤器节点),然后通过Keras 网络执行器节点处理它们,并将预测结果与相应的目标答案合并。
之后,在样本内测试组件之外,数值评分器节点计算一些误差度量,线图(Plotly)节点展示原始时间序列和重构后的时间序列(最终工作流程见图 6.25)。数值误差度量量化了误差,而线图则直观地展示了预测结果的忠实度。采用这种方法生成的预测称为样本内预测。
数值评分器节点计算六个误差度量(图 6.19):R2,平均绝对误差(MAE),MSE,均方根误差(RMSE),平均符号差异(MSD)和平均绝对百分比误差(MAPE)。对应的公式如下所示:






这里,
是来自测试集的预测数量,
是测试样本的输出值
,而
是对应的目标答案。我们选择在一个包含 600 个张量的测试集上应用该网络,生成相应的预测结果,并计算误差度量。以下是我们得到的结果:

图 6.19 – 样本内预测的 600 个值与对应目标值之间的误差度量
每个度量标准都有其优缺点。常用的时间序列预测误差包括 MAPE、MAE 或 MSE。例如,MAPE 在预测的时间序列的接下来的 600 个值上显示出仅 9%的误差,这是一个非常好的结果。图 6.20中的图表证明了这一点:

图 6.20 – 时间序列中接下来的 600 个样本预测值与目标值的比较
这是一个简单的测试。对于每一个要预测的值,我们将历史真实值输入网络。这是一个奢侈的情况,我们并不总是能承担。通常,我们仅根据过去预测的值预测接下来的 600 个值,一次一个。也就是说,一旦我们训练好网络,我们就用测试集中的前 200 个真实过去值触发下一次预测。然而,在此之后,我们将基于最新的 199 个真实值和当前预测值预测下一个值;然后再基于最新的 198 个真实值、之前预测的值以及当前预测的值进行预测,依此类推。这是一个次优的,但更现实的情况。使用这种方法生成的预测称为外样本预测,这种测试方式被称为外样本测试。
为了实现外样本测试,我们需要实现一个将当前预测反馈到过去样本向量中的循环。这个循环也在部署工作流中得到了实现。让我们来看一下这个实现的细节。
构建部署循环
为了实现外样本测试,我们需要实现上一节中描述的循环,其中当前预测值成为下一个预测的过去值张量的一部分。这是在名为部署循环的组件中完成的(图 6.21),该组件也位于最终工作流中的外样本测试组件内(图 6.25):

每次迭代中的新输入序列](https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/cdls-dl-knime/img/B16391_06_021.jpg)
图 6.21 – 部署循环。注意递归循环将新输入序列传回每次迭代
这里,no_preds 被创建为no_preds=600)。
Integer Configuration 节点属于一个特殊的配置节点组,因此其配置窗口会转移到包含它的组件的配置窗口中。因此,部署循环组件具有一个配置设置,用于设置递归循环中要生成的预测次数,如图 6.22所示:

图 6.22 – 部署循环组件的配置窗口
重要说明
递归循环是 KNIME 分析平台中少数几个允许将结果传回并在下一次迭代中使用的循环之一。
部署循环组件使用了两个新的重要节点:
-
Keras 到 TensorFlow 网络转换节点:Keras 到 TensorFlow 转换节点将一个带有 TensorFlow 后端的 Keras 深度学习模型转换为 TensorFlow 模型。TensorFlow 模型使用 TensorFlow Java API 执行,这通常比通过 Keras Python API 提供的 Python 内核要更快。如果在递归循环中使用 Keras 网络执行节点,那么每次迭代都必须启动一个 Python 内核,这会导致网络执行变慢。使用 TensorFlow 模型能显著加快网络执行速度。
-
TensorFlow 网络执行节点:TensorFlow 网络执行节点的配置窗口与 Keras 网络执行节点的配置窗口类似,唯一的区别是后端引擎,在这种情况下是 TensorFlow。
对于外样本测试,部署循环通过测试集中的第一个张量触发,从那里开始自动生成 600 个预测。在外样本测试组件中,这些预测会与目标值结合,而在外样本测试组件之外,数值误差节点会计算选定的误差指标。
显然,对于外样本测试,误差值变大了(图 6.23),因为预测误差受到前几步预测误差的影响。例如,MAPE 达到 18%,几乎是样本内测试结果的两倍:

图 6.23 – 外样本预测的 600 个值与相应目标值之间的误差度量
在图 6.24中,我们可以看到在可视化预测的时间序列并将其与原始时间序列进行比较时,前 600 个外样本预测的预测误差:

图 6.24 – 时间序列中接下来的 600 个外样本预测值(橙色)与接下来的 600 个目标值(蓝色)对比
在那里,我们可以看到第一次预测相当准确,但随着我们远离测试集的起点,预测开始变差。当然,这种效果在样本内预测中是不存在的。实际上,第一次外样本预测的误差值与相应样本内预测的误差值相当。
我们这里进行了一个相对粗略的时间序列预测,因为我们没有将季节性预测作为一个独立的问题来考虑。我们某种程度上让网络自行管理整个预测过程,而没有将季节性和残差分开。对于这个用例,结果是令人满意的。然而,对于更复杂的用例,可以计算季节性指数,扣除季节性部分,并仅对时间序列的残差值进行预测。希望这样的问题会更简单,并且会带来更准确的预测。不过,考虑到网络还需要处理季节性预测,我们对预测误差还是感到满意的。
最终的工作流,包括构建、训练和样本内测试网络,如图 6.25所示:

图 6.25 – 为时间序列预测问题准备数据、构建、训练并测试基于 LSTM 的网络的最终工作流
这个工作流可以在本书的 GitHub 空间中找到。接下来,我们将讨论部署工作流。
部署 LSTM 基于 RNN 的模型
在这一点上,部署非常简单。我们读取部署数据,例如从.table文件中;然后,按照与训练数据和测试数据相同的步骤进行数据准备。我们隔离出前 200 个过去的样本作为输入序列;我们应用部署循环生成
新样本(这里我们选择了
);我们在部署循环中应用训练好的基于 LSTM 的 RNN;最后,我们通过一个线图(Plotly)节点来可视化预测结果。请注意,这次没有预测与目标值的对比,因为部署数据是真实世界数据,而非实验室数据,因此没有目标值可以进行对比。
部署工作流如图 6.26所示,并可以在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%206/

图 6.26 – 需求预测问题的部署工作流
这是部署工作流,包括数据读取、与训练工作流中数据相同的数据准备、网络读取和部署循环生成预测。
在最后一节中,我们学会了如何将部署循环应用到部署工作流中,以生成现实生活中的新预测。
总结
在本章中,我们介绍了一种新的递归神经单元:LSTM 单元。我们展示了它是如何构建和训练的,以及如何将其应用于时间序列分析问题,如需求预测。
作为一个需求预测问题的例子,我们尝试预测一个用户群体在接下来一小时内的平均能耗,前提是给定过去 200 小时的能耗数据。我们展示了如何进行样本内和样本外预测测试,以及一些常用的数值衡量方法来量化预测误差。需求预测应用于能耗仅仅是众多需求预测用例中的一个。这里学到的相同方法也可以应用于预测餐厅的顾客数量、网站的访客数量,或超市中某种食品的需求量。
在本章中,我们还介绍了 KNIME Analytics Platform 中的一种新循环——递归循环,并提到了一个新的可视化节点——线性图(Plotly)节点。
在下一章中,我们将继续讲解 RNN,重点讨论不同的文本相关应用。
问题与练习
通过回答以下问题,检查你对本章所探讨概念的理解程度:
-
为什么 LSTM 单元适用于时间序列分析?
a). 因为它们比经典的前馈网络更快
b). 因为它们能记住过去的输入张量
c). 因为它们使用门控
d). 因为它们具有隐藏状态
-
时间序列分析中,进行数据分割时应使用哪种数据提取选项?
a). 随机绘制
b). 从顶部开始
c). 分层抽样
d). 线性抽样
-
什么是张量?
a). 张量是一个二维向量。
b). 张量是一个k维向量。
c). 张量仅仅是一个数字。
d). 张量是一个数字序列。
-
样本内测试和样本外测试有什么区别?
a). 样本内测试使用来自测试集的真实过去值进行预测。样本外测试则使用过去的预测值来进行新的预测。
b). 样本内测试比样本外测试更具现实性。
c). 样本内测试比样本外测试更复杂。
d). 样本内测试应用经过训练的网络,而样本外测试使用规则。
第七章:第七章: 实现 NLP 应用
在第六章《需求预测的循环神经网络》中,我们介绍了循环神经网络(RNN)作为一种特别擅长分析顺序数据的神经网络家族。作为案例研究,我们训练了一个基于长短期记忆(LSTM)的 RNN 来预测消耗的电能时间序列中的下一个值。然而,RNN 不仅仅适用于严格的数字时间序列,它们也成功地应用于其他类型的时间序列。
RNN 的另一个先进应用领域是自然语言处理(NLP)。实际上,RNN 已成功应用于文本分类、语言模型和神经机器翻译等任务。在所有这些任务中,时间序列是由单词或字符组成的序列,而不是数字。
本章我们将简要回顾一些经典的 NLP 案例研究及其基于 RNN 的解决方案:情感分析应用、自由文本生成解决方案,以及为新产品生成名称候选的类似解决方案。
我们将首先概述文本编码技术,以准备将单词/字符序列输入我们的神经网络。第一个案例研究将文本根据其情感进行分类。接下来的两个案例研究分别生成新的文本序列和新的单词序列,新的单词则由新字符序列构成。
本章我们将涵盖以下主题:
-
探索神经网络的文本编码技术
-
找到客户声音的语气——情感分析
-
使用 RNN 生成自由文本
-
使用 RNN 生成产品名称
探索神经网络的文本编码技术
在第四章《构建与训练前馈神经网络》中,你学习了前馈网络——以及所有其他神经网络——是通过数字进行训练的,并不理解名义值。在本章中,我们希望将单词和字符输入神经网络。因此,我们需要引入一些技术,将单词或字符序列——也就是名义值的序列——编码为数字序列或数值向量。此外,在使用 RNN 的 NLP 应用中,必须确保在整个文本编码过程中保持单词或字符序列的顺序。
在深入 NLP 案例研究之前,让我们先看一下几种文本编码技术。
索引编码
在第四章《构建与训练前馈神经网络》中,你学习了针对名义值的索引编码。其思想是用整数值表示每个名义类,这个整数值也叫做索引。
我们可以使用相同的思路进行文本编码。在这里,我们不是用不同的索引来编码每个类别,而是用不同的索引来编码每个单词或每个字符。首先,必须创建一个字典,将文本集合中的所有单词/字符映射到一个索引;然后,通过这个映射,每个单词/字符被转换成其对应的索引,从而将每个单词/字符序列转换成相应索引的序列。最终,每个文本被表示为一个索引序列,其中每个索引编码了一个单词或一个字符。下面的图给出了一个例子:

图 7.1 – 基于索引的单词级文本编码示例
注意,在序列中,单词the的索引 1 和单词brown的索引 13 在序列中被重复了两次,因为这两个单词在示例句子the quick brown fox jumped over the brown dog中各出现了两次。
在本章后面,在找到客户声音的语气 – 情感分析一节中,我们将使用基于索引的编码来表示文本中的单词。
另一方面,在使用 RNN 进行自由文本生成一节中,我们将使用独热向量作为字符级文本编码。让我们来探索什么是独热向量编码。
独热向量编码
索引序列的缺点在于,它在单词/字符之间引入了人为的距离。例如,如果apple被编码为 1,shoe为 2,pear为 3,那么apple和pear之间的距离是 2,而shoe和pear之间的距离是 1,这在语义上可能并不合理。通过这种方式,由于单词没有顺序结构,我们会人为地在单词之间引入一些可能在实际中并不存在的距离/相似性。我们在第四章《构建和训练前馈神经网络》中也遇到了这个问题,并通过引入独热向量的概念来解决它。
使用1来编码特定的单词/字符,否则使用0。这意味着每个单词/字符都被表示为一个独热向量,因此,每个文本是一个独热向量的序列。下图展示了句子the quick brown fox jumped over the brown dog的独热向量编码示例。
请注意,在图 7.2中,单词the和brown的独热向量在序列中被重复了两次:

图 7.2 – 基于独热向量的单词级文本编码示例
提示
记住,Keras Learner节点可以将基于索引的编码转换为独热向量。因此,要训练一个神经网络来处理独热向量,只需将文本文档的基于索引的编码输入即可。
一种常用的文本编码——类似于独热向量,但不保留单词顺序——是1)或缺失(0)的单词。一个向量表示一个文本文档,包含多个 1。请注意,这种编码不保留单词顺序,因为所有文本都被编码在同一个向量结构中,而不管单词的顺序如何。
在处理单词时,独热编码向量的维度等于词典大小——也就是说,等于文档语料库中可用单词的数量。如果文档语料库很大,词典大小会迅速变成整个语言中的单词数量。因此,在单词级别上的独热编码可能会导致非常大且稀疏的表示。
在处理字符时,词典大小是字符集的大小,即使包括标点符号和特殊符号,这也比前一种情况小得多。因此,独热向量编码适合字符编码,但在单词编码时可能导致维度爆炸。
要在单词级别对文档进行编码,一种更合适的方法是使用嵌入技术。
词编码的嵌入技术
词嵌入的目标是将单词映射到几何空间中。通过为词典中的每个单词关联一个数值向量来实现这一点,使得具有相似含义的单词具有相似的向量,并且任何两个向量之间的距离捕捉了这两个相关单词之间的某些语义关系。由这些向量构成的几何空间被称为嵌入空间。对于单词编码,嵌入空间的维度比独热编码的向量空间要低(通常只有几十或几百),而独热编码的向量空间维度则通常达到几千。
为了学习每个单词在连续向量空间中的投影,使用了一个专门的神经网络层,这个层被称为嵌入层。这个层学习将每个单词与一个向量表示关联起来。最著名的词嵌入技术是Word2vec和GloVe。
词嵌入可以有两种使用方式(J. Brownlee,如何在 Keras 中使用词嵌入层进行深度学习,机器学习精通博客,2017 年,machinelearningmastery.com/use-word-embedding-layers-deep-learning-keras/):
-
采用一个已经在某些外部文本语料库上训练好的现成层
-
将新的嵌入层作为神经网络的一部分进行训练
如果与神经网络联合训练,嵌入层的输入是一个基于索引的编码序列。嵌入层中的输出单元数量定义了嵌入空间的维度。嵌入层的权重用于计算每个索引的嵌入表示,因此也是每个单词的嵌入表示,这些权重在网络训练过程中学习得到。
现在我们已经熟悉了不同的文本编码技术,接下来让我们进入第一个自然语言处理应用案例。
寻找客户声音的语气 – 情感分析
自然语言处理的一个常见用例是 情感分析。在这里,目标是识别文本中的潜在情感,无论是正面、负面,还是介于两者之间的各种细微差别。情感分析已被应用于许多领域,如分析来电信息、电子邮件、评论、录音对话及其他类似文本。
通常,情感分析属于更大范围的自然语言处理(NLP)应用组,被称为文本分类。在情感分析的情况下,目标是预测情感类别。
另一个常见的文本分类示例是语言检测。在这种情况下,目标是识别文本的语言。在这两种情况下,如果我们使用 RNN 来处理任务,我们需要采用 多对一架构。多对一神经网络架构接受不同时间的输入序列,
,并利用输出单元的最终状态来预测单一类别——即情感或语言。
图 7.3 显示了一个多对一架构的示例:

图 7.3 – 一个多对一神经网络架构的示例:一系列在不同时间的输入,仅使用输出的最终状态
在本章的第一个用例中,我们想要分析电影评论的情感。目标是训练一个基于词级别的 RNN,并结合嵌入层和 LSTM 层。
在这个示例中,我们将使用 IMDb 数据集,该数据集包含两列:电影评论的文本和情感标签。情感标签用 1 表示正面评论,用 0 表示负面评论。
图 7.4 显示了一个小子集,其中包含一些正面和一些负面的电影评论:

图 7.4 – IMDb 数据集的摘录,显示了标记为正面和负面的评论
让我们从读取和编码电影评论文本开始。
电影评论的预处理
嵌入层期望基于索引的编码输入序列。也就是说,每条评论必须编码为一个索引序列,其中每个索引(整数值)代表字典中的一个词。
由于 IMDb 文档语料库中的可用词汇量非常大,我们决定在文本预处理阶段对其进行简化,方法是去除停用词并将所有词语还原为词干。此外,仅将训练集中的最频繁术语用专用索引进行编码,而其他所有术语则使用默认索引。
理论上,RNN 可以处理可变长度的序列。然而,在实践中,一个训练批次中的所有输入样本的序列长度必须相同。由于每个评论中的词汇数量可能不同,我们定义了固定的序列长度,并对过短的序列进行零填充 —— 即,我们添加 0 来补充序列 —— 并截断过长的序列。
所有这些预处理步骤都应用于训练集和测试集,唯一的区别在于:在训练集的预处理中,会创建一个包含最频繁词汇的字典。这个字典仅在测试集的预处理过程中使用。
总结一下,我们执行以下预处理步骤:
-
读取并将数据集划分为训练集和测试集。
-
对训练集和测试集中的电影评论进行分词、清理和词干提取。
-
创建所有术语的字典。训练集中最频繁的术语由专用索引表示,所有其他术语由默认索引表示。
-
将训练集和测试集中的词汇映射到相应的字典索引。
-
截断训练集和测试集中过长的词序列。
-
对训练集和测试集中的过短序列进行零填充。
图 7.5 中的工作流执行了所有这些步骤:

图 7.5 – 情感分析案例研究的预处理工作流片段
第一个元节点读取并划分数据读取包含电影评论和情感信息的表格,并将数据集划分为训练集和测试集。预处理训练集元节点对训练集执行不同的预处理步骤,创建并应用字典,该字典会通过第二个输出端口提供。最后一个元节点预处理测试集将创建的字典应用于测试集,并对测试集执行不同的预处理步骤。
让我们看看这些步骤是如何在 KNIME Analytics Platform 中实现的。
读取和划分数据集
第一步,读取和划分数据集,由读取并划分数据元节点执行。
图 7.6 显示了元节点内部的工作流片段:

图 7.6 – 读取并划分元节点内部的工作流片段
表格读取器节点读取包含情感信息的表格作为整数值,以及作为字符串值的电影评论。接下来,使用数字转字符串节点将情感信息转换为字符串。这一步骤是必要的,以便在分区节点中进行分层抽样。在最后一步,使用字符串转数字节点将情感列的数据类型转换回整数,以便在训练过程中作为目标列由 Keras Learner 节点使用。
现在我们已经有了训练集和测试集,让我们继续进行训练集的预处理。
训练集预处理和字典创建
训练集的预处理和字典的创建在预处理训练集元节点中进行。
图 7.7 显示了元节点内部的内容:

图 7.7 – 预处理训练集元节点中的工作流片段
对于电影评论的预处理,使用了KNIME 文本处理扩展。
提示
KNIME 文本处理扩展包含读取和写入多种文本格式文档的节点;转换单词;清理句子中的无关字符和无意义单词;将文本转换为数字表格;计算所有所需的文本统计信息;最后,探索主题和情感。
KNIME 文本处理扩展依赖于一种新的数据类型:文档对象。原始文本通过添加附加的元数据,如标题、作者、来源和类别,变成了文档。文档中的文本按照多种可用的语言特定分词算法进行分词。文档分词生成了文本项的层次结构:章节、段落、句子和单词。单词通常被称为令牌或术语。
为了利用 KNIME 文本处理扩展的预处理节点,我们需要通过Strings To Document节点将电影评论转换为文档。该节点从不同的列收集值,并在对主文本进行分词后将其转换为文档对象。
图 7.8 显示了 Strings To Document 节点的配置窗口:

图 7.8 – Strings To Document 节点的配置窗口
该节点为您提供了定义以下内容的机会:
-
通过全文选项获取文档文本。
-
文档标题,作为列、行 ID或空字符串值。
-
作为固定字符串或列值的文档来源、文档类别、文档作者和文档发布日期。如果使用列值,请记得启用相应的标志。通常,文档类别字段用于存储任务类别。
-
文档类型,如事务、会议记录、书籍,或只是未知。
-
输出文档列的名称。
-
执行词法分析器的最大并行进程数。
-
词法分析器算法。
接下来,文档对象通过一系列文本预处理节点进行清理,这些节点包含在工作流的文本预处理组件中,见图 7.7。文本预处理组件的内部结构如图 7.9所示:

图 7.9 – 显示预处理组件内部的工作流片段
工作流片段从标点符号删除节点开始,用于去除输入文档中的所有标点符号。
数字过滤器节点过滤掉所有数字,包含数字形式的数字、十进制分隔符(, 或 .)和可能的前导符号(+ 或 -)。
字符数过滤器节点过滤掉所有少于
– 在我们的例子中,少于
– 字符的术语,正如在节点的配置窗口中指定的那样。
填充词,如so、thus 等,被称为停用词。它们承载的信息较少,可以通过停用词过滤器节点去除。该节点过滤掉所有在选定停用词列表中的术语。可以通过第二输入端口传递自定义停用词列表,或采用默认的内置停用词列表。为不同语言提供了多个内置停用词列表。
大小写转换器节点将所有术语转换为大写或小写。在这个案例中,它们被转换为小写。
最后,Snowball 词干提取器节点将单词简化为词干,去除语法屈折,使用 Snowball 词干提取库 (snowball.tartarus.org/)。
重要说明
词干提取的目标是将屈折形式和派生相关形式归约为共同的基础形式。例如,look、looking、looks 和 looked 都被替换为它们的词干 look。
现在我们已经清理了训练集中的电影评论文本,可以创建词典了。
基于训练集创建词典
词典必须为每个单词分配两个索引:
-
索引:为训练集中最常见的术语分配递增的整数索引,并为所有其他术语分配相同的默认索引。
-
计数器:为每个单词分配一个递增的八位数索引。这个八位数索引只是一个临时索引,帮助我们处理截断问题。
图 7.10 显示了我们想要创建的词典的子集:

图 7.10 – 字典的小子集,其中每个单词由递增的整数索引和另一个递增的八位数字索引表示
两个索引都在创建字典组件中创建,图 7.11向您展示了组件内部的工作流片段:

图 7.11 – 创建字典组件中的工作流片段
创建字典组件有一个配置窗口,您可以在图 7.12中看到。配置窗口中的输入选项继承自整数配置节点,并要求字典大小为文档集合中出现最频繁的!个单词。默认值为!:

图 7.12 – 创建字典组件的配置窗口
组件内的工作流首先通过使用独特术语提取器节点在所有文档中创建一个独特术语的全局集合:

图 7.13 – 独特术语提取器节点的配置窗口
该节点允许我们创建索引列和频率列,如上面的截图所示。索引列包含从1开始的递增整数,其中1分配给最频繁的术语。
该节点可选择性地提供过滤最常见的 k 个术语的功能。为此,有三种频率度量可用:词频、文档频率和逆文档频率。现在,我们希望选择所有术语,字典大小稍后再处理。
重要提示
词频(TF):术语在所有文档中出现的次数
文档频率(DF):术语出现的文档数量
逆文档频率(IDF):文档总数与文档频率(DF)之比的对数
八位数字索引是通过1作为步长创建的。这个最小值确保了八位数字格式。
然后,索引和计数器列将通过数字转字符串节点从整数转换为字符串。
接下来是字典大小的缩减。最上方的
最常见术语保留由唯一术语提取器节点分配的逐步索引,而所有其他术语都获得一个默认索引
。请记住,
可以通过组件的配置窗口进行更改。在这个例子中,
设置为 20,000。在组件子工作流的下部分,行分割器节点将输入数据表拆分为两个子表:最上方的
行(顶部输出端口)和其余行(底部输出端口)。
然后,常量值列节点将下方子表中的所有索引值替换为默认索引值
。最后,两个子表被重新连接在一起。
现在字典已经准备好,我们可以继续进行电影评论的截断。
截断过长的文档
我们已经说明我们将处理固定大小的文档——即每个文档的最大单词数。如果文档的单词数超过允许的数量,它将被截断。如果文档的单词数少于允许的数量,它将被零填充。现在让我们看看截断过程是如何工作的——即如何从过长的文档中删除最后的单词。这一切都发生在截断组件中。图 7.14展示了组件内部的工作流片段:

图 7.14 – 截断组件中的工作流片段
首先,我们设置文档中允许的最大单词数
。同样,这个参数可以通过组件的配置窗口进行更改,形状由整数配置节点定义。我们设置文档中的最大单词数——即最大文档大小——为
个单词。如果文档太长,我们应该只保留前
个单词,并丢弃其余部分。
计算文本中的单词数并不容易。由于单词的长度可变,我们应该在循环中检测分隔单词的空格,然后计算单词数。然而,循环往往会减慢执行速度。因此,一个替代的技巧是使用文本中单词的八位数字表示。
在文本中,每个单词通过字典替换器节点用其八位数字代码进行替换。字典替换器节点将输入文档顶部输入端口中的术语与下方输入端口中的字典术语进行匹配,然后用字典表中对应的值进行替换。
字典替换器节点有两个输入端口:
-
上输入端口用于包含要替换术语的文档
-
下输入端口与用于匹配和替换操作的字典表
重要提示
字典表必须至少包含两列字符串。一列字符串列包含要替换的术语(键),另一列字符串列包含替换的字符串(值)。在配置窗口中,我们可以从数据表的下部输入端口设置这两列。
此时,我们得到的是具有固定长度(8 位数字 + 1 <space>)的文本,而不是可变长度的单词。因此,将文本限制为
个单词就等于将文本限制为
个字符,如果
,则为 720 个字符。这个操作可以更容易地进行,无需使用循环或复杂的节点结构,只需使用 字符串操作 节点即可。然而,字符串操作 节点只对字符串对象进行操作,而不是对文档进行操作。为了使用它,我们需要暂时将文本返回为字符串。
文本通过 文档数据提取器 节点从文档中提取为简单的字符串。该节点提取文档单元格中的信息,例如文本和标题。
数学公式(变量) 节点获取流变量,以确定文档的最大大小,并计算文档中允许的最大字符数。
使用 substr() 函数,直到达到允许的最大字符数,0)。这实际上仅保留前
个单词并移除其他所有单词。
最后,文本被转换回一个称为 截断文档 的文档,所有多余的列将在 列过滤器 节点中被移除。
此时,八位数字索引已完成其任务,可以被逐渐递增的整数索引替代,用于编码。这在 字典替换器 节点中再次完成。
这样,我们就将过长的文档截断至允许的最大单词数。接下来,我们需要对过短的文档进行零填充。
零填充过短的文档
当序列相对于设置的值数量过短时,通常会应用 零填充。零填充意味着向序列中添加 0,直到达到设定的值数量。在我们的例子中,如果文档的单词数少于设定数量,我们将用 0 填充剩余的空位。这发生在 Zero Pad 组件中。
图 7.15 展示了 Zero Pad 组件中的工作流片段:

图 7.15 – Zero Pad 组件中的工作流片段
Zero-padding 再次是在字符串级别进行,而不是在文档级别进行。文本通过 <space> 从输入文档中提取为字符串后,并为每个索引创建一个新的列。
记住,所有被截断的文本现在的最大长度是来自前一步骤的
索引。因此,从这些文本中,新生成的列数肯定是
。对于所有其他文本(具有较短术语序列的文本),单元拆分器节点将用缺失值填充空列。只需要将这些缺失值替换为 0,零填充过程就完成了。这种用 0 替换缺失值的操作是由缺失值节点完成的。
最后,所有多余的列在列过滤器节点中被移除。
现在,所有的术语序列——即所有文本——都有相同的长度,使用创建集合单元节点来创建集合单元,以便将其输入到 Keras 学习节点中。
接下来,我们需要对测试集进行相同的预处理,并应用已创建的字典。
测试集预处理
测试集的预处理是在预处理测试集元节点中执行的。此元节点有两个输入端口:上端口用于从预处理训练集元节点创建的字典,下端口用于测试集。
图 7.16 展示了预处理测试集元节点内的工作流片段:

图 7.16 – 预处理测试集元节点内的工作流片段
工作流的下半部分与预处理训练集元节点内的工作流片段类似,只不过包括字典创建的部分不同。在这里,测试集的字典是基于训练集的字典创建的。所有在训练集字典中可用的术语都将获得相应的索引编码;所有其余的术语将获得默认索引。
因此,首先使用唯一术语提取器节点创建测试集中的所有术语的列表。接下来,使用右外连接将该列表与训练集字典中的术语列表连接。右外连接允许我们保留来自下输入端口的所有行——即测试集中的所有术语——并添加训练字典中的索引(如果有的话)。对于所有不在训练字典中的术语,连接节点会在索引列中创建缺失值。这些缺失值随后会通过缺失值节点被替换为默认的索引值。
所有其他步骤,如截断和零填充,都与训练集的预处理方式相同。
我们已经完成了预处理阶段,现在可以继续定义网络架构并进行训练。
定义和训练网络架构
在本节中,我们将定义并训练用于情感分类任务的网络架构。
网络架构
我们希望使用基于 LSTM 的 RNN,其中我们也训练嵌入。嵌入由嵌入层进行训练。因此,我们创建一个具有四层的神经网络:
-
一个 输入层 用于定义输入大小
-
一个 嵌入层 用于生成术语空间的嵌入表示
-
一个 LSTM 层 用于利用文本的序列特性
-
一个 全连接层,具有一个单元,并使用 sigmoid 激活函数,因为我们面临的是一个二分类问题
嵌入层期望以基于索引的编码术语序列作为输入。因此,输入层必须接受
整数索引序列(在我们的例子中,
)。这意味着在 Keras 输入层 节点的配置窗口中,Shape = 80 和 data type = Int 32。
接下来,Keras 嵌入层节点必须学习将整数索引嵌入到合适的高维向量空间中。图 7.17 显示了它的配置窗口。输入张量直接从前一个输入层的输出中恢复:

图 7.17 – Keras 嵌入层节点的配置窗口
对于 128,有两个重要的配置设置。输出张量为 序列长度 ![, 嵌入维度]。在我们的例子中,这就是 [80, 128]。
接下来,128 单元,表示 Units = 128,Activation = Tanh,Recurrent activation = Hard sigmoid,Dropout = 0.2,Recurrent dropout = 0.2,并且返回序列,返回状态,反向传播,和展开所有 unchecked。
最后,使用一个 Keras 全连接层 节点,具有一个单元和 sigmoid 激活函数,用于预测最终的二元情感分类。
现在我们已经有了预处理的数据和神经网络架构,可以开始训练网络。
使用嵌入训练递归网络
网络按常规方式训练,通过 Keras 网络学习器 节点。
在第一个标签页,输入数据,选择了 从数字集合(整数) 转换,因为我们的输入是一个整数值集合单元(索引),它对我们的电影评论进行编码。接下来,选择集合单元作为输入。
在第二个标签页,目标数据,选择了 从数字(整数) 转换类型和带有情感类别的列。在下方选择了二元交叉熵作为损失函数,因为这是一个二分类任务。
在第三个标签页中,Epochs = 30,训练批次大小 = 100,在每个 epoch 之前对训练数据进行洗牌,优化器 = Adam(使用默认设置)。
现在网络已经训练完成,我们可以将其应用到测试集并评估其在预测评论文本情感方面的表现。
在测试集上执行并评估网络
要在测试集上执行该网络,使用Keras 网络执行器节点。
在配置窗口中,我们再次选择从数字集合(整数)作为转换类型,并将集合单元格作为输入。
作为输出,我们关注最后一个密集层的输出,因为它给出了情感为1(正面)的概率。因此,我们点击添加输出按钮,选择 sigmoid 层,并确保使用转换为数字(双精度)。
1。
接下来,规则引擎节点将此概率转换为类预测,使用以下表达式:
$dense_1/Sigmoid:0_0$ > 0.5 => 1
TRUE => 0
这里,$dense_1/Sigmoid:0_0$是网络输出列的名称。
该表达式将所有大于0.5的值转换为 1,其它则转换为 0。
重要说明
请记住,规则引擎节点中的不同指令行是顺序执行的。当某一行的前提被验证时,执行停止。
最后,评分器节点评估模型的性能,Keras 网络写入器节点将训练好的网络保存以供部署。图 7.18展示了网络性能,从评分器节点的角度来看,在电影评论上的情感分类正确率达到了 83%:

图 7.18 – LSTM 和基于嵌入的网络在情感分类上的表现
到此,我们完成了第一个 NLP 案例研究。图 7.19展示了实现该示例所使用的完整工作流程。你可以从 KNIME Hub 下载该工作流程,网址为 https://hub.knime.com/kathrin/spaces/Codeless Deep Learning with KNIME/latest/Chapter 7/:

图 7.19 – 准备文本并构建、训练和评估情感分析神经网络的完整工作流程
目前,我们没有提供部署工作流程。在第十章中,部署深度学习网络,我们将回到这个已训练的网络,构建一个部署工作流程。
现在让我们继续进入下一个 NLP 应用:使用 RNN 生成自由文本。
使用 RNN 生成自由文本
现在我们已经看到 RNN 可以用于文本分类,我们可以进入下一个案例研究。在这里,我们想要训练一个 RNN 来生成具有特定风格的新自由文本,无论是莎士比亚式英语、rap 歌曲,还是模仿格林兄弟的童话故事。我们将专注于最后一个应用:训练一个网络以生成格林兄弟童话风格的自由文本。然而,该网络和过程可以轻松调整,以生成新的 rap 歌曲或莎士比亚风格的旧英语文本。
那么,我们如何训练一个 RNN 来生成新的文本呢?
数据集
首先,你需要一个文本语料库来训练网络生成新的文本。任何文本语料库都可以。然而,请记住,你用于训练的文本将自动决定生成文本的风格。如果你在莎士比亚的戏剧上训练网络,你将得到用古老的莎士比亚英语生成的新文本;如果你在说唱歌曲上训练网络,你将得到城市风格的文本,甚至可能带有韵律;如果你在童话故事上训练网络,你将得到童话风格的文本。
因此,为了让网络生成新的童话,它必须在现有的童话故事上进行训练。我们从古腾堡计划下载了格林兄弟语料库,链接地址为www.gutenberg.org/ebooks/2591。
预测单词还是字符?
第二个需要做出的决定是是否在单词级别或字符级别上训练网络。两种选择各有利弊。
在单词级别训练网络听起来更合逻辑,因为语言是由单词而非字符构成的。输入序列(单词序列)较短,但字典的大小(领域中的所有单词)非常大。另一方面,在字符级别训练网络依赖于更小且更易管理的字典,但可能导致非常长的输入序列。根据维基百科的说法,英语语言大约有 170,000 个不同的单词,而只有 26 个不同的字母。即使我们区分大小写,并添加数字、标点符号和特殊字符,字典也只有不到 100 个字符。
我们希望训练一个网络,以生成格林兄弟风格的文本。为了实现这一目标,我们使用了少量的格林兄弟故事来训练网络,这已经意味着字典中的单词数量非常庞大。因此,为了避免庞大字典和随之而来的网络规模管理问题,我们选择在字符级别上训练我们的童话生成器。
在字符级别上训练意味着网络必须学习在过去的!字符经过输入后,预测下一个字符。那么,训练集必须由许多包含!字符序列及其对应的下一个预测字符(目标值)的样本组成。
在部署过程中,一段启动序列的!字符必须触发网络生成新的文本。实际上,这个初始序列预测了下一个字符;然后在下一步中,最近的初始字符和预测字符将组成新的输入序列来预测下一个字符,以此类推。
在接下来的章节中,我们将解释如何清理、转换和编码格林童话的文本数据,以供网络使用。
预处理和编码
我们使用滑动窗口方法填充训练集——即,使用部分重叠的序列。为了更清楚地说明这一点,让我们使用窗口长度为
并滑动步长为1的窗口,将句子从前有一个包含在训练集中。五个字符Once<space>应该预测u;然后,我们将窗口向右滑动一步,nce<space>u应该预测p。再次向右滑动窗口一个字符,ce<space>up应该预测o,依此类推。
在图 7.20的左侧,你可以看到创建的输入序列和目标值:

图 7.20 – 用于训练的重叠序列示例
接下来,我们需要对字符序列进行编码。为了避免引入字符之间的人工距离,我们选择了独热向量编码。我们将通过两个步骤进行独热编码。首先,我们执行基于索引的编码;然后,通过Keras 网络学习器节点,使用从数字集合(整数)转换选项为独热张量,将其转换为独热编码。训练集的重叠索引编码序列显示在图 7.20的右侧。
下一个图中的工作流片段读取并转换童话故事,生成重叠的基于索引编码的字符序列及其相关目标字符。输入序列和目标字符都存储在集合类型的列中:

《格林童话》](https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/cdls-dl-knime/img/B16391_07_021.jpg)
图 7.21 – 预处理工作流片段,读取并转换《格林童话》中的文本
工作流执行以下步骤:
-
从语料库中读取所有童话故事,提取五个童话故事进行训练,并以
白雪公主与玫瑰红作为部署的种子 -
重新调整文本格式,将每个字符放置在单独一行的单列中
-
创建并应用基于索引的字典,在本例中,字典由字符集组成,包括标点符号和特殊符号
-
使用滞后列节点创建重叠序列,然后按从最旧到最新的顺序对其进行重新排序
-
将输入序列和目标字符封装成集合类型的列
让我们详细了解这些步骤。
读取和提取童话故事
在读取和提取童话故事的元节点中,工作流片段首先通过文件读取器节点读取童话故事。该表只有一列,其中每一行的内容对应童话故事中的一行。
然后,行过滤器节点去除文件顶部和底部的不必要的元信息,如作者、标题、目录和许可协议。在训练或部署过程中,我们不会使用这些元信息。
白雪公主与玫瑰红和顶部输出端口的其他所有童话故事。我们将保存白雪公主与玫瑰红以供部署。
接下来,使用行过滤器节点提取前五个童话故事,这些将用于训练。
下一步是将文本重塑为单一列的字符序列。
重塑文本
在我们能够创建重叠的字符序列以输入网络之前,我们需要将所有童话故事文本转化为一个由单个字符组成的长序列(列):每行一个字符。这个步骤叫做重塑,它是在重塑文本元节点中实现的。图 7.22 显示了它的内容:

图 7.22 – 重塑文本元节点中的工作流片段
它从两个<space>字符开始,使用regexReplace()函数。regexReplace()利用正则表达式,例如"[^\\s]"来匹配输入字符串中的任何字符,"$0 "为匹配的字符加上<space>。在$Col0$中使用的regexReplace()函数的最终语法如下:
regexReplace($Col0$,"[^\\s]" ,"$0 ")
接下来,<space>字符用于生成多个列,每个单元格一个字符。
注意,段落中的最后一个字符(换行符)后面没有添加<space>字符。为了解决这个问题,使用常量值列节点添加了一个包含<space>字符的常量列。
未旋转节点将数据表从多列重塑为仅包含单字符序列的一列。让我们花些时间来了解未旋转节点及其意想不到的技巧,用于重塑数据表。未旋转节点执行输入数据表的去聚合操作。图 7.23为你展示了一个例子。它区分了值列和保持列。选中的值列随后会被旋转成行,并与保持列中的相应值相附加。由于值列的旋转可能会导致多行,因此可能需要重复保持列值的行:

图 7.23 – 展示了未旋转操作的示例,其中产品 1 和产品 2 是选择的值列,ID 和城市是选择的保持列
对文本进行重塑时,我们将所有列设置为值列,而没有设置任何列为保持列。最终结果是将童话故事表示为一列长字符序列。
最后进行一些清理:使用行过滤器节点删除所有缺失值的行。
创建并应用字典
我们现在需要创建字典和基于索引的编码映射。由于我们在字符级别进行操作,因此这里的字典实际上就是字符集——也就是童话语料库中的唯一字符列表。为了获得这个列表,我们使用删除重复过滤器节点从重塑后的文本中删除所有重复字符。
提示
删除重复过滤器节点在检测和处理数据集中的重复记录时非常强大。
接下来,我们为每一行分配一个索引——即为每个唯一字符分配一个索引——使用0表示1表示缩放单元。
现在我们已经准备好字典,接下来我们通过单元替换器节点应用它,之前在第四章中已经介绍过,构建和训练前馈神经网络。
创建并重新排序重叠的序列
为了创建重叠的字符序列,我们使用100、1,并且在输出表格的开始和结束处跳过不完整的行。
根据col-100的方式,它位于最右边的列;当前需要预测的字符(col)则位于最左边的列。基本上,序列的时间顺序是相对于网络期望的内容进行倒序排序的。
下图展示了一个示例:

图 7.24 – 滞后列节点的结果输出,时间按从右到左的升序排序
我们需要重新排序列,使其按从左到右的升序排列,以便最旧的字符位于左侧,最新的字符位于右侧。这一重新排序操作由重新排序列元节点执行。
图 7.25展示了元节点内部的内容:

图 7.25 – 包含在“重新排序列”元节点中的工作流片段
在这里,参考列排序器节点根据下输入端口数据表中所建立的顺序更改数据表的列顺序。下输入端口中的参考数据表必须包含一个字符串类型的列,列标题的顺序应与第一个输入表中的列标题顺序一致。然后,第一数据表中的列将根据第二数据表中列名的行顺序进行排序。
为了创建包含排序列标题的表格,我们使用提取列标题节点提取列标题。提取列标题节点将列标题从表格内容中分离,并在上输出端口输出列标题,在下输出端口输出内容。
然后,通过转置节点将列头的行转置为一列。
最后,我们通过计数器生成节点为每个列头分配一个递增的整数编号,并通过排序器节点按计数器值降序排序它们。
现在我们已经将来自第一个表的列头按时间顺序正确排序,可以将其输入到参考列重新排序器节点的下端口。结果是一个数据表,其中每一行都是一个由
字符组成的序列,时间从左到右排序,后续的行包含重叠的字符序列。在这一点上,我们可以为网络的输入和目标数据创建集合单元。
重要提示
即使目标数据只有一个单一的值,我们仍然需要将其转换为集合单元,这样索引就可以通过Keras 网络学习器节点转换为一个独热向量。
让我们进入下一步:定义和训练网络架构。
定义和训练网络架构。
现在我们来设计并训练一个适合处理时间序列、字符编码和过拟合的神经网络架构,以预测序列中的下一个字符。
定义网络架构。
在这个案例研究中,我们决定使用一个包含四层的神经网络:
-
一个Keras 输入层,用于定义输入形状。
-
一个Keras LSTM 层,用于处理时间序列。
-
一个Keras Dropout 层,用于防止过拟合。
-
一个Keras 全连接层,用于输出下一个字符的概率。
像往常一样,我们使用?, 65来定义神经网络的输入形状。
由于我们不需要中间的隐藏状态,我们将大部分设置保持为512的默认值。
自由文本生成可以视为一个多类分类应用,其中字符是类别。因此,网络输出的Keras 全连接层节点被设置为 65 个单元(每个字符集中的一个字符),并使用 softmax 激活函数来评分每个字符作为下一个字符的概率。
让我们继续在编码的重叠序列上训练这个网络。
训练网络。
再次,为了训练网络,我们使用已经熟悉的Keras 网络学习器节点。
在第一个配置标签中,输入数据,我们选择从数字集合(整数)到独热张量来处理编码转换,并将字符序列的集合列作为输入。
在第二个配置标签中,目标数据,我们再次在包含目标值的集合列上选择从数字集合(整数)到独热张量。由于这是一个多类分类问题,我们将损失函数设置为分类交叉熵。
在第三个配置标签中,50 epochs,训练批次大小为256,打乱选项为on,优化器选择Adam,学习率使用默认设置。
最终,网络使用Keras 格式通过Keras 网络写入器节点保存。此外,网络通过Keras 到 TensorFlow 网络转换器节点转换为 TensorFlow 网络,并通过TensorFlow 网络写入器节点保存。TensorFlow 网络在部署时使用,以避免 Keras 网络所需的耗时 Python 启动。
图 7.26 显示了完整的工作流,实施了所有描述的步骤来训练神经网络生成童话故事。此工作流和所使用的数据集可在 KNIME Hub 上找到,网址为 https://hub.knime.com/kathrin/spaces/Codeless Deep Learning with KNIME/latest/Chapter 7/:

图 7.26 – 训练神经网络生成童话故事的工作流
现在我们已经训练并保存了网络,接下来我们将进行部署,生成新的童话故事文本。
构建部署工作流
为了在部署期间触发新文本的生成,我们从与每个训练序列相同长度的输入序列开始(
)。我们将该序列输入网络,以预测下一个字符;然后,我们删除序列中的最旧字符,添加预测的字符,再次将网络应用于新的输入序列,依此类推。这与我们在需求预测案例研究中使用的程序完全相同。因此,我们将在这里再次实现它,使用递归循环(图 7.27):

图 7.27 – 部署工作流生成新的自由文本
触发序列取自白雪公主与玫瑰红的童话故事。触发序列的文本经过预处理、分序列和编码,方式与训练网络时使用的工作流相同。这是在读取和预处理元节点中完成的,如图 7.28所示:

图 7.28 – 读取和预处理元节点中的工作流内容,用于读取和预处理触发序列
该工作流读取白雪公主与玫瑰红的童话故事以及训练工作流中创建的字典文件。然后,应用与训练工作流相同的预处理步骤。
之后,我们读取训练好的 TensorFlow 网络,并将其应用于触发序列,使用TensorFlow 网络执行器节点。
网络的输出是每个字符成为下一个字符的概率。我们可以采用两种可能的策略来选择预测的字符:
-
概率最高的字符被分配为下一个字符,这就是贪心策略。
-
下一个字符是根据概率分布随机选择的。
我们已经在 提取索引 元节点中实现了这两种策略,并在两个不同的部署工作流中使用。
图 7.29 显示了实现第一种策略时 提取索引 元节点的内容:

图 7.29 – 提取具有最高概率的字符的工作流片段
这个元节点以已执行网络的输出概率为输入,提取具有最高概率的字符。这里的关键节点是 多对一 节点,它从网络输出中提取得分(概率)最高的单元格。
图 7.30 显示了实现第二种策略时 提取索引 元节点的内容:

图 7.30 – 基于概率分布选择下一个字符的工作流片段
这个工作流片段期望输入字符的概率分布,并根据它选择一个字符。这里的关键节点是 随机标签分配器(数据) 节点,它根据输入的概率分布分配一个值。
随机标签分配器(数据) 节点根据上游输入端口的概率分布为下游输入端口的每一行数据分配一个索引。上游输入端口的数据表必须包含两列:一列是类别值 —— 在我们的例子中,是以字符串格式编码的字符索引 —— 另一列是相应的概率。因此,图 7.30 中的工作流片段第一部分利用 转置 节点、计数器生成 节点和 数字转字符串 节点,准备好数据表供 随机标签分配器(数据) 节点的顶部输入端口使用,而 表创建器 节点则创建一个只有一行的新表。也就是说,随机标签分配器(数据) 节点根据第一输入端口的表中定义的概率分布,选择一个索引。
提示
递归循环的概念及其实现详细解释请参见 第六章,需求预测的递归神经网络。
你可以从 KNIME Hub 下载实现这两种选项的部署工作流:https://hub.knime.com/kathrin/spaces/Codeless Deep Learning with KNIME/latest/Chapter 7/.
新的童话故事
最后,我相信你一定想看看网络能够生成的自由文本。以下是使用第一种策略生成的自由文本示例。
触发序列中的 100 个字符(非斜体)来自童话故事的第一句话,白雪公主与玫瑰红。其余的文本由网络自动生成。
雪白与玫红 从前有一位贫穷的寡妇,她住在一个孤独的小屋里。小屋前有一只猫,门后有一百瓶酒;他回答道:“你想要的是什么?你说的那东西像是好事,还是哭了?我们会说我只给了寡妇那群人的大地去带走它。”但当父亲说:“猫很快就会死。”年青人,老人……
网络成功地学会了英语语言的结构。尽管文本不完美,但你可以看到合理的字符组合、完整的单词、一些正确使用的引号以及其他类似的有趣特征,这些都是网络从训练文本中吸收的。
使用 RNN 生成产品名称
这个最后的自然语言处理案例研究与前一个类似。前者我们希望网络根据一个起始序列生成新的自由文本;而在这里,我们希望网络根据一个起始符号生成新的自由单词。在前者中,我们希望网络生成新的单词序列;而在这里,我们希望网络生成新的字符序列。实际上,这个产品名称生成案例研究的目标是创造新的名称——也就是新的单词。尽管会有一些差异,但方法是相似的。
在本节中,我们将探讨这种新方法的细节。
产品名称生成问题
通常,我们不会将人工智能与创意联系在一起,因为它通常用于根据之前见过的例子预测结果。本案例的挑战是使用人工智能创造出一些新的东西,而这通常被认为是创意人才的领域。
让我们看一个经典的创意营销例子:产品命名。在新产品推出市场之前,它实际上需要一个名字。为了找到这个名字,公司的创意团队会集思广益,生成多个产品名称提案,并考虑不同的需求。例如,产品名称应该让顾客感到熟悉,同时又要新颖、富有创意。在这些候选名称中,最终只有一个能够脱颖而出,成为新产品的名称。这可不是一项容易的任务!
现在,我们来看一个最具创意的行业:时尚。一家专门生产户外服饰的公司准备推出一系列新款服装。任务是为这一新款服装系列生成足够多的名称候选。许多户外时尚品牌提出过山脉的名字,这些名字能唤起自然的感觉,而且顾客也会觉得很熟悉。然而,新名称还必须没有版权问题,并且要足够原创,能够在市场中脱颖而出。
那为什么不使用虚构的山脉名称呢?由于它们是虚构的,因此不受版权保护,并且与竞争者名称不同;然而,由于它们类似于现有的山脉名称,它们也足够熟悉,能吸引潜在客户。人工智能模型是否可以帮助生成既具有现实感又能唤起冒险精神的新虚构山脉名称?我们可以为这样的任务使用什么样的网络架构?
由于我们希望能够形成某种程度上类似于山脉名称的新词,因此网络必须基于已有的山脉名称进行训练。
为了形成训练集,我们使用从维基百科通过 Wikidata 查询提取的 33,012 个美国山脉名称列表。
图 7.31 显示了训练数据的一个子集:

图 7.31 – 训练集中美国山脉名称的子集
现在我们有了一些训练数据,可以开始考虑网络架构。这次,我们想训练一个多对多的基于 LSTM 的 RNN(见图 7.32)。这意味着在训练过程中,我们有一个输入序列和一个输出序列。在部署时,RNN 基于一些初始化的隐藏状态和开始标记,必须预测新名称候选的第一个字符;然后在下一步,根据预测的字符和更新后的隐藏状态,它必须预测下一个字符——依此类推,直到预测出结束标记并完成生成新候选名称的过程:

图 7.32 – 用于产品名称生成案例研究的多对多 RNN 架构的简化展开可视化
为了训练 LSTM 单元执行此任务,我们需要两个序列:一个输入序列,由开始标记和山脉名称组成,一个目标序列,由山脉名称和结束标记组成。请注意,在每次训练迭代中,我们将正确的字符输入到网络中,而不是它的预测。这称为教师强制训练方法。
让我们首先专注于预处理和编码输入及目标序列。
预处理和编码山脉名称
预处理的目标是创建并编码输入和目标序列,包括开始标记和结束标记。与前一个案例研究一样,我们希望使用独热编码。因此,我们创建一个基于索引的编码,并使用1作为开始标记的索引,0作为结束标记的索引。
在上一个案例研究中,你学到了在训练过程中,一批次中的序列长度必须相同。因此,我们将最长山脉名称的字符数(58)加 1 作为序列长度。由于这是最长山脉名称的长度,无需截断,但所有较短的序列将通过添加多个结束标记来进行零填充:

图 7.33 – 用于读取、编码和创建输入及目标序列的山脉名称生成工作流
上述图中的工作流片段通过以下方式创建输入和目标序列:
-
使用表格读取器节点和重复行过滤器节点读取山脉名称并去除重复项
-
使用两个字符串操作节点,将每个
<space>替换为波浪号字符,然后将每个字符与字符本身和<space>一起替换(该步骤在前一个案例研究的预处理部分中有详细描述,基于 RNN 的自由文本生成) -
创建和应用字典(我们将在下一小节中仔细查看此步骤)
-
基于
<space>进行字符拆分,并将所有缺失值替换为结束标记,以零填充过短的序列 -
创建输入和目标序列作为集合类型单元
大多数步骤类似于自由文本生成的预处理步骤,我们只会更仔细地查看步骤 3和步骤 5。我们从步骤 3开始。
创建和应用字典
创建和应用字典是在创建和应用字典元节点中实现的。图 7.34 展示了它的内容。该元节点的输入是具有空格字符的山脉名称:

图 7.34 – 创建和应用字典元节点中的工作流片段
在此元节点中,我们再次使用 KNIME 文本处理扩展中的节点。2 是因为我们希望使用索引 0 和 1 作为开始和结束标记。为了在下一步中将其用作字典,创建的数字索引通过数字转字符串节点转换为字符串。最后,字典被应用(字典替换器节点),以将字符转换为原始山脉名称中的索引,文本则通过文档数据提取器节点从文档中提取。
提示
KNIME 文本处理扩展及其一些节点,如字符串转文档、唯一术语提取器、字典替换器和文档数据提取器,在本章的第一个案例研究中有更详细的介绍,寻找客户声音的语调——情感分析。
在流程图的独立下分支中,我们通过添加一行用于结束标记,使用 0 作为整数单元的默认值,空字符串作为字符串单元的默认值,来为部署完成词典。这会为我们的词典表格增加一行,在索引列中填充 0,在字符列中填充空字符串。我们需要这个附加的行在部署工作流程中去除结束标记:

图 7.35 – 添加空行节点的配置窗口
让我们继续进行预处理的最后一步。
创建输入和目标序列
在缺失值节点处理之后,流程图中图 7.35展示了零填充的编码序列。然而,缺少的是输入序列开头的开始标记和目标序列末尾的结束标记,以确保输入序列和目标序列的长度一致。
附加的值是通过 1 来表示输入序列中的开始标记,而目标序列中的结束标记则由值 0 表示。对于输入序列,新的开始标记列必须放在序列的开头。这一过程由列重排序器节点处理。现在,可以将序列聚合并转换为集合单元,使用创建集合列节点。
现在我们来设计并训练适当的网络架构。
定义与训练网络架构
设计和训练网络的过程与之前 NLP 案例研究中使用的过程相似。
设计网络
在这种情况下,我们希望使用一个五层的网络:
-
一个Keras 输入层,用于定义输入形状
-
一个Keras LSTM 层用于序列分析
-
一个Keras dropout 层用于正则化
-
一个Keras 全连接层,使用线性激活
-
一个Keras softmax 层,用于将输出转化为概率分布
训练集中的唯一字符数量,也就是字符集的大小为 95。由于我们允许变长的序列,输入层的形状为 ?, 95。其中 ? 代表变量序列长度。
接下来,我们为该层设置了 256 单元,并且其他所有设置保持不变。
在这个案例研究中,我们希望在输出层增加更多的随机化,以提升网络的创造力。这是通过在训练好的输出层的 softmax 函数中引入
温度参数来实现的。
记住,softmax 函数的定义如下:
与 
如果我们现在引入额外的
温度参数,则激活函数的公式将改变为如下所示:
与 
这意味着我们在应用 softmax 函数之前将线性部分除以
。
为了能够在训练后插入温度参数,我们将输出层拆分为两个层:一个Keras Dense Layer节点,用于线性部分的线性激活函数,另一个Keras Softmax Layer节点用于应用激活函数。
重要提示
温度是一个可以在训练后添加的参数,用于控制网络输出的置信度。
使网络更有信心,但也更保守,这通常导致每次运行时生成相同的结果。
则对不同的输出实现更柔和的概率分布,从而带来更多的多样性,但同时也会带来更多的错误,比如在这个例子中,生成了英语中不可能的字符组合。
训练与后处理网络
网络使用Keras Network Learner节点进行训练。对于输入数据和目标数据,选择从数字集合(整数)转换为One-Hot Tensor。不同的字符再次类似于多类别分类问题中的不同类别,因此,采用Categorical Cross Entropy损失函数进行训练。
在第三个选项卡中,使用30个训练周期,128行数据的批量大小,在每个周期之前对数据进行洗牌,并使用Adam作为优化算法,采用默认设置。到目前为止,这与之前的 NLP 案例研究中的设置完全相同。
训练网络后,通过使用DL Python Editor节点和以下 Python 代码行来添加温度,
:
from keras.models import Model
from keras.layers import Input, Lambda
from keras import backend as K
# Define Inputs
state1=Input((256,))
state2=Input((256,))
new_input=Input((1,95))
# Extract layers
lstm=input_network.layers[-4]
dense_softmax=input_network.layers[-1]
dense_linear=input_network.layers[-2]
# Apply LSTM Layer on new Inputs
x, h1, h2=lstm(new_input, initial_state=[state1, state2])
# Apply the linear layer
linear=dense_linear(x)
# Add lambda
linear_div_temp=Lambda(lambda x: x*0.9)(linear)
# Apply Softmax activation
probabilities = dense_softmax(linear_div_temp)
output_network = Model(inputs=[new_input, state1, state2], outputs=[probabilities, h1, h2])
请记住,前一个 LSTM 单元的隐藏状态始终作为输入传递给下一个 LSTM 单元。因此,在代码中定义了三个输入:两个用于两个隐藏状态,一个用于最后预测的字符,编码为 one-hot 向量。
最终,网络被转化为一个 TensorFlow 网络对象并保存以供部署。最终的训练工作流如图 7.36所示:

图 7.36 – 产品名称生成案例的训练工作流
工作流可以在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%207/。
让我们继续部署工作流。
构建部署工作流
部署工作流再次使用递归循环方法,类似于 NLP 和需求预测案例中的部署工作流。不同的是,这次有一个重大区别。
在最后两个案例研究中,隐藏状态向量在每次迭代时都会重新初始化,因为我们总是有
前一个字符或
前一个值作为输入。在本案例研究中,我们从循环结束节点返回到循环起始节点时,不仅传递预测的索引,还包括来自 LSTM 层的两个隐藏状态张量。
在图 7.37中,您可以看到部署工作流,它也可以在 KNIME Hub 上找到:https://hub.knime.com/kathrin/spaces/Codeless Deep Learning with KNIME/latest/Chapter 7/。我们来详细看看设置的差异:

图 7.37 – 部署工作流以创建多个可能的产品名称
第一个组件,1。另外两列包含初始的隐藏状态——也就是,两个列中各有 256 个零的集合单元。
TensorFlow 网络执行器节点首次执行网络,输出索引的概率分布。在TensorFlow 网络执行器的配置窗口中,我们选择了作为输入的列:第一个隐藏状态、第二个隐藏状态和输入集合。此外,我们设置了三个输出列:一个用于概率分布的输出列,一个用于第一个隐藏状态的输出列,和一个用于第二个隐藏状态的输出列。然后,我们根据输出的概率分布,使用随机标签分配器(数据)节点在第一个字符元节点中选择下一个索引编码字符。所有这些输出值、预测的索引和隐藏状态都传送到循环起始节点,用于预测第二个索引编码字符。
接着,我们开始递归循环,每次生成一个字符。在每次迭代中,我们将网络应用于最后预测的索引和隐藏状态。然后,我们通过随机数分配器(数据)节点选取下一个字符,并将最后预测的值和新的隐藏状态输入到递归循环结束节点的下输入端口,以便它们能返回到循环起始节点。
在提取山脉名称组件中,我们最终应用了在训练工作流中创建的字典,并移除了在训练集中已经出现过的山脉名称。
在图 7.38中,您可以看到一些生成的山脉名称。事实上,它们是全新的、无版权的、富有山脉和自然感觉的名称,并且可以按照所需的数量自动生成!。

图 7.38 – 通过部署工作流生成的山脉名称
其中一个将最终被选为新的产品名称。
总结
我们已经结束了这一相对较长的章节。在这里,我们描述了三个 NLP 案例研究,每个案例都是通过训练一个基于 LSTM 的 RNN,应用于时间序列预测问题来解决的。
第一个案例研究分析了电影评论文本,以提取其中隐藏的情感。我们在这里处理了一个简化的问题,采用二分类(正面与负面)来代替考虑过多的用户情感细节。
第二个案例研究是语言建模。我们在给定文本语料库和风格的基础上训练了一个 RNN,产生了一个能够按照特定风格生成自由文本的网络。根据网络训练时使用的文本语料库,它可以生成童话故事、莎士比亚的对话,甚至是说唱歌曲。我们展示了一个生成童话风格文本的例子。相同的工作流可以轻松地扩展并成功地生成说唱歌曲(R. Silipo,AI 生成说唱歌曲,CustomerThink,2019,customerthink.com/ai-generated-rap-songs/)或莎士比亚的对话(R. Silipo,AI 能像莎士比亚那样写作吗?,Towards data Science,2019,towardsdatascience.com/can-ai-write-like-shakespeare-de710befbfee)。
最后的案例研究涉及生成新的产品名称候选,这些名称必须具有创新性、无版权并且在市场上突出,同时能够唤起自然的联想。因此,我们训练了一个 RNN 来生成虚构的山脉名称,作为新户外服装系列的名称候选。
在下一章中,我们将描述另一个 NLP 示例:神经机器翻译。
问题与练习
-
什么是词嵌入?
a) 可以在神经网络内训练的编码功能
b) 文本清理程序
c) RNN 的训练算法
d) 一种后处理技术,用于选择最可能的字符
-
哪种关于情感分析的说法是正确的?
a) 情感分析只能通过 RNN 解决。
b) 情感分析与情绪检测相同。
c) 情感分析识别文本中的潜在情感。
d) 情感分析是一个图像处理任务。
-
多对多架构是什么意思?
a) 具有输入序列和输出序列的架构
b) 具有输入序列和向量作为输出的架构
c) 具有多个隐藏单元和多个输出的架构
d) 具有一个输入特征和一个输出序列的架构
-
为什么我需要触发序列来生成自由文本?
a) 计算概率
b) 将预测与目标进行比较
c) 在预测下一个字符之前初始化隐藏状态
d) 以 TensorFlow 格式保存网络
第八章:第八章: 神经机器翻译
在上一章中,第七章,实现 NLP 应用程序,我们介绍了几种文本编码技术,并将其应用于三个自然语言处理(NLP)应用程序。其中一个应用是自由文本生成。结果表明,网络有可能学习语言的结构,从而生成某种风格的文本。
在本章中,我们将在自由文本生成的案例研究基础上,训练一个神经网络来自动将句子从源语言翻译成目标语言。为此,我们将使用从自由文本生成网络以及在第五章,用于欺诈检测的自编码器中学到的概念。
我们将首先描述机器翻译的一般概念,然后介绍将用于神经机器翻译的编码器-解码器神经架构。接下来,我们将讨论实现该应用程序的所有步骤,从预处理到定义网络结构,再到训练和应用网络。
本章的结构分为以下几个部分:
-
神经机器翻译的理念
-
编码器-解码器架构
-
为两种语言准备数据
-
构建和训练编码器-解码器架构
神经机器翻译的理念
自动翻译一直是一个热门且富有挑战性的任务。人类语言的灵活性和模糊性使其至今仍然是最难实现的任务之一。同一个单词或短语根据上下文可以有不同的含义,而且通常并非只有一个正确的翻译,而是存在多种可能的翻译方式。那么,计算机如何学会将文本从一种语言翻译成另一种语言呢?多年来,已经提出了不同的方法,所有方法的目标都是相同的:将源语言的句子或文本自动翻译成目标语言。
自动翻译系统的发展始于 1970 年代初期,采用基于规则的机器翻译(RBMT)。在这里,自动翻译是通过专门的语言学家在句子的词汇、句法和语义层面上手工开发的规则和词典来实现的。
在 1990 年代,统计机器翻译模型成为了当时的先进技术,尽管统计机器翻译的第一个概念是在 1949 年由沃伦·韦弗提出的。与使用词典和手写规则不同,新的思路是使用大量的示例语料库来训练统计模型。这个任务可以描述为建模概率分布,
,即目标语言(例如德语)中的一个字符串,
,是源语言(例如英语)中的一个字符串,
,的翻译。为建模这个
概率分布,提出了不同的方法,其中最流行的来自贝叶斯定理,并将
建模为
。因此,在这种方法中,任务被分为两个子任务:训练一个语言模型,
,以及建模概率,
。更一般来说,可以定义多个子任务,并为每个子任务训练和调整多个模型。
最近,神经机器翻译在自动翻译任务中获得了相当大的关注。此外,在这里,训练翻译模型需要大量的源语言和目标语言的示例句子语料库。经典的基于统计的模型和神经机器翻译的区别在于任务的定义:不是训练许多小的子组件并分别调整它们,而是训练一个单一的网络,以端到端的方式进行训练。
一种可以用于神经机器翻译的网络架构是编码器-解码器网络。让我们来了解一下这是什么。
编码器-解码器架构
在本节中,我们将首先介绍编码器-解码器架构的基本概念。之后,我们将重点讨论编码器在神经机器翻译中的应用。在最后两个子节中,我们将集中讨论解码器在训练和部署过程中的应用。
神经机器翻译的一种可能结构是编码器-解码器网络。在第五章《用于欺诈检测的自编码器》中,我们介绍了由编码器和解码器组成的神经网络的概念。记住,在自编码器的情况下,编码器的任务是提取输入的密集表示,而解码器的任务是根据编码器提供的密集表示重建输入。
在神经机器翻译的编码器-解码器网络中,编码器的任务是将源语言(输入句子)的上下文提取为密集表示,而解码器的任务是根据编码器的密集表示在目标语言中生成相应的翻译。
图 8.1 可视化了这个过程:

图 8.1 – 神经机器翻译中编码器-解码器网络的通用结构
这里,源语言是英语,目标语言是德语。目标是将句子 I am a student 从英语翻译成德语,其中一种正确的翻译可能是 Ich bin ein Student。编码器接收句子 I am a student 作为输入,并输出句子内容的密集向量表示。这个密集向量表示被输入到解码器,解码器随后输出翻译结果。
在这个案例研究中,网络的输入和输出都是序列。因此,循环神经网络(RNN)层通常用于编码器和解码器部分,以捕获上下文信息并处理可变长度的输入和输出序列。
一般来说,基于编码器-解码器 RNN 的架构用于各种序列到序列的分析任务——例如问答系统。这里,问题首先由编码器处理,编码器为问题生成一个密集的数值表示,然后解码器生成答案。
现在让我们专注于神经翻译网络的编码器部分,在我们继续讲解解码器之前,理解需要哪些数据准备。
应用编码器
编码器的目标是从输入句子中提取上下文的密集向量表示。这可以通过使用 长短期记忆(LSTM)层来实现,其中编码器逐字或逐字符地读取输入句子(英语)。
提示
在 第六章,《需求预测的循环神经网络》中,我们介绍了 LSTM 层。请记住,LSTM 层有两个隐藏状态,一个是单元状态,另一个是它的过滤版本。单元状态包含了所有先前输入的摘要。
在经典的编码器-解码器网络架构中,LSTM 层的隐藏状态向量用于存储密集表示。图 8.2 展示了基于 LSTM 的编码器如何处理输入句子:

图 8.2 – 编码器如何处理输入句子的示例
编码器从一些初始化的隐藏状态向量开始。在每一步,序列中的下一个单词被输入到 LSTM 单元,隐藏状态向量得到更新。处理完源语言的整个输入序列后,最终的隐藏状态向量包含了上下文表示,并成为解码器中隐藏状态向量的输入。
编码器的中间输出隐藏状态不会被使用。
现在我们有了编码器的密集上下文表示,可以使用它来馈送给解码器。虽然编码器在训练和部署过程中的工作方式保持不变,但解码器在训练和部署过程中的工作方式有所不同。
让我们首先集中讨论训练阶段。
在训练过程中应用解码器
解码器的任务是从密集的上下文表示中生成目标序列的翻译,可以按单词或字符逐个生成,再次使用带有 LSTM 层的 RNN。这意味着,理论上,每个预测的单词/字符都应该被反馈到网络中作为下一次输入。然而,在训练过程中,我们可以跳过理论,应用教师强制的概念。在这里,实际的单词/字符会被反馈到 LSTM 单元,而不是预测的单词/字符,这极大地有利于训练过程。
图 8.3 显示了解码器训练阶段的教师强制示例:

图 8.3 – 解码器训练阶段的教师强制示例
编码器的密集上下文表示用于初始化解码器 LSTM 层的隐藏状态。接下来,LSTM 层使用两个序列来训练解码器:输入序列,包含真实的单词/字符值,从开始标记开始,和目标序列,也包含真实的单词/字符值。
重要说明
在这种情况下,目标序列是输入序列向右移动一个字符,并在末尾添加一个结束标记。
总结一下,训练过程中需要三组单词/字符序列:
-
编码器的输入序列
-
解码器的输入序列
-
解码器的输出序列
在部署期间,我们没有解码器的输入和输出序列。因此,让我们来看看训练好的解码器如何在部署过程中使用。
在部署过程中应用解码器
当我们应用训练好的网络时,我们并不知道翻译序列的真实值。因此,我们只将来自编码器的密集上下文表示和一个开始标记输入到解码器中。然后,解码器多次应用 LSTM 单元,每次都将上一个预测的单词/字符反馈到 LSTM 单元作为下一步的输入。图 8.4 展示了在部署期间解码器的使用:

图 8.4 – 解码器在部署期间的使用
在第一步中,编码器的密集上下文表示形成输入的隐藏状态向量,而起始标记作为解码器的输入值。基于此,预测第一个单词,并更新隐藏状态向量。在接下来的步骤中,更新后的隐藏状态向量和最后预测的单词将被反馈到 LSTM 单元,以预测下一个单词。这意味着,如果某个单词第一次被预测错误,这种错误会在这种顺序预测中累积。
在本节中,你学习了什么是编码器-解码器神经网络以及它们如何应用于神经机器翻译。
在接下来的几节中,我们将介绍训练一个神经机器翻译网络的步骤,目的是将英文句子翻译成德语。像往常一样,第一步是数据准备。
所以,让我们从创建训练神经机器翻译网络所需的三个序列开始,使用编码器-解码器结构。
准备两种语言的数据
在第七章《实现 NLP 应用》中,我们讨论了在字符级别和词汇级别训练神经网络的优缺点。由于我们已经有了一些字符级别的经验,因此决定也在字符级别训练这个自动翻译网络。
为了训练一个神经机器翻译网络,我们需要一个包含两种语言的双语句子对的数据集。不同语言组合的数据集可以从www.manythings.org/anki/免费下载。在那里,我们可以下载一个包含英语和德语常用句子的数据集。该数据集仅由两列组成:英文原文和相应的德语翻译。
图 8.5展示了一个子集数据集,作为训练集使用:

图 8.5 – 包含英语和德语句子的训练集子集
如你所见,对于一些英文句子,可能有多个翻译。例如,句子Hug Tom可以翻译成Umarmt Tom、Umarmen Sie Tom或Drücken Sie Tom。
请记住,网络并不理解字符,只有数字值。因此,字符输入序列需要转换为数字输入序列。在上一章的第一部分中,我们介绍了几种编码技术。
与自由文本生成的案例研究一样,我们采用了独热编码作为编码方案,这将分两步实现。首先,产生基于索引的编码;然后,在训练时通过Keras 网络学习器节点将其转换为独热编码,在应用训练好的网络时通过Keras 网络执行器节点进行转换。
此外,还需要一个字典,用于映射英语和德语字符及其索引。在上一章中,为了生成产品名称,我们使用了KNIME 文本处理扩展来生成基于索引的字符序列编码。我们将在此处做同样的操作。
为了训练神经机器翻译,必须创建三种索引编码的字符序列:
-
输入序列,用于输入编码器。这是来自源语言的索引编码字符序列——在我们的例子中是英语。
-
输入序列,用于输入解码器。这是目标语言的索引编码字符序列,以起始标记开头。
-
用于训练解码器的目标序列,是解码器的输入序列向后偏移一步,并以结束标记结尾。
图 8.6 中的工作流读取双语句子对,提取前 10,000 个句子,分别对英语和德语句子进行索引编码,最后将数据集划分为训练集和测试集:

图 8.6 – 用于准备训练神经机器翻译网络的数据的预处理工作流片段
预处理的主要工作发生在名为索引编码和序列创建的组件内。图 8.7展示了该组件的内容:

图 8.7 – 组件内名为索引编码和序列创建的工作流片段
组件内的工作流片段首先将英语文本与德语文本分离,然后为句子生成索引编码——上部分为德语句子,下部分为英语句子。然后,最终,为每种语言创建字典并应用并保存。
在对德语句子进行索引编码后,将为解码器创建两个序列:在上支路通过在序列开头添加一个起始标记,在下支路通过在序列末尾添加一个结束标记来创建。
德语和英语的所有序列随后会转换为集合单元格,以便在训练前将其转换为独热编码。
构建和训练编码器-解码器架构
现在,三个序列已准备好,我们可以开始在工作流中定义网络结构。在本节中,您将学习如何在 KNIME 分析平台中定义和训练一个编码器-解码器结构。一旦网络训练完成,您将学习如何将编码器和解码器提取成两个网络。在最后一节中,我们将讨论如何在部署工作流中使用提取的网络将英语句子翻译成德语。
定义网络结构
在编码器-解码器架构中,我们希望将编码器和解码器都设置为 LSTM 网络。编码器和解码器有不同的输入序列。英语的 one-hot 编码句子作为编码器的输入,而德语的 one-hot 编码句子作为解码器的输入。这意味着需要两个输入层:一个用于编码器,一个用于解码器。
编码器网络由两层组成:
-
通过Keras 输入层节点实现的输入层:输入张量的形状为
,其中
是源语言的词典大小。输入张量形状中的?表示可变长度的序列,而n表示具有
个组件的 one-hot 向量。在我们的示例中,英语语言的形状为
,输入张量的形状是[?,71]。 -
通过Keras LSTM 层节点实现的 LSTM 层:在这个节点中,我们使用 256 个单元并启用return state复选框,将隐藏状态传递到即将到来的解码器网络。
解码器网络由三层组成:
-
首先,使用Keras 输入层节点来定义输入形状。同样,输入形状
是一个元组,其中
代表变量长度,
代表输入序列中每个向量的大小——即目标语言(德语)的词汇表大小。在我们的示例中,德语的输入张量形状为
。 -
通过 Keras LSTM 层节点实现 LSTM 层。这一次,可选的输入端口用于将编码器中的隐藏状态传递到解码器。这意味着编码器网络中第一个 LSTM 层的输出端口连接到解码器网络中的两个可选输入端口。此外,Keras 输入层节点的输出端口用于连接德语输入序列到顶部输入端口。在其配置窗口中,选择正确的输入张量和隐藏张量是非常重要的。必须激活return sequence和return state复选框,以返回中间输出的隐藏状态,这些状态在下一层中用于提取下一个预测字符的概率分布。与编码器 LSTM 一样,使用 256 个单元。
-
最后,通过Keras Dense 层节点添加了一个 softmax 层,以生成目标语言(德语)词典中字符的概率向量。在配置窗口中,选择 softmax 激活函数,设定 85 个单元,这是目标语言词典的大小。
图 8.8中的工作流定义了这个编码器-解码器网络结构:

图 8.8 – 定义编码器-解码器网络的工作流片段
工作流的上半部分定义了带有 Keras 输入层 和 Keras LSTM 层 节点的编码器。在下半部分,解码器按之前描述的方式定义。
现在我们已经定义了编码器-解码器架构,可以开始训练网络了。
训练网络
正如本书中的所有其他示例一样,Keras 网络学习器 节点被用来训练网络。
在配置窗口的第一个标签页,名为 输入数据 中,选择了两个输入层的输入列:上半部分是源语言,即编码器的输入,下半部分是目标语言,即解码器的输入。为了将索引编码的序列转换为 one-hot 编码序列,两个列都使用 从数字集合(整数)到 One-Hot 张量 的转换类型。
在配置窗口的下一个标签页,名为 目标数据 中,选择了解码器的目标序列列,并再次启用 从数字集合(整数)到 One-Hot 张量 的转换类型。字符再次被视为多类分类问题中的类别;因此,训练过程中采用了分类交叉熵损失函数。
在第三个标签页 Options 中,训练阶段设置为最多运行 120 个周期,批量大小为 128 数据行,每个周期前对数据进行洗牌,并使用 Adam 作为优化算法,采用默认设置。
在训练过程中,我们使用 Learner Monitor 视图来监控 Keras 网络学习器节点的性能,并在准确率达到 94% 时决定停止学习过程。
提取训练好的编码器和解码器
为了将训练好的模型应用于翻译新的句子,我们需要将编码器和解码器分开。为此,每个部分都可以通过在 DL Python 网络编辑器 节点中使用几行 Python 代码从完整的网络中提取出来。该节点允许我们直接使用 Python 库 编辑和修改网络结构。
记住,解码器的输出是目标语言中所有字符的概率分布。在 第七章,实现自然语言处理应用 中,我们介绍了基于此输出概率分布预测下一个字符的两种方法。选项一是选择具有最高概率的字符作为下一个字符。选项二是根据给定的概率分布随机选择下一个字符。
在这个案例研究中,我们使用选项一,并通过额外的 lambda 层 直接在解码器中实现它。总结来说,在后处理时,我们需要执行以下步骤:
-
分离网络中的编码器和解码器部分。
-
引入一个带有 argmax 函数的 lambda 层,它选择 softmax 层中概率最高的字符。
重要提示
Lambda 层允许你在使用 TensorFlow 作为后端构建顺序模型和功能 API 模型时,使用任意的 TensorFlow 函数。Lambda 层最适合用于简单操作或快速实验。
让我们从提取编码器开始。
提取编码器:
在下面的代码中,你可以看到用于提取编码器的 Python 代码:
-
加载包:
from keras.models import Model from keras.layers import Input -
定义输入:
new_input = Input((None,70)) -
提取训练好的编码器 LSTM 并定义模型:
encoder = input_network.layers[-3] output = encoder(new_input) output_network = Model(inputs=new_input, outputs=output)
它从定义输入开始,将其输入到编码器的 LSTM 层,然后定义输出。
更详细地说,在前两行中,加载了所需的包。接下来,定义了输入层;然后,提取了-3层——编码器的训练 LSTM 层。最后,网络输出被定义为训练好的编码器 LSTM 层的输出。
现在我们已经提取了编码器,接下来看看如何提取解码器。
提取解码器并添加 lambda 层:
在下面的代码片段中,你可以看到在DL Python 网络编辑器节点中使用的代码,用于提取解码器部分并向其中添加 lambda 层:
-
加载包:
from keras.models import Model from keras.layers import Input, Lambda from keras import backend as K -
定义输入:
state1 = Input((256,)) state2 = Input((256,)) new_input = Input((1,85)) -
提取训练好的解码器 LSTM 层和 softmax 层:
decoder_lstm = input_network.layers[-2] decoder_dense = input_network.layers[-1] -
应用 LSTM 和全连接层:
x, out_h, out_c = decoder_lstm(new_input, initial_state=[state1, state2]) probability_output = decoder_dense(x) -
添加 lambda 层并定义输出:
argmax_output = Lambda(lambda x: K.argmax(x, axis=-1))(probability_output) output_network = Model(inputs=[new_input, state1, state2], outputs=[probability_output, argmax_output, out_h, out_c])
这段代码首先加载了必要的包,然后定义了三个输入——两个是输入的隐藏状态,一个是单热编码的字符向量。接着,它提取了解码器中的训练 LSTM 层和 softmax 层。最后,它引入了带有 argmax 函数的 lambda 层并定义了输出。
为了在部署过程中加速执行,编码器和解码器会使用Keras 到 TensorFlow 网络转换器节点转换为 TensorFlow 网络。
现在我们已经训练好了神经机器翻译网络,并且分离了编码器和解码器,我们希望将它们应用到测试集中的句子上。
完整的训练工作流可以在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%208/.
应用训练好的网络进行神经机器翻译:
为了将编码器和解码器网络应用到测试数据中,我们需要一个工作流,首先将编码器应用到索引编码的英文句子中以提取上下文信息,然后应用解码器生成翻译。
解码器应该使用来自编码器的第一个隐藏状态和输入序列中的起始符号进行初始化,以便在递归循环中逐字符地触发翻译。图 8.9 展示了这一过程:

图 8.9 – 部署过程中应用编码器和解码器模型的思路
图 8.10中的工作流片段正好执行了这些步骤:

图 8.10 – 此工作流片段应用训练好的编码器-解码器神经架构将英文句子翻译成德语句子
它从TensorFlow 网络执行器节点开始(位于图 8.10的最左侧)。此节点将编码器和索引编码的英文句子作为输入。在其配置窗口中,定义了来自 LSTM 隐藏状态的两个输出。
接下来,我们创建一个起始标记,并将其转换为一个集合单元。对这个起始标记,我们应用解码器网络,使用另一个TensorFlow 网络执行器节点(从左侧数第二个)。在配置窗口中,我们确保使用上一个TensorFlow 网络执行器节点中生成的编码器隐藏状态作为输入。作为输出,我们再次设置隐藏状态,以及下一个预测字符——即翻译句子的第一个字符。
现在,我们进入递归循环,在此过程中,使用来自上次迭代的更新隐藏状态和最后预测的字符作为输入,重复此过程多次。
最后,德语词典被应用于索引编码的预测字符,最终翻译结果得以获得。以下是翻译结果的摘录:

图 8.11 – 部署的翻译网络在新英文句子上的最终结果
在第一列,我们有新的英文句子,在第二列,有正确的翻译,在最后一列,有网络生成的翻译。尽管这些翻译大多数实际上是正确的,尽管它们与第二列的句子不匹配,因为相同的句子可以有不同的翻译。另一方面,Talk to Tom句子的翻译是不正确的,因为rune不是德语单词。
描述的部署工作流可以在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%208/。
在这一部分,你已经学会了如何根据字符级别的神经机器翻译示例,定义、训练并应用编码器-解码器架构。
总结
在本章中,我们探讨了神经机器翻译的主题,并训练了一个网络来生成英译德翻译。
我们从自动机器翻译的介绍开始,讲解了其历史,从基于规则的机器翻译到神经机器翻译。接着,我们介绍了基于编码器-解码器 RNN 架构的概念,这些架构可以用于神经机器翻译。一般来说,编码器-解码器架构可以用于序列到序列的预测任务或问答系统。
之后,我们讲解了训练和应用一个基于字符级的神经机器翻译模型所需的所有步骤,使用一个简单的网络结构,其中编码器和解码器都只有一个 LSTM 单元。由编码器和解码器结合而成的联合网络,采用了教师强制范式进行训练。
在训练阶段结束并在部署之前,lambda 层被插入到解码器部分,用于预测概率最高的字符。为此,训练后的网络结构在训练过程后被用几行 Python 代码修改。Python 代码将解码器和编码器网络分开,并添加了 lambda 层。这是唯一涉及一小段简单 Python 代码的部分。
当然,这个网络可以通过许多方式进一步改进——例如,通过堆叠多个 LSTM 层,或者使用额外的嵌入层在词汇级别上训练模型。
这是关于 RNN 的最后一章。在下一章中,我们将介绍另一类神经网络——卷积神经网络(CNNs),这种网络在图像处理方面已经证明了其非常成功的应用。
问题与练习
-
编码器-解码器模型是一个:
a.) 多对一架构
b.) 多对多架构
c.) 一对多架构
d.) CNN 架构
-
编码器在神经机器翻译中的任务是什么?
a.) 编码字符
b.) 生成翻译
c.) 提取目标语言内容的密集表示
d.) 提取源语言内容的密集表示
-
编码器-解码器 LSTM 网络的另一个应用是什么?
a.) 文本分类
b.) 问答系统
c.) 语言检测
d.) 异常检测
第九章:第九章: 卷积神经网络在图像分类中的应用
在前几章中,我们讨论了递归神经网络(RNN)及其如何应用于不同类型的序列数据和使用场景。本章我们将讨论另一类神经网络——卷积神经网络(CNN)。当应用于具有网格状拓扑和空间依赖的数据时,如图像或视频,CNN 尤其强大。
我们将首先进行 CNN 的基本介绍,解释卷积层背后的基本理念,并介绍一些相关术语,如填充、池化、滤波器和步幅。
随后,我们将从零开始构建并训练一个用于图像分类的 CNN。我们将涵盖所有必要的步骤:从读取和预处理图像到定义、训练和应用 CNN。
要从零开始训练一个神经网络,通常需要大量的标注数据。对于一些特定领域,如图像或视频,可能没有足够的数据,网络训练可能变得不可行。迁移学习是为了解决这个问题而提出的解决方案。迁移学习的理念是利用已经为任务 A 训练好的最先进神经网络作为任务 B 的起点,任务 B 是与 A 相关的另一个任务。
本章将涵盖以下主题:
-
CNNs 简介
-
使用 CNN 进行图像分类
-
迁移学习简介
-
应用迁移学习进行癌症类型预测
CNNs 简介
CNN 常用于图像处理,并且在多个图像处理竞赛中获得了优胜。它们通常用于图像分类、物体检测和语义分割等任务。
有时,CNN 也用于与图像无关的任务,如推荐系统、视频或时间序列分析。事实上,CNN 不仅适用于具有网格结构的二维数据,还可以在一维或三维数据中应用。然而,本章我们将专注于 CNN 最常见的应用领域:图像处理。
CNN 是一种至少包含一个卷积层的神经网络。顾名思义,卷积层对输入数据执行卷积数学变换。通过这种数学变换,卷积层获得了从图像中检测和提取多个特征的能力,如边缘、角落和形状。这些提取特征的组合被用于对图像进行分类或检测图像中的特定物体。
卷积层通常与池化层一起出现,池化层也常用于图像处理中的特征提取部分。
本节的目标是解释卷积层和池化层如何单独以及共同工作,并详细说明这两种层的不同设置选项。
如前所述,在本章中我们将专注于图像分析的卷积神经网络(CNN)。因此,在深入探讨 CNN 的细节之前,让我们快速回顾一下图像是如何存储的。
图像是如何存储的?
灰度图像可以存储为矩阵,其中每个单元格表示图像的一个像素,单元格的值表示该像素的灰度级。例如,一张黑白图像,大小为
像素,可以表示为维度为
的矩阵,其中矩阵中的每个值介于
和
之间。
表示一个黑色像素,
表示一个白色像素,矩阵中的中间值表示灰度级。
图 9.1这里展示了一个例子:

图 9.1 – 灰度 5 x 5 图像的矩阵表示
由于每个像素仅由一个灰度值表示,一个通道(矩阵)就足以表示这张图像。另一方面,对于彩色图像,需要多个值来定义每个像素的颜色。一种选择是使用三个值来指定红色、绿色和蓝色的强度,从而定义像素颜色。在以下截图中,表示彩色图像时,使用了三个通道而不是一个:(图 9.2):

图 9.2 – 使用三个通道表示 28 x 28 彩色图像(RGB)
从灰度图像到红色、绿色和蓝色(RGB)图像时,更为通用的张量概念——而不是简单的矩阵——变得必不可少。这样,灰度图像可以被描述为
的张量,而具有
像素的彩色图像则可以用一个
张量表示。
一般来说,一个表示图像的张量,其高度为
像素,宽度为
像素,通道数为
,其维度为
x
x
。
那么,为什么我们需要专门的网络来分析图像呢?我们不能只是展平图像,将每个图像表示为一个长向量,然后训练一个标准的全连接前馈神经网络吗?
重要提示
将图像的矩阵表示转换为向量的过程称为展平。
为什么我们需要卷积神经网络(CNN)?
对于基本的二值图像,展平和全连接前馈网络可能会得到可接受的性能。然而,对于更复杂的图像,图像中的像素依赖性较强,展平和前馈神经网络的组合通常无法有效工作。
确实,当图像被展平为一个向量时,空间依赖性会丧失。因此,完全连接的前馈网络不是平移不变的。这意味着它们对于同一图像的不同位移版本会产生不同的结果。例如,网络可能会学习在图像的左上角识别猫,但同一个网络无法检测图像右下角的猫。
此外,展平图像会生成一个非常长的向量,因此它需要一个非常大的完全连接的前馈网络,包含大量权重。例如,对于一个
像素、三个通道的图像,网络需要
个输入。如果下一层有
个神经元,我们将仅在第一层训练
个权重。你会发现,权重的数量可能会迅速变得难以管理,导致训练过程中出现过拟合。
卷积层是 CNN 的主要构建块,它利用图像的空间属性来解决这个问题。那么,让我们来看看卷积层是如何工作的。
卷积层是如何工作的?
卷积神经网络(CNN)的思路是使用滤波器来检测图像不同部分的模式——也叫特征——如角落、垂直边缘和水平边缘。
对于一个单通道图像,滤波器是一个小矩阵,通常大小为
或
,称为卷积核。不同的卷积核——即具有不同数值的矩阵——过滤不同的模式。卷积核在图像上滑动并执行卷积操作。这个卷积操作赋予了该层一个名称。这样的卷积输出称为特征图。
重要说明
对于一个具有三个通道的输入图像(例如,输入张量形状为
),大小为 2 的卷积核的形状为
。这意味着卷积核可以从所有通道获取信息,但仅限于输入图像的一个小区域(例如,在本例中为 2 x 2)。
图 9.3 这里展示了如何计算卷积,图像大小为
,卷积核大小为
:

图 9.3 – 通过将一个 3 x 3 的卷积核应用于一个 4 x 4 图像得到的卷积示例
在这个例子中,我们首先将卷积核应用于图像的左上角
区域。图像的值与卷积核的值按元素相乘,然后求和,计算过程如下:

这种逐元素相乘并求和的结果就是输出特征图左上角的第一个值。接着,卷积核会在整张图像上滑动,计算输出特征图的所有其他值。
重要提示
卷积操作用*表示,且与矩阵乘法不同。尽管这一层叫做卷积层,但大多数神经网络库实际上实现的是一个相关的函数,叫做交叉相关(cross-correlation)。为了执行正确的卷积,按照其数学定义,核还必须翻转。对于卷积神经网络(CNN),这并不影响结果,因为权重无论如何都会被学习。
在卷积层中,大量的滤波器(核)会并行训练输入数据集,并针对所需任务进行优化。也就是说,核中的权重不是手动设置的,而是在网络训练过程中作为权重自动调整。在执行时,所有训练过的核都会应用于计算特征图。
特征图的维度随后变成一个大小为
的张量。在图 9.3 的示例中,我们只应用了一个核,特征图的维度为
。
从历史上看,核是手工设计的,用于特定任务。例如,图 9.3 中的核用于检测垂直线。图 9.4 显示了其他一些手工设计的核的影响:

图 9.4 – 一些手工设计的核对原始图像的影响
卷积操作只是卷积层的一部分。之后,偏置值和非线性激活函数会应用于特征图中的每个条目。例如,我们可以向特征图中的每个值添加偏置值,然后应用整流线性单元(ReLU)作为激活函数,将所有小于偏置的值设置为 0。
重要提示
在第三章,神经网络入门一章中,我们介绍了密集层。在密集层中,首先计算输入的加权和;然后,将偏置值添加到和中,最后应用激活函数。在卷积层中,密集层的加权和被卷积所取代。
卷积层有多个设置选项。我们已经在前面的内容中介绍了其中三个,这里列出它们:
-
核的大小,通常是
![]()
-
滤波器的数量
-
激活函数,其中 ReLU 是最常用的函数。
还有三个设置选项:填充(padding)、步幅(stride)和扩张率(dilation rate)。我们继续讨论填充(padding)。
引入填充(Padding)
当我们在图 9.3中的示例中应用滤波器时,特征图的维度相比输入图像的维度有所缩小。输入图像的大小为
,而特征图的大小为
。
此外,通过查看特征图,我们可以看到输入图像内部的像素(值为 f, g, j, k 的单元格)在卷积过程中比角落和边缘的像素更常被考虑。这意味着内部值在后续分析中将获得更高的权重。为了解决这个问题,可以通过在额外的外部单元格中添加零来对图像进行零填充(图 9.5)。这就是所谓的填充过程。
图 9.5 这里展示了一个零填充输入的示例:

图 9.5 – 零填充图像示例
这里,在原始图像的每一行和每一列周围都添加了两个零值单元格。如果现在对这个零填充的图像应用大小为
的卷积核,特征图的输出维度将与原始图像的维度相同。用于零填充的单元格数量是卷积层中的另一个可配置参数。
另外两个影响输出大小的设置,如果不使用填充,分别叫做步幅和膨胀率。
介绍步幅和膨胀率
在图 9.3的示例中,我们将滤波器应用于每一个像素。对于大尺寸的图像,通常不需要对每个像素进行卷积。我们可以将卷积核按水平或垂直方向移动多个像素,而不是每次只移动一个像素。
用于卷积核滑动的像素数量称为步幅。步幅通常由一个元组定义,指定水平和垂直方向上滑动的单元格数量。较高的步幅值,在没有填充的情况下,会导致输入图像的下采样。
图 9.6 的顶部部分展示了一个大小为 3 x 3 的卷积核如何以步幅 2, 2 在图像上滑动。
卷积层的另一个设置选项是膨胀率。膨胀率表示输入图像中每
个连续单元格中只使用其中一个进行卷积操作。膨胀率为
时,仅使用输入图像中的每两个像素进行卷积。膨胀率为
时,使用三个连续像素中的一个。就像步幅一样,膨胀率是一个水平方向和垂直方向的值元组。当使用高于
的膨胀率时,核会膨胀成在原始图像上更大的视野。因此,一个 3 x 3 的核,膨胀率为
时,探索输入图像中大小为 5 x 5 的视野,同时仅使用九个卷积参数。
对于一个
核心和一个膨胀率为
的情况,核心仅使用其角值扫描输入图像上的
区域(见 图 9.6 下部)。这意味着对于膨胀率为
的情况,我们有一个大小为 1 的间隙;对于膨胀率为
的情况,我们会有一个大小为 2 的间隙,依此类推:

图 9.6 – 不同步幅和膨胀率值对输出特征图的影响
卷积神经网络中另一个常用的层是池化层。
引入池化
池化的思想是用汇总统计值替代特征图中的一块区域。例如,池化可以用每个
区域的最大值来替代该区域,称为最大池化,或者用其平均值来替代,称为平均池化(图 9.7):

图 9.7 – 最大池化和平均池化的结果
池化层以更高效的方式减少输入图像的维度,并允许提取主导的、旋转不变和位置不变的特征。
和滤波器一样,在池化中我们需要定义要计算汇总统计的区域大小。一个常用的设置是池化大小为
像素,且每个方向的步幅为两个像素。这个设置将图像的维度减半。
重要提示
池化层没有任何权重,所有设置都是在层配置期间定义的。它们是静态层,其参数不会像网络中的其他权重一样进行训练。
池化层通常在一个卷积层或多个堆叠卷积层之后使用。
卷积层既可以应用于输入图像,也可以应用于特征图。事实上,多个卷积层通常会堆叠在一起形成 CNN。在这种层级结构中,第一层卷积可能会提取低级特征,如边缘。接下来的层中的滤波器将基于提取的特征进行处理,可能会学习检测形状,等等。
最终提取的特征可以用于不同的任务。在图像分类的情况下,特征图——由多个卷积层堆叠而成——被平展,然后在其上应用分类网络。
总结一下,标准的图像分类 CNN 首先使用一系列卷积层和池化层,然后是一个平展层,最后是一系列全连接层用于最终分类。
现在我们已经熟悉了卷积层和池化层,让我们看看如何将它们引入到图像分类网络中。
使用 CNN 进行图像分类
在本节中,我们将学习如何从零开始构建和训练用于图像分类的 CNN。
目标是使用来自MNIST 数据库的数据,将手写数字进行分类,MNIST 是一个常用的手写数字数据库,通常用于训练各种图像处理应用。MNIST 数据库包含 60,000 张训练图像和 10,000 张测试图像,数字为手写体,可以从以下网站下载:yann.lecun.com/exdb/mnist/。
为了读取和预处理图像,KNIME 分析平台提供了一组专用的节点和组件,在安装KNIME 图像处理扩展后可用。
小贴士
KNIME 图像处理扩展(www.knime.com/community/image-processing)允许你读取超过 140 种不同格式的图像(得益于生物格式应用处理接口(API))。此外,它还可以用来应用众所周知的图像处理技术,如分割、特征提取、跟踪和分类,利用 KNIME 分析平台中的图形用户界面。
通常,这些节点操作多维图像数据(例如,视频、3D 图像、多通道图像,甚至这些的组合),通过内部库 ImgLib2-API。几个节点计算分割图像(例如,单个细胞)的图像特征(例如,Zernike、纹理或直方图特征)。机器学习算法应用于结果特征向量,用于最终分类。
为了在图像上应用和训练神经网络,我们需要一个额外的扩展:KNIME 图像处理 - 深度学习扩展。这个扩展引入了一些有用的图像操作——例如,一些必要的转换,用于将图像数据输入到Keras 网络学习器节点中。
重要提示
为了在图像上训练和应用神经网络,您需要安装以下扩展:
KNIME 图像处理 (www.knime.com/community/image-processing)
KNIME 图像处理 – 深度学习扩展 (hub.knime.com/bioml-konstanz/extensions/org.knime.knip.dl.feature/latest)
让我们开始读取和预处理手写数字。
读取和预处理图像
对于本案例研究,我们使用 MNIST 数据集的一个子集:10,000 张图像样本用于训练,1,500 张用于测试。每张图像有
像素且只有一个通道。训练和测试图像保存在两个不同的文件夹中,文件名为递增数字。此外,我们有一个包含图像标签的表格,按图像文件名的顺序进行排序。
读取和预处理工作流的目标是读取图像并将它们与标签匹配。因此,实施了以下步骤(也见于图 9.8):
-
读取并排序用于训练的图像。
-
导入训练图像的数字标签。
-
将标签与图像匹配。
-
将像素类型从无符号字节转换为浮动。
-
将标签转换为集合单元格。
这些步骤由以下截图中所示的工作流执行:

图 9.8 – 此工作流读取 MNIST 数据集的一个子集,添加对应的标签,并将像素类型从无符号字节转换为浮动
要读取图像,我们使用图像读取器(表格)节点。该节点需要输入一列包含指向图像文件的统一资源定位符(URL)路径。为了创建排序后的 URL 列表,列出文件节点首先获取训练文件夹中所有图像文件的路径。然后,使用排序图像元节点。这里的图 9.9展示了元节点内部的情况:

图 9.9 – 排序图像元节点内部
元节点通过字符串操作节点从文件名中提取图像编号,并通过排序器节点对其进行排序。然后,图像读取器(表格)节点读取图像。
文件读取器节点,在下部分支中,读取包含图像标签的表格。
在下一步中,列附加器节点将正确的标签附加到每个图像上。由于图像已经被排序以匹配相应的标签,简单的附加操作就足够了。这里的图 9.10展示了列附加器节点输出的一个子集:

图 9.10 – 列追加节点的输出,包含数字图像及其对应标签。
接下来,图像计算器 节点通过将每个像素值除以 255,将像素类型从 无符号字节 改为 浮动。
最后,创建集合列 节点为每个标签创建一个集合单元。这个集合单元在训练过程中用于创建 one-hot 向量编码的类别。
现在我们已经读取并预处理了训练图像,可以设计网络结构了。
设计网络结构
在本节中,你将学习如何定义一个经典的 CNN 用于图像分类。
一个经典的 CNN 用于图像分类,通常包含两部分,它们以端到端的方式共同训练,具体如下:
-
特征提取:第一部分通过训练若干滤波器来进行图像的特征提取。
-
分类:第二部分在提取到的特征上训练分类网络,提取后的特征存在于从特征提取部分得到的扁平化特征图中。
我们从一个简单的网络结构开始,只有一个卷积层,后面接着一个池化层用于特征提取部分。得到的特征图会被扁平化,随后在其上训练一个简单的分类网络,这个网络只有一个隐藏层,并使用 ReLU 激活函数。
这里的工作流在图 9.11中展示了这个网络结构:

图 9.11 – 这个工作流片段构建了一个简单的 CNN,用于 MNIST 数据集的分类。
工作流从 Keras 输入层 节点开始,用于定义输入形状。MNIST 数据集的图像具有
像素,并且只有一个通道,因为它们是灰度图像。因此,输入是形状为
的张量,输入形状设置为
。
接下来,卷积层通过 Keras 卷积 2D 层 节点实现。图 9.12 展示了该节点的配置窗口:

图 9.12 – Keras 卷积 2D 层节点及其配置窗口。
名为 Filters 的设置决定了要应用的滤波器数量。这将是特征图的最后一个维度。在这个例子中,我们决定训练 32 个滤波器。
接下来,你可以在像素中设置 Kernel size 选项,也就是一个整数元组,定义每个卷积核的高度和宽度。对于 MNIST 数据集,我们使用的卷积核大小是
。这意味着设置为
。50。
接下来,你可以将 dilation_rate 设置为大于 1 的值。
接下来,你可以选择是否使用零填充。填充选项让你在有效和相同之间进行选择。有效表示不执行填充操作。相同表示执行零填充,使得特征图的输出维度与输入维度相同。由于图像边缘主要是黑色像素,我们决定不对图像进行零填充,选择了有效。
接下来,你可以选择膨胀率选项,作为一个整数元组。目前,指定任何大于 1 的膨胀率值与指定任何大于 1 的步幅值是不兼容的。膨胀率为
表示没有像素被跳过。膨胀率为
表示每隔一个像素使用一个像素,这意味着间隔大小为 1。我们使用
表示膨胀率为.52。
最后,必须选择激活函数选项。对于这个案例研究,我们选择了卷积层中最常用的激活函数:ReLU。
卷积层的输出张量(即我们的特征图)具有维度
,因为我们有
个滤波器,并且没有使用填充。
接下来,使用Keras Max Pooling 2D Layer节点对两个维度进行最大池化。
图 9.13 显示了节点的配置窗口:

图 9.13 – Keras Max Pooling 2D Layer 节点及其配置窗口
在Keras Max Pooling 2D Layer节点的配置窗口中,你可以定义池化大小。这同样是一个整数元组,定义了池化窗口。请记住,最大池化的理念是用池化窗口中的最大值来表示每个区域。
步幅再次是一个整数元组,用于设置池化窗口的步长。
最后,你可以选择是否应用零填充,选择有效表示不填充,选择相同表示应用填充。
对于这个 MNIST 示例,我们将池化大小设置为
,步幅设置为
,并且没有应用填充。因此,池化层的输出维度为
。
接下来,使用一个Keras Flatten Layer节点将特征图转换为向量,维度为
。
在Keras 扁平化层节点之后,我们构建了一个简单的分类网络,包含一个隐藏层和一个输出层。隐藏层使用 ReLU 激活函数和 100 个单元,由图 9.11中的第一个Keras Dense 层节点实现,而输出层由图 9.11中的第二个(也是最后一个)Keras Dense 层节点实现。由于这是一个有 10 个不同类别的多类分类问题,因此这里使用了带有 10 个单元的 softmax 激活函数。此外,使用名称前缀 output,这样在将网络应用于新数据时可以更容易地识别输出层。
现在我们已经定义了网络结构,可以开始训练 CNN。
训练和应用网络
为了训练上一节中构建的 CNN,我们再次使用Keras 网络学习器节点。在前面的章节中,我们已经看到这个节点提供了许多输入和目标数据的转换类型(例如,从数字集合(整数)到独热张量的选项)。安装KNIME 图像处理 – 深度学习扩展后,新增了一个转换选项:从图像(自动映射)。这个新的转换选项允许我们从输入表中选择一个图像列,并自动创建张量以输入到网络中。
图 9.14 显示了输入数据标签,来自Keras 网络学习器节点的配置窗口,其中包括这个额外的转换选项:

图 9.14 – Keras 网络学习器节点配置窗口的输入数据标签,带有额外的转换选项:从图像(自动映射)
在目标数据标签中,选择了将从数字集合(整数)到独热张量的转换选项,适用于图像标签的集合单元列。
底部选择了类别交叉熵激活函数,因为这是一个多类分类问题。
在选项标签中,设置了以下训练参数:
-
10 -
200 -
Adadelta 默认设置
图 9.15 显示了Keras 网络学习器节点执行后的学习监视器视图,显示训练过程的进展:

图 9.15 – 学习监视器视图显示网络的训练进度
学习监视器视图显示了在多个训练批次中的网络训练进度。在右侧,你可以看到最后几个批次的准确率。当前值显示的是最后一个批次的准确率,在这个例子中是 0.995。
现在我们已经训练出了一个在训练集上表现良好的 CNN,可以将其应用于测试集。在此,必须对测试集执行与训练集相同的读取和预处理步骤。
Keras 网络执行器节点将训练好的网络应用于测试集中的图像。在配置窗口中,选择产生不同数字概率分布的最后一层作为输出。
此时,需要进行一些后处理,以便从网络输出中提取最终的预测结果。
预测提取与模型评估
Keras 网络执行器节点的输出是一个包含 12 列的表,包含以下内容:
-
图像列
-
真实类别值,命名为实际值
-
10 列包含图像类别的概率值,列标题为:
output/Softmax:0_x,其中x是介于 0 到 9 之间的数字,用来表示类别。
后处理的目标是提取概率最高的类别,然后评估网络性能。这是通过图 9.16中所示的工作流片段实现的:

图 9.16 – 这个工作流片段提取概率最高的数字类别,并在测试集上评估网络性能
一对多节点提取每一行中概率最高的列的列标题。
然后,列表达式节点从列标题中提取类别。
提示
列表达式节点是一个非常强大的节点。它提供了通过表达式附加任意数量的新列或修改现有列的可能性。
对于每个需要附加或修改的列,可以定义一个单独的表达式。这些表达式可以像使用=一样简单地通过预定义函数创建。
可以通过提供的访问函数变量("variableName")和列("columnName")来访问可用的流程变量和输入表的列。
图 9.17这里显示了列表达式节点的配置窗口,其中包含工作流片段图 9.16中用于提取类别信息的表达式。在此案例中,表达式从名为检测到的数字的列中的字符串中提取最后一个字符:

图 9.17 – 列表达式节点及其配置窗口
接下来,预测类别的数据类型从String转换为Integer,通过字符串转数字节点实现,接着用评分器节点在测试集上评估网络性能。
图 9.18这里显示了评分器节点产生的视图:

图 9.18 – Scorer 节点视图,展示了网络在测试集上的表现
如你所见,这个简单的卷积神经网络已经在测试集上达到了 94%的准确率和 0.934 的 Cohen’s kappa 值。完整的工作流可以在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%209/。
在本节中,我们从头开始构建并训练了一个简单的卷积神经网络(CNN),并在这个相对简单的图像分类任务中达到了可接受的性能。当然,我们可以通过以下方法进一步提高该网络的性能:
-
增加训练周期数
-
添加第二个卷积层,并结合池化层
-
使用批归一化进行训练
-
使用数据增强
-
使用丢弃法(dropout)
我们将此留给你去完成,接下来介绍另一种网络学习方式,称为迁移学习。
迁移学习简介
迁移学习的基本理念是将用于任务A的网络在另一个相关任务B上重新使用。例如,如果我们训练一个网络来识别帆船(任务 A),我们可以将这个网络作为起点,训练一个新模型来识别摩托艇(任务 B)。在这种情况下,任务 A 被称为源任务,任务 B 则是目标任务。
将一个训练过的网络作为起点来训练一个新网络,与传统的网络训练方式不同,传统方法通常是将神经网络针对特定任务和数据集单独进行训练。图 9.19 这里可视化了传统的网络训练方式,其中不同的系统为不同的任务和领域进行训练:

图 9.19 – 传统的机器学习模型和神经网络训练方式
那么,为什么我们要使用迁移学习,而不是以传统、孤立的方式训练模型呢?
为什么使用迁移学习?
当前最先进的神经网络在处理特定复杂任务方面表现出了惊人的性能。有时,这些模型甚至超过了人类,在棋盘游戏中击败世界冠军,或在图像中检测物体。为了训练这些成功的网络,通常需要大量的标注数据,以及大量的计算资源和时间。
获取一个全面标注的数据集用于一个新领域,以便能够训练一个网络达到最先进的性能,可能是困难的,甚至是不可能的。举个例子,常用的ImageNet 数据库,用于训练最先进的模型,已经在多年的时间里开发出来。要为一个新的图像领域创建一个类似的新数据集需要时间。然而,当这些最先进的模型应用到其他相关领域时,它们往往会遭遇显著的性能下降,甚至更糟糕的是,模型可能会崩溃。这是因为模型对训练数据和领域存在偏倚。
转移学习使我们能够利用在一个任务和领域中训练时获得的知识(该领域有足够的标注数据)作为起点,在数据不足的新领域中训练新的模型。这种方法在许多计算机视觉和自然语言处理(NLP)任务中取得了显著的成果。
图 9.20 在这里可视化了转移学习的基本概念:

图 9.20 – 转移学习的基本概念
在我们讨论如何在训练神经网络时应用转移学习之前,先快速浏览一下转移学习的正式定义以及它可以应用的多种场景。
转移学习的正式定义
转移学习的正式定义及相关场景可以在 Sinno Jialin Pan 和 Qiang Yang 的论文《转移学习综述》中找到,IEEE Transactions on Knowledge and Data Engineering, 2009(ieeexplore.ieee.org/abstract/document/5288526)。
这个定义涉及到领域和任务的概念。
在这篇论文中,引入了领域
,其定义为元组 {
其中
是特征空间,
是
的边际概率分布。
对于一个给定的领域
,一个任务
由以下两个组成部分构成:
-
标签空间
![]()
-
预测函数
![]()
在这里,预测函数
可以是条件概率分布
。一般来说,预测函数是基于标注的训练数据训练出来的,用来预测任何样本
在特征空间中的标签
。
使用这一术语,转移学习由 Sinno Jialin Pan 和 Qiang Yang 以以下方式定义:
“给定一个源领域
和学习任务
,一个目标领域
和学习任务
,迁移学习旨在帮助改善目标预测函数的学习
,使用在
中的知识
和
,其中
,或
*。”
Sebastian Ruder 在他的文章《迁移学习——机器学习的下一个前沿》(2017)中使用了这个定义(ruder.io/transfer-learning/),描述了迁移学习可以应用的以下四种情境:
-
不同的特征空间:
![]()
论文中的一个例子是跨语言适配,我们有不同语言的文档。
-
不同的边际概率:
![]()
一个例子是讨论不同主题的文档。这个情境称为领域适配。
-
不同的标签空间:
![]()
(例如,如果我们有不同标签的文档)。
-
不同的条件概率
这通常与情境 3 一起发生。
现在我们对迁移学习有了基本的理解,接下来让我们探讨迁移学习如何应用于深度学习领域。
应用迁移学习
在神经网络中,训练过程中获得的知识存储在各层的权重中。例如,在 CNN 中,许多滤波器被训练以提取一系列特征。因此,从图像中提取这些特征的知识被存储在实现滤波器的卷积核权重中。
在用于图像分类的堆叠卷积神经网络(CNN)中,最初的卷积层负责提取低级特征,如边缘,而接下来的卷积层提取更高级的特征,如身体部位、动物或面部。最后的层被训练用于根据提取的特征对图像进行分类。
因此,如果我们想为不同的图像分类任务训练一个 CNN,处理不同的图像并使用不同的标签,我们就不能从零开始训练新的滤波器,而应该使用在最先进网络中训练过的卷积层作为起点。希望新的训练过程能够更快,且所需的数据量更少。
要使用另一个网络训练过的层作为训练起点,我们需要从原始网络中提取卷积层,然后在其上构建一些新的层。为此,我们有以下两个选择:
-
我们冻结已经训练好的层的权重,只根据被冻结层的输出训练新增的层。这种方法在 NLP 应用中经常使用,其中已训练的词向量会被重用。
-
我们使用训练好的权重来初始化网络中的新卷积层,然后在训练新增的层时对其进行微调。在这种情况下,会使用较小的学习率,以避免遗忘源任务中已经学到的知识。
作为本书的最后一个案例研究,我们希望训练一个神经网络,通过组织病理学切片图像预测癌症类型。为了加快学习过程,并考虑到我们所拥有的相对较小的数据集,我们将应用迁移学习,从这里作为源网络的流行 VGG16 网络的卷积层开始。
应用迁移学习进行癌症类型预测
我们将在这里介绍一个新的(也是最后的)案例研究。我们将从最先进的 VGG16 网络作为源网络,训练一个新的目标网络,该目标网络将基于描述三种不同类型淋巴瘤的图像数据集进行训练,这三种类型分别是慢性淋巴细胞白血病(CLL)、滤泡性淋巴瘤(FL)和外套细胞淋巴瘤(MCL)。
病理学家在医院的典型任务之一是查看组织病理学切片图像,并判断淋巴瘤的类型。即使是经验丰富的病理学家,这也是一项困难的任务,而且在许多情况下,仍需要后续检查来确认诊断。如果能有一种辅助技术来指导病理学家并加速他们的工作,那将具有极大的价值。
VGG16 是 2014 年 ImageNet 挑战赛中的获胜模型之一。它是一个堆叠的卷积神经网络(CNN),使用大小为
的卷积核,并且具有越来越深的结构——即,过滤器的数量逐渐增加。原始网络是在 ImageNet 数据集上训练的,该数据集包含了
图像,涵盖了超过 1,000 个类别。
图 9.21展示了 VGG16 模型的网络结构。
它从两个卷积层开始,每个卷积层有 64 个过滤器。经过一个最大池化层后,再使用两个卷积层,这次每个卷积层有 128 个过滤器。然后,另一个最大池化层后跟着三个卷积层,每个卷积层有 256 个过滤器。再经过一个最大池化层后,又有三个卷积层,每个卷积层有 512 个过滤器,接着是另一个池化层和三个卷积层,每个卷积层有 512 个过滤器。最后经过一个池化层后,使用了三层全连接层:

图 9.21 – VGG16 模型的网络结构
在这个案例研究中,我们希望重用 VGG16 模型训练好的卷积层,并在其上添加一些新的层来进行癌细胞分类任务。在训练过程中,卷积层将被冻结,只有新增的层会被训练。
为此,我们构建了三个独立的子工作流:一个工作流用于下载数据,一个工作流用于预处理图像,第三个工作流用于训练神经网络,使用迁移学习。你可以从 KNIME Hub 下载包含这三个子工作流的工作流:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter%209/。让我们从下载数据的工作流开始。
下载数据集
包含癌细胞图像的完整数据集以单个tar.gz文件的形式提供,包含 374 张图像:ome.grc.nia.nih.gov/iicbu2008/lymphoma/index.html。如图 9.22所示的工作流下载该文件,并创建一个包含每个图像文件路径和类别信息的表格:

图 9.22 – 这个工作流下载了完整的标注图像数据集,包含癌细胞图像
因此,工作流首先使用tar.gz文件定义一个目录来存储下载的数据,并将其解压到创建的目录中。.table文件。
下一步是预处理图像。
读取和预处理图像
在下一步中,将读取图 9.22中工作流创建的表格,并对图像进行预处理。每张图像的尺寸为 1388px x 1040px,具有三个颜色通道;这意味着
。为了减少计算的空间复杂度,我们采用与论文Histology Image Classification Using Supervised Classification and Multimodal Fusion(ieeexplore.ieee.org/document/5693834)中类似的方法,将每张图像切割成 25 个块。对于这个用例,我们决定将每张图像切割成大小为
的块。
加载和预处理步骤由此处图 9.23所示的工作流执行:

图 9.23 – 这个工作流加载并预处理图像
第二个工作流从读取第一个工作流中创建的表格开始,其中包含图像路径以及类别信息。接下来,类别到数字节点用索引编码不同的类别值(FL、MCL 和 CLL),然后使用分割节点将数据集分为训练集和测试集。对于这个案例研究,我们决定使用 60% 的数据用于训练,40% 的数据用于测试,并在类别列上使用分层抽样。
在加载和预处理图像(本地文件)组件中,图像被上传并预处理。
图 9.24 显示了这个组件的内部结构:

图 9.24 – 加载和预处理图像(本地文件)组件的内部
该组件使用循环来依次加载和预处理每一张图像。Chunk Loop Start节点以每个块一行的方式启动循环,而Loop End节点则在循环迭代结束时将结果行连接起来,结束循环。
在循环体内,Image Reader (Table)节点始终加载一张图像。然后,使用Image Calculator节点将图像归一化,每个像素值除以 255。
接下来,使用Image Cropper节点裁剪图像到可被 64 整除的大小。由于原始图像的尺寸为 1388px x 1040px,因此每个图像的左侧裁剪掉前 44 个像素,顶部裁剪掉 16 个像素。
此处的图 9.25展示了该节点的配置窗口:

图 9.25 – 图像裁剪器节点及其配置窗口
接下来,Splitter节点将每个图像拆分成 336 个 64 x 64 像素的小图像,将每个新子图像存储在新的一列中,共生成约 75,000 个补丁。此处的图 9.26展示了Splitter节点配置窗口中的高级标签,已设置生成图像每个维度的最大尺寸:

图 9.26 – Splitter 节点及其配置窗口
接下来,表格被转置为一列并重命名,然后通过Cross Joiner节点将类别信息添加到每个图像中。
现在我们已经准备好图像,可以继续执行最后的工作流。
训练网络
训练工作流的第一步是定义网络结构,使用VGG16 的卷积层作为起点。
VGG16 模型最初是为了预测 ImageNet 数据集中的类别而训练的。尽管该数据集包含 1,000 个类别,但其中没有任何类别与本研究中的三种癌症类型相匹配。因此,我们只回收 VGG16 网络中已训练好的卷积层。然后,我们会在其上添加一些新的神经层用于分类任务,并最终对得到的网络进行微调,以适应我们的任务。
为了训练最终的网络,我们将使用Keras Network Learner节点和从训练集图像中创建的约 75,000 个补丁。以下步骤由图 9.27所示的工作流执行:

图 9.27 – 训练工作流以训练新的网络来分类癌细胞图像
工作流首先读取包含完整网络结构和权重的 VGG16 网络的.h5文件,或者网络保存在仅包含网络结构的.json或.yaml文件中。
在这种情况下,我们读取了训练好的 VGG16 网络的.h5文件,因为我们打算利用网络中嵌入的所有知识。
VGG16 网络的输出张量的尺寸为
,这是最后一个最大池化层的输出大小。在我们能够为分类任务添加一些全连接层之前,我们使用Keras 展平层节点将输出展平。
现在,使用Keras 全连接层节点添加一个具有ReLU激活函数和 64 个神经元的全连接层。接下来,引入了一个Dropout 层节点,设置丢弃率为
。最后,最后一个Keras 全连接层节点定义了网络的输出。由于我们正在处理一个有三个不同类别的分类问题,因此采用了具有三个单元的softmax激活函数。
如果我们将最后一个Keras 全连接层节点的输出连接到Keras 网络学习器节点,我们将微调所有层,包括从 VGG16 模型中训练出来的卷积层。但我们不希望丢失所有这些知识!因此,我们决定不微调 VGG16 模型的层,而只训练新增的层。因此,VGG16 模型的层必须被冻结。
为了冻结网络的层,我们使用Keras 冻结层节点。图 9.28展示了该节点的配置窗口:

图 9.28 – Keras 冻结层节点及其配置窗口
在配置窗口中,您可以选择要冻结的层。在之后训练网络时,所选层的权重将不会更新,其他所有层将会被训练。我们冻结了除了 VGG16 网络末端添加的层以外的所有层。
在工作流的下半部分,我们使用表格读取器节点读取训练数据,并使用一对多节点对类别进行一热编码。
现在我们有了训练数据和网络结构,我们可以使用Keras 网络学习器节点对其进行微调。
与本书中的所有其他案例研究一样,输入数据和目标数据的列会在Keras 网络学习器节点的配置窗口中选择,并选择所需的转换类型。在本例中,输入列选择了从图像转换,目标列选择了从数字(双精度)转换。因为这是一个多类别分类任务,所以采用了类别交叉熵损失函数。为了微调该网络,它已使用训练批次大小为 64、优化器为 RMSProp(默认设置)训练了 5 个 epoch。
一旦网络经过微调,我们就可以评估其在测试图像上的表现。经过预处理的测试图像,以 64 x 64 像素的小块形式,通过Table Reader节点读取。为了预测图像的类别,我们使用Keras Network Executor节点为每个 64 x 64 像素的小块生成预测。然后,所有预测结果通过一个简单的多数投票方案结合起来,这个方案在Extract Prediction元节点中实现。
最后,使用Scorer节点评估网络。分类器已经达到了 96%的准确率(再微调几个周期可以将准确率提高到 98%)。
提示
在这个使用案例中,VGG16 模型仅用于特征提取。因此,另一种方法是提前应用 VGG16 模型的卷积层来提取特征,并将其作为输入馈送到经典的前馈神经网络中。这样做的好处是,VGG16 的前向传播仅需对每张图像进行一次,而不是在每次批处理更新时都进行。
我们现在可以保存网络并将其部署,例如,让病理学家通过网页浏览器访问这些预测。如何使用 KNIME Analytics Platform 和 KNIME Server 来实现这一点将在下一章中展示。
总结
在本章中,我们探讨了 CNN,重点讨论了图像数据。
我们从卷积层的介绍开始,这也促成了这一新型神经网络家族的命名。在这个介绍中,我们解释了为什么 CNNs 如此常用于图像数据,卷积网络是如何工作的,以及各种设置选项的影响。接着,我们讨论了池化层,它通常用于 CNNs 中以高效地下采样数据。
最后,我们将所有这些知识付诸实践,通过从头开始构建并训练一个 CNN 来对 MNIST 数据集中的数字 0 到 9 的图像进行分类。之后,我们讨论了迁移学习的概念,介绍了四种迁移学习应用场景,并展示了如何在神经网络领域应用迁移学习。
在上一节中,我们应用迁移学习训练了一个 CNN 来分类组织病理学切片图像。这一次,我们没有从头开始训练,而是重新使用了经过训练的 VGG16 模型的卷积层来提取图像的特征。
现在我们已经涵盖了许多不同的使用案例,接下来我们将进入下一步,即训练好的神经网络的部署。在下一章中,你将了解使用 KNIME 软件的不同部署选项。
问题与练习
-
卷积层中的核大小是什么?
a) 用统计值总结的区域
b) 图像中移动矩阵的大小
c) 矩阵移动的像素数量
d) 层使用的区域大小
-
什么是池化层?
a) 池化层是 RNN 中常用的层
b) 池化层用统计值总结一个区域
c) 池化层是前馈网络中常用的层
d) 池化层可以用来对图像进行上采样
-
转移学习在什么时候有帮助?
a) 将数据转移到另一个系统
b) 如果没有可用的模型
c) 如果没有足够的标注数据
d) 用于比较不同的模型
第三部分:部署与生产化
部署是整个数据分析项目中一个重要且具有决定性的阶段。因此,作为总结,我们将展示不同的部署选项,供已训练的神经网络使用。
本节包含以下章节:
-
第十章**, 部署深度学习网络
-
第十一章**, 最佳实践与其他部署选项
第十章:第十章: 部署深度学习网络
在本书的前几个部分,我们涵盖了多种不同用例下的深度神经网络训练,从用于欺诈检测的自编码器,到用于能耗预测和自由文本生成的 长短期记忆(LSTM)网络,再到癌细胞分类。但训练网络并不是项目的唯一部分。一旦深度学习网络训练完成,下一步就是进行部署。
在探索一些用例时,已经介绍了第二个工作流,用于将网络部署到实际数据中进行工作。因此,你已经看到了一些部署示例。然而,在本书的最后一部分,我们将重点关注机器学习模型的多种部署选项,特别是对于已训练的深度学习网络。
通常,会构建一个专门用于部署的第二个工作流。该工作流读取训练好的模型和新的实际数据,按照与训练数据相同的方式预处理这些数据,然后将训练好的深度学习网络应用于转换后的数据,并根据项目的需求生成结果。
本章重点介绍了部署工作流中数据的读取、写入和预处理。
本章首先回顾了保存、读取和转换训练网络的功能。接下来,介绍了如何在部署工作流中实现情感分析用例的预处理的两个示例。最后,本章展示了如何通过启用 GPU 支持来提高执行速度。
本章包含以下部分:
网络结构的转换
构建一个简单的部署工作流
提高可扩展性——GPU 执行
网络结构的转换
部署工作流的目标是将已训练的网络应用于新的实际数据。因此,训练工作流的最后一步必须是保存训练好的网络。
保存已训练的网络
本书中描述的所有网络都使用 Keras 库进行训练,并依赖 TensorFlow 作为后端。因此,保存网络的最自然方法是继续使用 Keras 库,并使用 .h5 文件。
然而,Keras 格式的网络只能通过 Keras 库进行解释和执行。这已经比 TensorFlow 库多了一层。在 TensorFlow Java API 上直接执行网络应用,而不是通过 Keras Python API 在 Python 内核上执行,可以提高执行速度。好消息是,KNIME 分析平台除了基于 Keras 库的节点外,还提供了用于 TensorFlow 执行的节点。
因此,如果需要更快的执行,应该将 Keras 网络转换为 TensorFlow 网络,使用 SavedModel 文件,即一个压缩的 zip 文件。SavedModel 文件包含完整的 TensorFlow 程序,包括权重和计算。它不需要原始的模型构建代码就能运行,这使得它在共享或部署时非常有用。
部署网络的第一步是读取一个已训练的网络。
读取已训练的网络
KNIME Analytics Platform 提供了许多节点用于读取已训练的神经网络,以下是其中一些:
-
Keras 网络读取器
-
TensorFlow 网络读取器(以及 TensorFlow 2 网络读取器)
-
DL Python 网络创建器
-
ONNX 网络读取器
.h5 文件)或者仅仅是没有权重的网络架构定义(如 .json 或 .yaml 文件)。你可以使用该节点读取通过 KNIME Analytics Platform 训练的网络,或者直接用 Keras 训练的网络,比如预训练的 Keras 网络。
zip 文件。如果是从目录读取,它必须是有效的 SavedModel 文件夹。如果是从 zip 文件读取,它必须包含一个有效的 SavedModel 文件夹。
提示
TensorFlow 网络读取器节点允许我们在其配置窗口中选择一个标签和一个签名。标签用于识别要加载的元图定义。SavedModel 的签名可以有多个标签,并且每个标签下可以有多个签名。通过 KNIME Analytics Platform 保存的网络只有一个标签和一个签名。在配置窗口的 高级 标签页中,你可以通过选择一个隐藏层作为输出,定义模型的输入和输出,从而定义自己的签名。
另一个节点是 ONNX 网络读取器 节点,它允许你在无需写任何代码的情况下读取预训练的网络。ONNX 代表 开放神经网络交换,是由微软和 Facebook 开发的神经网络标准格式。由于它是标准格式,ONNX 网络可以跨不同的机器学习框架使用,如 PyTorch、Caffe2、TensorFlow 等。你可以从 ONNX 模型库(github.com/onnx/models#vision)下载预训练的网络,并使用 ONNX 网络读取器节点读取它们。ONNX 网络还可以通过 ONNX 到 TensorFlow 网络转换器 节点转换为 TensorFlow 网络,然后使用 TensorFlow 网络执行器节点进行执行。
提示
要使用 ONNX 节点,你需要安装 KNIME 深度学习 – ONNX 集成 扩展。
另一种使用 Python 代码读取网络的方式是 DL Python 网络创建器 节点,它可以通过几行 Python 代码读取预训练的神经网络。
提示
DL Python 网络创建器节点也可以在训练工作流中使用,使用 Python 代码定义网络架构,而不是使用层节点。
到目前为止,我们使用了基于 Keras 的节点,TensorFlow 1 作为后端。也有使用 TensorFlow 2 作为后端的节点来实现类似的操作。
使用 TensorFlow 2
本书中的所有示例都使用了基于 Keras 的节点,TensorFlow 1 作为后端。自 KNIME Analytics Platform 4.2 版本发布以来,TensorFlow 2 也得到了支持。在 KNIME Hub 上,您可以找到许多如何使用 TensorFlow 2 集成的示例。
TensorFlow 2 集成提供了三个节点:
-
TensorFlow 2 网络执行器节点
-
TensorFlow 2 网络读取器节点
-
TensorFlow 2 网络写入器节点
要使用 TensorFlow 2 训练深度学习模型,可以使用 DL Python 网络学习器节点。
现在我们已经回顾了保存和读取神经网络的多种选项,让我们专注于构建一个简单的部署工作流。
构建一个简单的部署工作流
到目前为止,在我们探讨的所有案例研究中,我们总是对输入数据进行某种预处理,例如对分类特征进行编码、对文本进行编码或对数据进行归一化,仅举一些采用的预处理步骤。部署期间,新的输入数据必须经过与训练数据完全相同的预处理,以确保与任务以及网络期望的输入一致。
在本节中,我们使用第七章中的情感分析案例研究,实施 NLP 应用程序,作为示例,构建两个部署工作流。两个工作流的目标是从数据库中读取新的电影评论,预测情感,并将预测写入数据库。
在第一个示例中,预处理步骤被手动实现到部署工作流中。在第二个示例中,使用了集成部署功能。
手动构建部署工作流,无需集成部署
部署工作流应从数据库中的表格获取新的评论,应用训练好的网络,将带有相应预测的评论写入数据库中的另一张表,并删除第一张表中的评论。
这些步骤由图 10.1中的工作流执行,您可以从 KNIME Hub 下载,网址为:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter_10/:

图 10.1 – 来自第七章的情感分析案例研究的部署工作流,实施 NLP 应用程序
工作流首先使用SQLite 连接器节点连接到 SQLite 数据库,数据库中存储了新的电影评论。
接下来,SELECT SQL 语句通过DB Table Selector节点来读取名为new_reviews的表中的新评论。
SQL 语句通过DB Reader节点执行。因此,我们在节点的输出端口得到了包含新评论的数据表。
提示
在第二章中,使用 KNIME 分析平台进行数据访问和预处理详细介绍了数据库扩展。请记住,数据库节点在其输出的棕色方形端口上创建 SQL 语句。
在将网络应用于这些新评论之前,我们需要执行与训练工作流中相同的转换。在第七章中报告的训练工作流中,存在一个名为Preprocess test set的元节点,所有必要的预处理步骤都在其中应用于测试数据。我们使用这个元节点作为创建部署工作流中传入数据预处理步骤的基础。
图 10.2显示了该元节点的内容,它专门用于测试集的预处理:

图 10.2 – 第七章情感分析案例研究中训练工作流的测试数据预处理
在图 10.1的部署工作流中,首先读取训练过程中创建的字典;然后在Preprocessing元节点中执行预处理步骤。
图 10.3向您展示了此元节点内的工作流片段:

图 10.3 – 部署工作流中预处理元节点内的工作流片段
如果我们对比图 10.2和图 10.3中的工作流片段,可以看到它们包含了相同的预处理步骤,正如预期的那样。
现在,已经对部署数据应用了与训练数据相同的预处理,训练好的网络可以通过Keras Network Reader节点引入(图 10.1)。
接下来,训练好的网络通过Keras Network Executor节点在预处理过的部署评论上运行。网络的输出是情感为 1 的概率,其中 1 表示正面的电影评论。与训练时相同的阈值也通过Rule Engine节点应用在此:阈值为
。
在最后一步,数据库中的表格被更新。首先,DB Delete 节点从 new_reviews 表中删除我们刚刚分析的评论。然后,DB Writer 节点将带有预测的新电影评论附加到数据库中的另一个表格,名为 review-with-sentiment。
这是使用 KNIME Analytics Platform 部署神经网络的第一个示例。这个工作流应该定期执行,以预测所有新进电影评论的情感。
提示
KNIME Server 可以调度工作流的执行,因此你可以定期自动触发它们的执行。
这种方法有一个缺点。如果模型在更多数据上重新训练或使用不同的设置(例如,在训练过程中考虑的术语更多或更少,或规则引擎节点的阈值发生变化),我们需要记得更新部署工作流中的预处理步骤。由于我们是健忘的人类,可能会忘记或犯错。
克服这个问题的解决方案是 集成部署 的概念。
使用集成部署自动构建部署工作流
直到 KNIME Analytics Platform 4.2 版本,以及其他工具中,常见的做法是在部署工作流中手动实现数据混合、数据转换和网络执行。这意味着你需要从训练工作流中复制不同的预处理代码段、参数和网络执行节点到部署工作流中,确保所有设置保持不变。
这一手动步骤会减慢过程,并且很容易导致错误。自动构建部署工作流的部分内容可以是一个更安全的选择,尤其是在模型经常改变的情况下,例如每天甚至每小时都可能变化。
重要提示
训练过程的其他常见名称是数据科学创建或建模工作流。
来自集成部署扩展的节点弥合了创建和部署数据科学之间的差距。
集成部署扩展
集成部署扩展允许数据科学家将模型训练和部署合并成一个单一的工作流。其思想是在执行训练工作流的过程中,捕捉训练工作流的部分内容,并自动将它们写入部署工作流中。
不必逐个手动复制预处理部分,训练工作流中所需的部分会在 Capture Workflow Start 和 Capture Workflow End 节点之间捕捉。然后,通过 Workflow Writer 节点,捕捉到的工作流部分可以写入新的工作流。
在训练工作流中使用集成部署扩展
让我们再次考虑情感分析案例的部署工作流,该工作流在 第七章《实施 NLP 应用程序》中进行了描述。在训练工作流中,我们引入了 Capture Workflow Start 节点和 Capture Workflow End 节点,以便精确地隔离我们希望在部署工作流中重现的工作流片段。
这包括以下内容:
-
名为 Preprocessing test set 的元节点,包括所有所需的预处理步骤
-
Keras 网络执行器 节点,用于在部署后的数据上应用训练好的网络
-
Rule Engine 节点,根据应用于输出类别概率的阈值决定正类或负类
图 10.4 展示了基于情感分析案例的工作流示例。你可以从 KNIME Hub 下载该工作流:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter_10/:

图 10.4 – 使用集成部署自动创建部署工作流的训练工作流
粗体框中的部分是捕获的工作流片段。Capture Workflow Start 节点定义了工作流片段的开始,Capture Workflow End 节点定义了工作流片段的结束。
起始节点不需要任何配置。图 10.5 显示了 Capture Workflow End 节点的配置窗口:

图 10.5 – Capture Workflow End 节点的配置窗口
在配置窗口中,你可以设置捕获的工作流片段的名称。你还可以设置是否将捕获的片段与数据一起存储,如果是,设置应包含的最大数据行数。稍后我们将看到,存储一些数据在捕获的工作流片段中是如何有帮助的。
捕获的工作流片段,是否包含数据,将通过 Capture Workflow End 节点的输出端口(黑色方块)导出。在图 10.4 中,工作流片段随后被 Workflow Writer 节点收集并写入部署工作流,设置和配置保持不变。
图 10.6 显示了 Workflow Writer 节点的配置窗口:

图 10.6 – Workflow Writer 节点及其配置窗口
在顶部,你可以设置目标工作流的文件夹位置(输出位置)。
接下来,您需要设置目标工作流的名称。该节点会自动提供默认名称,您可以通过使用自定义工作流名称选项进行自定义。如果您选择的名称已经指向一个现有的工作流,您可以选择让写入节点失败或者覆盖。
在底部,您可以选择目标工作流的部署选项:仅创建、创建并打开,或保存为.knwf文件进行导出。
下图,图 10.7,展示了由工作流写入器节点自动生成的部署工作流:

图 10.7 – 通过集成部署捕获的工作流片段自动生成的部署工作流
在捕获的工作流中,您可以看到预处理测试集元节点,以及Keras 网络执行器、规则引擎和列过滤器节点。此外,整个集成部署过程还添加了以下内容:
-
两个引用读取器节点。它们是通用的读取器节点,加载在捕获的工作流片段中未找到的静态参数的连接信息。
-
容器输入(表格)和容器输出(表格)节点用于接受输入数据和分别将输出数据发送至其他应用程序。
可以通过另一个工作流使用调用工作流(基于表格)节点或通过 REST 服务触发此部署工作流,如果工作流已经部署在 KNIME 服务器上。在下一章中,我们将详细讨论 REST 调用和 REST 服务。
在图 10.7中,示例部署工作流在工作流顶部使用两个读取器节点读取两个实体,这两个节点内部没有图标。左侧节点基于训练数据提供字典表,右侧节点提供训练好的神经网络。
此外,您可以看到另外两个新节点,即容器输入(表格)和容器输出(表格)节点。
容器输入(表格)节点从外部调用者(即调用工作流(基于表格)节点)接收数据表,并在输出端口上提供。配置参数使外部调用者能够向容器输入(表格)节点发送数据表。
容器输入(表格)节点还有一个可选的输入端口(用未填充的输入端口表示)。如果连接了数据表到可选输入端口,节点将简单地将此表转发到下一个节点;如果通过 REST API 提供了表格,则提供的表格将在输出端口上可用。
如果没有输入,则节点输出默认模板表。这里涉及到来自捕获工作流结束节点的存储输入表格设置。如果选择存储某些数据行,则它们用于定义此默认模板表。
容器输出(表格)节点将 KNIME 数据表发送到外部调用者。
现在,让我们了解一下如何在部署过程中使用自动创建的工作流来预测新评论的情感。
使用自动创建的工作流
现在让我们来看一下如何使用部署工作流。
- 图 10.8展示了如何使用自动创建的部署工作流来分类新电影评论的情感,您可以从 KNIME Hub 下载该工作流进行试用,网址:
hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter_10/: - 图 10.8 – 调用自动创建的部署工作流的工作流

该工作流连接到数据库并读取新到的电影评论。
然后,调用工作流(基于表格)节点调用部署工作流(图 10.7),即自动构建的那个。调用工作流(基于表格)节点实际上会调用存储在本地工作区或挂载的 KNIME 服务器上的其他工作流。被调用的工作流必须至少包含一个容器输入节点和一个容器输出节点,以定义两个工作流之间的接口:被调用工作流和调用工作流。
通过调用工作流(基于表格)节点,我们将新的电影评论发送到部署工作流,以供容器输入(表格)节点使用。然后,部署工作流被执行,预测结果被发送回调用工作流,并通过调用工作流(基于表格)节点的输出端口提供。
这种策略的一个大优点是确保了训练工作流和部署工作流中的数据操作一致性。如果我们现在更改训练工作流中的数据操作设置,例如更改规则引擎节点中的阈值(图 10.4),并重新执行训练工作流,这些更改将自动导入到部署工作流的新版本中(图 10.7),并被任何依赖于该工作流的工作流使用(图 10.8)。
提示
集成部署扩展的另一个优秀节点是工作流合并器节点,它允许我们将不同原始工作流中的工作流片段合并在一起。
我们已进入本章的最后一部分,内容涉及可扩展性和 GPU 执行。
提高可扩展性 – GPU 执行
在本书中描述的案例研究中,我们使用了相对较小的数据集和小型网络。这使我们能够仅使用基于 CPU 的执行在几个小时内训练网络。然而,原本在小数据集上需要几分钟或几个小时的训练任务,在大数据集上可能需要几天或几周;小型网络架构很快就会增大,执行时间也会迅速变得不可承受。通常,在处理深度神经网络时,训练阶段是最为消耗资源的任务。
GPU 设计用于同时处理多个计算。这个范式非常适合训练深度学习网络所需的密集计算。因此,GPU 是在大数据集上高效有效地训练大规模深度学习网络的替代方案。
一些 Keras 库可以通过 TensorFlow 范式利用 NVIDIA® 兼容 GPU 的计算能力。因此,KNIME Keras 集成 也可以利用 GPU 的计算能力来更快速地训练深度学习网络。
在 第一章,使用 KNIME 分析平台介绍深度学习 中,我们介绍了如何为 KNIME Keras 集成和 KNIME TensorFlow 集成设置 Python。为了在 GPU 上运行 KNIME Keras 集成而不是在 CPU 上,您无需额外采取很多步骤。
当然,您需要一台支持 GPU 的计算机。TensorFlow 1.12 需要一张具有 CUDA 计算能力 3.5 或更高版本的 NVIDIA GPU 显卡。
此外,大多数所需的依赖项(即 CUDA® 和 cuDNN)将在安装 conda tensorflow=1.12 和 keras-gpu=2.2.4 软件包时由 Anaconda 自动安装。
安装过程中唯一的额外步骤是手动安装最新版本的 NVIDIA® GPU 驱动程序。
在安装时,通过选择 keras-gpu=2.2.4 创建。
在使用 TensorFlow 集成时,您还可以通过 GPU 执行以读取和执行 TensorFlow 的 SavedModel。
重要提示
KNIME TensorFlow 集成(使用 TensorFlow Java API)的 GPU 支持通常与 KNIME Keras 集成(使用 Python)的 GPU 支持是独立的。因此,两个 GPU 支持必须单独设置。由于 TensorFlow 的限制,KNIME TensorFlow 集成的 GPU 支持只能在 Windows 和 Linux 上运行,不能在 Mac 上运行。
在写作时,KNIME 推荐以下 GPU 配置。
KNIME TensorFlow 集成使用 TensorFlow 版本 1.13.1,这要求系统上安装以下 NVIDIA® 软件:
-
NVIDIA® GPU 驱动程序:CUDA® 10.0 需要 410.x 或更高版本。
-
CUDA® 工具包:TensorFlow(≥ 1.13.0)支持 CUDA® 10.0。
-
cuDNN(版本 ≥ 7.4.1):选择 cuDNN v7.6.0(2019 年 5 月 20 日)用于 CUDA® 10.0。
有关详细的说明和最新的更新,请查看 KNIME 文档 (docs.knime.com/2019-06/deep_learning_installation_guide/index.html#tensorflow-integration)。
总结
在这一章中,我们涵盖了三个不同的主题。我们从总结阅读、转换和写入神经网络的多种选项开始。
然后我们继续讨论神经网络的部署,使用来自 第七章的情感分析案例研究作为示例,实现 NLP 应用程序。这里的目标是构建一个工作流,使用训练好的神经网络预测存储在数据库中的新评论的情感。我们已经展示了可以通过两种方式组装部署工作流:手动或通过集成部署自动完成。
本章的最后部分讨论了网络训练和执行的可扩展性,特别是展示了如何在训练神经网络时利用 GPU 的计算能力。
在本书的下一章也是最后一章,我们将进一步探索部署选项以及在深度学习中工作的最佳实践。
问题和练习
-
KNIME 分析平台支持哪些网络转换?
a) Keras 到 TensorFlow 网络转换
b) TensorFlow 到 Keras 网络转换
c) ONNX 到 Keras 网络转换
d) Keras 到 ONNX 网络转换
-
关于集成部署,哪些陈述是正确的(有两个陈述是正确的)?
a) 集成部署允许我们在执行期间重新训练模型。
b) 自动生成的工作流的执行可以由另一个工作流触发。
c) 训练工作流的执行由部署工作流触发。
d) 集成部署缩小了训练和部署之间的差距。
第十一章:第十一章:最佳实践和其他部署选项
在第十章,深度学习网络的部署中,我们介绍了部署的概念,并展示了如何构建一个工作流将网络应用于新数据。在本章中,我们将重点介绍使用 KNIME 软件的另外两种部署选项。
本章的第一部分,你将学习如何将深度学习模型部署为一个 web 应用程序,以便最终用户可以通过 web 浏览器执行、交互并控制该应用程序。为了实现 web 应用程序,我们需要介绍 KNIME WebPortal,这是 KNIME Server 的一项功能。组件在 web 应用程序开发中起着核心作用,因为它们用于根据 KNIME 软件的引导分析功能实现交互点。在本章中,你还将更多地了解组件。
另一种消费深度学习模型的部署选项是通过 REST 接口的 web 服务。由于 web 服务能够让你在同一生态系统中无缝而轻松地集成和协调多个应用程序,因此它们最近变得非常流行。在本章的第二部分,你将学习如何使用 KNIME 软件构建、部署并调用作为 REST 服务的工作流。
本章的结尾部分,我们将提供一些最佳实践建议以及在使用神经网络和 KNIME 分析平台时的技巧与窍门。这些最佳实践和技巧来源于我们多年来在深度学习项目中的实际经验,其中一些已经在本书中有所描述。
本章的组织结构如下:
-
构建 web 应用程序
-
使用 REST 接口构建 web 服务
-
KNIME 技巧与窍门
构建 web 应用程序
在这一部分中,我们将向你展示使用 KNIME 软件构建web 应用程序所需的几个步骤。
在简要介绍KNIME WebPortal之后,我们将展示如何创建复合视图,如何将它们包含在内以创建交互点,以及如何按照引导分析原则将应用程序结构化为一系列作为交互点的网页。
作为示例,我们将应用所学的知识,围绕第九章,卷积神经网络在图像分类中的应用案例研究中的癌细胞分类部署工作流,构建一个 web 应用程序。
KNIME WebPortal 简介
构建 web 应用程序的第一步是设计并实现工作流中的一系列基于 web 的交互点。在一个癌细胞分类的案例研究中,我们的数据科学家可以构建一个部署工作流,包含两个交互点:一个允许最终用户上传组织病理切片图像,另一个在最终的网页上展示结果。在这两个交互点之间,工作流会摄取新的图像并执行训练好的模型来进行分类。
一旦工作流准备好,它将被转移到生产 KNIME 服务器。从此以后,工作流可以通过任何 web 浏览器通过 KNIME WebPortal 按需访问。基于 web 的交互方式使病理学家能够控制整个过程,而无需熟悉 KNIME Analytics Platform 或深度学习算法。图 11.1 向您展示了这个基于 web 的应用程序可能的样子:

](https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/cdls-dl-knime/img/B16391_11_001.jpg)
图 11.1 – 通过 KNIME 工作流实现的 web 应用程序,运行在 KNIME Server 上,并可以通过任何 web 浏览器通过 KNIME WebPortal 调用
在这个例子中,web 应用程序非常简单。它只有两个交互点——即两个网页:第一个用于图像上传,第二个用于查看结果。
可以使用 KNIME Analytics Platform、KNIME Server 和 KNIME WebPortal 的组合,开发更复杂的无代码 web 应用程序。像 Guided Visualization、Guided Labeling 和 Guided Automation 等一些相当复杂且设计精美的 web 应用程序示例,可以从 KNIME Hub 下载(hub.knime.com)。
与 KNIME Analytics Platform 相比,KNIME Server 不包含数据操作或模型训练算法。然而,它包含了完整的 IT 基础设施,允许团队成员之间的协作,应用程序的按需和定时执行,定义每个注册用户或用户组的访问权限,模型管理,审计功能,当然还有部署选项,正如我们将在本章中看到的那样。此外,与 KNIME Analytics Platform 相比,KNIME Server 不是开源的,而是需要购买年度许可证。图 11.2 显示了 KNIME WebPortal 的登录页面:

图 11.2 – KNIME WebPortal 登录页面
在 KNIME Server 提供的众多 IT 功能中,KNIME WebPortal 允许您通过任何 web 浏览器查看和管理工作流。这个功能看起来很简单,但它可能是数据科学家和最终用户之间缺失的纽带。
重要提示
最终用户是某一领域的专家,通常既没有时间也没有兴趣打开 KNIME Analytics Platform 查看工作流和节点。最终用户所需要的,只是一个在网页浏览器上运行的舒适的 Web 应用程序,且只显示他们需要看到的信息;至少,包括数据上传页面和总结结果的最终页面。
WebPortal 不需要任何特殊安装。它已经随 KNIME Server 的安装预先打包。然而,其外观可以通过专用的CSS 样式表轻松定制。KNIME WebPortal 只接受注册用户,并且需要登录(图 11.2)。
成功登录后,起始页面会显示您有权限访问的文件夹。导航到您想要开始的工作流,然后点击运行(图 11.3):

图 11.3 – 在 KNIME WebPortal 上选择的工作流的起始页面
重要提示
KNIME Server 是 KNIME Analytics Platform 的补充工具。虽然 KNIME Analytics Platform 拥有所有算法和数据操作功能,KNIME Server 提供了团队协作、应用自动化、模型管理和部署选项所需的 IT 基础设施。
让我们来看看工作流如何结构化,以便在 KNIME WebPortal 上创建一个具有定义交互选项的页面序列。
创建一个在 KNIME WebPortal 上运行的工作流
在 KNIME WebPortal 上执行工作流时,从一个网页移动到下一个网页。这些页面,也称为向导步骤,为最终用户提供了可视化引导操作的可能性,使其能够与流程进行交互。
现在,如果我们必须从头开始构建所有这些页面/步骤,那将会是漫长且复杂的。幸运的是,有了组件。每个页面/步骤只是将组件在底层工作流中的复合视图的内容可视化。因此,实际实现 WebPortal 的一系列网页仅仅对应于实现一系列具有所需复合视图的组件。
图 11.4 的上半部分展示了在 KNIME WebPortal 上运行的一个应用程序的三个网页:一个从数据库导入客户的表单;一个散点图和一个表格,二者相互连接,用于选择客户;最后是一个展示选定客户信息的页面。图 11.4 的下半部分展示了对应的工作流和三个组件。每个组件的复合视图在 KNIME WebPortal 上执行工作流时会生成一个页面:

图 11.4 – 上:在 KNIME WebPortal 上执行应用程序的步骤。下:生成网页的对应工作流
图 11.4 中的工作流用作从 web 浏览器执行工作流的步骤示例,并涉及客户数据集。我们将仅使用此数据集,因为它使我们能够展示在组件构建中使用的多种不同功能。此 web 应用程序旨在允许最终用户检查客户数据并选择高风险流失的客户,以便由团队成员联系。
第一个组件,从数据库获取客户,创建了左侧的第一页。在这里,最终用户必须提供他们的用户名和密码以连接到数据库。
点击右下角的下一步按钮后,工作流会执行直到到达下一个组件选择要联系的客户,并创建相应的网页。在此页面上,最终用户可以通过散点图和表格查看客户数据,并选择要联系的客户。选择时,视图提供了两个交互选项:通过左上角的单选按钮选择产品,或使用左下角的范围滑块更改流失分数。散点图和表格会根据新的选择参数自动更新。一旦最终用户对选择满意,他们再次点击下一步以进入 web 应用的最后一页。
最后一页由浏览并下载客户列表组件创建。在这里,每个选定客户的数据以卡片视图呈现,并可以导出为 Excel 文件。该工作流可在 KNIME Hub 上找到:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter_11/。
提示
要打开 KNIME Analytics Platform 中已存在组件的交互视图,执行后,右键点击该组件并选择交互视图:<组件名称>。
总结一下,每一页都是由工作流中的一个组件创建的,并显示其交互视图。组件及其复合视图是构建 web 应用工作流的关键元素。
现在让我们看看如何创建和自定义一个复合视图。
创建复合视图
组件的复合视图收集了其中包含的视图和小部件节点的所有交互视图。
提示
要创建一个新组件,您必须选择要包含在组件中的节点,然后右键点击并选择创建组件...选项。
在深入查看视图和小部件节点之前,我们先来看一下选择要联系的客户组件(图 11.5):

图 11.5 – 选择要联系的客户组件的内容
在相应页面的左下角,最终用户可以通过滑块定义流失分数的阈值。这个交互式滑块由交互式范围滑块筛选器小部件节点创建。
在左上角,选择产品的选项由交互式值筛选器小部件节点创建。
此外,页面展示了一个交互式散点图和一个交互式表格。这两个视图分别由散点图节点和表格视图节点创建。
如你所见,每个小部件/视图节点为最终的复合视图添加一个元素,因此也为 WebPortal 中的相应页面添加内容。
提示
在 KNIME 分析平台中,右键点击节点并选择交互式视图:<节点名称>,即可查看每个小部件/视图节点的视图。
可以为复合视图贡献元素的节点可分为三类:
-
小部件节点
-
视图节点
-
交互式小部件节点
让我们详细看看每个类别。
小部件节点
小部件节点生成带有交互式表单的视图,用于设置参数。新设置的参数随后作为流变量导出,并可以被工作流中其他节点使用。
提示
在第二章《使用 KNIME 分析平台进行数据访问和预处理》中,我们介绍了流变量的概念以及它们如何用于覆盖设置选项。
每个小部件节点专门用于生成一种特定的输入或交互表单,如字符串输入、整数输入、从列表中选择一个或多个值等。你可以在节点库的工作流抽象 | 小部件中找到所有可用的小部件节点,如图 11.6所示:

图 11.6 – 节点库中的可用小部件节点
小部件节点本身可以分为三组:
-
输入小部件节点:输入类别中的小部件节点在网页上生成一个输入表单,允许你将不同类型的值输入到工作流中——整数、字符串、布尔值、双精度数或列表——以及其他格式的数据,如日期和时间或凭证。
-
选择小部件节点:选择类别中的小部件节点生成网页表单,用于从列表中选择值,例如从数据表中选择特定列、包括/排除数据集中的多列,或选择一个或多个值以从表中筛选数据。
-
输出小部件节点:这些小部件节点向复合视图中添加自定义文本、链接或图像。
作为一个例子,图 11.7展示了单选小部件节点及其配置窗口:

图 11.7 – 单选小部件节点及其配置窗口
大多数小部件节点共享一些重要的设置,如标签、描述和变量名:
-
标签:这将在小部件节点创建的表单顶部创建一个标签。
-
描述:该值作为工具提示显示在小部件表单上。
-
变量名:这为节点创建的流程变量提供名称。
让我们来看一下单选小部件节点的附加配置设置(图 11.7):
-
选择类型:定义用于选择的对象:下拉菜单、垂直或水平单选按钮,或列表。
-
可能的选择:定义可供选择的值列表。
-
默认值:为选择操作分配一个初始默认值。
标准小部件节点产生一些流程变量或一个表格作为输出,可以在工作流中的下游节点中使用。一组特殊的小部件节点是交互式小部件节点。
视图节点
视图节点通过交互式图表、图形和表格可视化数据。
图 11.8 向您展示了节点库中可用的视图节点概览:

图 11.8 – 节点库中可用的视图节点
如果一个组件中包含多个视图节点,它们的视图将在生成的组件视图中相互交互;例如,通过选择,在一个节点的视图中选择的数据点可以在另一个节点的视图中被选择或甚至被隔离。
提示
Plotly节点和JavaScript节点位于实验室类别中,提供更多的交互式选项,用于在复合视图中可视化数据。来自本地(Swing)类别中(本地)节点的视图不能集成到组件的复合视图中。
交互式小部件节点
交互式小部件节点是特殊的小部件节点。它们实现过滤事件并提供视图节点。在执行过程中,交互式小部件节点的变化会立即反映在后续视图节点的视图中。
在撰写本文时,KNIME Analytics Platform 提供了两个交互式小部件节点:交互式范围滑块过滤器小部件节点和交互式值过滤器小部件节点。
这些节点可用于触发复合视图中的更新。在下游视图节点的配置窗口中,我们可以设置该节点是否应监听先前交互式小部件节点的过滤事件。如果设置为“是”,当先前交互式小部件节点的过滤事件中的设置发生变化时,由视图节点生成的视图会立即更新。
与标准小部件节点相比,这两个节点会在打开的复合视图或网页中触发直接的过滤事件。标准小部件节点创建的流程变量可以被后续节点使用,但不会在打开的页面或复合视图中触发直接变化。
现在我们已经概览了可用于构建复合视图的节点,让我们通过一些布局选项来定制一个组件的复合视图。
定义复合视图的布局
你可以为每个包含至少一个小部件或视图节点的组件定义复合视图的布局。
提示
要在工作流编辑器中以新标签页打开一个组件,必须按住Ctrl键并双击组件,或者右键点击组件并选择组件 | 打开。
复合视图中的布局通过组件内部的布局编辑器进行设置。在工作流编辑器中新标签页打开组件内容后,点击顶部工具栏最右侧的布局编辑器按钮,如图 11.9所示:

图 11.9 – 带有布局编辑器按钮的工具栏,位于最右侧
单击布局编辑器按钮后,打开可视化布局编辑器(图 11.10):

图 11.10 – 可视化布局编辑器
布局编辑器使用具有行和列的网格结构。
左侧有不同列数的行模板,以及所有尚未放置的视图列表。右侧是布局编辑器本身。
你可以通过将新行模板从左侧的模板列表拖放到右侧的布局编辑器来更改布局。要添加一个新的空列,请点击布局编辑器中的+按钮。行中的列可以手动调整大小。
布局编辑器中的空单元格可以通过将未使用视图从视图列表中拖放到布局编辑器中的单元格来填充。
默认布局仅由一列组成,所有来自小部件和视图节点的视图都从上到下放置在其中。要从空白画布开始,请点击布局编辑器左上角的清除布局按钮。此清除操作将所有视图添加到左侧列表中。
提示
节点标签(节点下方的文本)在布局编辑器中用于标识视图。最佳实践是将节点标签更改为有意义的描述,以便在布局编辑器中轻松识别视图。
如果你想将一个节点的视图从复合视图中排除,可以进入布局编辑器的第一个标签,名为节点使用,并禁用 WebPortal/复合视图的节点视图。
还可以拥有嵌套组件,即一个组件内嵌另一个组件。如果嵌套组件有视图,它将在布局编辑器中显示为一个节点视图。因此,您可以像处理其他任何节点一样,将嵌套组件的视图集成到您的布局中。
复合视图可以很容易地美化——例如,通过添加一个头部或侧边栏,并对正文进行样式设置。幸运的是,KNIME Hub 上有共享组件可以帮助完成这一点。
图 11.11 显示了使用一些共享组件后,网页样式元素前后的变化:

图 11.11 – 没有(左)和有(右)页眉、侧边栏以及页面主体中附加信息的网页
在本节的末尾,当我们构建癌细胞分类示例时,你将看到一些共享组件的实际应用。
让我们首先了解更多关于共享组件的信息。
共享组件
在上一节《创建复合视图》中,我们讨论了如何使用组件创建复合视图,并为 WebPortal 应用程序创建页面。组件还可以打包成可重用的功能,并通过 KNIME Hub 和 KNIME Server 与他人共享。这些功能从简单的重复性任务,如将凭证输入数据库,到更复杂的任务,如优化参数,种类繁多。
与元节点相比,组件拥有自己的配置窗口。可以在不触及内部节点的情况下进行配置,这提供了一种便捷的方式来隐藏配置的复杂性。当然,如果需要,你仍然可以打开组件,深入查看细节,并根据你的使用情况进行任何调整。
要在组件的配置窗口中添加设置,可以使用 配置节点。它们的工作方式类似于小部件节点,但作用于配置窗口级别,而非复合视图级别。你可以在节点库中找到它们,路径为 工作流抽象 | 配置。与任何 KNIME 节点一样,组件也可以在 描述 面板中拥有描述。从组件内部,你可以通过点击 描述 面板左上角的笔图标来编辑描述。
要使组件变得像其他所有的 KNIME 节点一样,它们必须是共享的。
要共享一个组件,你可以右键点击它并选择 组件 | 共享…。
然后,你可以决定将模板保存在哪里:本地工作区、KNIME Hub 或 KNIME Server。
接下来,你可以选择链接类型,将组件实例与组件模板进行关联。链接类型定义了在检查更新时组件模板的位置。选择完组件模板的目标后,会弹出一个对话框询问你选择链接类型:
-
创建绝对链接:工作流在查找组件模板时使用绝对路径。
-
创建挂载点相对链接:工作流在查找组件模板时,使用从所选挂载点开始的相对路径。
-
创建工作流相对链接:工作流在查找组件模板时使用相对路径,该路径从当前工作流文件夹开始。
-
不要与共享实例创建链接:一个组件模板已创建,但没有与当前实例建立链接。
小贴士
当你将工作流部署到 KNIME 服务器时,请确保组件实例上的所有链接类型在服务器上也能正常工作。
要创建共享组件的实例,只需将组件模板从 KNIME Hub 或 KNIME Explorer 拖放到工作流编辑器中。新创建的实例是只读的,并且与相应的共享组件链接。
每次启动工作流时,KNIME 分析平台会搜索组件模板的可能更新,如果有任何更新,它会建议同时更新该实例。这有一个优点,如果组件模板中发生了变化,实例中的变化会自动反映出来。
小贴士
由于是只读的,新的实例无法编辑。你需要先断开实例与模板的连接才能更改其内容。为此,你需要右键点击组件实例,并选择 组件 | 断开链接。
在 EXAMPLES 服务器或 KNIME Hub 上有许多公共共享组件。你还可以在 KNIME Hub 的本章工作流组中找到一些共享组件。
现在你已经熟悉了共享组件和 WebPortal,让我们看看癌细胞分类的部署示例。
为癌细胞分类构建 WebPortal 应用程序
让我们回到癌症数据和 第九章 中描述的癌细胞分类工作流,用于图像分类的卷积神经网络。在这一节中,我们将展示如何使用 KNIME WebPortal 将训练好的深度学习模型部署为一个网页应用程序。
这里的目标是为那些不熟悉 KNIME 分析平台和数据科学的病理学家制作一个网页应用程序。它应该能帮助他们在日常工作中,通过分析组织病理学图像时,提供癌症分类的建议。另一个要求是,能够在不重新启动应用程序的情况下,连续上传多个图像。图 11.12 展示了实现该应用程序的工作流。你可以从 KNIME Hub 下载该工作流:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/Chapter_11/。
首先,让我们关注工作流的中间部分:注释框中的循环体:

图 11.12 – 从网页浏览器部署工作流评分新的组织病理学图像
每次迭代时,都会上传一张图像,生成分类,并向病理学家展示两个网页。循环负责迭代和循环体中的两个组件——上传图像组件和查看结果组件——的网页:

图 11.13 – 上传图像组件内的工作流及其创建的网页
循环体从上传图像组件开始,该组件创建了 Web 应用程序的第一个网页。您可以在图 11.13中看到创建的页面以及组件内部的情况。
网页的头部,由 KNIME 徽标和导航路径组成,是由名为WebPortal Header的共享组件创建的。对于具有多个步骤的 WebPortal 应用程序,这样的头部有助于最终用户概览当前步骤(在框架中)、已经完成的步骤(黄色框或浅灰色框)以及尚未完成的步骤(灰色框)。
WebPortal Header组件左下角的小绿箭头表示该组件实例与共享组件模板相连。WebPortal Header组件带有一个配置窗口(图 11.14),这是由其中的配置节点生成的。在该配置窗口中,您可以定义步骤标签,并设置是否用黄色框突出显示当前步骤:

图 11.14 – WebPortal Header 组件的配置窗口
上传图像步骤的网页仅包含一个项目,用于上传下一张图像。通过点击选择文件按钮,病理学家将含有组织病理切片图像的文件上传到临时本地文件夹。该项目由文件上传控件节点创建。该节点的输出变量包含指向临时文件夹中所选图像的文件路径。
在图 11.12中的工作流中,流变量通过Variable to Table Row节点写入一个表格。加载和预处理图像元节点执行与训练时相同的预处理步骤,如在第九章中所述,卷积神经网络用于图像分类。也就是说,它加载图像,进行归一化处理,将其分割为 64x64 像素的小块,并交换某些维度,以适应作为迁移学习起点的 VGG16 模型。
接下来,工作流使用Keras 网络读取器节点读取训练好的深度学习网络,并通过Keras 网络执行器节点将其应用于图像小块。
在准备可视化元节点中,根据图像属于三类癌症之一的概率,为图像小块分配颜色。
最后,结果通过最后一个组件查看结果进行可视化。图 11.15展示了该组件内部的工作流以及在浏览器中执行工作流后获得的相应网页:

图 11.15 – 查看结果组件内部的工作流片段及其创建的网页
在查看结果组件中,我们再次发现共享的WebPortal Header组件,用于创建页面头部,这一次带有上传图片框(过去步骤)和结果框(当前步骤),黄色框架。
表格到图像节点将选定列的第一行中的图像转换为图像对象。然后,该图像对象被传入图像输出小部件节点,在复合视图中显示出来。
最后,病理学家必须决定是否上传另一张图片。这个选择部分通过单选按钮在网页上实现,并通过单选小部件节点在工作流中实现。
这个节点在其输出端口生成一个带有选定选项的流变量:

图 11.16 – 变量条件循环结束节点的配置窗口
整个片段,从上传图片到查看结果,被包装在一个循环中,以满足额外的需求,给病理学家提供上传多张图片的选项。最后的单选按钮选择作为循环停止的标准。
提示
请记住,循环始终需要一个循环开始节点和一个循环结束节点。在这两个节点之间是循环体,它会在每次循环迭代时执行。
有许多不同的循环开始和循环结束节点可供选择。例如,有些节点每次迭代时只使用一部分行(分组循环开始和块循环开始),有些节点则只使用一部分列(列列表循环开始)。
图 11.12 中的工作流使用 keepgoing – 由 No 创建。由于通用循环开始节点始终需要输入表格,因此使用空表创建器节点创建了一个空表来喂给该节点。
在将此工作流部署到 KNIME 服务器并在 KNIME WebPortal 上运行后,病理学家可以轻松地上传新图像并获得自动分类的结果。
在本节中,您已经了解了如何使用 KNIME 软件构建 Web 应用程序,并且了解了如何将深度学习网络作为 Web 应用程序进行部署。
现在让我们来看看如何将深度学习网络作为 REST 服务进行部署。
使用 REST 接口构建 Web 服务
在本节中,您将学习如何使用 KNIME 软件构建REST服务。作为实际示例,我们将通过第七章中的情感分析示例的部署工作流进行讲解,实现自然语言处理应用程序。
KNIME 服务器 REST API 为非 KNIME 应用程序提供了一个接口,通过简单的 HTTP 请求与 KNIME 服务器进行通信。RESTful Web 服务的主要好处是它可以轻松地将应用程序集成到企业的 IT 环境中。自包含和独立的应用程序可以通过 REST 接口相互调用并交换数据。通过这种方式,向生态系统中添加新应用程序变得更加容易。
在 KNIME 服务器上上传的任何工作流都会通过REST API自动提供。这使得您能够通过 REST API 将 KNIME 工作流无缝部署为 Web 服务,并将其集成到数据科学实验室的基础设施中。
在情感分析示例中,我们希望将深度学习网络部署为REST 服务。通过这种方式,外部应用程序——例如,网站或移动应用——可以将一些文本发送到 REST 服务,并返回预测的情感。
让我们快速了解一下在 KNIME 分析平台中将部署工作流作为 REST 服务所需的步骤。
构建 REST 服务工作流
在情感预测示例中,目标是构建一个具有输入(新的电影评论)和输出(情感预测)的 REST 服务。
在构建有输入和输出的 REST 服务时,我们需要定义输入和输出的结构。在 KNIME 分析平台中,这可以通过容器输入和输出节点来完成。
重要说明
并非所有的 REST 服务都有输入和输出。例如,一个连接到数据库以获取最新数据的 REST 服务只有输出。一个通过将结果写入数据库来结束过程的 REST 服务则不需要输出任何结果。
KNIME 分析平台提供了多种输入节点,可以用来定义 REST API 的输入结构。您可以在节点库中的工作流抽象 | 工作流调用下找到这些节点(图 11.17):

图 11.17 – 定义 REST API 的可用容器节点
如图 11.17所示,有四个容器输入节点——用于凭证、仅用于一行数据、用于数据表或用于流变量。表格输入允许您将单行数据或多行数据发送到 Web 服务。另一方面,行输入仅发送一行数据。
容器输入(行)和容器输入(表格)节点具有一个可选的输入端口。该端口接收一个模板数据表,并基于该表格定义输入结构。此模板有两个作用:首先,如果在通过 REST API 调用工作流时未提供输入表格,则使用模板中的值作为默认输入来执行工作流。其次,表格用于定义 Web 服务期望的输入结构。如果当前输入的结构与模板不同,Web 服务将产生错误信息。这种模板技术的优点是输入会自动解析并转换为指定的类型。
同样,若要定义 REST 服务的输出,可以使用其中一个容器输出节点:容器输出(行)节点或容器输出(表格)节点。
对于我们的部署工作流,为了对一次电影评论进行分类,我们使用了容器输入(行)节点来定义输入结构,并使用容器输出(行)节点来定义输出结构以传递给 REST 服务。为了同时分类一条或多条电影评论,可以使用容器输入(表格)节点和容器输出(表格)节点。
创建可以作为 REST 服务部署的工作流有两种方法:
-
通过集成部署功能自动化
-
手动从头构建工作流
在第十章,部署深度学习网络中,我们介绍了 KNIME Analytics Platform 的集成部署扩展,该扩展允许你捕获训练工作流的部分并自动部署它们。即使在此,我们也以情感分析案例研究为例。在图 11.18中,你可以看到通过集成部署自动创建的工作流,其中包括一个容器输入(表格)节点和一个容器输出(表格)节点,用于定义输入和输出数据结构:

图 11.18 – 从第十章《部署深度学习网络》自动创建的部署工作流
在第十章,部署深度学习网络中,我们将这个自动创建的工作流保存在本地,并通过调用工作流(基于表格)节点触发其执行。我们也可以选择不将工作流保存到本地,而是将其部署到 KNIME 服务器上。
另一种选择是从头手动构建一个 REST 服务。在这种情况下,我们必须提供字典和训练好的模型(图 11.19):

图 11.19 – 手动构建的 REST 服务部署工作流
如你所见,它看起来与图 11.18中的工作流非常相似,唯一的区别是它使用了Table Reader节点和Keras 网络读取器节点来读取字典和训练好的模型。此外,已经插入了一个模板表来定义 REST API 的输入数据结构。
我们已经有了 REST 服务。接下来,看看如何调用它。
调用 REST 服务
要从外部应用程序调用已部署的工作流作为 REST 服务,你需要知道 REST 服务的路径以及预期的输入数据结构。KNIME 服务器可以在浏览器中显示 API 定义。只需右键点击服务器上已部署的工作流并选择显示 API 定义。浏览器窗口将打开,显示该特定工作流的 REST API 定义(图 11.20):

图 11.20 – 使用 Swagger 的 REST API 文档
这个网页是使用一个名为Swagger的开源框架创建的。Swagger 已被集成到 KNIME 服务器中,用于文档化 REST API,方便地浏览不同的 HTTP 请求并进行测试。
例如,你可以测试如何通过POST请求触发 REST 服务的执行。通过选择 POST 请求,Swagger 会显示可能的参数概览、输入数据的架构以及调用的 URL。你还可以点击尝试一下按钮来进行测试。
你还可以通过使用调用工作流(基于表格)节点从另一个工作流中触发 REST 服务的执行。该节点可以调用本地或远程工作流,发送提供的输入表并输出 REST 服务的响应。
图 11.21中的工作流展示了如何在 KNIME 服务器上触发 REST 服务的执行:

图 11.21 – 此工作流触发在 KNIME 服务器上执行 REST 服务
如果你想在 KNIME 服务器上运行工作流,你必须确保调用工作流节点已连接到服务器。要连接到 KNIME 服务器,可以使用KNIME 服务器连接节点。在其配置窗口中,你需要提供服务器的地址,可以手动输入或选择一个挂载点并输入凭据。
在调用工作流(基于表格)节点的配置窗口中,你可以通过点击浏览工作流按钮查看所有在 KNIME 服务器上部署的工作流。选择工作流后,在高级设置中,你可以将输入表分配给被调用工作流的输入,将输出表分配给被调用工作流的输出。当部署的工作流有多个输入节点时,这个功能非常方便。
在本节中,你学习了如何将工作流部署为 KNIME Server 上的 REST 服务。现在,让我们通过一些来自我们自身经验的小贴士来做个总结。
KNIME 小贴士与技巧
在本书中,我们讨论了许多使用 KNIME Analytics 平台实施的案例研究。在本书的 KNIME Hub 空间中,你可以找到这些工作流,并可以将它们作为深度学习项目的起点:hub.knime.com/kathrin/spaces/Codeless%20Deep%20Learning%20with%20KNIME/latest/。在最后一节中,我们将分享一些在 KNIME Analytics 平台中进行深度学习的技巧与窍门。
让我们从训练数据的洗牌开始。
训练过程中洗牌数据
在训练神经网络时,为了加速训练过程的收敛并避免过拟合,建议在每个训练周期前对训练数据进行洗牌。
为此,确保在Keras Network Learner节点的配置窗口的高级标签中激活每个训练周期前洗牌训练数据复选框。
使用批量归一化
批量归一化是一种标准化每个批次数据的技术。这一技术有助于稳定学习过程,并显著减少训练深度网络所需的训练周期数。
要向你的网络添加批量归一化,你可以使用Keras 批量归一化层节点。
保持工作流的整洁和结构化
为了方便维护你的工作流,重要的是要以逻辑清晰、易于理解的块状结构来记录和组织它们:
-
使用元节点和组件:为了保持大型工作流的整洁,建议将实现细节和一些复杂性隐藏在元节点或组件中。事实上,为了让工作流在初次查看时就能容易理解,你可以为项目中的每个步骤创建一个元节点或组件,如数据访问、数据预处理、模型训练和模型评估。在每个元节点/组件内部,你还可以进一步创建元节点和组件来表示不同的子步骤,例如不同的预处理步骤或网络层。
-
记录工作流:KNIME Analytics 平台为你提供了三种记录工作流的方法:
a) 节点标签
b) 注释框
c) 工作流描述
节点标签和注释框可以帮助你和其他用户一眼理解工作流的任务和子任务。
也可以通过描述面板向你的工作流添加元信息。为此,点击工作流编辑器中的任意位置(不要点击节点)。描述视图会切换为工作流描述,显示有关工作流的元信息:标题、描述以及相关链接和标签。
使用 GroupBy 节点和 Pivoting 节点来避免循环
循环的执行可能较慢,因为每次迭代时都必须执行节点。然而,通常由于我们编程背景的原因,我们会过度使用循环,甚至在有更高效的替代方案时也使用它们。
例如,可以通过简单地使用以下聚合节点来避免一些循环:GroupBy、Pivoting、Ungroup 和 Unpivoting。Aggregation 节点通常执行与循环相同的任务,并且在执行速度上更为高效。
指定执行顺序
当工作流中有并行分支时,有时需要定义执行顺序。图 11.22 向你展示了一个非常简单的例子,强制执行将表格写入 Excel 表格的顺序:

图 11.22 – 在此工作流中,使用流变量连接强制执行顺序。
当然,Excel Sheet Appender (XLS) 节点应在 Excel Writer (XLS) 节点之后执行。通过使用从 Excel Writer (XLS) 节点的流变量输出端口到 Excel Sheet Appender (XLS) 节点的流变量输入端口的流变量连接,我们强制 Excel Sheet Appender (XLS) 节点仅在 Excel Writer (XLS) 节点执行完成后才开始执行。
总结
在本章中,你了解了部署已训练的深度学习网络的另外两种选项:Web 应用程序和 REST 服务。我们以一些成功使用 KNIME Analytics Platform 进行深度学习的技巧和窍门结束了这一章——也是结束了本书。
在本章的第一部分,你学习了如何使用 KNIME Server 的 KNIME WebPortal 构建 Web 应用程序,以便最终用户可以方便地通过 Web 浏览器执行他们的工作流并与网页互动。
接下来,你学习了如何使用 KNIME Server 构建、部署和调用 REST 服务,将深度学习网络集成到公司的 IT 基础设施中。你了解了定义 REST 服务输入和输出数据结构的多种选项,如何使用开源 Swagger 工具检查 REST API,以及如何从 KNIME Analytics Platform 内部触发 REST 服务的执行。
在最后一节中,我们整理了一些来自我们自身经验的技巧和窍门,这些技巧在使用 KNIME Analytics Platform 进行深度学习时可能会非常有用。
此时,我们认为你已经掌握了足够的知识,能够开始使用 KNIME 软件构建和部署自己的工作流,以训练和使用适合你自己业务案例和数据的深度学习网络。
问题与练习
-
你可以使用哪种类型的节点向复合视图添加输入字段?
a) 配置节点
b) 小部件节点
c) 视图节点
d) 容器输入节点
-
如何创建复合视图?
a) 通过选择一些节点,右键点击,选择创建元节点
b) 通过选择一些视图或小部件节点,右键点击,选择创建元节点
c) 通过选择一些视图或小部件节点,右键点击,选择创建组件
d) 通过在工作流中的任意位置右键点击并选择创建组件
-
如何定义复合视图的布局?
a) 右键点击组件并选择组件 | 布局
b) 双击组件并进入配置窗口中的布局标签
c) 进入组件内部,点击工具栏中的布局按钮
d) 右键点击组件并选择布局
-
哪个节点可以用来定义 REST 服务的输入和输出?
a) 配置节点
b) 小部件节点
c) 查看节点
d) 容器节点
第十二章:你可能会喜欢的其他书籍
如果你喜欢这本书,你可能对 Packt 出版的其他书籍感兴趣:

深度学习实用数学
Jay Dawani
ISBN: 978-1-83864-729-2
-
理解构建神经网络模型的关键数学概念
-
发现核心的多变量微积分概念
-
使用优化技术提高深度学习模型的性能
-
覆盖优化算法,从基本的随机梯度下降(SGD)到高级的 Adam 优化器
-
理解计算图及其在深度学习中的重要性
自动驾驶汽车的应用深度学习与计算机视觉
Sumit Ranjan, Dr. S. Senthamilarasu
ISBN: 978-1-83864-630-1
-
使用 Keras 库从零开始实现深度神经网络
-
理解深度学习在自动驾驶汽车中的重要性
-
掌握使用 OpenCV 库进行图像处理中的特征提取技术
-
设计一个软件管道,用于检测视频中的车道线
-
实现一个卷积神经网络(CNN)图像分类器,用于交通信号标志识别
-
通过在虚拟模拟器中驾驶汽车训练和测试神经网络进行行为克隆
-
发现各种最先进的语义分割和目标检测架构
留下评论 - 让其他读者知道你的想法
请在你购买书籍的站点上分享你对这本书的想法。如果你从亚马逊购买了这本书,请在该书的亚马逊页面上留下真实的评论。这对其他潜在读者非常重要,他们可以通过你的无偏见意见做出购买决定,同时我们也能了解客户对我们产品的看法,作者可以看到他们与 Packt 合作创作的书籍的反馈。留下评论只需要几分钟时间,但对其他潜在客户、我们的作者和 Packt 都非常有价值。感谢你的支持!







在输出层的所有单位中计算。然后,
从输出层反向传播通过所有网络连接(和权重)直到输入层,所有隐藏层中的
也被计算。这就是后向传播:
:
对于
和 
或
来计算输出
,根据权重矩阵
,并且可能是
或
:





训练样本,计算方法如下:
训练样本,它的计算公式如下:
,我们有原始的前馈网络,具有权重矩阵
和
,输入为
和
,输出为
。
,我们再次得到了原始的前馈网络,具有权重矩阵
和
,但这次的输入是
和
,输出是
。
,我们再次得到了原始的前馈网络,具有权重矩阵
和
,但这次的输入是
和
,输出是
。
提供,大小为
,由一系列
维向量组成
,大小为
,由一系列
维向量组成
,与输出张量
相关,用作网络记忆
不是整个网络的输出,而只是这个递归单元的输出——即整个网络的中间隐藏状态。
维向量(这些
过去的样本)。
,其中
是源语言的词典大小。输入张量形状中的?表示可变长度的序列,而n表示具有
个组件的 one-hot 向量。在我们的示例中,英语语言的形状为
,输入张量的形状是[?,71]。
是一个元组,其中
代表变量长度,
代表输入序列中每个向量的大小——即目标语言(德语)的词汇表大小。在我们的示例中,德语的输入张量形状为
。





这通常与情境 3 一起发生。
浙公网安备 33010602011771号