当前位置:   article > 正文

无监督学习与生成式人工智能(MEAP)(三)

无监督学习与生成式人工智能(MEAP)(三)

原文:zh.annas-archive.org/md5/ef4ba0ae2a37f1fc608875bd4cfb7156

译者:飞龙

协议:CC BY-NC-SA 4.0

第七章: 无监督学习用于文本数据

“每个人用相同的语言微笑 - 乔治·卡林”

我们的世界有这么多语言。这些语言是我们表达思想和情感的最常见媒介。用文字表达我们的想法的能力是人类独有的。这些词语对我们来说是信息的来源。这些词语可以被写成文本。在本章中,我们将探讨我们可以对文本数据进行的分析。文本数据属于非结构化数据,并携带着大量有用信息,因此是业务洞察的有用来源。我们使用自然语言处理或 NLP 来分析文本数据。

与此同时,为了分析文本数据,我们必须准备好数据分析。简单来说,由于我们的算法和处理器只能理解数字,我们必须用数字或向量表示文本数据。我们在本章中探讨了所有这些步骤。文本数据包含了一些重要用例的关键,如情感分析、文档分类、语言翻译等等。我们将通过案例研究来涵盖这些用例,并在此基础上开发 Python 解决方案。

本章从定义文本数据、文本数据的来源和文本数据的各种用例开始。然后,我们将转向清理和处理文本数据的步骤和过程。我们将涵盖 NLP 的概念、数学基础和将文本数据表示为向量的方法。我们将为用例创建 Python 代码。最后,我们分享了关于文本数据的案例研究。在这本书中,我们提供了适当深度的数学支持,而不会深入探讨过多 - 这是实际世界和数学概念的最佳结合。

在本书的第七章中,我们将涵盖以下主题:

  1. 文本数据和文本数据分析的各种用例

  2. 我们在处理文本数据时面临的挑战

  3. 文本数据的预处理和数据清理

  4. 将文本数据表示为向量的方法

  5. 使用 Python 进行情感分析 - 一个案例研究

  6. 使用 Python 进行文本聚类

欢迎来到第七章,祝你一切顺利!

7.1 技术工具包

我们将继续使用到目前为止所用的相同版本的 Python 和 Jupyter 笔记本。本章中使用的代码和数据集已经上传到了这个位置。

在本章中,您需要安装一些 Python 库,它们是 - XXXX。除此之外,我们还需要 numpy 和 pandas。使用库,我们可以非常快速地实现算法。否则,编写这些算法是非常耗时且繁琐的任务。

在这里,我们正在处理文本数据,也许你会发现它非常有趣和有用。

让我们开始书的第七章吧!

7.2 文本数据无处不在

请回忆一下书的第一章,我们探讨了结构化和非结构化数据集。非结构化数据可以是文本、音频、图像或视频。下面给出了非结构化数据及其来源的示例(请参见图 7-1),我们解释了非结构化数据的主要类型:文本、图像、音频和视频以及它们的示例。本章重点是文本数据。

图 7-1 非结构化数据可以是文本、图像、音频、视频。本章我们处理文本数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

语言确实是赐予人类的礼物。我们沉迷于说话、发短信、写作、倾听来传达我们的想法。而这是通过生成的文本数据来完成的,这些数据是由博客、社交媒体帖子、推文、评论、故事、评价、对话等产生的。文本数据通常更加直接,情感更具表达力。必须解锁文本数据的潜力,并从中得出见解。我们可以更好地了解我们的客户,探索业务流程,并衡量提供的服务质量。我们生成的文本数据以新闻、Facebook 评论、推文、Instagram 帖子、客户评价、反馈、博客、文章、文学、故事等形式存在。这些数据代表了各种情绪和表达。

你是否在亚马逊上评论过产品或服务?你给产品评星级,同时也可以输入自由文本。去亚马逊看一些评论吧。你可能会发现一些评论有很多文字作为反馈。这些文本对产品/服务提供商来说是很有用的,可以帮助他们改进他们的产品/服务。此外,你可能参与了一些调查,要求你分享反馈。另外,随着 Alexa、Siri、Cortana 等技术的出现,语音指令正在充当人类和机器之间的接口 - 这又是一个丰富的数据来源。甚至我们打给客服中心的电话也可以成为文本数据的来源。这些通话可以被记录,并通过语音转文字转换,我们可以生成大量的文本数据。海量数据集,对吧!

我们将在下一节讨论一些文本数据的重要用例。

7.3 文本数据的用例

文本数据确实非常有用。对于业务而言,这真是一个见解丰富的来源。下面列出了一些令人感兴趣的用例。列表并不是详尽无遗的。同时,并非所有给出的用例都实施无监督学习。有些用例也需要监督学习。尽管如此,为了让你了解,我们分享了基于监督学习和无监督学习的两种用例 - 基于监督学习和无监督学习的用例。

  1. **情感分析:**你可能参与过调查或针对产品/调查提供了反馈。这些调查为我们生成了大量文本数据。可以分析这些文本数据,我们可以确定评论中的情感是积极的还是消极的。简单来说,情感分析就是评估文本数据中的积极性或消极性。因此,客户对产品或服务的情感是什么。我们可以使用监督式和非监督式学习进行情感分析。

  2. **新闻分类或文档分类:**看看 Google 新闻网页,你会发现每个新闻都被分类为体育、政治、科学、商业或任何其他类别。传入的新闻将根据实际文本的内容进行分类。同样,想象一下,我们手头有一些文档,我们可能想根据它们的类别或研究领域进行区分。例如,医学、经济学、历史、艺术、物理等。这样的用例确实会节省大量时间和人力。

  3. **语言翻译:**从一种语言到另一种语言的文本翻译是一个非常有趣的用例。使用自然语言处理可以在各种语言之间进行翻译。语言翻译非常棘手,因为不同的语言有不同的语法规则。通常,基于深度学习的解决方案最适合语言翻译。

  4. **垃圾邮件过滤:**可以使用自然语言处理和监督式机器学习来构建电子邮件垃圾邮件过滤器。监督式学习算法可以分析传入邮件的参数,并可以预测该邮件是否属于垃圾邮件文件夹。预测可以基于诸如发件人电子邮件 ID、主题行、邮件正文、附件、邮件时间等各种参数。通常,在这里使用监督式学习算法。

  5. 词性标注或 POS 标注是其中一个受欢迎的用例。这意味着我们能够区分句子中的名词、形容词、动词、副词等。命名实体识别或 NER 也是自然语言处理的著名应用之一。它涉及在句子中识别人物、地点、组织、时间、数字。例如,John 住在 London 并为 Google 工作。NER 能够生成类似[John][Person]住在[London][Location]并为[Google][organization]工作的理解。

  6. 生成句子,为图像加标题,语音转文本或文本转语音任务,手写识别是其他一些重要和受欢迎的用例。

上述列出的用例并不是穷尽的。还有大量其他用例可以使用自然语言处理实现。NLP 也是一个非常受欢迎的研究领域。我们在本章末尾分享了一些重要的论文供您参考。

虽然文本数据非常重要,但同时也是一种难以分析的数据集。需要注意的是,我们的计算机和处理器只能理解数字。因此,文本仍然需要表示为数字,以便我们可以对其进行数学和统计计算。但在深入研究文本数据准备之前,我们将介绍在处理文本数据集时面临的一些挑战。

7.4 文本数据的挑战

文本可能是最难处理的数据。有很多种方式可以表达同样的想法。例如,如果我问:“嘿,伙计,你几岁了?”和“嘿,伙计,我可以知道你多大了吗?”意思相同,对吧!对于人类来说,回答这两个问题是相同的,并且很容易解释。但对于机器来说可能是同样艰巨的任务。

我们面临的最常见的挑战有:

  1. 处理文本数据可能很复杂。文本中可能有很多垃圾字符,比如$^%*&之类的。

  2. 随着现代通信的发展,我们开始使用缩写词,比如“u”可以代表“you”,“brb”可以代表“be right back”等。

  3. 语言在变化,解除了限制,不断发展。它每天都在变化,新词汇不断被加入到语言中。

如果你做一个简单的谷歌搜索,你会发现每年都有相当多的词汇被添加到词典中。

  1. 世界上有近 6500 种语言,每一种语言都具有其独特性。每一种语言都构成了我们的世界。例如,阿拉伯语、中文、英语、法语、德语、印地语、意大利语、日语、西班牙语等。每种语言都有自己独特的用法和语法规则。甚至写作方式也可能不同 - 有些从左到右书写;有些可能从右到左书写,或者垂直书写!相同的情感,在不同语言中可能需要更少或更多的词汇来表达。

  2. 一个词的意义取决于上下文。一个词在不同的上下文中可以是形容词,也可以是名词。看看下面这些例子:

  3. “这本书是必读的”和“请为我预订一个房间”。

  4. “汤米”可以是一个名字,但当用作“汤米·希尔菲格”时,它的用法完全改变了。

  5. “苹果”是一种水果,而“Apple”是一家生产 Macintosh、iPhone 等产品的公司。

  6. “四月”是一个月份,也可以是一个名字。

  7. 再看一个例子 - “马克从英国去了法国,正在那里和约翰一起工作。他想念他的朋友”。人类很容易理解第二句中的“他”是指马克而不是约翰,这对于机器来说可能不那么简单。

  8. 同一个词可能有很多同义词,比如“好”在不同情境中可以用“积极的”、“精彩的”、“出色的”、“异常的”来替换。或者,像“studying”、“studying”、“studies”、“studies”这样的词都与同一个词根“study”相关。

  9. 文本数据的大小也可能令人生畏。管理文本数据集、存储它、清理它并更新它本身就是一项艰巨的任务。

像任何其他的机器学习项目一样,文本分析遵循机器学习的原则,尽管确切的过程略有不同。回想一下第一章,我们在图 7-2 中展示了机器学习项目的流程。建议您从第一章刷新一下流程。

图 7-2 数据科学项目的整体步骤对文本数据也是一样的。文本数据的预处理与结构化数据集非常不同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定义业务问题、数据收集和监控等工作保持不变。主要的差异在于文本的处理,包括数据清理、特征创建、文本数据的表示等。我们现在来介绍它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

弹出测验 – 回答这些问题来检查你的理解。答案在书的末尾。

(1) 文本数据的三个最有影响力的用例是什么?

(2) 为什么处理文本数据如此繁琐?

7.5 文本数据的预处理

文本数据,像任何其他数据源一样,可能会杂乱无章。我们在数据发现阶段清理了一部分数据,而在预处理阶段清理了大部分数据。同时,我们需要从数据集中提取特征。这个清理过程有时是相似的,并且可以应用于大多数文本数据集。一些文本数据集可能需要定制的处理方法。我们将从清理原始文本数据开始。

7.5.1 数据清理

数据质量的重要性不容置疑。文本数据越干净,分析结果就会越好。与此同时,预处理并不是一项简单的任务。这是一个复杂且耗时的任务。

文本数据需要进行清理,因为它包含了大量的垃圾字符、无关的词语、噪音和标点符号、URL 等。清理文本数据的主要方法有:

  1. 停用词去除: 在任何语言中,有一些词是最常见的。停用词是词汇中最常见的单词,比关键词的重要性低。例如,“是”,“一个”,“这”,“有”,“已经”,“它”等。一旦我们从文本中去除了停用词,数据的维度就被减少了,因此解决方案的复杂性也减少了。

    与此同时,在去除停用词时,我们必须非常了解上下文。例如,如果我们问一个问题“下雨了吗?”。那么答案“下雨了”就是一个完整的答案。

    要去除停用词,可以定义一个定制的停用词列表并去除它们。否则,也可以使用标准库去除停用词。

当我们在处理需要上下文信息很重要的解决方案时,我们不会去除停用词。

  1. 基于频率的词汇移除: 有时,您可能希望移除文本中最常见或非常独特的词。这个过程是获取文本中词语的频率,然后设置一个频率阈值。我们可以移除最常见的词。或者也许您希望移除整个数据集中只出现一次/两次的词。根据需求,您将决定。

  2. 基于库的清洗是在我们希望使用预定义和自定义库来清理数据时进行的。我们可以创建一个词库,其中包含我们不希望在文本中出现的词,然后可以迭代地从文本数据中移除它们。这种方法允许我们以自己的选择实施清理。

  3. 垃圾或不需要的字符: 文本数据,特别是推文、评论等,可能包含许多 URL、标签、数字、标点符号、社交媒体提及、特殊字符等。我们可能需要从文本中清除它们。与此同时,我们必须小心,因为对于一个领域不重要的一些词对于另一个领域可能是非常重要的。如果数据被从网站或 HTML/XML 来源中爬取,我们需要摆脱所有 HTML 实体、标点符号、非字母等。

清理文本数据时,始终要牢记业务背景。

我们知道很多新类型的表达进入了语言。例如,lol,hahahaha,brb,rofl 等。这些表达必须被转换为它们的原始含义。甚至像:-),;-)等表情符号也必须被转换为它们的原始含义。

  1. 数据编码: 有许多数据编码可用,如 ISO/IEC,UTF-8 等。通常,UTF-8 是最流行的。但不是硬性规定一定要使用 UTF-8。

  2. 词典归一化: 根据上下文和使用情况,同一个词可能以不同的方式被表示。在词典归一化期间,我们清理这样的歧义。基本思想是将单词缩减到其根形式。因此,从彼此派生出来的词可以映射到中心词,只要它们有相同的核心含义。

    看一下图 7-2,在这里我们展示了相同的单词“eat”,已经被用在各种形式中。根词是“eat”,但这些不同的形式是 eat 的许多不同表达。

图 7-3 Ate,eaten,eats,eating 都有相同的根词——eat。词干提取和词形恢复可用于获取根词。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们希望将所有这些词,如 eating,eaten 等,映射到它们的中心词“eat”,因为它们具有相同的核心含义。在这方面有两种主要方法可以处理:

  1. 词干提取: 词干提取是一种基本的基于规则的方法,将一个单词映射到它的核心词。它会去掉单词末尾的“es”,“ing”,“ly”,“ed”等。例如,studies 会变成 studi,studying 会变成 study。显然,作为一种基于规则的方法,输出的拼写可能并不总是准确的。

  2. 词形还原:是一种有组织的方法,将单词缩减为它们的词典形式。单词的Lemma是其词典或规范形式。例如,eats, eating, eaten 等所有单词都有相同的根词 eat。词形还原提供比词干提取更好的结果,但它需要比词干提取更多的时间。

这些只是清洗文本数据的一些方法。这些技术在很大程度上会有所帮助。但是,仍然需要商业眼光来进一步理解数据集。我们将通过开发 Python 解决方案来使用这些方法清洁文本数据。

一旦数据被清洗,我们就必须开始表示数据,以便机器学习算法可以处理它 - 这是我们的下一个主题。

7.5.2 从文本数据集中提取特征

文本数据,就像任何其他数据源一样可能会混乱和嘈杂。我们在上一节中探讨了清理它的概念和技术。现在我们已经清理了数据,准备好使用。下一步是以算法可以理解的格式表示这些数据。我们知道我们的算法只能理解数字。文本数据在其最纯粹的形式下无法被算法理解。因此,一切都需要转换为数字。

一个非常简单的技术可以是简单地对我们的单词进行独热编码,并将它们表示为矩阵。

我们在书的前几章已经介绍了独热编码

如果我们描述这些步骤,那么单词可以首先转换为小写,然后按字母顺序排序。然后可以为它们分配一个数字标签。最后,单词将被转换为二进制向量。让我们通过一个例子来理解。

例如,文本是“It is raining heavily”。我们将使用以下步骤:

  1. 小写单词,所以输出将会是“it is raining heavily”

  2. 现在我们将它们按字母顺序排列。结果是 - heavily, is, it, raining。

  3. 现在我们可以为每个单词分配位置值,如 heavily:0, is:1, it:2, raining:3。

  4. 最后,我们可以将它们转换为如下所示的二进制向量

[[0\. 0\. 1\. 0.] #it
[0\. 1\. 0\. 0.] #is
[0\. 0\. 0\. 1.] #raining
[1\. 0\. 0\. 0.]] #heavily
  • 1
  • 2
  • 3
  • 4

尽管这种方法非常直观和简单易懂,但由于语料库和词汇的庞大规模,实际上是不可能的。

语料库指的是一系列文本。它是拉丁文的意思。它可以是一组书面文字或口头文字,用于进行语言分析。

此外,处理如此多维的大数据集将在计算上非常昂贵。因此创建的矩阵也将非常稀疏。因此,我们需要寻找其他方法来表示我们的文本数据。

有更好的替代方案可用于一热编码。这些技术侧重于单词的频率或单词的使用上下文。这种科学方法的文本表示更准确、更健壮、更具解释性。它也产生更好的结果。有多种这样的技术,如 tf-idf、词袋模型等。我们将在接下来的章节中讨论其中一些技术。但我们首先会考察标记化的一个重要概念!

Tokenization(标记化)

Tokenization(标记化)就是简单地将文本或一组文本分解成单个标记。它是自然语言处理的基本构件。看一下图 7-3 中的示例,我们为句子中的每个单词创建了单独的标记。标记化是一个重要的步骤,因为它允许我们为每个单词分配唯一的标识符或标记。一旦我们为每个单词分配了特定的标记,分析就变得不那么复杂了。

图 7-3 标记化可以将句子分解为不同的单词标记。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标记通常用于单个单词,但并不总是必要的。我们可以将一个单词或单词的子词或字符进行标记化。在子词的情况下,同一句子可以有子词标记,如 rain-ing。

如果我们希望在字符级别执行标记化,那么可以是 r-a-i-n-i-n-g。实际上,在上一节讨论的一热编码方法中,标记化是在单词上进行的。

标记化是自然语言处理解决方案的基石。

一旦我们获得了标记,那么这些标记就可以用来准备一个词汇表。词汇表是语料库中唯一标记的集合。

有多个用于标记化的库。Regexp 标记化使用给定的模式参数来匹配标记或标记之间的分隔符。Whitespace 标记化通过将任何空白字符序列视为分隔符来使用。然后我们有 blankline,它使用空白行的序列作为分隔符。Wordpunct 标记化通过匹配字母字符序列和非字母非空白字符序列来进行标记化。当我们为文本数据创建 Python 解决方案时,我们将执行标记化。

现在,我们将探讨更多表示文本数据的方法。第一个这样的方法是词袋模型。

词袋模型方法

正如名称所示,语料库中的所有单词都会被使用。在词袋模型方法中,或者说 BOW 方法中,文本数据被标记化为语料库中的每个单词,然后计算每个标记的相应频率。在此过程中,我们忽略语法、单词的顺序或上下文。我们只专注于简单性。因此,我们将每个文本(句子或文档)表示为它自己的单词袋

在整个文档的 BOW 方法中,我们将语料库的词汇表定义为语料库中存在的所有唯一单词。请注意,我们使用语料库中的所有唯一单词。如果我们愿意,我们也可以设置一个阈值,即单词被选中的频率的上限和下限。一旦我们获得了唯一的单词,那么每个句子都可以用与基础词汇向量相同维度的向量来表示。这个向量表示包含了句子中每个单词在词汇表中的频率。这听起来可能很复杂,但实际上这是一种直接的方法。

让我们通过一个例子来理解这种方法。假设我们有两个句子——It is raining heavily 和 We should eat fruits。

要表示这两个句子,我们将计算这些句子中每个单词的频率,如图 7-4 所示。

图 7-4 每个单词的频率已经计算出来了。在这个例子中,我们有两个句子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,如果我们假设只有这两个单词代表整个词汇表,我们可以将第一个句子表示如图 7-5 所示。请注意,该表格包含了所有单词,但是不在句子中的单词的值为 0。

图 7-5 第一个句子对于词汇表中的所有单词进行了表示,我们假设词汇表中只有两个句子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这个例子中,我们讨论了如何使用 BOW 方法将句子表示为向量。但 BOW 方法没有考虑单词的顺序或上下文。它只关注单词的频率。因此,它是一种非常快速的方法来表示数据,并且与其同行相比计算成本较低。由于它是基于频率的,所以它通常用于文档分类。

但是,由于其纯粹基于频率的计算和表示,解决方案的准确性可能会受到影响。在语言中,单词的上下文起着重要作用。正如我们之前所看到的,苹果既是一种水果,也是一个著名的品牌和组织。这就是为什么我们有其他考虑比仅仅是频率更多参数的高级方法。下面我们将学习一种这样的方法,即 tf-idf 或词项频率-逆文档频率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

弹出测验——回答这些问题以检查你的理解。答案在本书的末尾。

(1) 用简单的语言解释标记化,就好像你在向一个不懂 NLP 的人解释一样。

(2) Bag of words 方法关注单词的上下文而不仅仅是频率。True or False.

(3) Lemmatization is less rigorous approach then stemming. True or False.

tf-idf(词项频率和逆文档频率)

我们在上一节学习了词袋方法。在词袋方法中,我们只重视单词的频率。这个想法是,频率较高的词可能不像频率较低但更重要的词那样提供有意义的信息。例如,如果我们有一套医学文件,我们想要比较两个词“疾病”和“糖尿病”。由于语料库包含医学文件,单词疾病必然会更频繁,而“糖尿病”这个词会更少,但更重要,以便识别处理糖尿病的文件。tf-idf 方法使我们能够解决这个问题,并提取更重要的词的信息。

在术语频率和逆文档频率(tf-idf)中,我们考虑单词的相对重要性。TF-idf 表示术语频率,idf 表示逆文档频率。我们可以定义 tf-idf 如下:

  1. 术语频率(t是整个文档中术语的计数。例如,文档“D”中单词“a”的计数。

  2. 逆文档频率(id是整个语料库中总文档数(N)与包含单词“a”的文档数(df)的比率的对数。

因此,tf-idf 公式将为我们提供单词在整个语料库中的相对重要性。数学公式是 tf 和 idf 的乘积,表示为

w[i,j] = tf[i,j] * log (N/df[i]) (方程式 7-1)

其中 N:语料库中的文档总数

tf[i,j]是文档中单词的频率

df[i]是包含该词的语料库中的文档数量。

这个概念听起来可能很复杂。让我们通过一个例子来理解。

假设我们有一百万本运动期刊的集合。这些运动期刊包含了许多不同长度的文章。我们还假设所有文章都只有英语。所以,假设在这些文件中,我们想要计算单词“ground”和“backhand”的 tf-idf 值。

假设有一个包含 100 个词的文档,其中“ground”出现了五次,而“backhand”只出现了两次。所以 ground 的 tf 为 5/100 = 0.05,而 backhand 的 tf 为 2/100 = 0.02。

我们了解到,“ground”这个词在体育中是相当常见的词,而“backhand”这个词的使用次数会较少。现在,我们假设“ground”出现在 100,000 个文档中,而“backhand”只出现在 10 个文档中。所以,“ground”的 idf 为 log (1,000,000/100,000) = log (10) = 1。对于“backhand”,它将是 log (1,000,000/10) = log (100,000) = 5。

要得到“ground”的最终值,我们将 tf 和 idf 相乘= 0.05 x 1 = 0.05。

要得到“backhand”的最终值,我们将 tf 和 idf 相乘= 0.02 x 5 = 0.1。

我们可以观察到,“背手”这个词的相对重要性要比单词“地面”的相对重要性更高。这就是 tf-idf 相对于基于频率的 BOW 方法的优势。但是,与 BOW 相比,tf-idf 计算时间更长,因为必须计算所有的 tf 和 idf。尽管如此,与 BOW 方法相比,tf-idf 提供了一个更好、更成熟的解决方案。

接下来我们将在下一节中介绍语言模型。

语言模型

到目前为止,我们已经学习了词袋模型方法和 tf-idf。现在我们将专注于语言模型。

语言模型分配概率给词的序列。N-grams 是语言模型中最简单的模型。我们知道,为了分析文本数据,它们必须被转换为特征向量。N-gram 模型创建了特征向量,使得文本可以以进一步分析的格式来表示。

n-gram 是一个概率语言模型。在 n-gram 模型中,我们计算第 N^(th) 个词在给定(N-1)个词的序列的情况下出现的概率。更具体地说,n-gram 模型将基于词 x[i-(n-1)], x[i-(n-2)]…x[i-1] 预测下一个词 x[i]。若我们希望使用概率术语,可以表示为给定前面的词 x[i-(n-1)], x[i-(n-2)]…x[i-1] 的条件概率 P(x[i] | x[i-(n-1)], x[i-(n-2)]…x[i-1])。该概率通过文本语料库中序列的相对频率计算得出。

若条目是单词,n-grams 可能被称为shingles

让我们用一个例子来学习这个。

假设我们有一个句子 It is raining heavily。我们已经使用不同的 n 值展示了相应的表示方式。您应该注意到,对于不同的 n 值,单词的序列以及它们的组合方式是如何变化的。如果我们希望使用 n=1 或单个词来进行预测,表示将如图 7-6 所示。请注意,此处每个词单独使用。称为unigrams

如果我们希望使用 n=2,那么现在使用的词数量将变为两个。它们被称为bigrams,这个过程将继续下去。

图 7-6 Unigrams, bigrams, trigrams 可以用来表示相同的句子。这个概念也可以扩展到 n-grams。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,如果我们有一个 unigram,那么它是一个词的序列;对于两个词的序列,称为 bigram;对于三个词的序列,称为 trigram,依此类推。因此,trigram 模型将使用仅考虑前两个词的条件概率来逼近后一个词的概率,而 bigram 则仅考虑前一个词的条件概率。这确实是一个非常强的假设,即一个词的概率只取决于之前的一个词,被称为马尔可夫假设。一般来说,N > 1 被认为较 unigrams 更加信息丰富。但显然计算时间也会增加。

n-gram 方法对 n 的选择非常敏感。它还在很大程度上取决于所使用的训练语料库,这使得概率非常依赖于训练语料库。因此,如果遇到一个未知单词,模型将很难处理该新单词。

我们现在将创建一个 Python 示例。我们将展示一些使用 Python 进行文本清洗的示例。

使用 Python 进行文本清洗

我们现在将用 Python 清洗文本数据。有一些库可能需要安装。我们将展示一些小的代码片段。你可以根据需要使用它们。我们还附上了代码片段及其结果的相应截图。

代码 1:删除文本中的空格。我们导入库re,它被称为正则表达式。文本是 It is raining outside with a lot of blank spaces in between.

import re
doc = "It is     raining       outside"
new_doc = re.sub("\s+"," ", doc)
print(new_doc)
  • 1
  • 2
  • 3
  • 4

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码 2:现在我们将从文本数据中删除标点符号。

text_d = "Hey!!! How are you doing? And how is your health! Bye, take care."
re.sub("[^-9A-Za-z ]", "" , text_d)
  • 1
  • 2

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码 3:这是另一种去除标点符号的方法。

import string
text_d = "Hey!!! How are you doing? And how is your health! Bye, take care."
cleaned_text = "".join([i for i in text_d if i not in string.punctuation])
cleaned_text
  • 1
  • 2
  • 3
  • 4

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码 4:我们现在将删除标点符号,并将文本转换为小写。

text_d = "Hey!!! How are you doing? And how is your health! Bye, take care."
cleaned_text = "".join([i.lower() for i in text_d if i not in string.punctuation])
cleaned_text
  • 1
  • 2
  • 3

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码 5:我们现在将使用标准的nltk库。标记化将在这里使用 NLTK 库完成。输出也附在下面。

import nltk
text_d = "Hey!!! How are you doing? And how is your health! Bye, take care."
nltk.tokenize.word_tokenize(text_d)
  • 1
  • 2
  • 3

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,在代码的输出中,我们有包括标点符号的所有单词作为不同的标记。如果你希望排除标点符号,可以使用之前共享的代码片段来清理标点符号。

代码 6:接下来是停用词。我们将使用 nltk 库删除停用词。然后,我们将对单词进行标记。

stopwords = nltk.corpus.stopwords.words('english')
text_d = "Hey!!! How are you doing? And how is your health! Bye, take care."
text_new = "".join([i for i in text_d if i not in string.punctuation])
print(text_new)
words = nltk.tokenize.word_tokenize(text_new)
print(words)
words_new = [i for i in words if i not in stopwords]
print(words_new)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码 7:我们现在将在文本示例上执行词干提取。我们使用 NLTK 库进行词干提取。首先对单词进行标记,然后我们对其应用词干提取。

import nltk
from nltk.stem import PorterStemmer
stem = PorterStemmer()
text = "eats eating studies study"
tokenization = nltk.word_tokenize(text)
for word in tokenization:
    print("Stem for {} is {}".format(word, stem.stem(w)))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码 8:我们现在将在文本示例上执行词形还原。我们使用 NLTK 库进行词形还原。首先对单词进行标记,然后我们对其应用词形还原。

import nltk
from nltk.stem import WordNetLemmatizer
wordnet_lemmatizer = WordNetLemmatizer()
text = "eats eating studies study"
tokenization = nltk.word_tokenize(text)
for word in tokenization:
    print("Lemma for {} is {}".format(word, wordnet_lemmatizer.lemmatize(w)))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

观察并比较词干提取和词形还原的两个输出之间的差异。对于 studies 和 studying,词干提取生成的输出为 studi,而词形还原生成了正确的输出 study。

到目前为止,我们已经介绍了词袋模型、tf-idf 和 N-gram 方法。但在所有这些技术中,忽略了单词之间的关系,而这些关系在词嵌入中被使用 - 我们的下一个主题。

词嵌入

“一个单词的特点在于它周围的公司” - 约翰·鲁珀特·费斯。

到目前为止,我们研究了许多方法,但所有的技术都忽略了单词之间的上下文关系。让我们通过一个例子来学习。

假设我们的词汇表中有 100,000 个单词,从 aa 到 zoom。现在,如果我们执行上一节学习的 one-hot 编码,所有这些单词都可以以向量形式表示。每个单词将有一个唯一的向量。例如,如果单词 king 的位置在 21000,那么向量的形状将如下所示,其中在 21000 位置上有 1,其余位置为 0。

[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0…………………1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

这种方法存在一些明显的问题:

  1. 维度的数量非常高,计算复杂。

  2. 数据在本质上非常稀疏。

  3. 如果要输入 n 个新单词,则词汇量增加 n,因此每个向量的维度增加 n。

  4. 这种方法忽略了单词之间的关系。我们知道,ruler(统治者)、king(国王)、monarch(君主)有时可以互换使用。在 one-hot 编码方法中,任何这种关系都被忽略了。

如果我们希望进行语言翻译或生成聊天机器人,我们需要将这样的知识传递给机器学习解决方案。单词嵌入为这个问题提供了解决方案。它们将高维度的单词特征转换为较低的维度,同时保持上下文关系。单词嵌入允许我们创建更加泛化的模型。我们可以通过示例来理解含义。

如图 7-7 所示的示例中,“man” 到 “woman” 的关系类似于 “king” 到 “queen”,“eat” 到 “eating” 类似于 “study” 到 “studying” 或 “UK” 到 “London” 类似于 “Japan” 到 “Tokyo”。

图 7-7 单词嵌入可以用来表示单词之间的关系。例如,从 men(男人)到 women(女人)之间存在一种关系,类似于 king(国王)到 queen(女王)之间的关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简而言之,使用单词嵌入,我们可以将具有相似含义的单词表示为类似的形式。单词嵌入可以被认为是一类技术,其中我们将每个单词在预定义的向量空间中表示出来。语料库中的每个单词都被映射到一个向量上。根据单词的使用情况来理解分布式表示。因此,可以使用类似的单词具有相似的表示。这使得解决方案能够捕捉单词及其关系的潜在含义。因此,单词的含义起着重要作用。相比于词袋方法,这种表示更加智能,词袋方法中的每个单词都是独立处理的,不考虑它们的使用情况。而且,维度的数量较少,相比于 one-hot 编码,每个单词由 10 或 100 维的向量表示,这比 one-hot 编码方法中使用的超过 1000 维的向量表示要少得多。

我们将在下一节介绍两种最流行的技术 Word2Vec 和 GloVe。这一节提供了对 Word2Vec 和 GloVe 的理解。Word2Vec 和 GloVe 的数学基础超出了本书的范围。我们将理解解决方案的工作机制,然后使用 Word2Vec 和 GloVe 开发 Python 代码。到目前为止,书中还有一些术语我们没有讨论过,所以下一节关于 Word2Vec 和 GloVe 可能会很繁琐。如果你只对解决方案的应用感兴趣,可以跳过下一节。

Word2Vec 和 GloVe

Word2Vec 首次发表于 2013 年。它是由 Google 的 Tomas Mikolov 等人开发的。我们会在章节结束时分享论文的链接。建议你彻底研究这篇论文。

Word2Vec 是一组用于生成词嵌入的模型。输入是一个大型文本语料库。输出是一个向量空间,具有非常多的维度。在这个输出中,语料库中的每个单词被分配了一个唯一且对应的向量。最重要的一点是,在语料库中具有相似或共同上下文的单词,在生成的向量空间中位置相似。

在 Word2Vec 中,研究人员介绍了两种不同的学习模型 - 连续词袋模型和连续跳字模型,我们简要介绍如下:

  1. 连续词袋模型或 CBOW:在 CBOW 中,模型从周围上下文单词的窗口中预测当前单词。因此,CBOW 学习了在词袋方法中,单词的顺序不起作用。同样,在 CBOW 中,单词的顺序是无关紧要的。

  2. 连续跳字模型:它使用当前单词来预测周围窗口的上下文单词。在这样做时,它给邻近单词分配比远离单词更多的权重。

GloVe 或全局词向量是用于生成词向量表示的无监督学习算法。它由斯坦福的 Pennington 等人于 2014 年开发,并在 2014 年推出。它是两种技术的组合 - 矩阵分解技术和 Word2Vec 中使用的基于本地上下文的学习。GloVe 可用于找到像邮政编码和城市、同义词等关系。它为具有相同形态结构的单词生成了一组单一的向量。

这两个模型(Word2Vec 和 GloVe)都从共现信息中学习和理解它们的单词的向量表示。共现意味着单词在大型语料库中一起出现的频率。主要区别在于 Word2Vec 是基于预测的模型,而 GloVe 是基于频率的模型。Word2Vec 预测给定单词的上下文,而 GloVe 通过创建一个共现矩阵来学习单词在给定上下文中出现的频率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

弹出测验 - 回答这些问题以检查您的理解。书的末尾有答案

(1)BOW 比 tf-idf 方法更严格。真或假。

(2)Word2Vec 和 GloVe 之间的区别。

我们现在将在下一节中转到案例研究和 Python 实现。

用 Python 实现的情感分析案例研究

到目前为止,我们已经讨论了许多关于 NLP 和文本数据的概念。在本节中,我们首先将探讨一个业务案例,然后在同一案例上开发 Python 解决方案。我们正在进行情感分析。

产品评论是信息的丰富来源 - 对客户和组织都是如此。每当我们希望购买任何新产品或服务时,我们倾向于查看其他客户的评论。您可能自己也曾评论过产品和服务。这些评论可以在亚马逊、博客、调查等处找到。

让我们考虑一个案例。一个供水公用事业提供商收到了客户的投诉,对供水的评论以及对整体体验的评论。可能的流是 - 产品质量、定价、注册体验、注册流程的简易性、付款流程、供水评论、电力评论等等。我们想要确定评论的一般背景 - 它是积极的、消极的还是中立的。评论有分配的星级数量、实际文本评论、关于产品/服务的优点和缺点、属性等。但与此同时,也存在一些业务问题,如:

  1. 许多时候,观察到产品/服务收到的星级数量非常高,而实际评论却相当负面。

  2. 组织和产品所有者需要知道客户喜欢哪些功能,哪些功能不受客户喜欢。然后团队可以着手改进客户不喜欢的功能。

  3. 还需要评估并密切关注竞争!组织需要知道竞争对手的热门产品的属性。

  4. 产品所有者可以更好地计划他们希望在未来发布的功能。

因此,业务团队将能够回答这两个最重要的问题:

  1. 我们客户对产品和服务的满意度水平是多少?

  2. 客户的主要痛点和不满,驱动客户参与的因素,哪些服务是复杂且耗时的,哪些服务/产品最受欢迎?

这个商业用例将带来以下业务利益:

  1. 最令人满意且最受欢迎的产品和服务应该继续。

  2. 那些不受欢迎且得到负面评分的功能必须得到改进,挑战也必须得到缓解。

  3. 各自的团队,如财务、运营、投诉、CRM 等,可以被通知,并且他们可以分别工作以改善客户体验。

  4. 喜欢或不喜欢服务的精确原因将对相应的团队有助于朝正确的方向努力。

  5. 总的来说,它将为测量客户基础的净推荐得分(NPS)提供一个基准。企业可以努力提升整体客户体验。

  6. 我们可能希望通过仪表板来表示这些发现。这个仪表板将定期刷新,比如每月或每季度刷新一次。

要解决这个业务问题,团队可以从网站、调查、亚马逊、博客等收集相关数据。然后对该数据集进行分析。分析结构化数据相对容易。在这个例子中,我们将处理文本数据。

Python Jupyter 笔记本在 GitHub 地址上进行了检入。建议您使用 GitHub 地址上的 Jupyter 笔记本,因为它包含更多步骤。

第 1 步:我们在这里导入所有库。

#### Loading all the required libraries here
from lxml import html  
import requests
import pandas as pd
from nltk.corpus import stopwords
from textblob import TextBlob
import matplotlib.pyplot as plt
import sys
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import sklearn
import scikitplot as skplt
import nltk
#to ignore warnings
import warnings
warnings.filterwarnings("ignore")
nltk.download('stopwords')
nltk.download('punkt')
nltk.download('wordnet')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

第 2 步:我们在这里定义标签。这些标签用于从评论中获取产品的属性。

xpath_reviews = '//div[@data-hook="review"]'
reviews = parser.xpath(xpath_reviews)
xpath_rating  = './/i[@data-hook="review-star-rating"]//text()' 
xpath_title   = './/a[@data-hook="review-title"]//text()'
xpath_author  = './/a[@data-hook="review-author"]//text()'
xpath_date    = './/span[@data-hook="review-date"]//text()'
xpath_body    = './/span[@data-hook="review-body"]//text()'
xpath_helpful = './/span[@data-hook="helpful-vote-statement"]//text()'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

第 3 步:我们现在正在准备好提取数据。我们正在创建一个数据框来存储客户评论。然后我们迭代所有评论,然后提取信息。

# Create a dataframe here. 

reviews_df = pd.DataFrame()
for review in reviews:
    rating  = review.xpath(xpath_rating)
    title   = review.xpath(xpath_title)
    author  = review.xpath(xpath_author)
    date    = review.xpath(xpath_date)
    body    = review.xpath(xpath_body)
    helpful = review.xpath(xpath_helpful)

    review_dict = {'rating': rating,
                   'title': title,
                   'author': author,             
                   'date': date,
                   'body': body,
                   'helpful': helpful}
    reviews_df = reviews_df.append(review_dict, ignore_index=True)
all_reviews = pd.DataFrame()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

第 4 步:让我们迭代通过评论然后填写详细信息。

# Fill the values of the reviews here. . 

for i in range(1,90):
    amazon_url = 'https://www.amazon.co.uk/Hive-Heating-Thermostat-Professional-Installation/product-reviews/B011B3J6KY/ref=cm_cr_othr_d_show_all?ie=UTF8&reviewerType=all_reviews&pageNumber='+str(i)
    headers = {'User-Agent': user_agent}
    page = requests.get(amazon_url, headers = headers)
    parser = html.fromstring(page.content)
    xpath_reviews = '//div[@data-hook="review"]'
    reviews = parser.xpath(xpath_reviews)
    reviews_df = pd.DataFrame()
    xpath_rating  = './/i[@data-hook="review-star-rating"]//text()' 
    xpath_title   = './/a[@data-hook="review-title"]//text()'
    xpath_author  = './/a[@data-hook="review-author"]//text()'
    xpath_date    = './/span[@data-hook="review-date"]//text()'
    xpath_body    = './/span[@data-hook="review-body"]//text()'
    xpath_helpful = './/span[@data-hook="helpful-vote-statement"]//text()'
    #print(i)
    for review in reviews:
        rating  = review.xpath(xpath_rating)
        title   = review.xpath(xpath_title)
        author  = review.xpath(xpath_author)
        date    = review.xpath(xpath_date)
        body    = review.xpath(xpath_body)
        helpful = review.xpath(xpath_helpful)

        review_dict = {'rating': rating,
                       'title': title,
                       'author': author,             
                       'date': date,
                       'body': body,
                       'helpful': helpful}
        reviews_df = reviews_df.append(review_dict, ignore_index=True)
    #print(reviews_df)
    all_reviews = all_reviews.append(reviews_df)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

第 5 步:让我们看看我们生成的输出。

all_reviews.head()
  • 1

第 6 步:现在我们将输出保存到一个路径。您可以提供自己的路径。

out_folder = '/Users/vaibhavverdhan/Book/UnsupervisedLearningBookFinal/'
all_reviews.to_csv(out_folder + 'Reviews.csv')
  • 1
  • 2

第 7 步:加载数据并分析。

#Load the data now and analyse it
data_path = '/Users/vaibhavverdhan/Book/UnsupervisedLearningBookFinal/'
reviewDataCSV = 'Reviews.csv'
reviewData = (pd.read_csv(data_path+reviewDataCSV,index_col=0,))
  • 1
  • 2
  • 3
  • 4

第 8 步:我们现在将查看数据集的基本信息。

reviewData.shape
reviewData.rating.unique()
reviewData.rating.value_counts()
  • 1
  • 2
  • 3

第 9 步:我们现在将查看评论中给出的星级分布。这将帮助我们理解客户给出的评论。

labels = '5 Stars', '1 Star', '4 Stars', '3 Stars', '2 Stars'
sizes = [reviewData.rating.value_counts()[0], reviewData.rating.value_counts()[1],reviewData.rating.value_counts()[2],reviewData.rating.value_counts()[3],reviewData.rating.value_counts()[4]]
colors = ['green', 'yellowgreen', 'coral', 'lightblue', 'grey']
explode = (0, 0, 0, 0, 0)  # explode 1st slice

# Plot
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
        autopct='%1.1f%%', shadow=True, startangle=140)

plt.axis('equal')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

第 10 步:将文本转换为小写,并删除停用词和频率最高的单词。

reviewData.body = reviewData.body.str.lower()
reviewData.body = reviewData.body.str.replace('[^\w\s]','')
stop = stopwords.words('english')
reviewData.body = reviewData.body.apply(lambda x: " ".join(x for x in x.split() if x not in stop))
freq = list(freq.index)
reviewData.body = reviewData.body.apply(lambda x: " ".join(x for x in x.split() if x not in freq))
freq = pd.Series(' '.join(reviewData.body).split()).value_counts()[-10:]
freq = list(freq.index)
reviewData.body = reviewData.body.apply(lambda x: " ".join(x for x in x.split() if x not in freq))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

第 11 步:现在对数据进行分词。

from nltk.tokenize import word_tokenize
tokens = word_tokenize(reviewData.iloc[1,1])
print(tokens)
  • 1
  • 2
  • 3

第 12 步:我们现在正在执行词形还原。

from textblob import Word
reviewData.body = reviewData.body.apply(lambda x: " ".join([Word(word).lemmatize() for word in x.split()]))
reviewData.body.head()
  • 1
  • 2
  • 3

第 13 步:现在我们正在将所有评论附加到字符串上。

sentimentString = reviewData.iloc[1,1]
# append to this string 
for i in range(2,len(reviewData)):
    sentimentString = sentimentString + reviewData.iloc[i,1]
  • 1
  • 2
  • 3
  • 4

第 14 步:情感分析在这里完成。我们从 TextBlob 中获取情感方法。它为情感生成极性和主观性。

# the functions generates polarity and subjectivity here, subsetting the polarity only here
allReviewsSentiment = reviewData.body[:900].apply(lambda x: TextBlob(x).sentiment[0])
# this contains boths subjectivity and polarity
allReviewsSentimentComplete = reviewData.body[:900].apply(lambda x: TextBlob(x).sentiment)
allReviewsSentimentComplete.head()
  • 1
  • 2
  • 3
  • 4
  • 5

第 15 步:将情感保存到 csv 文件中。

allReviewsSentiment.to_csv(out_folder + 'ReviewsSentiment.csv')
  • 1

第 15 步:我们现在将给情感分配一个含义或标签。我们正在将每个分数分类为非常满意到非常不满意。

allReviewsSentimentDF = allReviewsSentiment.to_frame()
# Create a list to store the data
grades = []

# For each row in the column,
for row in allReviewsSentimentDF['body']:
    # if more than a value,
    if row >= 0.75:
       grades.append('Extremely Satisfied')
    elif (row >= 0.5) & (row < 0.75):
        grades.append('Satisfied')
    elif (row >= 0.2) & (row < 0.5):
        grades.append('Nice')
    elif (row >= -0.2) & (row < 0.2):
        grades.append('Neutral')
    elif (row > -0.5) & (row <= -0.2):
        grades.append('Bad')
    elif (row >= -0.75) & (row < -0.5):
        grades.append('Dis-satisfied')
    elif  row < -0.75:
        grades.append('Extremely Dis-satisfied')
    else:
        # Append a failing grade
        grades.append('No Sentiment')

# Create a column from the list
allReviewsSentimentDF['SentimentScore'] = grades
allReviewsSentimentDF.head()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

第 16 步:我们现在将查看情感得分并绘制它们。最后,我们将它们与主数据集合并。

allReviewsSentimentDF.SentimentScore.value_counts()
allReviewsSentimentDF['SentimentScore'].value_counts().plot(kind='bar')
#### Merge the review data with Sentiment generated

# add column Polarity Score
reviewData['polarityScore'] = allReviewsSentimentDF['body']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这个案例研究中,您不仅从网站上抓取了评论,还分析了数据集。如果我们比较情感,我们可以看到给产品的星级并不代表真实情况。

在 () 中,我们正在比较实际的星级和情感分析的输出。我们可以观察到,73% 的人给出了 5 星,7% 的人给出了 4 星,而在情感分析中,大多数评论被分类为中性。这就是情感分析的真正力量!

图 7-8 比较左侧的原始星级分布,观察情感分析的实际结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

情感分析是一个非常重要的用例。它对企业和产品团队非常有用。

我们现在将转到使用 Python 进行文档分类的第二个案例研究。

使用 Python 进行文本聚类

想象一下。你有一堆的文本数据集或文档。但是它们都混在一起了。我们不知道文本属于哪个类别。在这种情况下,我们假设我们手头有两类文本数据集 - 一个与足球有关的数据,第二类是旅行。我们将开发一个可以分离这两个类别的模型。

第一步:导入所有库

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import numpy as np
import pandas as pd
  • 1
  • 2
  • 3
  • 4

第二步:我们现在正在创建一个虚拟数据集。这段文本数据是我们自己写的几句话。有两个类别 -

text = ["It is a good place to travel",
            "Football is a nice game", "Lets go for holidays and travel to Egypt",
            "It is a goal, a great game.", "Enjoy your journey and fortget the rest", "The teams are ready for the same" ]
  • 1
  • 2
  • 3

第三步:我们将使用 tfidf 对数据进行向量化处理。

tfidf_vectorizer = TfidfVectorizer(stop_words='english')
X = tfidf_vectorizer.fit_transform(text)
  • 1
  • 2

第四步:现在让我们进行聚类。

k = 2
model = KMeans(n_clusters=k, init='k-means++', max_iter=10, n_init=2)
model.fit(X)
  • 1
  • 2
  • 3

第五步:让我们表示质心并打印输出。

centroids = model.cluster_centers_.argsort()[:, ::-1]
features = vectorizer.get_feature_names()

for i in range(k):
    print("Cluster %d:" % i),
    for ind in centroids[i, :10]:
        print("%s" % terms[ind])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您还可以将此示例扩展到其他数据集。使用自己的数据集并复制上面示例中的代码。

不再有使用 Word2Vec 和 GloVe 的 Python Jupyter 笔记本了。我们已经将代码检入到了本书的 GitHub 位置。建议您使用它。这是一个非常重要的表示文本数据的资源。

至此,我们来到了这个令人兴奋的章节的结尾。现在让我们进入总结部分。

7.6 小结

文本数据是最有用的数据集之一。很多智慧隐藏在文本中。日志、博客、评论、推文、投诉、评论、文章等等 - 文本数据的来源很多。机构已经开始投资建立访问文本数据和存储文本数据的基础设施。分析文本数据需要更好的处理能力和更好的计算机。它需要特殊的技能和更深入的理解概念。NLP 是一个不断发展的领域,许多研究正在进行中。与此同时,我们不能忽视商业敏锐度和知识的重要性。

数据分析和机器学习并不容易。我们必须理解很多关于数据清洗、数据探索、数据表示和建模的概念。但是,分析非结构化数据可能比结构化数据集更加复杂。在上一章中,我们处理了图像数据集。在当前章节中,我们处理了文本数据。

文本数据是最难分析的数据之一。文本数据有很多排列组合。清洗文本数据并不容易,是一项相当复杂的任务。在本章中,我们讨论了几种清洗文本数据的重要技术。我们还介绍了几种将文本数据表示为向量形式的重要方法。建议您对这些方法进行实践,并通过应用每种技术进行比较性能。

随着这一章的结束,我们也结束了书的第二部分。在书的下一部分,复杂性会增加。我们将研究更深层次的无监督学习算法概念。

你现在可以转到练习问题。

实用的下一步和建议阅读

  1. 从下面的链接获取数据集。在这里你会找到很多文本数据集。建议你实现聚类和降维解决方案。

    blog.cambridgespark.com/50-free-machine-learning-datasets-natural-language-processing-d88fb9c5c8da

  2. 这是文本数据集的第二个来源,你会找到许多有用的数据集。

    www.kaggle.com/datasets?search=text

  3. 你被建议阅读研究论文《在向量空间中高效估计词表示》(Efficient Estimation of Word Representations in Vector Space),作者是 Tomas Mikolov、Kai Chen、Greg Corrado、Jeffrey Dean。

    arxiv.org/pdf/1301.3781.pdf

  4. 你被建议阅读研究论文《GloVe:用于词表示的全局向量》(GloVe: Global Vectors for Word Representation),作者是 Jeffrey Pennington、Richard Socher、Christopher D. Manning。

    nlp.stanford.edu/pubs/glove.pdf

  5. 有几篇论文被广泛引用。

  6. Avrim Blum 和 Tom Mitchell:使用共训练结合标记和未标记数据,1998 年

  7. Kevin Knight:贝叶斯推断与眼泪,2009 年。

  8. Thomas Hofmann:概率隐语义索引,SIGIR 1999。

  9. Donald Hindle 和 Mats Rooth。结构歧义和词汇关系,计算语言学,1993 年。

  10. Collins 和 Singer:命名实体分类的无监督模型,EMNLP 1999。

  11. 你被建议阅读研究论文《使用 TF-IDF 确定文档查询中单词相关性》(Using TF-IDF to Determine Word Relevance in Document Queries),作者是 Juan Ramos。

    citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.121.1424&rep=rep1&type=pdf

  12. 你被建议阅读研究论文《使用 TF-IDF 和下一个词否定改进的文本情感分类模型》(An Improved Text Sentiment Classification Model Using TF-IDF and Next Word Negation),作者是 Bijoyan Das 和 Sarit Chakraborty。

    arxiv.org/pdf/1806.06407.pdf

第八章:深度学习:基本概念

本章介绍

  • 深度学习

  • 深度学习的构建模块

  • 神经网络中的层

  • 激活函数

  • 使用深度学习的监督学习

  • 无监督学习使用深度学习

  • 使用 tensorflow 和 keras 的 Python 代码

  • 深度学习库

“生活真的很简单,但我们一直坚持要把它弄复杂 - 孔子”

欢迎来到本书的第三部分。到目前为止,你已经学习了很多概念、案例研究和 Python 代码。从本章开始,复杂性水平将更高。

在本书的前两部分,我们涵盖了各种无监督学习算法,如聚类,降维等等。我们讨论了简单和高级算法。我们还在本书的最后一部分讨论了处理文本数据的方法。从本书的第三部分开始,我们将开始深度学习的旅程。

深度学习和神经网络改变了世界和商业领域。你一定听说过深度学习和神经网络。它们的实施和复杂性导致更好的癌症检测,自动驾驶汽车,改进的灾害管理系统,更好的污染控制系统,减少交易欺诈等等。

在本书的第三部分,我们将探讨使用深度学习的无监督学习。我们将学习什么是深度学习和神经网络的基础知识。我们将研究神经网络中的层,激活函数,深度学习的过程和各种库。然后我们将转向自动编码器、生成对抗网络和深度信念网络。这些话题确实很复杂,有时候相当数学密集。我们将使用不同类型的数据集来解决问题,但主要是非结构化的数据集。和往常一样,Python 将用于生成解决方案。我们还分享了许多外部资源来补充这些概念。请注意,这些都是非常先进的主题,对于这些主题仍在进行大量的研究。

我们将第三部分分为三章。第八章介绍了所需的深度学习和神经网络的基础概念。接下来的两章将专注于自动编码器,GAN 和深度信念网络。本书的最后一章讨论了这些模型的部署。

本章讨论了神经网络和深度学习的概念。我们将讨论什么是神经网络,什么是激活函数,什么是不同的优化函数,神经网络训练过程等。在你理解自动编码器和生成对抗网络的更深层次概念之前,了解这些深度学习概念对你来说至关重要。本章涵盖的概念是神经网络和深度学习的基础,也是下两章进一步学习的基础。因此,你清楚这些概念非常重要。在本章末尾还有更详细的外部资源可供获取这些概念。

欢迎来到第八章,祝一切顺利!

8.1 技术工具包

我们将继续使用迄今为止使用的相同版本的 Python 和 Jupyter 笔记本。本章中使用的代码和数据集已经保存到了此位置。

您需要在本章中安装一些 Python 库,它们是 - tensorflow 和 keras。

让我们开始学习第八章吧!

8.2 深度学习:是什么?它是做什么的?

近几年来,深度学习已经积累了很多动力。神经网络正在推动机器学习解决方案的边界。深度学习只是机器学习。深度学习是基于神经网络的。它利用了相似的概念,即利用历史数据,理解属性和收集的智能可以用于找到模式或预测未来,尽管深度学习比我们迄今为止涵盖的算法更复杂。

回想一下第一章,我们在那里介绍了结构化和非结构化数据集的概念。非结构化数据集包括文本、图像、音频、视频等。在图 8-1 中,我们描述了文本、图像、音频、视频数据集的主要来源。

图 8-1 非结构化数据集如文本、音频、图像、视频可以使用深度学习进行分析。这样的数据集有多个来源。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

虽然深度学习也可以用于结构化数据集,但它在非结构化数据集上的表现却是非常出色的。其主要原因之一是,经典的机器学习算法在像图像、文本、音频和视频这样的非结构化数据集上有时并不那么有效。我们列举了深度学习在各个领域取得的一些突破性解决方案。

  1. 医学和制药: 深度学习在骨骼和关节问题的识别,或者在确定动脉或静脉中是否有血栓等领域发挥作用。在制药领域,它可以加快临床试验的进程,并帮助更快地找到目标药物。

  2. 银行和金融业: 基于深度学习的算法可用于检测交易中潜在的欺诈行为。利用基于图像识别的算法,我们还可以区分支票上的伪造签名。

  3. 汽车行业: 你一定听说过自动驾驶,即自动驾驶汽车。使用深度学习,算法能够检测道路上的交通信号、行人、其他车辆、它们之间的距离等。

  4. 使用深度学习技术可以实现自动语音识别。通过复杂的神经网络,人类能够创建语音识别算法。这些解决方案被应用于 Siri、Alexa、Translator、百度等产品中。

  5. 零售业: 在零售行业中,使用基于深度学习的算法,人类能够改善客户定位,并开发先进和定制的营销策略。使用深度学习改进了提供下一优产品推荐的模型。我们能够获得更好的投资回报率(ROI),并改善交叉销售和上销售策略。

  6. 图像识别: 神经网络正在改进我们的图像识别技术:可以使用卷积神经网络来实现,这种技术正在改进计算机视觉。使用案例有很多,比如:

  7. 深度学习对于区分癌细胞和良性细胞非常有效。可以通过使用癌细胞和良性细胞的图像来实现。

  8. 使用神经网络已经开发了自动车牌识别系统。

  9. 使用深度学习可以开发目标检测方法。

  10. 使用深度学习可以开发运动感知和跟踪系统。

  11. 在灾难管理系统中,深度学习可以检测受影响区域的人员存在。想象一下,使用更好的检测技术可以拯救多么宝贵的时间,最终拯救人的生命。

所列举的使用案例并不详尽。通过深度学习,我们能够改进用于测量客户情感、语言翻译、文本分类、命名实体识别等的自然语言处理(NLP)解决方案。在生物信息学、军事、移动广告、电信、科技、供应链等领域的使用案例中,深度学习正在为未来铺平道路。

我们已经介绍了深度学习的强大之处。现在我们将开始讲述神经网络的构建模块。

8.3 神经网络的构建模块

人工神经网络(ANNs)据说受到了人脑工作方式的启发。人脑是我们目前能够接触到的最好的机器。当我们看到一张图片、一张脸或听到一首曲子时,我们会为其贴上一个标签或名称。这使我们能够训练我们的大脑和感官,以便在再次看到/听到时识别出一张图片、一张脸或一首曲子。

人工神经网络通过学习或接受训练来执行类似的任务。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 小测验 - 回答这些问题来检查你的理解。本书末尾附有答案。

  1. 深度学习的含义是什么?

  2. 神经网络不能用于无监督学习。真或假?

  3. 探索深度学习在非传统业务领域的更多应用案例。

接下来,我们将在下一节中探讨神经网络如何帮助解决商业问题。

8.3.1 解决方案的神经网络

在深度学习中,监督和非监督学习的概念也适用。我们将介绍网络的两种训练类型:有监督和无监督。这为您提供了完整的图片。同时,为了充分欣赏无监督的深度学习,建议首先了解有监督深度学习的过程。

举个例子,让我们了解深度学习的过程。例如,我们希望创建一个可以识别人脸的解决方案,也就是说,一个可以区分面部并通过给面部分配一个名称来识别人物的解决方案。为了训练模型,我们将准备一个包含人脸图像和相应名称的数据集。在训练过程中,人工神经网络(ANN)不具有先前对图像数据集或属性的了解。在训练过程中,ANN 会从训练数据中学习属性和识别特征,并利用这些学习到的属性来区分面部。此时,我们只涵盖了高层次的过程,后续章节将更详细地介绍这个过程。

您可以在图 8-2 中看到神经网络的表示形式。

图 8-2 是一个典型的神经网络,有神经元和各种层。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

神经网络中的过程相当复杂。我们将首先介绍神经网络中所有构建块的内容,例如神经元、激活函数、权重、偏置项等,并然后讨论神经网络中的过程。我们将从主角-神经元开始。

8.3.2 人工神经元和感知器

人类大脑包含数十亿个神经元。神经元是我们大脑中相互连接的细胞。这些神经元接收信号,处理它们并产生结果。人工神经元基于生物神经元,并可以被认为是生物神经元的简化计算模型。

1943 年,研究人员 Warren McCullock 和 Walter Pitts 提出了一个简化的脑细胞概念,称为 McCullock-Pitts(MCP)神经元。它可以被认为是一个具有二进制输出的简单逻辑门。

人工神经元的工作方法类似于生物神经元,尽管它们比生物神经元简单得多。感知器是生物神经元的数学模型。在实际的生物神经元中,树突从其他神经元的轴突中接收电信号。在感知器中,这些电信号被表示为数字值。

人工神经元接收来自前一神经元的输入,或者可以接收输入数据。然后处理输入信息并输出结果。输入可以是原始数据或来自前一神经元的处理信息。神经元将输入与其自身的内部状态结合起来,分别加权并通过非线性函数传递接收到的输出以生成输出。这些非线性函数也被称为激活函数(我们稍后会讨论它们)。您可以将激活函数视为数学函数。可以将神经元表示如图 8-3 所示。

图 8-3 神经元获得输入,使用数学函数处理输入,然后生成输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简单来说,神经元可以称为一个计算其输入数据集的加权平均值的数学函数,然后将这个总和通过激活函数进行处理。然后神经元的输出可以成为下一个神经元的输入,该神经元再次处理接收到的输入。让我们再深入一点。

在感知器中,每个输入值都乘以一个称为权重的因子。生物神经元在总强度的输入信号超过一定阈值时激活。在感知器中也遵循类似的格式。在感知器中,计算输入数据的加权总和,然后对每个输出应用激活函数。然后每个输出可以馈送到感知器的下一层。

让我们假设感知器 X 有两个输入值“a”和“b”,为了简单起见,它只有一个输出。让 a 和 b 分别的权重为 P 和 Q。所以,加权总和可以表示为:Px + Qb。只有当加权总和超过一定阈值时,感知器才会激活或产生非零输出。让我们称阈值为“C”。因此,我们可以说:

如果 Px + Qy <= C,则 X 的输出将为 0

如果 Px + Qy > C,则 X 的输出将为 1

如果我们概括这一理解,我们可以表示如下。如果我们将感知器表示为一个函数,该函数将输入"x"映射为如下函数

f(x) = 1 如果 w*x + b > 0

否则为 0

其中:

x 是输入值的向量

w 表示权重向量

b 是偏置项

我们将在此处解释偏差和权重项。

回想一下线性方程:y = mx+ c 其中 m 是直线的斜率,c 是常数项。 偏置和权重都可以使用相同的线性方程定义。

权重:权重的作用类似于线性方程中直线的斜率。它定义了 f(x)的值在 x 的值单位变化时的变化。

偏置:偏置的作用类似于线性函数中常数的作用。如果没有偏差,激活函数的输入就是 x 乘以权重。

权重和偏置项是网络中进行训练的参数。

函数的输出将取决于所使用的激活函数。在我们讨论完网络中不同层之后,我们将在下一节介绍各种类型的激活函数。

8.3.3 网络中的不同层

一个简单而有效的组织神经元的方式如下。与其允许任意神经元连接到任意其他神经元,不如将神经元组织成层次结构。一层中的神经元的所有输入仅来自上一层,并且所有输出仅传递到下一层。没有其他连接,例如同一层中的神经元之间的连接,或者属于远程层的神经元之间的连接(对于一个相当特殊的情况有一个小小的例外,但超出了本书的范围)。

我们知道信息通过神经网络流动。这些信息在网络中的一层又一层地被处理和传递。如图 8-4 所示,神经网络有三层。典型的神经网络如下图所示:

图 8-4 一个具有神经元和输入、隐藏和输出层的典型神经网络

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 8-4 所示的神经网络有 3 个输入单元,2 个每个有 4 个神经元的隐藏层和一个最终的输出层。

输入层:顾名思义,它接收输入数据并与隐藏层共享。

隐藏层:它是网络的核心和灵魂。隐藏层的数量取决于手头的问题,层数可以从几层到数百层不等。在这些层中进行所有的处理、特征提取和属性学习。在隐藏层中,所有的输入原始数据都被分解成属性和特征。这种学习对以后的决策有用。

输出层:决策层和网络中的最后一块拼图。它接受来自前面隐藏层的输出,然后做出预测。

例如,输入的训练数据可能是原始图像或处理过的图像。这些图像将被馈送到输入层。数据现在传输到隐藏层,其中所有的计算都是由每一层的神经元完成的。输出是需要完成的任务,例如识别一个对象或者如果我们想要对图像进行分类等。

ANN 由各种连接组成。每个连接的目标是接收输入并将输出提供给下一个神经元。这个输出将作为下一个神经元的输入。另外,正如之前讨论的,每个连接都被赋予一个权重,这代表了其相应的重要性。值得注意的是,一个神经元可以有多个输入和输出连接,这意味着它可以接收多个输入并提供多个输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 小测验 - 回答这些问题来检查你的理解。答案在书的末尾。

  1. 输入数据被馈送到神经网络的隐藏层中。是或否?

  2. 偏置项类似于线性方程的斜率。对或错。

  3. 查找并探索有史以来训练最深的神经网络。

那么,一个层的作用是什么呢? 一个层接收输入,处理它们,并将输出传递给下一个层。 从技术上讲,层实现的转换必须由它的权重参数化,这也被称为层的参数。 为了简化,为了使神经网络能够“训练”到一个特定的任务,必须更改网络中的某些内容。 结果证明,改变网络的架构(即神经元如何彼此连接)只有很小的影响。 另一方面,正如我们将在本章后面看到的,改变权重是“学习”过程的关键。

我们现在将转移到非常重要的激活函数主题。

8.3.4 激活函数

回想一下,在最后几节中,我们介绍了激活函数。 激活函数的主要作用是决定神经元/感知器是否应该发射。 它们在后期的网络训练中起着核心作用。 有时它们被称为传输函数。 还重要的是要知道为什么我们需要非线性激活函数。 如果我们仅使用线性激活函数,输出也将是线性的。 同时,线性函数的导数将是常数。 因此,学习的可能性将不大。 因此,出于这样的原因,我们更喜欢具有非线性激活函数。

我们现在将研究最常见的激活函数。

Sigmoid 函数

Sigmoid 是一个有界的单调数学函数。 Sigmoid 是一个数学函数,当输入值增加时,其输出值总是增加的。 其输出值始终在 -1 和 1 之间。

它是一个可微函数,具有 S 形曲线,其一阶导函数呈钟形。 它具有非负的导函数,并且对所有实数输入值定义。 如果神经元的输出值在 0 和 1 之间,则使用 Sigmoid 函数。

从数学上讲,sigmoid 函数是:

(方程式 8.1)

S(x) = 1 = e^x

1 + e^(-x) e^x +1

sigmoid 函数的图形可以在图 8-5 中显示。

图 8-5 显示了一个 sigmoid 函数。请注意函数的形状和最小/最大值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sigmoid 函数在复杂学习系统中找到其应用。 通常用于二进制分类和网络的最终输出层。

Tanh 函数

在数学中,双曲正切函数或 tanh 是一个可微的双曲函数。它是一个平滑函数,其输入值在 -1 到 +1 的范围内。

Tanh 函数被写成方程式 8.2。

(方程式 8.2)

Tanh(x) = ex – e-x

ex + e-x

双曲线的图形表示如图 8-6 所示。它是 Sigmoid 函数的缩放版本,因此可以从 Sigmoid 函数导出 tanh 函数,反之亦然。

图 8-6 这里显示了一个 tanh 函数,它是 sigmoid 函数的缩放版本

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

tanh 函数通常用于隐藏层。它使均值接近于零,从而使网络中的下一层训练更容易。这也被称为数据居中

Rectified Linear Unit 或 ReLU

Rectified Linear Unit 或 ReLU 是一个定义参数的正部分的激活函数。我们在下面展示了 ReLU 函数。注意,即使对于负值,值也为 0,并且从 0 开始倾斜。

(方程 8.3)

F(x) = max (0, x)

即,如果是正数,则输出为 x,否则为 0

图 8-7 显示了 ReLU 函数

图 8-7 这里显示了 ReLU 函数,它是神经网络隐藏层中受欢迎的激活函数之一。ReLU 易于使用且训练成本较低。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

它是一个简单的函数,因此计算成本较低,速度更快。它是无界的,并且不以零为中心。除零点外,它在所有位置上都可微。由于 ReLU 函数较不复杂,计算成本较低,因此在隐藏层中被广泛用于更快地训练网络。

Softmax 函数

Softmax 函数用于神经网络的最后一层,以从网络中生成输出。它是激活函数,输出可以是图像的最终分类,用于不同的类别。它是一个对于多类分类问题有用的激活函数,并强制神经网络输出总和为 1。

例如,如果图像的不同类别是汽车、摩托车或卡车,则 Softmax 函数将为每个类别生成三个概率。获得最高概率的类别将是预测的类别。

还有其他激活函数,如 ELU、PeLU 等,超出了本书的范围。我们在本章末尾提供了各种激活函数的摘要。

我们将在下一节中介绍超参数。它们是我们在训练网络时拥有的控制杆。

8.3.5 超参数

在训练网络时,算法不断学习原始输入数据的属性。同时,网络无法自行学习所有内容,有些参数需要提供初始设置。这些变量决定了神经网络的结构以及训练网络时有用的相应变量。

我们在开始网络训练之前提供超参数。超参数的一些例子包括网络中隐藏层数的数量、每个层中神经元的数量、层中使用的激活函数、权重初始化等。我们必须选择超参数的最佳值。为此,我们选择一些合理的超参数值,训练网络,然后测量网络的性能,然后调整超参数,然后重新训练网络,重新评估和重新调整,这个过程继续进行。

超参数是由我们控制的,因为我们输入超参数来提高性能。

梯度下降和随机梯度下降

在任何基于预测的解决方案中,我们希望尽可能好地预测,换句话说,我们希望尽可能减少错误。误差是实际值和预测值之间的差异。机器学习解决方案的目的是找到我们函数的最优值。我们想减少错误或最大化准确性。梯度下降可以帮助实现这一目的。

梯度下降技术是一种优化技术,用于找到函数的全局最小值。我们迭代地沿着最陡的下降方向前进,这个方向是由负梯度定义的。

但梯度下降在运行非常大的数据集或具有非常高维数的数据集时可能运行速度较慢。这是由于梯度下降算法的一次迭代会针对训练数据集中的每个实例进行预测。因此,很显然,如果我们有成千上万条记录,它将花费很长时间。对于这种情况,我们有随机梯度下降。

在随机梯度下降中,系数不是在数据批次结束时更新,而是对每个训练实例进行更新,因此需要较少的时间。

下面的图显示了梯度下降的工作方式。注意我们如何朝向全局最小值进展。

图 8-8 梯度下降的概念。这是最小化损失函数的机制

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

学习和学习率

对于网络,我们采取各种步骤来提高解决方案的性能,学习率就是其中之一。学习率将定义模型减少错误所采取的纠正步骤的大小。学习率定义了我们应该如何调整网络权重的值,以使其相对于损失梯度(这个过程的更多信息将在下一节提供)调整的数量。如果我们采用较高的学习率,准确性会降低。如果我们采用非常低的学习率,训练时间将大大增加。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 小测验-回答这些问题以检验您的理解。答案在本书结尾处。

  1. 比较并对比 Sigmoid 和 tanh 函数。

  2. ReLU 通常用于网络的输出层。是或否?

  3. 梯度下降是一种优化技术。真或假。

我们现在已经了解了深度学习的主要概念。现在让我们研究一下神经网络是如何工作的。我们将了解各个层是如何相互作用的,以及信息是如何从一层传递到另一层的。

8.4 深度学习如何在监督方式下工作?

我们现在已经介绍了神经网络的主要组成部分。现在是所有部分汇聚在一起,组织整个学习的时候了。神经网络的训练是一个非常复杂的过程。整个过程可以按照以下步骤一步步地进行检查。

也许你会想知道神经网络的学习是什么意思。学习是一个过程,为了所有网络层找到最佳和最优化的权重和偏置值,以便我们可以达到最佳准确度。由于深度神经网络在权重和偏置项方面实际上具有无限的可能性,我们必须找到所有参数的最优值。考虑到改变一个值会影响其他值,这似乎是一项艰巨的任务,而实际上它是一个各种网络参数在变化的过程。

回想一下,在第一章中我们介绍了监督学习的基础知识。我们将在这里刷新对此的理解。刷新监督学习的原因是确保您能够充分理解训练神经网络的过程。

8.4.1 监督学习算法

一个快速的定义是 - 监督学习算法具有“指导”或“监督”,以指导向着实现未来预测的业务目标。

正式地说,监督模型是使用输入数据和期望输出来预测未来的统计模型。输出是我们希望预测的值,被称为目标变量,用于进行预测的数据称为训练数据。目标变量有时被称为标签。数据中存在的各种属性或变量称为独立变量。每个历史数据点或训练示例都包含这些独立变量和相应的目标变量。监督学习算法对未来看不见的数据进行预测。解决方案的准确性取决于所进行的训练以及从标记历史数据中学到的模式。

大多数深度学习解决方案都基于监督学习。然而,无监督深度学习正在迅速获得认可,因为未标记的数据集比标记的数据集更加丰富。

例如,如果我们希望创建一个可以识别人脸的解决方案。在这种情况下,我们将有:

训练数据:来自不同角度的人脸图像。

目标变量:人的姓名。

这个训练数据集可以输入到算法中。然后算法将理解各种面部的属性,或者换句话说,学习各种属性。基于所进行的训练,算法可以对面部进行预测。如果概率得分表明面部属于某人 X,那么我们可以安全地说该面部属于某人 X。

监督学习问题用于需求预测、信用卡欺诈检测、客户流失预测、保费估算等。它们在零售、电信、银行和金融、航空、保险等行业被广泛应用。

我们现在为您刷新了监督学习的概念。我们将现在转移到神经网络训练的第一步,即前馈传播。

8.4.2 第 1 步:前馈传播

让我们开始神经网络中的过程。我们尝试在图 8-9 中创建一个说明性的图表。这是我们为了解释该过程而创建的网络的基本骨架。我们假设有一些输入数据点,我们将有输入数据层,该层将消耗输入数据。信息从输入层流向数据转换层(隐藏层)。在隐藏层中,使用激活函数处理数据,并基于权重和偏置项进行处理。然后对数据集进行预测。这称为前馈传播,因为在此过程中,输入变量按顺序从输入层到输出层计算。

让我们拿同样的问题来解释 8.3 节中监督算法中的过程。例如,如果我们希望创建一个能够识别人脸的解决方案。在这种情况下,我们将有

训练数据:来自各个角度的不同人脸图像。

目标变量:人的姓名。

这个训练数据集可以输入到算法中。然后网络将理解各种面孔的属性,或者换句话说,学习面部数据的各种属性。基于所进行的训练,算法可以对面部进行预测。如果概率得分表明面部属于某人 X,那么我们可以安全地说该面部属于某人 X。

图 8-9 神经网络训练过程的基本骨架,我们有输入层和数据转换层。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一旦在隐藏层中完成数据处理,就会生成一个预测,即面部属于某人 X 的概率。

8.4.3 第 2 步:添加损失函数

第 1 步生成输出。现在我们必须评估该网络的准确性。我们希望我们的网络在识别面部时具有尽可能高的准确性。并使用算法生成的预测,我们将控制并提高网络的准确性。

网络中的准确度测量可以通过损失函数来实现,也被称为目标函数。损失函数比较实际值和预测值。损失函数计算差异分数,因此能够测量网络的表现如何以及错误率是多少。

让我们更新我们在第 1 步创建的图表,通过添加一个损失函数和相应的损失分数,来测量网络的准确性,如图 8-10 所示。

图 8-10 添加了一个损失函数来测量准确性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

8.4.4 第 3 步:计算错误

我们在网络的第 1 步生成了预测。在第 2 步,我们将输出与实际值进行比较,以得到预测误差。我们解决方案的目标是最小化这个错误,即最大化准确性。

为了不断降低误差,损失分数(预测-实际)被用作反馈来调整权重的值。这个任务是由反向传播算法完成的。

8.5 反向传播

在上个部分的第 3 步中,我们说我们使用优化器不断更新权重以减小错误。学习速率定义了减小错误的修正步长的大小,反向传播用于调整连接权重。这些权重是根据错误向后更新的。随后,重新计算错误,计算梯度下降,并调整相应的权重。因此,反向传播有时被称为深度学习中的中心算法。

反向传播最初是在 20 世纪 70 年代提出的。然后在 1986 年,大卫·鲁梅尔哈特,杰弗里·辛顿和罗纳德·威廉斯的论文得到了很多赞赏。在现代,反向传播是深度学习解决方案的支柱。

下图显示了反向传播的过程,信息从输出层向隐藏层反向流动。注意,信息的流动是与正向传播相反的,正向传播中信息从左到右流动。反向传播的过程如图 8-11 所示。

图 8-11 反向传播作为一个过程- 信息从最终层向初始层流动

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先,我们将以非常高层次描述过程。记住,在训练过程的开始,在步骤 1 中,权重被分配了一些随机值。使用这些随机值,生成了初始输出。由于这是第一次尝试,收到的输出可能与实际值相差很大,相应的损失分数也很高。但这将要改善。在训练神经网络时,权重(和偏置)会在正确的方向上稍微调整,随后,损失分数减少。我们迭代这个训练循环很多次,最终得到最优的最小化损失函数的权重值。

反向传播允许我们在网络训练过程中迭代地减少误差。

下面的部分将涉及大量数学内容。如果你对过程背后的数学不感兴趣,可以跳过它。

8.5.1 反向传播背后的数学

要训练神经网络,我们计算一个损失函数。损失函数告诉我们预测值与实际值之间的差异有多大。反向传播计算损失函数相对于每个权重的梯度。有了这些信息,每个权重都可以在迭代中逐渐更新,从而逐渐减少损失。

在反向传播中,梯度是从网络的最后一层通过隐藏层到第一层计算的。所有层的梯度使用微积分链式法则组合在一起,以获得任何特定层的梯度。

现在我们将更详细地介绍这个过程。首先让我们表示一些数学符号:

  1. h^(i)) – 隐藏层 i 的输出

  2. g^(i))- 隐藏层 i 的激活函数

  3. w^(i))- 层 i 中的隐藏权重矩阵

  4. b^(i))- 层 i 中的偏置

  5. x- 输入向量

  6. N – 网络中的总层数

  7. W^(i))[jk]- 网络中从第(i-1)层节点 j 到第 i 层节点 k 的权重

  8. ∂A/∂B:它是 A 相对于 B 的偏导数

在网络训练过程中,输入 x 被馈送到网络,并通过各层生成输出ŷ。期望的输出是 y。因此,比较 y 和ŷ的成本函数或损失函数将是 C(y, ŷ)。此外,网络的任何隐藏层的输出都可以表示为:

(方程式 8.4)

h^((i)) = g^((i)) (W^((i)T) x + b^((i)))

这里,i(索引)可以是网络中的任意层

最终层的输出是:

(方程 8.5)

y(x) = W^((N)T) h^((N-1)) + b^((N))

在网络训练过程中,我们调整网络的权重以减少 C。因此,我们计算 C 相对于网络中每个权重的导数。以下是网络中每个权重的 C 导数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们知道神经网络有很多层。反向传播算法从网络的最后一层开始计算导数,即第 N^(th)层。然后这些导数向后传播。因此,N 层的导数将被馈送到网络的(N-1)层,依此类推。

使用微积分链式法则分别计算 C 的导数的每个分量。

根据链式法则,对于一个依赖于 b 的函数 c,其中 b 依赖于 a,c 相对于 a 的导数可以写成

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,在反向传播中,第 N 层的导数被用于第 (N-1) 层,以便保存它们然后在第 (N-2) 层再次使用。我们从网络的最后一层开始,遍历所有层直到第一层,并且每次,我们使用最后一次计算的导数来得到当前层的导数。因此,与普通方法相比,反向传播变得极其高效,因为我们不需要分别计算网络中的每个权重。

一旦我们计算出梯度,我们将更新网络中的所有权重。目标是最小化成本函数。我们已经在上一节中学习了类似梯度下降的方法。

我们现在将继续进行神经网络训练过程的下一步。

步骤 4:优化

在上一节中我们学习了反向传播。它让我们能够优化我们的网络并实现最佳准确度。因此,我们也更新了图中的图 8-12。请注意优化器提供了定期和连续的反馈以达到最佳解决方案。

图 8-12 优化是最小化损失函数的过程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一旦我们为我们的网络获得了权重和偏差的最佳值,我们称之为我们的网络已经训练完成。我们现在可以用它对未经训练的数据集进行预测。

现在你已经了解了深度学习的各个组件以及它们在监督方式下如何协同工作。我们现在将简要描述无监督深度学习。

8.6 无监督深度学习的工作原理

我们知道无监督学习解决方案用于未标记的数据集。对于无监督设置中的深度学习,训练数据集是未标记的。

与有标签的监督数据集相比,无监督方法必须自我组织以获取密度、概率分布、偏好和分组。我们可以使用监督和无监督方法来解决类似问题。例如,监督深度学习方法可用于识别狗和猫,而无监督深度学习方法可能用于将狗和猫的图片聚类到不同的组中。在机器学习中也观察到,许多最初构想为监督学习的解决方案,随着时间的推移采用了无监督学习方法来丰富数据,从而改进了监督学习解决方案。

在无监督深度学习的学习阶段,预期网络将模拟数据,然后根据错误进行自我改进。在监督学习算法中,还有其他方法起到与反向传播算法相同的作用。它们是:

  1. 波兹曼学习规则

  2. 对比散度

  3. 最大似然

  4. 霍普菲尔德学习规则

  5. Gibbs 采样

  6. 深度信念网络等等

在本书中,我们将讨论自动编码器和深度信念网络。我们还将探索 GAN(生成对抗网络)。现在是时候让你检查所有用于深度学习的工具和库了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 - 答题测验 - 回答这些问题以检查你的理解。答案在书的末尾。

  1. 以简单形式写出反向传播技术的主要步骤。

  2. 反向传播在无监督学习中更受欢迎。正确还是错误?

  3. 深度学习的目标是最大化损失函数。正确还是错误?

8.7 流行的深度学习库

在过去的几章中,我们使用了许多库和包来实现解决方案。在行业中有很多用于深度学习的库。这些包加快了解决方案的构建,并减少了工作量,因为大部分繁重的工作都是由这些库完成的。

我们在这里讨论最流行的深度学习库:

TensorFlow:Google 开发的 TensorFlow(TF)可以说是最流行和广泛使用的深度学习框架之一。它于 2015 年推出,自那以后被全球许多企业和品牌使用。

Python 主要用于 TF,但也可以使用 C++、Java、C#、Javascript、Julia。你需要在系统上安装 TF 库并导入该库。

前往 www.tensorflow.org/install 并按照说明安装 TensorFlow。

TensorFlow 是最流行的库之一,也可以在 iOS 和 Android 等移动设备上运行。

Keras:Keras 是一个成熟的 API 驱动解决方案,非常易于使用。它是初学者的最佳选择之一,也是在易于理解和快速原型设计简单概念方面最好的选择之一。Keras 最初于 2015 年发布,是最受推荐的库之一。

前往 keras.io 并按照说明安装 Keras。可以使用 Tf.keras 作为 API。

使用 Python 生成器进行序列化/反序列化 API、回调和数据流传输非常成熟。在 Keras 中,庞大的模型被简化为单行函数,这使得它成为一个 less configurable 环境,因此非常方便和易于使用。

PyTorch:Facebook 的心头宝贝 PyTorch 于 2016 年发布,是另一个流行的框架。PyTorch 使用动态更新的图形,并允许数据并行和分布式学习模型。在 PyTorch 中有像 pdb 或 PyCharm 这样的调试器可用。对于小型项目和原型设计,PyTorch 可能是一个不错的选择。

Sonnet:DeepMind 的 Sonnet 是使用和基于 TF 开发的。Sonnet 专为复杂的神经网络应用和架构设计而设计。它通过创建与神经网络特定部分相对应的主要 Python 对象来工作。然后这些 Python 对象独立于计算 TF 图形地连接。由于这种分离(创建 Python 对象并将其与图形关联),设计得到了简化。

拥有高级面向对象类库非常有帮助,因为在我们开发机器学习解决方案时,它允许我们抽象化。

MXNet:Apache 的 MXNet 是一个高度可扩展的深度学习工具,易于使用并具有详细的文档。MXNet 支持许多语言,如 C ++、Python、R、Julia、JavaScript、Scala、Go 和 Perl。

还有其他框架,如 Swift、Gluon、Chainer、DL4J 等,但我们只讨论了流行的框架。

我们现在将检查 tensorflow 和 keras 中的一个简短的代码。这只是为了测试您是否已正确安装这些库。您可以在 https://www.tensorflow.org 和 https://keras.io 上了解更多关于 tensorflow 和 keras 的信息。

8.7.1 keras 和 tensorflow 的 Python 代码

我们在 tensorflow 中实现了一个非常简单的代码。我们只是导入了 tensor flow 库并打印“hello”。我们还会检查 tensorflow 的版本。

import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
print("TensorFlow version:", tf.__version__)
  • 1
  • 2
  • 3
  • 4
  • 5

如果此代码可以在您的计算机上运行并为您打印出 tensorflow 的版本,则意味着您已经正确安装了tensorflow

from tensorflow import keras
from keras import models
  • 1
  • 2

如果该代码对您运行并打印出 keras 的版本,那么这意味着您已正确安装了keras

8.8 结束语

深度学习正在改变我们生活的世界。它使我们能够训练和创建真正复杂的解决方案,这些只是以前的想法。深度学习的影响可以在多个领域和行业中看到。也许没有一个行业不受深度学习奇迹的影响。

深度学习是研究和开发中最受追捧的领域之一。每年都有许多关于深度学习的期刊和论文发表。世界上重要机构和大学(如牛津、斯坦福等)的研究人员正全神贯注于寻找改进的神经网络架构。与此同时,世界知名机构(如谷歌、Facebook 等)的专业人员和工程师正在努力创建复杂的架构来提高我们的性能。

深度学习使得我们的系统和机器能够解决通常被认为是人类领域的问题。人们改进了药物行业的临床试验流程,改进了欺诈检测软件、自动语音检测系统、各种图像识别解决方案、更强大的自然语言处理解决方案、改进客户关系管理和推荐系统的定向营销解决方案、更好的安全流程等等。这个列表相当长,并且每天都在增长。

与此同时,仍然存在一些挑战。对深度学习的期望不断增加。深度学习不是解决所有问题的灵丹妙药或魔法棒。它确实是更为复杂的解决方案之一,但绝对不是所有业务问题的 100%解决方案。与此同时,我们需要为算法提供的数据集并不总是可用的。缺乏代表业务问题的高质量数据集。经常可以观察到,像谷歌、Meta 或亚马逊这样的大型组织可以负担得起收集如此大规模的数据集。而且很多时候,我们在数据中发现了很多质量问题。拥有处理这些复杂算法的处理能力也是一个挑战。随着云计算的出现,尽管这个问题在一定程度上已经得到了解决。

在本章中,我们探讨了神经网络和深度学习的基础知识。我们涵盖了神经元、激活函数、网络不同层次和损失函数的细节。我们还详细介绍了反向传播算法——用于训练监督深度学习解决方案的核心算法。然后,我们简要介绍了无监督深度学习算法。我们将在接下来的章节中详细介绍这些无监督深度学习解决方案。

我们还展示了主要的激活函数在图 8-13 中。

图 8-13 主要激活函数一览(图片来源:towardsdatascience)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您现在可以转向练习问题。

实用的下一步和建议阅读
  1. 深度学习与 Python》这本由 François Chollet 编写的书籍是澄清深度学习概念的最佳资源之一。它涵盖了深度学习和神经网络的所有概念,并由 Keras 的创作者编写。

  2. 阅读以下研究论文:

  3. 通过 G.Hinton 等人的论文《在神经网络中提炼知识

  4. 通过 R. Srivastava 等人的论文《训练非常深的网络

  5. 通过 Tomas Mikolov 等人的论文《词和短语的分布式表示及其组合性(Word2Vec)

  6. 通过 Ian J. Goodfellow 等人的论文《生成对抗网络(GANs)

  7. 通过 Kaining He 等人的论文《用于图像识别的深度残差学习(ResNet)

8.9 总结

  • 深度学习和神经网络

  • 神经元的定义

  • 不同类型的激活函数

  • 不同类型的优化函数

  • 神经网络训练过程

  • 深度学习的各种库

第九章:自编码器

“在强烈的复杂性中,简单的事物显现出来 - 温斯顿·丘吉尔”

本章内容包括:

  • 自编码器

  • 自编码器的训练

  • 自编码器的类型

  • 使用 tensorflow 和 keras 的 Python 代码

在书的最后一章,我们探讨了深度学习的概念。这些是使您能够掌握无监督深度学习的基础概念。因此,让我们开始无监督深度学习的第一个主题。我们从自编码器开始作为第一个主题。我们将首先介绍自编码器的基础知识,它们是什么以及我们如何训练自编码器。然后我们将进入不同类型的自编码器,然后是有关实现的 Python 代码。

欢迎来到第九章,祝你好运!

9.1 技术工具包

我们将继续使用迄今为止使用的相同版本的 Python 和 Jupyter 笔记本。本章中使用的代码和数据集已经在此位置签入。

在本章中,您需要安装几个 Python 库 - tensorflow 和 keras。

让我们开始阅读书籍的第九章吧!

9.2 特征学习

预测建模是一个非常有趣的话题。在各种领域和业务功能中,预测建模被用于各种目的,如预测明年业务销售额、预测预期降雨量、预测即将到来的信用卡交易是否为欺诈、预测客户是否会购买等。用例很多,上述所有用例都属于监督学习算法。

我们使用的数据集具有变量或属性。它们也被称为特征。

尽管我们希望创建这些预测模型,但我们也有兴趣了解对于进行预测有用的变量。让我们考虑一个银行想要预测即将到来的交易是否是欺诈的情况。在这种情况下,银行希望知道哪些因素是重要的,以便将即将到来的交易标识为欺诈。可能考虑的因素包括交易金额、交易时间、交易的来源/目的地等。用于进行预测的重要变量称为显著变量

为了创建基于机器学习的预测模型,我们使用特征工程。特征工程,又称特征提取,是从原始数据中提取特征以提高模型整体质量并增强准确性的过程,与仅向机器学习模型提供原始数据的模型相比。

特征工程可以使用领域理解、各种手动方法以及一些自动化方法来完成。其中一种方法称为特征学习。特征学习是一组技术,它们帮助解决方案自动发现所需的特征检测表示。利用特征学习,不需要手动特征工程。特征学习对使用图像、文本、音频和视频的数据集的影响更加重要。

特征学习可以是有监督和无监督的。对于有监督的特征学习,神经网络是最好的例子。对于无监督的特征学习,我们有矩阵分解、聚类算法和自编码器等例子。在本书的上一章中已经详细介绍了聚类和矩阵分解。在本章中,我们将讨论自编码器。

接下来,我们将在下一节中介绍自编码器。

9.3 自编码器介绍

当我们开始处理任何数据科学问题时,数据起到最重要的作用。具有大量噪声的数据集是数据科学和机器学习中最大的挑战之一。现在有很多解决方案,自编码器就是其中之一。

简而言之,自编码器是一种人工神经网络,用于学习数据编码。它们通常用于降维方法。它们还可以用作生成模型,可以为我们创建类似于旧数据的合成数据。例如,如果我们没有足够的数据来训练机器学习模型,我们可以使用生成的合成数据来训练模型。

自编码器是前馈神经网络,它们将输入压缩成低维代码,然后尝试从这个表示中重建输出。自编码器的目标是学习高维数据集的低维表示(有时也称编码)。回顾一下前面章节中的主成分分析(PCA)。自编码器可以看作是 PCA 的一般化。PCA 是一种线性方法,而自编码器也可以学习非线性关系。因此,自编码器非常适合用于捕捉输入数据的最重要属性的降维解决方案。

接下来,我们将在下一节中研究自编码器的各个组成部分。

9.4 自编码器的组成部分

自动编码器的结构相当简单。自动编码器由三部分组成:编码器、瓶颈或代码以及解码器,如(图 9.1)所示。简单来说,编码器压缩输入数据,瓶颈或代码包含这些压缩信息,解码器解压知识,从而将数据重构回其原始形式。一旦解压完成并且数据被重构成其已编码形式,输入和输出可以进行比较。

让我们更详细地学习这些组件。

  1. 编码器:输入数据通过编码器。编码器实际上是一个全连接的人工神经网络。它将输入数据压缩成编码表示,并且,在过程中生成的输出大大缩小。编码器将输入数据压缩成一个称为瓶颈的压缩模块。

  2. 瓶颈:瓶颈可以称为编码器的大脑。它包含压缩的信息表示,瓶颈的工作是只允许最重要的信息通过。

  3. 解码器:从瓶颈接收到的信息由解码器解压。它将数据重新创建为其原始或编码形式。一旦解码器完成其工作,实际值将与解码器创建的解压值进行比较。

图 9.1 自动编码器的结构,包括输入层、隐藏层和输出层。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于自动编码器,应该注意几个重要的点:

  1. 在自动编码器中,当解压缩与原始输入相比时会出现信息丢失。因此,当压缩数据解压时,与原始数据相比会存在损失。

  2. 自动编码器是特定于数据集的。这意味着在花朵图片上训练的算法不会在交通信号灯图片上起作用,反之亦然。这是因为自动编码器学到的特征只适用于花朵。因此,我们可以说自动编码器只能压缩与训练数据相似的数据。

  3. 训练专门的算法实例以在特定类型的输入上良好执行相对较容易。我们只需要代表性的训练数据集来训练自动编码器。

我们现在已经涵盖了自动编码器的主要组件。接下来让我们进入训练自动编码器的过程。

9.5 自动编码器的训练

需要注意的是,如果在数据中变量之间没有相关性,那么很难对输入数据进行压缩和随后进行解压。为了创建一个有意义的解决方案,输入数据中的变量之间应该存在某种程度的关系或相关性。为了创建一个自动编码器,我们需要一个编码方法,一个解码方法和一个损失函数来比较实际值与解压值。

过程如下:

  • 首先,输入数据通过编码器模块。

  • 编码器将模型的输入压缩成紧凑的瓶颈。

  • 瓶颈的任务是限制信息的流动,并只允许重要信息通过,因此有时将瓶颈称为知识表示

  • 紧随瓶颈之后的是解码器,它对信息进行解压缩,并将数据重新创建为其原始或编码形式。

  • 这个编码器-解码器架构非常有效地从输入数据中获取最重要的属性。

  • 解决方案的目标是生成与输入相同的输出。

通常观察到解码器架构是编码器架构的镜像。这不是强制性的,但通常会遵循。我们确保输入和输出的维度相同。

我们需要为训练自动编码器定义四个超参数:

  1. Code size: 这可能是最重要的超参数。它表示中间层中节点的数量。这决定了数据的压缩程度,也可以作为正则化项。代码大小的值越小,数据的压缩程度就越大。

  2. 层数是指自动编码器的深度的参数。具有更深度的模型显然更复杂,处理时间也更长。

  3. 每层的节点数是每层使用的权重。随着每个后续层的输入在层之间变小,每层的节点数通常会减少。然后在解码器中增加。

  4. 最后一个超参数是所使用的损失函数。如果输入值在[0,1]范围内,首选二进制交叉熵,否则使用均方误差。

我们已经介绍了用于训练自动编码器的超参数。训练过程类似于我们在上一章中已经介绍过的反向传播。

我们现在将在下一节中介绍自动编码器的一些重要应用。

9.6 自动编码器的应用

自动编码器能够解决许多固有于无监督学习的问题。自动编码器的主要应用包括:

  1. 降维是自动编码器的主要应用之一。有时观察到自动编码器可以学习比主成分分析和其他技术更复杂的数据投影。

  2. 异常检测也是自动编码器的一种应用。错误或重建数据之间的误差(实际数据和重建数据之间的误差)可以用来检测异常。

  3. 数据压缩也被认为是自动编码器的主要应用之一。但已经观察到,通过训练算法很难打败像 JPEG 这样的基本解决方案。此外,由于自动编码器是数据特定的,它们只能用于它们已经训练过的数据类型。如果我们希望增加容量以包含更多数据类型并使其更加通用,那么所需的训练数据量将会非常高,显然所需的时间也会很长。

  4. 还有其他应用,比如药物发现,机器翻译,图像去噪等。但是在现实世界中,自动编码器的实际实现还不是很多。这是因为诸多原因,如数据集的不可用性,基础设施,各种系统的准备情况等。

我们现在将在下一节继续介绍自动编码器的类型。

9.7 自动编码器的类型

有五种主要类型的自动编码器。下面简要描述了不同类型编码器的情况。我们将本节的数学内容保持简单,并跳过幕后的数学原理,因为这些原理相当复杂难以理解。对于好奇的读者,本章的进一步阅读部分中分享了理解幕后数学原理的链接。

  1. 欠完备自动编码器:欠完备自动编码器是自动编码器的最简单形式。它只是接受一个输入数据集,然后从压缩的瓶颈区域重新构建相同的数据集。通过根据重构误差惩罚神经网络,模型将学习数据的最重要属性。通过学习最重要的属性,模型将能够从压缩状态重构原始数据。由于在重构压缩数据时存在损失,这种损失被称为重构损失。

    欠完备自动编码器在本质上是无监督的,因为它们没有任何目标标签来训练。这种类型的自动编码器用于降维。回想一下第二章中我们讨论的降维(PCA),以及第六章中我们讨论的高级降维算法(t-SNE 和 MDS)。

图 9.2 随着维度的增加,性能开始改善,但在一段时间后开始下降。维度灾难是一个真正的问题

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用欠完备自编码器可以进行降维,因为会创建一个压缩形式的输入数据瓶颈。可以利用网络将这种压缩数据解压缩。回想一下在第三章中我们讨论过 PCA 提供了输入变量的线性组合。要获取更多详细信息并刷新 PCA,请参阅第三章。我们知道 PCA 尝试获得一个低维超平面来描述原始数据集,而欠完备自编码器也可以学习非线性关系。我们在下图 9.3 中展示了它们之间的差异:

图 9.3 PCA 是线性的,而自编码器是非线性的。这是两种算法之间的核心区别。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有趣的是,如果从欠完备自编码器中去除所有非线性激活函数,只使用线性层,那么它等价于只有 PCA。为了使自编码器能够泛化而不是记住训练数据,欠完备自编码器是受到限制的,并通过瓶颈的大小进行微调。它允许解决方案不记住训练数据并且泛化能力非常好。

如果一个机器学习模型在训练数据上表现非常好,但在未见过的测试数据上却不起作用,则称为过拟合。

  1. 稀疏自编码器:稀疏自编码器与欠完备自编码器类似,只是它们使用了不同的方法来解决过拟合问题。在概念上,稀疏自编码器改变了每个隐藏层的节点数量并使其灵活。现在,由于不可能有一个具有这种灵活神经元数量能力的神经网络,因此为其定制了损失函数。在损失函数中,引入了一个项来捕捉激活的神经元数量。还有一个与激活的神经元数量成比例的惩罚项。激活的神经元数量越多,惩罚就越高。这个惩罚被称为稀疏函数。通过使用惩罚,可以减少激活的神经元数量,因此惩罚较低,网络能够解决过拟合问题。

  2. 收缩自编码器:收缩自编码器与其他自编码器的工作原理类似。它们认为输入数据相似的部分应该被编码成相同的。因此,它们应该具有相同的潜在空间表示。这意味着输入数据和潜在空间之间不应该有太大的差异。

  3. 去噪自编码器:去噪意味着去除噪音,这正是去噪自编码器的精确任务。它们不接受图像作为输入,而是接受图像的嘈杂版本作为输入,如下图 9.4 所示。

图 9.4 原始图像,嘈杂输出和自编码器的输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

去噪自编码器中的过程如下所示。 通过向原始图像添加噪声来改变原始图像。 这个嘈杂图像被输入到编码器-解码器架构中,接收的输出与原始图像进行比较。 自编码器学习了图像的表示,该表示用于去除噪音,并且通过将输入图像映射到低维流形来实现。

图 9.5:自编码器中的去噪过程。 它从原始图像开始,添加噪音产生一个嘈杂图像,然后将其输入到自编码器中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以使用去噪自编码器进行非线性降维。

  1. 变分自编码器:在标准自编码器模型中,使用瓶颈以压缩形式表示输入。 它们是概率生成模型,只需要神经网络作为整体结构的一部分。 它们是使用期望最大化元算法进行训练的。 技术细节超出了本书的范围。

我们现在将在下一节中学习如何使用 Python 创建一个自编码器。

9.8 自编码器的 Python 实现

我们在这里创建了两个版本的自编码器。 代码来源于 Keras 网站的官方来源(blog.keras.io/building-autoencoders-in-keras.html),并已经修改以供我们使用。

步骤 1:首先,我们将导入必要的库:

import keras
from keras import layers
  • 1
  • 2

步骤 2:我们在这里创建我们的网络架构

# This is the size of our encoded representations
encoding_dim = 32  # 32 floats -> compression of factor 24.5, assuming the input is 784 floats

# This is our input image
input_img = keras.Input(shape=(784,))
# "encoded" is the encoded representation of the input
encoded = layers.Dense(encoding_dim, activation='relu')(input_img)
# "decoded" is the lossy reconstruction of the input
decoded = layers.Dense(784, activation='sigmoid')(encoded)

# This model maps an input to its reconstruction
autoencoder = keras.Model(input_img, decoded)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

步骤 3:向模型添加更多细节

# This model maps an input to its encoded representation
encoder = keras.Model(input_img, encoded) 

# This is our encoded (32-dimensional) input
encoded_input = keras.Input(shape=(encoding_dim,))
# Retrieve the last layer of the autoencoder model
decoder_layer = autoencoder.layers[-1]
# Create the decoder model
decoder = keras.Model(encoded_input, decoder_layer(encoded_input))

autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

步骤 4:加载数据集

(x_train, _), (x_test, _) = mnist.load_data()
  • 1

步骤 5:创建训练和测试数据集

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
print(x_train.shape)
print(x_test.shape)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

步骤 6:现在适配模型

autoencoder.fit(x_train, x_train,
                epochs=5,
                batch_size=128,
                shuffle=True,
                validation_data=(x_test, x_test))
  • 1
  • 2
  • 3
  • 4
  • 5

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 7:在测试数据集上进行测试

# Encode and decode some digits
# Note that we take them from the *test* set
encoded_imgs = encoder.predict(x_test)
decoded_imgs = decoder.predict(encoded_imgs)
  • 1
  • 2
  • 3
  • 4

步骤 8:并绘制结果。 您可以看到原始图像和最终输出。

# Use Matplotlib (don't ask)
import matplotlib.pyplot as plt

n = 10  # How many digits we will display
plt.figure(figsize=(20, 4))
for i in range(n):
    # Display original
    ax = plt.subplot(2, n, i + 1)
    plt.imshow(x_test[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # Display reconstruction
    ax = plt.subplot(2, n, i + 1 + n)
    plt.imshow(decoded_imgs[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.9 思考收尾

深度学习是一个强大的工具。 有了合理的业务问题和高质量的数据集,我们可以创建许多创新解决方案。 自编码器只是这类解决方案中的一种。

在本章中,我们从特征工程开始,它允许我们从数据集中提取最重要的特征。 然后我们转向自编码器。 自编码器是一种仅用于学习未标记数据集的高效编码的神经网络类型。 自编码器可以应用于许多业务问题,如面部识别,异常检测,图像识别,药物发现,机器翻译等。

在本章中,我们涵盖了自编码器。 在下一章中,我们将讨论生成人工智能或 GenAI,这是一个热门话题。 这将是本书的第十章,也是倒数第二章。

9.10 总结

  • 我们在本章中学习了特征工程。 特征工程或特征提取是从原始数据中提取特征以改善模型的总体质量和增强与仅将原始数据馈送到机器学习模型相比的精度的过程。

    • 然后我们在接下来的章节中介绍了自编码器。我们在本章中学习了自编码器。自编码器是前馈神经网络,它们将输入压缩成低维代码,然后尝试从该表示重构输出。

    • 自编码器的典型架构包括编码器、瓶颈和解码器。异常检测、数据压缩和降维是自编码器的主要用途。

  • 我们还涵盖了不同类型的自编码器,如欠完备、稀疏、去噪、收缩和变分自编码器。

实际的下一步和建议阅读
  1. 这里有一个很棒的博客 blog.keras.io/building-autoencoders-in-keras.html

  2. 阅读 G.E.Hinton、A. Krizhevsky、S.D.Wang 撰写的关于自编码器的论文《转换自编码器》www.cs.toronto.edu/~bonner/courses/2022s/csc2547/papers/capsules/transforming-autoencoders,-hinton,-icann-2011.pdf

  3. 阅读 Dor Bank、Naom Koenigstein、Raja Giryes 撰写的关于自编码器的论文《自编码器》arxiv.org/abs/2003.05991

  4. 阅读 Umberto Michelucci 撰写的关于自编码器的论文《自编码器简介》arxiv.org/abs/2201.03898

  5. 在 tensorflow 官方页面有很好的代码和数据集可用 www.tensorflow.org/tutorials/generative/autoencoder

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/943429
推荐阅读
相关标签
  

闽ICP备14008679号