搜索系统中的文本相关性实践经验

前言

文本相关性问题就是判断两个文本之间的相关程度,也是搜广推中的重点问题之一。本篇文章主要粗略总结这方面的一些实践经验,包括特征、模型以及部署上需要注意的问题,都是本人在工作中积累的实际经验,非综述类文章,只总结用过的。

总体包括特征和模型两个方面,特征一般指类似 BM25、tf-idf 之类的统计特征,模型则是指各类双塔、交互深度学习模型。
——————————————————————————————————————————————

统计类特征

TF-IDF

TF

词频(TF),即一个term在一个文档中出现的次数,一般来说,在某个文档中反复出现的term,往往能够表征文档的主题信息,即TF值越大,越能代表文档所反映的内容。

TF的计算方式如下:

  • 直接计算: W T F = T F W_{TF} = TF WTF=TF
  • 计算后取对数: W T F = 1 + l o g ( T F ) W_{TF} = 1+log(TF) WTF=1+log(TF)。取对数是为了抑制直接计算 TF 可能导致的 gap 很大的情况。数字 1 是为了平滑处理。
  • 规范化 TF: W T F = a + ( 1 − a ) × T F max ⁡ ( T F ) W_{T F}=a+(1-a) \times \frac{T F}{\max (T F)} WTF=a+(1a)×max(TF)TF 为了减弱文章长度的影响,采用归一化的方式对 TF 进行处理。

IDF

IDF代表的是文档集合范围内term的相对重要性,公式如下:
I D F k = log ⁡ N n k I D F_{k}=\log \frac{N}{n_{k}} IDFk=lognkN 其中的 N N N 代表文档集合中总共有多少个文档,而 n k n_k nk 代表特征 t e r m k term k termk 在其中多少个文档中出现过,即文档频率。IDF 就是衡量不同 term 对文档的区分能力的,其值越高,则其区分不同文档差异的能力越强,反之则区分能力越弱。

考虑到一些特殊情况可能导致分母为 0 等问题,一般会对 IDF 进行平滑处理,平滑的方式有很多,一种最常见的平滑后的 IDF 公式为:
IDF ⁡ ( x ) = log ⁡ N + 1 N ( x ) + 1 + 1 \operatorname{IDF}(x)=\log \frac{N+1}{N(x)+1}+1 IDF(x)=logN(x)+1N+1+1

实践注意事项

这两个特征是最基础也是最常用的,一般来说以维护一个词表的形式来应用,线上服务通过将词表加载成 key-value 的形式来直接获取词的 tf 和 idf

BM25 及其变种

BM25

BM25 是一种常见用来做相关度打分的公式,思路比较简单,就是计算一个 query 里面所有 term 和文档的相关度,然后在把分数做加权求和, 而每个词的相关度分数受到 tf/idf 的影响。公式如下:
score ⁡ ( Q , d ) = ∑ t ∈ Q W t R ( t , d ) \operatorname{score}(Q, d)=\sum_{t \in Q} W_{t} R(t, d) score(Q,d)=tQWtR(t,d)其中: R ( t , d ) R(t,d) R(t,d) 是每个词和文档的相关度值; t t t 代表 query 中的 term; d d d 代表相关的文档; W t W_t Wt 是词 t t t 的权重,可由外部设置,默认是 IDF 值。

下面是 R ( t , d ) R(t,d) R(t,d) 的公式:
R ( t , d ) = t f ( t ) ( k 1 + 1 ) t f ( t ) + K ( d ) q f ( t ) ( k 2 + 1 ) q f ( t ) + k 2 R(t, d)=\frac{t f(t)\left(k_{1}+1\right)}{t f(t)+K(d)} \frac{q f(t)\left(k_{2}+1\right)}{q f(t)+k_{2}} R(t,d)=tf(t)+K(d)tf(t)(k1+1)qf(t)+k2qf(t)(k2+1) K ( d ) = k 1 ( 1 − b + b d l a v g d l ) K(d)=k_{1}\left(1-b+b \frac{d l}{a v g d l}\right) K(d)=k1(1b+bavgdldl)其中: k 1 k1 k1 k 2 k2 k2 b b b 都是调节因子,一般 k 1 = 2 k1=2 k1=2 k 2 = 1 k2=1 k2=1 b = 0.75 b=0.75 b=0.75 t f ( t ) tf(t) tf(t) 是词 t 在文档中的次数, q f ( t ) qf(t) qf(t) 代表词在查询句里的次数; d l dl dl 是文档长度, a v g d l avgdl avgdl 是文档平均长度;

乘积的左边因数代表词在文档中的次数关系,乘积的右边因数代表词在查询语句中的次数关系。绝大多数情况下,查询词在查询语句里面出现一次,所以 q f ( t ) qf(t) qf(t) 可以看成是 1,又因为 k 2 k2 k2 为 1,所以右边因数其实就等于 1。最终公式可化简为下面这样:
score ⁡ ( Q , d ) = ∑ t ∈ Q IDF ⁡ ( t ) t f ( t ) ( k 1 + 1 ) t f ( t ) + k 1 ( 1 − b + b d l  avgdl  ) \operatorname{score}(Q, d)=\sum_{t \in Q} \operatorname{IDF}(t) \frac{t f(t)\left(k_{1}+1\right)}{t f(t)+k_{1}\left(1-b+b \frac{d l}{\text { avgdl }}\right)} score(Q,d)=tQIDF(t)tf(t)+k1(1b+b avgdl dl)tf(t)(k1+1)
从最终公式中可以看出:

  • IDF 越高分数越高
  • TF 越高分数越高
  • 文档长度越长分数越低,其实是衡量了 term 在 doc 中的占比

BM25F

一般情况下,一篇文章是分为多个部分的,如 title,content,description,anchor 等,在 BM25F 算分公式中,这些部分被称为域(Field)。对于两篇,一篇文章的 title 部分与 query 的 BM25 相关性得分为 a, 另一篇文章 content 部分与 query 的 BM25 相关性得分也为 a。假设不考虑这两篇文章其他部分与 query 的相关性情况,根据经验,一般第一篇文章应该应该比第一篇文章更相关, 因为一般 title 是比 content 更重要的。BM25F 引入了文章的每个域的信息,它将每个 term 在文章中的每个域中的相关性进行了处理。公式如下:
score ⁡ ( Q , d ) = ∑ t ∈ Q IDF ⁡ ( t ) w ( t , d ) k 1 + w ( t , d ) \operatorname{score}(Q, d)=\sum_{t \in Q} \operatorname{IDF}(t) \frac{w(t, d)}{k_{1}+w(t, d)} score(Q,d)=tQIDF(t)k1+w(t,d)w(t,d) w ( t , d ) = ∑ f ∈ d t f ( t , f , d ) ×  boost  f 1 − b f + b f len ⁡ ( f , d )  avglen(f)  w(t, d)=\sum_{f \in d} \frac{t f(t, f, d) \times \text { boost }_{f}}{1-b_{f}+b_{f} \frac{\operatorname{len}(f, d)}{\text { avglen(f) }}} w(t,d)=fd1bf+bf avglen(f) len(f,d)tf(t,f,d)× boost f

BM25 其他变种

大部分变种原理上差不多,细微处改变,这里不赘述,贴一些论文链接

【1】OkaTP:Y. Rasolofo and J. Savoy. Term Proximity Scoring for Keyword-Based Retrieval Systems. In Proceedings of the 25th European Conference on IR Research (ECIR 2003) pages 207–218, April 2003
【2】BM25TP: S. B uttcher, C. L. A. Clarke, and B. Lushman. Term proximity scoring for ad-hoc retrieval on very large text collections. In Proc. SIGIR, pages 621- 622, 2006.
【3】newTP:Song R , Taylor M J , Wen J R , et al. Viewing Term Proximity from a Different Perspective[C]// European Conference on Information Retrieval. Springer, Berlin, Heidelberg, 2008.

实践注意事项

BM25 类的特征一般在 rank 部分使用,注意事项就是在前期要把分词信息带过来,到用的时候即时分词服务的耗时肯定起飞。
再一个是相比直接把分词信息的文本信息裸的带过来,设计一些数据结构把分词信息的词频等提前计算好带过来会更好,这些都可以在前期服务中找地方异步完成。

cqr\ctr

即 cover query ratio 和 cover title ratio,两个覆盖率特征,设 Q 代表 query,T 代表 title,cqr 和 ctr 的计算公式如下:
s i m c q r = ∣ Q ∩ T ∣ ∣ Q ∣ sim_{cqr} = \frac{|Q \cap T|}{|Q|} simcqr=QQT s i m c t r = ∣ Q ∩ T ∣ ∣ T ∣ sim_{ctr} = \frac{|Q \cap T|}{|T|} simctr=TQT

实践注意事项

线上直接计算即可

点击二部图

SimRank 是一种基于图的推荐算法。思想与协同过滤算法相似:

  • 如果两个用户相似,则与这两个用户相关联的物品也类似;
  • 如果两个物品类似,则与这两个物品相关联的用户也类似。

将点击日志构成二部图,通过二部图进行向量传播,收敛之后,query 和 doc (类比 item)将在同一空间上生成词向量,如此一来,就可以通过相似度的计算方式得到文本相关性。对于未曾有过点击行为的 query 和 doc,也可以进行该空间词向量的估计。

假设语料库长度为 V V V ,则 Query 构成的矩阵为: ∣ Q u e r y ∣ ∗ V |Query|*V QueryV,Doc 构成的矩阵为 ∣ D o c ∣ ∗ V |Doc|*V DocV ,我们的目标是计算这两个矩阵。这里的语料指的就是Query 和 Doc 共处的向量空间,即由 Query 分词后的 term,或者 Doc 中的title/content 分词后的 term 集合构建。

若从 Query 侧开始迭代,将 Query 向量初始化为 Q i 0 Q^0_i Qi0,0 表示第一次迭代,迭代公式如下:
D j ( n ) = 1 ∥ ∑ i = 1 ∣ Query  ∣ C i , j ⋅ Q i ( n − 1 ) ∥ 2 ∑ i = 1 ∣ Query  ∣ C i , j ⋅ Q i ( n − 1 ) D_{j}^{(n)}=\frac{1}{\left\|\sum_{i=1}^{\mid \text {Query } \mid} C_{i, j} \cdot Q_{i}^{(n-1)}\right\|_{2}} \sum_{i=1}^{\mid \text {Query } \mid} C_{i, j} \cdot Q_{i}^{(n-1)} Dj(n)= i=1Query Ci,jQi(n1) 21i=1Query Ci,jQi(n1) Q i ( n ) = 1 ∥ ∑ j ∣ D o c ∣ C i , j ⋅ D j ( n ) ∥ 2 ∑ j = 1 ∣ D o c ∣ C i , j ⋅ D i ( n ) Q_{i}^{(n)}=\frac{1}{\left\|\sum_{j}^{|\mathcal{D} o c|} C_{i, j} \cdot D_{j}^{(n)}\right\|_{2}} \sum_{j=1}^{|\mathcal{D o c}|} C_{i, j} \cdot D_{i}^{(n)} Qi(n)= jDocCi,jDj(n) 21j=1DocCi,jDi(n)若从 Doc 侧开始迭代也是类似的。

实践注意事项

这类特征在 bert 这种大型预训练模型出现后意义不大了,但是由于历史原因还是存在于一些搜索系统中。

tips:

  1. 点击量为二部图边的权值
  2. 应该过滤掉 query 和 doc 中点击率过低的实例
  3. 为了避免头部词的权重过高,可进行 log 转换平滑

计算过程均可在离线完成,结果可以以 key-value 的形式放入 redis,线上即用即取。

锚点特征

这个名字是我乱起的,原理是搜到过(曝光过)这个 content 的所有历史 query,与当前 query 做相似度,方法为计算 bm25。

实践注意事项

上文提到的历史 query,可以通过离线挖掘的方式挖出来放到 redis(或将其分词结果放入 redis),点击率等信息也可以随着放入。

线上服务用的时候请求 redis,拿到这些 query 利用上文提到过的 bm25 公式计算即可,其点击率可以替换 bm25 中的权重。
———————————————————————————————————————————————

模型类特征

模型类特征现在一般分为两类,表示型和交互型。在 bert 出现之前,存在 dssm 之类的模型,但现在一般都使用 bert,本人的经验也是利用 bert 的经验,所以以下以 bert 的视角阐述。

表示模型

表示模型一般是双塔,即两个共享参数的 bert,一座用来编码 query,一座用来编码 content/title,或者可以理解为一个 bert 按顺序先后编码了 query 和 content/title。输出的 embedding 直接拿 cls 或者利用每个 token 进行 pooling 差别不大,query 和 content/title 的 embedding 可以直接做点积或者上层加一些 dense 层。

标注数据一般是人工标注的相关性程度,量化到具体的几档,loss 一般为 pointwise/pairwise。

实践注意事项

content/title 训练所得 embedding 直接放 redis 当 cache,线上只需要实时推理 query 的 embedding,热门query 集的 embedding 也可以做一些相应的 cache 策略。

表示模型一般 12 层的 bert-base 较为合适,6 层效果不好,24 层提升不大。12 层 bert 也可以利用 24 层蒸馏得到,直接蒸馏最后的结果就行,同时蒸隐层收益不大。输入长度最长不要超过 128,否则线上压力比较大。

bert 上线一定要 GPU 机器,否则 CPU 推理不仅 QPS 上来扛不住,单条样本推理的耗时也非常高。bert 模型本身比较吃内存,建议单独成一个独立的推理服务,方便管理。

交互模型

交互模型即将样本拼成 query | title 的样子直接一行句子输入 bert,末端直接拿 cls 的 embedding 过若干 dense 得到相关性分数。由于 bert 输入长度的限制,一般只用于 query 和 title 的相关性。

交互模型一般是搜索相关性特征中最强的一个单体特征,值得好好做这个模型。

实践注意事项

交互模型需要推理每一个 query 和候选doc title 的拼接体,所以推理量一定是比表示模型大的,输入长度一般限制在 50 以下,层数一般用 6 层 bert,否则线上压力极大。

由于 6 层 bert 参数量相对少,这里一般是通过训练 24 层 bert 然后蒸馏给 6 层 bert。初始化方式直接把 24 层 bert 的前 6 层参数拿过来初始化,亲测跳着层初始化效果很差。。。蒸馏也是直接蒸最后的结果,软硬 label 的权重实验中调整,蒸隐层亲测收益不大(甚至毫无收益

一定要用 GPU 机器,CPU 完全没有机会,一般交互模型的 QPS 还是不小的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Matlab相关性可以通过多个函数来计算和分析。其,corr和corrcoef是两个常用的函数。 corr函数用于计算线性或秩相关性。它可以计算单个数据序列的相关性,也可以计算两个数据序列之间的相关性。该函数的输出结果为相关系数rho。可以使用以下方式调用corr函数: - rho = corr(X):计算X每一列之间的相关性。 - rho = corr(X,Y):计算X和Y之间的相关性。 - [rho,pval] = corr(X,Y):除了相关系数rho,还返回相关系数的p值。 - [rho,pval] = corr(___,Name,Value):可以使用附加的参数来设置相关性计算的选项。 corrcoef函数用于计算相关系数。它可以计算两个数据序列之间的相关系数,并返回一个2×2的矩阵R。对角线元素为1,非对角线元素为相关系数。可以使用以下方式调用corrcoef函数: - R = corrcoef(A):计算A每一列之间的相关系数。 - R = corrcoef(A,B):计算A和B之间的相关系数。 另外,在Matlab还存在其他与相关性相关的函数,比如xcorr函数,用于计算互相关函数。xcorr函数可以对两个具有时延的信号进行对齐处理,并计算相关系数。通过调整移位量(滑动偏移值),可以找到最大相关系数对应的移动时间,从而确定两个信号的时延关系。 综上所述,Matlab有多个函数可以用于计算和分析相关性,包括corr和corrcoef函数用于计算相关系数,以及xcorr函数用于计算互相关函数。这些函数可以帮助我们理解数据之间的关联程度。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值