一、FM简介
在一般的回归线性模型中,模型可表示为然而这样的线性模型并未考虑到特征与特征之间交叉的影响,当加入特征交叉时,模型可表示为
从上面的式子可以很容易看出,组合部分的特征相关参数共有个。但是某些情况下为categorical特征,需要通过one-hot编码处理,因而样本的特征就会变的稀疏。在大规模稀疏特征存在的场景下,比如CTR预估和推荐排序,这些场景的最大特点就是特征的大规模稀疏,此时满足,都不为0的情况非常少,这样将导致无法通过训练得出。
为了解决这一问题,FM对于每个特征,学习一个大小为的一维向量,于是特征与特征的特征组合权重值,通过特征对应的向量与的内积表示。因此FM模型可表示为
FM对特征的处理方式本质上是在对特征进行embedding化表征。那么为什么说FM的这种特征embedding模式,在大规模稀疏特征应用环境下比较好用?为什么说它的泛化能力强呢?根据上式,即使在训练数据里两个特征并未同时在训练实例里同时出现过,但是因为FM是学习了单个特征的embedding,并不依赖某个特定的特征组合是否出现过,所以只要特征和其它任意特征组合出现过,那么就可以学习自己对应的embedding向量。于是,尽管样本中并没有和这样的特征组合,但他们与其他特征有过组合并学习到了自身的embedding,就可以通过内积算出这个新特征组合的权重。因而FM模型泛化能力强。
二、梯度推导
经过这样的简化之后,再对FM中需要训练学习的参数计算梯度
对于
对于
对于
三、FM与其他模型的联系
四、FM代码
import tensorflow as tf
class fm(object):
"""
"""
def _init_graph(self,feature_dim,vector_dim,learning_rate):
self.input_x = tf.placeholder(tf.int32, [None, feature_dim], name="input_x")
self.input_y = tf.placeholder(tf.float32, [None, 1], name="input_y")
#input_x shape is [B, N], w shape is [N,1], v shape is [N, K]
w0 = tf.Variable(tf.random_uniform([1]))
w = tf.Variable(tf.truncated_normal([feature_dim, 1]))
linear_part = tf.add(w0, tf.matmul(self.input_x, w))
v = tf.Variable(tf.truncated_normal([feature_dim, vector_dim]))
head = tf.pow(tf.matmul(self.input_x, v), 2)
tail = tf.matmul(tf.pow(self.input_x, 2), tf.pow(v, 2))
pair_part = 0.5*tf.reduce_sum(head - tail)
final = tf.add(linear_part, pair_part)
lambda_w = tf.constant(0.0001)
lambda_v = tf.constant(0.0001)
w_l2_loss = tf.reduce_sum(tf.multiply(lambda_w, tf.pow(w, 2)))
v_l2_loss = tf.reduce_sum(tf.multiply(lambda_v, tf.pow(v, 2)))
l2_loss = tf.add(w_l2_loss, v_l2_loss)
error = 0.5*tf.reduce_mean(tf.pow(self.input_y - final, 2))
self.loss = tf.add(error, l2_loss)
self.optimal = tf.train.AdagradOptimizer(learning_rate=learning_rate)
self.train_op = self.optimal.minimize(self.loss, global_step=self._global_step)
参考
https://cloud.tencent.com/developer/article/1099532
https://zhuanlan.zhihu.com/p/58160982
https://www.zhihu.com/question/58312854