【序列到序列学习】使用Scheduled Sampling改善翻译质量

生成古诗词

序列到序列学习实现两个甚至是多个不定长模型之间的映射,有着广泛的应用,包括:机器翻译、智能对话与问答、广告创意语料生成、自动编码(如金融画像编码)、判断多个文本串之间的语义相关性等。

在序列到序列学习任务中,我们首先以机器翻译任务为例,提供了多种改进模型供大家学习和使用。包括:不带注意力机制的序列到序列映射模型,这一模型是所有序列到序列学习模型的基础;使用Scheduled Sampling改善RNN模型在生成任务中的错误累积问题;带外部记忆机制的神经机器翻译,通过增强神经网络的记忆能力,来完成复杂的序列到序列学习任务。除机器翻译任务之外,我们也提供了一个基于深层LSTM网络生成古诗词,实现同语言生成的模型。

【序列到序列学习】

02

使用Scheduled Sampling

改善翻译质量

|1. 概述

序列生成任务的生成目标是在给定源输入的条件下,最大化目标序列的概率。训练时该模型将目标序列中的真实元素作为解码器每一步的输入,然后最大化下一个元素的概率。生成时上一步解码得到的元素被用作当前的输入,然后生成下一个元素。可见这种情况下训练阶段和生成阶段的解码器输入数据的概率分布并不一致。

Scheduled Sampling [1]是一种解决训练和生成时输入数据分布不一致的方法。在训练早期该方法主要使用目标序列中的真实元素作为解码器输入,可以将模型从随机初始化的状态快速引导至一个合理的状态。随着训练的进行,该方法会逐渐更多地使用生成的元素作为解码器输入,以解决数据分布不一致的问题。

标准的序列到序列模型中,如果序列前面生成了错误的元素,后面的输入状态将会收到影响,而该误差会随着生成过程不断向后累积。Scheduled Sampling以一定概率将生成的元素作为解码器输入,这样即使前面生成错误,其训练目标仍然是最大化真实目标序列的概率,模型会朝着正确的方向进行训练。因此这种方式增加了模型的容错能力

|2. 算法简介

Scheduled Sampling主要应用在序列到序列模型的训练阶段,而生成阶段则不需要使用。

训练阶段解码器在最大化第t个元素概率时,标准序列到序列模型使用上一时刻的真实元素yt−1作为输入。设上一时刻生成的元素为gt−1,Scheduled Sampling算法会以一定概率使用gt−1作为解码器输入。

设当前已经训练到了第i个mini-batch,Scheduled Sampling定义了一个概率ϵi控制解码器的输入。ϵi是一个随着i增大而衰减的变量,常见的定义方式有:

  • 线性衰减:ϵi=max(ϵ,k−c∗i),其中ϵ限制ϵi的最小值,k和c控制线性衰减的幅度。
  • 指数衰减:ϵi=ki,其中0<k<1,k控制着指数衰减的幅度。
  • 反向Sigmoid衰减:ϵi=k/(k+exp(i/k)),其中k>1,k同样控制衰减的幅度。

图1给出了这三种方式的衰减曲线,

图1. 线性衰减、指数衰减和

反向Sigmoid衰减的衰减曲线

如图2所示,在解码器的t时刻Scheduled Sampling以概率ϵi使用上一时刻的真实元素yt−1作为解码器输入,以概率1−ϵi使用上一时刻生成的元素gt−1作为解码器输入。从图1可知随着i的增大ϵi会不断减小,解码器将不断倾向于使用生成的元素作为输入,训练阶段和生成阶段的数据分布将变得越来越一致。

图2. Scheduled Sampling选择不同元素作为解码器输入示意图

|3. 模型实现

由于Scheduled Sampling是对序列到序列模型的改进,其整体实现框架与序列到序列模型较为相似。为突出本文重点,这里仅介绍与Scheduled Sampling相关的部分,完整的代码见network_conf.py。

首先导入需要的包,并定义控制衰减概率的类RandomScheduleGenerator,如下:

import numpy as np

import math

class RandomScheduleGenerator:

"""

The random sampling rate for scheduled sampling algoithm, which uses devcayed

sampling rate.

"""

...

下面将分别定义类RandomScheduleGenerator的__init__、getScheduleRate和processBatch三个方法。

__init__方法对类进行初始化,其schedule_type参数指定了使用哪种衰减方式,可选的方式有constant、linear、exponential和inverse_sigmoid。constant指对所有的mini-batch使用固定的ϵi,linear指线性衰减方式,exponential表示指数衰减方式,inverse_sigmoid表示反向Sigmoid衰减。__init__方法的参数a和b表示衰减方法的参数,需要在验证集上调优。self.schedule_computers将衰减方式映射为计算ϵi的函数。最后一行根据schedule_type将选择的衰减函数赋给self.schedule_computer变量。

def __init__(self, schedule_type, a, b):

"""

schduled_type: is the type of the decay. It supports constant, linear,

exponential, and inverse_sigmoid right now.

a: parameter of the decay (MUST BE DOUBLE)

b: parameter of the decay (MUST BE DOUBLE)

"""

self.schedule_type = schedule_type

self.a = a

self.b = b

self.data_processed_ = 0

self.schedule_computers = {

"constant": lambda a, b, d: a,

"linear": lambda a, b, d: max(a, 1 - d / b),

"exponential": lambda a, b, d: pow(a, d / b),

"inverse_sigmoid": lambda a, b, d: b / (b + math.exp(d * a / b)),

}

assert (self.schedule_type in self.schedule_computers)

self.schedule_computer = self.schedule_computers[self.schedule_type]

getScheduleRate根据衰减函数和已经处理的数据量计算ϵi。

def getScheduleRate(self): """ Get the schedule sampling rate. Usually not needed to be called by the users """ return self.schedule_computer(self.a, self.b, self.data_processed_)

processBatch方法根据概率值ϵi进行采样,得到indexes,indexes中每个元素取值为0的概率为ϵi,取值为1的概率为1−ϵi。indexes决定了解码器的输入是真实元素还是生成的元素,取值为0表示使用真实元素,取值为1表示使用生成的元素。

def processBatch(self, batch_size):

"""

Get a batch_size of sampled indexes. These indexes can be passed to a

MultiplexLayer to select from the grouth truth and generated samples

from the last time step.

"""

rate = self.getScheduleRate()

numbers = np.random.rand(batch_size)

indexes = (numbers >= rate).astype('int32').tolist()

self.data_processed_ += batch_size

return indexes

Scheduled Sampling需要在序列到序列模型的基础上增加一个输入true_token_flag,以控制解码器输入。

true_token_flags = paddle.layer.data(

name='true_token_flag',

type=paddle.data_type.integer_value_sequence(2))

这里还需要对原始reader进行封装,增加true_token_flag的数据生成器。下面以线性衰减为例说明如何调用上面定义的RandomScheduleGenerator产生true_token_flag的输入数据。

def gen_schedule_data(reader,

schedule_type="linear",

decay_a=0.75,

decay_b=1000000):

"""

Creates a data reader for scheduled sampling.

Output from the iterator that created by original reader will be

appended with "true_token_flag" to indicate whether to use true token.

:param reader: the original reader.

:type reader: callable

:param schedule_type: the type of sampling rate decay.

:type schedule_type: str

:param decay_a: the decay parameter a.

:type decay_a: float

:param decay_b: the decay parameter b.

:type decay_b: float

:return: the new reader with the field "true_token_flag".

:rtype: callable

"""

schedule_generator = RandomScheduleGenerator(schedule_type, decay_a, decay_b)

def data_reader():

for src_ids, trg_ids, trg_ids_next in reader():

yield src_ids, trg_ids, trg_ids_next, \

[0] + schedule_generator.processBatch(len(trg_ids) - 1)

return data_reader

这段代码在原始输入数据(即源序列元素src_ids、目标序列元素trg_ids和目标序列下一个元素trg_ids_next)后追加了控制解码器输入的数据。由于解码器第一个元素是序列开始符,因此将追加的数据第一个元素设置为0,表示解码器第一步始终使用真实目标序列的第一个元素(即序列开始符)。

训练时recurrent_group每一步调用的解码器函数如下:

def gru_decoder_with_attention_train(enc_vec, enc_proj, true_word,

true_token_flag):

"""

The decoder step for training.

:param enc_vec: the encoder vector for attention

:type enc_vec: LayerOutput

:param enc_proj: the encoder projection for attention

:type enc_proj: LayerOutput

:param true_word: the ground-truth target word

:type true_word: LayerOutput

:param true_token_flag: the flag of using the ground-truth target word

:type true_token_flag: LayerOutput

:return: the softmax output layer

:rtype: LayerOutput

"""

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)

gru_out_memory = paddle.layer.memory(

name='gru_out', size=target_dict_dim)

generated_word = paddle.layer.max_id(input=gru_out_memory)

generated_word_emb = paddle.layer.embedding(

input=generated_word,

size=word_vector_dim,

param_attr=paddle.attr.ParamAttr(name='_target_language_embedding'))

current_word = paddle.layer.multiplex(

input=[true_token_flag, true_word, generated_word_emb])

decoder_inputs = paddle.layer.fc(

input=[context, current_word],

size=decoder_size * 3,

act=paddle.activation.Linear(),

bias_attr=False)

gru_step = paddle.layer.gru_step(

name='gru_decoder',

input=decoder_inputs,

output_mem=decoder_mem,

size=decoder_size)

out = paddle.layer.fc(

name='gru_out',

input=gru_step,

size=target_dict_dim,

act=paddle.activation.Softmax())

return out

该函数使用memory层gru_out_memory记忆上一时刻生成的元素,根据gru_out_memory选择概率最大的词语generated_word作为生成的词语。multiplex层会在真实元素true_word和生成的元素generated_word之间做出选择,并将选择的结果作为解码器输入。multiplex层使用了三个输入,分别为true_token_flag、true_word和generated_word_emb。对于这三个输入中每个元素,若true_token_flag中的值为0,则multiplex层输出true_word中的相应元素;若true_token_flag中的值为1,则multiplex层输出generated_word_emb中的相应元素。

【参考文献】

  1. Bengio S, Vinyals O, Jaitly N, et al. Scheduled sampling for sequence prediction with recurrent neural networks//Advances in Neural Information Processing Systems. 2015: 1171-1179.

原文发布于微信公众号 - PaddlePaddle(PaddleOpenSource)

原文发表时间:2018-03-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器学习算法与Python学习

Torch7模型训练

Torch7搭建卷积神经网络详细教程已经详细的介绍啦Module模块,这里再次基础上再给出一些上Container、 Transfer Functions La...

404130
来自专栏素质云笔记

keras系列︱Sequential与Model模型、keras基本结构功能(一)

不得不说,这深度学习框架更新太快了尤其到了Keras2.0版本,快到Keras中文版好多都是错的,快到官方文档也有旧的没更新,前路坑太多。 到发文为止...

4.4K80
来自专栏人工智能LeadAI

图像学习-验证码识别

这是去年博主心血来潮实现的一个小模型,现在把它总结一下。由于楼主比较懒,网上许多方法都需要切割图片,但是楼主思索了一下感觉让模型有多个输出就可以了呀,没必要一定...

70240
来自专栏小鹏的专栏

01 TensorFlow入门(2)

Working with Matrices:         了解TensorFlow如何使用矩阵对于通过计算图理解数据流非常重要。 Getting read...

29560
来自专栏AI研习社

详解自动识别验证码,LSTM大显身手

这是去年博主心血来潮实现的一个小模型,现在把它总结一下。由于楼主比较懒,网上许多方法都需要切割图片,但是楼主思索了一下感觉让模型有多个输出就可以了呀,没必要一定...

45580
来自专栏数据科学学习手札

(数据科学学习手札25)sklearn中的特征选择相关功能

一、简介   在现实的机器学习任务中,自变量往往数量众多,且类型可能由连续型(continuou)和离散型(discrete)混杂组成,因此出于节约计算成本、精...

52690
来自专栏DHUtoBUAA

编程求取直线一般式表达式,两直线交点

背景介绍   最近在水面无人艇(USV)模拟仿真中,用到了一些点和线的关系求解,本文主要讲述一下两点确认直线,点到直线距离,两条直线的交点等问题的解决方法,并给...

54970
来自专栏书山有路勤为径

Batch Normalization怎么加入batch normalization

Batch Normalization 会使你的参数搜索问题变得很容易,使神经网络对超参数的选择更加稳定,超参数的范围会更加庞大,工作效果也很好,也会使你的训练...

9720
来自专栏懒人开发

(10.4)James Stewart Calculus 5th Edition:Areas and Lengths in Polar Coordinates

极坐标系中的面积和长度 (这里看见 Coordinates ,就想到了 CoordiateLayout _ ) 我们简单要求一个圆的部分面积

11520
来自专栏null的专栏

简单易学的机器学习算法——Rosenblatt感知机的对偶解法

一、Rosenblatt感知机回顾    image.png 二、Rosenblatt感知机的对偶形式    image.png 三、算法流程 image....

39050

扫码关注云+社区

领取腾讯云代金券