转自:https://chuansongme.com/n/2035198
推荐引擎的研究结果成千上万,绝大部分工作都来自于矩阵分解或者类似,在针对用户和Item分别训练出特征向量之后,根据向量内积计算返回针对特定用户的Top K Item。类似的场景在广告点击率预估中也同样存在,然而,成千上万的工作里,却极少有适合于大规模推荐引擎的:想一想有上千万甚至上亿的Item等待推荐,针对每个用户都要计算这上千万的内积,不论是离线,还是在线计算,都是一笔昂贵的开销—我们假定内积运算都是浮点数,用户和Item的向量表示都有20维,那么计算用户跟1个Item的相似度就可能需要20次浮点运算,在2G主频的服务器下,这需要耗时40纳秒左右,1千万次计算,就需要0.04秒,1亿次计算,就会有0.4秒了。如果向量表示的维度更高,比如50维乃至100维,那么计算开销会继续成倍增加,考虑到其他因素,比如虚拟机损耗,内存cache miss等等,实际时间比以上结果还要高很多。对于离线计算,如果有1千万用户和1千万item,假定有几十个mapreduce任务,那么就需要数小时,如果有更多的用户和item,这个数字会直线增加。 对于在线计算,推荐引擎,还有广告点击率预估,这些都是高并发场景的典型应用,给单个用户计算就耗时几十毫秒甚至接近1秒,那么支撑数千的并发,将需要多少服务器资源呢?由此可见,这的的确确是一个现实的工程问题,更是个大数据场景中容易忽略的挑战。
这样一个具有典型意义的问题在2012年之前几乎没人提及,这时距离推荐引擎的诞生已经有十年了,距离推荐引擎的研究高潮也过去了五,六年。那么,为什么这个经常遇到的场景却很少有人提及,或者有人去关注呢?想来有这么一些原因:
-
早期推荐引擎并没有面临很多的Item项可以推荐,就算是书籍这样的大规模推荐,也不过数百万规模。至于Netflix这种闻名的音像制品,Item只有上万条;
-
一些大规模的推荐引擎,比如Youtube,采用的是协同过滤,没有面临这样的大规模内积求解问题;
-
还有一些电商类的推荐引擎,事先做好了有效的降维,例如针对类目,品牌等聚合后的结果计算;
-
还有的则做了各种牺牲,比如牺牲了新鲜数据引入模型的时效性,完成离线训练后模型几乎不再更新或者很长时间才去更新;或者仅仅针对部分用户做模型更新,等等,不一而足。
上面的解决方案,有的是很有效的,例如降维,不过手段都是ad hoc的。那么,有没有通用的解决之道呢?从2012年之后,这方面的问题逐渐引起关注,14年之后,这个问题引起了更多人的注意,跟大数据的流行应当也有一定关系。下面汇总一下这方面的资料,并不一定完整,但基本思路已经都涵盖了:
-
Efficient Retrieval of Recommendations in a Matrix Factorization Framework. Koenigstein, Noam and Ram, Parikshit and Shavitt, Yuval, CIKM 2012
-
Learning Binary Codes for Collaborative Filtering. Zhou, Ke and Zha, Hongyuan, SIGKDD 2012
-
Maximum Inner-Product Search using Tree Data-structures. Ram, Parikshit and Gray, Alexander G, arXiv preprint arXiv:1202.6101
-
Asymmetric LSH (ALSH) for Sublinear Time Maximum Inner Product Search (MIPS). Shrivastava, Anshumali and Li, Ping, arXiv preprint arXiv:1405.5869
-
Asymmetric Minwise Hashing for Indexing Binary Inner Products and Set Containment. Shrivastava, P Li, WWW 2015
-
Speeding Up the Xbox Recommender System Using a Euclidean Transformation for Inner-Product Spaces. Bachrach, Yoram and Finkelstein, Yehuda and Gilad-Bachrach, Ran and Katzir, Liran and Koenigstein, Noam and Nice, Nir and Paquet, Ulrich, RecSys 2014
-
Preference Preserving Hashing for Efficient Recommendation. Zhang, Zhiwei and Wang, Qifan and Ruan, Lingyun and Si, Luo, SIGIR 2014
-
On Symmetric and Asymmetric LSHs for Inner Product Search. Behnam Neyshabur and Nathan Srebro, arXiv preprint arXiv:1410.5518
-
Clustering is Efficient for Approximate Maximum Inner Product Search. Alex Auvolat, Pascal Vincent, arXiv preprint arXiv:1507.0591
-
LEMP: Fast Retrieval of Large Entries in a Matrix Product. Teflioudi, Christina and Gemulla, Rainer and Mykytiuk, Olga, ACM SIGMOD 2015
-
Fast and Accurate Maximum Inner Product Recommendations on Map-Reduce. R Hall,J Attenberg, WWW 2015
-
Music Recommendations at Spotify. http://www.slideshare.net/erikbern/music-recommendations-mlconf-2014
稍微总结一下以上各种思路和方案:这个问题跟最近邻搜索有一些像,假设度量空间中有很多点,给定一个点,返回跟该点距离最近的所有点就是最近邻查询。常见的距离度量有欧氏距离,Cosine距离等。内积空间的最近邻,跟Cosine距离很类似,如果所有点的坐标全部归一化,那么Cosine距离就是内积。图中显示的是没有归一化的三种距离,可以看到差别是很大的:
跟点q欧氏距离最近的是Pe,Cosine距离最近的是Pc,内积距离最近的是Pi。
在Cosine距离最近邻检索上,一种常用的手段是借助于LSH局部敏感哈希,LSH用于把对象投射到整数上,使得整数之间的汉明距离等同于对象之间的相似度,也就是相似的对象有更高的概率被投射到相同的哈希桶。然而,普通的LSH并不能用于内积空间检索,这是因为通常的LSH要求度量空间的距离满足三角形不等式,既两边之和大于第三边,然而对于内积来说,即便坐标归一化之后,可能仍然不满足,例如:假设3个点x,y,z,已经归一化,||x||=||y||=||z||=1,x,y,z之间的夹角分别为(π/4-0.1),π/4,(π/2-0.3),那么d(x,y)+d(y,z)
2012年,首个解决内积空间检索的方案采用“Ball Tree”的方法,在度量空间构造球形树。树的每个节点代表度量空间中的点的集合,节点不断划分,直到叶节点包含的点在阀值之下。
构造Ball Tree时,可选取最远的两个点,然后把所有点按照跟这两个点的距离划分为两部分放入Ball Tree节点,每个节点内还存放圆心和半径(既分别为内部包含点的均值和最大距离),然后分别递归构造直至叶节点内的数量达到阀值。搜索时,通常采用深度优先遍历。Ball Tree的方式跟K-D Tree很类似,后者通常用于高维数据最近邻检索,因此,缺点跟K-D Tree也类似,维度高时复杂度高,甚至逐渐退化为线性扫描。
2014年,LSH研究者专门为内积空间设计了一种特殊的LSH方案,针对没有归一化的内积空间,称为非对称局部敏感哈希ALSH,用来区别传统的LSH—后者实际上是对称型。作者把LSH的计算分为两个阶段:索引和检索,两者使用同样的哈希函数,而ALSH则分别采用不同的哈希。没有归一化的内积计算缺乏一个相似度计算的基本性质:自己跟自己的距离并不是最小的,例如Cosine距离,一定有 <= ,但内积则不一定。ALSH的理论证明见论文。
尽管前文提到归一化的向量内积计算,无法用LSH近似,可是在线音乐推荐公司Spotify却仍然在把所有用户和Item的向量表示归一化之后,采用LSH的一个变种针对Cosine距离近似求解TopK—利用Random Projection来针对Cosine距离做近似近邻查找ANN(Approximate Nearest Neighbour),性能远高于KD-Tree类的方案:基于Random Projection构建树,在每个树的中间节点,选择一个随机超平面,把空间划分成子空间。重复k次之后得到了一系列树。利用Random Projection就可以绕过常规LSH对于三角形不等式的等价变换依赖,这点本人还没想明白。
工艺品电商Etsy的方案是转化内积计算为欧氏距离,首先,Etsy针对ALSH的提出疑问,认为后者是假定用户和Item之间的内积很大得出的近似,然而有些时候即便是TopK,可内积的值依然很小,所以ALSH的近似计算会存在问题。Etsy的方案依然是类似LSH,但主要是以离线MapReduce的方式进行计算,并通过LSH加速。首先,Etsy把用户和Item的向量表示全部归一化,并增加1维,这样可以把内积最大问题转化为求欧氏距离最小。然后把用户和Item分别映射到哈希桶中,那么桶中的用户和Item就是欧氏距离最近的相似对。哈希桶的大小大体按照Item数量的平方根来操作,Etsy并没有很严格地证明自己的方案,但在实际使用中得到了很好的加速和近似。附图是分别针对用户和Item增加1维的方案。
微软在给XBox使用的推荐引擎里提出了另外一种解决方案。但跟Etsy的方法有类似,都是通过给数据增加1个维度把内积空间问题转化为欧氏空间检索问题。毕竟是出自研究院的成果,对理论的正确性更加看重,因此在方案一开始就提到了内积不满足三角形不等式关系,所以许多加速方案都无法实施。XBox增加1个维度的方式见附图,可以跟Etsy做个对比:
在转换为欧氏空间问题之后,微软采用了一种称为PCA(Principal Component Axes)树的方式进行检索。PCA树,顾名思义,就是针对变换后的数据进行SVD分解,但个人对该方案并不认可,既然已经解决了不等式问题,那么像Etsy这样转而采用LSH显然是一种更快速和有效的计算手段。
除此之外还有一些解决手段依赖于纯学术的哈希学习(Hash Learning),思想是通过机器学习把数据映射成二进制串,从而显著减少数据存储和计算的开销。然而,目前相关领域的研究才刚刚开始,距离实用,乃至大数据场景的还有待于进一步深入思考,因此尽管上述文献列出相关工作,但仅仅是以示关注而已。
所以可以看出,尽管在之前,相关问题并没有引起足够的重视,但这几年来自工业和学术界的工作已经取得了显著成绩,在海量用户和Item数基础之上构建大规模推荐引擎(点击率预估引擎)已经是商业验证过的方案。
然而,从理论上证明上述2个商业方案(Spotify和Etsy)的正确性:就是把内积距离转化为Cosine和欧氏距离之后,为什么采用的类LSH算法就不会再收到三角形不等式的约束,这个问题是留待考虑的,有兴趣给本公众号留言。Etsy在自己的论文里提到自己确实也没有很好的证明自己方法的正确性。