自然语言处理[1]是计算机科学领域与人工智能领域中的另一个重要方向,其中很重要的一点就是语音识别(speech recognition)、机器翻译、智能机器人。
自然打量处理[1]是核算机科学范畴与人工智能范畴中的另一个重要方向,其间很重要的一点便是语音辨认(speech recognition)、机器翻译、智能机器人。
与打量相关的技能能够运用在许多当地。例如,日本的富国生命保险公司花费170万美元装置人工智能体系,把客户的打量转换为文本,并剖析这些词是正面的仍是负面的。这些自动化作业将协助人类更快地处理保险业务。除此之外,现在的人工智能公司也在把智能客服作为要点的研讨方向。
与图画辨认不同,在自然打量处理中输入的往往是一段语音或许一段文字,输入数据的长短是不确定的,而且它与上下文有很亲近的联系,所以常用的是循环神经网络(recurrent neural network,RNN)模型。
在本节里,咱们将别离介绍自然打量模型的挑选、神经机器翻译的原理,终究,用200余行PaddlePaddle代码手把手带领咱们做一个英法翻译机。
自然打量处理模型的挑选
下面咱们就来介绍运用不同输入和不同数据时,别离适用哪种模型以及怎么运用。
鄙人图中,每一个矩形是一个向量,箭头则表明函数(如矩阵相乘)。最下面一行为输入向量,最上面一行为输出向量,中心一行是RNN的状况。
图中从左到右别离表明以下几种状况。
(1)1对1:没有运用RNN,如Vanilla模型,从固定巨细的输入得到固定巨细输出(运用在图画分类)。
(2)一对多:以序列输出(运用在图片描绘,输入一张图片输出一段文字序列,这种往往需求CNN和RNN相结合,也便是图画和打量相结合,详见第12章)。
图
(3)多对一:以序列输入(运用在情感剖析,输入一段文字,然后将它分类成活泼或许消沉情感,如淘宝下某件产品的谈论分类),如运用LSTM。
(4)多对多:异步的序列输入和序列输出(运用在机器翻译,如一个RNN读取一条英文语句,然后将它以法语办法输出)。
(5)多对多:同步的序列输入和序列输出(运用在视频分类,对视频中每一帧打符号)。
咱们留意到,在上述解说中,因为中心RNN的状况的部分是固定的,能够屡次运用,所以不需求对序列长度进行预先特定束缚。更具体的谈论拜见Andrej Karpathy的文章《The Unreasonable Effectiveness of Recurrent Neural Networks》[2]。
自然打量处理一般包括语音组成(将文字生成语音)、语音辨认、声纹辨认(声纹鉴权),以及它们的一些扩展运用,以及文本处理,如分词、情感剖析、文本发掘等。
神经机器翻译原理
机器翻译的作用便是将一个源打量的序列(如英文Economic growth has slowed down in recent years)转化成方针打量序列(如法文La croissance economique sest ralentie ces dernieres annees)。其间翻译机器是需求运用已有的语料库(Corpora)来进行练习。
所谓的神经网络机器翻译便是运用神经网络来完成上述的翻译机器。依据神经网络的许多技能都是从Bengio的那篇开创性论文[3]衍生出来的。管中窥豹咱们介绍在机器翻译中最常用的重要技能及演进。
自然打量处理模型演进概览
咱们知道正如卷积神经网络(convolutional neural network,CNN)的演进从LeNet到AlexNet,再到VggNet、GoogLeNet,终究到ResNet,演进的办法有必定规则,而且也在ImageNet LSVRC比赛上用120万张图片、1000类符号上取得了很好的成果。循环神经网络(recurrent neural networks,RNN)的演进从vanilla RNN到躲藏层结构精巧的GRU和LSTM,再到双向和多层的Deep Bidirectional RNN,都有一些结构和演化头绪,下面咱们就首要来讨论。
Original LSTM
1997年Hochreiter和Schmidhuber首要提出了LSTM的网络结构,处理了传统RNN关于较长的序列数据,练习过程中简略呈现梯度消失或爆破的现象。Original LSTM的结构如下:
图
Standard LSTM
可是,传统的LSTM存在一个问题:跟着时间序列的增多,LSTM网络没有重置机制(比方两句话组成一句话作为输入的话,期望是在榜首句话完毕的时分进行重置),然后导致cell state简略发生饱满;另一方面输出h趋近于1,导致cell的输出近似等于output gate的输出,意味着网络丧失了memory的功用。比较于简略的循环神经网络,LSTM增加了回忆单元、输入门、忘记门及输出门。这些门及回忆单元组合起来大大广大了循环神经网络处理长序列数据的才能。
Standard LSTM的结构如下:
图[4]
GRU[5]
比较于简略的RNN,LSTM增加了回忆单元(memory cell)、输入门(input gate)、忘记门(forget gate)及输出门(output gate),这些门及回忆单元组合起来大大广大了RNN处理远距离依靠问题的才能。
GRU是Cho等人在LSTM上提出的简化版别,也是RNN的一种扩展,如下图所示。GRU单元只要两个门:
- 重置门(reset gate):假如重置门封闭,会疏忽掉前史信息,即前史不相干的信息不会影响未来的输出。
- 更新门(update gate):将LSTM的输入门和忘记门兼并,用于操控前史信息对当时时间隐层输出的影响。假如更新门挨近1,会把前史信息传递下去。
GRU(门控循环单元)
一般来说,具有短距离依靠特点的序列,其重置门比较活泼;相反,具有长距离依靠特点的序列,其更新门比较活泼。GRU尽管参数更少,可是在多个使命上都和LSTM有附近的体现。
双向循环神经网络
双向循环神经网络结构的意图是输入一个序列,得到其在每个时间的特征表明,即输出的每个时间都用定长向量表明到该时间的上下文语义信息。
具体来说,该双向循环神经网络别离在时间维以次序和逆序——即前向(forward)和后向(backward)——顺次处理输入序列,并将每个时间步RNN的输出拼接成为终究的输出层。这样每个时间步的输出节点,都包括了输入序列中当时时间完好的曩昔和未来的上下文信息。
下图展现的是一个按时间步翻开的双向循环神经网络。该网络包括一个前向和一个后向RNN,其间有六个权重矩阵:输入到前向隐层和后向隐层的权重矩阵(W1,W3W1,W3),隐层到隐层自己的权重矩阵(W2,W5W2,W5),前向隐层和后向隐层到输出层的权重矩阵(W4,W6W4,W6)。留意,该网络的前向隐层和后向隐层之间没有衔接。
图 按时间步翻开的双向循环神经网络
seq2seq+Attention
seq2seq模型是一个翻译模型,主要是把一个序列翻译成另一个序列。它的基本思想是用两个RNNLM,一个作为编码器,另一个作为解码器,组成RNN编码器-解码器。
在文本处理范畴,咱们常用编码器-解码器(encoder-decoder)结构,如图所示。
图
这是一种合适处理由一个上下文(context)生成一个方针(target)的通用处理模型。因而,关于一个语句对<X, Y>,当输入给定的语句X,经过编码器-解码器结构来生成方针语句Y。X和Y能够是不同打量,这便是机器翻译;X和Y能够是对话的问句和答句,这便是谈天机器人;X和Y能够是图片和这个图片的对应描绘(看图说话)。
X由x1、x2等单词序列组成,Y也由y1、y2等单词序列组成。编码器对输入的X进行编码,生成中心语义编码C,然后解码器对中心语义编码C进行解码,在每个i时间,结合现已生成的y1, y2,…, yi-1的前史信息生成Yi。可是,这个结构有一个缺陷,便是生成的语句中每一个词选用的中心语义编码是相同的,都是C。因而,在语句比较短的时分,还能比较恰当,语句长时,就显着不合语义了。
在实践完成谈天体系的时分,一般编码器和解码器都选用RNN模型以及RNN模型的改善模型LSTM。当语句长度超越30今后,LSTM模型的作用会急剧下降,一般此时会引进Attention模型,对长语句来说能够显着广大体系作用。
Attention机制是认知心理学层面的一个概念,它是指当人在做一件工作的时分,会专心地做这件事而疏忽周围的其他事。例如,人在专心地看这本书,会疏忽周围人说话的声响。这种机制运用在谈天机器人、机器翻译等范畴,就把源语句中对生成语句重要的关键词的权重进步,产生出更精确的应对。
增加了Attention模型的编码器-解码器结构如下图所示。
现在的中心语义编码变成了不断改变的Ci,能够出产更精确的方针Yi。
图
方针成果展现[6]
以中英翻译(中文翻译到英文)的模型为例,当模型练习完毕时,假如输入如下已分词的中文语句:
这些 是 期望 的 曙光 和 摆脱 的 痕迹 .
假如设定显现翻译成果的条数为3,生成的英语语句如下:
0 -5.36816 These are signs of hope and relief . <e>
1 -6.23177 These are the light of hope and relief . <e>
2 -7.7914 These are the light of hope and the relief of hope . <e>
左起榜首列是生成语句的序号;左起第二列是该条语句的得分(从大到小),分值越高越好;左起第三列是生成的英语语句。 别的有两个特别标志:<e>表明语句的完毕,<unk>表明未登录词(unknown word),即未在练习字典中呈现的词。
PaddlePaddle最佳实践[7]
下面咱们就来用200余行代码构建一个英法文翻译机。
数据集及数据预处理
本次实践运用WMT-14[8]数据会集的bitexts(after selection)作为练习集,dev+test data作为测验集和生成集。
数据集格局如下:
bitexts.selected数据集,共12075604行,有很多的并行数据的英文/法文对,约850M法文单词。这个数据是适当喧闹的,是神经网络练习的一大应战。因而,官方现已执行了数据挑选来提取最合适的数据。
“pc”之后的数字表明百分比。 一般咱们依据短语的基准体系仅在这些数据上进行练习。
ep7_pc45 Europarl版别7 (27.8M)
nc9 新闻谈论版别9 (5.5M)
2008年至2011年的dev08_11旧开发数据 (0.3M)
抓取常见抓取数据 (90M)
ccb2_pc30 10 ^ 9平行语料库 (81M)
un2000_pc34 联合国语料库 (143M)
下载后的数据文件如下:
咱们翻开Europarl版别7(ep7_pc45)数据一探终究。
less ep7_pc45.en
能够看到,英文版别的第8行:Me ?
less ep7_pc45.fr
能够看到,对应法文版别的第8行Moi ?
因为完好的数据集数据量较大,为了验证练习流程,PaddlePaddle接口paddle.dataset.wmt14中默许供给了一个经过预处理的较小规划的数据集(wmt14)。该数据集有193319条练习数据,6003条测验数据,词典长度为30000。咱们能够在这个数据集上对模型进行试验;但真实需求练习,仍是主张选用原始数据集。
咱们对这个较小规划的数据集进行预处理。预处理后的文件如下:
预处理流程包括3步:
1.将每个源打量到方针打量的平行语料库文件兼并为一个文件;
2.兼并每个XXX.src和XXX.trg文件为XXX。 - XXX中的第i行内容为XXX.src中的第i行和XXX.trg中的第i行衔接,用'\t'分隔。 如train和test中处理后如下,下图每一行是一句法文和英文的平行语料,红框处代表两句之间用’\t’的分隔:
3.创立练习数据的“源字典”和“方针字典”。每个字典都有DICTSIZE个单词,包括:语料中词频最高的(DICTSIZE - 3)个单词,和3个特别符号<s>(序列的开端)、<e>(序列的完毕)和<unk>(未登录词)。得到的src.dict(法文词典)和trg.dict(英文词典)别离如下:
最佳实践[9]
数据处理好后,接下来咱们就开端编写代码建立神经网络及练习。[10]
paddle初始化
首要,进行paddle的初始化,直接导入Python版别的Paddle库,和TensorFlow很类似。
# 加载 paddle的python包
import sys
import paddle.v2 as paddle
# 装备只运用cpu,而且运用一个cpu进行练习
paddle.init(use_gpu=False, trainer_count=1)
# 练习形式False,生成形式True
is_generating = False
全局变量及超参数界说
管中窥豹,因为咱们对数据预处理做了30000维的数据字典,所以在全局变量中也填写对应的值。
dict_size = 30000 # 字典维度
source_dict_dim = dict_size # 源打量字典维度
target_dict_dim = dict_size # 方针打量字典维度
word_vector_dim = 512 # 词向量维度
encoder_size = 512 # 编码器中的GRU隐层巨细
decoder_size = 512 # 解码器中的GRU隐层巨细
beam_size = 3 # 柱宽度
max_length = 250 # 生成语句的最大长度
构建模型
首要,构建编码器结构:
输入是一个文字序列,被表明成整型的序列。序列中每个元素是文字在字典中的索引。所以,咱们界说数据层的数据类型为integer_value_sequence(整型序列),序列中每个元素的规模是[0, source_dict_dim]。
src_word_id = paddle.layer.data(
name='source_language_word',
type=paddle.data_type.integer_value_sequence(source_dict_dim))
将上述编码映射到低维打量空间的词向量s。
src_embedding = paddle.layer.embedding(
input=src_word_id, size=word_vector_dim)
用双向GRU编码源打量序列,拼接两个GRU的编码成果得到h。
src_forward = paddle.networks.simple_gru(
input=src_embedding, size=encoder_size)
src_backward = paddle.networks.simple_gru(
input=src_embedding, size=encoder_size, reverse=True)
encoded_vector = paddle.layer.concat(input=[src_forward, src_backward])
接着,构建依据留意力机制的解码器结构:
对源打量序列编码后的成果(即上面的encoded_vector),过一个前馈神经网络(Feed Forward Neural Network),得到其映射。
encoded_proj = paddle.layer.fc(
act=paddle.activation.Linear(),
size=decoder_size,
bias_attr=False,
input=encoded_vector)
结构解码器RNN的初始状况。
backward_first = paddle.layer.first_seq(input=src_backward)
decoder_boot = paddle.layer.fc(
size=decoder_size,
act=paddle.activation.Tanh(),
bias_attr=False,
input=backward_first)
界说解码阶段每一个时间步的RNN行为。
def gru_decoder_with_attention(enc_vec, enc_proj, current_word):
decoder_mem = paddle.layer.memory(
name='gru_decoder', size=decoder_size, boot_layer=decoder_boot)
context = paddle.networks.simple_attention(
encoded_sequence=enc_vec,
encoded_proj=enc_proj,
decoder_state=decoder_mem)
decoder_inputs = paddle.layer.fc(
act=paddle.activation.Linear(),
size=decoder_size * 3,
bias_attr=False,
input=[context, current_word],
layer_attr=paddle.attr.ExtraLayerAttribute(
error_clipping_threshold=100.0))
gru_step = paddle.layer.gru_step(
name='gru_decoder',
input=decoder_inputs,
output_mem=decoder_mem,
size=decoder_size)
out = paddle.layer.mixed(
size=target_dict_dim,
bias_attr=True,
act=paddle.activation.Softmax(),
input=paddle.layer.full_matrix_projection(input=gru_step))
return out
那在练习形式下的解码器怎么调用呢?
首要,将方针打量序列的词向量trg_embedding,直接作为练习形式下的current_word传给gru_decoder_with_attention函数。
其次,运用recurrent_group函数循环调用gru_decoder_with_attention函数。
接着,运用方针打量的下一个词序列作为标签层lbl,即猜测方针词。
终究,用多类穿插熵丢失函数classification_cost来核算丢失值。
代码如下:
if not is_generating:
trg_embedding = paddle.layer.embedding(
input=paddle.layer.data(
name='target_language_word',
type=paddle.data_type.integer_value_sequence(target_dict_dim)),
size=word_vector_dim,
param_attr=paddle.attr.ParamAttr(name='_target_language_embedding'))
group_inputs.append(trg_embedding)
# For decoder equipped with attention mechanism, in training,
# target embeding (the groudtruth) is the data input,
# while encoded source sequence is accessed to as an unbounded memory.
# Here, the StaticInput defines a read-only memory
# for the recurrent_group.
decoder = paddle.layer.recurrent_group(
name=decoder_group_name,
step=gru_decoder_with_attention,
input=group_inputs)
lbl = paddle.layer.data(
name='target_language_next_word',
type=paddle.data_type.integer_value_sequence(target_dict_dim))
cost = paddle.layer.classification_cost(input=decoder, label=lbl)
那生成(猜测)形式下的解码器怎么调用呢?
首要,在序列生成使命中,因为解码阶段的RNN总是引用上一时间生成出的词的词向量,作为当时时间的输入,
其次,运用beam_search函数循环调用gru_decoder_with_attention函数,生成出序列id。
if is_generating:
# In generation, the decoder predicts a next target word based on
# the encoded source sequence and the previous generated target word.
# The encoded source sequence (encoder's output) must be specified by
# StaticInput, which is a read-only memory.
# Embedding of the previous generated word is automatically retrieved
# by GeneratedInputs initialized by a start mark <s>.
trg_embedding = paddle.layer.GeneratedInput(
size=target_dict_dim,
embedding_name='_target_language_embedding',
embedding_size=word_vector_dim)
group_inputs.append(trg_embedding)
beam_gen = paddle.layer.beam_search(
name=decoder_group_name,
step=gru_decoder_with_attention,
input=group_inputs,
bos_id=0,
eos_id=1,
beam_size=beam_size,
max_length=max_length)
练习模型
1.结构数据界说
咱们获取wmt14的dataset reader。
if not is_generating:
wmt14_reader = paddle.batch(
paddle.reader.shuffle(
paddle.dataset.wmt14.train(dict_size=dict_size), buf_size=8192),
batch_size=5)
2.结构trainer
依据优化方针cost,网络拓扑结构和模型参数来结构出trainer用来练习,在结构时还需指定优化办法,管中窥豹运用最基本的SGD办法。
if not is_generating:
optimizer = paddle.optimizer.Adam(
learning_rate=5e-5,
regularization=paddle.optimizer.L2Regularization(rate=8e-4))
trainer = paddle.trainer.SGD(cost=cost,
parameters=parameters,
update_equation=optimizer)
3.结构event_handler
能够经过自界说回调函数来评价练习过程中的各种状况,比方错误率等。下面的代码经过event.batch_id % 2 == 0 指定每2个batch打印一次日志,包括cost等信息。
if not is_generating:
def event_handler(event):
if isinstance(event, paddle.event.EndIteration):
if event.batch_id % 2 == 0:
print "\nPass %d, Batch %d, Cost %f, %s" % (
event.pass_id, event.batch_id, event.cost, event.metrics)
4.发动练习
if not is_generating:
trainer.train(
reader=wmt14_reader, event_handler=event_handler, num_passes=2)
随后,就能够开端练习了。练习开端后,能够观察到event_handler输出的日志如下:
Pass 0, Batch 0, Cost 148.444983, {'classification_error_evaluator': 1.0}
.........
Pass 0, Batch 10, Cost 335.896802, {'classification_error_evaluator': 0.9325153231620789}
.........
猜测模型
咱们加载预练习的模型,然后从wmt14生成会集读取样本,试着生成成果。
1.加载预练习的模型
if is_generating:
parameters = paddle.dataset.wmt14.model()
2. 数据界说
从wmt14的生成会集读取前3个样本作为源打量语句。
if is_generating:
gen_creator = paddle.dataset.wmt14.gen(dict_size)
gen_data = []
gen_num = 3
for item in gen_creator():
gen_data.append((item[0], ))
if len(gen_data) == gen_num:
break
3. 结构infer
依据网络拓扑结构和模型参数结构出infer用来生成,在猜测时还需求指定输出域field,管中窥豹运用生成语句的概率prob和语句中每个词的id。
if is_generating:
beam_result = paddle.infer(
output_layer=beam_gen,
parameters=parameters,
input=gen_data,
field=['prob', 'id'])
4.打印生成成果
依据源/方针打量字典,将源打量语句和beam_size个生成语句打印输出。
if is_generating:
# load the dictionary
src_dict, trg_dict = paddle.dataset.wmt14.get_dict(dict_size)
gen_sen_idx = np.where(beam_result[1] == -1)[0]
assert len(gen_sen_idx) == len(gen_data) * beam_size
# -1 is the delimiter of generated sequences.
# the first element of each generated sequence its length.
start_pos, end_pos = 1, 0
for i, sample in enumerate(gen_data):
print(" ".join([src_dict[w] for w in sample[0][1:-1]]))
for j in xrange(beam_size):
end_pos = gen_sen_idx[i * beam_size + j]
print("%.4f\t%s" % (beam_result[0][i][j], " ".join(
trg_dict[w] for w in beam_result[1][start_pos:end_pos])))
start_pos = end_pos + 2
print("\n")
生成开端后,能够观察到输出的日志如下:
日志的榜首行为源打量的语句。下面的三行别离是分数由高到低摆放的生成的英文翻译成果。
总结
管中窥豹咱们侧重解说了自然打量处理傍边神经机器翻译的原理,以及怎么用200余行PaddlePaddle代码做一个英法翻译机。更多的,PaddlePaddle在
线性回归、辨认数字、图画分类、词向量、个性化引荐、情感剖析、语义人物标示等各个范畴也有十分老练的运用和简练易上手示例,等待和咱们一同讨论。
1.广义的自然打量处理包括语音处理及文本处理,狭义的单指了解和处理文本。管中窥豹指广义的概念。 ↑
2.http://karpathy.github.io/2015/05/21/rnn-effectiveness/ ↑
3.《A Neural Probabilistic Language Model》 ↑
4.https://github.com/PaddlePaddle/book/blob/develop/06.understand_sentiment/README.cn.md ↑
5.http://staging.paddlepaddle.org/docs/develop/book/08.machine_translation/index.cn.html#%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE ↑
6.http://staging.paddlepaddle.org/docs/develop/book/08.machine_translation/index.cn.html#%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE ↑
7.http://staging.paddlepaddle.org/docs/develop/book/08.machine_translation/index.cn.html#%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE ↑
8.http://www-lium.univ-lemans.fr/~schwenk/cslm_joint_paper/ ↑
9.http://staging.paddlepaddle.org/docs/develop/book/08.machine_translation/index.cn.html#%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE ↑
10.https://github.com/PaddlePaddle/book/blob/develop/08.machine_translation/train.py ↑