Python 深度学习(一)

原文:zh.annas-archive.org/md5/98cfb0b9095f1cf64732abfaa40d7b3a

译者:飞龙

协议:CC BY-NC-SA 4.0

序言

随着全球对人工智能的兴趣不断增长,深度学习引起了广泛的关注。每天,深度学习算法被广泛应用于不同行业。本书将为您提供关于主题的所有实际信息,包括最佳实践,使用真实用例。您将学会识别和提取信息,以提高预测精度并优化结果。

书籍首先快速回顾了重要的机器学习概念,然后直接深入探讨使用 scikit-learn 的深度学习原则。随后,您将学习使用最新的开源库,如 Theano、Keras、Google 的 TensorFlow 和 H2O。使用本指南来揭示模式识别的困难之处,以更高精度扩展数据,并讨论深度学习算法和技术。无论您是想深入了解深度学习,还是想探索如何更充分地利用这一强大技术,您都可以在本书中找到答案。

本书内容

第一章, 机器学习 - 简介,介绍了不同的机器学习方法和技术,以及它们在现实问题中的一些应用。我们将介绍 Python 中用于机器学习的一个主要开源软件包,即 scikit-learn。

第二章, 神经网络,正式介绍了神经网络是什么。我们将深入描述神经元的工作原理,并展示如何堆叠多层来创建和使用深度前馈神经网络。

第三章, 深度学习基础,将带您了解深度学习是什么,以及它与深度神经网络的关系。

第四章, 无监督特征学习,涵盖了两种最强大且常用的无监督特征学习架构:自编码器和受限玻尔兹曼机。

第五章, 图像识别,从类比我们视觉皮层的工作方式开始,并介绍卷积层,随后描述了它们为什么有效的直观认识。

第六章, 循环神经网络和语言模型,讨论了一些非常有前景的强大方法,在许多任务中表现出很高的潜力,比如语言建模和语音识别。

第七章, 棋盘游戏的深度学习,介绍了用于解决跳棋和国际象棋等棋盘游戏的不同工具。

第八章, 计算机游戏的深度学习,研究了训练 AI 玩计算机游戏所面临的更复杂的问题。

第九章, 异常检测,从解释异常值检测和异常检测概念之间的差异和相似之处开始。您将通过一个想象中的欺诈案例研究,以及展示在现实世界应用程序中存在异常的危险以及自动化和快速检测系统的重要性的示例来指导您。

第十章, 构建一个生产就绪的入侵检测系统,利用 H2O 和常用做法构建一个可部署到生产环境中的可扩展分布式系统。您将学习如何使用 Spark 和 MapReduce 来训练深度学习网络,如何使用自适应学习技术实现更快的收敛速度,并且非常重要的是如何验证模型和评估端到端流程。

您需要为本书准备什么

您将能够使用以下任何操作系统:Windows,Linux 和 Macintosh。

要顺利阅读本书,您需要以下内容:

  • TensorFlow

  • Theano

  • Keras

  • Matplotlib

  • H2O 。

  • scikit-learn

这本书是为谁准备的

本书适用于数据科学实践者和拥有基本机器学习概念和一些 Python 编程经验的有志者。还希望具备数学背景,对微积分和统计概念有概念上的理解。

约定

在本书中,您将找到一系列区分不同类型信息的文本样式。以下是一些示例和解释它们的含义。

文本中的代码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄显示如下:上述用于绘图的代码应立即清晰,我们只需要注意导入cm这一行。

代码块设置如下:

(X_train, Y_train), (X_test, Y_test) = cifar10.load_data()
X_train = X_train.reshape(50000, 3072)
X_test = X_test.reshape(10000, 3072)
input_size = 3072

当我们想要引起您对代码块的特定部分的注意时,相关行或项将以粗体设置:

def monte_carlo_tree_search_uct(board_state, side, number_of_rollouts):
    state_results = collections.defaultdict(float)
    state_samples = collections.defaultdict(float)

任何命令行输入或输出都是这样写的:

git clone https://github.com/fchollet/keras.git
cd keras
python setup.py install

新术语重要单词以粗体显示。

注意

警告或重要说明以这样的框显示。

提示

提示和技巧显示如下。

第一章:机器学习——简介

“机器学习(CS229)是斯坦福最受欢迎的课程”——这是由劳拉·汉密尔顿在《福布斯》上的一篇文章的开头,然后她继续说“为什么?因为越来越多地,机器学习正在改变世界”。

确实,机器学习技术正在被应用于各种领域,并且数据科学家在许多不同的行业中备受追捧。有了机器学习,我们可以确定从数据中并不容易发现的知识,以便能够做出决策。机器学习技术的应用可能差异巨大,并且适用于医学、金融和广告等多种学科领域。

在本章中,我们将介绍不同的机器学习方法和技术,以及它们在实际问题中的一些应用,并且我们将介绍 Python 中一种主要的开源机器学习软件包scikit-learn。这将为随后的章节打下基础,我们将专注于一种特定类型的机器学习方法,使用神经网络来模拟大脑功能,特别是深度学习。深度学习利用比 80 年代使用的更先进的神经网络,不仅得益于理论的最新发展,还得益于计算机速度的提高以及使用GPU(图形处理单元)而不是更传统的CPU(计算处理单元)。本章主要是对机器学习是什么以及能做什么的一个总结,并准备读者更好地了解深度学习如何与流行的传统机器学习技术有所不同。

特别是,本章我们将涵盖:

  • 什么是机器学习?

  • 不同的机器学习方法

  • 机器学习系统涉及的步骤

  • 流行的技术/算法的简要描述

  • 现实生活中的应用

  • 一个流行的开源软件包

什么是机器学习?

机器学习经常和术语“大数据”和“人工智能”,或者简称为 A.I.一起提到,但它与两者都大不相同。要理解机器学习是什么,以及它为何有用,了解大数据是什么以及机器学习如何应用于其中是很重要的。大数据是一个用来描述通过摄像头、传感器或互联网社交网站等方式产生的大规模数据集的术语。据估计,仅谷歌每天处理超过 20PB 的信息,而且这个数字还将继续增加。IBM 估计(www-01.ibm.com/software/data/bigdata/what-is-big-data.html)每天都会产生 25 亿 GB 的数据,而且世界上 90%的数据是在过去两年内创建的。

显然,人类自己无法理解,更别说分析如此庞大的数据量了,而且机器学习技术被用来理解这些非常庞大的数据集。机器学习是用于大规模数据处理的工具,非常适用于具有大量变量和特征的复杂数据集。许多机器学习技术,特别是深度学习,其优势之一是在处理大量数据集时表现最好,从而提高了其分析和预测能力。换句话说,机器学习技术,尤其是深度学习神经网络,在可以访问大量数据集时“学习”最好,以发现数据中隐藏的模式和规律。

另一方面,机器学习的预测能力可以很好地适应人工智能系统。机器学习可以被认为是人工智能系统的“大脑”。人工智能可以被定义为(尽管这个定义可能不是独一无二的)一个能够与环境进行交互的系统:人工智能机器被赋予传感器,使它们可以了解所处的环境,以及可以进行关联的工具。因此,机器学习是允许机器分析经过传感器摄入的数据并制定适当答案的大脑。一个简单的例子是 iPhone 上的 Siri。Siri 通过麦克风听到命令,并通过扬声器或显示屏输出答案,但为了这样做,它需要“理解”所说的话来制定正确的答案。同样,无人驾驶汽车将配备摄像头、GPS 系统、声纳和激光雷达,但所有这些信息都需要被处理,以便提供正确的答案,即加速,刹车,转弯等。导致答案的信息处理代表了机器学习的内容。

不同的机器学习方法

机器学习这个术语,正如我们所看到的,被以非常普遍的方式使用,它指的是从大型数据集中外推模式的一般技术,或者是基于分析已知数据进行学习,并根据所学的内容对新数据进行预测的能力。这是一个非常普遍和广泛的定义,它囊括了许多不同的技术。机器学习技术可以大致分为两类:监督学习和无监督学习,尽管通常还会添加一类,称为强化学习。

监督学习

机器算法的第一类被称为监督学习。 监督学习算法是一类使用一组已标记数据以对相似未标记数据进行分类的机器学习算法。 已标记数据是已经被分类的数据,而未标记数据是还没有被分类的数据。 正如我们将看到的那样,标签可以是离散的或连续的。 为了更好地理解这个概念,让我们举个例子。

假设一个用户每天收到大量电子邮件,其中一些是重要的商务邮件,一些是垃圾邮件或垃圾邮件。 一个监督式机器算法将拿到用户已标记为垃圾邮件或非垃邮件的大量邮件。 该算法将运行在所有已标记的数据上,并预测这些邮件是否属于垃圾邮件。 这意味着算法将检查每个示例,并为每个示例预测这封邮件是否是垃圾邮件。 通常情况下,算法首次运行未标记的数据时,会错误标记许多邮件,并且表现可能相当糟糕。 然而,每次运行之后,算法将比较其预测与期望结果(标记)。 这样一来,算法将学会提高其性能和准确性。 如上所述,这种方法将受益于大量数据,以便更好地学习每封邮件被分类为垃圾邮件或非垃圾邮件的特征(或特征)。

算法在标记数据上运行一段时间后(通常也称为训练数据),并且在其准确性停止改善后,它可以用于新的未标记数据来测试其在新的电子邮件上的准确性。

在我们所使用的例子中,我们描述了一个从已标记数据中学习的算法过程(已被分类为垃圾邮件或非垃圾邮件的邮件),以便对新的未分类邮件进行预测。 然而,重要的是要注意,我们可以将这个过程泛化到不仅仅是两个类别:例如,我们可以运行软件并在一组已标记的电子邮件上对其进行训练,其中标签称为个人商务/工作社交垃圾邮件

事实上,谷歌提供的免费电子邮件服务 Gmail 允许用户选择最多五种类别,分别标注为:

  • 主要,包括人与人之间的对话

  • 社交,包括社交网络和媒体分享网站的消息

  • 促销,包括市场营销邮件、优惠和折扣

  • 更新,包括账单、银行对账单和收据

  • 论坛,包括在线群体和邮件列表的消息

在某些情况下,结果可能并不一定是离散的,我们可能没有一个有限的类别来对数据进行分类。例如,我们可能正在基于预先确定的健康参数来预测一群人的预期寿命。在这种情况下,由于结果是一个连续函数(我们可以指定寿命预期为表示人们预期活多少年的实数),我们不谈论分类任务,而是一个回归问题。

想象一下监督学习的一种方法是,我们试图构建一个在数据集上定义的函数f。我们的数据集将包含由特征组织的信息。在电子邮件分类的例子中,这些特征可能是在垃圾邮件中出现频率较高的特定单词。使用显式的与性相关的词语很可能可以识别出垃圾邮件而不是商务/工作邮件。相反,诸如“会议”,“商务”和“演示”之类的词可能更有可能描述一个工作邮件。如果我们有访问元数据的权限,发送方信息也可以用来更好地分类电子邮件。然后,每封电子邮件将关联一组特征,并且每个特征将有一个值(在这种情况下,特定单词在电子邮件正文中出现的次数)。机器学习算法将寻求将这些值映射到表示一组类别的离散范围,或者在回归的情况下是一个实值。该算法将运行多个示例,直到能够定义出最佳函数,以便正确匹配大部分标记数据。然后它可以在未标记数据上运行,以做出预测而不需要人为干预。这定义了一个函数:

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

我们也可以将分类视为一种寻求分离不同数据点组的过程。一旦我们定义了我们的特征,任何例子,比如说,是我们数据集中的一个电子邮件,可以被视为特征空间中的一个点,每一个点代表一个不同的例子(或电子邮件)。机器算法的任务是画出一个超平面(即高维空间中的平面),将具有不同特征的点分开,正如我们想要将垃圾邮件与非垃圾邮件分开一样。

虽然在二维情况下可能看起来很简单,但在具有数百或数千维度的情况下可能非常复杂。

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

分类可以被看作是分隔输入数据的一种方式

在后面的章节中,我们将看到几个分类或回归问题的例子。我们将讨论其中一个问题是数字的分类:给定一组代表 0 到 9 的图像,机器学习算法将尝试对每个图像进行分类,并分配给它所描绘的数字。对于这样的例子,我们将使用最经典的数据集之一,即 MNIST 数据集。在这个例子中,每个数字由一个 28 x 28(=784)像素的图像表示,我们需要对每个数字进行分类,因此我们需要在 784 维空间中画出 9 个分隔超平面。

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

来自 MNIST 数据集的手写数字示例

无监督学习

机器学习算法的第二类称为无监督学习。在这种情况下,我们不事先为数据贴上标签,而是让算法得出结论。无监督学习中最常见、也许是最简单的例子之一是聚类。这是一种试图将数据分成子集的技术。

举例来说,在前述的垃圾邮件/非垃圾邮件的情况下,算法可能能够找到所有垃圾邮件共有的元素(例如,拼写错误的单词的存在)。尽管这可能提供比随机分类更好的结果,但不清楚垃圾邮件/非垃圾邮件是否能够如此轻松地分开。算法将数据分离成的子集是数据集的不同类别。为了使聚类有效,每个聚类中的每个元素在原则上应具有高的类内相似度和与其他类别的低相似度。聚类可以处理任意数量的类别,并且聚类方法(如 k 均值)背后的想法是找到原始数据的 k 个子集,这些子集的元素彼此之间比与其类外的任何其他元素更接近(更相似)。当然,为了做到这一点,我们需要定义更接近更相似的含义,也就是说,我们需要定义某种度量,来定义点之间的距离。

在下图中,我们展示了一组点如何被分类成三个子集:

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

给定数据集的元素不一定需要聚集在一起形成一个有限集合,而聚类也可能包括给定数据集的无界子集,如下图所示:

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

聚类并不是唯一的无监督技术,我们将看到深度学习最近的成功与其在无监督学习任务中如此有效有关。

每天都会快速产生新数据,而对所有新数据进行标记是一项相当费力和耗时的活动。无监督学习算法的一个优点是它们不需要标记数据。无监督深度学习技术和方法,比如受限玻尔兹曼机,通过从数据中抽象特征来工作。例如,使用 MNIST 数据集,受限玻尔兹曼机将提取出对每个数字独特的特征,检测每个数字的线条和曲线的形状。无监督学习通过揭示数据中的隐藏结构来分类数据,而不是通过将其与标签进行匹配。

此外,例如使用深度信念网络,我们可以通过用监督学习对其进行改进来改善无监督方法的性能。

强化学习

机器学习技术的第三类是强化学习。尽管它仍然使用反馈元素来提高性能,但它的工作方式与监督学习不同。强化学习技术的一个常见应用是教导机器如何玩游戏:在这种情况下,我们不会将每一步标记为好或坏,而是从游戏中获得反馈,要么通过游戏的结果,要么通过游戏过程中的信号,比如得分或失分。赢得游戏会反映为积极的结果,类似于识别正确的数字或电子邮件是垃圾邮件还是不是,而输掉游戏将需要进一步的“学习”。强化学习算法倾向于重复尝试过去导致成功结果的动作,就像在游戏中获胜一样。然而,在未知领域,算法必须尝试新的动作,根据结果,它将更深入地学习游戏的结构。因为通常,动作是相互关联的,因此不能将单个动作评价为“好”或“坏”,而是整体动作的动态评价。类似于在下棋时有时候牺牲一个兵可能被认为是积极的动作,如果它带来了更好的棋盘位置,尽管丢失一个棋子通常是一个负面的结果,在强化学习中,探索的是整个问题及其目标。例如,一个移动的清洁机器人可能必须决定是继续清洁房间还是开始回到充电站,并且这样的决定可以基于在类似情况下它是否能在电池耗尽之前找到充电站。在强化学习中,基本思想是奖励,算法将寻求最大化总奖励。

强化学习的一个简单示例可以用来玩经典的井字棋游戏。在这种情况下,棋盘上的每个位置都关联了一个概率(一个值),这是基于先前经验从该状态赢得游戏的概率。开始时,每个状态被设定为 50%,这意味着在开始时我们假设从任何位置开始我们赢得或输掉的概率是相等的。一般来说,机器将尝试朝着价值更高的位置前进以赢得游戏,并且如果失败则重新评估它们。在每个位置,机器将基于可能的结果而做出选择,而不是基于固定的确定规则。随着继续进行游戏,这些概率将得到精炼,并根据位置输出更高或更低的成功机会。

机器学习系统涉及的步骤

到目前为止,我们已经讨论了不同的机器学习方法,并且我们已经大致将它们组织在三种不同的类别中。另一个重要的方面是了解数据,以更好地理解手头的问题。我们需要定义的重要方面大致可以描述如下:

  • 学习者:这代表着使用的算法及其"学习哲学"。正如我们将在下一段中看到的,有许多不同的机器学习技术可以应用于不同的学习问题。学习者的选择很重要,因为不同的问题可以更适合某些机器学习算法。

  • 训练数据:这是我们感兴趣的原始数据集。这样的数据可能是未标记的,用于无监督学习,或者它可能包含标签,用于监督学习。确保学习者有足够的样本数据以理解问题的结构非常重要。

  • 表示:这是数据以所选特征的方式表达,以便学习者可以摄入的方式。例如,如果我们试图使用图像对数字进行分类,这将代表描述图像像素的值数组。良好的数据表示选择对于取得更好的结果是重要的。

  • 目标:这代表了从手头的问题中学习的原因。这与目标息息相关,并且有助于定义应该使用什么学习者和什么表示。例如,目标可能是清理我们的邮箱中不需要的邮件,目标定义了我们的学习者的目标,例如,检测垃圾邮件。

  • 目标:这代表着正在学习和最终输出的内容。它可以是未标记数据的分类,可以是根据隐藏的模式或特征表示输入数据,可以是未来预测的模拟器,可以是对外部刺激的响应,也可以是强化学习中的策略。

无论如何强调都不为过,任何机器学习算法只能达到目标的近似值,而不能得到完美的数值描述。机器学习算法不是问题的精确数学解,而只是近似值。在前面的段落中,我们已经将学习定义为从特征空间(输入)到类别范围的函数;我们将在后面看到,某些机器学习算法,如神经网络,理论上可以被证明能够近似地逼近任何函数到任何程度。这个定理被称为通用逼近定理,但这并不意味着我们可以得到问题的精确解。此外,通过更好地理解训练数据,可以更好地解决问题。

通常,使用经典机器学习技术可解决的问题在部署之前可能需要对训练数据进行深入了解和清理。如果我们要陈述处理机器学习问题所需的一些步骤,我们可以总结如下:

  • 数据收集:这意味着尽可能收集尽可能多的数据,并且在监督学习问题中还要正确标记数据。

  • 数据处理:这意味着清理数据(例如删除多余或高度相关的特征,或填充缺失数据),并且理解定义训练数据的特征。

  • 测试用例的创建:通常数据可以分为两到三组:一个用于训练算法的训练数据集,一个用于在训练算法后测试方法准确性的测试数据集。通常情况下,我们还会创建一个用于最终测试(或验证)的验证数据集,经过多次训练-测试流程后,我们最终满意结果,进而做最终测试(或验证)。

有充分的理由创建一个测试集和一个验证集。正如我们所提到的,机器学习技术只能产生期望结果的近似值。这是因为通常情况下,我们只能包括有限数量的变量,而可能有许多变量是我们无法控制的。如果我们只使用一个数据集,我们的模型可能最终会“记住”数据,并在已记住的数据上产生极高的准确性值,但这个结果可能无法在其他类似的数据集上重现。机器学习技术的一个关键目标是其泛化能力。这就是为什么我们既创建了一个用于训练后模型选择调整的测试数据集,又创建了一个仅在流程结束时才用于确认所选算法有效性的最终验证数据集。

为了理解在数据中选择有效特征的重要性以及避免“记忆”数据的重要性(更技术性的术语是文献中所称的“过拟合”,从现在开始我们将使用这个术语),让我们用一个来自xkcd漫画的笑话来举例(xkcd.com/1122):“直到 1996 年,没有一个现任的民主党美国总统候选人,且没有军事经验,曾经打败过任何人名的首字母在 Scrabble 中价值更高的人”。很显然,这种“规则”在这个例子中是没有意义的,但它突出了选择有效特征的重要性(一个人的名字在 Scrabble 中价值多少与选择美国总统有关吗?),而选择随机特征作为预测因子,虽然可能会预测当前数据,但不能用作更一般数据的预测器,而 52 次选举中这一点成立只是一个简单的巧合。这通常被称为过拟合,也就是说,做出与手头数据完全吻合的预测,但不能推广到更大的数据集。过度拟合是试图理解通常所说的“噪音”(即,没有任何实际意义的信息)的过程,并尝试适应模型的小扰动。

另一个例子可以通过尝试使用机器学习来预测从地面抛出并上升到又落回地面的球的轨迹(不是垂直向上)。物理学告诉我们,轨迹呈抛物线状,我们期望一个好的机器学习算法观察到数千次这样的抛掷会得出一个抛物线作为解。然而,如果我们放大球并观察空气湍流中最小的波动,我们可能会注意到球不会保持稳定的轨迹,而可能受到小的扰动。这就是我们所称的“噪音”。试图模拟这些小扰动的机器学习算法将无法看到整体图景,并得出一个不令人满意的结果。换句话说,过拟合是使机器学习算法看到树木而忘记了整个森林的过程。

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

一个好的预测模型与一个糟糕的(过拟合的)预测模型有着不同的轨迹,对于一个从地面上抛出的球的轨迹来说。

这就是为什么我们将训练数据与测试数据分开的原因:如果测试数据的准确率与在训练数据上获得的结果不相似,那么这将是一个很好的指示,表明我们已经过度拟合了模型。当然,我们也需要确保我们不犯相反的错误,也就是说,不要欠拟合模型。但是在实践中,如果我们的目标是尽可能地使我们的预测模型在我们的训练数据上尽可能准确,那么欠拟合比过拟合的风险要小得多,因此我们应尽量避免过度拟合模型。

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

欠拟合也可能是一个问题

流行技术/算法的简要描述

除了根据它们的"学习风格"将算法分组之外,即本书开头讨论的三类,监督学习、无监督学习和强化学习,我们还可以根据它们的实现将它们分组。显然,上面讨论的每个类别都可以使用不同的机器学习算法来实现,例如,有许多不同的监督学习技术,每种技术可能最适合于手头的特定分类或回归任务。事实上,分类和回归之间的区别是最关键的之一,并且理解我们试图完成的任务是很重要的。

以下绝不意味着是一个详尽的列表或对每种机器学习方法的彻底描述,对于这些,我们建议读者参考 Sebastian Raschka 的书籍Python Machine Learning (www.packtpub.com/big-data-and-business-intelligence/python-machine-learning),而是意味着作为一个简单的回顾,为读者提供不同技术的简单味道以及深度学习与它们的区别。在接下来的章节中,我们将看到深度学习不仅仅是另一种机器学习算法,而且在很多方面与传统的机器学习技术不同。

我们将介绍一个回归算法,线性回归,经典的分类器,如决策树、朴素贝叶斯和支持向量机,以及无监督的聚类算法,如 k 均值,和强化学习技术,交叉熵方法,仅仅是对存在的各种机器学习技术的一个小小的了解,我们将通过介绍神经网络来结束这个列表,这是本书的主要焦点。

线性回归

回归算法是一种监督算法,它使用输入数据的特征来预测一个值,例如给定某些特征(如大小、年龄、浴室数量、楼层数、位置等)可以预测出房屋的价格。回归分析试图找到最能拟合输入数据集的函数参数值。在线性回归算法中,目标是通过找到适当的函数参数来最小化成本函数,使其最好地逼近目标值。成本函数是一个错误的函数,它表示我们离正确结果有多远。通常使用的成本函数是均方误差,其中我们计算预期值与预测结果之间的差的平方。对所有输入示例的总和给出了算法的错误值,它代表了成本函数。

假设我们有一所 100 平方米的房子,建于 25 年前,有三个浴室,两层。此外,假设我们将房子所在的城市分成 10 个不同的区域,用从 1 到 10 的整数表示,假设这所房子位于编号为 7 的区域。我们可以用一个 5 维向量 x = (100, 25, 3, 2, 7) 来对这所房子进行参数化。假设我们还知道这所房子的估计价值为€10,0000。我们想要实现的是创建一个函数 f,使得 f(x) = 100000

在线性回归中,这意味着找到一个向量w =(w[1],w[2],w[3],w[4],w[5],使100w*[1]* + 25w[2]* + 3w[3]* + 2w[4]* + 7w[5]* = 100000*。如果我们有一千幢房子,我们可以为每栋房子重复相同的过程,理想情况下,我们希望找到一个* w向量,可以为每栋房子预测正确的值(或足够接近)。假设我们最初选择了一些 w的随机值。在这种情况下,我们不希望 f(x)* = 100* w*[1]* + 25* w*[2]* + 3* w*[3]* + 2* w*[4]* + 7* w*[5]* 等于 1,00,000,因此我们可以计算误差∆ =(100000 − * f(x) [2]。这是一个示例 x的均方误差,所有示例的均方误差的均值代表了我们的成本,也就是我们的函数与真实值的差异有多少。因此,我们的目标是最小化此误差,为此我们计算成本函数相对于 w 的导数δ。导数指示函数增加(或减少)的方向,因此,把 w 移动到导数的相反方向会提高我们函数的准确性。这是线性回归的要点,向着成本函数的最小值移动,这代表了错误。当然,我们需要决定我们想以多快的速度沿着导数指示的方向移动,因为我们的导数只指明了一个方向。成本函数不是线性的,因此我们需要确保只在导数指示的方向上迈出小步。迈出太大的一步可能会导致我们超过最小值,因此无法收敛到最小值。这一步的大小就是所谓的学习率*,让我们用符号“lr”表示它的大小。

通过设置w = w - δ**lr,* 我们因此改善了w向更好解决方案的选择。重复这个过程多次将产生表示* f的最佳可能选择的w*值。然而,我们应该强调,如果空间不是凸的,这个过程只在局部起作用,并且可能无法找到全局的最佳值。正如图像所暗示的,如果存在许多局部最小值,算法可能最终会被困在其中一个局部最小值中,无法逃脱到达误差函数的全局最小值,类似于一个小球从山上滚下来,可能会卡在一个小山谷中,无法到达山底。

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

顶部图是凸的,因此只存在一个最小值。在底部图中,函数有两个局部最小值,因此,取决于初始化,该过程可能会找到第一个不是全局最小值的局部最小值。

决策树

另一个广泛使用的监督算法是决策树算法。决策树算法创建一个“树”形式的分类器。决策树由决策节点组成,其中对特定属性进行测试,以及指示目标属性值的叶节点。决策树是一种分类器,通过从根节点开始并通过决策节点向下移动直到达到叶子节点来工作。

该算法的一个经典应用是鸢尾花数据集(archive.ics.uci.edu/ml/datasets/Iris),其中包含来自三种鸢尾花(山鸢尾、维吉尼亚鸢尾和变色鸢尾)的 50 个样本的数据。创建数据集的罗纳德·费舍尔测量了这些花的四种不同特征,即它们的萼片的长度和宽度,以及它们的花瓣的长度和宽度。根据这些特征的不同组合,可以创建一个决策树来决定每朵花属于哪个物种。在这里,我们将描述一个简单的简化决策树,它将只使用这两个特征,花瓣的长度和宽度,就能正确分类几乎所有的花。

我们从第一个节点开始,我们对花瓣长度进行第一个测试:如果花瓣长度小于 2.5,则该花属于山鸢尾物种。事实上,这将正确地对所有花瓣长度小于 2.5 厘米的山鸢尾花进行分类。因此,我们到达了一个标记为山鸢尾的叶子节点。如果花瓣长度大于 2.5,我们选择另一条分支,我们到达一个新的决策节点,并测试花瓣宽度是否大于 1.8。如果花瓣宽度大于或等于 1.8,则我们到达一个叶节点,并将我们的花分类为维吉尼亚鸢尾,否则我们到达一个新的决策节点,在这里我们再次测试花瓣长度是否大于 4.9。如果是,则我们到达一个标记为维吉尼亚鸢尾花的叶子节点,否则我们到达另一个标记为变色鸢尾花的叶子节点。

所讨论的决策树可以表示如下,其中左分支反映了决策节点中测试的积极答案,而右分支表示决策节点中测试的否定答案。每个分支的末端节点都是叶节点。

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

这个例子展示了决策树算法与线性回归有多么不同。此外,当我们介绍神经网络时,读者将能够通过使用相同的数据集来看到神经网络是如何工作的一个示例。在那个例子中,我们还将提供 Python 代码,并展示一些神经网络将如何基于它们的特征来尝试分离花朵的图片。

K-means

如我们已经讨论过的,聚类算法是一种无监督的机器学习方法。最常见的聚类技术是称为 k-means 聚类的技术,它是一种将数据集中的每个元素分组到 k 个不同子集中的聚类技术(因此在名称中有 k)。K-means 是一个相对简单的过程,包括选择代表 k 个不同子集的随机 k 点,称为中心。然后,我们为每个中心选择所有最接近它的点。这将创建 k 个不同的子集。此时,对于每个子集,我们将重新计算中心。我们再次有 k 个新中心,然后重复上述步骤,为每个中心选择与中心最接近的新子集。我们继续这个过程,直到中心停止移动。

很明显,为了使这种技术起作用,我们需要能够识别一种允许我们计算点之间距离的度量标准。此过程可以总结如下:

  1. 选择初始 k 点,称为中心点。

  2. 将数据集中的每个点与最近的中心关联起来。

  3. 计算与特定中心点关联的点集的新中心。

  4. 将新中心定义为新的中心。

  5. 重复步骤 3 和 4,直到中心停止移动。

需要注意的是,此方法对随机中心的初始选择非常敏感,可能重复使用不同的初始选择是个好主意。此外,某些中心可能不是数据集中任何点最近的中心,将子集数目减少到 k。值得一提的是,如果我们在上面讨论决策树的例子中使用 k=3 的 k-means,我们可能不会得到与使用决策树找到的鸢尾花数据集相同的分类,再次强调了如何重要地为每个问题选择和使用正确的机器学习方法。

现在,让我们讨论一个使用 k-means 聚类的实际示例。假设一个披萨外卖店想要在一个新城市开设四家新的连锁店,他们需要选择四个新店的位置。这是一个可以通过 k-means 聚类轻松解决的问题。其思想是找到最常订购披萨的地点;这些地点将成为我们的数据点。接下来,我们选择四个随机点作为站点位置。通过使用 k-means 聚类技术,我们可以后来确定最佳位置,以最小化到每个送货地点的距离。这是一个 k-means 聚类可以帮助解决业务问题的例子。

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

左边是披萨最常送达的点的分布。右边是圆点表示新的连锁店应该位于的位置及其相应的送货区域

朴素贝叶斯

朴素贝叶斯不同于许多其他机器学习算法。从概率上讲,大多数机器学习技术试图评估的是在给定条件X下某个事件Y的概率,我们用*p(Y|X)*表示。例如,给定描述数字的图片(即,具有特定像素分布的图片),那么该数字为 5 的概率是多少?如果像素的分布接近于其他标记为 5 的示例的像素分布,那么该事件的概率将很高,否则概率将很低。

有时我们具有相反的信息,也就是说,我们知道我们有一个事件Y的情况下,我们知道样本为X的概率。贝叶斯定理说明:p(X|Y) = p(Y|X)p(X)/p(Y),其中p(X|Y)表示在知道Y的情况下生成实例X*的概率,这也是为什么朴素贝叶斯被称为生成方法。简而言之,我们可以计算某个像素配置代表数字 5 的概率,知道在有 5 的情况下,即使随机像素配置可能与给定的一致,这是为什么。

这在医学测试领域是最容易理解的。假设我们针对特定疾病或癌症进行测试。我们想知道在我们测试结果为阳性的情况下,我们可能患有特定疾病的概率是多少。现在,大多数测试都有可靠性值,这是在针对患有特定疾病的人群时测试呈阳性的概率。通过颠倒表达式*p(X|Y) = p(Y|X)p(X)/p(Y),我们有:

p(癌症 | 测试=阳性) = p(测试=阳性 | 癌症) * p(癌症)/p(测试=阳性)

假设测试的可靠率为 98%,这意味着在 98%的情况下,如果一个人患有癌症,那么测试结果为阳性,同样地,如果一个人没有癌症,测试结果将为阴性。还假设这种特定的癌症只影响年龄较大的人,50 岁以下的人中只有 2%的人患有这种癌症,对于这部分人群进行测试,结果呈阳性的概率仅占到人群的 3.9%(我们可以从数据中推导出这个事实,但为简单起见,我们提供这些信息)。

我们可能会提出这样一个问题:如果一项癌症测试的准确率为 98%,45 岁的人接受了测试,并且测试结果呈阳性,那么他/她可能患癌症的概率是多少?使用上述公式,我们可以计算:

p(癌症 | 测试=阳性) = 0.98 * 0.02/0.039 = 0.50

因此,尽管测试的准确性很高,朴素贝叶斯告诉我们我们还需要考虑这样一个事实:50 岁以下罹患癌症的情况相当罕见,因此仅仅通过测试结果的阳性并不能给出 98%的癌症患病概率。概率p(癌症),或者更一般地说是我们试图估计的结果的概率 p,被称为先验概率,因为它代表了没有任何额外信息的事件概率,也就是在我们进行测试之前的概率。

此时,我们可能会想知道如果我们有更多信息会发生什么,例如如果我们使用了可靠性更高的不同测试,或者了解了一些人的信息,例如家族中的癌症复发情况。在上述方程中,我们使用了作为计算因素之一的概率 p(test=positive | cancer),如果我们进行第二个测试,并且结果也为正,我们也会有 p(test2=positive | cancer)。朴素贝叶斯技术假设每个信息片段都是独立的(这意味着第二个测试的结果不知道第一个测试的结果,并且它与第一个测试无关,即进行第一个测试不能改变第二个测试的结果,因此它的结果不受第一个测试的影响)。朴素贝叶斯是一种分类算法,它假设不同事件之间是相互独立的,以计算它们的概率。因此:

*= p(当第一个测试和第二个测试都为正时,癌症的条件概率) =p(当第一个测试为正时,癌症的条件概率)p(当第二个测试为正时,癌症的条件概率)

这个方程也称为在人确实患有癌症的情况下,test1test2为阳性的概率 L(test1 和 test2 = pos)

我们可以将方程重写为:

= p(癌症在两个测试都为正时的条件概率) =

= p(当两个测试为正时,癌症的条件概率)p(癌症)/p(两个测试都为正) =

*= p(当第一个测试为正时,癌症的条件概率)*p(当第二个测试为正时,癌症的条件概率)p(癌症)/p(两个测试都为正)

支持向量机

支持向量机是一种用于分类的监督机器学习算法。支持向量机相对于其他机器学习算法的优势在于,它不仅将数据分成类别,而且还通过寻找最大化将每个点与超平面(多于三个维度的空间中的平面的类比)分离的分隔超平面来实现这一目标。此外,支持向量机还可以处理数据不是线性可分的情况。处理非线性可分数据的方法有两种,一种是引入软边界,另一种是引入所谓的核技巧。

松弛边界在保留算法大部分预测能力的同时允许存在少量错误分类的元素。正如我们上面所讨论的,在实践中,最好不要过度拟合任何机器学习模型,我们可以通过放宽一些支持向量机的假设来实现这一点。

相反,核技巧涉及将特征空间映射到另一个空间,在该空间中我们可以定义一个超平面,将其映射回特征空间时,它不再是一个线性超平面,从而允许分离数据集中看似不可分离的元素。由于本书主要关注深度学习,我们不会详细讨论支持向量机的实现方式,这可能会花费太多时间,而是要强调支持向量机之所以非常流行和有效的概念,这要归功于它们能够推广到非线性情况。正如我们之前所见,监督式机器学习算法的任务是找到从特征空间到一组类别的函数。每个输入x= (x[1], x[2], …, x[n])表示一个输入示例,而每个x[i]表示第i个特征的值。早些时候我们举了一个例子,试图根据一些特征(如浴室数量或位置)来估计某个房屋的转售价值。如果第i个特征对应于浴室数量,则x[i]将对应于房屋x中存在的浴室数量。我们可以从特征空间创建一个函数k到这个空间的另一个表示,称为核:例如,k可以将x[i]映射到*(x*[i])²,并且通常将特征空间非线性地映射到另一个空间W。因此,在W中的分离超平面可以映射回特征空间,其中它将不再是线性超平面。这个条件确切的定义在哪些情况下成立是明确定义的,但超出了这个简短介绍的范围。然而,这再次突显了在经典机器学习算法中选择正确特征的重要性,这样的选择可以帮助找到特定问题的解决方案。

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

左侧是应用核之前的非线性可分数据集。右侧是应用了核之后的相同数据集,数据可以线性分离。

交叉熵方法

到目前为止,我们介绍了监督学习和无监督学习算法。相反,交叉熵方法属于强化学习类算法,将在本书的第七章和第八章中详细讨论,《棋类游戏的深度学习》和《电子游戏的深度学习》。交叉熵方法是解决优化问题的技术,即找到最佳参数以最小化或最大化特定函数。

通常,交叉熵方法包括以下阶段:

  1. 生成我们试图优化的变量的随机样本。对于深度学习,这些变量可能是神经网络的权重。

  2. 运行任务并存储性能。

  3. 识别最佳运行并选择性能最佳的变量。

  4. 根据表现最佳的运行,计算每个变量的新均值和方差,并生成变量的新样本。

  5. 重复步骤,直到达到停止条件或系统停止改进。

假设我们正在尝试解决一个依赖于许多变量的函数,例如我们正在尝试建立一个模型飞机,当从特定高度发射时,它能够飞得最远。飞机飞行的距离将取决于其机翼的大小、它们的角度、重量等。每次,我们都可以记录每个变量,然后发射飞机并测量它飞行的距离。但是,我们不是尝试所有可能的组合,而是创建统计数据,我们选择最佳和最差的运行,并注意在最佳运行和最差运行期间变量设置的值。例如,如果我们发现每次最佳运行飞机都具有特定大小的机翼,我们可以得出结论,该特定大小可能对于飞机飞行很远是最优的。相反,如果对于每次最差运行,飞机的机翼都处于某个角度,我们会得出结论,该特定角度对于我们飞机的机翼是一个不好的选择。总的来说,我们将为应该产生最佳飞机的每个值产生一个概率分布,这些概率不再是随机的,而是基于我们收到的反馈。

因此,该方法利用运行的反馈(飞机飞了多远)来确定问题的最佳解决方案(每个变量的值),这是典型的强化学习过程。

神经网络

在给读者带来一些流行的经典机器学习算法之后,我们现在将介绍神经网络,并深入解释它们的工作原理以及它们与我们简要总结的算法的区别。

神经网络是另一种机器学习算法,它们有着高人气的时期和极少被使用的时期。理解神经网络,我们将在接下来的几章中专门介绍,确实是理解本书内容的关键。

第一个神经网络的例子被称为感知机,它是由弗兰克·罗森布拉特于 1957 年发明的。感知机是一个由输入层和输出层组成的网络。在二元分类的情况下,输出层只有一个神经元或单元。一开始,感知机似乎非常有前途,但很快就发现它只能学习线性可分的模式。例如,马文·明斯基和西摩·帕普特证明它无法学习异或逻辑函数。在其最基本的表示中,感知机只是一个神经元及其输入的简单表示,输入可以由多个神经元组成。

给定不同的输入到一个神经元,我们通过公式外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传定义激活值,其中x [i]是输入神经元的值,而w [i]是神经元 i 和输出之间的连接值。我们将在下一章节中深入学习这个公式,现在我们只需要注意感知机与逻辑回归算法有许多相似之处,并且也受到线性分类器的限制。如果激活值(被视为神经元的内部状态)大于固定阈值 b,则神经元将被激活,即会发生激活,否则不会。

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

一个带有三个输入单元(神经元)和一个输出单元(神经元)的简单感知机。

上面定义的简单激活可以理解为向量w和向量x的点积。向量w是固定的,并且它定义了感知机的工作方式,而x表示输入。如果*<* w,x > = 0,则向量x垂直于权重向量w,因此所有满足*<* w,x > = 0的向量x定义了R ^(3) (其中3x的维度,但通常可以是任何整数)中的一个超平面。因此,任何满足*<* w,x > > 0的向量x都是位于w定义的超平面的一侧的向量。这清楚地说明了感知机如何定义一个超平面,并且可以作为一个分类器工作。一般而言,我们可以将阈值设置为任何实数b,这使得超平面远离原点。然而,通常我们在网络中包含一个偏置单元,它是一个始终开启(值为 1)的特殊神经元,并具有连接权重*-b*。在这种情况下,如果连接权重的值为*-b*,激活值变为外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,而设置a(x) > 0等同于设置外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

一个感知机加上一个偏置单元作为输出向量。偏置单元始终为开启状态。

感知机在性能上有限,但在历史上非常重要,因为它们是神经网络的第一个例子。

神经网络当然不需要只有一个输出神经元,事实上,一般情况下不会只有一个。如果网络有多个输出神经元,那么对于每个输出神经元,我们可以重复相同的过程。然后,每个权重都将被标记为两个指标,ij,以指示权重连接了输入层的神经元 i 和输出层的神经元 j。还将从偏置单元连接到输出层的每个神经元,其值为 1。还应该注意,我们可以在激活值上定义不同的活动函数。我们已经将激活值定义为 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(从现在开始,我们将假设偏差已包含在此公式中),并且我们已经说过,如果激活大于 0,则神经元激活。正如我们将看到的,这已经定义了一个活动函数,即在激活上定义的函数,即在神经元的内部状态上定义的函数,并且这被称为阈值活动,因为当激活大于 0 时,神经元激活。但是,我们将看到,神经网络可以具有许多不同的活动函数,这些函数可以在其激活值上定义,并且我们将在下一章中对其进行更详细的讨论。

深度学习

前面的段落介绍了一个非常简单的神经网络示例,即前馈 1 层网络。它们被称为前馈,因为信息从输入向输出传递,永远不会循环返回,而且是 1 层,因为除了输入层之外只有 1 个输出层。这不是一般情况。当我们提到它们只能处理线性可分数据时,我们已经讨论了前馈 1 层网络的局限性,特别是我们提到它们无法逼近逻辑异或函数。然而,存在具有额外层的网络,这些层位于输入和输出层之间:这些层称为隐藏层。具有隐藏层的前馈网络将信息从输入通过其隐藏层传递到输出层,这定义了一个接受输入并定义输出的函数。存在一个定理,称为通用定理,它说明任何函数都可以由具有至少一个隐藏层的神经网络逼近,并且我们将在下一章中给出为什么这是正确的直觉。

长时间以来,考虑到这个定理以及与复杂网络合作的困难,人们一直使用只有一个隐藏层的浅层网络。然而,最近人们意识到,具有许多隐藏层的更复杂的网络可以理解比浅层网络更多的抽象层次。此外,还引入了循环网络,其中神经元也可以将信息反馈给自身。一些神经网络的结构也可以允许定义能量函数,从而可以创建记忆。所有这些令人兴奋的功能将在接下来的章节中讨论,我们将深入研究深度学习的最新发展。

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

一个隐藏层的神经网络

在现实生活中的应用

一般来说,机器学习,尤其是深度学习,在预测质量、特征检测和分类方面正在产生越来越令人惊讶的结果。近年来,许多最近的结果都成为了新闻。进展如此之快,以至于许多专家担心很快机器将比人类更加智能。在 2015 年 10 月 14 日的联合国会议上,人工智能专家和其他许多领域的研究人员警告说,需要定义道德准则来防止超级智能机器可能给人类社会带来的危险。这些担忧源于一些最近的令人难以置信的结果,其中计算机已经能够击败人类最好的冠军,在人们认为直觉会给人类在与机器的比赛中带来优势的游戏中。

AlphaGo 是基于深度学习的人工智能机器,在 2016 年曾因击败世界围棋冠军李世石而成为新闻头条。在 2016 年 1 月,AlphaGo 已经因击败欧洲冠军范辉而成为新闻,尽管当时看起来不太可能击败世界冠军。几个月后,AlphaGo 成功通过以 4-1 的胜利系列横扫对手来实现这一非凡壮举。庆祝的原因在于围棋比其他游戏(如国际象棋)拥有更多可能的游戏变化,因此不可能事先考虑所有可能的走法。此外,在围棋中,即使是判断当前棋局上的单个棋子的位置或价值也是非常困难的,与国际象棋不同。

AlphaGo 的优势在于它不是被编程来玩游戏的,而是通过使用强化学习和深度学习技术与自身进行数千场比赛而学会玩游戏的。学习能力是使机器学习,尤其是深度学习,成为解决问题的完全不同方法的原因。深度学习是关于创建可以自己学习的程序,几乎不需要人类的帮助。

但是,深度学习获得重大成功的领域的种类不仅限于游戏。Kaggle(www.kaggle.com)是一个主办许多不同机器学习竞赛的网站。这些竞赛在使用领域和应用领域上有很大的差异。2013 年,俄勒冈大学发起了一场竞赛,要求使用机器学习技术通过标准的实际音频数据录音来检测和识别鸟类。为了更好地了解鸟类种群趋势,通常需要付出昂贵的人力努力。机器学习通过仅仅通过听音频记录自动识别存在的鸟类来解决这个问题。

亚马逊最近启动了另一项竞赛,用于解决员工访问内部计算机和网络的问题,希望成功的解决方案能够减少人工监督干预带来的昂贵延迟。

2015 年,芝加哥卫生部举办了一场比赛,要求提供“根据天气、地点、检测和喷洒数据……在什么地方以及何时会检测到不同种类的蚊子携带西尼罗河病毒”的答案。

2015 年 8 月,一项竞赛要求预测西澳大利亚的租金价格,2016 年 2 月,法国巴黎银行 BNP Paribas 发起了一场竞赛,以加快其索赔管理流程。

这提供了一些用机器学习解决的问题的种类,值得注意的是,所有这些比赛都提供了最佳解决方案的奖励。2009 年,Netflix 推出了一项百万美元的竞赛,以提高其根据用户之前观看电影的排名预测用户可能喜欢的电影的准确性,而数据科学家的工作通常被排名为工资最高且最受欢迎的工作之一。

从自动驾驶汽车、军事无人机和目标侦查系统到医疗应用,例如能够读取医生笔记以发现潜在健康问题的应用以及能够提供面部识别的监控系统,机器学习在各种应用中得到了常规使用。

光学字符识别广泛应用于诸如邮局等机构,以读取信封上的地址,我们将展示如何使用 MNIST 数据集将神经网络应用于数字识别。自主无监督深度学习在自然语言处理 (NLP)方面也有许多应用和出色的成果,我们每个人几乎在自己的智能手机上都有一个应用深度学习在 NLP 上的 NLP 应用,因为苹果和安卓都使用应用于 NLP 的深度学习来作为虚拟助手(例如,Siri)。机器学习还可以应用于生物特征识别,例如识别指纹、DNA 或视网膜。此外,自动驾驶汽车在近年来取得的进展已经到达了一个现实的阶段。

机器学习也可以应用于目录中的图片或者更重要的卫星图像,根据它们是不是城市环境,是否描述了森林、冰区、水域等不同环境进行描述。

总而言之,机器学习最近在我们生活的方方面面都找到了应用,并且其准确性和性能也得到了持续改善,这也要归因于越来越好和更快的计算机。

一个受欢迎的开源包

机器学习是一个受欢迎且竞争激烈的领域,有许多开源包实现了大多数经典的机器学习算法。其中最受欢迎的是scikit-learnscikit-learn.org),这是一个广泛使用的 Python 开源库。

scikit-learn提供了实现大多数经典机器学习分类器、回归器和聚类算法的库,例如支持向量机SVM)、最近邻、随机森林、线性回归、k 均值、决策树和神经网络等许多机器学习算法。

基类sklearn有几个可用的包,取决于选择的算法类型,比如sklearn.ensemblesklearn.linear_modelsklearn.naive_bayessklearn.neural_networksklearn.svmsklearn.tree

也有一些辅助工具来进行交叉验证,以及帮助选择最佳特征。我们将不再花时间抽象地描述所有功能,而是从使用多层神经网络的一个简单示例开始。scikit-learn库使用类似签名的方法来实现每种机器学习算法,因此分类器共享相同的通用功能。此外,我们希望读者能够快速了解神经网络的功能,而无需花时间从头开始创建神经网络。下一章将讨论其他库以及更多复杂的深度学习神经网络类型的实现,但目前,用户可以快速了解它们的功能。

例如,如果想要在 scikit-learn 中使用多层神经网络,只需在程序中导入它即可:

from sklearn.neural_network.multilayer_perceptron import MLPClassifier

每个算法都需要使用预定义的参数进行调用,尽管在大多数情况下可以使用默认值。对于 MLPClassifier 来说,不需要参数,可以使用默认值(所有参数都在 scikit-learn 网站上描述,特别是对于 MLPClassifier 可以在这里找到它们:scikit-learn.org/dev/modules/generated/sklearn.neural_network.MLPClassifier.html)。

然后在训练数据上调用该算法,使用标签来调整参数,使用fit函数:

MLPClassifier().fit(data, labels)

一旦算法在训练数据上拟合好,它就可以使用predict_proba函数在测试数据上进行预测,该函数将为每个类输出概率:

probabilities = MLPClassifier().predict_proba(data)

让我们写一个完整的例子,演示如何在我们简要介绍决策树时简要讨论的iris数据集上使用MLPClassifier分类器。

Scikit-learn 使加载重要的经典数据集变得很容易。要做到这一点,我们只需要:

from sklearn import datasets
iris = datasets.load_iris() 
data = iris.data 
labels = iris.target

这将加载数据集。现在,要加载分类器,我们只需要:

from sklearn.neural_network.multilayer_perceptron import MLPClassifier

现在我们使用数据来调整参数:

mlp = MLPClassifier(random_state=1) 
mlp.fit(data, labels)

现在,由于权重是随机初始化的,random_state值只是为了强制初始化始终使用相同的随机值,以便在不同试验中获得一致的结果。这与理解过程完全无关。fit函数是调用的重要方法,它是通过使用提供的数据和标签,在受监督的方式下训练算法以找到最佳权重的方法。

现在我们可以检查我们的预测并将其与实际结果进行比较。由于函数predict_proba输出概率,而predict输出具有最高概率的类,因此我们将使用后者进行比较,并使用 sikit-learn 的一个辅助模块来给出准确度:

pred = mlp.predict(data)
from sklearn.metrics import accuracy_score 
print('Accuracy: %.2f' % accuracy_score(labels, pred))

就是这样。当然,正如我们提到的,通常最好将我们的数据分为训练数据和测试数据,并且我们还可以通过对数据进行一些正则化来改进这个简单的代码。Scikit-learn 也提供了一些辅助函数:

from sklearn.cross_validation import train_test_split 
from sklearn.preprocessing import StandardScaler
data_train, data_test, labels_train, labels_test = train_test_split(data, labels, test_size=0.5, random_state=1)  
scaler = StandardScaler() 
scaler.fit(data) 
data_train_std = scaler.transform(data_train) 
data_test_std = scaler.transform(data_test)  
data_train_std = data_train 
data_test_std = data_test

这段代码很容易理解,我们将数据拆分并对其进行归一化处理,这意味着我们减去均值并将数据缩放到单位方差。然后我们在训练数据上拟合我们的算法,然后在测试数据上进行测试:

mlp.fit(data_train, labels_train)
pred = mlp.predict(data_test)
print('Misclassified samples: %d' % (labels_test != pred).sum())
from sklearn.metrics import accuracy_score print('Accuracy: %.2f' % accuracy_score(labels_test, pred))

然后我们得到以下输出:

Misclassified samples: 3 Accuracy: 0.96

我们可以绘制一些图片来展示数据以及神经网络将空间分成三个区域以分离三种类型的花(由于我们只能绘制二维图片,我们一次只会绘制两个特征)。第一个图显示了算法如何根据花瓣的宽度和长度来分离花,而没有对数据进行归一化:

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

第二个图显示了基于花瓣宽度和花萼宽度的分离情况:

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

第三个图显示了第一个图的相同数据,在归一化数据之后:

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

最后,第四个图与第二个图相同,只是数据已归一化:

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

我们还展示了用于创建这些图形的代码。请注意,用于绘制这些图片的代码是根据 Sebastian Raschka 在他的Python 机器学习书籍中的类似代码进行调整的,该书由 Packt Publishing 出版,我们建议读者参考该书获取更多详情。

制作上述图形的代码如下。请注意,在数据之前必须设置为仅包含与两个变量相关的数据,例如对于萼片和花瓣长度,data = iris.data[:,[1,3]],因为我们只能绘制二维图像。

import numpy
from matplotlib.colors import ListedColormap 
import matplotlib.pyplot as plt
markers = ('s', '*', '^') 
colors = ('blue', 'green', 'red') 
cmap = ListedColormap(colors)   
x_min, x_max = data[:, 0].min() - 1, data[:, 0].max() + 1 
y_min, y_max = data[:, 1].min() - 1, data[:, 1].max() + 1 
resolution = 0.01  
x, y = numpy.meshgrid(numpy.arange(x_min, x_max, resolution), numpy.arange(y_min, y_max, resolution)) 
Z = mlp.predict(numpy.array([x.ravel(), y.ravel()]).T) 
Z = Z.reshape(x.shape)  
plt.pcolormesh(x, y, Z, cmap=cmap) 
plt.xlim(x.min(), x.max()) 
plt.ylim(y.min(), y.max())  
# plot the data 
classes = ["setosa", "versicolor", "verginica"] 
for index, cl in enumerate(numpy.unique(labels)):     
plt.scatter(data[labels == cl, 0], data[labels == cl, 1], c=cmap(index), marker=markers[index], s=50, label=classes[index])     
plt.xlabel('petal length') 
plt.ylabel('sepal length') 
plt.legend(loc='upper left') 
plt.show() 

如我们所述,MLPClassifier具有许多参数可供我们使用;我们仅引用激活函数和隐藏层数以及每个隐藏层可能具有的神经元数量,但所有可能参数的文档都可在 scikit-learn.org/dev/modules/generated/sklearn.neural_network.MLPClassifier.html 上找到。

隐藏层数和神经元数量可以通过添加hidden_layer_sizes=(n[1], n[2], n[3], …, n[m])来指定,其中n[i]是第i层的神经元数量。

对于一个具有分别为200100个神经元的两个隐藏层的神经网络,我们会写成:

mlp = MLPClassifier(random_state=1, hidden_layer_sizes=(200, 100,))

另一个重要的参数是激活函数,我们之前称之为活动函数。该模块支持以下三种类型的定义:

注意

ReLU 是最简单的,也是最受欢迎的之一(也是默认的激活函数),其定义简单地为 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

逻辑 函数用于计算事件的概率时使用,实际上它的值介于 0 和 1 之间,定义如下: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,tanh 简单定义为: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如,要使用分别具有 200 个和 100 个神经元的两个隐藏层,其中一个逻辑激活函数,代码将修改为:

mlp = MLPClassifier(random_state=1, hidden_layer_sizes=(200, 100,), activation = "logistic")

我们邀请读者尝试一些这些参数,并且使用max_iter参数,它将限制迭代次数。迭代次数是指对训练数据的传递次数。小值,例如max_iter=100,将不会产生很好的结果,因为算法没有时间收敛。但请注意,在这样一个小数据集上,更多的隐藏层不一定会产生更好的预测结果,反而可能会降低预测准确性。

这就结束了本章,我们向读者介绍了机器学习的重要性以及在现实世界中的许多应用。我们简要提到了一些问题和困难,并且涉及了下一章的重点——神经网络的主题。我们还介绍了如何使用标准的开源库,例如scikit-learn来开始实现一些简单的多层前馈网络。

现在我们转而深入讨论神经网络及其使用背后的动机。

总结

在本章中,我们已经介绍了什么是机器学习以及为什么它如此重要。我们提供了几个机器学习技术应用的示例,以及使用机器学习可以解决哪些问题。我们还介绍了一种特定类型的机器学习算法,称为神经网络,它是深度学习的基础,并提供了一个编码示例,在其中,使用一种流行的机器学习库,我们解决了一个特定的分类问题。在下一章中,我们将更详细地介绍神经网络,并根据从观察我们自己的大脑工作方式中得出的生物学考虑,提供它们的理论解释。

第二章:神经网络

在上一章中,我们描述了几种机器学习算法,并介绍了不同的技术来分析数据以进行预测。例如,我们建议机器可以使用房屋销售价格的数据来预测新房屋的价格。我们描述了大型公司,例如 Netflix,如何使用机器学习技术来建议用户他们可能喜欢的新电影,这是一种在电子商务中被亚马逊或沃尔玛等巨头广泛使用的技术。然而,大多数这些技术需要有标签的数据才能对新数据进行预测,并且为了提高性能,需要人类描述数据以符合有意义的特征。

人类能够快速推断出模式并推断出规则,而不需要对数据进行清理和准备。如果机器也能学会做同样的事情,那就太好了。正如我们所讨论的,弗兰克·罗森布拉特于 50 多年前的 1957 年发明了感知器。感知器对于现代深度神经网络而言就像单细胞生物对于复杂多细胞生物一样重要,但了解和熟悉人工神经元的工作原理对于更好地理解和欣赏通过在许多不同层上组合许多神经元来生成的复杂性至关重要。神经网络试图模仿人脑的功能以及通过简单观察抽象出新规则的能力。尽管我们对人类大脑如何组织和处理信息还知之甚少,但我们已经对单个人类神经元的工作原理有了很好的理解。人工神经网络试图模仿相同的功能,将化学和电信号传递交换成数值和函数。在过去的十年中取得了很大进展,神经网络变得流行之后至少两次被遗忘:这种复苏部分原因是计算机的运行速度越来越快,使用GPU图形处理单元)而不是最传统的CPU计算处理单元),更好的算法和神经网络设计,以及越来越大的数据集,正如我们将在本书中看到的。

在本章中,我们将正式介绍神经网络是什么,我们将彻底描述神经元是如何工作的,并且我们将看到如何堆叠许多层来创建和使用深度前馈神经网络。

为什么要使用神经网络?

神经网络存在很多年了,并经历了几个时期的兴衰。然而,近年来,它们一直在与许多其他竞争的机器学习算法相比稳步地取得进展。这是因为先进的神经网络架构在许多任务上显示出的准确性远远超过其他算法。例如,在图像识别领域,准确性可能是针对一个名为 ImageNet 的包含 1600 万图像的数据库进行衡量的。

在引入深度神经网络之前,准确性一直以较慢的速度改善,但在引入深度神经网络之后,准确性从 2010 年的 40%的错误率下降到 2014 年的不到 7%,而且这个数值仍在下降。人类的识别率仍然较低,约为 5%。考虑到深度神经网络的成功,2013 年 ImageNet 竞赛的所有参赛者都使用了某种形式的深度神经网络。此外,深度神经网络会“学习”数据的表示,即不仅学习识别对象,还学习识别被识别对象所具有的重要特征。通过学习自动识别特征,深度神经网络可以成功地用于无监督学习,通过自然地将具有相似特征的对象分类在一起,而无需费力地人工标记。在其他领域,例如信号处理,也取得了类似的进展。现在,深度学习和使用深度神经网络是普遍存在的,例如在苹果的 Siri 中使用。当谷歌为其 Android 操作系统引入深度学习算法时,错误识别率降低了 25%。用于图像识别的另一个数据集是 MNIST 数据集,其中包含用不同手写方式书写的数字的示例。现在,使用深度神经网络进行数字识别的准确率可以达到 99.79%,与人类的准确率相当。此外,深度神经网络算法是人工智能中最接近人脑工作方式的例子。尽管它们可能仍然是我们大脑的一个更简化、基本版本,但它们比任何其他算法更多地包含了人类智能的种子,本书的其余内容将致力于研究不同的神经网络以及提供几个不同应用神经网络的示例。

基础知识

在第一章中,我们讨论了机器学习的三种不同方法:监督学习、无监督学习和强化学习。经典神经网络是一种监督式机器学习,尽管我们将在后面看到,现代深度神经网络的普及更多地归功于这样一个事实,即现代深度神经网络也可以用于无监督学习任务。在接下来的章节中,我们将重点介绍传统浅层神经网络和深度神经网络之间的主要区别。然而,现在我们将主要集中在以监督方式工作的经典前馈网络上。我们的第一个问题是,神经网络究竟是什么?也许解释神经网络的最佳方式是将其描述为信息处理的数学模型。虽然这可能听起来相当模糊,但在接下来的章节中,它将变得更加清晰。神经网络不是一个固定的程序,而是一个模型,一个处理信息或输入的系统,在某种程度上类似于生物实体被认为处理信息的方式。我们可以确定神经网络的三个主要特征:

  • 神经网络架构:这描述了神经元之间的连接集合(前馈、循环、多层或单层等),层数以及每层中的神经元数量。

  • 学习:这描述了我们通常定义为训练的内容。无论我们使用反向传播还是某种能量级训练,它都确定了我们如何确定神经元之间的权重。

  • 活动函数:这描述了我们在传递给每个神经元的激活值上使用的函数,神经元的内部状态,以及它描述了神经元的工作方式(随机、线性等)以及在什么条件下它将激活或触发,以及它将传递给相邻神经元的输出。

但是,需要指出的是,一些研究人员会将活动函数视为架构的一部分;然而,对于初学者来说,现在将这两个方面分开可能更容易。需要注意的是,人工神经网络仅代表了生物大脑运作的近似方式。生物神经网络是一个更复杂的模型;然而,这不应该成为一个问题。人工神经网络仍然可以执行许多有用的任务,事实上,正如我们将在后面展示的那样,人工神经网络确实可以以我们希望的任何程度近似于输入到输出的任何函数。

神经网络的发展基于以下假设:

  • 信息处理以其最简单的形式发生在称为神经元的简单元素上。

  • 神经元之间相连并沿着连接链路交换信号。

  • 神经元之间的连接可以更强或更弱,这决定了信息如何被处理。

  • 每个神经元都有一个内部状态,该状态由来自其他神经元的所有传入连接确定。

  • 每个神经元都有一个不同的活动函数,该函数是根据神经元的内部状态计算的,并确定其输出信号。

在下一节中,我们将详细定义神经元的工作原理以及它与其他神经元的交互方式。

神经元和层

什么是神经元?神经元是一个处理单元,接收一个输入值,并根据预定义的规则输出一个不同的值。

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

1943 年,Warren McCullock 和 Walter Pitts 发表了一篇文章(W. S. McCulloch 和 W. Pitts. A Logical Calculus of the Ideas Immanent in Nervous Activity, The Bulletin of Mathematical Biophysics, 5(4):115–133, 1943),其中描述了单个生物神经元的功能。生物神经元的组成部分包括树突、细胞体(细胞体)、轴突和突触间隙。在不同的名称下,这些也是人工神经元的组成部分。

树突将来自其他神经元的输入传递到细胞体,即神经元的主体。细胞体是输入被处理并汇总在一起的地方。如果输入超过一定的阈值,神经元将会“发射”,并传递一个单一的输出,该输出通过轴突以电信方式发送。在传输神经元的轴突和接收神经元的树突之间存在着介导化学脉冲的突触间隙,从而改变其频率。在人工神经网络中,我们通过一个数值权重来模拟频率:频率越高,脉冲越强,因此权重越高。然后,我们可以建立生物和人工神经元之间的等价表格(这是一个非常简化的描述,但适用于我们的目的):

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

生物神经元与人工神经元的示意对应关系

因此,我们可以如下示意地描述一个人工神经元:

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

图片的中心是神经元,或称为细胞体,它接收输入(激活)并设置神经元的内部状态,从而触发输出(活动函数)。输入来自其他神经元,并且通过权重(突触间隙)的强度来调节。

神经元的简单激活值由外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传给出,其中 x[i] 是每个输入神经元的值,w[i] 是神经元 i 与输出之间连接的值。在第一章中,我们在对神经网络的介绍中引入了偏差。如果我们包含偏差并希望使其存在明确化,我们可以将上述方程重写为外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。偏差的效果是将由权重定义的超平面进行平移,使其不一定通过原点(因此得名)。我们应该将激活值解释为神经元的内部状态值。

如前一章所述,先前定义的激活值可以解释为向量w和向量x的点积。 如果*<w,x> = 0*,则向量x将与权重向量w垂直,因此所有满足*<w,x> = 0的向量xR^n 中定义一个超平面(其中 n 是x*的维数)。

因此,任何满足*<w,x> > 0的向量x都是在由w*定义的超平面的一侧的向量。 因此,神经元是线性分类器,根据此规则,在输入高于一定阈值时激活,或者在几何上,在由权重向量定义的超平面的一侧时激活输入。

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

单个神经元是线性分类器

神经网络可以具有无限数量的神经元,但无论其数量如何,在传统网络中,所有神经元都将按层次排序。 输入层代表数据集,即初始条件。 例如,如果输入是灰度图像,则输入层由每个像素的输入神经元表示,其内部值为像素的强度。 但是,应该注意,输入层中的神经元不像其他神经元那样,因为它们的输出是恒定的,等于它们的内部状态的值,因此通常不计算输入层。 因此,1 层神经网络实际上是一个仅有一个层次的简单神经网络,即输出层之外的输入层。 我们从每个输入神经元绘制一条线连接到每个输出神经元,并且这个值由人工突触间隙中介,即连接输入神经元xi 到输出神经元y[j]的权重w[i,j]。 通常,每个输出神经元代表一个类别,例如,在 MNIST 数据集的情况下,每个神经元代表一个数字。 因此,可以使用 1 层神经网络进行预测,例如,输入图像表示的是哪个数字。 实际上,输出值集合可以视为图像表示给定类别的概率的度量,因此具有最高值的输出神经元将代表神经网络的预测。

必须注意,同一层中的神经元永远不会彼此连接,如下图所示; 相反,它们都连接到下一层的每个神经元,依此类推:

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

1 层神经网络的示例:左侧的神经元代表具有偏差 b 的输入,中间列代表每个连接的权重,而右侧的神经元代表给定权重w的输出。

这是经典神经网络的必要和定义条件之一,即不存在层内连接,而神经元连接到相邻层中的每个神经元。在前面的图中,我们明确显示了神经元之间每个连接的权重,但通常连接神经元的边隐含地代表权重。1代表偏置单元,值为 1 的神经元与之前引入的偏置相等的连接权重。

如多次提到的,1 层神经网络只能对线性可分类进行分类;但是,没有任何东西可以阻止我们在输入和输出之间引入更多层。这些额外的层称为隐藏层。

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

显示的是一个具有两个隐藏层的 3 层神经网络。输入层有 k 个输入神经元,第一个隐藏层有 n 个隐藏神经元,第二个隐藏层有 m 个隐藏神经元。原则上,可以有任意多个隐藏层。在本例中,输出是两个类别,y[1]和y[2]。顶部的始终开启的偏置神经元。每个连接都有自己的权重 w(为简单起见未显示)。

不同类型的激活函数

从生物学角度来看,神经科学已经确定了数百,也许是上千种不同类型的神经元(参见大脑的未来,作者 Gary Marcus 和 Jeremy Freeman),因此我们应该能够模拟至少一些不同类型的人工神经元。这可以通过使用不同类型的活动函数来完成,即定义在神经元内部状态上的函数,表示为从所有输入神经元计算的激活值外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

活动函数是定义在*a(x)*上的函数,它定义了神经元的输出。最常用的活动函数包括:

  • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传:此函数允许激活值通过,并称为身份函数

  • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传:如果激活值高于某个特定值,则此函数激活神经元,称为阈值活动函数

  • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传:这个函数是最常用的之一,因为它的输出被限制在 0 和 1 之间,可以随机解释为神经元激活的概率,通常称为逻辑函数或逻辑 S 形函数。

  • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传:这个活动函数被称为双极 S 形函数,它简单地是一个逻辑 S 形函数重新缩放和平移,使其范围在(-1, 1)之间。

  • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传:这个活动函数被称为双曲正切函数。

  • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传:这个活动函数可能是与其生物学相似度最高的,它是标识和阈值函数的混合体,被称为整流器,或ReLU,如 Rectfied Linear Unit

这些激活函数之间的主要区别是什么?通常,不同的激活函数对不同的问题效果更好。一般来说,标识活动函数或阈值函数,在神经网络的实现初始阶段广泛使用,例如 感知器Adaline(自适应线性神经元),但最近逐渐失去了优势,转而使用 logistic sigmoid、双曲正切或 ReLU。虽然标识函数和阈值函数要简单得多,因此在计算机没有太多计算能力时是首选函数,但通常更倾向于使用非线性函数,例如 sigmoid 函数或 ReLU。还应该注意,如果我们只使用线性活动函数,那么添加额外的隐藏层就没有意义,因为线性函数的组合仍然只是一个线性函数。最后三个活动函数在以下方面有所不同:

  • 它们的范围不同。

  • 随着x的增加,它们的梯度可能会消失。

当我们增加x时,梯度可能消失的事实以及为什么这很重要,稍后会更清楚;现在,我们只需提一下,函数的梯度(例如,导数)对神经网络的训练很重要。这类似于在线性回归示例中我们在第一章介绍的,我们试图最小化函数,沿着与其导数相反方向进行。

logistic 函数的范围是(0,1),这是这个函数被选择作为随机网络的首选函数的一个原因,即具有可能根据概率函数激活的神经元的网络。双曲函数与 logistic 函数非常相似,但其范围是(-1, 1)。相比之下,ReLU 的范围是(0, 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传),因此它可能具有非常大的输出。

然而,更重要的是,让我们看一下这三个函数的导数。对于一个 logistic 函数 f,其导数是 f * (1-f),而如果 f 是双曲正切,其导数是 (1+f) * (1-f)

如果f是 ReLU,导数就简单得多,它简单地是 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提示

让我们简要地看一下如何计算 logistic sigmoid 函数的导数。通过简单地注意到,相对于a的导数 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 函数是以下形式的快速计算:

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

当我们讨论反向传播时,我们会发现深层网络的一个问题是梯度消失(如之前提到的),而 ReLU 激活函数的优势在于导数是恒定的,当a变大时不趋于0

通常,同一层中的所有神经元具有相同的激活函数,但不同的层可能具有不同的激活函数。但为什么神经网络多于 1 层深(2 层或更多)如此重要?正如我们所见,神经网络的重要性在于它们的预测能力,即能够逼近以输入为定义的函数与所需输出。存在一个定理,称为通用逼近定理,它指出在R[n]的紧致子集上的任何连续函数都可以由至少有一个隐藏层的神经网络逼近。虽然该定理的正式证明过于复杂无法在此进行解释,但我们将尝试仅使用一些基本数学给出直观的解释,并且对此我们会使用逻辑 sigmoid 作为我们的激活函数。

逻辑 sigmoid 被定义为 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 其中 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。现在假设我们只有一个神经元 x=x[i]:

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

左侧是一个标准 sigmoid,权重为 1,偏差为 0。中间是一个权重为 10 的 sigmoid,右侧是一个权重为 10 且偏差为 50 的 sigmoid。

然后很容易证明,如果w非常大,逻辑函数会接近一个阶梯函数。w越大,它就越像一个高度为 1 的 0 阶梯函数。另一方面,b只会平移函数,并且平移将等于比值b/w的负数。让我们称t = -b/w

有了这个基础知识,现在让我们考虑一个简单的神经网络,其中有一个输入神经元和一个具有两个神经元的隐藏层,输出层只有一个输出神经元:

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

X 被映射到两个带有权重和偏差的隐藏神经元上,使得顶部隐藏神经元的比值 –b/wt[1] 而底部隐藏神经元是 t[2]。两个隐藏神经元都使用逻辑 sigmoid 激活函数。

输入 x 映射到两个神经元,一个具有权重和偏差,使得比例为t[1],另一个具有比例为t**[2]的权重和偏差。然后这两个隐藏神经元可以映射到输出神经元,其权重分别为w和*–w*。如果对每个隐藏神经元应用逻辑 S 形活动函数,并对输出神经元应用恒等函数(没有偏差),我们将获得一个步函数,从t[1]到t[2],高度为w,就像下图中所示的一样。由于类似图中的一系列步函数可以近似于R的紧致子集上的任何连续函数,这为什么普适逼近定理成立提供了直观(这是一个数学定理称为“简单函数逼近定理”的简化版本)。

多做一点努力,就可以推广到R[n]。

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

生成上述图像的代码如下:

#The user can modify the values of the weight w 
#as well as biasValue1 and biasValue2 to observe
#how this plots to different step functions

import numpy 
import matplotlib.pyplot as plt
weightValue = 1000
#to be modified to change where the step function starts
biasValue1 = 5000 
#to be modified to change where the step function ends 
biasValue2 = -5000

plt.axis([-10, 10, -1, 10])  

print ("The step function starts at {0} and ends at {1}"
        .format(-biasValue1/weightValue, 
        -biasValue2/weightValue))  

y1 = 1.0/(1.0 + numpy.exp(-weightValue*x - biasValue1)) 
y2 = 1.0/(1.0 + numpy.exp(-weightValue*x - biasValue2)) 
#to be modified to change the height of the step function 
w = 7 
y = y1*w-y2*w  
plt.plot(x, y, lw=2, color='black') 
plt.show()

反向传播算法

我们已经看到了神经网络是如何将输入映射到确定的输出,取决于固定的权重。一旦神经网络的架构被定义(前馈,隐藏层数量,每层神经元数量),以及一旦为每个神经元选择了活动函数,我们需要设置权重,这将定义网络中每个神经元的内部状态。我们将看到如何为 1 层网络设置这些权重,然后如何将其扩展到深度前馈网络。对于深度神经网络,用于设置权重的算法称为反向传播算法,我们将在本节中讨论和解释这个算法,因为这是多层前馈神经网络中最重要的主题之一。然而,我们将首先快速讨论一层神经网络的情况。

我们需要理解的一般概念是:每个神经网络都是函数的近似,因此每个神经网络都不等于期望的函数,而是会有一些差异。这个差异被称为误差,目标是最小化这个误差。由于误差是神经网络中的权重的函数,我们希望在权重方面最小化误差。误差函数是许多权重的函数;因此它是许多变量的函数。数学上,此函数为零的点集因此代表一个超曲面,为了在这个超曲面上找到最小值,我们需要选择一个点,然后沿着最小值方向跟随一条曲线。

线性回归

我们已经在第一章介绍了线性回归,但由于我们现在处理的是许多变量,为了简化事情,我们将引入矩阵表示法。让x是输入;我们可以将x视为一个向量。在线性回归的情况下,我们将考虑一个单输出神经元y;因此,权重w的集合是一个与x的维度相同的向量。然后,激活值被定义为内积*<x, w>*。

让我们假设对于每个输入值x,我们想要输出一个目标值t,而对于每个x,神经网络将输出一个值y,由选择的激活函数定义,在这种情况下,绝对值差异(y-t)表示预测值和特定输入示例x的实际值之间的差异。如果我们有m个输入值x[i],每个值都将有一个目标值t[i]。在这种情况下,我们使用均方误差计算误差外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,其中每个y[i]是w的函数。因此,误差是w的函数,并且通常用*J(w)*表示。

如前所述,这表示了与w的维度相等的超曲面(我们隐式地也考虑了偏差),对于每个w[j],我们需要找到一个曲线,该曲线将导致表面的最小值。曲线沿特定方向增加的方向由其对该方向的导数给出,在这种情况下由以下公式给出:

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

为了朝着最小值移动,我们需要按照外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传设置的相反方向移动每个w[j]。

让我们计算以下:

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

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

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

提示

符号有时可能令人困惑,特别是第一次看到它时。输入由向量x^i 给出,其中上标表示第 i 个示例。由于xw是向量,下标表示向量的j^th 坐标。y^i 然后表示给定输入x^i 的神经网络输出,而t^i 表示目标值,即与输入x[i]对应的期望值。

为了朝向最小值移动,我们需要将每个权重按其导数方向移动一小步长 l,称为学习速率,通常远小于 1,(例如 0.1 或更小)。因此,我们可以重新定义导数并将“2”合并到学习率中,以获得以下给出的更新规则:

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

或者,更一般地,我们可以将更新规则写成矩阵形式如下:

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

在这里,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(也称为 nabla)代表偏导数的向量。这个过程通常被称为梯度下降。

提示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传是偏导数的向量。我们可以将对w的更新规则分别写为每个其分量wj,也可以用矩阵形式写出更新规则,其中,用外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传代替为每个j写出偏导数。

最后一点;更新可以在计算所有输入向量后进行,但在某些情况下,权重可以在每个示例之后或在一定预设数量的示例后进行更新。

逻辑回归

在逻辑回归中,输出不是连续的;相反,它被定义为一组类。在这种情况下,激活函数不会像之前那样是恒等函数,而是我们将使用逻辑 sigmoid 函数。正如我们之前看到的,逻辑 sigmoid 函数输出(0,1)中的实值,因此它可以被解释为概率函数,这也是为什么在 2 类分类问题中它可以运行得很好的原因。在这种情况下,目标可以是两个类别中的一个,而输出表示它是其中两个类别之一(比如t=1)的概率。

提示

再次,符号可能令人困惑。t是我们的目标,它可以在这个例子中有两个值。这两个值通常被定义为类别 0 和类别 1。这些值 0 和 1 不应与逻辑 sigmoid 函数的值混淆,后者是介于 0 和 1 之间的连续实值函数。sigmoid 函数的实际值表示输出属于类别 0 或类别 1 的概率。

如果a是之前定义的神经元激活值,让我们用 s(a)表示逻辑 sigmoid 函数,因此,对于每个示例 x,给定权重w时输出为类别y的概率是:

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

我们可以更简洁地将方程写为如下形式:

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

由于对每个样本x^i,概率P(t[i]|x[i]*, w)*是独立的,全局概率如下:

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

如果我们取前述方程的自然对数(将乘积变为和),我们得到如下结果:

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

目标现在是最大化这个对数以获得预测正确结果的最高概率。通常,这是通过使用梯度下降最小化由J(w)= -log(P(y¦ x *,w))定义的损失函数J(w)*来实现的,就像前面的情况一样。

与以前一样,我们计算相对于权重w[j]的损失函数的导数,得到:

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

提示

要理解最后一个等式,让我们提醒读者以下事实:

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

因此,根据链式法则:

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

同样:

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

通常,在多类输出t的情况下,其中t是一个向量(t[1],*…, t[n]),我们可以使用外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 = 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传来推导出权重的更新方程:

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

这类似于我们对线性回归所看到的更新规则。

反向传播

在单层情况下,权重调整很容易,因为我们可以使用线性或逻辑回归,并同时调整权重以获得更小的错误(最小化成本函数)。对于多层神经网络,我们可以对连接最后隐藏层与输出层的权重使用类似的论证,因为我们知道输出层的期望值,但我们无法对隐藏层做同样的操作,因为预先我们并不知道隐藏层神经元的值应该是什么。相反,我们计算最后一个隐藏层的误差,并估计前一层的误差,从最后一层向第一层反向传播误差,因此得名反向传播。

反向传播是最难理解的算法之一,但所需的只是对基本微分和链式法则的一些知识。首先让我们引入一些符号。我们用J表示成本(误差)y表示被定义为在激活值a上的活动函数(例如,y 可以是逻辑 Sigmoid),它是权重w和输入x的函数。让我们也定义w[i,j],i^(th)输入值和jth 输出之间的权重。在这里,我们比对 1 层网络更泛化地定义输入和输出:如果w[i,j]连接一个前馈网络中的连续两层,我们将"输入"称为第一层包含的神经元,"输出"称为第二层包含的神经元。为了不使符号过于繁重,并且不必指出每个神经元在哪一层,我们假设第i个输入y[i]始终在包含第j^(th)输出 y[j]的层之前的那一层。

提示

请注意,字母y既用于表示输入,也用于表示活动函数的输出。 y[j]是下一层的输入,而 y[j]是活动函数的输出,但它也是下一层的输入。因此,我们可以将 y[j]'s 视为 y[j]'s 的函数。

我们还使用下标ij,其中我们始终将带有下标i的元素归属于包含下标j的元素的层之前的那一层。

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

图 10

在这个例子中,第 1 层表示输入,第 2 层表示输出,所以 w[i,j] 是连接一层中的 y[j] 值和下一层中的 y[j] 值的数值。

使用这个符号表示法和导数的链式法则,我们可以为我们神经网络的最后一层写出以下结果:

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

既然我们知道 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,我们有以下结果:

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

如果 y 是之前定义的逻辑 S 型函数,我们将得到与前一节末尾已经计算过的相同结果,因为我们知道成本函数,我们可以计算所有的导数。

对于前面的层,相同的公式成立:

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

实际上,a j 是活动函数,我们知道,这是权重的一个函数。y[j] 值,是“第二”层神经元的活动函数,是其激活值的函数,当然,成本函数是我们选择的活动函数的函数。

提示

即使我们有几个层,我们总是集中在连续层对中,因此,或许有点滥用符号,我们总是有一个“第一”层和一个“第二”层,就像图 10 中的那样,它是“输入”层和“输出”层。

既然我们知道 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,并且我们知道 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 是我们可以计算的活动函数的导数,我们只需要计算导数 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。让我们注意到,这是相对于“第二”层的激活函数的误差的导数,如果我们可以计算出最后一层的这个导数,并且有一个允许我们计算下一层的导数的公式,我们可以从最后一层开始计算所有导数并向后移动。

让我们注意到,正如我们通过 y[j] 定义的那样,它们是“第二”层神经元的激活值,但它们也是活动函数,因此是第一层激活值的函数。因此,应用链式法则,我们有以下结果:

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

再次,我们可以计算 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,因此一旦我们知道 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,我们可以计算 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,由于我们可以计算出最后一层的 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,我们可以向后移动并计算任何一层的 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,因此可以计算出任何一层的 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结一下,如果我们有一系列层,其中

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

然后我们有了这两个基本方程,第二个方程中的求和应该是对从y j到任何神经元外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传的传出连接的总和。

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

通过使用这两个方程,我们可以计算对每层成本的导数。

如果我们设置外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传表示成本对激活值的变化,我们可以将外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传看作是y[j]神经元的误差。我们可以重写

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

这意味着外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。这两个方程给出了看待反向传播的另一种方式,即成本对激活值的变化,并提供了一种计算这种变化的公式,以便我们知道了如何为以下层的任何层计算这种变化:

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

我们还可以组合这些方程并证明:

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

更新权重的反向传播算法然后在每一层上给出

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

在最后一节,我们将提供一个代码示例,以帮助理解和应用这些概念和公式。

工业应用

在上一章中,我们提到了一些机器学习应用的例子。神经网络,特别是具有相似应用的神经网络。我们将回顾一些应用程序,它们在 1980 年代末和 1990 年代初变得流行之后使用了这些应用程序,后者发现了反向传播,并且可以训练更深的神经网络。

信号处理

在信号处理领域,神经网络有许多应用。神经网络最早的应用之一是抑制电话线上的回声,特别是在 1957 年由伯纳德·威德罗和马西安·霍夫开发,特别是在洲际电话中。Adaline 使用恒等函数作为其训练的激活函数,并寻求最小化激活和目标值之间的均方误差。Adaline 经过训练,通过将输入信号应用于* Adaline (滤波器)和电话线来消除电话线上的回声。电话线输出和 Adaline *输出之间的差异是误差,用于训练网络并从信号中消除噪声(回声)。

医疗

该网络是由安德森于 1986 年开发的,其背后的思想是存储有关每种情况的症状、诊断和治疗信息的大量医疗记录。该网络经过训练,可以对不同症状的最佳诊断和治疗进行预测。

最近,IBM 利用深度神经网络开发了一个神经网络,可以预测可能的心脏衰竭,阅读医生的笔记,类似于经验丰富的心脏病专家。

自动驾驶汽车

1989 年,Nguyen 和 Widrow,以及 1990 年,Miller、Sutton 和 Werbos 开发了一个可以为大型拖车提供倒车到装货码头的方向指示的神经网络。神经网络由两个模块组成:第一个模块能够使用多层的神经网络计算新的位置,通过学习卡车对不同信号的反应。这个神经网络称为仿真器。第二个模块称为控制器,通过使用仿真器来了解其位置,学习给出正确的指令。近年来,自动驾驶汽车已经取得了巨大进步,并且已经成为现实,尽管更复杂的深度学习神经网络与来自摄像头、GPS、激光雷达和声纳单元的输入一起使用。

商业

1988 年,Collins、Ghosh 和 Scofield 开发了一个神经网络,可以用来评估是否应该批准和发放抵押贷款。利用抵押贷款评估员的数据,神经网络被训练来确定是否应该给予申请人贷款。输入是一些特征,如申请人的就业年限、收入水平、受抚养人数、财产的评估价值等等。

模式识别

我们已经多次讨论了这个问题。神经网络已经被应用的一个领域是字符识别。比如,这可以用于数字的识别,也可以用于手写邮政编码的识别。

语音产生

1986 年,Sejnowski 和 Rosenberg 提出了广为人知的 NETtalk 示例,通过阅读书面文字来产生口语。NETtalk 的要求是一组书面文字及其发音的示例。输入包括要发音的字母以及它前面和后面的字母(通常是三个),训练是使用最常见的单词及其语音转录进行的。在实现中,该网络首先学习识别元音和辅音,然后学习识别单词的开头和结尾。通常需要多次迭代才能使发音变得清晰,其进展有时类似于孩子学习如何发音单词。

一个用于 xor 函数的神经网络的代码示例

这是一个众所周知的事实,也是我们已经提到过的,即单层神经网络无法预测 XOR 函数。单层神经网络只能对线性可分集进行分类,然而,正如我们所见,通用逼近定理指出,一个具有足够复杂架构的 2 层网络可以近似任何函数。我们现在将创建一个隐藏层中具有两个神经元的神经网络,并演示如何模拟 XOR 函数。但是,我们将编写代码,让读者可以简单地修改它以允许任意数量的层和每层的神经元,以便读者可以尝试模拟不同的情景。我们还将使用双曲正切函数作为此网络的活动函数。为了训练网络,我们将实现之前讨论过的反向传播算法。

我们只需要导入一个库,numpy,尽管如果读者希望可视化结果,我们还建议导入matplotlib。因此,代码的前几行是:

import numpy 
from matplotlib.colors import ListedColormap 
import matplotlib.pyplot as plt 

接下来我们定义我们的活动函数及其导数(在本示例中我们使用tanh(x)):

def tanh(x):     
    return (1.0 - numpy.exp(-2*x))/(1.0 + numpy.exp(-2*x))

def tanh_derivative(x):     
    return (1 + tanh(x))*(1 - tanh(x))

接下来我们定义NeuralNetwork类:

class NeuralNetwork:

为了遵循 Python 语法,NeuralNetwork类中的任何内容都必须缩进。我们定义了NeuralNetwork类的“构造函数”,即其变量,这在本例中将是神经网络的架构,即有多少层以及每层有多少个神经元,并且我们还将随机初始化权重为介于负 1 和正 1 之间。net_arch将是一个包含每层神经元数量的一维数组:例如[2,4,1]表示具有两个神经元的输入层,具有四个神经元的隐藏层和具有一个神经元的输出层。

由于我们正在研究 XOR 函数,因此对于输入层,我们需要有两个神经元,对于输出层,只需要一个神经元:

    #net_arch consists of a list of integers, indicating 
    #the number of neurons in each layer, i.e. the network 
    #architecture
    def __init__(self, net_arch): 
        self.activity = tanh
        self.activity_derivative = tanh_derivative 
        self.layers = len(net_arch)         
        self.steps_per_epoch = 1000   
        self.arch = net_arch

        self.weights = []         
        #range of weight values (-1,1)         
        for layer in range(self.layers - 1):             
            w = 2*numpy.random.rand(net_arch[layer] + 1, net_arch[layer+1]) - 1
            self.weights.append(w)

在此代码中,我们已定义活动函数为双曲正切函数,并定义了其导数。我们还定义了每个时期应有多少个训练步骤。最后,我们初始化了权重,确保我们也初始化了稍后将添加的偏置的权重。接下来,我们需要定义fit函数,这个函数将训练我们的网络。在最后一行中,nn代表NeuralNetwork类,predict是我们稍后将定义的NeuralNetwork类中的函数:

    #data is the set of all possible pairs of booleans
    #True or False indicated by the integers 1 or 0 
    #labels is the result of the logical operation 'xor' 
    #on each of those input pairs
    def fit(self, data, labels, learning_rate=0.1, epochs=100):
        #Add bias units to the input layer         
        ones = numpy.ones((1, data.shape[0]))        
        Z = numpy.concatenate((ones.T, data), axis=1)
        training = epochs*self.steps_per_epoch
        for k in range(training):             
            if k % self.steps_per_epoch == 0:                  
                print('epochs: {}'.format(k/self.steps_per_epoch))
                for s in data:                     
                    print(s, nn.predict(s))

我们在这里所做的一切只是在输入数据中添加了一个“1”(始终开启的偏置神经元),并设置了代码以在每个时期结束时打印结果,以便跟踪我们的进度。我们现在将继续设置我们的前向传播:

               sample = numpy.random.randint(data.shape[0])
               y = [Z[sample]]
               for i in range(len(self.weights)-1):
                   activation = numpy.dot(y[i], self.weights[i])
                   activity = self.activity(activation)
                   #add the bias for the next layer
                   activity = numpy.concatenate((numpy.ones(1), 
                              numpy.array(activity)))
                   y.append(activity)

               #last layer 
               activation = numpy.dot(y[-1], self.weights[-1])
               activity = self.activity(activation)
               y.append(activity)

我们将在每个步骤后更新我们的权重,因此我们随机选择其中一个输入数据点,然后设置前向传播,为每个神经元设置激活,然后在激活值上应用tanh(x)。由于我们有一个偏差,我们将偏差添加到我们的矩阵 y 中,该矩阵跟踪每个神经元的输出值。

现在我们进行错误的反向传播以调整权重:

               #error for the output layer
               error = labels[sample] - y[-1]
               delta_vec = [error * self.activity_derivative(y[-1])] 
               #we need to begin from the back, 
               #from the next to last layer
               for i in range(self.layers-2, 0, -1):  
                   error = delta_vec[-1].dot(self.weights[i][1:].T) 
                   error = error*self.activity_derivative(y[i][1:])
                   delta_vec.append(error)
               #Now we need to set the values from back to front
               delta_vec.reverse()

               #Finally, we adjust the weights, 
               #using the backpropagation rules
               for i in range(len(self.weights)):
                   layer = y[i].reshape(1, nn.arch[i]+1)
                   delta = delta_vec[i].reshape(1, nn.arch[i+1])
                   self.weights[i] +=learning_rate*layer.T.dot(delta)

这结束了我们的反向传播算法;我们所要做的只是编写一个预测函数来检查结果:

    def predict(self, x):          
        val = numpy.concatenate((numpy.ones(1).T, numpy.array(x)))      
        for i in range(0, len(self.weights)):             
            val = self.activity(numpy.dot(val, self.weights[i]))             
            val = numpy.concatenate((numpy.ones(1).T, 
                                     numpy.array(val)))         
        return val[1]

在这一点上,我们只需要按照下面的主函数进行编写:

    if __name__ == '__main__':  
    numpy.random.seed(0)
    #Initialize the NeuralNetwork with 
    #2 input neurons
    #2 hidden neurons
    #1 output neuron    
    nn = NeuralNetwork([2,2,1])      
    X = numpy.array([[0, 0],
                    [0, 1],
                    [1, 0],
                    [1, 1]])

    #Set the labels, the correct results for the xor operation    
    y = numpy.array([0, 1, 1, 0])      

    #Call the fit function and train the network 
    #for a chosen number of epochs
    nn.fit(X, y, epochs=10)

    print "Final prediction"     
    for s in X:         
       print(s, nn.predict(s))

注意numpy.random.seed(0)的用法。这只是为了确保权重初始化在不同运行中的一致性,以便比较结果,但对于神经网络的实现并不是必需的。

这结束了代码,结果应该是一个四维数组,例如:(0.003032173692499,0.9963860761357,0.9959034563937,0.0006386449217567),表明神经网络学会了输出应该是(0,1,1,0)。

读者可以略微修改我们之前在本书中使用的plot_decision_regions function中创建的代码,看看不同的神经网络如何根据所选择的架构区分不同的区域。

输出图片将如下图所示。圆代表(TrueTrue)和(FalseFalse)的输入,而三角形代表(TrueFalse)和(FalseTrue)的输入对于 XOR 函数。

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

同一图,左边是缩小的,右边是放大选择的输入。神经网络学会了分离这些点,创建了一个含有两个True输出值的带状区域。

不同的神经网络架构(例如,实现具有不同隐藏层中神经元数量的网络,或者具有不止一个隐藏层)可能产生不同的分离区域。为了实现这一点,读者只需要改变代码中的一行nn = NeuralNetwork([2,2,1]).。第一个2必须保留(输入不变),但可以修改第二个2以表示不同隐藏层中的神经元数量。添加另一个整数将添加一个带有所添加的整数指示的神经元数的新的隐藏层。最后的1不能修改。例如,([2,4,3,1])将表示一个 3 层神经网络,第一个隐藏层中有四个神经元,第二隐藏层中有三个神经元。

然后读者会发现,虽然解决方案是一样的,但是根据所选择的架构,分离区域的曲线会有所不同。实际上,选择nn = NeuralNetwork([2,4,3,1])将给出以下图形:

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

例如,选择nn = NeuralNetwork([2,4,1])会产生以下结果:

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

因此,神经网络的架构定义了神经网络解决手头问题的方式,不同的架构提供了不同的方法(尽管它们可能都会产生相同的结果),类似于人类思维过程可以沿着不同的路径达到相同的结论。我们现在准备更仔细地研究深度神经网络及其应用。

摘要

在本章中,我们详细介绍了神经网络,并提到了它们在与其他竞争算法相比的成功。神经网络由它们所属的“单元”或神经元,以及属于它们的连接或权重组成,这些权重表征了不同神经元之间通信的强度以及它们的活动函数,即神经元如何处理信息。我们讨论了如何创建不同的架构,以及神经网络如何可以具有许多层,以及为什么内部(隐藏)层很重要。我们解释了信息如何通过基于权重和定义的活动函数从输入流向输出,最后我们展示了如何定义一种称为反向传播的方法来“调整”权重以提高所需的准确性。我们还提到了许多神经网络被应用的领域。

在下一章中,我们将继续讨论深度神经网络,特别是我们将解释“深度”一词的含义,就像深度学习一样,我们将解释它不仅仅是指网络中隐藏层的数量,更重要的是指神经网络学习的质量。为此,我们将展示神经网络如何学习识别特征并将它们组合成识别对象的表示,这将为使用神经网络进行无监督学习打开大门。我们还将描述几个重要的深度学习库,最后,我们将提供一个具体的例子,说明我们如何应用神经网络进行数字识别。

第三章:深度学习基础

在第一章机器学习-简介中,我们介绍了机器学习及其一些应用,并简要讨论了一些可用于实现机器学习的算法和技术。在第二章神经网络中,我们专注于神经网络;我们已经表明 1 层网络太简单,只能处理线性问题,而且我们介绍了通用逼近定理,展示了只有一个隐层的 2 层神经网络能以任意程度逼近 R*[n]*的紧致子集上的任何连续函数。

在本章中,我们将介绍深度学习和深度神经网络,也就是至少有两个或更多个隐层的神经网络。读者可能会想知道为什么要使用多个隐层,考虑到通用逼近定理,并无不合理之处,因为在很长一段时间内使用的神经网络非常浅,只有一个隐层。答案是 2 层神经网络确实可以以任意程度逼近任何连续函数,然而,增加层次也增加了可能更加难以模拟的复杂性,并且可能需要更多的神经元来模拟浅层网络。还有另一个更重要的原因是深度学习的术语“深度”并不仅仅指网络的深度或神经网络的层数,而是指“学习”的水平。在深度学习中,神经网络不仅仅是学习在给定输入X的情况下预测输出Y,而且还能理解输入的基本特征。在深度学习中,神经网络能够对构成输入示例的特征进行抽象化,理解示例的基本特征,并根据这些特征进行预测。在深度学习中,存在其他基本机器学习算法或浅层神经网络中缺乏的抽象层面。

在本章中,我们将涵盖以下主题:

  • 什么是深度学习?

  • 深度学习的基本概念

  • 深度学习的应用

  • GPU 与 CPU 对比

  • 流行的开源库

什么是深度学习?

2012 年,Alex Krizhevsky,Ilya Sutskever 和 Geoff Hinton 在《神经信息处理系统》(NIPS)(2012)的《ImageNet 分类与深度卷积神经网络》一文中,写道:

“值得注意的是,如果移除一个卷积层,我们网络的性能会下降。例如,移除任何一个中间层都会导致网络的 top-1 性能损失约为 2%。所以深度确实对于实现我们的结果至关重要。”

在这个重要的论文中,他们明确提到了深度网络中隐藏层的数量的重要性。Krizheysky、Sutskever 和 Hilton 谈到了卷积层,我们将在第五章,图像识别中讨论它们,但基本问题仍然存在:这些隐藏层到底做什么?

一个典型的英语谚语是一张图片胜过千言万语。让我们使用这种方法来理解深度学习是什么。在 H. Lee、R. Grosse、R. Ranganath 和 A. Ng,用于可扩展无监督学习分层表示的卷积深度置信网络,发表于 2009 年国际机器学习会议(ICML)的论文中(参见web.eecs.umich.edu/~honglak/icml09-ConvolutionalDeepBeliefNetworks.pdf),作者使用了一些图片,我们在这里复制了一些。

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

在他们的例子中,他们展示了不同类别的对象和/或动物的神经网络图片,并且网络学习了每个类别的一些基本特征。例如,网络可以学习一些非常基本的形状,如线条或边缘,这些是每个类别都共有的。然而,在下一层,网络可以学习这些线条和边缘如何组合在一起,以使每个类别的图像具有眼睛或车轮等特征。这类似于人类视觉皮层的工作方式,我们的大脑从简单的线条和边缘开始越来越复杂地识别特征。

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

深度神经网络中的隐藏层也是通过逐层理解更加复杂的特征来工作的。如果我们想要定义什么是一个人脸,我们需要定义它的部分:眼睛、鼻子、嘴巴,然后我们需要上升到更高的层次,并定义它们相对于彼此的位置:两只眼睛在顶部的中间位置,处于同样的高度,鼻子在中间,嘴巴在下方中间位置,位于鼻子下方。深度神经网络通过自我学习来捕捉这些特征,首先学习图像的组成部分,然后学习它们的相对位置等等,就像在图像 1 和图像 2 中,我们可以看到深层抽象在每一层中的作用。一些深度学习网络实际上可以被看作是生成算法,例如受限玻尔兹曼机RBMs),而不仅仅是一个预测算法,因为它们学会生成一个信号,然后根据已学习的生成假设进行预测。随着我们在本章中逐步深入,我们将使这个概念更加清晰。

基本概念

1801 年,约瑟夫·玛丽·查尔斯发明了雅卡尔织布机。查尔斯(Charles)并非科学家,而是一个简简单单的商人,雅卡尔织布机以他的名字命名。雅卡尔织布机使用一组打孔卡片,每个打孔卡片代表了需要在织布机上复制的图案。每个打孔卡片都代表了一个设计的抽象,一个图案的抽象,每个打孔卡片都是该图案的一个抽象表示。打孔卡片之后被用在其他地方,例如赫尔曼·荷里歇在 1890 年发明的制表机中,或者在最早的计算机中,它们被用来输入机器的代码。然而,在制表机中,打孔卡片只是对样本的抽象,用于计算人口的统计数据。而在雅卡尔织布机中,打孔卡片的使用更加微妙;在其中,每个卡片都代表一个图案的抽象,然后与其他卡片组合在一起,形成更复杂的图案。打孔卡片是对现实特征的一个抽象表示,最终成为织物的设计。

在某种程度上,Jacquard 织机具有使得深度学习成为今天的样子的种子:通过其特征的表示来定义现实。在深度学习中,神经网络不仅仅是识别使猫成为猫,松鼠成为松鼠的因素,而是了解猫中存在哪些特征,松鼠中存在哪些特征,并且学会使用这些特征设计猫或松鼠。如果我们要使用 Jacquard 织机设计成猫形状的编织图案,我们需要使用带有猫鼻子上胡子的打孔卡,以及优雅修长的身体。相反,如果我们要设计松鼠,我们需要使用制作毛茸茸尾巴的打孔卡,例如。一个学会基本输出表示的深度网络可以使用它所做出的假设进行分类;因此,如果没有毛茸茸的尾巴,它可能不会是松鼠,而更可能是猫。这有许多含义,正如我们将看到的那样,最重要的是,网络学到的信息量更加完整和稳健。通过学习生成模型(在技术术语中通过学习联合概率p(x,y)而不仅仅是p(y|x),网络对噪声的敏感性大大降低,并且它学会了识别即使场景中存在其他物体或物体部分被遮挡的图像。最激动人心的部分是,深度神经网络自动学会做到这一点。

特征学习

Ising 模型是物理学家威廉·伦兹在 1920 年发明的,他把它作为问题交给了他的学生恩斯特·伊辛。该模型由可以处于两种状态(正或负)的离散变量组成,代表磁偶极子。

在第四章《无监督特征学习》中,我们将介绍限制玻尔兹曼机和自动编码器,并且我们将开始更深入地了解如何构建多层神经网络。迄今为止我们看到的神经网络类型都具有前馈架构,但我们将看到我们可以定义具有反馈环路的网络以帮助调整定义神经网络的权重。虽然 Ising 模型并不直接用于深度学习,但它是一个很好的物理示例,帮助我们理解调整深度神经结构的基本内部工作方式,包括限制玻尔兹曼机,特别是帮助我们理解表示的概念。

这一节我们将讨论的是对 Ising 模型进行的简单调整(和简化),以适应深度学习。在第二章 神经网络中,我们已经讨论了调整神经元之间连接权重的重要性。实际上,神经网络中的权重使网络学习。给定一个输入(固定),这个输入传播到下一层,并根据它们之间连接的权重设置下一层神经元的内部状态。然后,这些神经元会发射信号,并通过新的连接将信息传递到下一层,这些连接由新的权重定义,依此类推。权重是网络的唯一变量,它们使网络学习。通常情况下,如果我们的激活函数是一个简单的阈值函数,一个较大的正权重会倾向于使两个神经元一起激活。所谓一起激活,我们指的是,如果一个神经元激活,且连接权重很高,则另一个神经元也会激活(因为输入乘以较大的连接权重很可能会超过选择的阈值)。事实上,1949 年,在他的行为的组织中,唐纳德·赫布(s-f-walker.org.uk/pubsebooks/pdfs/The_Organization_of_Behavior-Donald_O._Hebb.pdf)提出了相反的观点也是真的。唐纳德·赫布是一位加拿大心理学家,生活在 20 世纪,他提出了以他的名字命名的规则,赫布规则,该规则指出当神经元一起激活时,它们的连接加强;当它们不一起激活时,它们的连接减弱。

在下面的示例中,我们将 Ising 模型看作是一种以二进制方式运作的神经元网络,即它们只能激活(发射)或不激活,并且,它们的相对连接越强,它们一起激活的可能性就越大。我们假设网络是随机的,因此如果两个神经元之间连接很强,它们只有很大的可能性一起激活。

小贴士

随机意味着概率性。在随机网络中,我们定义神经元激活的概率:概率越高,神经元激活的可能性就越大。当两个神经元之间的连接很强时,即它们之间连接的权重很大时,一个神经元激活将引起另一个神经元也激活的概率非常高(反之亦然,弱连接会导致低概率)。然而,神经元只会根据概率激活,因此我们无法确定它是否会激活。

另一方面,如果它们呈反相关(具有较大的负权重),它们非常可能不会一起激活。让我们举些例子:

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

在第一张图中,前两个神经元处于活跃状态,并且它们与第三个神经元的连接很大且为正,因此第三个神经元也将处于活跃状态。在第二张图中,前两个神经元处于关闭状态,并且它们与第三个神经元的连接为正,因此第三个神经元也将处于关闭状态。

在第二张图中,前两个神经元处于关闭状态,并且它们与第三个神经元的连接为正,因此第三个神经元也将处于关闭状态。

可能会出现几种组合;我们将只展示其中几种。想法是第一层神经元的状态将以概率方式确定后续层神经元的状态,取决于连接的符号和强度。如果连接较弱,则后续层中连接的神经元可能以任何状态相等或几乎相等的概率存在。但如果连接非常强,则权重的符号将使连接的神经元以类似或相反的方式运作。当然,如果第二层的神经元具有超过一个神经元作为其输入,我们将像往常一样加权所有输入连接。如果输入神经元并非全部处于开启或关闭状态,并且它们的连接同样强,则连接的神经元可能以相等或几乎相等的概率处于开启或关闭状态。

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

在第一张图中,前两个神经元处于活跃状态,并且它们与第三个神经元的连接很大且为负,因此第三个神经元也将处于关闭状态。在第二张图中,前两个神经元处于关闭状态,并且它们与第三个神经元的连接很大且为负,因此第三个神经元很可能处于打开状态。

接下来很明显,要最有可能地确定下一层神经元的状态,第一层神经元应该都处于相似的状态(开或关)并且都与强连接(即,较大的权重)连接。让我们看更多的例子:

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

在第一张图中,前两个神经元处于活跃状态,并且它们与第三个神经元的连接很大但方向相反,因此第三个神经元可能同样有可能处于开启或关闭状态。在第二张图中,前两个神经元一个处于开启状态,一个处于关闭状态,并且它们与第三个神经元的连接都很大且为正,因此第三个神经元同样有可能处于开启或关闭状态。在最后一张图中,前两个神经元处于活跃状态,但它们与第三个神经元的连接很小,因此第三个神经元更有可能处于开启状态,但它也有相当高的几率处于关闭状态。

引入这种 Ising 模型的改编的目的是理解深度神经网络中的表示学习是如何工作的。我们已经看到,设置正确的权重可以使神经网络打开或关闭某些神经元,或者一般地影响它们的输出。然而,将神经元描绘成只有两种状态,有助于我们直观地理解神经网络中发生的事情。在二维平面中表示我们的网络层对我们的直观和视觉描述也有所帮助,而不是表示为一维层。让我们把我们的神经网络层想象成二维平面。然后我们可以想象每个神经元代表了二维图像上的像素,而“开”状态的神经元代表了白色平面上的黑点,而“关”状态的神经元则与白色背景融为一体(不可见)。我们的开/关状态的输入层可以被看作一个简单的二维黑白图像。比如,假设我们想要表示一个笑脸,或者一个悲伤的脸——我们只需激活正确的神经元,就可以得到以下图形:

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

一个快乐的脸和一个悲伤的脸:区别在于嘴角的几个神经元,可能是开或关状态。

现在假设这对应于输入层,因此此层将连接到另一层,即隐藏层之一。然后,这幅图像中的每个像素(无论是黑色还是白色)与下一层的每个神经元之间都会有连接。特别是,每个黑色(开)像素将连接到下一层的每个神经元。现在假设每个使左眼的神经元的连接具有强(大正权重)连接到隐藏层中的特定像素,但与隐藏层中的其他任何神经元都有大的负连接:

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

左边是一个笑脸,右边是相同的笑脸和其左眼与隐藏神经元之间的连接。

这意味着,如果我们在隐藏层和左眼之间设置大的正权重,以及左眼与任何其他隐藏神经元之间的大的负连接,每当我们向网络展示一个包含左眼的脸时(这意味着那些神经元处于开状态),这个特定的隐藏神经元将激活,而所有其他神经元往往会保持关闭。这意味着这个特定的神经元将能够检测左眼是否存在。我们也可以类似地创建右眼、鼻子和嘴巴主要部分之间的连接,这样我们就可以开始检测所有这些面部特征。

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

每个脸部特征, 眼睛、鼻子和嘴巴, 都与某些隐藏神经元具有大的正连接, 但与其他神经元具有大的负连接。

这展示了我们如何为我们的连接选择权重,让隐藏神经元开始识别输入的特征。

提示

作为一个重要的提醒,我们想向读者指出,事实上,我们并没有选择权重来开始识别输入的特征。相反,这些权重是由网络使用反向传播或其他调整方法自动选择的。

另外,我们可以拥有更多的隐藏层,它们可以识别特征的特征(我们脸上的嘴是笑着的还是悲伤的?),因此可以得到更精确的结果。

深度学习有几个优点。第一个优点就像我们所见,它可以识别特征。另一个更重要的优点是,它会自动识别特征。在这个例子中,我们自己设置了权重以识别我们选择的特征。这是许多机器学习算法的缺点之一,用户必须使用自己的经验来选择他/她认为最好的特征。因此,需要大量的时间来进行特征选择,这仍然需要人类来执行。相反,深度学习算法会自动选择最佳特征。正如我们在前一章中所见,这可以通过反向传播来完成,但事实上,还存在其他技术来选择这些权重,这些将是下一章将要讨论的重要点,如自动编码器和受限玻尔兹曼机(或哈蒙尼姆,1986 年由保罗·斯莫伦斯基发明)。然而,我们还要提醒读者,我们从自动特征选择中获得的优势必须付出这样的代价,即我们需要选择正确的神经网络结构。

在一些深度学习系统中(例如在受限玻尔兹曼机中,正如我们将在下一章中看到的那样),神经网络还可以学会“修复”自己。正如我们在前面的例子中提到的,我们可以通过激活我们分别与右/左眼、鼻子和嘴相联系的四个神经元来产生一个通用的面孔。由于它们与前一层之间的连接权重较大,这些神经元将被激活,我们将激活与这些特征对应的神经元,从而生成一个通用的面孔图像。同时,如果与面部对应的神经元被激活,那么眼睛、鼻子和嘴的四个对应神经元也将被激活。这意味着,即使没有所有定义面部的神经元都处于开启状态,如果连接足够强大,它们仍然可能激活四个对应的神经元,进而激活面部缺失的神经元。

这还有一个额外的优势:鲁棒性。人类视觉在视图部分被遮挡时也能识别物体。我们甚至可以在对方戴帽子或遮住嘴巴的围巾时认出人;我们对图像中的噪声不敏感。同样地,当我们创建这种对应关系时,如果我们稍微改变面部,比如通过微调嘴巴一两个像素,信号仍然足够强大,可以打开“嘴巴”神经元,这将打开正确的像素并关闭组成修改后眼睛的错误像素。这个系统对噪声不敏感,并且可以进行自动修正。

比如说,嘴巴有一对像素关闭(在图中那些带有x的像素)。

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

这幅图有一对构成嘴巴的像素没有打开。

然而,嘴巴可能仍然有足够数量的神经元在正确的位置上,可以打开代表它的对应神经元:

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

即使一对神经元关闭,与其他神经元的连接足够强大,下一层代表嘴巴的神经元仍然会打开。

另一方面,我们现在可以沿着连接逆向传播,每当代表嘴巴的神经元打开时,这将打开组成嘴巴的所有神经元,包括以前关闭的两个神经元:

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

这两个神经元被顶部的神经元激活。

总之,深度学习相对于许多其他机器学习算法,特别是浅层神经网络的优势有:

  • 深度学习可以学习表示

  • 深度学习对噪声不太敏感。

  • 深度学习可以是一种生成算法(在下一章中会更详细介绍)

为了进一步理解为什么许多隐藏层可能是必要的,让我们考虑识别一个简单几何图形,一个立方体的任务。假设 3D 中的每条可能的线与一个神经元相关联(让我们暂时忘记这将需要无限多的神经元)。

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

同一视野上的每一条线都与不同的神经元相关联。

如果我们限制自己只看一个眼睛,我们视野中不同角度的线条将投影到二维平面上的同一条线上。因此,我们看到的每条线都可以由任何对应的三维线条给出,这些三维线条投影到视网膜上的同一条线上。假设任何可能的三维线条都与一个神经元相关联。因此,构成立方体的两条不同线条各自与一个神经元族相关联。然而,这两条线相交的事实允许我们连接属于不同族的两个神经元。我们对于构成立方体一条边的线有许多神经元,对于构成立方体另一条边的线也有许多神经元,但因为这两条线相交,有两个神经元会被连接。同样,每条线也连接到构成立方体的其他线条,使我们能够进一步重新定义我们的表示。在更高的层次上,我们的神经网络还可以开始识别这些线不是以任意角度相连,而是以确切的 90 度角相连。通过这种方式,我们可以制作越来越抽象的表示,从而使我们能够将在一张纸上画出的线条组识别为一个立方体。

不同层中的神经元按层次结构组织,并表示图像中基本元素及其结构的不同抽象水平。这个玩具例子显示,每个层次在抽象系统中都可以将下层的不同神经元联系在一起,建立它们之间的连接,类似于我们如何在抽象线条之间建立连接。它可以利用这些连接意识到这些抽象线条在一个点上相连,在更高层次上,实际上以 90 度相连并组成一个立方体,就像我们描述如何通过识别眼睛、鼻子和嘴巴及其相对位置来学习识别脸部的方式一样。

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

每条线都与一个神经元相关联,通过关联表示相交的线条来创建基本表示,通过关联表示特定角度的线条来创建更复杂的表示。

深度学习算法

在前面的段落中,我们对深度学习进行了直观的介绍。在本节中,我们将对下一章节中将彻底介绍的关键概念给出更精确的定义。具有许多层的深度神经网络也有存在的生物学原因:通过我们对人类理解语音的研究,实际上已经清楚地表明,我们天生具有一种分层的层次结构,它将听到的声音输入转化为语言水平。类似地,视觉系统和视觉皮层具有类似的分层结构,从 V1(或条纹皮层)到大脑中的 V2、V3 和 V4 视觉区域。深度神经网络模仿了我们大脑的本质,尽管以非常原始的方式。然而,我们应该警告读者,尽管理解我们的大脑可以帮助我们创建更好的人工神经网络,但最终,我们可能正在创建一种完全不同的架构,就像我们通过模仿鸟类创建了飞机,但最终得到了一个非常不同的模型。

在第二章 神经网络 中,我们介绍了反向传播算法作为一种流行的训练算法。在实践中,当我们有许多层时,反向传播可能是一种缓慢且难以使用的算法。事实上,反向传播主要是基于函数的梯度,而局部最小值的存在往往会阻止该方法的收敛。然而,深度学习这个术语适用于一类可能使用不同训练算法和权重调整的深度神经网络算法,它们不限于反向传播和经典的前馈神经网络。因此,我们应更加普遍地将深度学习定义为一类机器学习技术,其中信息在分层层次中进行处理,以便在逐渐增加的复杂性水平上理解数据的表示和特征。在这类算法中,我们通常可以包括:

  • 多层感知器(MLP):具有许多隐藏层的神经网络,采用前馈传播。正如讨论的那样,这是深度学习网络的第一个示例,但不是唯一可能的示例。

  • 玻尔兹曼机(BM):具有明确定义的能量函数的随机对称网络。

  • 受限玻尔兹曼机(RBM):与上面的伊辛模型示例类似,受限玻尔兹曼机由两层之间的对称连接组成,一个是可见层,一个是隐藏层,但与一般玻尔兹曼机不同,神经元之间没有层内连接。它们可以堆叠在一起形成 DBN。

  • 深度信念网络(DBN):一种随机生成模型,其中顶层之间具有对称连接(与前馈网络不同,是无向的),而底层通过来自上面层的定向连接接收来自处理后的信息。

  • 自动编码器:一类无监督学习算法,其输出形状与输入相同,这使得网络能够更好地学习基本表示。

  • 卷积神经网络(CNN):卷积层通过将滤波器应用于输入图像(或声音),通过在传入信号上滑动此滤波器来生成二维激活图。CNN 允许增强输入中隐藏的特征。

每种深度学习实现都有其优缺点,它们的训练难度取决于每层的层数和神经元数量。虽然简单的前馈深度神经网络通常可以使用第二章讨论的反向传播算法进行训练,但对于其他类型的网络存在不同的技术,这将在下一章中进一步讨论。

深度学习应用

在接下来的几段中,我们将讨论深度神经网络在语音识别和计算机视觉领域的应用,以及近年来它们在这两个领域的应用如何通过完全超越许多其他不基于深度神经网络的机器学习算法而大大提高了准确性。

语音识别

深度学习开始在本年代(2010 年及以后,例如 2012 年一篇标题为Deep Neural Networks for Acoustic Modeling in Speech Recognition的文章,由 Hinton 等人撰写,可在static.googleusercontent.com/media/research.google.com/en//pubs/archive/38131.pdf在线获取)中用于语音识别;在此之前,语音识别方法主要由称为 GMM-HMM 方法(具有高斯混合发射的隐马尔可夫模型)的算法主导。理解语音是一个复杂的任务,因为语音并不像天真地认为的那样,由清晰分隔开的单词组成,它们之间有明确的边界。实际上,语音中没有真正可辨识的部分,也没有清晰的单词边界。在组合单词时研究声音时,我们经常看到所谓的三音素,它们由三个区域组成,其中第一部分取决于前一个声音,中间部分通常是稳定的,下一个声音取决于后一个声音。此外,通常最好只检测三音素的部分,这些检测器称为 senones。

在*《语音识别中的深度神经网络用于声学建模》*中,对当时最先进的模型和作者采用的模型进行了几次比较,该模型由五个隐藏层组成,每层 2048 个单元。第一次比较是使用必应语音搜索应用程序,在 24 小时的训练数据上实现了 69.6%的准确率,而使用传统方法,名为 GMM-HMM 模型,在相同的训练数据上实现了 63.8%的准确率。该模型还在 Switchboard 语音识别任务上进行了测试,这是一个公共语音转文本转录基准(类似于用于数字识别的 MNIST 数据集),包括来自美国各地约 500 位发言者的大约 2500 次对话。此外,还使用了 Google 语音输入语音、YouTube 数据和英语广播新闻语音数据进行了测试和比较。在下一个表格中,我们总结了该文章的结果,显示了 DNN 与 GMM-HMM 的错误率对比。

任务训练数据总小时数DNN(错误率)具有相同训练的 GMM-HMM(错误率)具有更长训练的 GMM-HMM(错误率)
Switchboard(测试 1)30918.527.418.6(2000 小时)
Switchboard(测试 2)30916.123.617.1(2000 小时)
英语广播新闻5017.518.8
必应语音搜索2430.436.2
Google 语音587012.316.0(>>5870 小时)
YouTube140047.652.3

另一篇文章,《语音识别和相关应用的新型深度神经网络学习方法概述》,由邓、欣顿和金斯伯里(www.microsoft.com/en-us/research/publication/new-types-of-deep-neural-network-learning-for-speech-recognition-and-related-applications-an-overview/)撰写,作者们也注意到深度神经网络在嘈杂语音方面表现出色。

DNN 的另一个优点是在 DNN 出现之前,人们必须创建语音声谱图的变换。声谱图是信号中频率的视觉表示。通过使用 DNN,这些神经网络可以自主自动地选择原始特征,本例中以原始谱特征表示。使用卷积和池化等技术,可以应用于这种原始谱特征,以应对说话者之间的典型语音变化。近年来,更加复杂的具有循环连接的神经网络(RNN)取得了巨大成功(A. Graves、A. Mohamed 和 G. Hinton,《Speech Recognition with Deep Recurrent Neural Networks》发表于国际会议 Acoustic Speech and Signal Processing(ICASSP) (2013);参见 www.cs.toronto.edu/~fritz/absps/RNN13.pdf),例如,一种特定类型的深度神经网络称为 LSTM长短期记忆神经网络),将在后面的章节中描述。

在第二章 神经网络 中,我们讨论了不同的活动函数,尽管逻辑 S 形函数和双曲正切函数通常是最为人知的,但它们往往训练速度较慢。最近,ReLU 活动函数在语音识别中取得了成功应用,例如 G. Dahl、T. Sainath 和 G. Hinton 在 Improving Deep Neural Networks for LVCSR Using Rectified Linear Units and Dropout 中提到的文章,发表于国际会议 Acoustics Speech and Signal Processing (ICASSP) (2013) (www.cs.toronto.edu/~gdahl/papers/reluDropoutBN_icassp2013.pdf)。在第五章 图像识别 中,我们还将提及“Dropout”的含义,正如这篇论文中所讨论的(也在其标题中提到)。

对象识别和分类

这可能是深度神经网络取得成功并得到最好记录和理解的领域。就像语音识别一样,DNN 能够自动发现基本表示和特征。此外,手工选择的特征通常只能捕捉低级边缘信息,而 DNN 能够捕捉到更高级的表示,比如边缘交叉点。在 2012 年,来自 ImageNet 大规模视觉识别比赛的结果(结果可在image-net.org/challenges/LSVRC/2012/results.html上找到)显示,由 Alex Krizhevsky,Ilya Sutskever 和 Geoff Hinton 组成的获胜团队使用了一个拥有 6000 万参数和 650,000 个神经元的大型网络,其中包括五个卷积层和紧随其后的最大池化层,以 16.4%的错误率击败了第二名团队的 26.2%的错误率。卷积层和最大池化层将是第五章,图像识别的焦点。这是一个巨大而令人印象深刻的成果,这一突破性的结果引发了当前神经网络的复兴。作者们使用了许多新颖的方法来通过结合卷积网络、GPU 的使用以及一些技巧,比如放弃方法和使用 ReLU 活性函数代替 Sigmoid 来帮助学习过程。

该网络是使用 GPU 进行训练的(我们将在下一节讨论 GPU 的优势),并展示了大量标记数据可以极大地提高深度学习神经网络的性能,大大超越了图像识别和计算机视觉的更传统方法。鉴于深度学习中卷积层的成功,Zeiler 和 Fergus 在两篇文章中(M. Zeiler 和 R. Fergus,用于深度卷积神经网络的随机池化正则化,国际学习代表大会(ICLR) , 2013 年(www.matthewzeiler.com/pubs/iclr2013/iclr2013.pdf)和 M. Zeiler 和 R. Fergus,视觉化和理解卷积网络,arXiv:1311.2901, 页面 1-11, 2013 年,(www.matthewzeiler.com/pubs/arxive2013/arxive2013.pdf)试图了解为什么在深度学习中使用卷积网络效果如此好,以及网络学到了哪些表示。Zeiler 和 Fergus 试图通过映射回他们的神经活动来可视化中间层捕捉到的内容。他们为每个层创建了一个反卷积网络,将其环绕回输入的图像像素。

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

图片来源于 M. Zeiler 和 R. Fergus,《视觉化和理解卷积网络》。

文章展示了正在揭示的特征,其中第二层显示了角落和边缘,第三层显示了不同的网格图案,第四层显示了狗脸和鸟腿,而第五层显示了整个对象。

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

图像取自 M. Zeiler 和 R. Fergus,《可视化和理解卷积网络》

深度学习也可以通过使用包含 RBM 和自编码器的网络进行无监督学习。在 Q. Le、M. Ranzato、M. Devin、G. Corrado、K. Chen、J. Dean 和 A. Ng 的一篇文章中,使用大规模无监督学习构建高级特征,在国际机器学习大会(ICML)论文集中,作者使用了一个 9 层的自编码器网络,拥有十亿个连接,训练了来自互联网的 1000 万张图像。无监督特征学习使系统能够被训练以识别是否包含人脸的图像,而不需要告知。在文章中,作者表明:

“通过完全未标记的数据,可以训练神经元对高级概念进行选择性训练……通过对 YouTube 视频的随机帧进行训练,神经元可以成为面部、人体和猫脸的检测器……从这些表示开始,我们在 ImageNet 上的对象识别准确率达到了 15.8%,其中包括 20,000 个类别,相对于最先进技术的 70%的显著提高。”

GPU 与 CPU

如今深度学习受欢迎的一个原因是GPU(图形处理单元)的处理能力大幅增加。从架构上看,CPU(中央处理单元)由几个核心组成,每次只能处理几个线程,而 GPU 由数百个核心组成,可以同时处理数千个线程。与主要是串行单元的 CPU 相比,GPU 是高度可并行化的单元。

DNN 由几层组成,每一层的神经元的行为方式相同。此外,我们已经讨论了每个神经元的活动值是如何计算的,或者,如果用矩阵形式表示,我们有a = wx,其中ax是向量,w 是矩阵。在整个网络中,所有激活值都是以相同的方式计算的。CPU 和 GPU 具有不同的架构,特别是它们的优化方式不同:CPU 是延迟优化的,而 GPU 是带宽优化的。在具有许多层和大量神经元的深度神经网络中,带宽成为瓶颈,而不是延迟,这就是为什么 GPU 性能如此出色的原因。此外,GPU 的 L1 缓存比 CPU 的 L1 缓存速度快得多,而且也更大。

L1 缓存表示程序下一步可能要使用的信息的内存,并存储这些数据可以加快处理速度。在深度神经网络中,许多内存会被重复使用,这就是为什么 L1 缓存内存很重要的原因。使用 GPU,你可以让你的程序的速度比单纯使用 CPU 快上一个数量级,并且这种加速也是近年来在使用深度神经网络进行语音和图像处理方面取得的许多进展背后的原因,这种计算能力的增加在十年前是不可用的。

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

除了在 DNN 训练 方面更快外,GPU 在运行 DNN 推理 时也更有效率。推理是我们部署经过训练的 DNN 的后训练阶段。在 GPU 供应商 Nvidia 发布的一份名为基于 GPU 的深度学习推理:性能和功耗分析的白皮书中,对 AlexNet 网络(具有多个卷积层的 DNN)使用 GPU 和 CPU 的效率进行了比较,并在以下表格中总结了结果,该白皮书可在线获取:www.nvidia.com/content/tegra/embedded-systems/pdf/jetson_tx1_whitepaper.pdf

网络:AlexNet批大小Tegra X1(FP32)Tegra X1(FP16)Core i7 6700K(FP32)
推理性能147 img/sec67 img/sec62 img/sec
功耗5.5 W5.1 W49.7 W
性能/瓦特8.6 img/sec/W13.1 img/sec/W1.3 img/sec/W
推理性能128 (Tegra X1)48 (Core i7)155 img/sec258 img/sec242 img/sec
功耗6.0 W5.7 W62.5 W
性能/瓦特25.8 img/sec/W45 img/sec/W3.9 img/sec/W

结果表明,在 Tegra X1 上的推理可以比基于 CPU 的推理节能一个数量级,同时实现可比较的性能水平。

直接编写访问 GPU 而不是 CPU 的代码并不容易,但这就是为什么大多数流行的开源库(如 Theano 或 TensorFlow)允许你简单地在代码中打开一个简单的开关来使用 GPU 而不是 CPU。使用这些库不需要编写专门的代码,但如果可用,同样的代码可以在 CPU 和 GPU 上运行。开关取决于开源库,但通常可以通过设置确定的环境变量或创建一个特定的资源(.rc)文件来完成,该文件由所选择的特定开源库使用。

流行的开源库——简介

有几个开源库可用,允许在 Python 中创建深度神经网络,而无需显式地从头编写代码。最常用的是:Keras、Theano、TensorFlow、Caffe 和 Torch。在本书中,我们将提供使用前三个库的示例,这些库都可以在 Python 中使用。这样做的原因是 Torch 不基于 Python,而是基于一种称为 Lua 的不同语言,而 Caffe 主要用于图像识别。对于这些库,我们将快速描述如何打开我们在前一段讨论中讨论的 GPU 开关。然后,本书中的大部分代码都可以在 CPU 或 GPU 上运行,这取决于读者可用的硬件。

Theano

Theano(deeplearning.net/software/theano/)是一个用 Python 编写的开源库,实现了许多使编写神经网络代码变得容易的功能。此外,Theano 也可以很容易地利用 GPU 加速和性能。不深入讨论 Theano 如何工作的细节,Theano 使用符号变量和函数。在许多真正吸引人的功能中,Theano 允许我们通过为我们计算所有导数来很容易地使用反向传播。

正如前面提到的,Theano 也可以很容易地利用您计算机上的 GPU。有很多方法可以做到这一点,但最简单的方法是创建一个名为.theanorc的资源文件,并包含以下几行:

[global]
device = gpu  
floatX = float32

您可以通过简单地输入以下命令来检查 Theano 是否配置为使用您的 GPU:

print(theano.config.device)

我们参考 Theano 文档来学习如何使用 Theano 的第一步,并且我们将在本书中使用 Theano 实现一些深度学习的测试代码示例。

TensorFlow

TensorFlow(www.tensorflow.org)与 Theano 非常相似,在 TensorFlow 中,计算也表示为图。因此,TensorFlow 图就是对计算的描述。在 TensorFlow 中,您不需要显式地要求使用 GPU,而是 TensorFlow 将自动尝试使用您的 GPU(如果有的话),但是如果您有多个 GPU,则必须显式地将操作分配给每个 GPU,否则只会使用第一个。要做到这一点,您只需键入以下行:

with tensorflow.device("/gpu:1"):

在这里,可以定义以下设备:

  • "/cpu:0":您的计算机的主 CPU

  • "/gpu:0":如果存在的话,您计算机的第一个 GPU

  • "/gpu:1":如果存在的话,您计算机的第二个 GPU

  • "/gpu:2":如果存在的话,您计算机的第三个 GPU,以此类推

再次强调,我们参考 TensorFlow 文档来学习如何使用 TensorFlow 的第一步,并且测试使用 TensorFlow 的代码示例将在本书中实现。

Keras

Keras (keras.io) 是一个可以在 Theano 或 TensorFlow 上运行的神经网络 Python 库,尽管默认情况下会使用 TensorFlow 运行。在线提供了 keras.io/backend/ 的说明。Keras 可以在 CPU 或 GPU 上运行,如果你在 Theano 上运行它,你将需要像之前描述的那样设置一个 .theanorc 文件。Keras 允许不同的方式创建深度神经网络,它通过使用 model 来使其变得简单。主要类型的 modelSequential model,它创建了一个线性堆叠的层。然后你可以通过简单调用 add 函数来新增层。在接下来的部分中,我们将使用 Keras 创建一些示例。Keras 可以通过以下简单命令轻松安装:

pip install Keras

也可以通过从其 Git 存储库派生然后在上面运行设置来安装它:

git clone https://github.com/fchollet/keras.git
cd keras
python setup.py install

然而,我们建议读者查阅在线文档以获取更多信息。

使用 Keras 的深度神经网络示例代码

在本节中,我们将介绍一些简单的代码,使用 Keras 对使用流行数据集 MNIST 正确分类数字。MNIST 是一个包含许多不同人手写数字的数据集,共有 70,000 个示例。通常,前 60,000 个用于训练,剩下的 10,000 个用于测试。

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

从 MNIST 数据集中获取的数字示例

Keras 的一个优点是它可以为你导入这个数据集,而无需显式从网络上下载它(Keras 会为你下载)。这可以通过一行简单的代码实现:

from keras.datasets import mnist

我们需要从 Keras 导入一些类来使用经典的深度神经网络,它们是:

from keras.models import Sequential 
from keras.layers.core import Dense, Activation
from keras.utils import np_utils

我们现在准备开始编写导入数据的代码,我们可以用一行代码完成:

(X_train, Y_train), (X_test, Y_test) = mnist.load_data()

这导入了训练数据和测试数据;此外,这两个数据集被分为两个子集:一个包含实际图像,另一个包含标签。我们需要稍微修改数据以便使用它。事实上,X_trainX_test 数据包括了 60000 个小的 (28,28) 像素图像,但我们想将每个样本重新塑造为一个 784 像素长的向量,而不是一个 (28,28) 的二维矩阵。这可以通过以下两行轻松实现:

X_train = X_train.reshape(60000, 784)     
X_test = X_test.reshape(10000, 784)

同样地,标签指示了图像所描述的数字的值,我们希望将其转换为一个包含全部零值和仅在对应于该数字的条目中有一个 1 的 10-entry 向量,因此例如 4 被映射为 [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]。

classes = 10
Y_train = np_utils.to_categorical(Y_train, classes)     
Y_test = np_utils.to_categorical(Y_test, classes)

最后,在调用我们的主函数之前,我们只需设置我们的输入大小(mnist 图像的大小)、隐藏层有多少个隐藏神经元、我们想要尝试我们网络的时期数量以及训练的批次大小:

input_size = 784
batch_size = 100     
hidden_neurons = 100     
epochs = 15
main(X_train, X_test, Y_train, Y_test)

现在我们已经准备好为我们的主函数编写代码了。Keras 通过定义一个模型来工作,我们将使用Sequential模型,然后添加层(在这种情况下,我们将使用常规的* dense *,而不是稀疏层)指定输入和输出神经元的数量。对于每一层,我们指定其神经元的活动函数:

model = Sequential()     
model.add(Dense(hidden_neurons, input_dim=input_size)) 
model.add(Activation('sigmoid'))     
model.add(Dense(classes, input_dim=hidden_neurons)) 
model.add(Activation('softmax'))

现在,Keras 提供了一种简单的方法来指定成本函数(loss)及其优化(训练速率、动量等)。我们不打算修改默认值,因此我们可以简单地传递:

model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='sgd')

在这个例子中,优化器是sgd,代表随机梯度下降。在这一点上,我们需要训练网络,这与 scikit-learn 类似,通过调用fit函数完成。我们将使用 verbose 参数,以便可以跟踪这个过程:

model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=epochs, verbose=1)

唯一剩下的事情是添加代码来评估我们的网络在测试数据上的表现并打印准确率结果,这很简单:

score = model.evaluate(X_test, Y_test, verbose=1)
print('Test accuracy:', score[1]) 

这就是全部。现在可以运行了。测试准确率大约为 94%,这不是一个很好的结果,但这个例子在 CPU 上运行时间不到 30 秒,是一个非常简单的实现。有一些简单的改进可以做,比如选择更多的隐藏神经元或选择更多的 epochs,我们把这些简单的改变留给读者自己去熟悉代码。

Keras 还允许我们查看它创建的权重矩阵。要做到这一点,只需键入以下行:

weights = model.layers[0].get_weights()

通过在我们之前的代码中添加以下行,我们可以看看隐藏神经元学到了什么:

import matplotlib.pyplot as plt     
import matplotlib.cm as cm     
w = weights[0].T          
for neuron in range(hidden_neurons):         
    plt.imshow(numpy.reshape(w[neuron], (28, 28)), cmap = cm.Greys_r) 
    plt.show()  

为了得到更清晰的图像,我们将 epochs 的数量增加到 100,得到以下的图形:

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

所有隐藏神经元学到的内容组成的复合图形

为了简单起见,我们将每个神经元的所有图像聚合到一个单独的图形中,表示所有神经元的复合图形。显然,由于初始图像非常小且没有很多细节(它们只是数字),隐藏神经元学到的特征并不是很有趣,但已经清楚每个神经元都学到了不同的“形状”。

上面的绘图代码应该立即清晰明了;我们只注意到以下行正在导入cm

import matplotlib.cm as cm 

这只是允许对神经元进行灰度表示,它在imshow()调用中使用,通过传递选项cmap = cm.Greys_r。这是因为mnist图像不是彩色图像,而是灰度图像。

Keras 的美妙之处在于它很容易创建神经网络,但也很容易下载测试数据集。让我们尝试使用cifar10数据集而不是mnist数据集。cifar10数据集不是数字,而是由 10 类对象组成:飞机、汽车、鸟类、猫、鹿、狗、青蛙、马、船和卡车。要使用cifar10数据集,只需写:

from keras.datasets import cifar10

在前面的代码行的位置:

from keras.datasets import mnist

然后,我们需要对上面编写的代码进行以下更改:

(X_train, Y_train), (X_test, Y_test) = cifar10.load_data()
X_train = X_train.reshape(50000, 3072)     
X_test = X_test.reshape(10000, 3072)
input_size = 3072

这是因为训练图像仅有 50,000 张(而不是 60,000 张),并且图像是彩色(RGB)32 x 32 像素图像,因此它们的大小是 3 x 32 x 32。就目前而言,我们可以保持其他一切不变,但是,如果我们运行这个示例,我们会发现我们的性能现在非常差,只有大约 20%。这是因为数据更加复杂,需要更复杂的神经网络。事实上,大多数用于图像分类的神经网络都使用一些基本的卷积层,这将在第五章中讨论,图像识别,然而,现在我们可以尝试将隐藏神经元数提高到 3,000,并添加一个包含 2,000 个神经元的第二个隐藏层。我们还将在第一个隐藏层中使用 ReLU 激活函数。

要做到这一点,我们只需要写下以下定义模型的行,而不是之前的内容:

    model = Sequential()     
    model.add(Dense(3000, input_dim=input_size)) 
    model.add(Activation('sigmoid'))
    model.add(Dense(2000, input_dim=3000)) 
    model.add(Activation('sigmoid'))     
    model.add(Dense(classes, input_dim=2000)) 
    model.add(Activation('softmax'))

如果我们运行这段代码,我们会发现训练时间要长得多,但是最后,我们的训练集准确率约为 60%,而测试数据的准确率只有约 50%。与较简单的mnist数据集相比,尽管网络更大,训练时间更长,但准确率要低得多,这是由于数据的复杂性更高。此外,通过将适配网络的行替换为以下行:

model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=epochs, validation_split=0.1, verbose=1)

我们还可以在过程中输出训练数据分割为 90/10 的准确性如何提高。这也表明,尽管训练的准确性在训练过程中不断提高,但验证集的准确性在某一点上会达到饱和,表明网络开始过拟合并饱和一些参数。

尽管这可能看起来是深度网络在更丰富的数据集上无法提供良好准确性的失败,但事实上,我们将会看到,实际上有一些方法可以解决这个问题,让我们能够在更复杂更大的数据集上获得更好的性能。

摘要

在本章中,我们引导读者理解了深度学习的概念以及它与深度神经网络的关系。我们还讨论了除了经典的前馈实现之外,还存在许多不同的深度神经网络实现,并讨论了深度学习在许多标准分类任务上取得的最新成功。本章充满了从 Jacquard 织布机到伊辛模型的概念和想法,通过示例和历史评论进行了发展。这只是一个开始,我们将在许多示例中解释并更准确地发展本章介绍的思想。

我们将在接下来的章节开始这个过程,并向读者介绍许多我们在本章中涉及的概念,比如 RBM 和自编码器,以及清楚地展示我们如何创建比简单的前馈 DNN 更强大的深度神经网络。此外,在这些特定的神经网络中,表示和特征的概念如何自然地产生也将变得清晰。从上一个例子,使用 cifar10 数据集,可以清楚地看出经典的前馈 DNN 很难在更复杂的数据集上进行训练,我们需要更好的方法来设置权重参数。X. Glorot 和 Y. Bengio 在其论文《Understanding the difficulty of training deep feed-forward neural networks》中探讨了使用梯度下降来训练具有随机权重初始化的深度神经网络的性能不佳的问题。下一章将介绍并讨论可以成功训练深度神经网络的新算法。

第四章:无监督特征学习

深度神经网络能够成功的一个原因是能够学习数据中实体(特征)的正确表示,而不需要(太多)人类和领域知识。

理论上,神经网络能够直接消耗原始数据,并通过隐藏的中间表示将输入层映射到所需的输出。传统的机器学习技术主要专注于最终映射,假定“特征工程”的任务已经完成。

特征工程是利用现有的领域知识创建智能数据表示的过程,以便它可以被机器学习算法处理。

Andrew Yan-Tak Ng 是斯坦福大学的教授,也是机器学习和人工智能领域最著名的研究者之一。他在出版物和讲话中描述了传统机器学习在解决实际问题时的局限性。

使机器学习系统正常工作最困难的部分是找到正确的特征表示:

提出特征是困难的,耗时的,需要专业知识。在应用学习应用程序时,我们花费了大量时间调整特征。

安德鲁·吴,机器学习和人工智能通过大脑模拟,斯坦福大学

让我们假设我们正在将图片分类为几个类别,例如动物与车辆。原始数据是图像中的像素矩阵。如果我们直接在逻辑回归或决策树中使用这些像素,我们将为可能适用于给定的训练样本的每一张图片创建规则(或关联权重),但这将非常难以概括到相同图片的轻微变化。换句话说,假设我的决策树发现有五个重要的像素,它们的亮度(假设我们只显示黑白色调)可以确定大多数训练数据被分成两类–动物和车辆。相同的照片,如果裁剪、移位、旋转或重新着色,将不再遵循以前的那些规则。因此,模型可能会对它们进行随机分类。主要原因是我们正在考虑的特征太弱而不稳定。然而,我们可以首先预处理数据,以便提取这样的特征:

  • 图片是否包含对称的,像车轮一样的形状?

  • 它是否包含把手或方向盘?

  • 它是否包含腿或头?

  • 它是否有两只眼睛的脸?

在这种情况下,决策规则会非常容易和强大,如下所示:

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

需要多少努力才能提取这些相关特征?

由于我们没有把手检测器,我们可以尝试手动设计特征来捕捉图片的一些统计特性,例如,在不同的图片象限中找到不同方向的边缘。我们需要找到比像素更好的图像表示方法。

而且,强大和显著的特征通常是由先前提取的特征层次结构制成的。我们可以在第一步开始提取边缘,然后取得生成的“边缘向量”,并将它们组合起来识别物体部分,比如眼睛、鼻子、嘴巴,而不是光、镜子或者扰流板。最终的物体部分可以再次组合成对象模型;例如,两只眼睛,一只鼻子和一张嘴巴形成一张脸,或者两个车轮、一个座椅和一个把手形成一辆摩托车。整个检测算法可以以以下方式简化:

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

通过递归应用稀疏特征,我们设法获得更高级的特征。这就是为什么你需要比浅层算法更深的神经网络架构。单个网络可以学习如何从一个表示转移到另一个,但是将它们堆叠在一起将使整个端到端的工作流能够实现。

不过,真正的威力并不仅在于层次结构。重要的是要注意到,到目前为止我们只使用了无标签数据。我们通过对数据本身进行逆向工程来学习隐藏的结构,而不是依赖于手动标记的样本。监督学习仅表示最终的分类步骤,我们需要将其分配到车辆类别或动物类别。所有先前的步骤都是以无监督的方式执行的。

我们将在以下第五章中看到如何为图片执行特定的特征提取,图像识别。在本章中,我们将着重介绍学习任何类型数据(例如时间信号、文本或一般的属性向量)的特征表示的一般方法。

为此,我们将介绍两种最强大且广泛使用的无监督特征学习架构:自动编码器和受限波尔兹曼机。

自动编码器

自动编码器是用于无监督学习的对称网络,其中输出单元连接回输入单元:

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

H2O 训练手册中的自动编码器简单表示 (https://github.com/h2oai/h2o-training-book/blob/master/hands-on_training/images/autoencoder.png)

输出层的大小与输入层相同,因为它的目的是重构自己的输入,而不是预测一个依赖目标值。

这些网络的目标是通过编码层 Φ 充当压缩滤波器,将输入向量 X 适合到较小的潜在表示(编码) c,然后解码层 Φ 试图将其重构回 X’

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

损失函数是重构误差,它将迫使网络找到训练数据的最有效的紧凑表示,同时最小化信息损失。对于数值输入,损失函数可以是均方误差:

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

如果输入数据不是数值型,而是表示为比特向量或多项分布的向量,我们可以使用重构的交叉熵:

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

这里,d 是输入向量的维度。

网络的中央层(编码)是数据的压缩表示。我们实际上将一个 n 维数组转换为一个较小的 m 维数组,其中 m < n。这个过程与使用主成分分析PCA)进行降维非常相似。PCA 将输入矩阵分成正交轴(称为分量),以便您可以通过在这些轴上投影原始点来重构原始矩阵的近似值。通过按重要性对它们进行排序,我们可以提取出前 m 个组件,这些组件可以被视为原始数据的高级特征。

例如,在多元高斯分布中,我们可以将每个点表示为两个正交分量上的坐标,这两个分量描述了数据中可能的最大方差:

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

一个样本散点图,按照以(1,3)为中心,(0.866, 0.5)方向上标准差为 3,在正交方向上标准差为 1 的多元(双变量)高斯分布进行分布。这些方向表示与样本相关联的主成分(PC)。由 Nicoguaro(自己的作品)CC BY 4.0 (http://creativecommons.org/licenses/by/4.0),通过维基媒体公共领域。

PCA 的局限性在于它只允许对数据进行线性变换,这并不总是足够的。

自编码器的优势在于可以使用非线性激活函数表示非线性表示。

自编码器的一个著名示例是 MITCHELL 在他的书 机器学习 中给出的。在这个例子中,我们有一个数据集,其中包含八个分类对象,用八个相互排斥的比特标记的二进制编码。网络将学习一个仅具有三个隐藏节点的紧凑表示:

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

Tom Mitchell 的自编码器示例。

通过应用正确的激活函数,学习到的紧凑表示与三比特二进制表示完全对应。

然而,在某些情况下,仅仅单个隐藏层不足以表示数据的整个复杂性和变异性。更深的架构可以学习输入和隐藏层之间更复杂的关系。然后,网络能够学习潜在特征并利用这些特征来最好地表示数据中的非平凡信息组成部分。

通过连接两个对称网络获得深度自动编码器,通常由最多五个浅层组成:

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

自动编码器的示意结构,具有 3 个完全连接的隐藏层(https://en.wikipedia.org/wiki/Autoencoder#/media/File:Autoencoder_structure.png)

深度自动编码器可以学习新的潜在表示,将先前学到的表示组合起来,以便每个隐藏级别可以被视为原始数据的某种压缩层次表示。然后,我们可以使用编码网络的代码或任何其他隐藏层作为描述输入向量的有效特征。

网络设计

在构建深度神经网络时,最常见的问题可能是:我们如何选择隐藏层的数量和每个层的神经元数量?此外,我们使用哪种激活和损失函数?

没有确定的答案。经验方法包括运行一系列试验和错误或标准网格搜索,其中深度和每个层的大小简单地被定义为调整超参数。我们将看一些设计准则。

对于自动编码器,问题略有简化。由于自动编码器有许多变体,我们将定义通用用例的指南。请记住,每个变体都将有其自己的规则需要考虑。我们可以建议以下内容:

  • 输出层的大小与输入完全相同。

  • 网络大多数情况下是对称的。拥有不对称网络意味着编码器和解码器函数的不同复杂性。除非有特殊原因,通常没有对称网络的优势。但是,您可以决定共享相同的权重或者决定在编码和解码网络中具有不同的权重。

  • 在编码阶段,隐藏层比输入小,这种情况下,我们称之为“欠完备自动编码器”。多层编码器逐渐减小表示大小。隐藏层的大小通常最多是前一个的一半。如果数据输入层有 100 个节点,那么一个合理的架构可能是 100-40-20-40-100。比输入更大的层将导致没有任何压缩,这意味着不会学习到有趣的模式。我们将在正则化部分看到,这种约束在稀疏自动编码器的情况下并非必要。

  • 中间层(代码)起着重要作用。在特征减少的情况下,我们可以将其保持较小,并且等于 2、3 或 4,以便允许高效的数据可视化。在堆叠的自编码器的情况下,我们应该将其设置得更大,因为它将代表下一个编码器的输入层。

  • 在二进制输入的情况下,我们希望使用 sigmoid 作为输出激活函数,使用交叉熵,更确切地说,使用伯努利交叉熵的总和,作为损失函数。

  • 对于实值,我们可以使用线性激活函数(ReLU 或 softmax)作为输出,并且使用均方误差MSE)作为损失函数。

  • 对于不同类型的输入数据(x)和输出u,您可以遵循一般方法,其中包括以下步骤:

    1. 找到观察到 x 的概率分布,给定u,P(x/u)

    2. 找到u和隐藏层 h(x)之间的关系

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

  • 在深层网络(具有多个隐藏层)的情况下,为了不使编码器和解码器的复杂性失衡,使用相同的激活函数。

  • 如果我们在整个网络中使用线性激活函数,我们将近似于 PCA 的行为。

  • 除非是二进制的,否则最好对您的数据进行高斯缩放(0 均值和单位标准差),并且最好将输入值保留为 0 或 1。分类数据可以使用带有虚拟变量的独热编码来表示。

  • 激活函数如下:

    • ReLU 通常是大多数神经网络的默认选择。由于其拓扑结构,自编码器可能会受益于对称激活函数。由于 ReLU 往往过拟合,因此在与正则化技术(如 dropout)结合时更受欢迎。

    • 如果您的数据是二进制的或者可以缩放到[0,1]的范围内,则可能会使用 sigmoid 激活函数。如果您对输入分类数据使用了独热编码,则最好使用 ReLU。

    • 双曲正切(tanh)是在梯度下降情况下进行计算优化的不错选择。由于数据将围绕 0 中心化,导数将更高。另一个效果是减少梯度中的偏差,正如《高效的反向传播》一文中所解释的那样(yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf)。

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

    深度神经网络常用的不同激活函数

自编码器的正则化技术

在之前的章节中,我们已经看到了不同形式的正则化,例如 L1,L2,提前停止和 dropout。在本节中,我们将描述一些专门为自编码器量身定制的几种流行技术。

到目前为止,我们一直把自动编码器描述为"欠完备",这意味着隐藏层比输入层小。这是因为拥有更大的层根本没有任何压缩。隐藏单元可能只是精确复制输入并将精确复制作为输出返回。

另一方面,拥有更多的隐藏单元将使我们有更多的自由学习智能表示。

我们将看到如何用三种方法解决这个问题:去噪自动编码器,压缩自动编码器和稀疏自动编码器。

Denoising 自动编码器

想法是我们想训练我们的模型学习如何重建输入数据的嘈杂版本。

我们将使用 x 表示原始输入,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传表示带有噪音的输入,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传表示重建的输出。

带有噪声的输入,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,是通过随机分配输入外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传的子集为 0,概率为𝑝,再加上具有方差v的加性各向同性高斯噪声而生成的数值输入。

然后我们将有两个新的超参数要调整??和外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,它们代表噪音水平。

我们将使用带噪声的变体,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,作为网络的输入,但损失函数仍然是输出外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传与原始无噪声输入外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传之间的误差。如果输入维度是d,编码函数f,解码函数g,我们将把损失函数j写成这样:

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

这里,L是重构误差,通常是均方误差或交叉熵。

有了这种变体,如果一个隐藏单元试图精确复制输入值,那么输出层就无法完全信任,因为它知道这可能是噪音而不是原始输入。我们正在强迫模型基于其他输入单元之间的相互关系来重建数据的有意义结构。

我们期望的是添加的噪声越大,在每个隐藏单元上应用的滤波器就越大。所谓的滤波器是指针对提取特定特征而激活的原始输入的部分。如果没有噪音,隐藏单元倾向于提取输入数据的一个小子集,并将其作为最不触及的版本提供给下一层。通过向单元添加噪声,对坏重构外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传的错误惩罚将迫使网络保留更多信息,以便在可能存在噪音的情况下对特征进行上下文化。

请注意,只需添加一个小的白噪声就相当于使用权重衰减正则化。权重衰减是一种技术,它在每个训练时期将权重乘以小于 1 的因子,以便限制模型中的自由参数。虽然这是一种常用的神经网络正则化技术,但通过将输入设置为 0 的概率p,我们实际上实现了完全不同的结果。

我们不希望获得高频滤波器,这些滤波器组合在一起会给出更广义的模型。我们的去噪方法生成代表潜在数据结构的独特特征并具有独立含义的滤波器。

收缩自编码器

收缩自编码器旨在通过明确添加一个惩罚项来实现类似于去噪方法的目标,当模型试图学习无趣的变化并且仅促进在训练集中观察到的那些变化时,它就会受到惩罚。

换句话说,模型可能会试图通过产生代表训练数据中并非必然存在的变化的滤波器来逼近恒等函数。

我们可以将这种敏感性表示为所提取特征对输入维度的所有偏导数的平方和。

对于由编码函数f映射到大小为d[h]的隐藏表示h的维度为x的输入,以下数量对应于编码器激活的雅可比矩阵的 L2 范数(Frobenius):

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

损失函数将修改如下:

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

在这里,λ是正则化因子。很容易看出,雅可比的 Frobenius 范数在线性编码器的情况下对应于 L2 权重衰减。主要的区别在于对于线性情况,实现收缩的唯一方法是保持权重非常小。在 sigmoid 非线性的情况下,我们还可以推动隐藏单元进入饱和状态。

让我们分析这两个术语。

误差J(MSE 或交叉熵)推动保留尽可能多的信息以完美重建原始值。

处罚推动了摆脱所有这些信息,使得隐藏单元对X的导数最小化。大值意味着所学到的表示对于输入变化太不稳定。当我们观察到输入值变化时,所观察到的隐藏表示几乎没有变化时,我们得到一个小的值。在这些导数限制为 0 的情况下,我们只保留了相对于输入X不变的信息。我们实际上摆脱了所有不够稳定且对微小扰动过于敏感的隐藏特征。

假设我们的输入是同一数据的许多变化。在图像的情况下,它们可能是同一主题的小旋转或不同曝光。在网络流量的情况下,它们可能是同一类型流量的数据包头部的增加/减少,可能是由于包装/解包协议。

如果我们只看这个维度,模型很可能会非常敏感。雅可比项将惩罚高敏感性,但它会被低重构误差所抵消。

在这种情况下,我们会有一个单位,对变化方向非常敏感,但对所有其他方向并不是很有用。例如,在图片的情况下,我们仍然拥有相同的主题;因此,所有其余的输入值都是常数。如果我们在训练数据中没有观察到给定方向的变化,我们希望丢弃该特征。

H2O 目前不支持收缩自编码器;但是,可以在0xdata.atlassian.net/browse/PUBDEV-1265找到一个未解决的问题。

稀疏自编码器

自编码器,截至目前我们所见的,隐藏层始终小于输入。

主要原因是否则,网络将具有足够的能力只需记忆输入并完美地重构它。向网络添加额外的容量只会是多余的。

减少网络的容量会迫使基于输入的压缩版本进行学习。算法将不得不选择最相关的特征,以帮助更好地重构训练数据。

然而,有些情况下压缩是不可行的。让我们考虑每个输入节点由独立随机变量形成的情况。如果变量彼此不相关,则实现压缩的唯一方法是完全摆脱其中一些。我们实际上正在模拟 PCA 的行为。

为了解决这个问题,我们可以在隐藏单元上设置一个稀疏约束。我们将尝试推动每个神经元大部分时间处于不活跃状态,这对于 sigmoid 和 ReLU 来说意味着激活函数的输出接近于 0,对于 tanh 来说是-1。

如果我们称呼隐藏单元外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在输入为外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传时的激活为外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,我们可以如下定义隐藏单元外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传的平均激活:

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

在这里,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传是我们的训练数据集(或训练数据批次)的大小。

稀疏性约束包括强制外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,其中外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传稀疏参数,在区间[1,0]内且理想情况下足够接近 0。

原始论文(web.stanford.edu/class/cs294a/sparseAutoencoder.pdf)建议值接近 0.05。

我们将每个隐藏单元的平均激活值建模为具有均值外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传的伯努利随机变量,并且我们希望所有这些都趋向于具有均值外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传的伯努利分布。

为了实现这一点,我们需要添加一个额外的惩罚项,用于量化这两个分布之间的差异。我们可以根据我们希望实现的实际分布外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传和理论分布外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传之间的Kullback-LeiblerKL)散度来定义这个惩罚。

通常情况下,对于离散概率分布PQ,以比特为单位测量信息时,KL散度定义如下:

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

其中一个要求是PQ绝对连续,即对于任意可测的值P都满足外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。这也可以写成外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。每当外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传时,该项的贡献将是外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,因为那时的外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在我们的案例中,单元j的稀疏自编码器散度如下:

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

当两个平均值相等且单调递增时,此函数的性质是外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,否则直到外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传接近 8 时,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传会像这样增加。

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

或 1。

最终带有额外惩罚项的损失函数如下:

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

在这里,J是标准损失函数(均方根误差),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传是隐藏单元的数量,ß是稀疏项的权重。

这个额外的惩罚将导致反向传播算法出现一些小的低效。特别是,前述公式在计算每个示例的反向传播之前,将需要经过整个训练集进行额外的前向步骤来预先计算平均激活值外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

自编码器总结

自编码器是强大的无监督学习算法,在异常检测或特征工程等领域越来越受欢迎,使用中间层的输出作为特征来训练监督模型,而不是使用原始输入数据。

无监督意味着在训练过程中不需要指定标签或地面真相。只要网络有足够的能力学习和表示内在的存在关系,它们就可以处理输入的任何数据。这意味着我们可以设定编码层的大小(减少的维度m),但根据隐藏层的数量和大小来获得不同的结果。

如果我们正在构建一个自动编码器网络,我们希望在避免错误表示的同时实现稳健性,但同时不要通过较小的顺序层压缩信息来限制网络的容量。

除噪声、收缩和自动编码器都是解决这些问题的很好的技术。

添加噪声通常更简单,而且不会在损失函数中增加复杂性,这会导致更少的计算。另一方面,嘈杂的输入使梯度变得不稳定,并且为了获得更好的特征而丢弃部分信息。

收缩自动编码器非常擅长使模型对训练分布的小偏差更加稳定。因此,它是减少误报的一个很好的选择。缺点是一种反效果,它会增加重构误差以减少敏感性。

稀疏自动编码器可能是最完整的解决方案。对于大型数据集来说,它计算成本最高,但由于梯度是确定的,它可以在二阶优化器的情况下提供很好的稳定性和低重构误差。

不管你做出什么选择,采用正则化技术都是强烈推荐的。它们都带有超参数需调整,我们将在相应的Tuning部分中看到如何优化。

除了迄今为止描述的技术外,值得一提的是变分自动编码器,它似乎是正则化自动编码器的最终解决方案。变分自动编码器属于生成模型类别。它不仅学习了最好地描述训练数据的结构,还学习了潜在单位高斯分布的参数,这些参数可以最好地再现输入数据。最终的损失函数将是重构误差和重构的潜在变量之间的 KL 散度的总和。编码器阶段将生成由均值和标准差向量组成的代码。从代码中,我们可以表征潜在分布参数,并通过从该分布中采样重构原始输入。

受限玻尔兹曼机

  • 在 90 年代初,神经网络基本上已经过时。机器学习研究的大部分内容是关于其他技术,如随机森林和支持向量机。只有一个隐藏层的神经网络表现不如这些其他技术,而且人们认为训练更深的神经网络太困难。

  • 兴趣再次高涨于神经网络,由 2004 年由Geoffrey Hinton领导的研究团队率先使用受限玻尔兹曼机(RBM)取得一系列突破,创造了具有多层的神经网络;他们将这种方法称为深度学习。在 10 年内,深度学习从一种小众技术发展到主导每一个人工智能竞赛。RBM 是这一巨大突破的一部分,使得 Hinton 和其他人在多种图像和语音识别问题上取得世界纪录成绩。

  • 在这一部分中,我们将研究 RBM 的工作原理,如何实现它们以及如何将它们结合成深度信念网络。

一台受限玻尔兹曼机看起来很像是神经网络的一个单层。有一组输入节点与另一组输出节点相连:

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

图 1。受限玻尔兹曼机

输出节点被激活的方式也与自编码器完全相同。每个输入节点和输出节点之间有一个权重,每个输入节点的激活乘以这个权重映射矩阵,然后应用偏置向量,并且每个输出节点的总和将通过一个 sigmoid 函数。

使得受限玻尔兹曼机与众不同的是激活代表的内容、我们对它们的思考方式以及它们的训练方式。首先,当谈论 RBM 时,我们不是谈论输入和输出层,而是将层称为可见层和隐藏层。这是因为在训练时,可见节点代表我们已知的信息,而隐藏节点将旨在代表生成可见数据的一些变量。这与自编码器形成对比,自编码器的输出层不再明确地代表任何东西,只是通过信息传递的一种受限空间。

学习受限玻尔兹曼机的权重基础于统计物理学,并使用基于能量的模型(EBM)。在这些模型中,每个状态都经历一个能量函数,它与状态发生概率相关。如果能量函数返回一个高值,我们期望这种状态不太可能发生,很少发生。相反,能量函数的低结果意味着一个更稳定的状态,会更频繁发生。

一个很好的直观思考能量函数的方式是想象将大量的弹跳球扔进一个箱子中。起初,所有的球都具有很高的能量,因此会弹得很高。这里的状态是所有球的位置和它们关联速度的一个时间点快照。当球在弹跳时,这些状态将会非常短暂;它们只会存在片刻,因为球的移动范围很大,很不可能再次出现。但是当球开始平静下来,当能量离开系统时,一些球将开始越来越静止。这些状态一旦发生一次就稳定了,一旦发生就不会停止。最终,当球停止弹跳并且都变成静止时,我们有一个完全稳定的状态,具有很高的概率。

  • 以应用于受限波尔兹曼机的例子,考虑学习一组蝴蝶图像的任务。我们在这些图像上训练我们的 RBM,并且希望它对任何蝴蝶图像分配低能量值。但是当给出来自不同集合的图像,比如汽车时,它会给它分配一个高能量值。相关的对象,如蛾子、蝙蝠或鸟,可能具有中等能量值。

  • 如果我们定义了一个能量函数,那么给定状态的概率就如下所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 在这里,v 是我们的状态,E 是我们的能量函数,Z 是分区函数;v 的所有可能配置的总和定义如下:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

霍普菲尔德网络和波尔兹曼机

  • 在我们进一步讨论受限波尔兹曼机之前,让我们简要谈谈霍普菲尔德网络;这应该有助于我们对如何到达受限波尔兹曼机有更多的理解。霍普菲尔德网络也是基于能量的模型,但与受限波尔兹曼机不同,它只有可见节点,并且它们都是相互连接的。每个节点的激活始终为-1 或+1。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 2. 霍普菲尔德网络,所有输入节点都相互连接。

  • 在运行霍普菲尔德网络(或 RBM)时,您有两个选项。第一个选项是您可以将每个可见节点的值设置为您正在触发的数据项的相应值。然后,您可以触发连续的激活,在每次激活时,每个节点的值都根据其连接到的其他可见节点的值进行更新。另一个选项是仅随机初始化可见节点,然后触发连续的激活,以产生其已经训练过的数据的随机示例。这通常被称为网络做白日梦。

  • 下一个时间步的每个可见节点的激活定义如下:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 在这里,W 是一个矩阵,定义了时间步骤 t 时每个节点 v 之间的连接强度。然后对 a 应用阈值规则,得到 v 的新状态:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 节点之间的权重 W 可以是正的也可以是负的,在激活时会导致节点相互吸引或排斥。霍普菲尔德网络还有一个连续变体,它只是用 tanh 函数替换了阈值函数。

  • 该网络的能量函数如下:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 用矩阵表示,如下所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 方程中的外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传是因为我们要遍历每对 i 和 j,因此重复计算每个连接(当 i=1 且 j=2 时,然后当 i=2 且 j=1 时又计算一次)。

  • 这里可能出现的问题是:为什么只有可见节点的模型?我会给它激活,然后触发一些状态更新。但是这个新状态给我提供了什么有用的信息呢?能量基模型的特性在这里变得有趣。不同的 W 配置将改变与状态 v 相关的能量函数。如果我们将网络状态设置为具有高能量函数的东西,即不稳定状态(想象一下许多弹跳的球);网络会在连续的迭代中移动到一个稳定状态。

  • 如果我们对数据集训练霍普菲尔德网络,学习得到一个对数据集中每个条目都有低能量的 W,然后我们可以从数据中创建一个损坏的样本,比如,通过随机交换一些输入的正负状态。因为损坏使得这些样本不太可能是原数据集的成员,所以这些损坏的样本可能现在处于高能量状态。如果我们激活网络的可见节点上的损坏样本,运行网络的更多迭代直到达到低能量状态;那么网络有很大的可能性已经重构了原始未损坏的模式。

  • 这导致 Hopfield 网络的一个用途是拼写纠正;你可以在单词库上对其进行训练,其中包含单词中使用的字母作为输入。然后,如果给出一个拼写错误的单词,它可能能够找到正确的原始单词。Hopfield 网络的另一个用途是作为内容寻址内存。计算机内存和人类内存之间的一个重要区别是,计算机内存是用地址存储的。如果计算机想要检索内存,它必须知道存储它的确切位置。另一方面,人类记忆可以给出该记忆的部分内容,该内容的特性可以用来恢复其余部分。例如,如果我需要记住我的密码,我知道我正在寻找的内容以及该内容的属性,一个四位数;我的大脑利用这一点返回值。

  • Hopfield 网络允许您存储内容寻址内存,这导致一些人推测人类记忆系统可能像 Hopfield 网络一样运作,人类的梦境是学习权重的尝试。

  • Hopfield 网络的最后一个用途是,它可以用于解决优化任务,例如旅行推销员任务。可以定义能量函数来表示要优化的任务的成本,网络的节点表示要优化的选择。同样,只需最小化网络权重的能量函数即可。

Boltzmann 机器

  • Boltzmann 机器也被称为随机 Hopfield 网络。在 Hopfield 网络中,节点激活是基于阈值设置的;但在 Boltzmann 机器中,激活是随机的。Boltzmann 机器中的节点值始终设置为 +1 或 -1。节点处于状态 +1 的概率定义如下: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 这里,a[i] 是针对 Hopfield 网络定义的该节点的激活。

为了学习我们的 Boltzmann 机器或 Hopfield 网络的权重,我们希望最大化给定 W 的数据集的可能性,这简单地是每个数据项的可能性的乘积:

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

这里,W 是权重矩阵,x*^((n))* 是大小为 N 的数据集 x 的第 n 个样本。现在让我们用来自我们的 Boltzmann 机器的实际可能性替换 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

这里,Z 如下方程所示:

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

如果您查看我们能量函数和 Z 的原始定义,那么x’应该是基于概率分布p(x)的每个可能配置的x。我们现在的模型中有 W 的一部分,因此分布将更改为外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。不幸的是,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传如果不是完全棘手的,至少是计算成本太高,无法计算的。我们需要在所有可能的 W 的所有可能的 x 的配置中进行计算。

计算这种难以处理的概率分布的一种方法是所谓的蒙特卡罗采样。这涉及从分布中取大量样本,并使用这些样本的平均值来近似真实值。我们从分布中取的样本越多,它的准确性就越高。假设无限数量的样本将完全符合我们想要的数量,而 1 将是一个非常差的近似值。

由于概率的乘积可能变得非常小,因此我们将使用对数概率;另外,让我们也包括Z的定义:

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

这里,x’是从网络学习的概率分布外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传中获取的网络状态样本。如果我们对节点 i 和 j 之间的单个权重取这个梯度,它看起来像这样:

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

这里,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在所有 N 个样本中只是节点 i 和 j 之间的相关性。另一种写法是对所有 N 个样本,对于每个权重ij,可以写成这样:

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

这个方程可以理解为学习的两个阶段,被称为正相和负相或者,更具诗意地说,醒和睡眠。在正相中,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传根据我们所给的数据增加权重。在负相中,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,我们从模型中根据当前权重抽取样本,然后将权重远离该分布。这可以被认为是减少模型生成的项目的概率。我们希望我们的模型尽可能地反映数据,因此我们希望减少模型生成的选择。如果我们的模型产生的图像与数据完全相同,那么这两个术语将互相抵消,达到平衡。

玻尔兹曼机和霍普菲尔德网络可用于优化和推荐系统等任务。它们需要大量的计算资源。必须测量每个节点之间的相关性,然后对模型进行每一步训练时的蒙特卡洛样本的范围。此外,它可以学习的模式种类有限。如果我们在图像上训练以学习形状,它无法学习位置不变的信息。图像左侧的蝴蝶与图像右侧的蝴蝶完全不同。在第五章图像识别中,我们将看一下卷积神经网络,它提供了这个问题的解决方案。

受限玻尔兹曼机

受限玻尔兹曼机与玻尔兹曼机相比进行了两项改变:第一是添加了隐藏节点,每个节点都连接到每个可见节点,但彼此不连接。 第二是删除了可见节点之间的所有连接。这导致在给定隐藏层的情况下,可见层中的每个节点都是条件独立的。给定可见层后,隐藏层中的节点也是条件独立的。我们现在还将向可见和隐藏节点添加偏置项。玻尔兹曼机也可以在每个节点上训练有偏置项,但这在等式中被忽略了以便简化符号。

  • 由于我们拥有的数据只针对可见单元,我们的目标是通过训练找到隐藏单元的配置,当与可见单元结合时,可以导致低能态。在我们的受限玻尔兹曼机中,状态x现在是可见和隐藏节点的完整配置。因此,我们将能量函数参数化为 E(v, h)。它现在看起来像这样:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 在这里,a 是可见节点的偏置向量,b 是隐藏节点的偏置向量,W 是可见和隐藏节点之间的权重矩阵。此处,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 是这两个向量的点积,等价于外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。现在我们需要对新能量函数计算出的偏置和权重进行梯度下降。

  • 由于层之间的条件独立性,我们现在有这个:

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

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

  • 这两个定义将用于归一化常数 Z。由于我们不再有可见节点之间的连接,我们的外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 发生了很大的变化:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 在这里,i 遍历每个可见节点,j 遍历每个隐藏节点。如果我们对不同参数取梯度,那么最终你会得到这个:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与以前一样,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传是通过从分布中取蒙特卡洛样本来近似的。这最后三个方程给出了我们迭代地训练给定数据集的所有参数的完整方法。训练将是通过这些梯度以某个学习速率更新我们的参数的情况。

从概念层面上再次说明这里发生了什么是值得的。v 表示可见变量,即我们正在学习的来自世界的数据。h 表示隐藏变量,即我们将训练以生成可见变量的变量。隐藏变量并不明确地代表任何东西,但通过训练和最小化系统中的能量,它们最终应该找到我们正在查看的分布的重要组成部分。例如,如果可见变量是一系列电影,如果一个人喜欢这部电影,则其值为 1,如果不喜欢,则为 0,那么隐藏变量可能会表示电影的流派,如恐怖片或喜剧片,因为人们可能有流派偏好,所以这是一种编码人们口味的有效方式。

如果我们随机生成隐藏变量的样本,然后基于此激活可见变量,那么它应该给我们一个看起来合理的电影口味集。同样,如果我们将可见变量设置为在隐藏和可见节点的连续激活过程中的随机电影选择,那么它应该使我们找到一个更合理的选择。

在 TensorFlow 中的实现

现在我们已经通过了数学,让我们看看它的实现是什么样子的。为此,我们将使用 TensorFlow。TensorFlow 是一个谷歌开源数学图形库,用于深度学习很受欢迎。它没有内置的神经网络概念,比如网络层和节点,这是一个更高级别的库,比如 Keras 才有;它更接近于像 Theano 这样的库。之所以选择它,是因为能够直接处理网络底层的数学符号,使用户能够更好地理解他们在做什么。

TensorFlow 可以直接通过 pip 安装,使用命令 pip install tensorflow 安装 CPU 版本,或者如果您有 NVidea GPU 启用的机器,则使用命令 pip install tensorflow-gpu 安装 GPU 版本。

我们将构建一个小型的受限玻尔兹曼机,并对其进行 MNIST 手写数字集的训练。我们将比可见节点少的隐藏节点数,这将迫使 RBM 学习输入中的模式。训练的成功将通过网络在经过隐藏层后重构图像的能力来衡量;为此,我们将使用原始图像与我们的重构之间的均方误差。完整的代码示例在 GitHub 仓库 github.com/DanielSlater/PythonDeepLearningSamplesrestricted_boltzmann_machine.py 文件中。

由于 MNIST 数据集被如此广泛地使用,TensorFlow 有一种很好的内置方式来下载和缓存 MNIST 数据集。只需简单地调用以下代码即可完成:

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/")

这将把所有 MNIST 数据下载到 "MNIST_data/" 目录下的 MNIST_data 文件夹中,如果还没有。mnist 对象有 traintest 属性,允许您访问 NumPy 数组中的数据。MNIST 图像都是 28x28 大小的,即每个图像有 784 个像素。我们将为我们的 RBM 需要每个像素一个可见节点:

input_placeholder = tf.placeholder("float", shape=(None, 784))

TensorFlow 中的占位符对象表示在使用期间将传递到计算图中的值。在这种情况下,input_placeholder 对象将保存我们给它的 MNIST 图像的值。"float" 指定了我们将传递的值的类型,shape 定义了维度。在这种情况下,我们想要 784 个值,每个像素一个,None 维度用于批处理。有一个 None 维度意味着它可以是任何大小;因此,这将允许我们发送可变大小的 784 长度的数组的批次:

weights = tf.Variable(tf.random_normal((784, 300), mean=0.0, stddev=1./784))

tf.variable 表示计算图上的变量。这是前述方程中的 W。传递给它的参数是变量值应该如何首先初始化的方式。在这里,我们将其初始化为一个大小为 784x300 的正态分布,即可见节点到隐藏节点的数量:

hidden_bias = tf.Variable(tf.zeros([300]))
visible_bias = tf.Variable(tf.zeros([784]))

这些变量将是我们前述方程中的 ab;它们被初始化为全部从值为 0 开始。现在我们将编写网络的激活:

hidden_activation = tf.nn.sigmoid(tf.matmul(input_placeholder, weights) + hidden_bias)

这代表了在前述方程中隐藏节点的激活,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。应用 sigmoid 函数后,这个激活可以被放入二项分布中,以便隐藏层中的所有值都变为 0 或 1,概率由给定;但事实证明,RBM 的训练与原始概率一样好。因此,没有必要通过这种方式复杂化模型:

visible_reconstruction = tf.nn.sigmoid(tf.matmul(hidden_activation, tf.transpose(weights)) + visible_bias)

现在我们有了可见层的重构,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。根据方程的规定,我们给它 hidden_activation,从中我们得到了可见层的样本:

final_hidden_activation = tf.nn.sigmoid(tf.matmul(visible_reconstruction, weights) + hidden_bias)

现在我们计算我们需要的最终样本,来自我们的visible_reconstruction的隐藏节点的激活。这相当于方程中的 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。我们可以继续使用连续迭代的隐藏和可视激活来从模型中获取一个更加无偏的样本。但只进行一次旋转就足够用于训练:

Positive_phase = tf.matmul(tf.transpose(input_placeholder), hidden_activation)
Negative_phase = tf.matmul(tf.transpose(visible_reconstruction), final_hidden_activation)

现在我们计算正相位和负相位。第一阶段是我们的 input_placeholder 中的样本和第一个 hidden_activation 之间的相关性,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传。然后,负相位获取 visible_reconstruction外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传final_hidden_activation之间的相关性,外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

LEARING_RATE = 0.01
weight_update = weights.assign_add(LEARING_RATE * (positive_phase – negative_phase))

在我们的weights变量上调用assign_add会创建一个操作,当运行时,会将给定的数量添加到变量中。这里,0.01 是我们的学习率,我们通过它来缩放正相位和负相位:

visible_bias_update = visible_bias.assign_add(LEARING_RATE * tf.reduce_mean(input_placeholder - visible_reconstruction, 0))
hidden_bias_update = hidden_bias.assign_add(LEARING_RATE * tf.reduce_mean(hidden_activation - final_hidden_activation, 0))

现在我们创建缩放隐藏和可视偏置的操作。这些也会被我们的 0.01 学习率缩放:

train_op = tf.group(weight_update, visible_bias_update, hidden_bias_update)

调用tf.group创建一个新操作,当调用时会同时执行所有的操作参数。我们总是希望同时更新所有的权重,所以创建一个单独的操作是有意义的:

loss_op = tf.reduce_sum(tf.square(input_placeholder - visible_reconstruction))

这个loss_op将为我们提供有关我们的训练效果的反馈,使用 MSE。请注意,这仅用于信息;不会针对此信号进行反向传播。如果我们想将这个网络作为一个纯自动编码器来运行,我们将在这里创建一个优化器,并激活它以最小化loss_op:?

session = tf.Session()
session.run(tf.initialize_all_variables())

然后,我们创建一个将用于运行计算图的会话对象。调用tf.initialize_all_variables()时,所有内容都会初始化到图中。如果你在 GPU 上运行 TensorFlow,这是硬件首先被接口化的地方。现在我们已经为 RBM 创建了每一步,让我们经历几个时代的 MNIST 运行,并看看它学到了多少:

current_epochs = 0

for i in range(10):
    total_loss = 0
    while mnist.train.epochs_completed == current_epochs:
        batch_inputs, batch_labels = mnist.train.next_batch(100)
        _, reconstruction_loss = session.run([train_op, loss_op], feed_dict={input_placeholder: batch_inputs})
        total_loss += reconstruction_loss

    print("epochs %s loss %s" % (current_epochs, reconstruction_loss))
    current_epochs = mnist.train.epochs_completed

每次我们调用mnist.train.next_batch(100),就会从mnist数据集中检索 100 张图片。在每个时代结束时,mnist.train.epochs_completed会增加 1,所有训练数据都会重新洗牌。如果你运行这个,你可能会看到类似这样的结果:

epochs 0 loss 1554.51
epochs 1 loss 792.673
epochs 2 loss 572.276
epochs 3 loss 479.739
epochs 4 loss 466.529
epochs 5 loss 415.357
epochs 6 loss 424.25
epochs 7 loss 406.821
epochs 8 loss 354.861
epochs 9 loss 410.387
epochs 10 loss 313.583

现在我们可以通过在mnist数据上运行以下命令来看看图像重构是什么样的:

reconstruction = session.run(visible_reconstruction, feed_dict={input_placeholder:[mnist.train.images[0]]})

这里有一些使用 300 个隐藏节点的重建图像的示例:

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

图 3. 使用不同数量的隐藏节点对受限玻尔兹曼机进行数字的重构

正如您所见,使用 300 个隐藏节点,不到像素数量的一半,它仍然可以几乎完美地重建图像,只有边缘周围有一点模糊。但是随着隐藏节点数量的减少,重建的质量也会降低。将隐藏节点减少到只有 10 个时,重建的图像可能会产生对于人眼来说看起来像是错误的数字,例如图 3 中的 2 和 3。

深信度网络

如果我们想象我们的 RBM 正在学习一组生成我们可见数据的潜在变量,并且我们感到好奇,我们可能会想知道:我们是否可以学习第二层生成隐藏层潜在变量的潜在变量?答案是肯定的,我们可以将先前训练的 RBM 堆叠在一起,以便学习有关可见数据的二阶、三阶、四阶等信息。这些连续的 RBM 层使网络能够学习越来越不变的表示底层结构:

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

图 4 深信度网络,包含许多链接的 RBM

这些堆叠的 RBM 被称为深度信度网络,是 Geoffrey Hinton 在他的 2002 年论文《通过最小化对比散度训练专家产品》中首次在 MNIST 上取得突破性成果时使用的深度网络。他发现有用的确切技术是在数据上训练连续的 RBM,每一层的尺寸都只稍微减小。一旦一个层训练到重建误差不再改善的程度,它的权重就被冻结,然后在其上堆叠一个新的 RBM,并再次训练直到误差率收敛。一旦整个网络训练完毕,最后添加一个监督层,以将最终 RBM 的隐藏层映射到数据的标签。然后使用整个网络的权重构建标准的深度前馈神经网络,使得这些预先计算的深度信度网络的权重能够通过反向传播进行更新。

起初,这些方法效果很好,但随着时间的推移,用于训练标准前馈网络的技术已经改进,RBMs 不再被认为是图像或语音识别的最佳方法。它们还存在一个问题,就是由于其两阶段性质,它们的训练速度可能会慢得多。但是它们在诸如推荐系统和纯无监督学习等方面仍然非常受欢迎。此外,从理论上讲,使用能量模型来学习深度表示是一种非常有趣的方法,并且为许多可以建立在该方法之上的扩展留下了大门。

摘要

在本章中,我们看到了许多实际深度学习实现核心的两种最强大的技术:自动编码器和受限玻尔兹曼机。

对于它们两个,我们都从一个隐藏层的浅层示例开始,并且探索了如何将它们堆叠在一起形成一个深度神经网络,能够自动学习高层次和分层次的特征,而不需要显式的人类知识。

它们都有类似的目的,但有一点小小的实质性差别。

自动编码器可以被看作是我们用来压缩数据的压缩过滤器,以保留其中最具信息量的部分,并能够确定性地重构原始数据的近似。自动编码器是对维度约简和非线性压缩的优雅解决方案,绕过了主成分分析(PCA)技术的限制。自动编码器的优点是,它们可以用作进一步分类任务的预处理步骤,其中每个隐藏层的输出是数据信息表示的可能级别之一,或者是其去噪和恢复版本。另一个巨大的优点是利用重构误差作为一个单点与其余组的不相似性的度量。这样的技术广泛用于异常检测问题,其中我们观察到的内容与内部表示之间的关系是恒定的和确定性的。在时间变化关系或取决于可观察维度的情况下,我们可以分组和训练不同的网络,以便适应,但一旦训练完成,网络就假设这些关系不受随机变化的影响。

另一方面,RBM 使用随机方法对样本进行采样和调整权重,以最小化重构误差。直觉可能是存在一些可见的随机变量和一些隐藏的潜在属性,目标是找出这两组之间的联系。举个例子,在电影评分的情况下,我们可以有一些隐藏的属性,比如电影类型,以及一些随机的观察,比如评分和/或评论。在这样的拓扑结构中,我们还可以将偏差项看作是调整每部电影不同内在流行度的一种方式。如果我们让用户从由哈利·波特阿凡达指环王角斗士泰坦尼克号组成的集合中评价他们喜欢哪部电影,我们可能会得到一个结果网络,其中两个潜在单元可能代表科幻电影和奥斯卡获奖电影:

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

可能的 RBM 示例,仅绘制与权重明显不同于 0 的链接。

虽然科幻和奥斯卡获奖的属性是确定性的(实际上,它们是电影的属性),但用户的评级受到概率方式的影响。学习到的权重是表征电影评分的概率分布的参数(例如,哈利·波特获得五星),假设用户喜欢特定的类型(例如,科幻)。

在这种关系不确定的情况下,我们更倾向于使用受限玻尔兹曼机(RBM)而不是自编码器。

总的来说,无监督特征学习是一种非常强大的方法,可以用最少的知识和人为干预来丰富特征工程。

根据一些基准测试([Lee, Pham and Ng, 2009] 和 [Le, Zhou and Ng, 2011])的结果,用于衡量不同特征学习技术准确性的,已经证明无监督特征学习相对于目前的最新技术有所提高。

不过,还存在一些挑战。如果您有一些知识,最好不要将其丢弃。我们可以在初始化阶段以先验的形式嵌入这些知识,在这一阶段我们可以手工设计网络拓扑和初始状态。

此外,由于神经网络本身已经很难解释,并且大多数时候被视为黑匣子,因此至少了解输入特征可能有所帮助。在我们的无监督特征学习中,我们希望直接使用原始数据。因此,理解模型的工作原理变得更加困难。

我们在本书中不会涉及这些问题。我们认为现在下结论还为时过早,深度学习的进一步发展以及人们和企业处理这些应用的方式将会趋于稳定和可靠。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/586879.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT - 创建Qt Widgets Application项目

在Qt中结合OpenGL使用&#xff0c;可以创建一个Qt Widgets应用程序项目。在创建项目时&#xff0c;您可以选择使用OpenGL模板来生成一个已经集成了OpenGL的项目。这个模板会自动帮助您集成OpenGL和Qt&#xff0c;并生成一个基本的OpenGL窗口。您可以在这个窗口中进行OpenGL的开…

vue快速入门(四十七)路由基本用法

注释很详细&#xff0c;直接上代码 上一篇 新增内容 路由基本用法多级路由方法演示路由样式修改示范路由默认页面写法路由默认样式名修改方法路由高亮的两种匹配方法解析 源码 src/router/index.js //导入所需模块 import Vue from "vue"; import VueRouter from &q…

高级变换与动画基础

1、平移+旋转 1.1 矩阵变换库cuon-matrix.js OpenGL提供了一系列有用的函数来帮助我们创建变换矩阵。例如,通过调用glTranslate()函数并传入在X,Y,Z轴上的平移距离,就可以创建一个平移矩阵。 glTranslatef(5,80,30) ==》 WebGL没有提供类似的矩阵函数,因此,如果想要使用…

【web安全】-- 命令执行漏洞详解

本文将从原理开始介绍命令执行漏洞并附有三个实例来供各位客官学习 文章目录 一、什么是命令执行漏洞二、出现的原因三、有可能存在命令执行漏洞的函数&#xff08;php&#xff09;1、利用一些函数来实现命令执行2、直接执行系统命令的函数 四、命令拼接符号1、Windows2、linux…

亿图图示使用教程

亿图图示是一款强大的图形绘制工具&#xff0c;可以用于创建流程图、思维导图、组织结构图等多种类型的图表。下面是一些基本的使用教程&#xff1a; 下载和安装&#xff1a;首先&#xff0c;你需要在官方网站上下载亿图图示的安装包&#xff0c;然后按照提示进行安装。 新建项…

如何使用Go语言进行并发安全的数据访问?

文章目录 并发安全问题的原因解决方案1. 使用互斥锁&#xff08;Mutex&#xff09;示例代码&#xff1a; 2. 使用原子操作&#xff08;Atomic Operations&#xff09;示例代码&#xff1a; 3. 使用通道&#xff08;Channels&#xff09; 在Go语言中&#xff0c;进行并发编程是常…

亚马逊云科技AWS和微软白送的云计算/IT福利不来领一下?

亚马逊和微软经常举办很多活动&#xff0c;免费给大家送各种礼品&#xff0c;如徽章、水杯、T恤、帽子、充电线、电脑包、手提袋等等&#xff0c;小李哥拿的已经手软&#xff0c;今天就也给大家分享下如何领取这些攻略。1️⃣亚马逊云AWS Community Builder周边 中文名亚马逊云…

一个好用的MQTT客户端软件

软件功能如下&#xff0c;实现的协议版本是 3.1.1 仅实现了常用的 CONNECT , PUBLISH , SUBSCRIBE 及相应的应答报文。支持以 Hex 格式显示接收的原始报文&#xff08;方便初学者学习&#xff09;。支持所有字段的自定义配置。支持保存与加载配置文件。 软件界面如下所示&…

笔记本上打造专属的LLama3聊天机器人

1. 引言 万众期待的 Meta 第三代 Llama 发布了&#xff0c;我想确保你知道如何以最佳方式部署这个最先进的LLM。在本教程中&#xff0c;我们将在笔记本上部署该模型&#xff0c;并指导大家一步步具体操作步骤。 闲话少说&#xff0c;我们直接开始吧&#xff01; 2. LLama3 …

K8s容器部署maven项目

最近在整一整套devops自动化持续集成的东西&#xff0c;一开始就做好了踩坑的准备。 failed to verify certificate: x509: certificate signed by unknown authority 今天在执行kubectl get nodes的时候报的证书验证问题&#xff0c;看了一圈首次搭建k8s的都是高频出现的问题…

《代环问题》

代环问题 什么是代环代环的结构 怎么判断代环还是不代环呢&#xff1f;举一反三1&#xff1a;为什么一定会相遇,有没有可能会错过永远追不上? 请证明2:slow一次走一步&#xff0c;那么fast走3、4、5、6......n步可不可以?N是奇数C是偶数时&#xff0c;那就永远追不上这个条件…

Linux 安装Python3.12.0

下载源文件。 wget https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tgz 解压。 tar -zxvf Python-3.12.0.tgz 进入文件夹。 cd Python-3.12.0 指定安装目录。 ./configure --prefix/usr/local/python3.12/ 1 编译&#xff0c;把源码包里面的代码编译成linux服务器可以…

【JAVASE】带你了解的方法魅力

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青-CSDN博客 目标&#xff1a; 1. 掌握方法的定义以及使用 2. 掌握方法传参 3. 掌握方法重载 …

自学Java要到什么程度才足够能力去实习和就业?

引言 Java&#xff0c;作为当今软件开发领域的主流编程语言之一&#xff0c;对于初学者而言&#xff0c;明确掌握到什么程度才能开始寻找实习和入职机会是至关重要的。这涉及到对Java知识体系的理解深度、技能掌握程度以及实际项目经验的积累。 本文将分别从实习和入职两个不…

ElasticSearch教程入门到精通——第二部分(基于ELK技术栈elasticsearch 7.x新特性)

ElasticSearch教程入门到精通——第二部分&#xff08;基于ELK技术栈elasticsearch 7.x新特性&#xff09; 1. JavaAPI-环境准备1.1 新建Maven工程——添加依赖1.2 HelloElasticsearch 2. 索引2.1 索引——创建2.2 索引——查询2.3 索引——删除 3. 文档3.1 文档——重构3.2 文…

Golang | Leetcode Golang题解之第59题螺旋矩阵II

题目&#xff1a; 题解&#xff1a; func generateMatrix(n int) [][]int {matrix : make([][]int, n)for i : range matrix {matrix[i] make([]int, n)}num : 1left, right, top, bottom : 0, n-1, 0, n-1for left < right && top < bottom {for column : lef…

PotatoPie 4.0 实验教程(33) —— FPGA实现摄像头视频图像叠加

链接直达 https://item.taobao.com/item.htm?ftt&id776516984361 什么是视频水印&#xff1f; 视频水印就是图像叠加&#xff0c;跟画中画&#xff0c;或者是OSD是一样的原理&#xff0c;都是在视频的行场数据流上进行替换操作&#xff0c;比如叠加可以直接用水印图的数…

Vue.js课后练习(登录注册和大小比较)

第一题 请编写登录页面和注册页面&#xff0c;通过动态组件实现动态切换页面中显示的组件&#xff0c;效果如图1和图2所示。 图1 登录页面 图2 注册页面 代码&#xff1a; my.vue代码: <template>登录 </template><script setup> </script><st…

K8S执行完毕kubectl init xxx 执行 kubectl get ns 报错才connect: connection refused

问题场景&#xff1a; 在安装完毕K8S之后&#xff0c;执行 kubectl get ns 报错&#xff1a; [rootmaster ~]# kubectl get pods E0501 08:34:55.770030 11268 memcache.go:265] couldnt get current server API group list: Get "https://192.168.1.100:6443/api?ti…

RAGFlow:安装与体验

服务器需要有docker,或者直接访问官方提供的demo: https://demo.ragflow.io/ docker-compose安装 需要确保 vm.max_map_count 不小于 262144 【更多】:sysctl -w vm.max_map_count=262144 克隆仓库:$ git clone https://github.com/infiniflow/ragflow.git 进入 doc…
最新文章