基于FAQ的智能问答(三):精排篇

背景

在上一篇<基于FAQ的智能问答(二):召回篇>中已经介绍了,给定一个用户的query如何从知识库中快速准确的召回一小批相关的问题,本篇将继续介绍如何对这一小批问题进行精排,最终构建出answer返回给用户。

任务描述

给定一个用户的问题q,和一批召回的问题d,对每个d进行相关性的打分计算,并根据相关性进行评价。同时根据top1打分的不同,客户端执行不同的操作:

  • (1) 如果top1的评分”很高”,则直接将答案返回给用户
  • (2) 如果top1的评分”较高”,则进行问题的推荐
  • (3) 如果top1的评分”较低”,则提示无法回答。

评价指标

排序模型的评价指标是NDCG(Normalized Discounted Cumulative Gain)归一化折损累计增益。具体问答的场景中,给定一个$q$,返回有序的 $top@K$ 相关问题列表 $\{ {d_{1},d_{2},..,d_{k}} \}$

Gain(G)表示$q$与检索结果$d$之间的相关性,计为$r$。在问答场景里面我们定义三种级别:

q与d的相关度描述 r
非常相关,可直接作为答案返回 2
很相关,可以作为推荐问 1
不相关 0

Cumulative Gain(CG) 表示对$top@K$个相关性的加和:$CG@K=\sum_{i=1}^{K}r(i)$

Discounted Cumulative Gain(DCG) 继续引入位置的特征,排在前面的元素增益应该更高,排在后面的元素增益应该相对较低: $DCG@K=\sum_{i=1}^{K}\frac{2^{r(i)}-1}{\log_{2}(i+1)}$

Normalized Discounted Cumulative Gain (NDCG): 若对于$q$最佳的$top@K$ 结果为$\{ {d_{1}^{‘},d_{2}^{‘},..,d_{k}^{‘}} \}$, 记q与最佳序列的DCG为IDCG, 即:$IDCG=DCG_{max}@K$ , 那么$NDCG=\frac{DCG@K}{IDCG@K}$。

模型结构

模型结构

模型结构如上图所示,是一个基础的ALBERT + MLP的交互式模型结构,重点是loss的构建。这里采用了list wise中的lambda rank的loss:

$L=\sum_{r(i)>r(j)}|\Delta NDCG|\log_{2}(1+e^{-\sigma*(s_{i}-s_{j})})$

在智能问答的场景中,$r(i) > r(j) \Rightarrow i < j$, 也就是i应该在j的前面.

其中$|\Delta NDCG|$表示交换位置i,j前后NGCD的差值, 表明排错的代价程度,后一项$\log_{2}(1+e^{1-\sigma*(s_{i}-s_{j})})$促使模型排在前面的评分$s_{i}$大于排在后面的评分$s_{j}$。

所以该loss设计可以使得模型有效区分开 正样本(r=2),推荐样本(r=1),不相关的样本(r=0).

数据集构建

对于智能问答场景的精排模型,构建的数据集结构如下:

$$\{q,d_{1-1},d_{1-2},..,d_{1-5},d_{2-1},d_{2-2},..,d_{2-10},d_{3-1},d_{3-2},..,d_{3-5}\}$$

其中q表示输入的query,$d_{1-x}$表示正样本可以作为答案返回的结果,即r=2;$d_{2-x}$表示可作为相似问推荐的样本,即r=1;$d_{3-x}$表示不相关的样本,即r=0。

具体数据集的构建依然与召回篇中介绍的思路类似。给定一个query,在百度知道中进行检索,我们从p1-3的结果中随机选择5个结果作为$d_{1-x}$,从p28-30页中随机选择10个结果作为$d_{2-x}$,从其他query检索的结果中随机选择5个作为$d_{3-x}$.

数据集示例

所以通过这种方法,可以构建一个大规模的通用领域的弱标签的排序数据集,从而训练出一个通用的排序模型。

模型上线

在模型的预测阶段,给定q与d,可直接计算出q与d的相似度。所以给定一组d,就可根据相似度返回有序的结果。

整个精排模块在进行模型蒸馏以后,部署在k8s的cpu集群上(web API + Tensenflow-Serving),单个pod在batch size=20,max_*seq_*len = 64的场景下,响应时间为100ms. 满足线上的需求。

玄学阈值:在精排部分我们需要界定出top1的结果是否为正样本,即能不能直接作为答案返给用户;同时top1 - top5中哪些可以作为推荐问进行推荐;最后top1的结果什么情况下可以明确判定无法回答。

最简单的方案是卡一个阈值,例如相似度大于0.85,就认为是正样本,可以直接把知识库中的答案返回给用户;相似度小于0.85但是大于0.1,就认为可以作为推荐问;最后如果top1的相似度小于0.1,就认为无法解答。具体的阈值可以在测试集上进行搜索,保障在测试集上的准确率能够达到95%,同时召回率能够达到80%。(95%与80%来源于业务的指标要求)

但是这种方案需要小心翼翼,在实际的场景往往很难很好的去卡这个阈值。所以我们也还在思考如何优雅的进行这三种情况的区分,计算出清晰的边界,也欢迎大家来一起交流🤔

不过从产品实际上来考虑,真的要对边界抱有执念吗?对于原本应该直接回答的query,没有直接回答,而是把非常相关的top1结果进行了推荐,其实也没问题,不会牺牲特别大的用户体验;同时对于原本就没有答案的样本,没有不回答去转人工,而也将top1的结果进行推荐(因为有一点的相关性),也不会牺牲用户体验,反而也在引导用户。所以“尽可能的多推荐”