NLP教程
TF_IDF
词向量
句向量
Seq2Seq 语言生成模型
CNN的语言模型
语言模型的注意力
Transformer 将注意力发挥到极致
ELMo 一词多义
GPT 单向语言模型
BERT 双向语言模型
NLP模型的多种应用
自然语言模型注意力
如果说在视觉上,机器可以注意到某一个区域,那么在语言上,就是注意到某一个或多个词汇。 如果我们的任务不同,这些注意力可能会想去获取不同区域的词汇。我们举个例子
如果男生代表着一种属性的注意力模型,面对这样一长串销售语言,它注意到的就是关于性能和配置的信息。 你看,如果有了注意力,那么我们的生命是不是被节省了很多。这两个人类模型的目的可以是输出购买意向, 也可以是生成下一句回复销售的对话。我们就拿生成回复来细说一下模型是如何工作的。
首先模型得先通读一下这段文字,毕竟如果没有上下文的信息, 我们也不知道究竟要注意些什么。通读完之后,我们可以得到一个对于这句话的理解,熟悉AI的人应该知道这东西叫句向量。 单独靠一个句向量我们实际上是通过全局信息来生成对话,那么注意力是局部信息,我们可以将全局信息配合局部信息一起来生成每一个回复的词。
所以女生回复的“樱桃红”可以是注意到的“亮樱桃红色”这句销售话术,而“买它”则可能是注意到“千元”和“降价”促成的回复。 所以总结下来,深度学习的注意力,和我们人类的注意力生理机制也有那么异曲同工之处。
Seq2Seq Attention 注意力机制
视觉中,模型注意局部的图片信息,那么语言中,模型注意局部的文字信息。
上图是一个情感分析的简单例子,如果我要区分一句话的积极程度,我可能会注意到这句话中某些词语的积极程度,因为这些词对于我判断积极句子起到了很大作用。 这样的attention注意力就很好理解了。箭头越粗的部分,模型的注意力就越集中。如果是翻译的情景,那注意力就像下面这样
Attention 的方案有很多种,这个方法在 decoder 用“爱”预测时,他会用“爱”这里的 state,结合上 encoder 中所有词的信息,生成一个注意力权重,比如模型会更加注意 encoder 中的爱和莫烦。 然后再结合这个权重,再次把权重施加到 encoder 中的每个 state,这样就有了对于不同 state step 的不一样关注度,注意力的结果(context)也在这里产生。 接着,把 context 和 decoder 那边的信息再次结合,最终输出注意后的答案。
补充一些数学信息,论文中提出了三种计算attention score的方式。 这里的 h t h_t ht 是 decoder 见到输入生成的 hidden state, h s ^ \hat{h_s} hs^ 是 encoder 见到输入时生成的 hidden state。 意思是decoder每预测一个词, 我都拿着这个decoder现在的信息去和encoder所有信息做注意力的计算。三个公式的不同点就是是否要引入更多的学习参数和变量。
翻译
在这节内容中,还是以翻译为例。延续前几次用到日期翻译的例子, 我们知道在翻译的模型中,实际上是要构建一个Encoder,一个Decoder。这节内容我们就是让Decoder在生成语言的时候,也注意到Encoder的对应部分。
# 中文的 "年-月-日" -> "day/month/year"
"98-02-26" -> "26/Feb/1998"
例子就是将中文的日期形式转换成英文的格式,同时我们也会输出类似这样的注意力图,让我们知道在模型生成某些字的时候,它究竟依据的是哪里的信息。 x轴是中文的年月日,y轴是要生成的英文日月年。
代码
先来看训练过程, 整个训练过程一如既往的简单,生成数据,建立模型,训练模型。数据的生成是提前写好的utils.DateData()功能。
def train():
# get and process data
data = utils.DateData(2000)
model = Seq2Seq(
data.num_word, data.num_word, emb_dim=12, units=14, attention_layer_size=16,
max_pred_len=11, start_token=data.start_token, end_token=data.end_token)
# training
for t in range(1000):
bx, by, decoder_len = data.sample(64)
loss = model.step(bx, by, decoder_len)
最后你能看到它的整个训练过程。最开始预测成渣渣,但是后面预测结果会好很多。你看刚训练几轮其实效果就已经很不错了,可见注意力的强大。
t: 0 | loss: 3.29403 | input: 89-05-25 | target: 25/May/1989 | inference: 00000000000
t: 70 | loss: 0.41608 | input: 03-09-13 | target: 13/Sep/2003 | inference: 13/Jan/2000<EOS>
t: 140 | loss: 0.01793 | input: 92-06-01 | target: 01/Jun/1992 | inference: 01/Jun/1992<EOS>
t: 210 | loss: 0.00309 | input: 23-01-28 | target: 28/Jan/2023 | inference: 28/Jan/2023<EOS>
...
t: 910 | loss: 0.00003 | input: 11-09-13 | target: 13/Sep/2011 | inference: 13/Sep/2011<EOS>
t: 980 | loss: 0.00003 | input: 06-08-10 | target: 10/Aug/2006 | inference: 10/Aug/2006<EOS>
模型构建时,在encoder部分其实和seq2seq的方法是没有什么变化的。 所以下面的代码和seq2seq也没有什么不同之处。
import tensorflow as tf
from tensorflow import keras
import numpy as np
import tensorflow_addons as tfa
class Seq2Seq(