从原理到实战 英伟达教你用PyTorch搭建RNN(上)

本文涉及的产品
NLP自然语言处理_基础版,每接口每天50万次
NLP自然语言处理_高级版,每接口累计50万次
NLP 自学习平台,3个模型定制额度 1个月
简介:

从 Siri 到谷歌翻译,深度神经网络大步推动了机器对自然语言的理解。

迄今为止,大多数模型把语言看作是字词的平面序列(flat sequence),使用时间递归神经网络(recurrent neural network)来处理。但语言学家认为,这并不是看待语言的最佳方式,应把其理解为由短语组成的的分层树状结构( hierarchical tree of phrases)。由于对该类结构的支持,大量深度学习研究投入到结构递归神经网络(recursive neural network)之中。在业内,这些模型有非常难以执行、运行起来效率低下的名声。

但对于今年 Facebook 开源的新深度学习框架 PyTorch ,业内人士人认为它的一大贡献是:搭建结构递归神经网络以及其它复杂自然语言处理模型,变得更简便。

结构递归神经网络,是展示 PyTorch 灵活性的一个不错的例子。但同时,PyTorch 是一个对于各类深度学习任务有完备功能的框架,虽然特别适于计算机视觉问题。它诞生于 Facebook AI 研究院 FAIR 的研究人员之手,PyTorch 把 Torch7 中高效、灵活的 GPU 加速后端算法库,和直觉性的 Python 前端结合到一起,并具有快速创建原型机的能力、高度可读性的代码、以及对于各类深度学习模型的支持。

SPINNing Up

本文将带领大家在 PyTorch 上,实现一个有 recurrent tracker 和 TreeLSTM 节点的结构递归神经网络,即 SPINN。对于相当多的主流深度学习框架,这是一个很难搭建的自然语言处理模型。这里我描述的实现部分做了 batch,所以能够利用 GPU 加速的性能,比不用 batch 的版本要快得多。

SPINN 模型的全称是“Stack-augmented Parser-Interpreter Neural Network”,它作为一种解决了自然语言推理任务的方案,随 Bowman et al. (2016) 论文面世,当时使用的是斯坦福的 SNLI 数据集。

这里的任务,是把成对的语句分类为三组类别:假设第一个句子是对某幅用户无法看到的图像的准确注解,第二个句子同样是对该图像的注解,那么第二句话到底是 (a) 绝对准确 (b) 可能准确还是 (c) 绝对不准确的?举个例子,假设第一句话是 “two dogs are running through a field”(两条狗穿过一片农田)。那么,让这组语句“绝对正确”的句子可以是““there are animals outdoors”(户外有动物);让它们“可能准确”的,可以是“some puppies are running to catch a stick”(一群幼犬跑着去接一个木棒);让它们“绝对不准确”的可以是 “the pets are sitting on a couch”(宠物们坐在沙发上)。

导致 SPINN 诞生的研究,为实现其目标要在决定句子之间的关系之前,把每句话编码为固定长度的矢量表达(还有其他方式,比如注意力模型)。

数据集包含机器生成的语法树( syntactic parse trees),后者把每句话里的词组合为短语和子句,每一个都有独立涵义,并且有两个词或 sub-phrases 组成。许多语言学家认为,人类理解语言,是通过把涵义以层级(hierarchical)方式组合起来,就像这样的树状结构。因此,创建一个以同样方式运作的神经网络或许是必要的。下面的例子是一个数据集里的句子,它的语法树以括号结构表示:


  ( ( The church ) ( ( has ( cracks ( in ( the ceiling ) ) ) ) . ) )


用支持语法树结构的神经网络对这个句子编码,方法之一是创建一个神经网络层 Reduce,把词组(以 GloVe 这样的 word embedding 来表示)或短语组合起来,然后将这一层循环应用,把上一个 Reduce 操作的结果,作为句子的编码:


X = Reduce(“the”, “ceiling”)
Y = Reduce(“in”, X)
... etc.


但如果,我想让神经网络以更“人性化”的方式运作呢?能从左到右阅读,保持语境,同时使用语法树把短语组合起来?或者,如果我想要训练一个神经网络,让它在看到这句子时,基于读到的词语创建它自己的语法树?这是一个同样的语法树,只是写出来的方式稍稍有区别:


  The church ) has cracks in the ceiling ) ) ) ) . ) )


第三种方法,仍然是一回事:


WORDS:  The church   has cracks in the ceiling         .
PARSES: S   S      R S   S      S  S   S       R R R R S R R


我所做的,仅仅是去除括号,用“S” 代表“shift”来标记词语, 并用“R”代表“reduce”替代右括号。现在,信息可作为操作堆栈(stack) 和类似堆栈的 buffer 的一系列指令从左读到右,与上文描述的循环方式有同样的结果:

  1. 将文本导入 buffer。

  2. 从 buffer 的首词“The” pop 出去,把 push 入栈,这时“The”应该在“church”前面。

  3. Pop 最上面的两个堆栈值,应用 Reduce,把结果 push 入栈。

  4. 从 buffer pop 出“has”,push 到入栈,随后 “cracks”,再“in”,再“the”,再“ceiling”。

  5. 重复四次:pop 最前面的两个堆栈值,应用 Reduce,push 结果。

  6. 从缓存 pop 出“.”再 push 入栈。

  7. 重复两次:pop 最前面的两个堆栈值,应用 Reduce,push 结果。

  8. Pop 剩下的堆栈值,作为句子编码返回。

我还想维持语境,照顾到其他信息——句子中系统已读取的部分,并在句子的之后部分上进行 Reduce 操作。所以,我将把两个参数(two-argument)的 Reduce 函数,用三个参数的函数来替代,后者导入左子树、右子树短语以及当前语境状态。该状态由第二个神经网络层生成——一个名为 Tracker 的循环单位。给定现有句子语境状态,Tracker 在堆栈操作的每一步生成一个新状态(读取每个词语和右括号之后),buffer 最顶端的 entry b 和堆栈中最顶端的两个 entries s1、s2:


context[t+1] = Tracker(context[t], b, s1, s2)


可以想象一下用你最喜欢的编程语言写这些东西:对于需要处理的每个句子,它会从 buffer 中加载下一个词,运行 Tracker,检查是否要 push 入栈或者进行 Reduce,操作后不断重复,直到整个句子处理完毕。当应用在单个句子上面,这个过程由大且复杂的深度神经网络运行,网络上的两个可训练层一遍遍按照 stack manipulation 规定的方式执行。

但如果你对 TensorFlow、Theano 等传统深度学习框架很熟悉,你就知道执行这类动态过程有多么费劲。这值得我们花点时间多想想,为什么它们处理这种任务力不从心,以及 PyTorch 是否能提供不一样的东西。

图理论

从原理到实战 英伟达教你用PyTorch搭建RNN(上)

本质上,深度神经网路只是有海量参数的复杂函数。深度学习的目标也仅仅是通过计算 partial derivatives(梯度)、衡量损失来优化这些参数。如果该函数以计算图结构来表示,反着运行能去除计算梯度的不必要工作。所有现代深度学习框架都是基于这一反向传播概念,作为结果,每个框架都需要找到一种方式来表示计算图。

大多数的主流深度学习框架,比如 TensorFlow、Theano、Keras 以及 Torch7 的 nngraph 算法库,它们的计算图都是事先创建好的静态物体。该图由看起来像是数学表达的代码来定义,但它的变量其实是还没有赋予任何数值的占位符(placeholder)。由占位符标量组成的图,编译为一个函数,然后重复在训练数据 batch 上运行,生成输出和梯度。

这种静态计算图在 CNN 上的效果很好,后者的结构一般是固定的。但对于许多应用,开发者需要让神经网络图的机构能随数据修改。在自然语言处理中,研究人员通常希望把时间递归神经网络展开,最好输入有多少词,就有多少时间步(timestep)。上文提到的 SPINN 模型的 stack manipulation,非常倚赖控制流,比如“for”和“if”statement,来定义某个特定句子的计算图结构。在更复杂的例子里,你也许想要搭建结构取决于子网络输出的模型。

有的想法可以被硬塞进静态图系统,但不是全部 ,而且几乎总是以更糟的透明度、看不懂的代码作为代价。框架需要给计算图添加代表了编程基本指令(loops and conditionals)的特殊节点,用户需要学习、使用这些节点,而不是程序语言中的 “for”和“if” statement。这是因为任何程序员使用的控制流 statement  均只能使用一次,在创建图时写死(hard coding)一条计算通道。

比如说,词语(从初始状态 h0 开始)中的矢量上,运行一个时间递归神经网络(rnn_unit)需要 tf.while_loop,一个特殊的控制流节点。在 TensorFlow 运行时获取词语长度需要一个额外特殊节点,这是由于代码运行的时候它只是一个占位符。


# TensorFlow
# (this code runs once, during model initialization)
# “words” is not a real list (it’s a placeholder variable) so
# I can’t use “len”
cond = lambda i, h: i < tf.shape(words)[0]
cell = lambda i, h: rnn_unit(words[i], h)
i = 0
_, h = tf.while_loop(cond, cell, (i, h0))


一个在根本上与之区别的方式,是动态计算图,这在几十年前的学界就已展开研究,又被称为“define-by-run”。哈佛大学研发出来的 Kayak 、autograd,以及研究导向的框架 Chainer and DyNet 都基于动态计算图。在这样的框架中,计算图在运行时才被创建出来或重新创建。进行前馈通道运算的代码,也为反向传播创建所需的数据结构。该方式生成更直观的代码,因为控制流使用标准的“for”和“if”来写。修补漏洞也变得更简单,因为运行时的断点、堆栈踪迹(stack trace)让你直接找到写的代码,而不是执行引擎里的编译函数。同样变量长度的时间递归神经网络,可用简单的 Python “for”循环在动态框架里实现。


# PyTorch (also works in Chainer)
# (this code runs on every forward pass of the model)
# “words” is a Python list with actual values in it
h = h0
for word in words:
   h = rnn_unit(word, h)


PyTorch  是第一个在性能、灵活性上媲美静态图框架的 “define-by-run”深度学习框架。这使它适合于开发几乎所有模型,从标准的卷积网络到最离谱的强化学习想法。下篇中,我们将一起看看 SPINN 的代码实现。




====================================分割线================================

本文作者:三川
本文转自雷锋网禁止二次转载, 原文链接
目录
相关文章
|
29天前
|
监控 PyTorch 数据处理
通过pin_memory 优化 PyTorch 数据加载和传输:工作原理、使用场景与性能分析
在 PyTorch 中,`pin_memory` 是一个重要的设置,可以显著提高 CPU 与 GPU 之间的数据传输速度。当 `pin_memory=True` 时,数据会被固定在 CPU 的 RAM 中,从而加快传输到 GPU 的速度。这对于处理大规模数据集、实时推理和多 GPU 训练等任务尤为重要。本文详细探讨了 `pin_memory` 的作用、工作原理及最佳实践,帮助你优化数据加载和传输,提升模型性能。
58 4
通过pin_memory 优化 PyTorch 数据加载和传输:工作原理、使用场景与性能分析
|
6月前
|
机器学习/深度学习 自然语言处理 算法
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
|
2月前
|
机器学习/深度学习 数据采集 自然语言处理
【NLP自然语言处理】基于PyTorch深度学习框架构建RNN经典案例:构建人名分类器
【NLP自然语言处理】基于PyTorch深度学习框架构建RNN经典案例:构建人名分类器
|
3月前
|
机器学习/深度学习 数据挖掘 TensorFlow
解锁Python数据分析新技能,TensorFlow&PyTorch双引擎驱动深度学习实战盛宴
在数据驱动时代,Python凭借简洁的语法和强大的库支持,成为数据分析与机器学习的首选语言。Pandas和NumPy是Python数据分析的基础,前者提供高效的数据处理工具,后者则支持科学计算。TensorFlow与PyTorch作为深度学习领域的两大框架,助力数据科学家构建复杂神经网络,挖掘数据深层价值。通过Python打下的坚实基础,结合TensorFlow和PyTorch的强大功能,我们能在数据科学领域探索无限可能,解决复杂问题并推动科研进步。
67 0
|
5月前
|
机器学习/深度学习 PyTorch 编译器
Pytorch的编译新特性TorchDynamo的工作原理和使用示例
PyTorch的TorchDynamo是一个即时编译器,用于优化动态图执行,提高运行效率。它在运行时分析和转换代码,应用优化技术,如操作符融合,然后编译成高效机器码。通过一个包含特征工程、超参数调整、交叉验证的合成数据集示例,展示了TorchDynamo如何减少训练时间并提高模型性能。它易于集成,只需对现有PyTorch代码进行小改动,即可利用其性能提升。TorchDynamo的优化包括动态捕获计算图、应用优化和编译,适用于实时应用和需要快速响应的场景。
80 11
|
5月前
|
资源调度 PyTorch 调度
多任务高斯过程数学原理和Pytorch实现示例
本文探讨了如何使用高斯过程扩展到多任务场景,强调了多任务高斯过程(MTGP)在处理相关输出时的优势。通过独立多任务GP、内在模型(ICM)和线性模型(LMC)的核心区域化方法,MTGP能够捕捉任务间的依赖关系,提高泛化能力。ICM和LMC通过引入核心区域化矩阵来学习任务间的共享结构。在PyTorch中,使用GPyTorch库展示了如何实现ICM模型,包括噪声建模和训练过程。实验比较了MTGP与独立GP,显示了MTGP在预测性能上的提升。
91 7
|
4月前
|
机器学习/深度学习 PyTorch TensorFlow
【PyTorch】PyTorch深度学习框架实战(一):实现你的第一个DNN网络
【PyTorch】PyTorch深度学习框架实战(一):实现你的第一个DNN网络
181 1
|
5月前
|
机器学习/深度学习 数据挖掘 TensorFlow
解锁Python数据分析新技能,TensorFlow&PyTorch双引擎驱动深度学习实战盛宴
【7月更文挑战第31天】在数据驱动时代,Python凭借其简洁性与强大的库支持,成为数据分析与机器学习的首选语言。**数据分析基础**从Pandas和NumPy开始,Pandas简化了数据处理和清洗,NumPy支持高效的数学运算。例如,加载并清洗CSV数据、计算总销售额等。
63 2
|
5月前
|
机器学习/深度学习 人工智能 数据挖掘
从0到1构建AI帝国:PyTorch深度学习框架下的数据分析与实战秘籍
【7月更文挑战第30天】PyTorch以其灵活性和易用性成为深度学习的首选框架。
70 2
|
5月前
|
机器学习/深度学习 数据挖掘 PyTorch
🚀PyTorch实战宝典:从数据分析小白到深度学习高手的飞跃之旅
【7月更文挑战第29天】在数据驱动的世界里, **PyTorch** 作为深度学习框架新星, 凭借其直观易用性和高效计算性能, 助力数据分析新手成为深度学习专家。首先, 掌握Pandas、Matplotlib等工具进行数据处理和可视化至关重要。接着, 安装配置PyTorch环境, 学习张量、自动求导等概念。通过构建简单线性回归模型, 如定义 `nn.Module` 类、设置损失函数和优化器, 进行训练和测试, 逐步过渡到复杂模型如CNN和RNN的应用。不断实践, 你将能熟练运用PyTorch解决实际问题。
90 1