在训练过程中,我们需要将我们的target序列作为输入传给Decoder端RNN的每个阶段,而不是使用前一阶段预测输出,这样会使得模型更加准确。(这就是为什么我们会构建Training和Predicting两个Decoder的原因,下面还会有对这部分的解释)。 需要用target数据来计算模型的loss。 我们首先需要对target端的数据进行一步预处理。在我们将target中的序列作为输入给Decoder端的RNN时,序列中的最后一个字母(或单词)其实是没有用的。我们来用下图解释: 我们此时只看右边的Decoder端,可以看到我们的target序列是[<go>, W, X, Y, Z, <eos>],其中<go>,j2直播,W,X,Y,Z是每个时间序列上输入给RNN的内容,我们发现,<eos>并没有作为输入传递给RNN。因此我们需要将target中的最后一个字符去掉,同时还需要在前面添加<go>标识,告诉模型这代表一个句子的开始。 如上图,所示,红色和橙色为我们最终的保留区域,灰色是序列中的最后一个字符,我们把它删掉即可。 我们使用tf.strided_slice()来进行这一步处理。 其中tf.fill(dims, value)参数会生成一个dims形状并用value填充的tensor。举个栗子:tf.fill([2,2], 7) => [[7,7], [7,7]]。tf.concat()会按照某个维度将两个tensor拼接起来。2. 构造Decoder 对target数据进行embedding。 构造Decoder端的RNN单元。 构造输出层,从而得到每个时间序列上的预测结果。 构造training decoder。 构造predicting decoder。 注意,我们这里将decoder分为了training和predicting,这两个encoder实际上是共享参数的,也就是通过training decoder学得的参数,predicting会拿来进行预测。那么为什么我们要分两个呢,这里主要考虑模型的robust。 在training阶段,为了能够让模型更加准确,我们并不会把t-1的预测输出作为t阶段的输入,而是直接使用target data中序列的元素输入到Encoder中。而在predict阶段,我们没有target data,有的只是t-1阶段的输出和隐层状态。 上面的图中代表的是training过程。在training过程中,我们并不会把每个阶段的预测输出作为下一阶段的输入,下一阶段的输入我们会直接使用target data,这样能够保证模型更加准确。 这个图代表我们的predict阶段,在这个阶段,我们没有target data,这个时候前一阶段的预测结果就会作为下一阶段的输入。 当然,predicting虽然与training是分开的,但他们是会共享参数的,training训练好的参数会供predicting使用。 decoder层的代码如下: 构建好了Encoder层与Decoder以后,我们需要将它们连接起来build我们的Seq2Seq模型。 定义超参数 (责任编辑:本港台直播) |