Embedding-based Retrieval in Facebook Search

facebook的社交网络检索与传统的搜索检索的差异是,除了考虑文本,还要考虑搜索者的背景。通用搜索主要考虑的是文本匹配,并没有涉及到个性化。像淘宝,youtube这些其实都是涉及到了用户自身行为的,除了搜索还有推荐,搜推一体。为了个性化搜索,facebook构建了一套统一框架以及基于倒排索引

1. 介绍

搜索引擎帮助用户在海量的信息中进行检索,google和bing开发了各种技术来提高搜索质量。由于语义和意图非常难以表征,因此当前的搜索大多依赖于term匹配方法,也就是关键字匹配。

语义匹配:解决关键词不能完全匹配但是可以满足用户搜索意图所需要的结果

深度学习在语音,机器视觉和自然语言理解中取得了重大的进展。embedding即表征被证明是一种有效的方法。本质上来说embedding是一种将ids的稀疏向量表征为密集向量的方法,也被称为语义嵌入。一旦embedding建立好,就可以作为query和doc的表示,从而可以应用到搜索引擎的各个阶段。

一般来说,搜索引擎分为召回和排序。embedding在这两部分都可以使用,但是通常应用在召回层,因为位于系统的底部,而且也是瓶颈所在。基于embedding的检索通常称为EMR,基于embedding来表征query和doc,然后将检索问题转换为嵌入空间最邻的搜索问题。

召回:以低延时和低计算成本来检索一组相关的文档,称为recall
排序:以更复杂的算法和模型在顶部对最想要的文档进行排名,称为rank

EBR在搜索引擎中的最大挑战就是数据量巨大的问题,召回层需要处理数十亿或者万亿的文档。而且搜索引擎通常需要将基于embedding和term匹配的检索结合在一起,在检索层对文档进行评分。

为了解决这个问题,facebook提出了统一嵌入,这是一个双塔模型,其中一边是搜索请求,包括query,encoder和context,另一边则是doc。训练数据是从搜索日志中挖掘的,并从encode,query和context提取特征。

将embedding和term匹配的方法合并在一起非常简单,但是发现是次优的,

2. 模型

给定一个query,它的目标结果是 T = { t 1 , t 2 , . . . t N } T=\{t_1,t_2,...t_N\} T={t1,t2,...tN},模型返回的TopK个结果是 D = { d 1 , d 2 , . . . d K } D=\{d_1,d_2,...d_K\} D={d1,d2,...dK},模型想要最大化
r e c a l l @ K = ∑ i = 1 K d i ∈ T N recall@K=\frac{\sum_{i=1}^{K}d_i \in T}{N} recall@K=Ni=1KdiT

目标结果 T T T是基于某些条件与query相关的doc,例如用户点击的结果,或者是基于人类评级的文档。将召回优化的问题定义为基于query和doc之间计算距离的排名问题。query和doc都通过编码器转换为向量,使用余弦值作为距离度量,损失函数使用triple loss。
对于facebook来说,检索不仅需要考虑文本的内容,而且还需要考虑搜索者的信息以及搜索的上下文,以此来满足用户的个性化。以搜人为例,虽然Facebook有数千个名为小王的用户,但是用户的搜索目标通常是他们的熟人。

2.1 评价指标

线上AB测试,离线是平均recall@K

query目标文档个数召回结果中有几个在目标文档中
q 1 q_1 q1 n 1 n_1 n1 m 1 m_1 m1
q 2 q_2 q2 n 2 n_2 n2 m 2 m_2 m2
q k q_k qk n k n_k nk m k m_k mk

r e c a l l @ K = m 1 + m 2 + . . . + m k n 1 + n 2 + . . . + n k recall@K=\frac{m_1+m_2+...+m_k}{n_1+n_2+...+n_k} recall@K=n1+n2+...+nkm1+m2+...+mk

2.2 损失函数

给定一个三元组 ( q i , d + i , d − i ) (q^i,d^i_+,d^i_-) (qi,d+i,di),其中 q i q^i qi是query, d + i d^i_+ d+i d − i d^i_- di分别是正样本和负样本。loss定义为
L = ∑ i = 1 N max ( 0 , D ( q i , d + i ) − D ( q i , d − i ) + m ) L=\sum_{i=1}^{N}\text{max}(0,D(q^i,d^i_+)-D(q^i,d^i_-)+m) L=i=1Nmax(0,D(qi,d+i)D(qi,di)+m)

其中 D ( u , v ) D(u,v) D(u,v)两个向量的距离度量,距离越近说明向量越接近也就是越匹配。我们的期望是 q i q^i qi与正样本 d + i d^i_+ d+i距离越小越好,与负样本 d − i d^i_- di的距离越大越好,也就是说两个距离之间的差值越大越好。用下面这个表来说明,假设m是5

query正样本负样本距离loss
q q q d + 1 = 100 d^1_+=100 d+1=100 d − 1 = 90 d^1_-=90 d1=9010 m a x ( 0 , 10 + 5 ) = 15 max(0,10+5)=15 max(0,10+5)=15
q q q d + 1 = 8 d^1_+=8 d+1=8 d − 1 = 1 d^1_-=1 d1=12 m a x ( 0 , 2 + 5 ) = 7 max(0,2+5)=7 max(0,2+5)=7
q q q d + 1 = 9.9 d^1_+=9.9 d+1=9.9 d − 1 = 9.9 d^1_-=9.9 d1=9.90 m a x ( 0 , 0 + 5 ) = 5 max(0,0+5)=5 max(0,0+5)=5
q q q d + 1 = 80 d^1_+=80 d+1=80 d − 1 = 77 d^1_-=77 d1=77-3 m a x ( 0 , − 3 + 5 ) = 2 max(0,-3+5)=2 max(0,3+5)=2
q q q d + 1 = 10 d^1_+=10 d+1=10 d − 1 = 13.5 d^1_-=13.5 d1=13.5-3.5 m a x ( 0 , − 3.5 + 5 ) = 1.5 max(0,-3.5+5)=1.5 max(0,3.5+5)=1.5
q q q d + 1 = 0.8 d^1_+=0.8 d+1=0.8 d − 1 = 2 d^1_-=2 d1=2-1.2 m a x ( 0 , − 1.2 + 5 ) = 3.8 max(0,-1.2+5)=3.8 max(0,1.2+5)=3.8
q q q d + 1 = 8 d^1_+=8 d+1=8 d − 1 = 11 d^1_-=11 d1=11-3 m a x ( 0 , − 3 + 5 ) = 2 max(0,-3+5)=2 max(0,3+5)=2
q q q d + 1 = 4.9 d^1_+=4.9 d+1=4.9 d − 1 = 10 d^1_-=10 d1=10-5.1 m a x ( 0 , − 5.1 + 5 ) = 0 max(0,-5.1+5)=0 max(0,5.1+5)=0
q q q d + 1 = 0 d^1_+=0 d+1=0 d − 1 = 5 d^1_-=5 d1=5-5 m a x ( 0 , − 5 + 5 ) = 0 max(0,-5+5)=0 max(0,5+5)=0
q q q d + 1 = 9 d^1_+=9 d+1=9 d − 1 = 19 d^1_-=19 d1=19-10 m a x ( 0 , − 10 + 5 ) = 0 max(0,-10+5)=0 max(0,10+5)=0
q q q d + 1 = 1 d^1_+=1 d+1=1 d − 1 = 101 d^1_-=101 d1=101-100 m a x ( 0 , − 100 + 5 ) = 0 max(0,-100+5)=0 max(0,100+5)=0

从上面这个表格可以看出,如果loss为正,说明query与正样本的距离比负样本的距离大,这肯定不好,当距离为负数,说明负样本的距离更大。还做了一个margin,

当负样本的距离远大于正样本的距离的时候,其实其实已经不用过度惩罚了,可以认为loss为0了。
当负样本的距离小于正样本的距离,这个时候我们需要对模型进行惩罚,即loss大于0

我仔细想了一下,其实很简单,如果正样本的距离大于负样本的距离,那么越大惩罚的力度就越大,反之,如果小于负样本的距离是不是就不惩罚了呢?不是的,不仅要小于负样本的距离,而且要足够小,因此设置了一个margin,但是小太多的话其实就不管了,因此已经超过预期了。

目标:不仅要小,而且要足够小,如果足够小,那么就不用再小

调整margin的值是非常重要的,不同的margin值会导致召回率有5%-10%的方差变化。通过对负样本进行随机采样,triplet loss可以近似为recall@K。对于每一个正样本,如果随机采 n n n个负样本,模型优化的目标就是从 n n n个样本中找出那 1 1 1个正样本,假设实际上的候选集为 N N N,近似优化召回 r e c a l l @ K recall@K recall@K

2.3 统一嵌入模型

模型由三部分组成

  • query编码器 E Q = f ( Q ) E_Q=f(Q) EQ=f(Q),将查询query转变成向量embedding
  • doc编码器 E D = g ( D ) E_D=g(D) ED=g(D),将文档doc转变成doc的向量embedding
  • 距离度量函数 S ( E Q , D D ) S(E_Q,D_D) S(EQ,DD),查询query和文档doc之间的分数

编码器是一个神经网络,将稀疏输入 i d s ids ids输入转换成密集向量embedding, f ( ⋅ ) f(\cdot) f() g ( ⋅ ) g(\cdot) g()是两个编码器,形式上是两个分立的编码器,实际上参数相同。距离度量函数使用cosin
S ( Q , D ) = c o s ( E Q , E D ) = < E Q , E D > ∣ ∣ E Q ∣ ∣ ⋅ ∣ ∣ E D ∣ ∣ S(Q,D)=cos(E_Q,E_D)=\frac{<E_Q,E_D>}{||E_Q||\cdot ||E_D||} S(Q,D)=cos(EQ,ED)=∣∣EQ∣∣∣∣ED∣∣<EQ,ED>

Q和Q的cos值越大说明两个向量越接近,也就是距离越小,反之值越小距离越大,因此距离的定义为 dist = 1 − c o s ( E Q , E D ) \text{dist}=1-cos(E_Q,E_D) dist=1cos(EQ,ED)

传统的搜索输入只要文本信息,而这里的输入包含其他的信息,例如用户的位置,社交网络等,文档侧也是

双塔模型的一端是离线计算好的,文档侧所有的输入信息都应是静态的,不会随着query输入的变化而变化。
用户也会有静态特征,通常是一些统计数据,例如用户在某个类目(话题)下的点击率,这样的特征不仅会随着用户变化,而且也会随着文档变化。这样的特征有两种用法,

  1. 在召回侧,用户在各个类目下的点击率统一作为向量输入到编码器中,表针的是这个用户的基础信息,通过神经网络对这些特征做非线性映射

我们可以统计历史1个月内用户在不同类目下的点击率(ctr,tfidf,freq均可)

user类目1类目2类目3类目4类目5
u1 p 11 p_{11} p11 p 12 p_{12} p12 p 13 p_{13} p13 p 14 p_{14} p14 p 15 p_{15} p15
u2 p 21 p_{21} p21 p 22 p_{22} p22 p 23 p_{23} p23 p 24 p_{24} p24 p 25 p_{25} p25
u3 p 31 p_{31} p31 p 32 p_{32} p32 p 33 p_{33} p33 p 34 p_{34} p34 p 35 p_{35} p35

在召回层,我们的输入可以变更为 [ e 1 , e 2 , . . . e n , p i 1 , p i 2 , p i 3 , p i 4 , p i 5 ] [e_1,e_2,...e_n,p_{i1},p_{i2},p_{i3},p_{i4},p_{i5}] [e1,e2,...en,pi1,pi2,pi3,pi4,pi5],将所有的信息拼接在一起作为输入即可。

  1. 在排序侧,文档已经召回了,根据文档类型和用户信息,从属性库中可以获取用户在这个文档类型下的点击率,作为一个特征输入

而到了排序侧,doc都已召回了,针对<user,doc>进行打分,因此特征变为(只是举个例子)

pairdoc的类型用户embedding特征文档embedding特征用户在这个doc类型下的点击率特征
< u 1 , d 1 > <u_1,d_1> <u1,d1>类目1 e u 1 \bold{e}_{u1} eu1 e d 1 \bold{e}_{d1} ed1 p 11 p_{11} p11 [ e u 1 , e d 1 , p 11 ] [\bold{e}_{u1},\bold{e}_{d1},p_{11}] [eu1,ed1,p11]
< u 1 , d 2 > <u_1,d_2> <u1,d2>类目2 e u 1 \bold{e}_{u1} eu1 e d 2 \bold{e}_{d2} ed2 p 12 p_{12} p12 [ e u 1 , e d 2 , p 12 ] [\bold{e}_{u1},\bold{e}_{d2},p_{12}] [eu1,ed2,p12]
< u 2 , d 3 > <u_2,d_3> <u2,d3>类目3 e u 2 \bold{e}_{u2} eu2 e d 3 \bold{e}_{d3} ed3 p 23 p_{23} p23 [ e u 2 , e d 3 , p 23 ] [\bold{e}_{u2},\bold{e}_{d3},p_{23}] [eu2,ed3,p23]

2.4 数据挖掘

正样本使用点击的doc
负样本有两种方式

  1. 随机采样:对每个query,都从doc池中随机抽取一些doc作为负样本
  2. 曝光未点击:在同一个session中,随机抽取一些曝光未点击作为负样本

使用曝光未点击作为负样本效果明显更差,这是因为曝光的负样本通常由于一个或多个因素匹配查询的结果(也就是跟query强相关),但是索引中的大多数文档于query并不怎么相关,如果负样本都选择这种曝光未点击的难样本,相当于改变真实数据的分布,这会导致embedding学偏

3 特征引擎

统一嵌入模型的优点是可以融合文本以外的各种特征

  • 文本特征 字符n-gram是一种常见的方法来表征文本的向量,与单词n-gram相比他的优势有两个。1)词汇数量是有限的,而且embedding lookup会更小,训起来会更快。2)subword对oov会有更强的鲁棒性,query侧的拼写错误也可以识别。相当于term匹配,embedding召回有两个优点
    • 模糊匹配。召回类似的词,例如kind可以召回kinds等
    • 词汇扩增。搜索mini,可能会召回mini cooper等
  • 位置特征 位置匹配在本地搜索等业务中是非常有效额。为了让模型在生成向量的时候考虑位置信息,将位置信息添加到了query和doc两端。对于query侧,提取了城市,地区,国家和语言等,对于doc端,添加了公开可用的信息。
  • 社交网络特征 facebook有丰富的社交网络,因此单独训练了一个graph模型,将graph embedding作为特征输入到模型中

这种感觉非常的奇怪,把个性化的单塔模型做成双塔模型,我很难想想特征是如何确立的,这样不是会导致双塔的两个模型参数不一致吗

4 服务

4.1 ANN

量化有两个部分组成,一个是粗力度的量化,通过K-means将embedding量化到粗簇中(IVF),另一个是乘积量化(PQ),进行细粒度的量化。

  • 粗量化:IMI和IVF是有效的,调整num_cluster的数量是重要的,对召回结果有影响
  • PQ量化:PQ,OPQ(向量通过PCA转换再进行PQ)pq_bytes是需要调整的重要参数
  • nprobe:nprobe决定扫描多少个簇,直接影响召回的性能和精度

这几个参数调整的策略

  • 由于簇是不平衡的,例如分成了10个簇,可能80%的文档都集中再一个簇中,当簇不平衡的时候IMI算法大约一半的簇都只有几个样本。因此对于相同的num_clusternprobe来说,得到的文档都是不同的。
  • 应用量化之前对数据进行转换通常很有用,他们尝试了PCA和OPQ来转换数据,观察到OPQ效果更好。
  • 选择pq_bytes d / 4 d/4 d/4。PQ量化将向量最终压缩成x个字节,对于x的选择通常与维度d有关。较大的x会有更高的精度,但代价是增加内存和延迟。从经验看, x > d / 4 x>d/4 x>d/4之后精度提升是有限的

4.3 query和index选择

怎么来判断一个query是否需要启动emb查询呢?

5. 后期优化

facebook的搜索排名系统非常的复杂,每一层都是基于前一层进行的优化,之前的召回层是基于布尔规则的,所以排序模型也是基于布尔规则的召回doc来设计的,,如果直接将ebr召回的doc让当前的排序模型打分,会导致emb召回的结果被排在后面,有两种解决思路

本质就是老汤模型

  • embedding作为排序特征。将相似性分作为排序模型的一个特征,不仅有助于精排识别基于ebr的doc,而且还未所有结果提供了语义相似性的度量,探索了余弦相似性,Hadmard乘积和原始embedding向量,实验角度来看余弦相似性比其他的要好。

    • 本质就是做了特征补齐,原来布尔规则召回的doc也会反查向量,然后与query计算相似分,而ebr召回的doc也会去反查布关键字匹配构建的特征,例如tfidf,bm25等
    • embedding作为特征的意思是可以直接把embedding作为特征,也可以基于embedding构建一些其他特征作为精排的输入,脑子活络一点,看清问题的本质
  • 训练数据反馈。基于embedding的方式可以提高检索召回,但是与关键词召回相比精度较低,为了解决精度问题,建立了一个基于人类评级的pipeline。将基于embedding召回的记过发给人工去打分,以此来标记是否相关。然后使用人工打分的数据重新训练模型。

    • 老实讲,看着很像是ANCE的方式在做训练

6. 高级话题???

6.1 难样本挖掘

6.1.1 Hard negative mining(HNM). 分析人物搜索的EBR模型的时候发现,给定query,返回的前K个结果通常具有相同的名称,但是模型不会把正确结果排到其他结果之前,即使存在社交特征,模型也不会把这样的doc排到其他的doc之前。这说明模型并没有学会如何正确的利用社交特征,很有可能是因为负样本训练的太容易了,因为负样本很多都是随机采样的,通常与目标doc的名称不同。为了让模型更好的区分相似的结果,可以在embeding空间使用更接近正例的样本作为训练中的难负样本。

负样本是随机采样的,因此模型可以很容易区分出当前的正负,但是无法进行更细粒度的区分。例如模型不仅要可以区分出用户喜欢手机还衣服,还要区分出喜欢的是哪一款手机。

为什么即使拥有更多的特征,正确的结果依然不会被排在最前面,这些特征为什么没有被利用起来。这个分析的思路很好,但是怎么想到是因为负样本的原因的?

Online hard negative mining. 模型训练是基于mini-batch数据的,每个mini-batch的输入是n个正样本对 { q i , d + i } i = 1 n \{q^i,d^i_+\}_{i=1}^n {qi,d+i}i=1n,将mini-batch中其他的pair对中的doc作为负样本随机采样,优先选择相似度最高的负样本作为难负样本,而且最好不要超过两个。因为负样本就是从全量的doc中随机抽取的。

positive pairqueryd+d-d-d-d-
<q1,d1>q1d1d2d3d4d5
<q2,d2>q2d2d1d3d4d5
<q3,d3>q3d3d1d2d4d5
<q4,d4>q4d4d1d2d3d5
<q5,d5>q5d5d1d2d3d4

或者是

positive pairqueryd1d2d3d4d5
<q1,d1>q1+----
<q2,d2>q2-+---
<q3,d3>q3--+--
<q4,d4>q4---+-
<q5,d5>q5----+

此时每个query有一个正样本,有 n − 1 n-1 n1个负样本。我们在使用torch的dataloader的时候,可以在collect_fn将mini-batch的转换成我们想要的格式

使用mini-batch中的与正样本分数最接近的doc作为hard negative。使用triplet loss后,难负样本和非难负样本的差异是什么呢?从损失函数里面好像没有表现出来呀。

其实有个疑惑,mini-batch中的数据都是曝光且点击过的doc,因为都是正样本。但是哪些曝光始终未点击的doc怎么办呢?我有两点考虑,1)这些曝光但始终没有点击的doc或许就是垃圾,也可以认为是噪音,去掉反而会更好,毕竟优质库是哪些曝光且历史有过点击的doc,2)要看数据分布,如果doc池中大部分都是曝光未点击的,那么mini-batch肯定是不好的,因为与实际的分布不一致,但这个时候其实要考虑的就是为什么这么多doc曝光未点击,是不是因为资源池有问题。所以我觉得mini-batch其实是合理的。

Offline hard negative mining 在线的mini-batch负样本毕竟有限,不一定能很好的选出难负样本,而离线则可以从全量的库中进行采样。做法就是通过knn的方式筛选出top-k个负样本,而且只需要从一个簇中抽取即可,因为训练的过程中使用的其实就是semi-hard negative。

比较离线HNM和在线HNM,一个看起来违反直觉的发现是单纯使用难负样本会导致模型变差,分析之后发现单纯使用难负样本会导致模型在文本匹配上效果更差,通过调整抽样策略,最终得出了一个可以优于在线HNM模型的模型。

  • 使用最难区分的负样本训练并不是最优的,通过比较了来自不同排名位置的样本发现,排名101-500之间的样本实现了最佳的模型召回

    负样本是按照什么来排序的?如果按照跟query的相似分或者正样本的相似分来计算,这个打分模型又是哪里来的?人工打分还是BM25这种无监督模型。而且一个query到底抽取了多少个负样本

    0-100的样本只是用户未点击,但是可能只是这一次没有点击而已,并不一定就是负样本,有可能还是正样本,而位置靠后的更有可能是负样本。

  • 训练数据中包含简单的负样本是必须的,因为真实的数据就是会包含大量的easy样本

    召回模型是从全量的数据中找到与query最接近的doc,相关的doc必然是稀疏的,大部分都是比较好区分的doc,训练数据集的分布肯定是要跟实际分布一致的。在排序阶段,所有的数据都是跟query极度相关的了,数据分布于召回的数据分布肯定不一致了。

下面是两种抽样策略

  1. 使用难易样本混合训练,难易样本的比例为1:100
  2. 从“难”模型到“易”模型的迁移学习:从易到难模型的迁移不会使模型更好,但从难到易的迁移学习可以进一步增加模型的记忆能力

6.1.2 Hard positive mining 直接使用点击的样本作为正样本,这样会导致训练数据很少,所以从日志中挖掘出一些潜在转化的样本也作为正样本。例如可以有些浏览时长较长但未点击的样本

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值