在学习神经网络和深度学习时,你可能会搜索到大量的资源,从博客文章到 MOOC (如 Coursera 和 Udacity 提供的那些在线课程),甚至还有一些书……但是,这些资源的质量参差不齐,我在前几年开始探索这个主题时就已经对此有所了解。既然你开始阅读本书,就说明你之前了解的所有关于神经网络的解释在一定程度上有所欠缺。刚开始学习这一主题时,我有过同样的经历。就像盲人摸象似的,各种各样的解释描述了不同的方面,但都没有提供一个整体的描述。基于这种情况,我便开始编写本书。
现有的神经网络资源主要分为两类。一类资源侧重于概念领域和数学领域,包含两个方面:一方面是用两端有箭头的线连接圆来形成示意图,这种方式在解释神经网络时非常常见;另一方面是用大量数学公式来解释运行机制,这样做有助于“理解理论”。这类资源的一个典型例子是 Ian Goodfellow 等人所著的《深度学习》,这本书非常优秀。
另一类资源则包含密集的代码块,在运行这些代码块时,它们似乎会显示随时间减少的损失值。也就是说,神经网络会“学习”。例如,PyTorch 文档中的以下示例确实定义并训练了一个基于随机生成数据的简单神经网络:
# N是批次大小,D_in是输入维度,H是隐藏维度,D_out是输出维度
N, D_in, H, D_out = 64, 1000, 100, 10
# 创建随机输入数据和输出数据
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)
# 随机初始化权重
w1 = torch.randn(D_in, H, device=device, dtype=dtype)
w2 = torch.randn(H, D_out, device=device, dtype=dtype)
learning_rate = 1e-6
for t in range(500):
# 前向传递:计算预测值y
h = x.mm(w1)
h_relu = h.clamp(min=0)
y_pred = h_relu.mm(w2)
# 计算并输出损失值
loss = (y_pred - y).pow(2).sum().item()
print(t, loss)
# 反向计算w1和w2相对于损失值的梯度
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h < 0] = 0
grad_w1 = x.t().mm(grad_h)
# 使用梯度下降更新权重
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
当然,像这样的解释并不能让我们深入了解“工作机制”,如基本的数学原理、其中的独立神经网络组件以及它们协同工作的方式,等等 。
怎么样才能更好地解释神经网络呢?对于这个问题,可以参考关于其他计算机科学概念的解释。如果你想学习排序算法,那么会发现一些教科书中包含以下内容。
尽管我认为理应用这种方式对神经网络展开介绍,但很少有人(甚至从未有过)会全面地解释神经网络的这些内容,本书旨在填补这一空白。
虽然不是专业的研究人员,也没有取得博士学位,但是我曾经熟练地教授数据科学:我曾与 Metis 公司合作辅导过几个数据科学训练营,并在接下来的一年中走访世界各地,为许多不同行业的公司举办了为期 1 到 5 天的研讨会,向那里的员工解释机器学习和软件工程的基本概念。我一直热爱教学,致力于解决如何最好地解释技术概念这一问题。近年来,我重点关注机器学习和统计学中的概念。对于神经网络,我发现最具挑战性的部分是,为“什么是神经网络”传达正确的“思维模型”。这主要是因为,了解神经网络需要的不是一个而是多个思维模型,每一个都说明了神经网络工作方式的不同方面(而且每个方面都必不可少)。为了说明这一点,来看一个例子。以下 4 个句子都是“什么是神经网络”这一问题的正确答案。
事实上,很多人可能已经听过其中一个或多个解释,并且可能对神经网络的工作原理和含义有一定的了解。但是,要完全理解它们,必须了解它们的所有内容并展示它们之间的关系。例如,神经网络如何表示为与“层”的概念相关联的计算图?此外,为了使所有这些解释更加精确,我们将通过 Python 从零开始实现所有这些概念,并将它们融合在一起,形成可以在笔记本计算机上训练的有效神经网络。尽管我们会在实现细节上花费大量时间, 但是通过 Python 实现神经网络模型的目的是巩固并精确地理解概念,而不是尽可能简洁或高效地编写一个神经网络库。
本书旨在帮助你充分地理解所有这些思维模型以及它们对神经网络实现方式的影响,这样学习相关概念或在这个领域进一步做项目会变得容易得多。
前 3 章是最重要的部分,每一章都可以用一本书来讨论,当然,这里精简了内容。
第1章说明如何将数学函数表示为一系列连接在一起构成计算图的运算,并演示如何利用这种表示方法和微积分的链式法则,来计算函数的输出相对于其输入的导数。这一章将介绍一个非常重要的运算,即矩阵乘法,并说明如何让它既能够适应用这种方式表示的数学函数,又可以计算最终进行深度学习所需的导数。
第2章直接使用第1章中创建的构成要素来构建和训练模型,从而解决实际问题。具体地说,就是使用它们来构建线性回归模型和神经网络模型,并基于真实的数据集预测房价。这一章提出,神经网络比线性回归具有更好的性能,并试图直观地解释原因。在这一章中构建模型所采用的“基本原理”方法,可以帮助你很好地理解神经网络的工作原理,同时也展示了逐步的、纯粹基于基本原理的方法在定义深度学习模型方面的局限性。这便引出了第3章的内容。
第3章从前两章基于基本原理的方法中提取构成要素,并使用它们来构建构成所有深度学习模型的“更高层次”的组件,即
Layer
类、
Optimizer
类等。这一章的结尾在第2章的同一个数据集上训练一个从零定义的深度学习模型,该模型比简单的神经网络具有更好的性能。事实证明,当基于本书中使用的标准训练技术进行训练时,很少有理论保证具有给定架构的神经网络能够在给定的数据集上找到良好的解决方案。第4章介绍最重要的训练技术,这些技术通常会使神经网络更有可能找到好的解决方案。另外,书中会尽可能从数学角度说明它们发挥作用的原理。
第5章介绍 卷积神经网络 (convolutional neural network,CNN)背后的基本思想,它是一种专门用于理解图像的神经网络架构。关于 CNN 的解释有很多,本书重点介绍 CNN 的核心要点及其与常规神经网络的区别。比如说,CNN 如何将神经元的每一层都组织成“特征图”,以及如何通过卷积过滤器将其中的两层(每层都由多个特征图组成)连接在一起。此外,就像从零开始对神经网络中的常规层进行编码一样,这一章也将从零开始对卷积层进行编码,加深对其工作原理的理解。
第 1 ~ 5 章构建了一个微型神经网络库,该库将神经网络定义为一系列
Layer
类,
Layer
类本身由一系列
Operation
类组成,这些
Operation
类向前发送输入,向后发送梯度。实际上,这不是大多数神经网络的实现方式。相反,它们使用一种叫作
自动微分
(automatic differentiation)的技术。第6章对自动微分进行简单说明,并用它来引出这一章的核心主题——
循环神经网络
(recurrent neural network,RNN)。这种神经网络架构通常用于理解数据点按顺序出现的数据,例如时间序列数据或自然语言数据。这一章还会解释 vanilla RNN 及其两种变体 GRU 和 LSTM 的工作原理,当然,也会从零开始实现这 3 种神经网络。在整个过程中,你将了解 RNN 及与其变体之间的共同点和不同点。
第7章展示如何使用高性能的开源神经网络库 PyTorch,来实现第 1 ~ 6 章中从零开始执行的操作。学习这样的框架对于继续学习神经网络至关重要,但是如果不先深入了解神经网络的工作方式和原理,就接触并学习一个框架,那么从长远来看会严重限制今后的学习。本书各章的目的是让你有能力编写高性能的神经网络(通过教你使用 PyTorch),同时还能让你长期学习并取得成功(在学习 PyTorch 之前先了解基本原理)。最后,这一章将简要说明神经网络如何用于无监督学习。
本书的目标就是成为我在学习神经网络和深度学习时所渴望拥有的那样一本书,希望你从中有所收获。加油!
本书采用了以下排版约定。
表示新术语或重点强调的内容。
constant width
)
表示程序片段,以及正文中出现的变量、函数名、数据类型、环境变量、语句和关键字等。
constant width bold
)
表示应该由用户直接输入的命令或其他文本。
constant width italic
)
表示应该由用户输入的值或根据上下文确定的值替换的文本。
勾股定理表示为 。
该图标表示一般的注记。
补充材料(示例代码、练习等)可以从 https://github.com/SethHWeidman/DLFS_code下载 。
本书旨在帮助你完成工作。一般来说,你可以在自己的程序或文档中使用本书提供的示例代码。除非需要复制大量代码,否则无须联系我们获得许可。比如,使用本书中的几个代码片段编写程序无须获得许可,销售或分发 O'Reilly 图书的示例光盘则需要获得许可;引用本书中的示例代码回答问题无须获得许可,将本书中的大量示例代码放到你的产品文档中则需要获得许可。
我们很希望但并不强制要求你在引用本书内容时加上引用说明。引用说明通常包括书名、作者、出版社和 ISBN,比如“ Deep Learning from Scratch by Seth Weidman (O'Reilly). Copyright 2019 Seth Weidman, 978-1-492-04141-2”。
如果你觉得自己对示例代码的用法超出了上述许可的范围,欢迎你通过 permissions@oreilly.com与我们联系。
近 40 年来,O'Reilly Media 致力于提供技术和商业培训、知识和卓越见解,来帮助众多公司取得成功。
我们拥有独一无二的专家和革新者组成的庞大网络,他们通过图书、文章、会议和我们的在线学习平台分享他们的知识和经验。O'Reilly 的在线学习平台允许你按需访问现场培训课程、深入的学习路径、交互式编程环境,以及 O'Reilly 和 200 多家其他出版商提供的大量文本和视频资源。有关的更多信息,请访问 https://oreilly.com。
请把对本书的评价和问题发给出版社。美国:
O'Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
中国:
北京市西城区西直门南大街 2 号成铭大厦 C 座 807 室(100035)
奥莱利技术咨询(北京)有限公司
O'Reilly 的每一本书都有专属网页,你可以在那儿找到本书的相关信息,包括勘误表、示例代码以及其他信息 。本书的网页是 https://oreil.ly/dl-from-scratch。
对于本书的评论和技术性问题,请发送电子邮件到 bookquestions@oreilly.com。
要更多地了解 O'Reilly 图书、培训课程、会议和新闻,请访问以下网站:http://www.oreilly.com。
我们在 Facebook 的地址如下:http://facebook.com/oreilly。
请关注我们的 Twitter 动态:http://twitter.com/oreillymedia。
我们的 YouTube 视频地址如下:http://www.youtube.com/oreillymedia。
我要感谢编辑 Melissa Potter 和 O'Reilly 团队,他们为本书提供了认真且及时的反馈,并在整个出版过程中详细解答我的疑问。
我要特别感谢一些人,正是他们的努力让机器学习中的技术概念更容易为大多数人所接受,这直接影响了我。我有幸结识了其中一部分人,他们是 Brandon Rohrer、Joel Grus、Jeremy Watt 和 Andrew Trask。
我要感谢我在 Metis 公司和 Facebook 公司的领导,他们十分支持我写作本书。
我要特别感谢 Mat Leonard,在我们决定各自发展之前,他一度参与了本书的写作。Mat 帮助组织了与本书相关的小型图书馆示例 lincoln 的代码,并在前两章的初稿方面给予我非常有用的反馈,同时为这两章撰写了大部分内容。
最后,我要感谢我的朋友 Eva 和 John,他俩都直接鼓励并启发我真正开始写作。我还要感谢我在旧金山的许多朋友,他们理解我几个月以来为本书投入了大量的时间,表达了对本书的关心,并且在我需要时坚定地支持我。
扫描下方二维码,即可获取电子书相关信息及读者群通道入口。