Q:为什么推荐模型中Embedding层拟合速度较慢?
-
首先,推荐系统中的Embedding层与NLP中的Embedding层不同。在NLP中,Embedding层通常是Word2Vec类的方法,每个WordID对应Embedding Table Lookup中的一个向量,原始输入与Embedding Vector之间除了对应关系,一般无其他关联,也正因为如此,NLP中的Embedding层其实没有“稀疏”的说法,梯度反向传播时的参数更新与原始输入无关,截至到Embedding层即止;而在推荐系统中,Embedding层并不是Word2Vec那类的方法(因为特征向量一般都是01串,而非NLP中那样有多个不同的WordID,无法进行普通的Word2Vec),它可以是一般的全连接层,将稀疏向量映射到高维空间,一样能达到“Embedding”的含义。正因为如此,推荐系统中的Embedding一般与原始输入有数学运算关系,例如使用FC作为Embedding操作,那么Embedding Vector就由原始输入与几个连接权重分别相乘后得到,在梯度反向传播时,连接权重的更新就会受到原始输入的影响,(在使用标准的梯度下降优化算法时)只有非零的输入元素所连接的权重才能被有效更新,所以推荐系统Embedding层的训练速度受输入向量稀疏程度的影响
-
在推荐系统中,输入的特征往往是十分稀疏的,在以标准梯度下降作为优化算法的模型参数更新过程中,只有非零元素才能被有效更新,进一步导致Embedding层收敛速度过慢
-
以全连接层作为Embedding为例,在梯度反向传播中,链式求导在Embedding部分的局部表达式可简化为
y = w x y w ′ = x y = wx \\ y'_w = x y=wxyw′=x
其中 y y y代表某一特征的Embedding Vector, w w w代表(输入神经元与Embedding神经元的)连接权重, x x x代表输入特征。 -
若此时原始输入为0,那么Embedding输出关于参数 w w w的梯度也为0,从而在整个链式求导中,模型输出关于 w w w的梯度也为0,在标准梯度下降法中, w w w就不会被有效更新
-
-
Embedding层参数量往往占比很大,所以拖慢了整体模型的收敛速度
Embedding预训练
- 由于推荐系统Embedding层训练开销巨大,一般将Embedding层独立出来单独训练后再与其他特征一起输入神经网络进行训练,加快收敛速度。此时可以让Embedding层一起参与梯度反向传播,也可以冻结Embedding层参数只更新上层网络参数。由于用户的兴趣、物品的属性不可能在几天内发现巨大变化,所以Embedding训练的频率不需要很高,但上层神经网络为了尽快抓住最新的数据趋势信息,往往需要高频训练甚至实时训练。综上,使用不同的频率训练Embedding与上层网络模型是一种最优折中方案。
Embedding作为召回层
- 直接利用Embedding的内积来计算用户-物品相似度从而直接导出推荐列表
局部敏感哈希
Locality Sensitive Hashing(LSH)
-
为了筛选某个用户的候选物品,需要对候选集合中的所有物品进行遍历。在 k k k维的Embedding空间中,物品总数为 n n n,那么遍历计算用户和物品向量相似度的时间复杂度为 O ( k n ) O(kn) O(kn)。在物品综述动辄达到几百万量级的推荐系统中,时间开销是无法接受的
-
LSH核心思想:分桶策略,让相邻的点落入同一个桶内,在搜索时只需要在一个桶内或相邻的几个桶内进行遍历即可
-
先验知识:在欧氏空间中,将高维空间的点映射到低维空间,原本相近的点在低维空间中肯定依然相近,但原本远离的点则有一定概率变成相近的点(可利用二维点向一维直线映射作例子)。利用低维空间可以保留高维空间相近距离关系的性质,就可以构造LSH的“桶”(低维空间保持高维空间相近距离的性质本质上其实是相近距离在不同方向的映射中,“容错率”更高,因为距离相近,在各个方向的映射产生的新距离的变动范围都不会太大)
-
对于Embedding向量来说,亦可以像点那样,用内积操作构建LSH中的桶。假设 v v v是高维空间中的 k k k维Embedding向量, x x x是随机生成的 k k k维映射向量。内积操作可将 v v v映射到一维空间,成为一个数值:
h ( v ) = v ⋅ x h(v)=v \cdot x h(v)=v⋅x
- 由上述结论可以推知,一维空间也会部分保持高维空间的近似距离信息,因此可以使用如下的哈希函数进行分桶
h x , b ( v ) = ⌊ v ⋅ x + b w ⌋ h^{x, b}(\boldsymbol{v})=\left\lfloor\frac{\boldsymbol{v} \cdot \boldsymbol{x}+b}{w}\right\rfloor hx,b(v)=⌊wv⋅x+b⌋
w w w为分桶宽度, b b b是 0 0 0到 w w w之间的一个均匀分布随机变量,避免分桶边界固化-
映射操作势必会造成一些距离信息丢失,若仅采用一个哈希函数进行分桶,则必然存在相近点误判的情况。有效的解决办法是采用 m m m个哈希函数同时进行分桶,若有两个点在 m m m个哈希函数中都掉进了同一个桶,则它们是相似点的概率就大大增加
-
多哈希函数进行分桶存在一个问题:若两个点在一个哈希函数中落入同一个桶,而在另一哈希函数不在同一个桶,那么这两个点算相似还是不相似。两种策略,一种是“且”,另一种是“或”。“且”的话这两点就不算相似点,“或”的话这两点算相似点。“且”还是“或”需要由实际情况,根据准确率和召回率的权衡决定
-
综上,LSH的基本操作为:将用户向量与物品向量一同输入哈希函数进行分桶,用户向量所在的桶即为最近邻桶,遍历桶内其余物品向量即可。(但是算哈希分桶的过程不还是要所有物品向量都和一个随机向量作内积,依然需要 O ( k n ) O(kn) O(kn))