[Task-Oriented] 混合编码网络(Hybrid code network)

HCN-混合编码网络

Hybrid Code Networks: practical and efficient end-to-end dialog control with supervised and reinforcement learning
作者代码

介绍

  论文提出一个面向任务对话系统的网络模型, 可迁移性尚可,需要对系统做足够的设计工作,数据集数量要求不多但也需要比较严格的定制和规范化。

模型描述

[Task-Oriented] 混合编码网络(Hybrid code network)_第1张图片

  • Bag of words vector(词袋向量化)(step 2):基于语料库中的所有utterance词语作为词汇表,将utterance转换成词袋向量。

  • Utterance embedding(语句嵌入)(step3):使用word2vec对utterance中每个词语做word embedding, 对于word2vec模型词汇表中不存在的词语不予考虑进来,最后对句子的所有word embedding维度对齐做平均,最终的向量作为utterance embedding, 维度与word embedding相同。

  • Entity extraction(实体提取)(step 4):将本轮对话的用户提问(或用户上一轮的回复)中的实体值替换成实体类别,如句子中的Jennifer Jones, 替换成类别< name >。作者实现中这里的提问通常是用户基于上一轮机器提问的回复,论文中使用基于匹配的方法,根据具体的任务,预先定义好所有的实体类别和实体值,比如定义好两个实体< cuisine >, < location >, 其中 < cuisine >对应的实体值 [ ‘british’, ‘cantonese’, ‘french’, ‘indian’, ‘italian’, ‘japanese’, ‘korean’, ‘spanish’, ‘thai’, ‘vietnamese’], < locations >对应的实体值[ ‘bangkok’, ‘beijing’, ‘bombay’, ‘hanoi’, ‘paris’, ‘rome’, ‘london’, ‘madrid’, ‘seoul’, ‘tokyo’]。扫描整个句子,遇到存在的实体值就替换成相应的类别。

  • Entity tracking(实体追踪) (step 5):这个就是slot-filling的过程,将本轮对话的用户提问(或用户上一轮的回复)中提取出的实体值保存到本次多轮对话任务的实体追踪器上下文中(一次多轮对话任务维护一个实体追踪器和一个动作追踪器),一个实体类别对应一个实体值,在一次多轮对话中,随着对话的进行,累积实体值但是后来的实体值会替换先前的实体值,论文实现方法是维护一个{实体类别:实体值}的字典。

  • Context features(上下文特征):根据本轮用户提问,更新实体追踪器的实体类别-实体值状态,本论文是面向特定任务的对话系统,只关注当前上下文实体值的有和没有两种状态,所以论文实现使用0和1组成的掩码列表来表示对应实体值的有无。

  上面这实体提取、实体追踪和上下文特征部分其实就是PipeLine经典结构中的 对话状态追踪(Dialogue state tracker) 模块,作用是Entity extractionEntity tracking管理历史对话中每轮对话的输入,Context features输出当前对话的上下文状态。用户目的其表现形式就是一系列slot-value pairs, 本文中就是实体类别-实体值的组合。

  • Action Mask(动作掩码):表示在本轮用户提问,更新当前上下文特征后,允许机器在当前时间步做出的所有动作(回复),实现用一个位向量,置1的位表示本轮允许该回复,论文中的方法必须对具体的任务设计一个实体掩码(上下文特征)– 动作掩码的对应关系,即在当前轮次上下文状态中,允许机器做出的动作(回复)的所有情况,这些情况是当然也要预先设计好,所有的动作(回复)构成动作模板。

  • RNN和Dense Layer(step 7-12):将动作掩码,上下文特征,语句嵌入,词袋向量concat成 特征向量【动作掩码 上下文特征 语句嵌入 词袋向量】 输入进循环神经网络(LSTM,GRU)(作者放出的代码实现中没有连接动作掩码),对隐藏层(LSTM的话就把h和c水平连接成一个向量)的输出做一个全连接,映射到动作模板的维度(所有预先设计好的动作的数量),这一层的输出作为交叉熵损失函数的参数,映射后的向量做softmax归一化,这个归一化后的向量便是一个在动作模板上的分布向量,下一步,使用动作掩码对该向量做元素乘法,动作掩码中不允许的动作便被强制设为0概率,然后选取概率最大的作为最终选择的动作(如果强化学习在线学习的话这里不一样)。作者的代码到这里就结束了。

  动作掩码加上整个RNN可以看做是PipeLine中的 对话策略学习(Dialogue policy learning) 模块,作用是根据当前的对话状态(上下文特征)选择下一步要做出的反应。

  • Entity output(实体输出)(step 13):网络选择的动作对应一个动作模板,将动作模板中的实体类型替换成上下文特征中的实体值构造成完整形式的动作,比如动作模板“ < city >, right?”转换成“Seattle,right?”。

  • 最后(step 14-18):判断实体输出的动作类型,如果动作类型是一个API调用,例如“api_call french bombay four cheap”,相关的代码就会被执行,比如查询数据库,执行结果直接或经过处理后以呈现更丰富的内容返回给用户,如果API调用会返回与对话相关的特征,可以将调用结果在下一个时间步内以某种形式加入到网络输入时的特征向量中;如果动作类型仅仅是一个文本,直接返回给用户,这个动作也可以当做一种特征在下个时间步加入到网络输入时的特征向量。这里,作者开放的代码中均没有实现。

  实体输出和最后的步骤可以当成是PipleLine中的 自然语言生成(NLG) 模块,作用是将对话策略的输出转化成自然语言的句子反馈给用户。



  以下是参考了作者的代码实现和bAbI dialog数据集做出的总结。

语料规范和设计

  原始语料库内容为N次多轮对话,每次多轮对话的轮数可不同,每次多轮对话用空行隔开,每轮对话为用户一问机器一答(utterance-response)的形式,utterance和response用制表符\t分开,对于中文,utterance和response分别要用空格分词,去掉特殊符号,每轮对话占一行,一次对话要连贯、流畅、合理。比如一次多轮对话形式如下:

1 good morning  hello what can i help you with today
2 i'd like to book a table with italian food    i'm on it
3  where should it be
4 in paris  how many people would be in your party
5 for six people please which price range are looking for
6 in a cheap price range please ok let me look into some options for you
7  api_call italian paris six cheap
8 actually i would prefer for two people    sure is there anything else to update
9 instead could it be in madrid sure is there anything else to update
10 instead could it be with spanish food    sure is there anything else to update
11 no   ok let me look into some options for you
12     api_call spanish madrid two cheap
34     what do you think of this option: resto_madrid_cheap_spanish_8stars
35 no this does not work for me sure let me find an other option for you
36     what do you think of this option: resto_madrid_cheap_spanish_6stars
37 do you have something else   sure let me find an other option for you
38     what do you think of this option: resto_madrid_cheap_spanish_1stars
39 it's perfect great let me do the reservation
40 may i have the phone number of the restaurant    here it is resto_madrid_cheap_spanish_1stars_phone
41 thanks   is there anything i can help you with
42 no thank you you're welcome
...

  utterance:

  • utterance为用户提问或者对上一轮机器提问的回答。
  • 对话中,要考虑用户在某轮沉默的情况,如等待机器回复,此时utterance标记为< SILENCE >。
  • 对问句的形式没有限制和要求,流畅合理即可。
  • 从utterance中归纳概括出实体值和实体类别,做出实体类别-所有实体值的映射关系,实体类别-实体值即为slot-value,如foodtype = 川菜、location = 西二旗, 表达一个限制条件(constraint),也可理解为用户目标的一个组成单元。

  response:

  • response可以为对用户本轮提问的回答。如:

    what is the phone number of the restaurant \t here it is 86-xxxx
    do you have something else \t sure let me find an other option for you

  • response可以是为了得到实体值(用户目的信息)的进一步追问,如想知道实体类别(price range) 的实体值 (cheap) :

    in rome \t which price range are looking for
    i am looking for a cheap restaurant \t ok let me look into some options for you

  • response可为用户沉默情况下的追问,如:

    < SILENCE > \t how many people would be in your party

  • response可为用户沉默等待回复情况下的机器的回答,如:

    < SILENCE > \t what do you think of this option: resto_paris_moderate_british_8stars

  • response中对得到实体值slot-value pairs的value后做出的回复(即dialog act)转换成communicative function的形式,可以是“api调用”动作模板,如 inform(foodtype = 川菜,location = 西二旗), 这里的inform就是communicative function。转换后训练语料库的所有可能的response组成action templates, 其大小不能过大。

  • 设计实体掩码和动作掩码的映射关系。

  如何判断一次人机对话结束?
   用户规定t时间内无输入,可以认为用户反馈了< SILENCE >, 再过t时间无反馈则可认为本轮对话结束。

RNN网络结构图

[Task-Oriented] 混合编码网络(Hybrid code network)_第2张图片

实现流程

  1. 准备训练语料库,准备word2vec模型(基于其他语料库训练)
  2. 定义实体追踪器:更新维护(实体掩码)上下文特征;对语句中实体值替换成实体类型。
  3. 定义动作追踪器:将训练语料response中实体值替换成实体类型,去掉重复项,生成动作模板;设计和定义一个实体掩码—动作掩码映射,根据当前实体掩码,生成动作掩码,实体掩码每一位对应一个实体值是否存在,动作掩码每一位对应一个动作模板是否允许;
  4. 数据预处理,将每次多轮对话分开,记录每次对话的开始与结束位置,utterance直接从语料库读取,response映射成动作模板的ID, 处理后数据便为很多(utterance, action id) 组。可以使用留出法或交叉验证法划分训练集-验证集。
  5. 定义词袋编码器:目的是将utterance表示成词袋向量,词汇表为语料库中所有utterance词汇。
  6. 定义语句嵌入:使用word2vec对utterance中每个词语做word embedding, 对于word2vec模型词汇表中不存在的词语不予考虑进来,最后对句子的所有word embedding维度对齐做平均,最终的向量作为utterance embedding, 维度与word embedding相同。
  7. 构建网络训练,输入为特征向量【上下文特征 语句嵌入 词袋向量】,输出为预测的动作模板ID。 每次多轮对话训练步骤如下:
    • 重置上下文特征
    • 重置动作掩码
    • 隐藏层(LSTM也包括Context向量)初始状态设置0。
    • 遍历本次对话的每轮(utter—action_ id):
      • 使用实体追踪器提取utter中的实体值,更新上下文特征;
      • 使用动作追踪器根据当前上下文特征更新动作掩码;
      • 使用utter构建【上下文特征 语句嵌入 词袋向量】输入;
      • action_id为标签,损失函数为交叉熵损失,做一次梯度下降;
      • 得到隐藏层状态作为在本次对话下一个时间步隐藏层的初始状态(作者实现使用这种方式代替bptt)。

扩展

  应用强化学习实现在线学习 。

你可能感兴趣的:(Dialogue,System)