作者 : Christopher Olah (OpenAI)
译者 :朱小虎 Xiaohu (Neil) Zhu(CSAGI / University AI)
原文链接 : https://colahgithubio/posts/2015-08-Understanding-LSTMs/
术语 : 循环神经网络(Recurrent Neural Network, 简称 RNN); 长短期记忆(Long Short-Term Memory, 简称 LSTM); 门限循环单元(Gated Recurrent Unit, 简称 GRU)
人类并不是每时每刻都从一片空白的大脑开始他们的思考。在你阅读这篇文章时候,你都是基于自己已经拥有的对先前所见词的理解来推断当前词的真实含义。我们不会将所有的东西都全部丢弃,然后用空白的大脑进行思考。我们的思想拥有持久性。
传统的神经网络并不能做到这点,看起来也像是一种巨大的弊端。例如,假设你希望对**中的每个时间点的时间类型进行分类。传统的神经网络应该很难来处理这个问题——使用**中先前的事件推断后续的事件。
RNN 解决了这个问题。RNN 是包含循环的网络,允许信息的持久化。
在上面的示例图中,神经网络的模块, ,正在读取某个输入 ,并输出一个值 。循环可以使得信息可以从当前步传递到下一步。
这些循环使得 RNN 看起来非常神秘。然而,如果你仔细想想,这样也不比一个正常的神经网络难于理解。RNN 可以被看做是同一神经网络的多次复制,每个神经网络模块会把消息传递给下一个。所以,如果我们将这个循环展开:
链式的特征揭示了 RNN 本质上是与序列和列表相关的。他们是对于这类数据的最自然的神经网络架构。
并且 RNN 也已经被人们应用了!在过去几年中,应用 RNN 在语音识别,语言建模,翻译,描述等问题上已经取得一定成功,并且这个列表还在增长。我建议大家参考 Andrej Karpathy 的博客文章—— The Unreasonable Effectiveness of Recurrent Neural Networks 来看看更丰富有趣的 RNN 的成功应用。
而这些成功应用的关键之处就是 LSTM 的使用,这是一种特别的 RNN,比标准的 RNN 在很多的任务上都表现得更好。几乎所有的令人振奋的关于 RNN 的结果都是通过 LSTM 达到的。这篇博文也会就 LSTM 进行展开。
RNN 的关键点之一就是他们可以用来连接先前的信息到当前的任务上,例如使用过去的视频段来推测对当前段的理解。如果 RNN 可以做到这个,他们就变得非常有用。但是真的可以么?答案是,还有很多依赖因素。
有时候,我们仅仅需要知道先前的信息来执行当前的任务。例如,我们有一个语言模型用来基于先前的词来预测下一个词。如果我们试着预测 “the clouds are in the sky” 最后的词,我们并不需要任何其他的上下文 —— 因此下一个词很显然就应该是 sky。在这样的场景中,相关的信息和预测的词位置之间的间隔是非常小的,RNN 可以学会使用先前的信息。
但是同样会有一些更加复杂的场景。假设我们试着去预测“I grew up in France I speak fluent French”最后的词。当前的信息建议下一个词可能是一种语言的名字,但是如果我们需要弄清楚是什么语言,我们是需要先前提到的离当前位置很远的 France 的上下文的。这说明相关信息和当前预测位置之间的间隔就肯定变得相当的大。
不幸的是,在这个间隔不断增大时,RNN 会丧失学习到连接如此远的信息的能力。
在理论上,RNN 绝对可以处理这样的 长期依赖 问题。人们可以仔细挑选参数来解决这类问题中的最初级形式,但在实践中,RNN 肯定不能够成功学习到这些知识。 Bengio, et al (1994) 等人对该问题进行了深入的研究,他们发现一些使训练 RNN 变得非常困难的相当根本的原因。
然而,幸运的是,LSTM 并没有这个问题!
Long Short Term 网络—— 一般就叫做 LSTM ——是一种 RNN 特殊的类型,可以学习长期依赖信息。LSTM 由 Hochreiter & Schmidhuber (1997) 提出,并在近期被 Alex Graves 进行了改良和推广。在很多问题,LSTM 都取得相当巨大的成功,并得到了广泛的使用。
LSTM 通过刻意的设计来避免长期依赖问题。记住长期的信息在实践中是 LSTM 的默认行为,而非需要付出很大代价才能获得的能力!
所有 RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中,这个重复的模块只有一个非常简单的结构,例如一个 tanh 层。
LSTM 同样是这样的结构,但是重复的模块拥有一个不同的结构。不同于 单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。
不必担心这里的细节。我们会一步一步地剖析 LSTM 解析图。现在,我们先来熟悉一下图中使用的各种元素的图标。
在上面的图例中,每一条黑线传输着一整个向量,从一个节点的输出到其他节点的输入。粉色的圈代表按位 pointwise 的操作,诸如向量的和,而**的矩阵就是学习到的神经网络层。合在一起的线表示向量的连接,分开的线表示内容被复制,然后分发到不同的位置。
LSTM 的关键就是细胞状态,水平线在图上方贯穿运行。
细胞状态类似于传送带。直接在整个链上运行,只有一些少量的线性交互。信息在上面流传保持不变会很容易。
LSTM 有通过精心设计的称作为“门”的结构来去除或者增加信息到细胞状态的能力。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个按位的乘法操作。
Sigmoid 层输出 到 之间的数值,描述每个部分有多少量可以通过。 代表“不许任何量通过”, 就指“允许任意量通过”!
LSTM 拥有三个门,来保护和控制细胞状态。
在我们 LSTM 中的第一步是决定我们会从细胞状态中丢弃什么信息。这个决定通过一个称为 忘记门层 完成。该门会读取 和 ,输出一个在 到 之间的数值给每个在细胞状态 中的数字。 表示“完全保留”, 表示“完全舍弃”。
让我们回到语言模型的例子中来基于已经看到的预测下一个词。在这个问题中,细胞状态可能包含当前 主语 的性别,因此正确的 代词 可以被选择出来。当我们看到新的 主语 ,我们希望忘记旧的 主语 。
下一步是确定什么样的新信息被存放在细胞状态中。这里包含两个部分。第一, sigmoid 层称 “输入门层” 决定什么值我们将要更新。然后,一个 tanh 层创建一个新的候选值向量, ,会被加入到状态中。下一步,我们会讲这两个信息来产生对状态的更新。
在我们语言模型的例子中,我们希望增加新的主语的性别到细胞状态中,来替代旧的需要忘记的主语。
现在是更新旧细胞状态的时间了, 更新为 。前面的步骤已经决定了将会做什么,我们现在就是实际去完成。
我们把旧状态与 相乘,丢弃掉我们确定需要丢弃的信息。接着加上 。这就是新的候选值,根据我们决定更新每个状态的程度进行变化。
在语言模型的例子中,这就是我们实际根据前面确定的目标,丢弃旧代词的性别信息并添加新的信息的地方。
最终,我们需要确定输出什么值。这个输出将会基于我们的细胞状态,但是也是一个过滤后的版本。首先,我们运行一个 sigmoid 层来确定细胞状态的哪个部分将输出出去。接着,我们把细胞状态通过 tanh 进行处理(得到一个在 到 之间的值)并将它和 sigmoid 门的输出相乘,最终我们仅仅会输出我们确定输出的那部分。
在语言模型的例子中,因为他就看到了一个 代词 ,可能需要输出与一个 动词 相关的信息。例如,可能输出是否代词是单数还是负数,这样如果是动词的话,我们也知道动词需要进行的词形变化。
我们到目前为止都还在介绍正常的 LSTM。但是不是所有的 LSTM 都长成一个样子的。实际上,几乎所有包含 LSTM 的论文都采用了微小的变体。差异非常小,但是也值得拿出来讲一下。
其中一个流形的 LSTM 变体,就是由 Gers & Schmidhuber (2000) 提出的,增加了 “peephole connection”。是说,我们让 门层 也会接受细胞状态的输入。
上面的图例中,我们增加了 peephole 到每个门上,但是许多论文会加入部分的 peephole 而非所有都加。
另一个变体是通过使用 coupled 忘记和输入门。不同于之前是分开确定什么忘记和需要添加什么新的信息,这里是一同做出决定。我们仅仅会当我们将要输入在当前位置时忘记。我们仅仅输入新的值到那些我们已经忘记旧的信息的那些状态 。
另一个改动较大的变体是 Gated Recurrent Unit (GRU),这是由 Cho, et al (2014) 提出。它将忘记门和输入门合成了一个单一的 更新门。同样还混合了细胞状态和隐藏状态,和其他一些改动。最终的模型比标准的 LSTM 模型要简单,也是非常流行的变体。
这里只是部分流行的 LSTM 变体。当然还有很多其他的,如 Yao, et al (2015) 提出的 Depth Gated RNN。还有用一些完全不同的观点来解决长期依赖的问题,如 Koutnik, et al (2014) 提出的 Clockwork RNN。
要问哪个变体是最好的?其中的差异性真的重要吗? Greff, et al (2015) 给出了流行变体的比较,结论是他们基本上是一样的。 Jozefowicz, et al (2015) 则在超过 1 万种 RNN 架构上进行了测试,发现一些架构在某些任务上也取得了比 LSTM 更好的结果。
刚开始,我提到通过 RNN 得到重要的结果。本质上所有这些都可以使用 LSTM 完成。对于大多数任务确实展示了更好的性能!
由于 LSTM 一般是通过一系列的方程表示的,使得 LSTM 有一点令人费解。然而本文中一步一步地解释让这种困惑消除了不少。
LSTM 是我们在 RNN 中获得的重要成功。很自然地,我们也会考虑:哪里会有更加重大的突破呢?在研究人员间普遍的观点是:“Yes! 下一步已经有了——那就是 注意力 !” 这个想法是让 RNN 的每一步都从更加大的信息集中挑选信息。例如,如果你使用 RNN 来产生一个的描述,可能会选择的一个部分,根据这部分信息来产生输出的词。实际上, Xu, et al (2015) 已经这么做了——如果你希望深入探索 注意力 可能这就是一个有趣的起点!还有一些使用注意力的相当振奋人心的研究成果,看起来有更多的东西亟待探索……
注意力也不是 RNN 研究领域中唯一的发展方向。例如, Kalchbrenner, et al (2015) 提出的 Grid LSTM 看起来也是很有前途。使用生成模型的 RNN,诸如 Gregor, et al (2015) Chung, et al (2015) 和 Bayer & Osendorfer (2015) 提出的模型同样很有趣。在过去几年中,RNN 的研究已经相当的燃,而研究成果当然也会更加丰富!
I’m grateful to a number of people for helping me better understand LSTMs, commenting on the visualizations, and providing feedback on this post
I’m very grateful to my colleagues at Google for their helpful feedback, especially Oriol Vinyals , Greg Corrado , Jon Shlens , Luke Vilnis , and Ilya Sutskever I’m also thankful to many other friends and colleagues for taking the time to help me, including Dario Amodei , and Jacob Steinhardt I’m especially thankful to Kyunghyun Cho for extremely thoughtful correspondence about my diagrams
Before this post, I practiced explaining LSTMs during two seminar series I taught on neural networks Thanks to everyone who participated in those for their patience with me, and for their feedback
微博言论往往带有强烈的情感色彩,对微博言论的情感分析是获取用户观点态度的重要方法。许多学者都是将研究的重点集中在句子词性、情感符号以及情感语料库等方面,然而用户自身的情感倾向性并没有受到足够的重视,因此,提出了一种新的微博情感分类方法,其通过建模用户自身的情感标志得分来帮助识别语句的情感特征,具体地讲,将带有情感信息的微博语句词向量序列输入到长短期记忆网络(LSTM),并将LSTM输出的特征表示与用户情感得分进行结合作为全连接层的输入,并通过Softmax层实现了对微博文本的情感极性分类。实验表明,提出的方法UA-LSTM在情感分类任务上的表现超过的所有基准方法,并且比最优的基准方法MF-CNN在F1值上提升了34%,达到091。
关键词: 情感分析, 长短期记忆网络, 用户情感倾向
Abstract:
Micro-blog's speech often has strong sentimental color, and the sentiment analysis of Micro-blog's speech is an important way to get users' opinions and attitudes Many researchers conduct research via focusing on the parts of speech (POS), emotion symbol and emotion corpus This paper proposes a novel method for Micro-blog sentiment analysis, which aims to identify the sentiment features of a text by modeling user sentiment tendency Specifically, we construct a sentiment information embedded word embedding sequence, and input it into a long short term memory (LSTM) model to get a sentiment embedded output representation Then we merge both the user sentiment tendency score and the output representation of LSTM, and use it as the input of a fully connected layer which is followed by a softmax layer to get the final sentiment classification result The experiment shows that the performance of our proposed method UA-LSTM is better than all the baseline methods on the sentimental classification task, and it achieves the F1-score up to 091, with an improvement of 34% over the best baseline method MF-CNN
与人类理解文字的道理差不多,看书都是一个字一个字,一句话一句话去理解的。语言本身作为一种符号并没有意义,只不过是人类对其赋予了意义。而这种意义体现在每个字(语义)以及字的顺序(语义关系)上。RNN相当于在通用神经网络上加入了人的 先验知识 ,将文本信息按照序列输入的方式处理。
RNN对序列的基本思路是: 在序列任务中前面的数据会对当前的计算产生影响。 所以前一个cell的激活值会输入到后一个cell中。这样就其实就是对序列数据的特点做了一定程度的设计。
但是随着序列长度变化,激活值不断堆叠后就会损失一些信息,导致序列前面的信息对后面的影响变弱。要知道很多时候语言的头部信息对后面的信息可能有很大的影响。所以目前应用较广泛的是LSTM模型,在RNN基础结构上增加了一条长记忆线C,每个cell的X与A会使得C对信息进行补充或者丢失,而具有序列重要信息的C会对A的激活值具有影响。就像是模型附带了一个小本本,遇到新鲜事儿就记进去,然后在后续判断将小本本的信息加入,产出更有可信度的激活值。
在RNN应用过程中,逐渐发现有时候当前局部的计算不仅仅与前面的信息相关,也与后面的信息相关(特别是翻译、语音识别等)。所以提出了 双向RNN结构 ,将前面的信息与后面的信息综合起来做判断。
人在进行信息判断时,有时候不仅仅是综合整个序列的信息,有时候更会抓住重点去分析以便快速得到更好的答案,在序列模型中每个输入本身确实有重点,比如吃与食物相关,在分析吃的字词时只需将注意力分配到与食物相关得词上,其他的并不重要,因此提出了 注意力模型 。
如图所示,经过一个双向RNN处理过的输出值y,不同的y分配给不同的权重最终加和起来作为输入,那么该输入附带的信息就会有偏向,从而模型会有更好的效果。
正如前文所说,所有的模型都不完美,在拟合过程中就会出现信息丢失、梯度消失等现象,长短时记忆、双向计算、注意力机制都是典型的将人类知识加入模型中,使得模型负担减少,效果更好。
将语料库通过RNN模型训练后,模型就学会了人话的规律,从而可以在给定条件下判断下一个字是何字的概率,从而在多个场景有所应用:
同样的方式可以应用在音乐上,如果将音乐也当做一种序列去训练,最终我们也可以获得某种音乐风格的曲子,从而可以实现在文字上以及在音乐上的另类创作。
将RNN模型对接一个softmax输出,就可以对句子进行分类,通常用来判断情感趋向。
除了可以通过分析句子得到情感判断外,分析词语也可以。目前词的使用都是将符号向量映射( Word2Vec 算法)到语义空间上,所以词向量本身就具有语义含义,通过训练可以做情感分类。
翻译目前都是用如图所示结构,包含编码器与解码器。相当于将语句A通过RNN编码后灌入另一个模型去解码为另一个语句B,类似于卷积对的编码处理,序列模型在编码解码过程中也形成了一个表征语义的矩阵,该矩阵的语义表达与语言工具无关,作为两个语言之间的桥梁实现翻译功能。借鉴人类翻译过程中对前后文重点的读取,翻译模型会用到注意力机制以达到更好的模型效果
实际上前一阵子出现过AI换脸这种生成式的任务在社区火爆,特别是色情网站。其实这种生成任务很多时候也会用到这种编码-解码样式的结构
目前人机对话包含应用场景:问答型、聊天型、任务型。
问答型 在很多客服领域应用广泛,解决了头部高频问题。这类任务更多属于机器学习,对用户的疑问通过关键字检测分类至我们预先设好的问题分类中。
聊天型机器人 最典型的就是微软小冰,要保持这种开放性对话需要系统知识,不断产生新的话题。这类Chatbot的目标是实现《her》中的情感陪伴,但是就目前发展来讲,仍然不够。
任务型机器人 目前看起来最具有商业潜力,市面上的智能音箱基本属于这类范畴。目标是识别用户意图后在封闭的话题区间内进行对话直至满足用户需求。
在任务驱动型的人机对话中,首先就是获取人的意图。意图的识别属于自然语言理解,属于一种分类任务。很多智能音箱平台会推出一些技能,这些技能实际上就对应意图所对应的领域。通过意图识别后将业务处理逻辑落在这些技能上,技能与技能之间其实已经没有关联,这样的方式减轻了训练难度,使得机器人在特定任务上有更好的表现。
在计算机处理人类请求后,不仅要判断用户的意图分类,还要对请求语进行序列标注(实体识别、实体关系抽取等),分析出该意图下哪些必要信息已经获得,哪些信息没有获得,这些就是填槽的过程。
用户的请求往往是含糊不清的,多轮对话就是为了获取在该意图下所有的必要信息。整个过程需要对话管理的支持,对话管理实际一个决策过程(策略树),系统在对话过程中不断根据当前状态决定下一步应该采取的最优动作(如:提供结果,询问特定限制条件,澄清或确认需求…)从而最有效的辅助用户完成信息或服务获取的任务。对话管理的构建更需要人工设计,但似乎通过强化学习也能得到最佳路径。
DM对话管理过程中可能需要和用户交互,就会用到自然语言生成,将系统语义转化为人类语言。这是个有限集,用模板是一种选择,同样也可以用语言模型、类似翻译的编码解码模型。
neg=pdread_excel('negxls',header=None,index=None)
pos=pdread_excel('posxls',header=None,index=None) #读取训练语料完毕
pos['mark']=1
neg['mark']=0 #给训练语料贴上标签
pn=pdconcat([pos,neg],ignore_index=True) #合并语料
neglen=len(neg)
poslen=len(pos) #计算语料数目
cw = lambda x: list(jiebacut(x)) #定义分词函数
pn['words'] = pn[0]apply(cw)
comment = pdread_excel('sumxls') #读入评论内容
#comment = pdread_csv('acsv', encoding='utf-8')
comment = comment[comment['rateContent']notnull()] #仅读取非空评论
comment['words'] = comment['rateContent']apply(cw) #评论分词
d2v_train = pdconcat([pn['words'], comment['words']], ignore_index = True)
w = [] #将所有词语整合在一起
for i in d2v_train:
wextend(i)
dict = pdDataFrame(pdSeries(w)value_counts()) #统计词的出现次数
del w,d2v_train
dict['id']=list(range(1,len(dict)+1))
get_sent = lambda x: list(dict['id'][x])
pn['sent'] = pn['words']apply(get_sent)
maxlen = 50
print "Pad sequences (samples x time)"
pn['sent'] = list(sequencepad_sequences(pn['sent'], maxlen=maxlen))
x = nparray(list(pn['sent']))[::2] #训练集
y = nparray(list(pn['mark']))[::2]
xt = nparray(list(pn['sent']))[1::2] #测试集
yt = nparray(list(pn['mark']))[1::2]
xa = nparray(list(pn['sent'])) #全集
ya = nparray(list(pn['mark']))
print 'Build model'
model = Sequential()
modeladd(Embedding(len(dict)+1, 256))
modeladd(LSTM(256, 128)) # try using a GRU instead, for fun
modeladd(Dropout(05))
modeladd(Dense(128, 1))
modeladd(Activation('sigmoid'))
modelcompile(loss='binary_crossentropy', optimizer='adam', class_mode="binary")
print 'Fit model'
modelfit(xa, ya, batch_size=32, nb_epoch=4) #训练时间为若干个小时
classes = modelpredict_classes(xa)
acc = np_utilsaccuracy(classes, ya)
print 'Test accuracy:', acc
可以试一试
w = [] #将所有词语整合在一起
for i in d2v_train:
wextend(i)
newList = list(set(w))
print "newlist len is"
print len(newList)
dict = pdDataFrame(pdSeries(w)value_counts()) #统计词的出现次数
print type(dict)
print len(dict)
欢迎分享,转载请注明来源:浪漫分享网
评论列表(0条)