FAQ问答机器人

本文介绍了实现一个问答机器人的过程,主要使用ELMo和BERT作为基线模型。通过Mean Reciprocal Rank (MRR) 评估,发现ELMo的表现优于BERT。在数据集和模型优化方面,尝试了同义句构造、负例生成策略,并讨论了模型结构和损失函数的改进。实验结果显示,使用BERT的Sequence output MEAN方法在计算句子相似度时,性能有所提升,但仍不及预训练模型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0.Abstract

本文实现了一个解决用户信息获取类的问答机器人, 通过问题匹配来寻找可能的最佳答案. 评估方法使用Mean Reciprocal Rank.
项目代码github地址: https://github.com/neesetifa/FAQbot

1.任务介绍

FAQ问答机器人通常有两种(闲聊类的机器人,比如微软小冰,n年前小黄鸡这种暂不讨论)
第一种, 任务驱动型. 此类问答机器人通常用于完成一些指定任务,比如订餐,订票,订单处理等(比如Macy’s的客服电话,打过的朋友会发现拨通后都是该类型的问答机器人帮你处理一些简单的订单问题)

第二种, 解决用户信息获取类的问题. 该类型机器人通过用户提出的问题/关键字, 寻找潜在的最佳答案返回给用户. 此类型是本文实现的问答机器人.

本文的基本思路是, 根据用户提出的问题,在已有的问题库里寻找和当前问题可能最相关的问题,将该问题的答案作为当前问题的答案提供给用户.

本项目中, 首先实验两个基线模型查看效果,分别是ELMo和BERT. 然后对BERT进行各种finetune(微调)尝试提高模型效果.

数据集

项目的数据集使用ChineseNLPCorpus提供的"法律知道"
https://github.com/SophonPlus/ChineseNlpCorpus

评估方法

本项目使用的评估方法是Mean Reciprocal Rank.
它的计算方式是根据当前结果在所有结果中的排名的倒数求和做平均.
在这里插入图片描述
它的最大值是1. 即每个结果都在排名中被排在首位. 所以MRR值越大代表效果越好.

测试集

我自己造了一个数量为50条的测试数据集.
question为测试用问题(我提出的问题), title为对应匹配的问题(我认为应该匹配的问题).
在这里插入图片描述

2.使用ELMo预训练模型

尝试使用ELMo作为基线模型(base model)
(1)分词
使用ELMo模型,首先需要进行分词操作, 这里分词使用北大的分词工具pkuseg

import pkuseg
seg=pkuseg.pkuseg()
sents = ["今天天气真好啊", "潮水退了就知道谁没穿裤子"]
sents = [seg.cut(sent) for sent in sents]
print(sents)  
# [['今天', '天气', '真', '好', '啊'], ['潮水', '退', '了', '就', '知道', '谁', '没', '穿', '裤子']]

(2) ELMo环境
使用ELMo需要安装allennlp环境. 不过因为allennlp提供的ELMo只支持英文,所以…
使用中文的话,需要额外安装这个库Pre-trained ELMo Representations for Many Languages
https://github.com/HIT-SCIR/ELMoForManyLangs

然后我们就可以使用了

from elmoformanylangs import Embedder #只需要用到Embedder

这个repository里还提供了预训练好的EMLo简体中文模型,可以直接下载使用.
如何加载预训练好的模型

e=Embedder('./zhs.model')  #加载模型
# sents=[['今天', '天气', '真', '好', '啊'], ['潮水', '退', '了', '就', '知道', '谁', '没', '穿', '裤子']]
embeddings=e.sents2elmo(sents)  #将句子embedding成向量,变量类型为numpy.ndarray
print(len(embeddings))  # 2   两个句子  
print(embeddings[0].shape)  # (5,1024) 句子1里有5个词,每个词是1024维的向量

(3) 将数据集里的每个问题全部都做embedding
然后将 “问题,问题的embedding,问题的答案” 存入一个文件

这里为了节省空间,对每句话的embedding做了平均
未做平均: 文件大小约800MB, 做完平均: 约89MB
实际效果: 两者区别不大

(4) 将输入的问题做embedding,然后和所有问题的embedding作对比, 对比方式使用cosine similarity, 取出相似度最高的5条问答,打印出来. 可以看到,在5条候选答案中,较为相关的回答还是很多的.
在这里插入图片描述

(5) 评估
ELMo模型的MRR约为 0.198
在这里插入图片描述

3.使用BERT预训练模型

尝试使用BERT作为基线模型(base model)
(1) BERT的中文预训练模型使用Cui Yimin提供的<BERT-wwm-ext, Chinese>
https://github.com/ymcui/Chinese-BERT-wwm

(2)为了使用BERT对句子进行编码,这里借用并且修改了hugging face提供的代码.
https://github.com/huggingface/transformers/blob/master/examples/run_glue.py
我只使用了一个句子作为输入,即 [CLS]问题[SEP]None[SEP] 然后提取pooled_output来代表句子的向量, 使用cosine similarity作为评测分数

(3) 评估
BERT模型的MRR约为 0.183
在这里插入图片描述
BERT分数略低于ELMo

之后又测试了另一组数据,ELMo约为 0.203, BERT约为0.265.

4.针对基线模型的分析思考以及可能的提升方向

  1. 我发现构造测试数据集时, 问题的问法很有讲究,换一种问法模型可能就无法找到正确的答案. 模型在相同的句式以及较高的关键字匹配的情况下可以获得较高的分数, 而变化一种句型,比如原问题是"民事纠纷有哪些类型", 我提出的是"民事纠纷如何分类”, 模型便有可能无法匹配到正确答案.
  2. 同时我还发现, 在向模型提出毫不相关的问题时,模型给出的答案也会有非常高的分数:
    在这里插入图片描述

这样也引出了一个提升方向: 增大和正例(同义句)的分数,减小和负例(非同义句)的分数.
下面我将从这个方向对BERT模型结构进行微调(fine-tune),从而使得它能够更加准确的判断两个句子的相似度.

5.BERT训练模型

这里需要先提一下,在思考的时候,看到的一篇对我有很大启发的论文: ParaNMT-50M
这篇论文是2018年4月写的,那时BERT尚未提出.下面是我对这篇论文的概述:

该论文提出了一个数据集, 由5000万条(50 million)英语-英语句子释义对(sentential paraphrase pairs)或者说同义句子对组成. 作者生成这个数据集的方法是,将英语翻译成捷克语,再把捷克语翻译回英语.
作者希望这个成为一个比较好的释义生成资源(释义生成,paraphrase generation, 是文本生成text generation的一个子任务). 并认为这么训练可以获得更好的句子表示(sentence embedding).

原论文里作者使用了WORD AVERAGING,TRIGRAM,LSTM三种模型. 我这里使用BERT代替.

1) 损失函数

下面这个式子是原论文里用的损失函数hinge loss/margin loss, cos()是计算cosine similarity
l o s s = m a x ( 0 , δ − c o s ( g s , g s ′ ) + c o s ( g s , g t ) ) loss=max(0, \delta-cos(g_s,g_{s'})+cos(g_s,g_{t})) loss=max(0,δ<

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值