有多少爱可以重来,上海申花,奥特曼视频-酷技术,最新世界技术新闻发布,有趣有料的头条

频道:微博热点 日期: 浏览:259

依据检索模型的谈天机器人

本文咱们将介绍和完结一个依据检索模型的谈天机器人。检索模型所运用的回复数据通常是预先存储且知道(或界说)的数据,而不像生成式模型那样能够创造出簇新的、不知道的回复内容(模型没有见过)。精确来讲,检索式模型的有多少爱能够重来,上海申花,奥特曼视频-酷技能,最新国际技能新闻发布,风趣有料的头条输入是一段上下文内容 C (会话到现在不知道的内容信息) 和一个或许作为回复韩漫h的候选答案;模型的输出是对这个候选答案的打分。寻觅最适宜的回复内容的进程是:先对一堆候选答案进行打分及排序,终究选出分值最高的那个最为回复。

或许你会质疑为什么不直接运用生成式模型,生成式模型不需求预先存储且界说好的数据,比起检索模型愈加的灵敏多变。原因在于现在生成式模型的作用并欠安,由于生成式模型的约束条件少,过于多变的模型导致生成的response中呈现一些语法错误和语义无关的内容。生成式模型需求海量的练习数据,且难以优化。现在工业界常用的模型仍是依据检索的模型,或许以生成式模型作为弥补的两者结合,谷歌的Smart Reply便是一个比如。虽然现在生成式模型是学术界的研讨热门,但在实践中运用检索式模型是愈加适宜的挑选。

Ubuntu对话数据集

这篇博客咱们将运用Ubuntu对话数据集(论文来历 github地址)。这个数据集(Ubuntu Dialog Corpus, UDC)是现在最大的揭露对话数据集之一,它是来自Ubuntu的IRC网络上的对话日志。这篇论文介绍了该数据集生成的详细细节。下面简略介绍一下数据的格局。

练习数据有1,000,000条实例,其间一半是正例(label为1),一半是负例(label为0,负例为随机生成)。每条实例包括一段上下文信息(context),即Query;和一段或许的回复内容,即Response;Label为1表明该Response确实是Query的回复,Label为0则表明不是。下面是数据示例:

数据集的生成运用了NLTK东西,包括分词、stemmed、lemmatized等文本预处理进程;一起还运用了NER技能,将文本中的实体,如名字、地址、安排、URL等替换成特别字符。这些文本预处理并不是有必要的,可是能够提高一些模型的功能。据核算,query的均匀长度为86个word,而response的均匀长度为17个word,更多的数据核算信息见Jupyter notebook。

数据集也包括了测验和验证集,但这两部分的数据和练习数据在格局上不太相同。在测验集和验证会集,关于每一条实例,有一个正例和九个负例数据(也称为搅扰数据)。模型的方针在于给正例的得分尽或许的高,而给负例的得分尽或许的低。下面是数据示例:

模型的评测方法有很多种。其间最常用到的是recall@k,即经模型对候选的response排序后,前k个候选中存在正例数据(正确的那个)的占比;明显k值越大,由嬿丽该目标会越高,由于这对模型功能的要求越松。

在Ubuntu数据会集,负例数据都是随机生成的;然而在实践中,想要从悉数的数据中随机生成负例是不或许的。谷歌的Smart Reply则运用了聚类技能,然后将每个类的中取一些作为负例,这样生成负例的方法显得愈加合理(考虑了负例数据的多样性,一起削减时刻开支)。

BASELINE

在运用NN模型之前,先树立一些简略的baseline模插一下型,以便利后续的作用比照。运用如下的函数来核算recall@k:

def evaluate_recall(y, y_test, k=1):

num_examples = float(len(y))

num_correct = 0

for predictions, label in zip(y, y_test):

if label in predictions[:k]:

num_correct += 1

return num_correct/num_examples

其间,y是所猜测的以降序摆放的模型猜测分值,y_test是实践的label值。举个比如,假定y的值为[0,3,1,2,5,6,4,7,8,9],这说明第0号织田幼琳子的候选的猜测分值最高、作为回复的或许性最高,而9号则最低。这儿的第0号一起也是正确的那个,即正例数据,标号为1-9的为随机生成的负例数据。

理论上,最base的随机模型(Random Predictor)的recall@1的值为10%,recall@2的值为20%。相返校游戏实在工作应的代码如下:

# Random Predictor

def predict_random(context, utterances):

return np.random.choice(len(utterances), 10, replace=False)

# Evaluate Random predictor

y_random = [predict_random(test_df.Context[x], test_df.iloc[x,1:].values) for x in range(len(test_df))]

y_test = np.zeros(len(y_random))

for n in [1, 2, 5, 10]:

print("Recall @ ({}, 10): {:g}".format(n, evaluate_recall(y_random, y_test, n)))

实践的模型成果如下:

Recall @ (1, 10): 0.0937632

Recall @ (2, 10): 0.194503

Recall @ (5, 10): 0.49297

Recall @ (10, 10): 1

这与理论预期相符,但这不是咱们所寻求的成果。

别的一个baseline的模型为tfidf predictor。tfidf表明词频(term frequency)和逆文档词频(inverse document frequency),它衡量了一个词在一篇文档中的重要程度(依据整个语料库)。直观上,两篇文档对应的tfidf向量越挨近,两篇文章的内容也越类似。相同的,关于一个QR pair,它们语义上挨近的词共现的越多,也将越或许是一个正确的QR pair(这句话存疑,原因在于QR之间也有或许不存在语义上lreland的类似,一个Q对应的R是多样的。)。tfidf predictor对应的代码如下(运用scikit-learn东西能够容易完结):

class TFIDFPredictor:

def __init__(self):

self.vectorizer = TfidfVectorizer()

def train(self, data):

self.vectorizer.fit(np.append(data.Context.values,data.Utterance.values))

def predict(self, context, utterances):

# Convert context and utterances into tfidf vector

vector_context = self.vectorizer.transform([context])

vector_doc = self.vectorizer.transform(utterances)

# The dot product measures the similarity of the resulting vectors

result = np.dot(vector_doc, vector_context.T).todense()

result = np.asarray(result).flatten()

# Sort by top results and return the indices in desce有多少爱能够重来,上海申花,奥特曼视频-酷技能,最新国际技能新闻发布,风趣有料的头条nding order

return np.argsort(result, axis=0)[::-1]

# Evaluate TFIDF predictor

pred = TFIDFPredictor()

pred.train(train_df)

y = [p杨娅姣red.p好妹妹图片redict(test_df.Context[x], test_df.iloc[x,1:].values) for x in range(len(test_df))]

for n in [1, 2, 5, 10]:

print("Recall @ ({}, 10): {:g}".format(n, evaluate_recall(y, y_test, n)))

模型成果如下:

Recall @ (1, 10): 0.495032

Recall @ (2, 10): 0.596882

Recall @ (5, 10): 0.766121

Recall @ (10, 10): 1

明显这比Random的模型要好得多,但这还不行。之前的假定并不完美,首要query和response之间并不必定要是语义上的附近;其次tfidf模型疏忽了词序这一重要的信息。运用NN模型咱们能做得更好一些。

LSTM

这篇博文将树立的NN模型为两层Encoder的囊组词LSTM模型(Dual Encoder LSTM Network),这种方法的网络被广泛应用在chatbot中(虽然或许作用并不是最佳的那个,你可小丑的眼泪经典语句以尽或许地测验其他的NN模型)。seq2seq模型常用于机器翻译范畴,并获得了较大的作用。运用Dual LSTM模型的原因在于这个模型被证明在这个数据集有较好的作用(概况见这儿),这能够作为咱们后续模型作用的验证。

两层Encod冈村宁次孙立人的点评er的LSTM模型的结构图如下(论文来历):

大致的流程如下:

(1) Query和Response都是经过分词的,分词后每个词embedded为向量方法。初始的词向量运用GloVe vectors,之后词向量跟着模型的练习会进行fine-tuned(试验发现,初始的词向量运用GloVe并没有在功能上带来明显的提高)。

(2) 分词且向量化的Query和Response经过相同的RNN(word by word)。RNN助组词终究生成一个向量表明,捕捉了Query和Response之间的[语义联络](图中的c和r);这个向量的维度是能够指定的,这儿指定为256维。

(3) 将向量c与一个矩阵M相乘,来猜测一个或许的回复r’。假如c为一个256维的向量,M维256*256的矩阵,两者相乘的成果为另一个256维的向量,咱们能够将其解释为[一个生成式的回复向量]。矩阵M是需求练习的参数。

(4) 经过点乘的方法来猜测生成的回复r’和候选的回复r之间的类似程度,点乘成果越大表明候选回有多少爱能够重来,上海申花,奥特曼视频-酷技能,最新国际技能新闻发布,风趣有料的头条复作为回复的可信度越高;之后经过sigmoid函数归一化,转成概率方法。图中把第(3)步和第(4)步结合在一极速行进土耳其浴引发争议起了。

为了练习模型,咱们还需求一个丢失函数(loss function)。这儿运用二元的穿插熵(binary cross-entropy)作为丢失函数。咱们已知实例的实在label y,值为0或1;经过上面的第(4)步能够得到一个概率值 y';因而,穿插熵丢失值为L = -y * ln(y') - (1 - y) * ln(1 - y')。这个公式的意义是直观的,即当y=1时,L = -ln(y'),咱们希望y'尽量地挨近1使得丢失函数的值越小;反之亦然。

完结进程中运用了numpy、pandas、TensorFlow和TF Learn等东西。

数据预处理

数据集的原始格局为csv格局,咱们需求先将其转为TensorFlow专有的格局,这种格局的优点在于能够直接从输入文件中load tensors,并让TensorFlow来处理洗牌(shuffling)、批量(batching)和行列化(queuing)等操作。预处理中还包括创立一个字典库,将词进行标号,TFRecord文件将直接存储这些词的标号。

每个实例包括如下几个字段:

Query:表明为一串词标号的序列,如[231, 2190, 737, 0, 912];

Query的长度;

Response:相同是一串词标号的序列;

Response的长度;

Label;

Distractor_[N]:表明负例搅扰数据,仅在验证集和测验会集有,N的取值为0-8;

Distractor_[N]的长度;

数据预处理的Python脚本见这儿,生成了3个文件:train.tfrecords, validation.tfrecords 和 test.tfrecords。你能够测验自己运转程序,或许直接下载和运用预处理后的数据。

创立输入函数

为了运用TensoFlow内置的练习和评测模块,咱们需求创立一个输入函数:这个函数回来输入数据的batch。由于练习数据和测验数据的格局不同,咱们需求创立不同的输入函数。输入函数需求回来批量(batch)的特征和标签值(假如有的话)。类似于如下:

def input_fn():

# TODO Load and preprocess data here

return batched_features, labels

由于咱们需求在模型练习和评测进程中运用不同的输入函数,为了避免重复书写代码,咱们创立一个包装器(wrapper),称号为create_input_fn,针对不同的mode运用相应的code,如下:

def create_input_fn(mode, input_files, batch_size, num_epochs=None):

def input_fn():

# TODO Load and preprocess data here

return batched_features, labels

return input_fn

完好的code见udc_inputs.py。全体上,这个函数做了如下的工作:

(1) 界说了示例文件中的feature字段;

(2) 运用tf.TFRecordReader来读取input_files中的数据;

(3) 依据feature字段的界说对数据进行解析;

(4) 提取练习数据的标签;

(5) 发生批量化的练习数据;

(6) 回来批量的特征数据及对应标签;

界说评测目标

之前现已说到用recall@k这个目标来评测模型,TensorFlow中现已完结了许多规范目标(包括recall@k)。为了运用这些目标,需求创立一个字典,key为目标称号,value为对应的核算函数。如下:

def create_evaluation_metrics():

eval_metrics = {}

for k in [1, 2, 5, 10]:

eval_metrics["recall_at_%d" % k] = functools.partial(

tf.contrib.metrics.streaming_sparse_recall_at_k,

k=k)

return eval_metrics

如上,咱们运用了functools.partial函数,这个函数的输入参数有两个。不要被streaming_sparse_recall_at_k所困惑,其间的streaming的意义是表明目标的核算是增量式的。

训主播娇喘练和测验所运用的评测方法是不相同的,练习进程中咱们对每个case或许作为正确回复的概率进行猜测,而测验进程中咱们对每组数据(包括10个case,其间1个是正确的,别的9个是生成的负例/噪音数据)中的case进行逐条概率猜测,得到例如[0.34, 0.11, 0.22, 0.45, 0.01, 0.02, 0.03, 0.08, 0.33, 0.11]这样格局的输出有多少爱能够重来,上海申花,奥特曼视频-酷技能,最新国际技能新闻发布,风趣有料的头条,这些输出值的和并不要求为1(由于是逐条猜测的,有独自的猜测概率值,在0到1之间);而关于这组数据而言,由于数据index=0对应的为正有多少爱能够重来,上海申花,奥特曼视频-酷技能,最新国际技能新闻发布,风趣有料的头条确答案,这儿recall@1为0,由于0.34是其间第二大的值,所以recall@2是1(表明这组数据中猜测概率值在前二的中有一个是正确的)。

练习程序样例

首要,给一个模型练习和测验的程序样例,这之后你能够参照程序中所用到的规范函数,来快速切换和运用其他的网络模型。假定咱们有一个函数model_fn,函数的输入参数有batched features,label和mode(train/evaluation),函数的输出为猜测值。程序样例如下:

estimator = tf.contrib.learn.Estimator(

model_fn=model_fn,

model_dir=MODEL_DIR,

config=tf.contrib.lea钱韦成rn.RunConfig())

input_fn_train = udc_inputs.create_input_fn(

mode=tf.contrib.learn.ModeKeys.TRAIN,

input_files=[TRAIN_FILE],

batch_size=hparams.batch_size)

input_fn_eval = udc_inputs.create_input_fn(

mode=tf.contrib.learn.ModeKeys.EVAL,

input_files=[VALIDATION_FILE],

batch_size=hparams.eval_batch_size,

num_epochs=1)

eval_metrics = udc_metrics.create_evaluation_metrics()

# We need to subclass theis manually for now. The next TF version will

# have support ValidationMonitors with metrics built-in.

# It's already on the master branch.

class EvaluationMonitor(tf.contrib.learn.monitors.EveryN):

def every_n_s蒲熠星刘一戈秀恩爱tep_end(self, step, outputs):

self._estimator.evaluate(

input_fn=input_fn_eval,

metrics=eval_metrics,

steps=None)

eval_monitor = EvaluationMonitor(every_n_steps=FLAGS.eval_every)

estimator.fit(input_fn=input_fn_train, steps=None, monitors=[eval_monitor])

这儿创立了一个model_fn的estimator(评价函数);两个输入函数,input_fn_train和input_fn_eval,以及核算评测目标的函数;

创立模型

到现在为止,咱们创立了模型0x8007045b有多少爱能够重来,上海申花,奥特曼视频-酷技能,最新国际技能新闻发布,风趣有料的头条的输入、解析、评测和练习的样例程序。现在咱们来写LSTM的程序,create_model_fn函数用以处理不同格局的练习和测验数据;它的输入参数为model_impl,这个函数表明实践作出猜测的模型,这儿便是用的LSTM,当然你能够替换成恣意的其他模型。程序如下:

def dual_encoder_model(

hparams,

mode,

context,

context_len,

utterance,

utterance_len,

targets):

# Initialize embedidngs randomly or with pre-trained vectors if available

embeddings_W = get_embeddings(hparams)

# Embed the context and the utterance

context_embedded = tf.nn.embedding_lookup(

embeddings_W, context, name="embed_context")

utterance_embedded = tf.nn.embedding_lookup(

embeddings_W, utterance, name="embed_utterance")

# Build the RNN

with tf.variable_scope("rnn") as vs:

# We use an LSTM Cell

cell = tf.nn.rnn_cell.LSTMCell(

hparams.rnn_dim,

forget_bias=2.0,

use_peepholes=True,

state_is_tuple=True)

# Run the utterance and context 贺卫方处理成果through the RNN

rnn_outputs, rnn_states = tf.nn.dynamic_rnn(

cell,

tf.concat(0, [context_embedded, utterance_embedded]),

sequence_length=tf.concat(0, [context_len, utterance_len]),

dtype=tf.float32)

encoding_context, encoding_utterance = tf.split有多少爱能够重来,上海申花,奥特曼视频-酷技能,最新国际技能新闻发布,风趣有料的头条(0, 2, rnn_states.h)

with tf.variable_scope("prediction") as vs:

M = tf.get_variable("M",

shape=[hparams.rnn_dim, hparams.rnn_dim],

initializer=tf.truncated_normal_initializer())

# "Predict" a response: c * M

generated_response = tf.matmul(encoding_context, M)

generated_response = tf.expand_dims(generated_response, 2)

encoding_utterance = tf.expand_dims(encoding_utterance, 2)

# Dot product between generated response and actual response

# (c * M) * r

logits = tf.batch_matmul(generated_response, encoding_utterance, True)

logits = tf.squeeze(logits, [2])

# Apply sigmoid to convert logits to probabilities

probs = tf.sigmoid(logits)

# Calculate the binary cross-entropy loss

losses = tf.nn.sigmoid_cross_entropy_with_logits(logits, tf.to_float(targets))

# Mean loss across the batch of examples

mean_loss = tf.reduce_mean(losses, name="mean_loss")

return probs, mean_loss

完好的程序见dual_encoder.py。依据这个,咱们能够实例化model函数在咱们之前界说的udc_train.py,如下:

model_fn = udc_model.create_model_fn(

hparams=hparams,

model_impl=dual_encoder_model)

这样咱们就能够直接运转udc_train.py文件,来开端模桑卓董型的练习和评测了,你能够设定--eval_every参数来操控模型在验证集上的评测频率。更多的命令行参数信息可见tf.flags和hparams,你也能够运转python udc_train.py --help来检查。

运转程序的作用如下:

INFO:tensorflow:training step 20200, loss = 0.36895 (0.330 sec/batch).

INFO:tensorflow:Step 20201: mean_loss:0 = 0.385877

INFO:tensorflow:training step 20300, loss = 0.25251 (0.338 sec/batch).

INFO:tensorflow:Step 20301: mean_loss:0 = 0.405653

...

INFO:tensorflow:Results after 270 steps (0.248 sec/batch): recall_at_1 = 0.507581018519, recall_at_2 = 0.689699074074, recall_at_5 = 0.913020833333, recall_at_10 = 1.0, loss = 0.5383

...

模型的评测

在练习完模型后,你能够将其应用在测验集上,运用:

python udc_test.py --model_dir=$MODEL_DIR_FROM_TRAINING

例如:

python udc_test.py --model_dir=~/github/chatbot-retrieval/runs/1467389151

这将得到模型在测验集上的recall@k的成果,注意在运用udc_test.py文件时,需求运用与练习时相同的参数。

在练习模型的次数大约2w次时(在GPU上大约花费1小时),模型在测验集上得到如下的成果:

recall_at_1 = 0.507581018519

recall_at_2 = 0.689699074074

recall_at_5 = 0.913020833333

其间,recall@1的值与tfidf模型的差不多,可是recall@2和recall@5的值则比tfidf模型的成果好太多。原论文中的成果依次是0.55,0.72和0.92,或许经过模型调参或许预处理能够到达这个成果。

运用模型进行猜测

关于新的数据,你能够运用udc_predict.py来进行猜测;例如:

python udc_predict.py --model_dir=./runs/1467576365/

成果如下:

Context: Example context

Response 1: 0.44806

Response 2: 0.481638

你能够从候选的回复中,挑选猜测分值最高的那个作为回复。

总结

这篇博文中,咱们完结了一个依据检索的NN模型,它能够对候选的回复进行猜测和打分,经过输出分值最高(或许满意必定阈值)的候选回复已完结谈天的进程。后续能够测验其他更好的模型,或许经过调参来获得更好的试验成果。

以上内容为原文 DEEP LEARNING FOR CHATBOTS, PART 2 – IMPLEMENTING A RETRIEVAL-BASED MODEL IN TENSORFLOW 的翻译,供自己学习及别人参阅。本文涉及到的数据和代码见Github库房地址。

本文完毕,感谢赏识。

欢迎转载,请注明本文的链接地址:

http://www.jeyzhang.com/deep-learning-for-chatbots-2.html