一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型

一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型

提示:最近系统性地学习推荐系统的课程。我们以小红书的场景为例,讲工业界的推荐系统。
我只讲工业界实际有用的技术。说实话,工业界的技术远远领先学术界,在公开渠道看到的书、论文跟工业界的实践有很大的gap,
看书学不到推荐系统的关键技术。
看书学不到推荐系统的关键技术。
看书学不到推荐系统的关键技术。

王树森娓娓道来**《小红书的推荐系统》**
GitHub资料连接:http://wangshusen.github.io/
B站视频合集:https://space.bilibili.com/1369507485/channel/seriesdetail?sid=2249610

基础知识:
【1】一文看懂推荐系统:概要01:推荐系统的基本概念
【2】一文看懂推荐系统:概要02:推荐系统的链路,从召回粗排,到精排,到重排,最终推荐展示给用户
【3】一文看懂推荐系统:召回01:基于物品的协同过滤(ItemCF),item-based Collaboration Filter的核心思想与推荐过程
【4】一文看懂推荐系统:召回02:Swing 模型,和itemCF很相似,区别在于计算相似度的方法不一样
【5】一文看懂推荐系统:召回03:基于用户的协同过滤(UserCF),要计算用户之间的相似度
【6】一文看懂推荐系统:召回04:离散特征处理,one-hot编码和embedding特征嵌入


提示:文章目录

文章目录

  • 一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型
  • 矩阵补充
  • 为什么这个模型叫做矩阵补充?
  • 我分析一下这矩阵补充的缺点
  • 线上服务
  • 那么如何加速最近邻查找避免暴力枚举呢?快速最近邻查找
  • 总结


矩阵补充

最近这几篇都是详细讲解向量召回,
矩阵补充是向量召回最简单的一种方法,不过现在已经不太常用这种方法了。

我讲解矩阵补充是为了帮助大家理解下之后我要讲的的双塔模型

我会讲很多教科书里没有写但是在工业界非常有用的知识点

上一篇文章介绍了embedding,他可以把用户ID或者物品ID映射成向量。

我画的这个模型就是基于embedding做推荐,
模型的输入是一个用户ID和一个物品ID。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第1张图片

模型的输出是一个实数(两个向量的内积),是用户对物品兴趣的预估值rate,
这个数越大,表示用户对物品越感兴趣。

下面我们看一下模型的结构,左边的结构只有一个embedding层,
把一个用户ID映射到一个向量去做向量a,这个向量是对用户的表征。
回忆一下上一篇文章的内容,embedding层的参数是一个矩阵W,
矩阵中列的数量是用户数量,每一列都是图中a这么大的向量。
embedding层的参数数量等于用户数量乘以向量a的大小。

右边的结构是另一个embedding层,把一个物品ID映射到一个向量记作b,
大小跟向量a,这是乘一样的,向量b是对物品的表征。
embedding层的参数是一个矩阵输出的向量b是矩阵的一列矩阵,
中列的数量是物品的数量。

模型一共用了两个embedding层,它们不共享参数,
对向量a和b,求内积得到一个实数作为模型的输出,这个模型就是矩阵补充模型


为什么这个模型叫做矩阵补充?

接下来我可以解释为什么这个模型叫做矩阵补充。

刚才定义了模型结构,接下来我要讲模型的训练。

首先讲训练的基本思路,用户embedding参数是一个矩阵记作大A,
用户对应矩阵的第u列记作向量au
物品embedding参数是另一个矩阵记作大B,
物品对应矩阵的第b列,记作做向量bi,
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第2张图片

向量au和bi的内积是第u个用户和第i个物品兴趣的预估值rate,
内积越大说明用户u对物品i的兴趣越强。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第3张图片

训练模型的目的是学到矩阵A和B,使得预估值rate和真实观测(内积)的兴趣分数矩阵更接近。
A和B是embedding参数。

开始训练之前首先要准备一个数据集,
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第4张图片

数据集是很多三元组的集合,每个三元组包含用户ID、物品ID、兴趣分数y,
三元组的意思是:该用户对该物品真实的兴趣分数。

在系统里有记录把数据集记作Ω,
它是这样三元组的集合,U和I分别是用户ID和物品ID,Y是真实观测的兴趣分数,
数据集中的兴趣分数是系统记录的。

这里举个例子,凡是有曝光的,系统都会记录兴趣分数,
曝光的意思是把物品展示给用户,
如果有曝光但是没有点击,说明不感兴趣,分数为零。
如果有点击、点赞、收藏、转发这些行为各算一分。
这些行为都说明用户对物品感兴趣。
那么兴趣分数最低是零分,最高是四分。

训练的目的就是让模型的输出一个兴趣分数
模型中embedding层可以把用户ID=和物品ID映射成向量
优化映射成向量au
第i号物品映射成向量bi
训练的时候要求解这样一个优化问题,优化变量是矩阵A和B,它们是embedding参数。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第5张图片

仔细看一下公式,这里的三元组UIY是训练集中的一条数据,意思是用户u对物品I的真实兴趣,分数是Y。

<内积>这一项是向量au和bi的内积,它是模型对性取分数的预估,
反应第u号用户有多喜欢第i号物品,
y这一项是真实性取分数(groundtruth),
然后求Y与预估值<内积>之间的差,
我们希望这个差越小越好,
我们取差的平方,差的平方越小,则预估值越接近真实值。
Y对每一条记录的差的平方求和作为优化的目标函数。【这就是典型的MSE误差损失函数】

对目标函数求最小化优化的变量是矩阵A和B,
求最小化损失函数,可以用随机梯度下降的算法,
每次更新矩阵A和B的一列,这样就可以学出矩阵A和B。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第6张图片

我来解释一下为什么这个模型叫做矩阵补充。
看一下这个矩阵,
矩阵每一行对应一个用户,
每一列对应一个物品矩阵中的每个元素,
表示一个用户对一个物品的真实性矩阵数。

系统里物品很多,一个用户看过的物品,只是系统中的极少数在矩阵中。
绿色位置表示曝光给用户的物品,
灰色位置表示没有曝光的物品,
只要把物品曝光给用户,我们就知道用户对物品是否感兴趣。

曝光了没点击说明不感兴趣,分数是零
曝光之后,客户可能会点击,点赞,收藏,转发每个都算一分,加起来最多有四分,
比如这个绿色位置表示,第3号用户对第2号物品的兴趣,分数等于4
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第7张图片

矩阵中只有少数位置是绿色
大多数位置都是灰色,也就是没有曝光给用户的,我们并不知道用户对没曝光的物品是否感兴趣。

我们刚才拿绿色位置的数据训练出了模型,有了模型,
我们就可以预估出所有灰色位置的分数,
也就是把矩阵的元素给补全,这就是为什么模型叫做矩阵补充

把矩阵元素补全之后,我们就可以做推荐。
给定一个用户,我们选出用户对应的行中分数较高的物品推荐给该用户。

okay,这本文介绍矩阵补充方法,只是为了帮助大家理解向量召回而已。
矩阵补充并不是工业技能work的方法,在实践中并不会用矩阵补充。


我分析一下这矩阵补充的缺点

一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第8张图片

第一个缺点是矩阵补充,没有利用物品属性和用户属性
矩阵补充,仅仅用到了embedding,
用两个embedding层分别把物品ID和用户ID映射成两个向量,仅此而已。

在小红书的场景下,物品属性包括类目、关键词、地理位置、作者信息等等,
用户属性包括性别、年龄、地理定位,感兴趣的类目知道这些属性,召回可以做的更精准。

下一篇文章咱们介绍双塔模型
它可以看作矩阵补充模型的升级版,
双塔模型不单单使用物品ID和用户ID,
还会结合各种物品属性和用户属性
双塔模型的实际表现非常好。

矩阵补充的第二个缺点是负样本的选取方式不对
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第9张图片

这里的样本指的是用户u和物品I的二元组记录即括号u i
训练向量召回模型需要正样本和负样本矩阵,
补充的正样本指的是物品给用户曝光之后有点击交互的行为,这样的正样本是OK的,没问题,工业界都这么做,
但是负样本的选取方式是完全错误的。
矩阵补充的负样本是曝光之后没有点击交互的物品,这是种想当然的做法。
学数据的人可能以为这样没错,但可惜这样在实践中不work。

后面会专门用一篇文章讲解正负样本怎么选……

第三个缺点是训练模型的方法不好,矩阵补充模型,用向量au和bi的内积作为兴趣分数的预估,
这样没错,可以work,但是效果不如余弦相似度
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第10张图片

工业界普遍使用余弦相似度,而不是用内积矩阵补充,用平方损失函数,也就是做回归,
让预估的兴趣分数以和真实的兴趣分数。
这样做的效果不如交叉商损失函数,也就是做分类。

工业界通常做分类,判定一个样本是正样本还是负样本,


线上服务

好,从这剩下内容都是线上服务。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第11张图片

在训练好模型之后,可以把模型用作配件系统中的召回通道,
比如在用户刷小红书的时候,快速找到这个用户可能感兴趣的一两百篇笔记,
做完训练之后再把模型存储在正确的地方。
便于做召回训练得到矩阵A和B,它们是以embedding参数
A的每一列对应一个用户,
B的每一列对应一个物品。

做推荐的时候要用到矩阵A和B,这两个矩阵可能会很大,
比如小红书有几亿用户,几亿篇笔记,
那么这两个矩阵的列数都是好几亿。
为了快速读取和快速查找,需要特殊的存储方式

把矩阵a的列存储到一张key – value表(哈希表),存储的key值是用户的ID。
Value是矩阵a的一列,
给定用户ID在表中做查找,得到一个向量,也就是该用户的embedding。

另一个矩阵B也很大,B的存储和索引比较复杂,不能简单的用key value存储。
稍后我会解释原因以及解决方案。

在训练好模型,并且把以百里向量做存储之后,可以开始做线上服务。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第12张图片

某用户刷小红书的时候,小红书的后台会开始做召回,
把周围用户最可能感兴趣的K的物品作为召回结果,这叫做最近邻查找:nearest neighbor search

把第i个物品embedding向量记作bi,
计算用户向量a和物品向量bi的内积。
这是用户对第i号物品进取分数的预估。

返回内地最大的K的物品,比如K等于100,这些物品就是召回的结果。

这种最近邻查找有个严重的问题,如果逐一对比所有物品,
暴力方法的时间复杂度会正比于物品数量,这种巨大的计算量是不可接受的。

比如小红书有几亿篇比积,那么就有几亿个向量B逐一计算向量a和每个向量B的内积,
是不现实的根本做不到线上的实时计算,


那么如何加速最近邻查找避免暴力枚举呢?快速最近邻查找

避免暴力枚举有很多种算法加速
比如:快速最近邻查找,这些算法非常快,即使有几亿个物品,最多也只需要几万次内积。
这些算法的结果未必是最优的,但是不会比最优结果差又少。

快速最近零查找的算法已经被集成到很多向量数据库系统中,
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第13张图片

比较有名的包括milvus,faiss,hnswlib等等,
做最近邻查找需要定义什么是最近邻,
也就是衡量最近邻的标准,
比如最近邻距离可以定义为欧式距离最小的最近邻,
也可以定义为向量内积最大的,这叫做内积相似度
本文的矩阵补充用的都是内积相似度,
目前推荐系统最常用的是余弦相似度,其最近邻是向量夹角最小的
有些系统不支持余弦相似度,但这很好解决。
如果你把所有向量都做归一化,让它们的二范数全都等于一,那么内积就等于余弦相似度。

我用一个直观的例子来演示最近邻查找,
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第14张图片

这是个散点图,每个点是一个物品的embedding向量,embedding向量都是训练模型的时候计算出来的。

右边的五角星表示,一个用户的embedding向量记作a,
我们想要召回这个用户可能感兴趣的物品,
这就需要计算向量a与所有点的相似度。

如果用暴力枚举的话,计算量正比于点的数量,也就是物体的数量。
想要减少最近查找的计算量,必须要避免暴力枚举。

这里我介绍一种加速最近查找的算法,在做线上服务之前,先对数据做预处理,
把数据划分成很多区域,比如这样划分,
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第15张图片

至于如何划分,取决于衡量最近邻的标准
如果是cos相似度,那么划分的结果就是这样的扇形,
如果是用欧式距离,那么划分的结果就是多边形划分,
之后每个区域用一个向量表示,

比如那个蓝色区域,用那蓝色向量表示,
比如那个黄色区域,用那个黄色向量表示,

这些向量长度都是一。

划分区域之后建立索引,把每个区域的向量作为key,把扇区区域中所有点的列表作为value,【这样就省掉了大量的key,用一个代表表示】
给定这个向量就能取回蓝色扇形区域中的所有的点。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第16张图片

划分区域之后,每个区域都用一个单位向量来表示,
假如有一个点,那么划分成1万个区域,索引上一共有1万个key值,
每个向量是一个区域的key值,

给定一个向量可以快速取回这个区域内所有的点。
有了这样一个索引,就可以在线上快速做召回了。

在线上给一个用户做推荐,这个用户的一个向量记作a。
我们首先把向量a跟索引中这些代表向量做对比(量很少),计算它们的相似度,
如果物品数量是几亿,索引中的向量数量也只有几万而已。
这一步的计算开销不大,

计算相似度之后,我们发现索引中下面橘色这个向量与a最相似。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第17张图片

通过索引,我们找到这个区域内所有的点,每个点对应一个物品。
接下来我们计算点a跟区域内所有点的相似度,
如果一共有几亿个物品被划分到了几万个区域,
平均每个区域只有几万个点,所以这一步只需要计算几万次,相似度计算量也不大。

假如我们想要找向量a最相似的三个点。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第18张图片

也就是夹角最小的三个点,他们会找到这三个对应三个物品,这三个物品就是最近邻查找的结果,
哪怕有几亿个物品,用这种加速算法做查找,也只需要计算几万次,
相似度比暴力枚举快1万倍。

这就是加速的最近邻算法查找?如何,够强吧!!!——说白了就先大范围搜索,再小范围精确对比


最后总结一下本文内容,主要介绍了矩阵补充模型,
矩阵补充的想法是把物品ID和用户ID做embedding映射成两个向量,
两个向量记作au和bi
两者内积作为用户u对物品I兴趣的预估值rate。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第19张图片

训练的时候,我们让au和bi的内积拟合真实观测到的兴趣分数,
用回归的方式学习模型中embedding的参数矩阵,

补充是个学术界的模型,有很多缺点导致效果不好。

工业界其实不用矩阵补充模型,
而是用更先进的双塔模型,

假如用矩阵补充在现场做召回也是可以的,尽管效果不好。
把用户向量a作为query查找,使得向量a和bi内积最大化的物品I
寻找这样内积最大的topK物品I作为召回。
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型_第20张图片

在工业界的场景下,有上亿物品做暴力媒体的速度太慢了不可行,
实践中都用近似最近邻加速算法进行查找,不需要做枚举。

我已经讲了近似最近邻加速算法进行查找的做法,
工业界通常会用一些开源的向量数据库,比如milvus,faiss,hnswlib,
这些向量数据库都会支持近似最近邻加速算法进行查找。

完事!


总结

提示:如何系统地学习推荐系统,本系列文章可以帮到你

(1)找工作投简历的话,你要将招聘单位的岗位需求和你的研究方向和工作内容对应起来,这样才能契合公司招聘需求,否则它直接把简历给你挂了
(2)你到底是要进公司做推荐系统方向?还是纯cv方向?还是NLP方向?还是语音方向?还是深度学习机器学习技术中台?还是硬件?还是前端开发?后端开发?测试开发?产品?人力?行政?这些你不可能啥都会,你需要找准一个方向,自己有积累,才能去投递,否则面试官跟你聊什么呢?
(3)今日推荐系统学习经验:模型的输出是一个实数(两个向量的内积),是用户对物品兴趣的预估值rate,这个数越大,表示用户对物品越感兴趣。加速的最近邻算法查找说白了就先大范围搜索,再小范围精确对比

你可能感兴趣的:(个性化推荐系统,大厂人工智能技术概览,补充矩阵,双塔模型,最近邻搜索,近似最近邻搜索算法,推荐系统召回)