推荐系统炼丹笔记:好想哭,我居然输在了内存问题上!

作  者:一元  
公众号:炼丹笔记  

很多朋友都会发现,修改embedding的大小能对深度模型带来非常大的影响,往往越大的embedding能带来更佳的效果,但是却因为Embedding内存的问题,没法直接用,或者只能采用Hash Trick的技巧来弥补,真的是遗憾啊,太遗憾了,想哭。不急不急,本文就带大家一起学习一下Embedding的内存问题的一种解法

现代的基于深度学习的推荐系统利用了成百上千种不同的类别特征(Categorical Features),每一种分类都有数百万种,从点击到发布。为了符合类别数据中的自然多样性,Embedding将每个类别映射到嵌入到一个稠密的向量中。由于每个类别特征可能包含上千万个不同的可能类别(例如电商的商品个数很多都是上亿的),因此嵌入表在训练和推理过程中会出现内存瓶颈。

本文提出了一种新的方法,利用探索类别集合的互补划分为每个类别生成一个唯一的嵌入向量。基于每个互补分区存储多个较小的嵌入表,并结合每个表中的嵌入,可以以较小的内存开销为每个类别定义一个唯一的嵌入。这种方法可以解释为使用特定的固定码本(codebook)来确保每个类别的表示的唯一性。实验结果证明了该方法对于减少嵌入表的大小在模型损失和精确度方面的有效性,同时在参数上保留了相似的减少。

商余数技巧

1 问题

每个类别被映射到一个embedding向量表,数学上就是, 我们令

v2-546d71e3aef921a1942d3db726bc3d51_b.jpg

2 解决方法

2.1 Hash Trick

v2-bfc837c3b06010b22f35cdd110fd6ddf_b.jpg

我们的Embedding可以通过下面的方式得到:

v2-9ca9d0c6fd1d2ad6c29dfc958c6abef2_b.jpg

对应算法如下:

v2-0a642592bbb171caac7904f626dc6876_b.jpg

该方法将原始embedding矩阵的大小从O(|S|D)降低为O(mD), 因为m<<|S|,但这么做会将非常多不一样的类别映射到同一个embedding向量,导致模型的质量大大下降,当然这么做也没法为每个类别变量产出一个唯一的embedding向量。

2.2 quotient-remainder trick

我们令""表示正数除法, 或者是商操作, 使用两个互补的函数:一个正数商,一个余数函数,这么做我们就可以得到两个单独的embedding表,这么做我们就可以对每个类使用唯一的embedding向量进行唯一的表示。

v2-78ec78b744cb49c6e3bcbc9f58df2edd_b.jpg

v2-95eccd37c3e1e24060442e9c32386c10_b.jpg

3. 互补分割

v2-cd8e37e61e90735b54b5a7a87dc8e0f3_b.jpg

注意,给定分区的每个等价类都指定一个映射到嵌入向量的“bucket”。因此,每个分区对应于一个单独的嵌入表。在互补分区下,每个分区产生的每个嵌入通过某种操作组合后,每个索引映射到一个不同的嵌入向量。

3.1 一些例子

v2-54818c8ec3d1655a5edf8461bb83ff77_b.jpg

v2-e348f8c974c158b1bd50da0cb594a5e0_b.jpg

更加抽象的, 我们还可以根据应用程序定义更多的互补分割。回到我们的汽车例子,我们可以根据年份、品牌、类型等对其进行定义分区。假设这些属性是唯一规范的,能对应一辆独一无二的汽车,那么这些分区确实是互补的。

4. 使用互补分割构建合成Embedding

对于每个分割,我们构建一个embedding表, 这样每个等价的类被映射到一个embedding向量,这些embedding可以通过一些操作进行组合生成一个合成的embedding或者直接作为一个单独的稀疏特征。特征生成的方法虽然高效,但是也会大大增加参数的量。

v2-03498e7592fde8297590c3d1b1e86947_b.jpg

为了生成我们的合成embedding,们将给定类别的每个embedding表中所有对应的嵌入进行交互,以获得最终的embedding向量。

v2-6703c51d3dca2df1038511d38688a645_b.jpg

v2-5934b57af8b2bce2c845e640ec605f02_b.jpg

v2-ff28631e90c965c92d34bffb59f86b68_b.jpg

4.1 基于路径的合成embedding

生成嵌入的另一种方法是为每个分区定义一组不同的转换(第一个embedding表除外); 特殊地, 我们可以使用一个分区来定义一个初始embedding表,然后通过其他分区确定的函数组合来传递初始嵌入,从而得到最终的嵌入向量.

v2-c1a0bbba2117051eb91f46db65f5d68e_b.jpg

我们将这种嵌入公式称为基于路径(path-based)的组合嵌入,因为组合中的每个函数都是基于来自每个分区的唯一等价类集来确定,从而产生一个唯一的转换“路径”。这些转换可能包含参数,这些参数也需要与网络的其他部分同时训练。

v2-9bc799168d8247bc9040c51cdd8a7170_b.jpg

v2-af4c151f3aae4faaab4205666c1a0ac6_b.jpg

1. 合成特征

v2-24e78480452c1e06326b2512d3b44baf_b.jpg

v2-d17a05a51bf1f47fcdc22eef33647433_b.jpg
  • 当使用阈值化时,结果更加细微,性能的提高取决于所考虑的操作。特别是,我们发现元素级乘法最适合DCN,而级联操作更适合Facebook DLRM。
  • 对于DLRM,我们能够观察到相对于基线的0.7%的误差到0.5%的误差的改善,同时保持了大约4倍的模型尺寸减小。

2. 基于Path的合成Embedding

v2-adc1164c17f638657970b466ad8667af_b.jpg

使用较小的网络可能更容易训练,但可能无法充分转换Embedding,而较大的网络可能具有更大的能力适应更复杂的转换,但需要学习更多的参数。

3. 权衡的讨论

v2-64d39f1f8146be8462a9526d7625da96_b.jpg
  • 商余trick可以对类别数据施加任意的结构,这会在内存和效果上产生一个trade-off。一个更大的embedding表可以带来更好的效果, 但也会增加非常多的内存消耗。大多数模型的性能随着参数的数量呈指数级下降
  • 这两种类型的合成嵌入通过在生成每个类别的嵌入时隐式地强制执行由互补分区定义的某些结构来减少参数的数量。因此,模型的质量应该取决于所选的划分反映范畴集及其各自嵌入的内在属性的紧密程度
  • 基于路径的组合嵌入也可以产生更具计算性的模型,其优点是模型复杂度较低,但是基于路径的组合embedding不能取代基于operation的组合embedding;

小结

本文采用quotient-remainder的技巧降低高基数类别在Embedding表中出现的内存瓶颈。缓解了Hash Trick等技术带来的冲突问题,使得我们每次都可以得到一个唯一的embedding表示。

这种技巧虽然可以令每个类别获得唯一的embedding向量表示,但是中间存在多个约束(相乘,取余等必然会导致拆解的多个embedding之间出现共享),所以这种约束会对模型最终的影响是多少,仍然是一个值得思考的问题。比如拆解为两个embedding矩阵表示和10个embedding矩阵表示,虽然节省了内存,但是最终的效果也会下降很多,如何设计既能缓解冲突又能尽可能维持效果是一个值得探讨的问题。

参考文献

  1. Compositional Embeddings Using Complementary Partitions for Memory-Efficient Recommendation Systems:arxiv.org/pdf/1909.0210

weixin.qq.com/r/XSjP1zr (二维码自动识别)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值