在当代搜索引擎的召回环节,除了常见的经典倒排索引来对Query和Document进行文本字面匹配外,经常也会增加一路基于Bert模型的双塔结构,将用户查询Query和搜索文档,各自通过一个塔形结构来打Embedding,以此增加Query和Document的深层语义匹配能力。

再比如,在自然语言处理的QA领域,一般也会在第一步召回环节,上一个基于Bert模型的双塔结构,分别将问题Question和可能包含正确答案的Passage,通过双塔结构映射到同一个语义空间,并分别把Question和Passage打出各自的Embedding。

我的感觉,未来,双塔结构会在更多应用领域获得应用,这是个非常有生命力的模型。为啥呢?答案其实很简单:在面临海量候选数据进行粗筛的场景下,它的速度太快了,效果说不上极端好,但是毕竟是个有监督学习过程,一般而言也不差,实战价值很高,这个是根本。若一个应用场景有如下需求:应用面临大量的候选集合,首先需要从这个集合里面筛选出一部分满足条件的子集合,缩小筛查范围。那么,这种应用场景就比较适合用双塔模型。

上面说的是双塔模型的优点,所谓“天下没有免费的晚餐”,它为了速度快,是需要付出代价的,那么,代价是什么呢?就是要在一定程度上牺牲掉模型的部分精准性,而且这个代价是结构内生的,也就是说它这种结构必然会面临这样的问题。至于产生问题的具体原因,在后面介绍双塔模型的时候会讲。

也就是说,目前的现状是:对于绝大多数应用来说,双塔模型的速度是足够快了,模型精度还有待提升。然而,不改变双塔基本结构前提下(为了保速度),如何才能提升模型效果,从上面讲的结构内生性问题来说,看上去貌似又是无解的。那么,真的是这样吗?

我其实去年一直也在思考这个问题。好在,去年,我们尝试了一个改进的双塔模型,我称之为“SENet双塔模型”,在业务里证明了它的有效性。本文会介绍下SENet双塔模型的具体做法,尝试分析为何这种改造是有效的。除此外,还会谈及另外两个对模型召回或者粗排来说比较重要的问题:推荐模型召回、粗排及精排几个环节的优化目标一致性问题,以及,召回或粗排模型的负例选择问题。

python实现双塔模型 nlp 双塔_自然语言处理

用户塔,右侧是Item塔,可将特征拆分为两大类:用户相关特征(用户基本信息、群体统计属性以及行为过的Item序列等)与Item相关特征(Item基本信息、属性信息等),原则上,Context上下文特征可以放入用户侧塔。对于这两个塔本身,则是经典的DNN模型,从特征OneHot到特征Embedding,再经过几层MLP隐层,两个塔分别输出用户Embedding和Item Embedding编码。在训练过程中,User Embedding和Item Embedding做内积或者Cosine相似度计算(注:Cosine相当于对User Embedding和Item Embedding内积基础上,进行了两个向量模长归一化,只保留方向一致性不考虑长度),使得用户和正例Item在Embedding空间更接近,和负例Item在Embedding空间距离拉远。损失函数则可用标准交叉熵损失,将问题当作一个分类问题,或者类似DSSM采取BPR或者Hinge Loss,将问题当作一个表示学习问题。

,通过训练数据,训练好User侧和Item侧两个塔模型,我们要的是训练好后的这两个塔模型,让它们各自接受用户或者Item的特征输入,能够独立打出准确的User Embedding或者Item Embedding。

之后,对于海量的候选Item集合,可以通过Item侧塔,离线将所有Item转化成Embedding,并存储进ANN检索系统,比如FAISS,以供查询。为什么双塔结构用起来速度快?主要是类似FAISS这种ANN检索系统对海量数据的查询效率高。

再往后,某个用户的User Embedding,一般要求实时更新,以体现用户最新的兴趣。为了达成实时更新的目的,你有几种难度不同的做法,比如你可以通过在线模型来实时更新双塔的参数来达成这一点,这是在线模型的路子;但是很多情况下,并非一定要采取在线模型,毕竟实施成本高,而可以固定用户侧的塔模型参数,采用在输入端,将用户最新行为过的Item做为用户侧塔的输入,然后通过User侧塔打出User Embedding,这种模式。这样也可以实时地体现用户即时兴趣的变化,这是特征实时的角度,做起来相对简单。

最后,有了最新的User Embedding,就可以从FAISS库里拉取相似性得分Top K的Item,做为个性化召回结果。

以上内容介绍了双塔模型的结构以及训练及应用过程。在本文开始,提到过双塔结构有一个内生性的问题,就是它的结构必然会导致精度的损失,