您的位置:首页 > 理论基础 > 计算机网络

应用到文本领域的卷积方法

2017-05-27 15:49 519 查看
原文:Convolutional Methods for Text

tl;dr

RNNS对于文本非常有用,但是卷积网络拥有更快的效率

句子的任何部分都可能影响到一个单词的语义。 因此,我们希望我们的网络能够一次看到整个输入

获得这么大的接受能使梯度消失,我们的网络失败

我们可以解决DenseNets或扩张卷的消失梯度问题

有时我们需要生成文本。 我们可以使用“deconvolutions”来产生任意长的输出。

Intro

在过去三年中,由于深度学习的火热,NLP领域经历了巨大的革命。 这场革命的领导者是循环神经网络,特别是其LSTM模型的表现。 同时,计算机视觉领域也被卷积神经网络重塑。 这篇文章探讨了我们“研究文本的人”可以从我们做计算机视觉的朋友那里学到什么。

Common NLP Tasks

为了展示在词汇基础上的情景,我介绍了在NLP中介绍一些更常见的任务。 为了保持一致性,我假设我们所有的模型的输入是字符,我们的“观察单位”是一个句子。 这两个假设只是为了方便起见,如果您愿意,您可以用文字和句子替换字符。

Classification

这也许是这本书中最古老的技巧,我们经常想把句子分类。 例如,我们可能希望将电子邮件主题分类为是否是垃圾邮件的指示,猜测产品评论的意见或将主题分配给文档。

用RNN处理这种任务的直接方法是逐字输入整个句子,然后观察RNN的最终隐藏状态。

Sequence Labeling

序列标签任务是返回每个输入对应的输出的任务。 示例包括部分语音标签或实体识别任务。 单纯的LSTM虽然并不是当下最先进的技术,但易于实施并提供了令人信服的效果。 这篇文章 为Sequence Labeling任务提供了更加丰富的架构:



Sequence Generation

可以说,最近的NLP中最令人印象深刻的任务是翻译。 翻译是一个序列到另一个序列的映射,对输出句子的长度没有保证。 例如,将圣经的第一句话从希伯来语翻译成英文是בראשית=“In the Beginning”。



A basic Encoder Decoder for English to German translation (source)

成功的关键是序列到序列(AKA编码器解码器)框架,一种将序列“压缩”成代码,然后将其解码为另一个序列的方法。 值得注意的例子包括翻译(编码希伯来语和解码为英文),图像字幕(编码图像和解码其内容的文本描述)



Image captioning with Sequence to Sequence models (Source)

基本的编码器步骤类似于我们描述的分类的方案。最激动人心的是,我们可以构建一个学习生成任意长度输出的解码器。

上面的两个例子都是翻译,但序列生成的范围比这更广泛。 OpenAI最近发表了一篇文章,他们在控制输出情绪的同时学会产生“Amazon Reviews”



Example outputs from OpenAI. They trained a charterer level language model on Amazon reviews. They discovered a single neuron in their model responsible for sentiment and by fixing its value were able to generate new reviews with a particular sentiment. (Source)

另一个个人最喜欢的论文是Generating Sentences from a Continuous Space。 在这篇文章中,他们基于文本训练了一个变分自编码器,从而拥有了两句话之间的插值的能力,得到了一致的结果。



Interpolating between sentences (Homotopies) . (Source)

Requirements from an NLP architecture

我们所看到的所有实现都是基于循环的架构,通常是LSTM模型(如果你不确定这是什么,这篇文章是一个很好的介绍)。 值得注意的是,没有任何一个任务的名字中有循环,没有人提到LSTM。考虑到这一点,让我们花点时间来思考RNN,特别是LSTM提供了什么,使它们在NLP中无处不在。

Arbitrary Input Size

一个标准的前馈神经网络每个输入都有一个参数。 在处理文本或图像时,由于以下几个原因,这将成为一个问题。

它限制了我们可以处理的输入大小。 我们的网络将具有有限数量的输入节点,并且将无法增长到更多。

我们失去了很多共同的信息。 考虑句子“I like to drink beer a lot”和“I like to drink a lot of beer”。 前馈网络必须每次在不同的输入节点中学习到“a lot”的概念。

循环神经网络解决了这个问题。不再为每个输入设置一个节点,我们有一个大的“box”的节点,我们一次又一次地应用于输入。 “box”学习一种过渡函数,这意味着输出遵循一些循环关系。

请记住,研究计算机视觉的人对图像使用卷积取得了相同的效果。卷积允许跨整个图像重用相同的小的参数集合而非为每个像素设置一个输入节点。

Long Term Dependencies

RNN的承诺是他们模拟长期依赖的能力。 以下图片取自OpenAI。 他们训练了一个模型,最终以模型的输出,逐字识别情感和色彩。 请注意模型如何看待“best”一词,触发超过100个字符的积极情绪。 这是捕获长距离的依赖。



RNN的理论承诺我们长序列依赖于box的输出。 这种做法有点困难。 当我们通过反向传播学习时,我们需要通过整个递归关系传播信号。 事情是,在每一步,我们最终乘以一个数字。 如果这些数字一般小于1,我们的信号会很快进入0。如果它们大于1,那么我们的信号将会爆炸。

这些问题被称为消失和爆炸的梯度,通常可以通过LSTM和几个聪明的技巧来解决。 之所以提到这些,因为我们会再次遇到这些问题,并且需要另外一种解决方法。

Advantages of convolutions

到目前为止,我们已经看到了LSTM的伟大,但是这篇文章是关于卷积的。 本着don’t fix what ain’t broken的精神,我们必须问自己为什么要使用卷积。

一个答案是“Because we can”。

但是还有另外两个令人信服的理由来使用卷积,速度和上下文。

Parrelalisation

RNN依次运行,第二个输入的输出取决于第一个输入,因此我们无法使RNN并行化。 卷积没有这样的问题,卷积内核的每个“patch”都是独立的,我们可以同时遍历整个输入层。

要为此付出的代价是,我们必须将卷积叠加到深层,以便查看整个输入,并且按顺序计算每个层。 但是,每层的计算同时发生,每个单独的计算都很小(与LSTM相比),因此实际上我们得到了很大的加速。

当我开始写这个时,我只有自己的经验和Google的ByteNet来支持这个说法。 就在本周,Facebook发布了完整的卷积翻译模型,是LSTM的9倍速度。

View the whole input at once

LSTM从左到右(或从右到左)读取他们的输入,但有时候我们想让句子结尾的上下文影响网络对其开始的想法。 例如,我们可能会有一个句子,如“I’d love to buy your product. Not!“我们希望最后的否定会影响整个句子。

Borat learns to tell a “Not” joke

使用LSTM的话,我们必须通过运行两个LSTM来实现这一点,一个从左到右,另一个从左到右并连接其输出。 这在实践中运行良好,但是我们的计算负载增加了一倍。

另一方面,当我们堆叠越来越多的层时,卷积增长了一个更大的“接受领域”。 这意味着默认情况下,卷积表示中的每个“步骤”都会从其前后观察其接受领域中的所有输入。 我不知道有什么明确的论据,证明这本质上比LSTM更好,但它确实以可控的方式给我们带来了希望的效果,而且计算成本低。

到目前为止,我们已经设置了我们的问题域,并且谈了NLP中卷积的概念优势。 从这里出发,我想将这些概念转化为可用于分析和构建网络的实际方法。

Practical convolutions for text



Source

你可能已经看到一个像上面那样的动画,说明了卷积的作用。 底部是输入图像,顶部是结果,灰色阴影是重复应用的卷积核。

除了图片中描述的输入是具有两个空间尺寸(高度和宽度)的图像之外,这一切都是完美的。 我们正在谈论的文本只有一个维度,而且它的时间不是空间的。

对于实际目的,这并不重要。 我们只需要将我们的文本视为宽度n和高度1的图像。Tensorflow提供了一个对我们执行的conv1d函数,但它并没有在其1d版本中公开其他卷积运算。

为了使“文本=高度1的图像”具体化,让我们看看在Tensorflow中如何在一系列嵌入式草种牌中使用2d卷积运算。

import tensorflow as tf
def conv1d(input_, output_size, width, stride):
'''
:param input_: A tensor of embedded tokens with shape [batch_size,max_length,embedding_size]
:param output_size: The number of feature maps we'd like to calculate
:param width: The filter width
:param stride: The stride
:return: A tensor of the concolved input with shape [batch_size,max_length,output_size]
'''
inputSize = input_.get_shape()[-1] # How many channels on the input (The size of our embedding for instance)

#This is the kicker where we make our text an image of height 1
input_ = tf.expand_dims(input_, axis=1) #  Change the shape to [batch_size,1,max_length,output_size]

#Make sure the height of the filter is 1
filter_ = tf.get_variable("conv_filter",shape=[1, width, inputSize, output_size])

#Run the convolution as if this were an image
convolved = tf.nn.conv2d(input_, filter=filter_,strides=[1, 1, stride, 1], padding="SAME")
#Remove the extra dimension, eg make the shape [batch_size,max_length,output_size]
result = tf.squeeze(convolved, axis=1)
return result


所以我们在这里做的是用tf.expand_dims来改变输入的形状,使其成为一个“高度1”的图像。 运行2d卷积运算符后,我们挤出了额外的维度。

Hierarchy and Receptive Fields



我们中许多人已经看过像上面那样的照片。 它大致显示了CNN学习图像的抽象层次。 在第一层,网络学习基本的边缘。 在下一层,它结合了这些边缘来学习更多的抽象概念,如眼睛和鼻子。 最后,它结合了那些识别个人面孔。

考虑到这一点,我们需要记住,每个层不仅仅是学习上一层的更多抽象组合。 连续层次隐含或明确地看到更多的输入



Increasing Receptive Field

在视觉领域,我们会希望网络识别图片中的一个或多个对象,而忽略其他对象。 也就是说,我们会对一些局部现象感兴趣,但并不在于跨越整个投入的关系。



A convolutional network learns to recognize hotdogs. It doesn’t care what the hot dog is on, that the table is made of wood etc. It only cares if it saw a hotdog. (Source)

文本更微妙,我们经常希望我们的数据的中间表示,尽可能多考虑上下文环境。 换句话说,我们希望拥有尽可能大的接受领域。 这里有几个方法来解决这个问题。

Larger Filters

第一个最明显的方法是增加Filter的大小,即进行[1x5]卷积而不是[1x3]。 在我的文字工作中,这种方法并没有取得很好的结果,我会提供我的推测为什么会这样。

在我的研究领域中,我主要处理字符级别的输入和形式非常丰富的文本。 我想到(至少第一个)卷积的层次作为学习n-gram,使得过滤器的宽度对应于二进制,三元组等。网络学习较大的n-gram早期暴露于较少的示例,因为有更多的 在文本中出现的“ab”比“abb”。

我从来没有证明过这种解释,但滤波器宽度大于3的结果一直较差。

Adding Layers

正如我们在上图中看到的,添加更多的层将增加接受野。 Dang Ha The Hien写了一个great guide,我建议您阅读。

添加图层有两个不同但相关的效果。 被提到的很多的是,该模型将学习对其获得的输入进行更高级别的抽象(Pixels => Edges => Eyes => Face)。 另一个是接受场在每一步都会增长。

This means that given enough depth, our network could look at the entire input layer though perhaps through a haze of abstractions. Unfortunately this is where the vanishing gradient problem may rear its ugly head.

The Gradient / Receptive field trade off

神经网络是信息流经的网络。 在输入流和转化的前向过程中,希望成为更适合我们任务的表示。 在后期阶段,我们通过网络回传信号,梯度。 就像在RNN一样,该信号经常被倍增,如果它经过一系列小于1的数字,那么它会消失到0。这意味着我们的网络最终会得到很少的信号来学习。

这让我们有了一些权衡。 一方面,我们希望能够尽可能多考虑上下文。 另一方面,如果我们尝试通过堆叠层来增加我们的接受野,我们会冒着消失的梯度和没有学习任何东西的风险。

Two Solutions to the Vanishing Gradient Problem

幸运的是,很多大牛一直在思考这些问题。 更幸运的是,这些不是文本独有的问题,研究视觉的人们也希望更大的接受领域和信息丰富的梯度。 让我们来看看他们的一些疯狂的想法,并用它们来进一步推动自己的文本的荣耀。

Residual Connections

对于研究计算机视觉的研究者们,2016年是另一个伟大的年份,至少有两个非常受欢迎的架构出现, ResNetsDenseNets(特别是DenseNet论文,写得非常好,非常值得阅读)。 他们都解决同样的问题—“如何使我的网络非常深而不失去梯度信号?”

Arthur Juliani 写下了关于Resnet, DenseNets and Highway networks的精彩概述,为您寻找他们之间的细节和对比。 我将简要介绍将核心概念推向极致的DenseNets。



A densenet architecture (Source)

一般的想法是减少来自网络loss的信号与每个单独层之间的距离。 这样做的方法是通过在每个层与其前身之间添加一个 residual/direct连接。 这样,梯度可以直接从每一层流向其前一层。

DenseNets以一种特别有趣的方式做到这一点。 它们将每个层的输出连接到其输入,使得:

我们从输入的嵌入开始,就是说维度10。

我们的第一层计算10个特征图。 它的输出连接到原始嵌入的10个特征映射。

第二层作为输入20维向量(来自输入的10个,前一层的10个),并计算另外10个特征图。 因此,它输出30维向量。

等等,等等你想要的层数。 该文献描述了一系列技巧,使事情可以管理和高效,但这是基本前提,梯度消失的问题得到解决。

还有另外两件事我想指出。

我之前提到,上层可以看到可能被抽象层所掩盖的原始输入的视图。连接每层输出的亮点之一是,原始信号完整地达到下列层,以便所有层都具有较低层次特征的直观视图,从而基本上去除了一些雾度。

Residual 连接技巧要求我们所有的层都具有相同的形状。这意味着我们需要填充每个层,使其输入和输出具有相同的空间维度[1Xwidth]。这意味着,这种架构本身就适用于序列标签任务(输入和输出具有相同的空间维度),但是需要更多的编码和分类任务(我们需要将输入减少到一个固定大小的向量或一组向量)。 DenseNet论文实际上处理这个问题,因为他们的目标是做分类,我们稍后会在这一点上展开。

Dilated Convolutions

Dilated convolutions AKA atrous convolutions AKA convolutions with holes 是增加接受场而不会激怒梯度的另一种方法。目前为止,当我们看堆叠层时,我们看到接收场随深度线性增长。Dilated convolutions使我们随着深度指数地增长接受场。

您可以在论文 Multi scale context aggregation by dilated convolutions 中找到扩展卷积的几乎合理的解释。虽然在概念上很简单,但花了我一段时间才能明确地了解他们的工作,我可能还是不太了解。

基本思想是在每个过滤器中引入“holes”,使其不在输入的相邻部分上操作,而是跳过它们到更远的部分。请注意,这与使用stride> 1的卷积不同。当我们跨越过滤器时,我们跳过卷积应用之间的部分输入。随着卷积的扩大,我们在卷积的单个应用中跳过了部分输入。通过巧妙地安排日益扩大的扩张,我们可以实现接受场的指数增长。



Here we have a 3X3 filter applied with a dilation of 1,2 and 3. With a dilation of 1 we have a standard convolution. With a dilation of 2 we apply the same 3X3 filter but use every second pixel.

到目前为止,我们已经谈到了很多理论,但是我们终于可以看到他们的实际作用了!

个人最喜欢的文章是Neural Machine Translation in Linear Time。 它遵循我们在开始时谈到的编码器解码器结构。 我们仍然没有工具来谈论解码器,但我们可以看到编码器在实际运行。



The Encoder part of bytenet based on dilated convolutions. Notice how four layers in the effective receptive field is 16. even though the filter widths are just 3. (Source)

这里有一个英文输入:

Director Jon Favreau, who is currently working on Disney’s forthcoming Jungle Book film, told the website Hollywood Reporter: “I think times are changing.”

通过扩大的卷积给你的翻译:

Regisseur Jon Favreau, der zur Zeit an Disneys kommendem Jungle Book Film arbeitet, hat der Website Hollywood Reporter gesagt: “Ich denke, die Zeiten andern sich”.

作为一个奖励,请记住,声音就像文本一样,它只具有一个空间/时间维度。 查看DeepMind的Wavenet,它使用扩大的卷积(和许多其他魔法)来生成human sounding speechpiano music

Getting Stuff Out of your network

当我们讨论DenseNets时,我提到使用residual connections迫使我们保持序列的输入和输出长度相同,这是通过填充完成的。 这对于我们需要在序列中标记每个项目的任务非常有用,例如:

在词性标注中,每个单词都是语音的一部分。

在实体识别中,我们可以将“人物”,“公司”和“其他”标记为其他内容

其他时候,我们要将输入序列减少到矢量表示,并用它来预测整个句子的内容

我们可能会根据其内容或主题将电子邮件标记为垃圾邮件

预测某句话是否讽刺

在这些情况下,我们可以按照传统的计算式视觉研究者们的观点,并以不具有填充和/或使用池操作的卷积层来覆盖我们的网络。

但是有时候,我们想要遵循Seq2Seq范式, Matthew Honnibal 简洁地称之为Embed, encode, attend, predict。 在这种情况下,我们将输入减少到一些向量表示,然后需要以某种方式将该向量的样本返回到适当长度的序列。

这个任务需要两个问题

我们如何用卷积进行上采样?

我们如何做正确的抽样数量?

我还没有找到第二个问题的答案,至少还没有明白。 在实践中,我已经足够让我在输出的最大长度上假设一些上限,然后向上补充。 我估计Facebook的 translation paper论文可能会解决这个问题,但还没有深入阅读它来评论。

Upsampling with deconvolutions

反卷积是我们上采样的工具。 很容易通过可视化来了解他们怎么做的。 幸运的是,几个大牛在Distill出版了一个关于deconvolutions的 great post on deconvolutions ,并包括一些有趣的可视化。 让我们从那些开始。



考虑顶部的图像。 如果我们把底层作为输入,我们有一个步幅1和宽度3的标准卷积。但是,我们也可以从上到下,即顶层作为输入,得到稍大的底层。

如果您停止思考一秒钟,则当您进行反向传播时,这种“自顶向下”操作已经在您的卷积网络中发生,因为梯度信号需要以完全如图所示的方式传播。 更好的是,事实证明,这个操作只是卷积操作的转置,因此这个操作的另一个常用(和技术上正确的)名称被转置卷积。

这里是它的乐趣。 We can stride our convolutions to shrink our input。 因此,我们可以stride 我们的deconvolutions来增加我们的输入。 我认为了解如何使用deconvolutions工作的最简单的方法是查看以下图片。



我们已经看到了最上面的一个。 请注意,每个输入(顶层)输入三个输出,每个输出由三个输入(边沿除外)馈送。



在第二张照片中,我们在输入中放置虚构的孔。 请注意,现在每个输出都由最多两个输入馈送。



在第三张照片中,我们在输出层中添加了两个虚拟孔,因此每个输出都只有一个输入。 这将使输出的序列长度相对于输入的序列长度增加三倍。

最后,我们可以堆叠多个解卷积层,逐渐将我们的输出层增长到所需的大小。

一些值得思考的事情:

从底部看这些图纸,他们最终成为标准的阶梯卷积,我们刚刚在输出层中添加了虚构的孔(白色块)

在实践中,每个“输入”不是单个数字而是向量。 在图像世界中,它可能是3维RGB值。 在文本中可能是一个300维字嵌入。 如果你(de)卷入网络中间,每个点都将是从最后一层出来的任何大小的向量。

我指出,为了说服你,他们在反卷积的输入层中有足够的信息来分散在输出的几个点上。

在实践中,我已经成功地运行了在反卷积之后一些保留填充长度相同后的卷积。 我想象,尽管没有证明,这就像是信息的重新分配。 像烧烤后让牛排休息,让果汁重新分配。



Summary

你可能想在你的工作中考虑卷积的主要原因是因为它们很快。 我认为,使研究和探索更快更有效率是至关重要的。 更快的网络缩短了我们的反馈周期。

与文字遇到的大部分任务最终都具有相同的体系结构要求:在保持足够的梯度流程的同时,最大限度地提高接受场。 我们已经看到使用DenseNets和dilated convolutions来实现这一点。

最后,有时候我们想将一个序列或一个向量扩展成一个更大的序列。 我们将deconvolutions视为对文本进行“上采样”的一种方式,并作为奖励,相比之下添加卷积,然后放牛排休息并重新分配果汁。

我想更多地了解关于这些模型中你的想法和经验。 请在Twitter @thetalperry评论
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息