原文:Grokking Deep Learning
译者:飞龙
协议:CC BY-NC-SA 4.0
本章
- 什么是深度学习框架?
- 张量简介
- 自动求导简介
- 加法反向传播是如何工作的?
- 如何学习一个框架
- 非线性层
- 嵌入层
- 交叉熵层
- 循环层
“无论我们基于碳还是硅,在本质上都没有区别;我们都应该得到适当的尊重。”
亚瑟·C·克拉克,2010 年:《2001 太空漫游》(1982 年)
什么是深度学习框架?
好的工具可以减少错误,加快开发速度,并提高运行时性能
如果你长期关注深度学习,你可能已经遇到了一些主要的框架,例如 PyTorch、TensorFlow、Theano(最近已弃用)、Keras、Lasagne 或 DyNet。在过去几年中,框架的发展非常迅速,尽管所有框架都是免费的开源软件,但每个框架周围都有一股竞争和团结的气氛。
到目前为止,我一直在避免讨论框架的话题,因为首先,了解这些框架底层的工作原理对于你来说极其重要,这可以通过自己实现算法(从 NumPy 的零开始)来实现。但现在我们将过渡到使用框架,因为接下来你将要训练的网络——长短期记忆网络(LSTMs)——非常复杂,描述它们实现的 NumPy 代码难以阅读、使用或调试(梯度无处不在)。
深度学习框架的创建正是为了减轻这种代码复杂性。特别是如果你希望在 GPU 上训练神经网络(提供 10-100 倍的训练速度),深度学习框架可以显著减少代码复杂性(减少错误并提高开发速度),同时提高运行时性能。出于这些原因,它们在研究社区中几乎被普遍使用,对深度学习框架的深入了解将成为你成为深度学习用户或研究人员的旅程中必不可少的。
但我们不会跳入你听说过的任何深度学习框架,因为这会阻碍你了解复杂模型(如 LSTMs)底层的工作原理。相反,你将根据框架发展的最新趋势构建一个轻量级的深度学习框架。这样,你将毫无疑问地了解框架在用于复杂架构时的作用。此外,自己构建一个小框架应该会为使用实际的深度学习框架提供一个平稳的过渡,因为你已经熟悉了 API 及其底层的功能。我发现这项练习很有益,我在构建自己的框架中学到的教训在尝试调试麻烦的模型时特别有用。
框架是如何简化你的代码的?抽象地说,它消除了多次重复编写代码的需要。具体来说,深度学习框架最有益的部分是其对自动反向传播和自动优化的支持。这些功能让你只需指定模型的正向传播代码,框架会自动处理反向传播和权重更新。大多数框架甚至通过提供高级接口来简化常见的层和损失函数,使正向传播代码更容易编写。
张量简介
张量是向量和矩阵的抽象形式
到目前为止,我们一直在使用向量和矩阵作为深度学习的基本数据结构。回想一下,矩阵是一系列向量的列表,而向量是一系列标量(单个数字)的列表。张量是这种嵌套数字列表形式的抽象版本。向量是一维张量。矩阵是二维张量,更高维度的称为n维张量。因此,一个新的深度学习框架的开始是构建这种基本类型,我们将称之为:
GPT plus 代充 只需 145
这是这种基本数据结构的第一个版本。请注意,它将所有数值信息存储在 NumPy 数组()中,并且支持一个张量操作(加法)。添加更多操作相对简单:在张量类上创建更多具有适当功能的功能。
自动梯度计算(autograd)简介
以前,你手动执行了反向传播。让我们让它自动化吧!
在第四章中,你学习了关于导数的内容。从那时起,你一直在为每个训练的神经网络手动计算导数。回想一下,这是通过在神经网络中向后移动来完成的:首先计算网络的输出处的梯度,然后使用该结果来计算下一个组件的导数,依此类推,直到架构中的所有权重都有正确的梯度。这种计算梯度的逻辑也可以添加到张量对象中。让我向你展示我的意思。新的代码以粗体显示:
此方法引入了两个新概念。首先,每个张量都获得两个新属性。是一个列表,包含用于创建当前张量的任何张量(默认为)。因此,当两个张量和相加时,有两个,即和。是一个相关功能,它存储创建过程中使用的指令。因此,执行 = + 创建了一个包含三个节点(、和)和两个边( -> 和 -> )的计算图。每个边都标记为。此图允许你递归地反向传播梯度。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0235-01.jpg
在这个实现中引入的第一个新概念是,每当进行数学运算时,自动创建这个图。如果你对进行了进一步的操作,图将继续与指向的任何结果新变量相关联。
在的这个版本中引入的第二个新概念是使用这个图来计算梯度。当你调用时,它会根据应用于创建()的函数,发送和的正确梯度。查看图,你将一个梯度向量()放在上,然后它们被应用到它们的父节点上。正如你在第四章中学到的,通过加法进行反向传播意味着在反向传播时也要应用加法。在这种情况下,因为只有一个梯度要加到或上,所以你将上的梯度复制到和上:
GPT plus 代充 只需 145
这种形式的 autograd 最优雅的部分可能是它还可以递归地工作,因为每个向量都会在其所有上调用:
|
| 输出
GPT plus 代充 只需 145
|
一个快速的检查点
Tensor 中的所有内容都是已经学到的知识的另一种形式
在继续之前,我想首先承认,即使考虑梯度在图形结构上流动可能感觉有点牵强或费劲,但与你已经使用过的内容相比,这并不是什么新鲜事。在关于 RNN 的上一章中,你在一个方向上进行了正向传播,然后在(虚拟图)激活上进行了反向传播。
你并没有在图形数据结构中明确编码节点和边。相反,你有一个层的列表(字典),并手动编码了正向和反向传播操作的正确顺序。现在你正在构建一个很好的接口,这样你就不需要写那么多代码了。这个接口让你可以递归地进行反向传播,而无需手动编写复杂的反向传播代码。
本章主要涉及一些理论性的内容。它主要讲述的是学习深度神经网络时常用的工程实践。特别是,在正向传播过程中构建的这种图结构被称为动态计算图,因为它是在正向传播过程中即时构建的。这种类型的 autograd 存在于较新的深度学习框架中,如 DyNet 和 PyTorch。而像 Theano 和 TensorFlow 这样的旧框架则有一个所谓的静态计算图,它是在正向传播开始之前就定义好的。
通常,动态计算图更容易编写/实验,而静态计算图由于底层的一些复杂逻辑,运行速度更快。但请注意,动态和静态框架最近正朝着中间发展,允许动态图编译为静态图(以获得更快的运行时间)或允许静态图动态构建(以获得更易实验)。从长远来看,你很可能会两者都拥有。主要区别在于正向传播是在图构建期间发生还是在图已经定义之后发生。在这本书中,我们将坚持使用动态的。
本章的主要目的是帮助您为现实世界中的深度学习做好准备,在那里您将花费 10%(或更少)的时间思考新的想法,90%的时间用于弄清楚如何让深度学习框架协同工作。有时调试这些框架可能极其困难,因为大多数错误不会引发错误并打印出堆栈跟踪。大多数错误隐藏在代码中,导致网络无法按预期训练(即使它看起来似乎在训练)。
所有这些只是为了真正深入本章。当你在凌晨 2 点追逐一个优化错误,这个错误阻止你获得那个美味的最新分数时,你会很高兴你做了这件事。
被多次使用的张量
基本 autograd 有一个相当讨厌的错误。让我们把它压扁!
当前版本的只支持将反向传播到变量一次。但有时,在正向传播过程中,你会多次使用同一个张量(神经网络的权重),因此图的不同部分将反向传播梯度到同一个张量。但当前代码在反向传播到被多次使用的变量时(是多个子张量的父张量)会计算错误的梯度。我的意思如下:
在这个例子中,变量在创建的过程中被使用了两次。因此,其梯度应该是两个导数的总和:。这里展示了由这一系列操作创建的结果图。注意现在有两个指针指向:因此,它应该是来自和的梯度的总和。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0237-01.jpg
但当前的实现只是用前一个导数覆盖每个导数。首先,应用其梯度,然后它被的梯度覆盖。我们需要改变梯度写入的方式。
将 autograd 升级以支持多用途张量
添加一个新函数,并更新三个旧函数
对对象的这次更新增加了两个新功能。首先,梯度可以累积,以便当变量被多次使用时,它从所有子张量接收梯度:
GPT plus 代充 只需 145
- 1 跟踪张量有多少个子张量
- 2 检查张量是否从每个子张量接收到了正确数量的梯度
- 3 检查是否可以反向传播,或者你是否正在等待梯度,如果是,则递减计数器
- 4 从多个子节点累积梯度
- 5 开始实际的反向传播
此外,你创建了一个计数器,在反向传播期间计算每个子节点接收到的梯度数量。这样,你也可以防止变量意外地从同一个子节点两次进行反向传播(这会抛出异常)。
第二个新增功能是一个具有相当冗长名称的新函数。这个函数的目的是计算一个张量是否从其图中的所有子节点接收到了梯度。通常,每当在图中的中间变量上调用时,它会立即对其父节点调用。但由于一些变量从多个父节点接收梯度值,每个变量需要等待直到它具有局部的最终梯度后,再调用对其父节点进行反向传播。
如前所述,从深度学习理论的角度来看,这些概念并不新颖;这些都是深度学习框架试图面对的工程挑战。更重要的是,它们是你在标准框架中调试神经网络时将面临的那种挑战。在继续之前,花点时间玩一下这段代码,熟悉它。尝试删除不同的部分,看看它以各种方式崩溃。尝试两次调用。
加法反向传播是如何工作的?
让我们研究这个抽象,以了解如何添加对更多函数的支持
到目前为止,这个框架已经达到了一个令人兴奋的地方!你现在可以通过将函数添加到类并添加其导数到方法来支持任意操作。对于加法,有以下方法:
GPT plus 代充 只需 145
对于通过加法函数的反向传播,以下是方法中的以下梯度传播:
注意,在这个类中其他地方并没有处理加法。通用的反向传播逻辑被抽象化,所以所有必要的加法定义都包含在这两个地方。进一步注意,反向传播逻辑在每次加法中都会调用两次,一次针对每个参与加法的变量。因此,反向传播逻辑的默认设置是始终将反向传播应用于图中的每个变量。但有时,如果变量关闭了自动微分( == ),则会跳过反向传播。这个检查是在方法中进行的:
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0240-01_alt.jpg
尽管加法的反向传播逻辑将梯度反向传播到所有对其有贡献的变量,但除非将该变量的 设置为 ,否则反向传播不会运行(对于 或 分别)。注意,在 的第一行中,创建的张量(稍后是 )的 仅当 == == 时才为 。
添加对否定的支持
让我们修改支持加法以支持否定
现在加法功能已经正常工作,你应该能够复制并粘贴加法代码,进行一些修改,并为否定添加自动微分支持。让我们试试。 函数的修改内容以粗体显示:
GPT plus 代充 只需 145
几乎所有内容都是相同的。你不接受任何参数,所以“other”参数已在多个地方被移除。让我们看看你应该添加到 中的反向传播逻辑。 函数反向传播逻辑的修改内容以粗体显示:
因为 函数只有一个创建者,所以你只需要调用一次 。如果你想知道如何知道正确的梯度进行反向传播,请回顾第 4、5 和 6 章。你现在可以测试新的代码了:
GPT plus 代充 只需 145
当你使用 而不是 进行前向传播时,反向传播的梯度也会翻转符号。此外,你不需要对一般的反向传播系统做任何修改来使其工作。你可以根据需要创建新的函数。让我们添加一些吧!
添加对其他函数的支持
减法、乘法、求和、扩展、转置和矩阵乘法
使用你为加法和否定学到的相同思想,让我们添加几个其他函数的前向和反向传播逻辑:
我们之前讨论了所有这些函数的导数,尽管 和 可能看起来有些陌生,因为它们有新的名称。 在张量的一个维度上执行加法;换句话说,假设你有一个名为 的 2 × 3 矩阵:
GPT plus 代充 只需 145
函数在一个维度上求和。 将得到一个 1 × 3 矩阵(长度为 3 的向量),而 将得到一个 2 × 1 矩阵(长度为 2 的向量):
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0243-00_alt.jpg
你使用 来通过 进行反向传播。这是一个复制数据沿一个维度的函数。给定相同的矩阵 ,沿第一个维度复制会得到两个张量副本:
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0243-01_alt.jpg
为了明确起见, whereas 移除一个维度(2 × 3 -> 只剩 2 或 3), 添加一个维度。2 × 3 的矩阵变成了 4 × 2 × 3。您可以将其视为一个包含四个张量的列表,每个张量都是 2 × 3。但如果您扩展到最后一个维度,它将沿着最后一个维度复制,因此原始张量中的每个条目都变成了一个条目的列表:
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0243-02_alt.jpg
因此,当您对一个在该维度有四个条目的张量执行 时,您需要在反向传播时对梯度执行 。
您现在可以将相应的反向传播逻辑添加到 方法中:
- 1 通常是一个激活
- 2 通常是一个权重矩阵
如果您不确定这个功能,最好的做法是回顾一下您在第六章中是如何进行反向传播的。那一章有展示反向传播每个步骤的图表,其中一部分我在这里又展示了一遍。
梯度从网络的末端开始。然后您通过调用与用于将激活向前传递到网络中的函数相对应的函数,将错误信号 反向传递到网络中。如果最后一个操作是矩阵乘法(并且确实是),您通过在转置矩阵上执行矩阵乘法(点积)来进行反向传播。
在以下图像中,这发生在 这一行。在之前的代码中,它发生在 (加粗显示)。您正在执行与之前(按前向传播的相反顺序)完全相同的操作,但代码组织得更好。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0245-01_alt.jpg
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0245-02_alt.jpg
使用 autograd 训练神经网络
您不再需要编写反向传播逻辑!
这可能看起来需要相当多的工程努力,但很快就会得到回报。现在,当您训练神经网络时,您不必编写任何反向传播逻辑!作为一个玩具示例,这里有一个用于手动反向传播的神经网络:
GPT plus 代充 只需 145
- 1 预测
- 2 比较
- 3 均方误差损失
- 4 学习;这是反向传播的部分。
您必须以这种方式进行前向传播,使得 、 和 作为变量存在,因为您稍后需要它们。然后您必须将每个梯度反向传播到相应的权重矩阵,并适当地更新权重。
GPT plus 代充 只需 145
- 1 预测
- 2 比较
- 3 学习
但有了新潮的 autograd 系统,代码要简单得多。您不需要保留任何临时变量(因为动态图会跟踪它们),也不需要实现任何反向传播逻辑(因为 方法处理这个)。这不仅更方便,而且您在反向传播代码中犯愚蠢错误的可能性更小,从而降低了出错的可能性!
在继续之前,我想指出这个新实现中的一个风格问题。注意,我把所有参数都放在了一个列表中,这样我就可以在执行权重更新时遍历它们。这是对下一个功能功能的一点暗示。当你有一个自动微分系统时,随机梯度下降的实现变得非常简单(它只是最后的那个循环)。让我们试着把它也做成一个类。
添加自动优化
让我们创建一个随机梯度下降优化器
从字面上看,创建一个名为随机梯度下降优化器的东西可能听起来很困难,但实际上只是从上一个例子中复制粘贴,加上一点老式的面向对象编程:
GPT plus 代充 只需 145
之前的神经网络进一步简化如下,与之前完全相同的结果:
- 1 预测
- 2 比较
- 3 学习
添加对层类型的支持
你可能熟悉 Keras 或 PyTorch 中的层类型
到目前为止,你已经完成了新深度学习框架中最复杂的部分。接下来的工作主要是向张量添加新函数,创建方便的高阶类和函数。在几乎所有框架中,最常见的一种抽象是层抽象。它是一组常用的正向传播技术,封装在一个简单的 API 中,并带有某种方法来调用它们。以下是一个简单线性层的示例:
GPT plus 代充 只需 145
这里没有什么特别新的。权重被组织到一个类中(并且我添加了偏置权重,因为这是一个真正的线性层)。你可以一次性初始化这个层,使得权重和偏置都使用正确的尺寸,并且始终使用正确的正向传播逻辑。
还要注意,我创建了一个抽象类,它有一个单一的 getter。这允许更复杂的层类型(例如包含其他层的层)。你只需要重写来控制稍后传递给优化器(如上一节中创建的类)的张量。
包含层的层
层也可以包含其他层
最受欢迎的层是顺序层,它正向传播一个层的列表,其中每个层将其输出馈送到下一个层的输入:
- 1 预测
- 2 比较
- 3 学习
损失函数层
一些层没有权重
你也可以创建函数层,这些函数作用于输入。这类层中最受欢迎的版本可能是损失函数层,例如均方误差:
GPT plus 代充 只需 145
- 1 预测
- 2 比较
- 3 学习
如果您能原谅重复,再次强调,这里没有什么特别新的。在底层,最后几个代码示例都执行了完全相同的计算。只是自动微分正在执行所有的反向传播,正向传播步骤被封装在漂亮的类中,以确保功能按正确的顺序执行。
如何学习一个框架
过于简化地说,框架是自动微分加上一系列预构建的层和优化器
您已经能够(相当快速地)使用底层自动微分系统编写各种新的层类型,这使得组合任意功能层变得相当容易。说实话,这是现代框架的主要功能,消除了为正向和反向传播手动编写每个数学运算的需要。使用框架大大增加了您从想法到实验的速度,并将减少您代码中的错误数量。
将框架视为仅是一个与大量层和优化器耦合的自动微分系统,这有助于您学习它们。我预计您将能够快速地从本章转向几乎任何框架,尽管与在此处构建的 API 最相似的框架是 PyTorch。无论如何,为了您的参考,花点时间浏览一下几个大型框架中的层和优化器列表:
学习新框架的一般工作流程是找到最简单的代码示例,对其进行调整,了解自动微分系统的 API,然后逐步修改代码示例,直到达到您关心的任何实验。
GPT plus 代充 只需 145
在我们继续之前,我正在向 添加一个方便的函数,这样您在第一次调用 时就不必传入 1 的梯度。严格来说,这不是必需的——但它很方便。
非线性层
让我们在 Tensor 中添加非线性函数,然后创建一些层类型
对于下一章,您将需要 和 。让我们将它们添加到 类中。您很久以前就学过了这两个函数的导数,所以这应该很容易:
以下代码展示了添加到 方法的反向传播逻辑:
GPT plus 代充 只需 145
希望这感觉相当常规。看看您能否创建更多的非线性函数:尝试 或 。
让我们尝试新的非线性函数。新添加的内容以粗体显示:
GPT plus 代充 只需 145
- 1 预测
- 2 比较
- 3 学习
如您所见,您可以将新的 和 层直接放入 的输入参数中,神经网络会确切地知道如何使用它们。简单!
在上一章中,你学习了循环神经网络。特别是,你训练了一个模型来预测下一个单词,给定前几个单词。在我们完成本章之前,我希望你能将那段代码翻译成新的框架。为此,你需要三种新的层类型:一个学习词嵌入的嵌入层,一个可以学习建模输入序列的 RNN 层,以及一个可以预测标签概率分布的 softmax 层。
嵌入层
嵌入层将索引转换为激活
在第十一章中,你学习了关于词嵌入的内容,这些嵌入是将向量映射到单词,你可以将其前向传播到神经网络中。因此,如果你有一个 200 个单词的词汇表,你也将有 200 个嵌入。这为创建嵌入层提供了初始规范。首先,初始化一个(正确长度的)单词嵌入列表(正确的大小):
GPT plus 代充 只需 145
- 1 这种初始化风格是来自 word2vec 的惯例。
到目前为止,一切顺利。矩阵为词汇表中的每个单词都有一个行(向量)。现在,你将如何进行前向传播呢?好吧,前向传播始终从问题“输入将如何编码?”开始。在词嵌入的情况下,显然你不能传递单词本身,因为单词不会告诉你应该用中的哪一行进行前向传播。相反,如你从第十一章中可能记得的,你前向传播索引。幸运的是,NumPy 支持这个操作:
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0255-01_alt.jpg
注意,当你将整数矩阵传递给 NumPy 矩阵时,它返回相同的矩阵,但每个整数都被替换为指定的行。因此,一个索引的二维矩阵变成了一个三维的嵌入矩阵(行)。这太完美了!
将索引添加到 autograd
在构建嵌入层之前,autograd 需要支持索引
为了支持新的嵌入策略(该策略假设单词作为索引矩阵进行前向传播),你在上一节中玩弄的索引必须由 autograd 支持。这是一个相当简单的想法。你需要确保在反向传播过程中,梯度被放置在与前向传播中索引到的相同行中。这要求你保留传递的任何索引,以便在反向传播期间使用简单的循环将每个梯度放置在适当的位置:
首先,使用你在上一节中学到的 NumPy 技巧来选择正确的行:
GPT plus 代充 只需 145
然后,在 期间,初始化一个正确大小的新梯度(原始矩阵的大小,该矩阵正在被索引)。其次,展平索引,以便你可以遍历它们。第三,将 压缩成一个简单的行列表。(微妙之处在于 中的索引列表和 中的向量列表将按对应顺序排列。)然后,遍历每个索引,将其添加到你正在创建的新梯度的正确行中,并将其反向传播到 。正如你所看到的, 正确地更新了每一行(在这种情况下,添加一个由 1 组成的向量),并按照索引被使用的次数进行更新。索引 2 和 3 更新了两次(加粗):
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0256-01_alt.jpg
嵌入层(重访)
现在你可以使用新的 .index_select() 方法完成正向传播
对于正向传播,调用 ,autograd 将处理其余部分:
- 1 这种初始化风格是来自 word2vec 的约定。
GPT plus 代充 只需 145
- 1 预测
- 2 比较
- 3 学习
在这个神经网络中,你学习将输入索引 1 和 2 与预测 0 和 1 相关联。在理论上,索引 1 和 2 可以对应于单词(或某种其他输入对象),在最终的例子中,它们将这样做。这个例子是为了展示嵌入的工作。
交叉熵层
让我们向 autograd 添加交叉熵并创建一个层
希望到这一点,你已经开始对如何创建新的层类型感到舒适。交叉熵是一个相当标准的层,你在本书中已经多次见过。因为我们已经介绍了如何创建几个新的层类型,所以我会在这里留下代码供你参考。在复制此代码之前,尝试自己完成它。
GPT plus 代充 只需 145
- 1 预测
- 2 比较
- 3 学习
使用在几个先前神经网络中使用的相同交叉熵逻辑,你现在有一个新的损失函数。这个损失函数的一个显著特点是与其他不同:最终的 和损失的计算都在损失类内部完成。这在深度神经网络中是一个非常常见的约定。几乎每个框架都会这样做。当你想要完成一个网络并使用交叉熵进行训练时,你可以在正向传播步骤中省略 ,并调用一个交叉熵类,该类将自动将 作为损失函数的一部分执行。
这些之所以如此一致地组合在一起,是因为性能。在交叉熵函数中一起计算 和负对数似然比梯度的速度比在两个不同的模块中分别进行正向传播和反向传播要快得多。这与梯度数学中的捷径有关。
循环神经网络层
通过组合多个层,你可以学习时间序列
作为本章的最后一个练习,让我们再创建一个由多个较小的层类型组成的层。这个层的目的是学习你在上一章结束时完成的任务。这个层是循环层。你将使用三个线性层来构建它,方法将接受前一个隐藏状态和当前训练数据的输入:
GPT plus 代充 只需 145
本章不涉及重新介绍 RNNs,但指出一些应该已经熟悉的组成部分是值得的。RNNs 有一个状态向量,它在时间步长之间传递。在这种情况下,它是变量,它既是函数的输入参数也是输出变量。RNNs 还有几个不同的权重矩阵:一个将输入向量映射到隐藏向量(处理输入数据),一个将隐藏向量映射到隐藏向量(根据前一个更新每个隐藏向量),以及可选的隐藏到输出层,该层学习根据隐藏向量进行预测。这个 RNNCell 实现包括了这三个。层是输入到隐藏层,是隐藏到隐藏层,是隐藏到输出层。注意每个的维度。的输入大小和的输出大小都是词汇表的大小。所有其他维度都是基于参数可配置的。
最后,一个输入参数定义了在每个时间步长应用于隐藏向量的非线性函数。我添加了两种可能性(和),但有很多选项可供选择。让我们训练一个网络:
你可以学习适应你在上一章中完成的任务
现在,你可以使用嵌入输入初始化循环层,并训练一个网络来解决上一章相同的任务。请注意,尽管代码要简单得多,但由于这个小框架,这个网络稍微复杂一些(它有一个额外的层)。
GPT plus 代充 只需 145
首先,定义输入嵌入,然后定义循环单元。(注意,当循环层仅实现单个递归时,通常将其命名为cell。如果你创建了一个可以配置任意数量单元格的层,它将被称为 RNN,将是一个输入参数。)
GPT plus 代充 只需 145
GPT plus 代充 只需 145
如你所见,神经网络学会了以大约 37%的准确率预测训练数据集的前 100 个示例(对于这个玩具任务来说几乎是完美的)。它预测了玛丽可能移动的方向,就像在第十二章的结尾一样。
摘要
框架是前向和反向逻辑的高效、方便的抽象
我希望这一章的练习让你体会到了框架的便利性。它们可以使你的代码更易读,编写更快,执行更快(通过内置优化),并且错误更少。更重要的是,这一章将为你使用和扩展行业标准框架如 PyTorch 和 TensorFlow 做好准备。无论是调试现有的层类型还是原型设计你自己的,你在本章学到的技能将是你在本书中获得的最重要的技能之一,因为它们将之前章节中关于深度学习的抽象知识与你未来将用于实现模型的真实工具的设计联系起来。
与这里构建的框架最相似的是 PyTorch,我强烈建议你在完成这本书后深入探索它。它很可能是你感觉最熟悉的框架。
本章
- 字符语言模型
- 截断反向传播
- 梯度消失和梯度爆炸
- RNN 反向传播的一个玩具示例
- 长短期记忆(LSTM)单元
“主啊,这些凡人多么愚蠢!”
莎士比亚 仲夏夜之梦
字符语言模型
让我们用 RNN 解决一个更具挑战性的任务
在第十二章和第十三章的结尾,你训练了简单的循环神经网络(RNN),这些网络学习了一个简单的序列预测问题。但你是在一个玩具数据集上训练的,这个数据集是通过规则合成的短语。
在本章中,你将尝试在一个更具挑战性的数据集上进行语言建模:莎士比亚的作品。而且,与上一章中学习根据前面的单词预测下一个单词不同,该模型将训练在字符上。它需要学习根据观察到的先前字符预测下一个字符。这就是我的意思:
- 1 来自
与第十二章和第十三章的词汇表由数据集中的单词组成不同,现在词汇表由数据集中的字符组成。因此,数据集也被转换为一个索引列表,这些索引对应于字符而不是单词。之上是 NumPy 数组:
GPT plus 代充 只需 145
这段代码看起来都很熟悉。它初始化嵌入维度为 8,RNN 隐藏状态的大小为 512。输出权重初始化为 0(这不是规则,但我觉得这样效果更好)。最后,你初始化交叉熵损失和随机梯度下降优化器。
截断反向传播的需要
通过 100,000 个字符进行反向传播是不可行的
阅读 RNN 代码的更具挑战性的方面之一是为输入数据而进行的批处理逻辑。之前的(更简单的)神经网络有一个这样的内部循环(粗体部分):
你可能会问,“为什么迭代到 5?”实际上,之前的语料库没有超过六个单词的例子。它读取了五个单词,然后尝试预测第六个。
更重要的是反向传播步骤。考虑当你对一个简单的前馈网络进行 MNIST 数字分类时:梯度总是反向传播到整个网络,对吧?它们一直反向传播,直到达到输入数据。这允许网络调整每个权重,试图学习如何根据整个输入示例正确预测。
这里的循环例子也没有不同。你通过五个输入示例进行前向传播,然后,当你稍后调用时,它将梯度反向传播回网络到输入数据点。你可以这样做,因为你一次没有输入那么多数据点。但是莎士比亚数据集有 10 万个字符!这对于每个预测进行反向传播来说太多了。你怎么办?
你不需要!你向后传播一个固定数量的步骤到过去,然后停止。这被称为截断反向传播,并且是行业标准。你向后传播的长度成为另一个可调参数(就像批量大小或 alpha)。
截断反向传播
从技术上讲,它削弱了神经网络的最高理论极限
使用截断反向传播的缺点是它缩短了神经网络可以学习记住事物的距离。基本上,在比如说五个时间步长之后切断梯度,意味着神经网络无法学习记住过去超过五个时间步长的事件。
严格来说,情况比这更复杂。在 RNN 的隐藏层中,从过去超过五个时间步长可能会意外地保留一些残留信息,但神经网络不能使用梯度来特别请求模型从六个时间步长之前保留信息以帮助当前预测。因此,在实践中,神经网络不会学习基于过去超过五个时间步长的输入信号进行预测(如果截断设置为五个时间步长)。在实践中,对于语言建模,截断变量被称为,它通常设置在 16 到 64 之间:
GPT plus 代充 只需 145
截断反向传播的另一个缺点是它使得小批量逻辑变得稍微复杂一些。要使用截断反向传播,你假装你有一个大数据集,而不是大小为的一堆小数据集。你需要相应地分组数据集:
这里有很多事情在进行中。最上面一行使得数据集成为和之间的一个偶数倍。这样做是为了当你将其分组为张量时,它是平方的(或者你也可以用 0 填充数据集以使其成为平方)。第二行和第三行重新塑形数据集,使得每一列是初始数组的一个部分。我将展示这部分,就像被设置为 8(为了可读性):
|
GPT plus 代充 只需 145
|
|
|
这些是莎士比亚数据集中的前五个字符。它们拼写出字符串“That,”。接下来是中变换后的前五行的输出:
|
GPT plus 代充 只需 145
|
|
|
我已经用粗体突出显示了第一列。看看短语“That,”的索引是否在左边的第一列?这是一个标准构造。有八个列的原因是是 8。这个张量随后被用来构建一个更小的数据集列表,每个数据集的长度为。
你可以在这里看到输入和目标是如何构建的。注意,目标索引是输入索引偏移一行(因此网络预测下一个字符)。再次注意,在这个打印输出中设置为 8,这使得阅读更容易,但实际上你将其设置为 32。
GPT plus 代充 只需 145
如果这对你来说现在还不明白,也不要担心。这和深度学习理论关系不大;这只是设置 RNN 时一个特别复杂的部分,你有时会遇到。我想花几页纸来解释它。
让我们看看如何使用截断反向传播进行迭代
以下代码展示了截断反向传播的实际应用。注意,它看起来与第十三章中的迭代逻辑非常相似。唯一的真正区别是,你会在每个步骤生成一个;并且每进行一次步骤后,你都会进行反向传播并更新权重。然后你继续像什么都没发生一样读取数据集(甚至使用之前的相同隐藏状态,它仅在每轮中重置):
输出样本的一个示例
通过从模型的预测中采样,你可以写出莎士比亚的作品!
以下代码使用训练逻辑的子集来使用模型进行预测。你将预测存储在一个字符串中,并将字符串版本作为输出返回给函数。生成的样本看起来非常像莎士比亚的作品,甚至包括对话角色:
GPT plus 代充 只需 145
- 1 样本采样的温度;越高 = 越贪婪
- 2 预测样本
消失和爆炸梯度
简单的 RNN 会受到消失和爆炸梯度的影响
你可能还记得当你第一次组合 RNN 时的这个图像。想法是能够以某种方式组合单词嵌入,使得顺序很重要。你是通过学习一个矩阵来做到这一点的,该矩阵将每个嵌入转换到下一个时间步。然后,前向传播变成了两步过程:从第一个单词嵌入(以下示例中的“Red”嵌入)开始,乘以权重矩阵,并加上下一个嵌入(“Sox”)。然后你将得到的向量乘以相同的权重矩阵,并加入下一个单词,重复这个过程,直到读取整个单词序列。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0272-01.jpg
但正如你所知,隐藏状态生成过程中添加了一个额外的非线性项。因此,前向传播变成了一个三步过程:将前一个隐藏状态通过权重矩阵进行矩阵乘法,加入下一个单词的嵌入,并应用非线性函数。
注意,这种非线性在网络稳定性中起着重要作用。无论单词序列有多长,隐藏状态(理论上可能随时间增长而增长)都被迫保持在非线性函数的值之间(在 sigmoid 的情况下是 0 到 1)。但是,反向传播发生的方式与正向传播略有不同,不具有这种良好的性质。反向传播往往会引起极端大或极端小的值。大值可能导致发散(许多非数字 [NaN]),而极端小的值则使网络无法学习。让我们更仔细地看看 RNN 反向传播。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/grok-dl/img/f0272-02.jpg
RNN 反向传播的玩具示例
为了亲身体验梯度消失/爆炸,让我们合成一个示例
以下代码展示了 和 激活的反向传播循环。注意,对于 /,梯度分别变得非常小/大。在反向传播过程中,由于矩阵乘法的结果,它们变得很大,而由于 激活在尾部具有非常平坦的导数(许多非线性函数的常见情况),它们又变得很小。
GPT plus 代充 只需 145
- 1 sigmoid 的导数在激活值非常接近 0 或 1(尾部)时会导致非常小的梯度。
- 2 矩阵乘法会导致梯度爆炸,而非线性函数(如 sigmoid)无法将其压缩。
长短期记忆(LSTM)单元
LSTM 是对抗梯度消失/爆炸的行业标准模型
前一节解释了梯度消失/爆炸是如何由 RNN 中隐藏状态的更新方式引起的。问题是矩阵乘法和非线性函数的组合用于形成下一个隐藏状态。LSTM 提供的解决方案出人意料地简单。
门控复制技巧
LSTM 通过复制前一个隐藏状态并在必要时添加或删除信息来创建下一个隐藏状态。LSTM 用于添加和删除信息的机制被称为 门。
GPT plus 代充 只需 145
之前的代码是 RNN 单元的正向传播逻辑。以下是 LSTM 单元的新正向传播逻辑。LSTM 有两个隐藏状态向量:(隐藏)和 。
你需要关注的是 。注意它是如何更新的。每个新的单元是前一个单元加上 ,通过 和 加权。 是“忘记”门。如果它取值为 0,则新单元将擦除之前看到的内容。如果 为 1,它将完全添加 的值以创建新单元。 是一个输出门,它控制输出预测可以查看多少单元状态。例如,如果 全为零,则 行将忽略单元状态进行预测。
关于 LSTM 门的直觉
LSTM 门与从内存中读取/写入的语义相似
所以,这就是全部了!有三个门控器——、、——和一个细胞更新向量;分别想象这些是忘记、输入、输出和更新。它们共同工作以确保要存储或操作在中的任何信息都可以这样做,而无需要求每次更新时都应用任何矩阵乘法或非线性。换句话说,您正在避免永远调用或。
这使得 LSTM 能够在时间序列中存储信息而不用担心梯度消失或梯度爆炸。每一步都是一个复制(假设不为零)加上一个更新(假设不为零)。隐藏值随后是用于预测的细胞的一个掩码版本。
注意,三个门控器都是用相同的方式形成的。它们有自己的权重矩阵,但每个门控器都基于输入和前一个隐藏状态,通过一个函数进行条件化。正是这个非线性使得它们作为门控器非常有用,因为它在 0 和 1 之间饱和:
GPT plus 代充 只需 145
最后一个可能的批评是关于的。显然,它仍然容易受到梯度消失和梯度爆炸的影响,因为它基本上被用来和原始 RNN 一样。首先,因为向量总是使用一个组合的向量创建,这些向量被和压缩,所以梯度爆炸实际上并不是一个问题——只有梯度消失。但最终这没问题,因为依赖于,它可以携带长距离信息:梯度消失无法学习携带的那种信息。因此,所有长距离信息都是通过传输的,而只是的一个局部解释,对于在下一个时间步进行输出预测和构建门控激活很有用。简而言之,可以学习在长距离上传输信息,所以即使不能,这也没有关系。
长短期记忆层
您可以使用自动微分系统来实现一个 LSTM
升级字符语言模型
让我们用新的 LSTM 单元替换原始 RNN
在本章的早期,您训练了一个字符语言模型来预测莎士比亚。现在让我们训练一个基于 LSTM 的模型来做同样的事情。幸运的是,上一章的框架使得这变得很容易实现(书中的完整代码可在www.manning.com/books/grokking-deep-learning;或在 GitHub 上找到)。以下是新的设置代码。所有从原始 RNN 代码的编辑都在粗体中。注意,您设置神经网络的方式几乎没有变化:
GPT plus 代充 只需 145
- 1 这似乎有助于训练。
训练 LSTM 字符语言模型
训练逻辑也没有发生太多变化
从标准的 RNN 逻辑中,你唯一需要做的真正改变是截断反向传播逻辑,因为每个时间步长有两个隐藏向量而不是一个。但这只是一个相对较小的修复(粗体)。我还增加了一些使训练更简单的功能( 随时间缓慢减少,并且有更多的日志记录):
调整 LSTM 字符语言模型
我花费了大约两天的时间调整这个模型,并且它是在夜间训练完成的
这里是此模型的某些训练输出。请注意,训练这个模型花费了非常长的时间(有很多参数)。我还不得不多次训练它,以找到这个任务的良好调整(学习率、批量大小等),并且最终的模型是在夜间(8 小时)训练完成的。一般来说,你训练的时间越长,你的结果就会越好。
GPT plus 代充 只需 145
- 1 取最大预测
GPT plus 代充 只需 145
摘要
LSTM 是极其强大的模型
LSTM 学习生成莎士比亚语言的分布不容小觑。语言是一个极其复杂的统计分布,学习起来非常困难,而 LSTM 能够做得如此出色(在撰写本文时,它们是广泛领先的**方法)仍然让我(以及其他一些人)感到困惑。这个模型的小型变体要么是,要么最近一直是各种任务中的**状态,并且与词嵌入和卷积层一起,无疑将是我们长期以来的首选工具。
本章内容
- 深度学习中的隐私问题
- 联邦学习
- 学习检测垃圾邮件
- 窃取联邦学习
- 安全聚合
- 同态加密
- 同态加密联邦学习
“朋友不会互相监视;真正的友谊也关乎隐私。”
斯蒂芬·金,《海特斯堡之心》(1999 年)
深度学习中的隐私问题
深度学习(及其工具)通常意味着你可以访问你的训练数据
如你所敏锐地意识到的,深度学习作为机器学习的一个子领域,全部都是关于从数据中学习。但通常,被学习的数据极其个人化。最有意义的模型与人类生活中最个人化的信息互动,并告诉我们一些可能难以通过其他方式了解的事情。换句话说,深度学习模型可以研究成千上万人的生活,帮助你更好地理解自己。
深度学习的主要自然资源是训练数据(无论是合成的还是自然的)。没有它,深度学习就无法学习;而且因为最有价值的使用案例通常与最个人化的数据集互动,深度学习往往是公司寻求聚合数据的原因。他们需要它来解决特定的使用案例。
但在 2017 年,谷歌发布了一篇非常激动人心的论文和博客文章,对这次对话产生了重大影响。谷歌提出,我们不需要集中一个数据集来在上面训练模型。公司提出了这个问题:如果我们不能将所有数据带到一处,我们能否将模型带到数据那里?这是一个新的、令人兴奋的机器学习子领域,称为联邦学习,这正是本章的主题。
如果不是将训练数据集带到一处来训练模型,而是能够将模型带到数据生成的任何地方,会怎么样呢?
这种简单的逆转极其重要。首先,这意味着为了参与深度学习供应链,人们实际上不必将他们的数据发送给任何人。在医疗保健、个人管理和其他敏感领域,有价值的模型可以在不要求任何人透露个人信息的情况下进行训练。理论上,人们可以保留对自己个人数据唯一副本的控制权(至少在深度学习方面)。
这种技术将对企业竞争和创业中的深度学习竞争格局产生巨大影响。以前不会(或不能,由于法律原因)共享客户数据的大型企业可能仍然可以从这些数据中获得收入。在有些领域,数据的敏感性和监管约束一直是进步的阻力。医疗保健就是一个例子,数据集通常被严格锁定,使得研究变得困难。
联邦学习
你不必访问数据集才能从中学习
联邦学习的前提是许多数据集包含对解决问题有用的信息(例如,在 MRI 中识别癌症),但很难以足够的数量访问这些相关的数据集来训练一个足够强大的深度学习模型。主要担忧是,尽管数据集有足够的信息来训练深度学习模型,但它还包含了一些(可能)与学习任务无关的信息,如果泄露可能会对某人造成潜在伤害。
联邦学习是指模型进入一个安全的环境,学习如何解决问题,而不需要数据移动到任何地方。让我们来看一个例子。
- 1 数据集来自
学习检测垃圾邮件
假设你想要在人们的电子邮件上训练一个模型来检测垃圾邮件
我们将要讨论的使用案例是电子邮件分类。第一个模型将在一个公开可用的数据集上训练,这个数据集被称为 Enron 数据集,它是一批来自著名 Enron 诉讼案(现在是一个行业标准的电子邮件分析语料库)的大量电子邮件。有趣的事实:我曾经认识一个人,他专业地阅读/注释了这个数据集,人们互相发送了各种各样的疯狂东西(其中很多非常私人)。但由于它在法庭案件中公开发布,现在可以免费使用。
上一节和这一节的代码只是预处理。输入数据文件(ham.txt 和 spam.txt)可在本书的网站上找到,www.manning.com/books/grokking-deep-learning;以及 GitHub 上。你预处理它以准备好将其前向传播到在第十三章中创建的嵌入类。和之前一样,这个语料库中的所有单词都被转换成了索引列表。你还通过截断电子邮件或用 标记填充它,使所有电子邮件正好 500 个单词长。这样做使得最终数据集是方形的。
GPT plus 代充 只需 145
有这些不错的 和 函数,你可以使用以下几行代码初始化一个神经网络并对其进行训练。仅经过三次迭代,网络就可以在测试数据集上以 99.45%的准确率进行分类(测试数据集是平衡的,所以这相当不错):
|
|
|
GPT plus 代充 只需 145
|
让我们将其变为联邦学习
之前的例子是普通的深度学习。让我们保护隐私
在上一节中,你得到了电子邮件的例子。现在,让我们把所有电子邮件放在一个地方。这是老式的方法(这在世界上仍然非常普遍)。让我们首先模拟一个联邦学习环境,它包含多个不同的电子邮件集合:
足够简单。现在你可以像以前一样进行相同的训练,但同时在每个人的电子邮件数据库中进行。每次迭代后,你将平均鲍勃、爱丽丝和苏的模型值并评估。请注意,一些联邦学习的聚合方法在每个批次(或批次集合)之后进行;我保持简单:
GPT plus 代充 只需 145
下一个部分将展示结果。模型的学习效果几乎与之前相同,从理论上讲,你没有访问到训练数据——或者你有吗?毕竟,每个人都在以某种方式改变模型,对吧?你真的不能发现任何关于他们的数据集的信息吗?
窃取联邦学习
让我们用一个玩具示例来看看如何仍然学习训练数据集
联邦学习面临两大挑战,这两个挑战在训练数据集中每个人只有少量训练示例时最为严重。这些挑战是性能和隐私。实际上,如果某人只有少量训练示例(或者他们发送给你的模型改进只使用了少量示例:一个训练批次),你仍然可以学到很多关于数据的信息。假设有 10,000 人(每人有一些数据),你将花费大部分时间在来回发送模型,而不是在训练(尤其是如果模型非常大时)。
但我们跑题了。让我们看看当用户在单个批次上执行权重更新时,你能学到什么:
GPT plus 代充 只需 145
鲍勃将使用他收件箱中的一封电子邮件来创建对模型的更新。但鲍勃把他自己的密码保存在一封发给自己的电子邮件中,说:“我的电脑密码是披萨。”愚蠢的鲍勃。通过查看哪些权重发生了变化,你可以推断出鲍勃电子邮件的词汇(并推断其含义):
GPT plus 代充 只需 145
就这样,你学会了鲍勃的超秘密密码(也许还有他最喜欢的食物)。怎么办?如果从权重更新中很容易看出训练数据,你该如何使用联邦学习?
安全聚合
在任何人看到之前,让我们平均来自成千上万人的权重更新
解决方案是永远不要让鲍勃像那样公开地发布梯度。如果人们不应该看到它,鲍勃如何贡献他的梯度?社会科学使用一种有趣的技巧,称为随机响应。
它是这样的。假设你正在进行一项调查,你想询问 100 个人他们是否犯过严重的罪行。当然,即使你承诺不会告诉任何人,他们也会回答“没有”。相反,你让他们抛两次硬币(在你看不见的地方),并告诉他们如果第一次抛硬币是正面,他们应该诚实地回答;如果是反面,他们应该根据第二次抛硬币的结果回答“是”或“否”。
在这种情况下,你实际上从未要求人们告诉你他们是否犯了罪。真正的答案隐藏在第一次和第二次抛硬币的随机噪声中。如果 60%的人说“是”,你可以通过简单的数学计算确定,大约 70%的受访者犯了严重的罪行(上下几个百分点)。这个想法是,随机噪声使得你了解到关于个人的任何信息可能来自噪声而不是他们自己。
通过可辩驳的否认来保护隐私
特定答案来自随机噪声而不是个人的概率水平,通过提供可辩驳的否认来保护他们的隐私。这构成了安全聚合的基础,以及更广泛地,差分隐私的大部分内容。
你只看到整体的汇总统计数据。(你永远不会直接看到任何人的答案;你只看到答案对或更大的分组。)因此,在添加噪声之前,你可以聚合更多的人,你就不需要添加太多的噪声来隐藏他们(并且结果会更加准确)。
在联邦学习的背景下,你可以(如果你愿意)添加大量的噪声,但这会损害训练。相反,首先将所有参与者的梯度求和,这样没有人能看到除了自己的梯度以外的任何人的梯度。这类问题被称为 安全聚合,为了做到这一点,你还需要一个额外的(非常酷)工具:同态加密。
同态加密
你可以对加密值执行算术运算
研究中最激动人心的前沿之一是人工智能(包括深度学习)与密码学的交叉领域。在这个激动人心的交叉点中,有一个非常酷的技术叫做同态加密。简单来说,同态加密允许你在不解密的情况下对加密值进行计算。
尤其是我们对在这些值上执行加法感兴趣。详细解释其工作原理需要一本整本书,但我会用几个定义来展示它是如何工作的。首先,一个 公钥 允许你加密数字。一个 私钥 允许你解密加密的数字。加密的值称为 密文,未加密的值称为 明文。
让我们通过使用 phe 库的例子来看看同态加密。(要安装库,请运行 或从 GitHub 下载):
- 1 加密数字 5
- 2 加密数字 3
- 3 将两个加密值相加
- 4 解密结果
GPT plus 代充 只需 145
这段代码在加密状态下将两个数字(5 和 3)相加。非常巧妙,不是吗?还有一种技术与同态加密有点类似:安全多方计算。你可以在“密码学与机器学习”博客()上了解它。
现在,让我们回到安全聚合的问题。鉴于你新获得的知识,你可以将你看不见的数字相加,答案就变得显而易见了。初始化模型的个人将一个发送给鲍勃、爱丽丝和苏,这样他们就可以分别加密他们的权重更新。然后,鲍勃、爱丽丝和苏(他们没有私钥)直接相互沟通,并将所有梯度累积成一个单一、最终的更新,发送回模型所有者,该所有者使用对其进行解密。
同态加密联邦学习
让我们使用同态加密来保护正在聚合的梯度
现在,你可以运行新的训练方案,它增加了一个步骤。爱丽丝、鲍勃和苏在将模型发送回你之前,将他们的同态加密模型相加,这样你就永远不会看到哪些更新来自哪个人(一种合理的否认形式)。在生产中,你还会添加一些额外的随机噪声,足以满足鲍勃、爱丽丝和苏(根据他们的个人偏好)所需的一定隐私阈值。更多内容将在未来的工作中介绍。
GPT plus 代充 只需 145
摘要
联邦学习是深度学习中最激动人心的突破之一
我坚信,联邦学习将在未来几年改变深度学习的格局。它将解锁之前由于过于敏感而无法处理的新的数据集,从而为这种新出现的创业机会创造巨大的社会效益。这是加密与人工智能研究更广泛融合的一部分,在我看来,这是十年中最激动人心的融合。
阻碍这些技术在实际应用中发挥作用的因素主要是它们在现代深度学习工具包中的不可用性。转折点将是任何人都可以运行然后获得访问深度学习框架的权限,在这些框架中,隐私和安全是首要公民,并且内置了联邦学习、同态加密、差分隐私和安全多方计算等技术(而且你不需要是专家就能使用它们)。
出于这种信念,我在过去一年中作为 OpenMined 项目的一部分,与一群开源志愿者一起工作,将这些原语扩展到主要的深度学习框架中。如果你相信这些工具对未来隐私和安全的重要性,请访问我们的网站或 GitHub 仓库()。即使只是给几个仓库点个赞,也请表达你的支持;如果你能加入我们,那就更好了(聊天室:slack.openmined.org)。
本章内容
- 第 1 步:开始学习 PyTorch
- 第 2 步:开始另一门深度学习课程
- 第 3 步:获取一本数学深度学习教科书
- 第 4 步:开始写博客,教授深度学习
- 第 5 步:Twitter
- 第 6 步:实现学术论文
- 第 7 步:获取访问 GPU 的权限
- 第 8 步:通过实践获得报酬
- 第 9 步:加入开源项目
- 第 10 步:发展你的本地社区
“无论你是否相信你能做某事,你都是对的。”
亨利·福特,汽车制造商
恭喜你!
如果你正在阅读这篇文章,你已经走过了近 300 页的深度学习内容
你做到了!这是一大堆材料。我为你感到骄傲,你也应该为自己感到骄傲。今天应该是一个庆祝的日子。到目前为止,你理解了人工智能背后的基本概念,并且应该对自己的能力感到相当自信,无论是谈论它们还是学习高级概念。
这最后一章包含了一些简短的章节,讨论了适合你的下一步行动,尤其是如果你是深度学习领域的初学者。我的一般假设是你对这个领域感兴趣,或者至少想在旁边继续探索,我希望我的总体评论能帮助你找到正确的方向(尽管它们只是非常一般的指导方针,可能或可能不直接适用于你)。
第 1 步:开始学习 PyTorch
你制作的深度学习框架最接近 PyTorch
你一直使用 NumPy 学习深度学习,这是一个基本的矩阵库。然后你构建了自己的深度学习工具包,并且你也相当多地使用了它。但从这一点开始,除非在学习新的架构,你应该使用实际的框架进行实验。这将更少出错。它将运行(非常快),你将能够继承/学习其他人的代码。
为什么你应该选择 PyTorch?有很多好的选择,但如果你来自 NumPy 背景,PyTorch 会感觉最熟悉。此外,你在第十三章(kindle_split_021.xhtml#ch13)中构建的框架与 PyTorch 的 API 非常相似。我这样做是为了特别为你准备一个实际的框架。如果你选择 PyTorch,你会感到非常自在。话虽如此,选择深度学习框架有点像加入霍格沃茨的一所房子:它们都很棒(但 PyTorch 绝对是格兰芬多)。
现在下一个问题:你应该如何学习 PyTorch?最好的方法是参加一门教授你使用该框架进行深度学习的深度学习课程。这将帮助你回忆起你已经熟悉的概念,同时向你展示每个部分在 PyTorch 中的位置。(你将在学习随机梯度下降的同时了解它在 PyTorch API 中的位置。)在撰写本文时,做这件事的最好地方可能是 Udacity 的深度学习纳米学位(尽管我有所偏见:我帮助教授了它)或 fast.ai。此外,和是金子般的学习资源。
第 2 步:开始另一门深度学习课程
我通过反复学习相同的概念来学习深度学习
虽然认为一本书或一门课程就足以满足你整个深度学习教育是件很美好的事情,但事实并非如此。即使这本书(它们并没有)涵盖了所有概念,从多个角度听到相同的概念对于你真正理解它们是至关重要的(看看我做了什么?)。在我作为开发者的成长过程中,我可能参加了大约六门不同的课程(或 YouTube 系列),除了观看大量的 YouTube 视频和阅读大量描述基本概念的博客文章。
在 YouTube 上寻找来自大型深度学习大学或 AI 实验室(斯坦福、麻省理工、牛津、蒙特利尔、纽约大学等)的在线课程。观看所有视频。完成所有练习。如果可能的话,做 fast.ai 和 Udacity 的课程。反复学习相同的概念。练习它们。熟悉它们。你希望基本原理在你的脑海中变得像第二本能一样自然。
第 3 步:找一本数学深度学习教科书
你可以从你的深度学习知识中逆向工程数学
我在大学本科的专业是应用离散数学,但我从深度学习中学到的代数、微积分和统计学比我在课堂上学到的要多得多。此外,这可能听起来令人惊讶,我是通过编写 NumPy 代码并回到它实现的数学问题来解决问题的。这就是我真正在更深的层次上学习深度学习相关数学的方法。这是一个我希望你能够铭记在心的好方法。
如果你不确定该选择哪本数学书籍,那么在撰写本文时,市场上可能最好的是 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 合著的《深度学习》(MIT Press,2016 年)。它在数学方面并不疯狂,但它是这本书(以及书前面的数学符号指南)的下一步(数学符号指南是金子般的资源)。
第 4 步:开始写博客,并教授深度学习
我所做的一切都极大地帮助了我的知识和职业生涯
我可能应该把它作为第一步,但就这样开始了。没有什么比在我的博客上教授深度学习(以及我在深度学习领域的职业生涯)更能提升我的深度学习知识了。教学迫使你尽可能简单地解释一切,而公众羞辱的恐惧将确保你做得很好。
有趣的故事:我的第一篇博客文章登上了 Hacker News,但写得非常糟糕,一个顶级 AI 实验室的主要研究员在评论中彻底摧毁了我。这伤害了我的感情和自信,但它也使我的写作更加严谨。它让我意识到,大多数时候,当我读某件事很难理解时,这不是我的错;写这篇文章的人没有花足够的时间解释我需要了解的所有小细节,以便理解完整的概念。他们没有提供相关的类比来帮助我的理解。
总之,开始写博客。尽量登上 Hacker News 或 ML Reddit 首页。从教授基本概念开始。尽量做得比任何人都要好。不用担心话题是否已经被覆盖。时至今日,我最受欢迎的博客文章是“用 11 行 Python 实现神经网络”,它教授了深度学习中教授最多的东西:一个基本的正向神经网络。但我能够以新的方式解释它,这帮助了一些人。它之所以能这样做,主要是因为我以帮助我理解的方式写了这篇文章。这就是关键。以你想要学习的方式教授事物。
不要只是总结深度学习概念!总结很无聊,没有人想读它们。写教程。你写的每一篇博客文章都应该包括一个学习做某事的神经网络——读者可以下载并运行的东西。你的博客应该逐行说明每个部分的作用,这样即使是五岁的孩子也能理解。这就是标准。当你为两页博客文章工作了三天后,你可能想放弃,但那不是回头的时候:那是继续前进并使其变得惊人的时候!一篇优秀的博客文章可以改变你的生活。相信我。
如果你想要申请一份工作、硕士或博士项目来从事人工智能,选择一个你想要在那个项目中与之合作的研究员,并写关于他们工作的教程。每次我这样做,都导致后来遇到了那位研究员。这样做表明你理解他们正在使用的概念,这是他们想要与你合作的前提条件。这比冷邮件要好得多,因为,假设它出现在 Reddit、Hacker News 或某个其他场合,其他人会先把它发给他们。有时他们甚至会主动联系你。
第 5 步:推特
大多数人工智能对话都发生在推特上
我在 Twitter 上遇到的世界各地的研究人员比其他任何方式都要多,我几乎读过的每一篇论文都是因为我关注了那些发推文的人。你想要了解最新的变化;更重要的是,你想要成为对话的一部分。我开始是找到一些我尊敬的人工智能研究人员,关注他们,然后关注他们关注的人。这让我开始有了动态,极大地帮助了我。(只是不要让它变成一种上瘾!)
第 6 步:实现学术论文
Twitter + 你的博客 = 学术论文教程
观察你的 Twitter 动态,直到你遇到一篇听起来既有趣又不需要大量 GPU 的论文。为它写一篇教程。你将不得不阅读这篇论文,解读数学,并经历原始研究人员也必须经历的调整过程。如果你对抽象研究感兴趣,这无疑是一项最好的练习。我在国际机器学习会议(ICML)上发表的第一篇论文就是从我阅读这篇论文并随后逆向工程 word2vec 中的代码开始的。最终,当你阅读时,你会想,“等等!我觉得我可以让它变得更好!”就这样:你成为了一名研究人员。
第 7 步:获取访问 GPU(或多个)的权限
你能更快地进行实验,你就能更快地学习
没有人不知道 GPU 可以提供 10 到 100 倍更快的训练时间,但它的含义是你可以以 100 倍的速度迭代你自己的(好与坏)想法。这对学习深度学习来说是无价之宝。我在职业生涯中犯的一个错误是等得太久才开始使用 GPU。不要像我一样:从 NVIDIA 购买一个,或者使用你可以在 Google Colab 笔记本中访问的免费的 K80。NVIDIA 偶尔也允许学生在某些 AI 竞赛中免费使用他们的 GPU,但你必须小心。
第 8 步:获得报酬来练习
你有更多的时间进行深度学习,你就能更快地学习
我的职业生涯中的另一个转折点是当我得到一份让我能够探索深度学习工具和研究的工作。成为一名数据科学家、数据工程师或研究工程师,或者作为统计顾问自由职业。关键是,你想要找到一种方式,在工作时间内获得报酬的同时继续学习。这些工作确实存在;只是需要一些努力去找到它们。
你的博客对于获得这类工作至关重要。无论你想要什么样的工作,至少写两篇博客文章来展示你能够胜任他们想要招聘的任何工作。这就是完美的简历(比数学学位还要好)。理想的候选人已经证明他们能够胜任这项工作。
第 9 步:加入开源项目
在人工智能领域,最快建立人脉和职业发展的方式是成为开源项目中的核心开发者
找到一个你喜欢的深度学习框架,并开始实施项目。很快,你就会与顶级实验室的研究人员互动(他们将会阅读/批准你的拉取请求)。我知道很多人通过这种方法找到了令人惊叹的工作(看似从天而降)。
话虽如此,你必须投入时间。没有人会牵着你的手。阅读代码。交朋友。从添加单元测试和解释代码的文档开始,然后修复 bug,最终开始着手更大的项目。这需要时间,但这是对你未来的投资。如果你不确定,可以选择像 PyTorch、TensorFlow 或 Keras 这样的主要深度学习框架,或者你可以来 OpenMined 与我一起工作(我认为这是周围最酷的开源项目)。我们非常欢迎新手。
第 10 步:发展你的本地社区
我真正学习深度学习是因为我喜欢和那些
我在 Bongo Java 学习了深度学习,当时我坐在我的最好朋友旁边,他们也对这个领域感兴趣。当遇到难以修复的 bug(我花了两天时间才找到一个句号)或难以掌握的概念时,我之所以能坚持下去,很大一部分原因是我花时间与我所爱的人在一起。不要低估这一点。如果你在一个你喜欢的地方,与你喜欢的人在一起,你将会工作更长,进步更快。这不是火箭科学,但你必须是有意的。谁知道呢?你可能在这个过程中还会有点乐趣!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/239901.html