在这篇文章中,我们将实现一个基于检索的机器人。基于检索的模型具有可以使用的预定义响应的存储库,这与生成模型不同,后者可以生成他们以前从未见过的响应。更正式地说,基于检索的模型的输入是一个上下文C(到目前为止的对话)和一个潜在的响应[R。模型输出是响应的分数。要找到一个好的回答,您将计算多个回答的得分,并选择得分最高的回答。
但是,如果可以构建生成模型,为什么还要构建基于检索的模型呢?生成模型似乎更灵活,因为它们不需要预定义响应的存储库,对吧?
问题是生成模型在实践中不能很好地工作。至少还没有。因为他们在如何应对方面拥有如此多的自由,因此生成模型往往会产生语法错误并产生不相关的,通用的或不一致的反应。他们还需要大量的培训数据,难以优化。今天绝大多数生产系统都是基于检索的,或者是基于检索和生成的组合。谷歌的智能回复就是一个很好的例子。生成模型是一个活跃的研究领域,但我们尚未完全实现。如果你想今天建立一个会话代理,你最好的选择很可能是一个基于检索的模型。
问题输入:“现在”、“我”、“在”、“努力学习”、“英文”、“,”、“我”、“想”、“成为”、“一名”、“翻译”、“。”
回输出:“嗯”、“,”、“你”、“是”、“大有”、“前途”、“的”、“。”、“追逐”、“你”、“的”、“梦想”、“,”、“永不”、“放弃”、“。”
在这篇文章中,我们将使用Ubuntu Dialog Corpus 文章及代码,Ubuntu Dialog Corpus(UDC)是可用的最大公共对话数据集之一。它基于公共IRC网络上Ubuntu频道的聊天记录,数据下载地址。
培训数据包括1,000,000个例子,50%正样本(标签1)和50%负样本(标签0)。每个例子都包含一个上下文,到此为止的对话,一个话语,一个对上下文的回应。正面标签意味着话语是对上下文的实际响应,负面标签意味着话语不是 - 它是从语料库中的某个地方随机选取的。这是一些示例数据。
需要注意的是数据集生成脚本已经做了一堆预处理对我们的-它已经经过NLTK处理。该脚本还使用特殊标记替换了名称,位置,组织,URL和系统路径等实体。这种预处理并不是绝对必要的,但它可能会将性能提高几个百分点。平均上下文长86个字,平均话语长17个字。查看Jupyter笔记本以查看数据分析。
对train.csv
数据进行head()
,后可以得到:
对valid.csv
数据进行head()
,后可以得到:
对train.csv
数据进行describe()
,后可以得到:
对valid.csv
数据进行describe()
,后可以得到:
编码器的作用是把一个不定长的输入序列变换成一个定长的背景变量 c \boldsymbol{c} c,并在该背景变量中编码输入序列信息。常用的编码器是循环神经网络。
让我们考虑批量大小为 1 的时序数据样本。假设输入序列是 x 1 , … , x T x_1,\ldots,x_T x1,…,xT,例如 x i x_i xi 是输入句子中的第 i i i 个词。在时间步 t t t,循环神经网络将输入 x t x_t xt 的特征向量 x t \boldsymbol{x}_t xt 和上个时间步的隐藏状态 h t − 1 \boldsymbol{h}_{t-1} ht−1 变换为当前时间步的隐藏状态 h t \boldsymbol{h}_t ht。我们可以用函数 f f f 表达循环神经网络隐藏层的变换:
h t = f ( x t , h t − 1 ) . \boldsymbol{h}_t = f(\boldsymbol{x}_t, \boldsymbol{h}_{t-1}). ht=f(xt,ht−1).
接下来编码器通过自定义函数 q q q 将各个时间步的隐藏状态变换为背景变量
c = q ( h 1 , … , h T ) . \boldsymbol{c} = q(\boldsymbol{h}_1, \ldots, \boldsymbol{h}_T). c=q(h1,…,hT).
例如,当选择 q ( h 1 , … , h T ) = h T q(\boldsymbol{h}_1, \ldots, \boldsymbol{h}_T) = \boldsymbol{h}_T q(h1,…,hT)=hT 时,背景变量是输入序列最终时间步的隐藏状态 h T \boldsymbol{h}_T hT。以上描述的编码器是一个单向的循环神经网络,每个时间步的隐藏状态只取决于该时间步及之前的输入子序列。我们也可以使用双向循环神经网络构造编码器。这种情况下,编码器每个时间步的隐藏状态同时取决于该时间步之前和之后的子序列(包括当前时间步的输入),并编码了整个序列的信息。
评价机器翻译结果通常使用BLEU(Bilingual Evaluation Understudy)[1]。同样也可以用于Chatbot结果,对于模型预测序列中任意的子序列,BLEU考察这个子序列是否出现在标签序列中。
具体来说,设词数为 n n n的子序列的精度为 p n p_n pn。它是预测序列与标签序列匹配词数为 n n n的子序列的数量与预测序列中词数为 n n n的子序列的数量之比。举个例子,假设标签序列为 A A A、 B B B、 C C C、 D D D、 E E E、 F F F,预测序列为 A A A、 B B B、 B B B、 C C C、 D D D,那么 p 1 = 4 / 5 , p 2 = 3 / 4 , p 3 = 1 / 3 , p 4 = 0 p_1 = 4/5,\ p_2 = 3/4,\ p_3 = 1/3,\ p_4 = 0 p1=4/5, p2=3/4, p3=1/3, p4=0。设 l e n label len_{\text{label}} lenlabel和 l e n pred len_{\text{pred}} lenpred分别为标签序列和预测序列的词数,那么,BLEU的定义为
exp ( min ( 0 , 1 − l e n label l e n pred ) ) ∏ n = 1 k p n 1 / 2 n , \exp\left(\min\left(0, 1 - \frac{len_{\text{label}}}{len_{\text{pred}}}\right)\right) \prod_{n=1}^k p_n^{1/2^n}, exp(min(0,1−lenpredlenlabel))n=1∏kpn1/2n,
其中 k k k是我们希望匹配的子序列的最大词数。可以看到当预测序列和标签序列完全一致时,BLEU
为1。
因为匹配较长子序列比匹配较短子序列更难,BLEU对匹配较长子序列的精度赋予了更大权重。例如,当 p n p_n pn固定在0.5时,随着 n n n的增大, 0. 5 1 / 2 ≈ 0.7 , 0. 5 1 / 4 ≈ 0.84 , 0. 5 1 / 8 ≈ 0.92 , 0. 5 1 / 16 ≈ 0.96 0.5^{1/2} \approx 0.7, 0.5^{1/4} \approx 0.84, 0.5^{1/8} \approx 0.92, 0.5^{1/16} \approx 0.96 0.51/2≈0.7,0.51/4≈0.84,0.51/8≈0.92,0.51/16≈0.96。另外,模型预测较短序列往往会得到较高 p n p_n pn值。因此,上式中连乘项前面的系数是为了惩罚较短的输出而设的。举个例子,当 k = 2 k=2 k=2时,假设标签序列为 A A A、 B B B、 C C C、 D D D、 E E E、 F F F,而预测序列为 A A A、 B B B。虽然 p 1 = p 2 = 1 p_1 = p_2 = 1 p1=p2=1,但惩罚系数 exp ( 1 − 6 / 2 ) ≈ 0.14 \exp(1-6/2) \approx 0.14 exp(1−6/2)≈0.14,因此BLEU也接近0.14。
下面来实现BLEU的计算。
def bleu(pred_tokens, label_tokens, k):
len_pred, len_label = len(pred_tokens), len(label_tokens)
score = math.exp(min(0, 1 - len_label / len_pred))
for n in range(1, k + 1):
num_matches = 0
for i in range(len_pred - n + 1):
if ' '.join(pred_tokens[i: i + n]) in ' '.join(label_tokens):
num_matches += 1
score *= math.pow(num_matches / (len_pred - n + 1), math.pow(0.5, n))
return score
引用文本
[1] Papineni, K., Roukos, S., Ward, T., & Zhu, W. J. (2002, July). BLEU: a method for automatic evaluation of machine translation. In Proceedings of the 40th annual meeting on association for computational linguistics (pp. 311-318). Association for Computational Linguistics.
[2] WMT. http://www.statmt.org/wmt14/translation-task.html
[3] Tatoeba Project. http://www.manythings.org/anki/