tensorflow 默认路径seq2seq 跑默认脚本的测试结果很差,什么原因

登录以解锁更多InfoQ新功能
获取更新并接收通知
给您喜爱的内容点赞
关注您喜爱的编辑与同行
966,690 十月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
深度学习利器:TensorFlow与NLP模型
深度学习利器:TensorFlow与NLP模型
2&他的粉丝
日. 估计阅读时间:
:Facebook、Snapchat、Tumblr等背后的核心技术
相关厂商内容
相关赞助商
Word2Vec中用到两个模型,CBOW模型(Continuous Bag-of-Words model)和Skip-gram模型(Continuous Skip-gram Model)。模型示例如下,是三层结构的神经网络模型,包括输入层,投影层和输出层。
(点击放大图像)
(点击放大图像)
其中score(wt, h),表示在的上下文环境下,预测结果是的概率得分。上述目标函数,可以转换为极大化似然函数,如下所示:
(点击放大图像)
求解上述概率模型的计算成本是非常高昂的,需要在神经网络的每一次训练过程中,计算每个词在他的上下文环境中出现的概率得分,如下所示:
(点击放大图像)
然而在使用word2vec方法进行特性学习的时候,并不需要计算全概率模型。在CBOW模型和skip-gram模型中,使用了逻辑回归(logistic regression)二分类方法进行的预测。如下图CBOW模型所示,为了提高模型的训练速度和改善词向量的质量,通常采用随机负采样(Negative Sampling)的方法,噪音样本w1,w2,w3,wk&为选中的负采样。
(点击放大图像)
TensorFlow近义词模型
本章讲解使用TensorFlow word2vec模型寻找近义词,输入数据是一大段英文文章,输出是相应词的近义词。比如,通过学习文章可以得到和five意思相近的词有: four, three, seven, eight, six, two, zero, nine。通过对大段英文文章的训练,当神经网络训练到10万次迭代,网络Loss值减小到4.6左右的时候,学习得到的相关近似词,如下图所示:
(点击放大图像)
下面为TensorFlow word2vec API 使用说明:
构建词向量变量,vocabulary_size为字典大小,embedding_size为词向量大小
embeddings = tf.Variable(tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
定义负采样中逻辑回归的权重和偏置
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]))
定义训练数据的接入
train_inputs = tf.placeholder(tf.int32, shape=[batch_size])
train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])
定义根据训练数据输入,并寻找对应的词向量
embed = 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))
定义使用随机梯度下降法执行优化操作,最小化loss值
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1.0).minimize(loss)
通过TensorFlow Session Run的方法执行模型训练
for inputs, labels in generate_batch(...):
feed_dict = {train_inputs: inputs, train_labels: labels}
_, cur_loss = session.run([optimizer, loss], feed_dict=feed_dict)
TensorFlow语言预测模型
本章主要回顾RNN、LSTM技术原理,并基于RNN/LSTM技术训练语言模型。也就是给定一个单词序列,预测最有可能出现的下一个单词。例如,给定[had, a, general] 3个单词的LSTM输入序列,预测下一个单词是什么?如下图所示:
(点击放大图像)
RNN技术原理
循环神经网络(Recurrent Neural Network, RNN)是一类用于处理序列数据的神经网络。和卷积神经网络的区别在于,卷积网络是适用于处理网格化数据(如图像数据)的神经网络,而循环神经网络是适用于处理序列化数据的神经网络。例如,你要预测句子的下一个单词是什么,一般需要用到前面的单词,因为一个句子中前后单词并不是独立的。RNN之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。如下图所示:
(点击放大图像)
LSTM技术原理
RNN有一问题,反向传播时,梯度也会呈指数倍数的衰减,导致经过许多阶段传播后的梯度倾向于消失,不能处理长期依赖的问题。虽然RNN理论上可以处理任意长度的序列,但实习应用中,RNN很难处理长度超过10的序列。为了解决RNN梯度消失的问题,提出了Long Short-Term Memory模块,通过门的开关实现序列上的记忆功能,当误差从输出层反向传播回来时,可以使用模块的记忆元记下来。所以 LSTM 可以记住比较长时间内的信息。常见的LSTM模块如下图所示:
(点击放大图像)
(点击放大图像)
output gate类似于input gate同样会产生一个0-1向量来控制Memory Cell到输出层的输出,如下公式所示:
(点击放大图像)
三个门协作使得 LSTM 存储块可以存取长期信息,比如说只要输入门保持关闭,记忆单元的信息就不会被后面时刻的输入所覆盖。
使用TensorFlow构建单词预测模型
首先,该数据集大概包含10000个不同的单词,并对不常用的单词进行了标注。
首先需要对样本数据集进行预处理,把每个单词用整数标注,即构建词典索引,如下所示:
读取训练数据
data = _read_words(filename)
#按照单词出现频率,进行排序
counter = collections.Counter(data)
count_pairs = sorted(counter.items(), key=lambda x: (-x1, x[0]))
#构建词典及词典索引
words, _ = list(zip(*count_pairs))
word_to_id = dict(zip(words, range(len(words))))
接着读取训练数据文本,把单词序列转换为单词索引序列,生成训练数据,如下所示:
读取训练数据单词,并转换为单词索引序列
data = _read_words(filename) data = [word_to_id[word] for word in data if word in word_to_id]
生成训练数据的data和label,其中epoch_size为该epoch的训练迭代次数,num_steps为LSTM的序列长度
i = tf.train.range_input_producer(epoch_size, shuffle=False).dequeue()
x = tf.strided_slice(data, [0, i * num_steps], [batch_size, (i + 1) * num_steps])
x.set_shape([batch_size, num_steps])
y = tf.strided_slice(data, [0, i * num_steps + 1], [batch_size, (i + 1) * num_steps + 1])
y.set_shape([batch_size, num_steps])
构建LSTM Cell,其中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_cell for _ in range(config.num_layers)],
state_is_tuple=True)
根据词典大小,定义词向量
embedding = tf.get_variable(&embedding&,
[vocab_size, size], dtype=data_type())
根据单词索引,查找词向量,如下图所示。从单词索引找到对应的One-hot encoding,然后红色的weight就直接对应了输出节点的值,也就是对应的embedding向量。
inputs = tf.nn.embedding_lookup(embedding, input_.input_data)
(点击放大图像)
定义RNN网络,其中state为LSTM Cell的状态,cell_output为LSTM Cell的输出
for time_step in range(num_steps):
if time_step & 0: tf.get_variable_scope().reuse_variables()
(cell_output, state) = cell(inputs[:, time_step, :], state)
outputs.append(cell_output)
定义训练的loss值就,如下公式所示。
(点击放大图像)
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(output, 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())])
定义梯度及优化操作
cost = tf.reduce_sum(loss) / batch_size
tvars = tf.trainable_variables()
grads, _ = tf.clip_by_global_norm(tf.gradients(cost, tvars), config.max_grad_norm)
optimizer = tf.train.GradientDescentOptimizer(self._lr)
单词困惑度eloss
perplexity = np.exp(costs / iters)
TensorFlow语言翻译模型
本节主要讲解使用TensorFlow实现RNN、LSTM的语言翻译模型。基础的sequence-to-sequence模型主要包含两个RNN网络,一个RNN网络用于编码Sequence的输入,另一个RNN网络用于产生Sequence的输出。基础架构如下图所示
(点击放大图像)
上图中的每个方框表示RNN中的一个Cell。在上图的模型中,每个输入会被编码成固定长度的状态向量,然后传递给解码器。2014年,Bahdanau在论文&Neural Machine Translation by Jointly Learning to Align and Translate&中引入了Attention机制。Attention机制允许解码器在每一步输出时参与到原文的不同部分,让模型根据输入的句子以及已经产生的内容来影响翻译结果。一个加入attention机制的多层LSTM sequence-to-sequence网络结构如下图所示:
(点击放大图像)
针对上述sequence-to-sequence模型,TensorFlow封装成了可以直接调用的函数API,只需要几百行的代码就能实现一个初级的翻译模型。tf.nn.seq2seq文件共实现了5个seq2seq函数:
basic_rnn_seq2seq:输入和输出都是embedding的形式;encoder和decoder用相同的RNN cell,但不共享权值参数;
tied_rnn_seq2seq:同basic_rnn_seq2seq,但encoder和decoder共享权值参数;
embedding_rnn_seq2seq:同basic_rnn_seq2seq,但输入和输出改为id的形式,函数会在内部创建分别用于encoder和decoder的embedding矩阵;
embedding_tied_rnn_seq2seq:同tied_rnn_seq2seq,但输入和输出改为id形式,函数会在内部创建分别用于encoder和decoder的embedding矩阵;
embedding_attention_seq2seq:同embedding_rnn_seq2seq,但多了attention机制;
embedding_rnn_seq2seq函数接口使用说明如下:
encoder_inputs:encoder的输入
decoder_inputs:decoder的输入
cell:RNN_Cell的实例
num_encoder_symbols,num_decoder_symbols:分别是编码和解码的大小
embedding_size:词向量的维度
output_projection:decoder的output向量投影到词表空间时,用到的投影矩阵和偏置项
feed_previous:若为True, 只有第一个decoder的输入符号有用,所有的decoder输入都依赖于上一步的输出;
outputs, states = embedding_rnn_seq2seq(
encoder_inputs, decoder_inputs, cell,
num_encoder_symbols, num_decoder_symbols,
embedding_size, output_projection=None,
feed_previous=False)
,采用的是网站提供的语料数据,主要包含: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:主函数入口,执行翻译模型的训练
执行模型训练
python translate.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的语言预测模型;最后实例分析了TensorFlow sequence-to-sequence的机器翻译 API及官方示例。
深度学习利器:分布式TensorFlow及实例分析
深度学习利器:TensorFlow使用实战
深度学习利器:TensorFlow系统架构与高性能程序设计
深度学习利器:TensorFlow与深度卷积神经网络
武维:IBM Spectrum Computing 研发工程师,博士,系统架构师,主要从事大数据,深度学习,云计算等领域的研发工作。
Author Contacted
语言 & 开发
55 他的粉丝
架构 & 设计
219 他的粉丝
TensorFlow
3 他的粉丝
1 他的粉丝
0 他的粉丝
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
订阅InfoQ每周精要,加入拥有25万多名资深开发者的庞大技术社区。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。君,已阅读到文档的结尾了呢~~
这篇文章中我们将基于Tensorflow的Seq2Seq Attention模型,介绍如何训练一个中文的自动生成新闻标题的textsum模型。自动总结&#40;Automatic Summarization&#41;类型的模型一直是研究热点。 我们利用搜狐新闻的语聊,训练一个超过1M的模型。
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
Tensorflow Seq2Seq Attention自动文摘模型新闻标题生成Textsum
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口今天我们来解析下Tensorflow的Seq2Seq的demo。继上篇博客的PTM模型之后,Tensorflow官方也开放了名为translate的demo,这个demo对比之前的PTM要大了很多(首先,空间上就会需要大约20个G,另外差点把我的硬盘给运行死),但是也实用了很多。模型采用了encoder-decoder的框架结果,佐以attention机制来实现论文中的英语法语翻译功能。同时,模型的基础却来自之前的PTM模型。下面,让我们来一起来了解一下这个神奇的系统吧!
论文介绍及基础描写:
这个英语法语翻译器融合了多篇论文的核心内容,所以在学习的过程中其实我们可以变相的了解这些技巧。首先,Cho在论文Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation一文中指出可以通过encoder-decoder这种类似于编码-解码的框架来做机器翻译。这个框架在后续论文中掀起了不小的波澜,很多作品延续了这种sequence-to-sequence的框架在其他的一些领域,比如image caption。该框架说白了就是两个RNN,一个作为编码器,一个作为解码器。至于RNN cell的结构,虽然本项目支持使用LSTM, default的模型为GRU(Gated Recurrent Uint),一个LSTM的简化版模型。另外,为了使翻译的效果达到最好,2014年Bahdanau在论文Neural Machine Translation By Jointy Learning to Align and Translate中提出的attention机制也被运用了起来。背景介绍到此,下面我们赶快来看看代码吧!
较之PTM模型,机器翻译的demo代码有足足个file之多,可见其难度。(其实也没那么难,都是些犹如纸老虎般的存在,充其量也就在数量上吓唬吓唬人罢了。)项目源代码可以在Tensorflow官方github中找到,地址点击。打开项目后我们发现了3个文件,分别是data_utils.py, seq2seq_model.py以及translate.py。这三个文件里,data_utils.py是类似于helper function般的存在,如其名,是一个集合了对输入raw的数据做处理的一个file。file本身不是用来运行的,只是被translate.py所使用而已。这个文件本身也可以在你自己的Tensorflow框架的本地库内找到,所需要做的只是输入from tensorflow.models.rnn.translate import data_utils,就可以取得库里的函数了。为方便用户,这个data_utils文件里的函数还自带检测数据库是否存在于本地路径的功能,如果你没来得及或不知道如何下载数据库,只需要指定路径后运行库里的函数即可,是不是很方便?
Encoder-decoder模型存在于第二个文件中,即seq2seq_model.py文件。文件作为一个类包含了组建机器翻译所需要的神经网络图框架。与data_utils文件一样,他们都是被我们的&main&文件,translate.py使用的。
了解了三个文件的关系后,我们也了解了系统运行的过程以及解读顺序,那么,我们先来了解一下程序运行的大体顺序。运行该程序的方式为cd到文件所在的目录下后在terminal里面输入&python translate.py --data_dir /tmp/ --train_dir /tmp/&就可以了。 其中tmp为默认的tmp文件夹,如果你希望长期保留运行结果,建议在别的文件夹里进行实验。另外,你可以改变一些模型的参数,如把模型改为两层,每层改为256个神经元等。方法为在刚才的comment后面加上两横杠,更改参数名,等于号及更改后参数量。如改变模型为两层的框架的方法是&--num_layers=2&。那么在输入参数后系统是怎么运行的呢?我们在translate.py里找到了main函数的代码如下:
def main(_):
if FLAGS.self_test:
self_test()
elif FLAGS.decode:
&该代码显示,一般情况下如果你没表明要运行decode模式或者测试模式,训练模式将自动开始。那么很明显,我们的主程序在训练模式,也就train函数里。那么我们就顺藤摸瓜来看看train函数吧。
首先,train函数的开始为运行data_utils库的prepare_wmt_data函数,这里的输入为我们在之前手动输入的data_dir外还有英语和法语的单词数。这里除了data_dir是我们之前手动输入的外,英法语的单词数默认都是4万。通过这个神奇的prepare_wmt_data函数,我们可以得到英语,法语两种语言的训练以及测试资料外,还可以获得英语及法语单词的单词表存放路径。那么这个函数是如何工作的呢?我们这就来一探究竟。
def prepare_wmt_data(data_dir, en_vocabulary_size, fr_vocabulary_size, tokenizer=None):
"""Get WMT data into data_dir, create vocabularies and tokenize data.
data_dir: directory in which the data sets will be stored.
en_vocabulary_size: size of the English vocabulary to create and use.
fr_vocabulary_size: size of the French vocabulary to create and use.
tokenizer: a function to use to tokeniz
if None, basic_tokenizer will be used.
A tuple of 6 elements:
(1) path to the token-ids for English training data-set,
(2) path to the token-ids for French training data-set,
(3) path to the token-ids for English development data-set,
(4) path to the token-ids for French development data-set,
(5) path to the English vocabulary file,
(6) path to the French vocabulary file.
# Get wmt data to the specified directory.
# 建立训练集并取得他们的路径
train_path = get_wmt_enfr_train_set(data_dir)
dev_path = get_wmt_enfr_dev_set(data_dir)
# Create vocabularies of the appropriate sizes.
# 建立英语及法语的单词表
fr_vocab_path = os.path.join(data_dir, "vocab%d.fr" % fr_vocabulary_size)
en_vocab_path = os.path.join(data_dir, "vocab%d.en" % en_vocabulary_size)
create_vocabulary(fr_vocab_path, train_path + ".fr", fr_vocabulary_size, tokenizer)
create_vocabulary(en_vocab_path, train_path + ".en", en_vocabulary_size, tokenizer)
# Create token ids for the training data.
# 将输入数据里的单词数字化以方便运算
fr_train_ids_path = train_path + (".ids%d.fr" % fr_vocabulary_size)
en_train_ids_path = train_path + (".ids%d.en" % en_vocabulary_size)
data_to_token_ids(train_path + ".fr", fr_train_ids_path, fr_vocab_path, tokenizer)
data_to_token_ids(train_path + ".en", en_train_ids_path, en_vocab_path, tokenizer)
# Create token ids for the development data.
# 将测试数据里的单词数字化以方便运算
fr_dev_ids_path = dev_path + (".ids%d.fr" % fr_vocabulary_size)
en_dev_ids_path = dev_path + (".ids%d.en" % en_vocabulary_size)
data_to_token_ids(dev_path + ".fr", fr_dev_ids_path, fr_vocab_path, tokenizer)
data_to_token_ids(dev_path + ".en", en_dev_ids_path, en_vocab_path, tokenizer)
return (en_train_ids_path, fr_train_ids_path,
en_dev_ids_path, fr_dev_ids_path,
en_vocab_path, fr_vocab_path)
在data_utils库里,prepare_wmt_data整合了其他的helper函数,其中,get_wmt_enfr_train_set和get_wmt_enfr_dev_set两个函数测试了训练集的路径是否存在后,视情况下载训练集(如果训练集还未下载),之后便是解压了训练包中所用的具体集并提供其路径。虽然对于测试集有不同的应对方法,其逻辑大同小异,具体实现过程大家可以阅读这两个函数去一探究竟,这里将不做细说。
之后函数建立了两个不同的单词表,即英语单词表及法语单词表。在建立表的过程中,逻辑近似于之前讨论过的Word2Vec的create_dataset函数,即从海量数据里建立一个对应的字典来统计输入词。其中,值得注意的是这里有一个tokenizer输入的选项,默认的tokenizer是在符号处截断句子,其代码如下:
_WORD_SPLIT = re.compile(b"([.,!?\"':;)(])")
def basic_tokenizer(sentence):
"""Very basic tokenizer: split the sentence into a list of tokens."""
words = []
for space_separated_fragment in sentence.strip().split():
words.extend(re.split(_WORD_SPLIT, space_separated_fragment))
return [w for w in words if w]
&该项目鼓励读者们去采用更好的tokenizer去取得更好的结果。最后,不同于Word2Vec模型的最大地方在于我们将这个单词集保存后备用,也就是说,在第一次运算耗时可能很长后,之后在运行将会比较方便。
在建立完词典后,通过运用data_to_token_ids函数,我们可以将输入转化为数字序列并将其保存,这样可以方便我们系统的运用。其原理也可以在Word2Vec的demo代码里找到逻辑,即运用单词在词典里的位置来代替单词。具体内容请参考博客。所得的结果在保存在各自的文件中已备后用后,我们可以直接运用这些资料来训练我们的系统了。接下来,让我们重新回到translation.py文件的train()函数来继续了解它的机制。在得到了输入及训练资料后,我们看到了熟悉的with tf.Session() as sess,这里大家都明白怎么回事了吧,我们进入session了,可以开始建立模型并运行了。那么很明显,我们现在的任务就是建立模型。这里,我们看到了model = create_model(sess, False), 这个函数的具体内容就在train()函数之上,很好找。那么,它是怎么建立模型的呢?走进该函数后我们发现它其实就是个包装盒子,运用了系统的另一个文件,即seq2seq_model.py库里Seq2SeqModel类来得到模型,之后便是取得模型目前的状态。如果模型已经训练并保存,我们即呼唤之前训练的模型并返回。反之则初始化所有参数并返回模型。
现在,让我们来看看这个模型本身。在seq2seq_model.py文件里有三个函数:init函数,step函数及get_batch函数。目前,我们在制造模型阶段,所以先来看看这个init函数。
def __init__(self, source_vocab_size, target_vocab_size, buckets, size,
num_layers, max_gradient_norm, batch_size, learning_rate,
learning_rate_decay_factor, use_lstm=False,
num_samples=512, forward_only=False):
&这个函数的parameter列很长,有源语言和目标语言各自的单词数量,框架的层数,每层的神经元数,用于clipped的梯度的最大数值,训练batch的大小,learning rate,learning rate减少的比例及sampled softmax所接收的sample数量。这些都是常见的训练神经网络的参数。参数use_lstm也比较好理解,默认的false表明我们将会运用到GRU,即简易版本的lstm。设置为True时便是使用传统的LSTM cell了。现在,有两个参数我没讲解到,buckets参数和forward_only参数。这两个参数挺有意思。bucket参数的存在是针对机器翻译的,他的格式为一个充满(I,O)的list,I代表这最大输入长度,O代表着输出的最大长度。当输入或输出超出这个距离后,我们将超出的部分放入下一个batch。至于forward_only参数,其存在是因为两种不同的训练方式。一种方式为在训练中根据两种语言各自训练input及output,这是默认方式,即该参数设为Flase。如果我们设为True后,将会在训练output语言时运用output目标的开头后由输入语言取得剩下的数据。两种方法在官方的document里有详细讲解,这里附上供有兴趣的读者加深了解。
之后,在assign了变量后,我们又见到了熟悉的RNN模型框架,即
# If we use sampled softmax, we need an output projection.
output_projection = None
softmax_loss_function = None
# Sampled softmax only makes sense if we sample less than vocabulary size.
if num_samples & 0 and num_samples & self.target_vocab_size:
w = tf.get_variable("proj_w", [size, self.target_vocab_size])
w_t = tf.transpose(w)
b = tf.get_variable("proj_b", [self.target_vocab_size])
output_projection = (w, b)
def sampled_loss(inputs, labels):
labels = tf.reshape(labels, [-1, 1])
return tf.nn.sampled_softmax_loss(w_t, b, inputs, labels, num_samples,
self.target_vocab_size)
softmax_loss_function = sampled_loss
# Create the internal multi-layer cell for our RNN.
single_cell = tf.nn.rnn_cell.GRUCell(size)
if use_lstm:
single_cell = tf.nn.rnn_cell.BasicLSTMCell(size)
cell = single_cell
if num_layers & 1:
cell = tf.nn.rnn_cell.MultiRNNCell([single_cell] * num_layers)
# The seq2seq function: we use embedding for the input and attention.
def seq2seq_f(encoder_inputs, decoder_inputs, do_decode):
return tf.nn.seq2seq.embedding_attention_seq2seq(
encoder_inputs, decoder_inputs, cell,
num_encoder_symbols=source_vocab_size,
num_decoder_symbols=target_vocab_size,
embedding_size=size,
output_projection=output_projection,
feed_previous=do_decode)
&这里,我们先了解到如果我们的参数num_samples大于0但小于目标单词量时,我们再次如同PTB模型那样运用一个projection layer来减少空间的占据。之后,我们默认celll类型是GRU,但是如果用户设定了用lstm,我们即更新single_cell变量到lstm cell框架。当网络层大于1时(默认为3层),我们的cell变成了一个多层RNN框架,由单层cell累积组成。这个逻辑已经在之前关于PTM模型的博客里有过介绍,如果你不熟悉这个设定,请看之前PTB模型的博客。在之后,我们发现设计了一个seq2seq_f的内部函数,这个函数为模型加入attention机制,之后我们会用到。
如同往常,我们为源语言,目标语言的训练输入以及目标权重建立placeholder,因为训练目标是输入目标的下一句,我们设定目标为目标语言输入的现在位置+1。之后便是建立训练输出及计算loss的时刻了。基本方法如下:
self.outputs, self.losses = tf.nn.seq2seq.model_with_buckets(
self.encoder_inputs, self.decoder_inputs, targets,
self.target_weights, buckets,
lambda x, y: seq2seq_f(x, y, False),
softmax_loss_function=softmax_loss_function)
我们将会运用Tensorflow库seq2seq里的model_with_buckets函数来完成。这个函数是什么呢?让我们来一探究竟。该函数的目标是建立一个bucket版本的seq2seq模型。模型取得encoder, decoder的输入,目标和权重的Tensor,输入和输出大小配对列表叫做buckets的参数后,要求一个sequence to sequence模型,softmax_loss_function函数(default是None),每例子的loss(default None)及名字(default None)。输出是(output, losses)tuple,output指的是每一个bucket的输出,losses这该bucket的loss数值。了解了这些后,我们发掘这里的sequence to sequence函数输入我们运用了lambda匿名函数,核心是我们的attention模型。这是我们训练的基础,但是当forward_only被设为True时,训练后,我们又多了一步,及重新编写buckets的output为揉合输出及之前projection的output。代码如下:
if output_projection is not None:
for b in xrange(len(buckets)):
self.outputs[b] = [
tf.matmul(output, output_projection[0]) + output_projection[1]
for output in self.outputs[b]
&之后便是传统的RNN训练方法,即运用GradientDecentOptimizer,并运用clip_by_global_norm及appy_gradient函数。这些知识点在之前的PTB模型里以详细介绍,这里将不再重复。
&建立模型之后,在train()函数里,我们读入测试和训练的数据,计算训练的bucket并选择输入的句子属于哪个bucket (= [sum(train_bucket_sizes[:i + 1]) / train_total_size for i in xrange(len(train_bucket_sizes))]),之后便是具体训练的循环步骤。
步骤里,系统在运用seq2seq_model类里的get_batch和step两个函数,在取得了一个batch的数据后训练一个步骤的数据,并在一定的步骤后展出结果。代码的逻辑还是很清晰的,只是值得注意的是第205行的sys.stdout.flush()代码,这代码的存在是为了实时把运算结果展示在terminal的。除此之外,大家可以仔细阅读代码来加深了解,这里将不再细说。
就此,系统训练的步骤讲完了。但当我们准备测试我们的训练结果时,我们该怎么办呢?这里,我们就要讲讲这个decode()函数了。根据官方的说明,我们在训练模型后模型参数等全部资料全部都是有好好的保存的,所以我们不需要再次训练了,我们只需要运行&python translate.py --decode --data_dir /tmp/ --train_dir /tmp/"即可,一个interactive session将会打开供我们运作。
这个decode函数本身是用来测试系统的,所以在初始化英语法语的单词表后,系统读取我们输入的一行句子后,运行一下逻辑:
# 读取一行话
sentence = sys.stdin.readline()
while sentence:
# Get token-ids for the input sentence.
# 把输入转换成token_ids
token_ids = data_utils.sentence_to_token_pat.as_bytes(sentence), en_vocab)
# Which bucket does it belong to?
# 选择输入所对应的bucket大小
bucket_id = min([b for b in xrange(len(_buckets))
if _buckets[b][0] & len(token_ids)])
# Get a 1-element batch to feed the sentence to the model.
# 取得一个一个element的batch并通过step函数来取得运行结果
encoder_inputs, decoder_inputs, target_weights = model.get_batch(
{bucket_id: [(token_ids, [])]}, bucket_id)
# Get output logits for the sentence.
_, _, output_logits = model.step(sess, encoder_inputs, decoder_inputs,
target_weights, bucket_id, True)
# This is a greedy decoder - outputs are just argmaxes of output_logits.
outputs = [int(np.argmax(logit, axis=1)) for logit in output_logits]
# If there is an EOS symbol in outputs, cut them at that point.
if data_utils.EOS_ID in outputs:
outputs = outputs[:outputs.index(data_utils.EOS_ID)]
# Print out French sentence corresponding to outputs.
print(" ".join([tf.compat.as_str(rev_fr_vocab[output]) for output in outputs]))
print("& ", end="")
sys.stdout.flush()
sentence = sys.stdin.readline()
&通过这种方式,我们可以验证我们系统的好坏。可惜的是第一,我不懂法语。第二,系统在读取第1770000行句子时系统卡死了,差点废了我的硬盘,我没有得到测试结果,可能是模型过大我的电脑承受不起的缘故吧。对于这个错误我会研究一下,不过如果读者们有类似的情况并知道为何如此,请务必让我知道!谢谢大家!
阅读(...) 评论()}

我要回帖

更多关于 tensorflow 默认gpu 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信