页面树结构

2017-11-09 ApacheCN 开源组织,第二期邀请成员活动,一起走的更远 : http://www.apachecn.org/member/209.html


MachineLearning 优酷地址 : http://i.youku.com/apachecn

转至元数据结尾
转至元数据起始

循环神经网络可以学习建模语言,如RNN教程中已经讨论过的 (如果没有阅读,请继续阅读之前)。这提出了一个有趣的问题:我们可以在一些输入上对生成的单词进行调整,并产生有意义的响应吗?例如,我们可以训练一个神经网络来从英语翻译成法语吗?事实证明答案是肯定的

本教程将向您展示如何构建和训练这样的系统端到端。从GitHub 克隆TensorFlow主要回购TensorFlow模型回购。然后,您可以运行翻译程序:

cd models/tutorials/rnn/translate
python translate.py --data_dir [your_data_directory] 
它将从WMT'15网站下载英文到法文的翻译数据 ,准备训练和训练。大约需要20GB的磁盘空间,一段时间才能下载并准备(详见后文),所以在阅读本教程时可以开始运行。

本教程引用以下文件。

文件这里面是什么?
tensorflow/tensorflow/python/ops/seq2seq.py用于构建序列到序列模型的库。
models/tutorials/rnn/translate/seq2seq_model.py神经翻译序列 - 序列模型。
models/tutorials/rnn/translate/data_utils.py助手功能用于准备翻译数据。
models/tutorials/rnn/translate/translate.py训练和运行翻译模型的二进制。

序列到序列的基础知识

 Cho等人,2014 (pdf)中引入的基本序列到序列模型 由两个循环神经网络(RNN)组成:处理输入的编码器和产生输出的解码器。这个基本架构如下所示。

上图中的每个框都表示RNN的单元格,最常见的是GRU单元格或LSTM单元格(请参阅RNN教程 中的说明)。编码器和解码器可以共享权重,或者更常见的是使用不同的参数集合。多层细胞已经成功地用于序列序列模型,例如翻译Sutskever等,2014 (pdf)。

在上述基本模型中,每个输入都必须被编码为固定大小的状态向量,因为这是传递给解码器的唯一的东西。以允许所述解码器对输入更直接地访问,一个注意机构在被引入Bahdanau等人,2014 (PDF)。我们不会再赘述注意机制的细节(见文件); 足以说它允许解码器在每个解码步骤中窥视输入。在解码器中,具有LSTM单元和注意机制的多层序列到序列网络看起来像这样。

TensorFlow seq2seq库

如上所述,有许多不同的序列到序列模型。这些模型中的每一个都可以使用不同的RNN单元,但是它们都接受编码器输入和解码器输入。这激发了TensorFlow seq2seq库(tensorflow/tensorflow/python/ops/seq2seq.py)中的接口。基本的RNN编码器 - 解码器序列到序列模型的工作原理如下。

outputs, states = basic_rnn_seq2seq(encoder_inputs, decoder_inputs, cell) 
在上述调用中,encoder_inputs是表示对编码器的输入的张量的列表,即对应于上述第一张图中的字母A,B,C。类似地,decoder_inputs是表示第一图像上的解码器GO,W,X,Y,Z的输入的张量。

cell参数是的一个实例tf.contrib.rnn.RNNCell,用于确定哪些小区将模型内使用的类。您可以使用现有的单元格,例如GRUCellLSTMCell,或者您可以编写自己的单元格。此外,tf.contrib.rnn提供封装器来构建多层单元,将单元格输入或输出的输出添加到其他变换中。有关示例,请参阅RNN教程

调用basic_rnn_seq2seq返回两个参数:outputsstates。他们都是与长度相同的张量列表decoder_inputs。自然地,outputs对应于在上述第一幅图中的每个时间步长中的解码器的输出,它们将是W,X,Y,Z,EOS。返回值states表示每个时间步长解码器的内部状态。

在序列到序列模型的许多应用中,时间t处的解码器的输出被反馈,并且在时刻t + 1成为解码器的输入。在测试时,当对序列进行解码时,这是序列的构建方式。另一方面,在训练中,通常在每个时间步长的情况下,向解码器提供正确的输入,即使解码器之前犯了错误。在功能seq2seq.py支持使用这两种模式feed_previous的说法。例如,我们分析以下使用嵌入式RNN模型。

outputs, states = embedding_rnn_seq2seq(
    encoder_inputs, decoder_inputs, cell,
    num_encoder_symbols, num_decoder_symbols,
    embedding_size, output_projection=None,
    feed_previous=False)
embedding_rnn_seq2seq模型中,所有输入(both encoder_inputs和 decoder_inputs)都是表示离散值的整数张量。它们将被嵌入到密集的表示中(有关嵌入的更多细节,请参阅 向量表示教程),但是为了构建这些嵌入,我们需要指定将出现的离散符号的最大数量:num_encoder_symbols 在编码器侧和num_decoder_symbols解码器侧。

在上面的调用中,我们设置feed_previous为False。这意味着解码器将使用decoder_inputs所提供的张量。如果我们设置feed_previous 为True,解码器将只使用第一个元素decoder_inputs。该列表中的所有其他张量将被忽略,而是将使用解码器的先前输出。这用于翻译模型中的翻译,但也可以在培训过程中使用,以使模型对自己的错误更加强大,类似于Bengio等,2015 (pdf)。

以上使用的另一个重要论点是output_projection。如果未指定,嵌入模型的输出将是形状批量大小的张量,num_decoder_symbols因为它们表示每个生成的符号的对数。当训练具有大量输出词汇的模型时,即num_decoder_symbols大的时候,存储这些大张量是不现实的。相反,最好是返回较小的输出张量,这将稍后投影到使用大的输出张量上output_projection。这使得我们的seq2seq模型具有采样的softmax损耗,如Jean等人所述。2014年 (pdf)。

除了basic_rnn_seq2seqembedding_rnn_seq2seq中有几个序列对序列模型seq2seq.py; 看看那里。他们都有类似的界面,所以我们不会详细描述它们。我们将embedding_attention_seq2seq在下面使用 我们的翻译模型。

 

神经翻译模型

虽然序列到序列模型的核心是由函数构建的tensorflow/tensorflow/python/ops/seq2seq.py,但仍然有一些值得一提的技巧在我们的翻译模型中使用 models/tutorials/rnn/translate/seq2seq_model.py

采样softmax和输出投影

一个,如上所述,我们想使用抽样的softmax来处理大量的输出词汇。要从中解码,我们需要跟踪输出投影。采样的softmax损耗和输出投影均由以下代码构成seq2seq_model.py

if num_samples > 0 and num_samples < self.target_vocab_size:
  w_t = tf.get_variable("proj_w", [self.target_vocab_size, size], dtype=dtype)
  w = tf.transpose(w_t)
  b = tf.get_variable("proj_b", [self.target_vocab_size], dtype=dtype)
  output_projection = (w, b)

  def sampled_loss(labels, inputs):
    labels = tf.reshape(labels, [-1, 1])
    # We need to compute the sampled_softmax_loss using 32bit floats to
    # avoid numerical instabilities.
    local_w_t = tf.cast(w_t, tf.float32)
    local_b = tf.cast(b, tf.float32)
    local_inputs = tf.cast(inputs, tf.float32)
    return tf.cast(
        tf.nn.sampled_softmax_loss(
            weights=local_w_t,
            biases=local_b,
            labels=labels,
            inputs=local_inputs,
            num_sampled=num_samples,
            num_classes=self.target_vocab_size),
        dtype)
首先,请注意,如果样本数(默认为512)小于目标词汇大小,我们只构造一个采样的softmax。对于小于512的词汇,只是使用标准的softmax损失可能是一个更好的主意。

那么,你可以看到,我们构建一个输出投影。它是一对,由权重矩阵和偏置向量组成。如果使用,rnn单元格将返回形状批量大小的向量size,而不是按批量大小返回target_vocab_size。要恢复逻辑,我们需要乘以权重矩阵并添加偏移,如第124-126行中所述seq2seq_model.py

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 ...]

咬和填充

除了采样SOFTMAX,我们的翻译模型还利用铲装,这是有效地处理不同长度的句子的方法。我们先来澄清问题。当将英文翻译成法语时,我们将输入英文句子的长度不等于L1,而不同长度的法语句子在输出上是L2。由于英文句子被传递encoder_inputs,法语句子decoder_inputs以GO符号为前缀,所以我们原则上应该为英文和法文句子的每一对(L1,L2 + 1)创建一个seq2seq模型。这将导致一个巨大的图形,由许多非常相似的子图组成。另一方面,我们可以用特殊的PAD符号来填充每个句子。那么我们只需要一个seq2seq模型,用于填充长度。

作为构建每对长度和填充到单个长度的图形之间的妥协,我们使用多个存储桶,并将每个句子放在其上方的桶的长度上。在translate.py我们使用以下默认桶。

buckets = [(5, 10), (10, 15), (20, 25), (40, 50)]
这意味着如果输入是具有3个令牌的英文句子,并且相应的输出是具有6个令牌的法语句子,那么它们将被放入第一个数据桶,并填充到编码器输入的长度为5,解码器输入的长度为10 。如果我们有一个8个令牌的英文句子,相应的法语句子有18个令牌,那么它们将不适用于(10,15)桶,所以(20,25)桶将被使用,即英文句子被填补到20,而法国一到25。

请记住,当构建解码器输入时,我们将特殊GO 符号添加到输入数据。这是在get_batch()函数中 完成的seq2seq_model.py,这也反转了输入英文句子。反转输入显示可以改善Sutskever等,2014 (pdf)中的神经翻译模型的结果。把这一切放在一起,想象我们有句话“我走了”,["I", "go", "."]像输入一样被标记为“Je vais”。作为输出,标记化["Je", "vais", "."]。它将放在(5,10)桶中,编码器输入代表[PAD PAD "." "go" "I"]和解码器输入[GO "Je" "vais" "." EOS PAD PAD PAD PAD PAD]

 

我们来跑吧

为了训练上述模型,我们需要一个大的英语 - 法语语料库。我们将使用10 ^ 9 -法语-英语语料库从 WMT'15网站 进行训练,和2013年的新闻测试来自同一站点开发集。当这个命令运行时data_dir,两个数据集将被下载并进行培训,并保存检查点train_dir

python translate.py
  --data_dir [your_data_directory] --train_dir [checkpoints_directory]
  --en_vocab_size=40000 --fr_vocab_size=40000 
它需要约18GB的磁盘空间和几个小时来准备训练语料库。它是打包的,词汇文件被创建data_dir,然后语料库被标记化并转换为整数ids。注意确定词汇大小的参数。在上面的例子中,40K以外的最常见的单词将被转换成UNK代表未知单词的令牌。因此,如果您更改词汇大小,二进制文件将再次将语料库重新映射到token-id。

数据准备完毕后,开始训练。默认参数translate 设置为相当大的值。长时间训练的大型模型可以获得良好的效果,但是可能需要太长时间,或者为GPU使用太多的内存。您可以请求培训一个较小的模型,如下例所示。

python translate.py
  --data_dir [your_data_directory] --train_dir [checkpoints_directory]
  --size=256 --num_layers=2 --steps_per_checkpoint=50 
上述命令将训练2层(默认为3)的模型,每层256个单位(默认为1024),每隔50个步骤保存一个检查点(默认值为200)。您可以使用这些参数来查找模型能够适应GPU内存的大小。

在训练期间,steps_per_checkpoint二进制文件的每个步骤将打印最近步骤的统计数据。使用默认参数(3层1024大小),第一条消息看起来像这样。

global step 200 learning rate 0.5000 step-time 1.39 perplexity 1720.62
  eval: bucket 0 perplexity 184.97
  eval: bucket 1 perplexity 248.81
  eval: bucket 2 perplexity 341.64
  eval: bucket 3 perplexity 469.04
global step 400 learning rate 0.5000 step-time 1.38 perplexity 379.89
  eval: bucket 0 perplexity 151.32
  eval: bucket 1 perplexity 190.36
  eval: bucket 2 perplexity 227.46
  eval: bucket 3 perplexity 238.66 
您可以看到,每个步骤只需要1.4秒钟以下,训练集中的困惑和每个桶的开发集的困惑。大约30K步后,我们看到短句(第0和第1段)的困惑进入单位数字。由于训练语料库含有〜22M句子,一个时期(通过训练数据一次)需要约340K步长,批量大小为64.此时,该模型可用于使用该--decode选项将英语句子翻译成法语。
python translate.py --decode
  --data_dir [your_data_directory] --train_dir [checkpoints_directory]

Reading model parameters from /tmp/translate.ckpt-340000
>  Who is the president of the United States?
 Qui est le président des États-Unis ? 

接下来是什么?

以上示例显示了如何构建自己的英语到法语翻译器,端到端。运行它,看看模型如何为自己执行。虽然它具有合理的质量,默认参数不会给你最好的翻译模型。这里有几件事你可以改进。

首先,我们使用一个非常原始的标记器,basic_tokenizer功能在data_utils。在WMT'15网站上可以找到更好的 记号。使用该标记器和更大的词汇表,应该会改善您的翻译。

此外,翻译模型的默认参数也没有调整。您可以尝试以不同的方式更改学习率,衰减或初始化模型的权重。您还可以更改默认 GradientDescentOptimizerseq2seq_model.py到更先进的一个,如AdagradOptimizer。尝试这些事情,看看他们如何改善你的结果!

最后,上面提出的模型可以用于任何序列到序列任务,不仅用于翻译。即使您想将序列转换为树,例如生成解析树,与上述相同的模型可以提供最先进的结果,如 Vinyals&Kaiser等,2014 (pdf)所示。 。所以你不仅可以构建自己的翻译器,还可以构建一个解析器,一个聊天机器人程序,或任何您想要的程序。实验!

 

  • 无标签