前言自然语言处理(简称NLP)是一种研究计算机处理人类语言的技术。NLP技术使计算机能够基于一套技术和理论来分析和理解人类的交流内容。传统的自然语言处理方法涉及到很多语言学本身的知识,而深度学习是一种表示学习(representationlearning)的方法,应用于机器翻译、自动问答、文本分类、情感分析、信息抽取、序列标注等,它在语法分析等领域有着广泛的应用。谷歌2013年底发布的word2vec工具,将一个词表示为词向量,将文本数字化,有效应用于文本分析。2016年,谷歌开源了自动文本摘要模型和相关的TensorFlow代码。2016/2017年,Google发布/升级了语言处理框架SyntaxNet,识别率提高了25%,并为40种语言带来了文本分割和词法分析功能。2017年,谷歌正式开源了tf-seq2seq,一个用于自动翻译的通用编码器/解码器框架。本文主要结合TensorFlow平台讲解TensorFlow词向量生成模型(VectorRepresentationsofWords);使用RNN、LSTM模型进行语言预测;和TensorFlow自动翻译模型。Word2Vec数学原理介绍我们把自然语言交给机器学习,但机器无法直接理解人类语言。那么首先要做的就是将语言数学化。Hinton于1986年提出DistributedRepresentation方法,通过训练将语言中的每个词映射成一个固定长度的向量。所有这些向量组成一个词向量空间,每个向量可以看作是空间中的一个点,这样就可以根据词与词之间的距离来判断它们之间的相似度,其应用可以扩展到句子、文档和中文分词。Word2Vec中使用了两个模型,CBOW模型(ContinuousBag-of-Wordsmodel)和Skip-gram模型(ContinuousSkip-gramModel)。模型示例如下,是一个三层神经网络模型,包括输入层、投影层和输出层。其中,score(wt,h)表示预测结果在的上下文中的概率得分。上述目标函数可以转化为最大化似然函数,如下图:神经网络。出现的probabilityscore如下:但是,使用word2vec方法进行特征学习时,不需要计算全概率模型。在CBOW模型和skip-gram模型中,使用了逻辑回归二元分类方法做出的预测。如下图CBOW模型所示,为了提高模型的训练速度和提高词向量的质量,通常采用随机负采样(NegativeSampling)的方法,噪声样本w1,w2,w3,wk...都是选取的负样本。TensorFlow同义词模型本章介绍如何使用TensorFlowword2vec模型查找同义词。输入数据是一大段英文文章,输出是对应词的近义词。例如,通过研究文章,你可以得到与五意思相近的词:四、三、七、八、六、二、零、九。通过大段英文文章的训练,当神经网络训练到10万次迭代,网络Loss值降低到4.6左右时,学习到的相关近似词如下图所示:下面是TensorFlowword2vecAPI指令:构造一个词向量变量,vocabulary_size为字典大小,embedding_size为词向量大小embeddings=tf.Variable(tf.random_uniform([vocabulary_size,embedding_size],-1.0,1.0))定义logistic的权重和偏置负采样中的回归nce_weights=tf.Variable(tf.truncated_normal([vocabulary_size,embedding_size],stddev=1.0/math.sqrt(embedding_size)))nce_biases=tf.Variable(tf.zeros([vocabulary_size]))定义访问oftrainingdatatrain_inputs=tf.placeholder(tf.int32,shape=[batch_size])train_labels=tf.placeholder(tf.int32,shape=[batch_size,1])根据训练数据定义输入,找到对应的词矢量嵌入=tf.nn.embedding_lookup(embeddings,train_inputs)根据负采样方法计算Loss值loss=tf.reduce_mean(tf.nn.nce_loss(weights=nce_weights,biases=nce_biases,labels=train_labels,inputs=embed,num_sampled=num_sampled,num_classes=vocabulary_size))definition使用随机梯度下降法进行优化操作并最小化损失值optimizer=tf.train.GradientDescentOptimizer(learning_rate=1.0).minimize(loss)通过TensorFlowSessionRun的方法对inputs进行模型训练,labelsinggenerate_batch(...):feed_dict={train_inputs:inputs,train_labels:labels}_,cur_loss=session.run([optimizer,loss],feed_dict=feed_dict)TensorFlow语言预测模型本章主要回顾RNN和LSTM的技术原理,基于训练语言RNN/LSTM技术该模型是给定一个单词序列来预测最有可能出现的下一个单词。例如,给定一个包含3个词的LSTM输入序列[had,a,general],下一个要预测的词是什么?如下图所示:RNN技术原理递归神经网络(RNN)是一类用于处理序列数据的神经网络。与卷积神经网络的区别在于,卷积网络是一种适合处理网格化数据(如图像数据)的神经网络,而循环神经网络是一种适合处理序列化数据的神经网络。例如,如果要预测句子中的下一个单词是什么,一般需要使用前面的单词,因为句子中的前后单词不是独立的。RNN之所以被称为递归神经网络,是因为一个序列的当前输出也与之前的输出有关。具体表现是网络会记住之前的信息,并将其应用到当前输出的计算中,即隐藏层之间的节点不再是连通而是连通,并且隐藏层的输入不仅包括输入层的输出还包括前一时刻隐藏层的输出。如下图所示:LSTM技术原理RNN有问题。反向传播时,梯度也会呈指数衰减,导致传播很多阶段后梯度趋于消失,无法处理长期依赖的问题。虽然RNN理论上可以处理任意长度的序列,但在实际应用中,RNN很难处理超过10的序列。为了解决RNN梯度消失的问题,提出了LongShort-TermMemory模块,实现了通过门的开关对时序具有记忆功能。当错误从输出层反向传播时,可以使用模块的存储元件进行记录。所以LSTM可以更长时间地记住信息。一个常见的LSTM模块如下图所示:输出门与输入门类似,也会产生一个0-1的向量来控制MemoryCell向输出层的输出,如下式所示:三个门的配合使得LSTM记忆块可以长时间访问信息,例如只要输入门保持关闭状态,记忆单元的信息就不会被后面某个时间的输入覆盖。使用TensorFlow构建单词预测模型首先下载PTB模型数据,其中包含大约10,000个不同的单词,并标记出不常用的单词。首先,需要对样本数据集进行预处理,用整数标记每个词,并建立字典索引,如下所示:readtrainingdatadata=_read_words(filename)#根据词频排序collections.Counter(data)count_pairs=sorted(counter.items(),key=lambdax:(-x1,x[0]))#构建字典和字典索引词,_=list(zip(*count_pairs))word_to_id=dict(zip(words,range(len(words))))然后读取训练数据文本,将词序列转化为词索引序列,生成训练数据,如下:读取训练数据words,转化为awordindexsequencedata=_read_words(filename)data=[word_to_id[word]forwordindataifwordinword_to_id]生成训练数据的数据和标签,其中epoch_size是epoch的训练迭代次数,num_steps是LSTMi=tf的序列长度。train.range_input_producer(epoch_size,shuffle=False).dequeue()x=tf.strided_slice(数据,[0,i*num_steps],[batch_size,(i+1)*num_steps])x.set_shape([batch_size,num_steps])y=tf.strided_slice(数据,[0,i*num_steps+1],[batch_size,(i+1)*num_steps+1])y.set_shape([batch_size,num_steps])构造LSTMCell,其中size为隐藏神经元个数lstm_cell=tf.contrib.rnn.BasicLSTMCell(size,forget_bias=0.0,state_is_tuple=True)如果是训练模式,为了保证训练的稳健性,定义dropout操作attn_cell=tf.contrib.rnn.DropoutWrapper(lstm_cell,output_keep_prob=config.keep_prob)根据层数配置,定义多层RNN神经网络cell=tf.contrib.rnn.MultiRNNCell([attn_cellfor_inrange(config.num_layers)],state_is_tuple=True)根据字典大小,定义单词vectorembedding=tf.get_variable("embedding",[vocab_size,size],dtype=data_type())根据词索引找到词向量,从词索引找到对应的One-hot编码如下图,然后红色的权值直接对应输出节点的值,也就是对应的embeddingvector。inputs=tf.nn.embedding_lookup(embedding,input_.input_data)定义RNN网络,其中state为LSTMCell的状态,cell_output为LSTMCell的输出fortime_stepinrange(num_steps):iftime_step>0:tf.get_variable_scope().reuse_variables()(cell_output,state)=cell(inputs[:,time_step,:],state)outputs.append(cell_output)定义训练损失值,如下式所示。softmax_w=tf.get_variable("softmax_w",[size,vocab_size],dtype=data_type())softmax_b=tf.get_variable("softmax_b",[vocab_size],dtype=data_type())logits=tf.matmul(输出,softmax_w)+softmax_b损失值loss=tf.contrib.legacy_seq2seq.sequence_loss_by_example([logits],[tf.reshape(input_.targets,[-1])],[tf.ones([batch_size*num_steps],dtype=data_type())])定义梯度和优化操作train.GradientDescentOptimizer(self._lr)wordperplexityelossperplexity=np.exp(costs/iters)TensorFlow语言翻译模型本节主要讲解使用TensorFlow实现RNN和LSTM的语言翻译模型。基本的sequence-to-sequence模型主要包括两个RNN网络,一个RNN网络用于对Sequence的输入进行编码,另一个RNN网络用于生成Sequence的输出。基本架构如下图所示。上图中的每个方框代表RNN中的一个Cell。在上面的模型中,每个输入都被编码成一个固定长度的状态向量,然后传递给解码器。2014年,Bahdanau在论文《NeuralMachineTranslationbyJointlyLearningtoAlignandTranslate》中引入了Attention机制。Attention机制允许解码器在每个输出步骤参与原始文本的不同部分,让模型根据输入的句子和生成的内容影响翻译结果。一个带有注意力机制的多层LSTM序列到序列网络结构如下图所示:对于上面的序列到序列模型,TensorFlow将其封装成一个可以直接调用的函数API,只有少数几个一百行代码就可以实现一个基本的翻译模型。tf.nn.seq2seq文件一共实现了5个seq2seq函数:basic_rnn_seq2seq:输入输出都是embedding的形式;编码器和解码器使用相同的RNN单元,但不共享权重参数;tied_rnn_seq2seq:与basic_rnn_seq2seq相同,但编码器和解码器共享权重参数;embedding_rnn_seq2seq:同basic_rnn_seq2seq,但输入输出改为id形式,函数内部会分别为encoder和decoder创建embedding矩阵;embedding_tied_rnn_seq2seq:同tied_rnn_seq2seq,但输入输出改为id形式,内部会创建encoder和decoder的函数Embeddingmatrices;embedding_attention_seq2seq:和embedding_rnn_seq2seq一样,但是多了attention机制;embedding_rnn_seq2seq函数接口说明如下:encoder_inputs:编码器输入decoder_inputs:解码器inputcell:RNN_Cell实例denum_encodernum_symbols:分别编码和解码的大小embedding_size:词向量的维数output_projection:输出向量时使用的投影矩阵和偏置项解码器的映射到词汇空间。feed_previous:如果为True,只有第一个解码器的输入符号有用,所有解码器的输入都依赖于上一步的输出;outputs,states=embedding_rnn_seq2seq(encoder_inputs,decoder_inputs,cell,num_encoder_symbols,num_decoder_symbols,embedding_size,output_projection=None,feed_previous=False)TensorFlow官方提供了英译法的例子,使用statmt网站提供的语料数据主要包括:giga-fren.release2.fixed.en(英语语料,3.6G)和giga-fren.release2.fixed.fr(法语语料,4.3G)本例代码结构如下图:seq2seq_model.py:seq2seq的TensorFlow模型使用embedding_attention_seq2seq创建seq2seq模型。data_utils.py:对语料数据进行数据预处理,根据语料数据生成字典数据库;并根据词典数据库将待译句子转换为以词ID表示的训练序列。如下图所示:(点击放大)translate.py:主要功能入口,执行翻译模型训练executemodeltrainingpythontranslate.py--data_dir[your_data_directory]--train_dir[checkpoints_directory]--en_vocab_size=40000--fr_vocab_size=40000总结随着TensorFlow新版本的不断发布和新模型的不断增加,TensorFlow已经成为主流的深度学习平台。本文主要介绍TensorFlow在自然语言处理领域的相关模型和应用。首先介绍了Word2Vec的数学原理,以及如何使用TensorFlow学习词向量;然后回顾了RNN和LSTM的技术原理,讲解了TensorFlow的语言预测模型;最后分析了TensorFlowsequence-to-sequence的机器翻译API和官方例子。
