推荐算法:FM算法原理与实践

一直对FM(Factorization Machines)算法知其然而不知其所以然,今天看了下推导过程,对原理有了新的认识,先做个记录。

提纲

  1. FM原理
  2. FM代码实践

1. FM原理

FM被提出是为了解决特征之间的关联性,比如在电商数据中,“USA”与“Thanksgiving”、“China”与“Chinese New Year”这样的关联特征,对用户的点击有着正向的影响。换句话说,"China"和"Chinese New Year"组合后,与最终的label有更正相关的联系。因此,学习特征之间的关联性是非常有帮助的。
表示特征之间的关联,最直接的方法的是构造组合特征。方法有两种:

  • 人工构造
  • deep learning 、FM系列算法
    FM模型是通过增加多项式项来表示特征之间的关联,这里只讨论二阶的模型:

    其中,表示特征的数量,都是模型参数。
    从上式中可以看出,组合特征的参数有个,任意两个参数之间独立。

然而,在数据稀疏性普遍存在的实际应用场景中,二次项参数的训练是很困难的。其原因是,回归模型的参数的学习结果就是从训练样本中计算充分统计量(凡是符合指数族分布的模型都具有此性质),而在这里交叉项的每一个参数的学习过程需要大量的、同时非零的训练样本数据。由于样本数据本来就很稀疏,能够满足“和都非零”的样本数就会更少。训练样本不充分,学到的参数就不是充分统计量结果,导致参数不准确,而这会严重影响模型预测的效果(performance)和稳定性。

如果把看做一个矩阵,则可以借鉴矩阵分解的方法,将分解成,即每个参数,因此FM模型可以写成(只考虑二阶的情况):

其中,是第维特征的隐向量,<,>表示点积,计算公式为:

其中,表示隐向量的长度,并且而公式可以看成:

  • 线性模型+交叉项:前两项是线性回归模型,最后一项是二阶特征交叉项
  • 交叉项 -->隐向量內积:将交叉项转换成隐向量內积求解

直观上看FM的算法复杂度是,但是通过公式转换,可以将复杂度优化到,具体如下:

\begin{aligned} \sum_{i=1}^{n-1}\sum_{j=i+1}^{n}<v_i, v_j>x_ix_j \\ & =\frac{1}{2}\sum_{i=1}^{n}\sum_{j=1}^{n}<v_i, v_j>x_ix_j - \frac{1}{2}\sum_{i=1}^{n}<v_i, v_i>x_ix_i \\ & =\frac{1}{2}(\sum_{i=1}^{n}\sum_{j=1}^{n}\sum_{f=1}^kv_{i,f}v_{j,f}x_ix_j - \sum_{i=1}^{n}\sum_{f=1}^k v_{i,f}v_{i,f}x_ix_i) \\ & =\frac{1}{2}\sum_{f=1}^k(\sum_{i=1}^{n}v_{i,f}x_i\sum_{j=1}^{n}v_{j,f}x_j-\sum_{i=1}^{n}v_{i,f}^2x_i^2) \\ & =\frac{1}{2}\sum_{f=1}^k[(\sum_{i=1}^{n}v_{i,f}x_i)^2-\sum_{i=1}^{n}v_{i,f}^2x_i^2] \end{aligned}

采用随机梯度下降SGD求解

(老实说对第3种情况还有点没明白)
在使用SGD训练模型时,每次只需要计算1次所有的,这样计算的复杂度为,模型参数为,因此FM的复杂度为。

  1. FM代码实践
    代码主要参考FM.py,通过第1部分的式子可以看出,与LR相比,loss主要是多了多项式的部分,因此在LR代码的基础上加上多项式即可。
self.xv = tf.multiply(df_v, batch_embedding) # none * n * embedding_size
sum_square = tf.square(tf.reduce_sum(self.xv, axis=1)) # none * embedding_size
square_sum = tf.reduce_sum(tf.square(self.xv), axis=1) # none * embedding_size
fm_result = 0.5 * (tf.subtract(sum_square, square_sum))

其中,表示,计算的是, 计算的是,所以上面这段代码计算的是多项式的loss.

参考资料

  • Factorization Machines
  • 机器学习算法系列-因子分解机(FM)与场感知分解机(FFM)
  • FM算法解析

你可能感兴趣的:(推荐算法:FM算法原理与实践)