FFM

FFM理论与实践

       在CTR/CVR预估任务中,FFM(Field-aware Factorization Machine)与FM模型表现非常亮眼。FFM可以看作是FM的升级版,由Yuchi Juan于2016年提出。这里简单一下FFM的原理以及如何将理论转化为实践。

1. FFM公式定义

       相较于FM模型,FFM模型引入了域(Field)的概念可看做是对特征进行分组。例如,对于性别特征而言,通常有male,female两种取值,对值进行one-hot编码之后性别特征会拆分为两个独立的特征X_male,X_female。显然,这两个特征具有共同的性质:都属于性别。所以可以将这两个特征归在同一个Field下,即有相同的Field编号。不同域的特征之间,往往具有明显的差异性。对比FM中的做法,每个特征有且仅有一个隐向量,在对特征 xi,与其他特征进行交叉时,始终使用同一个隐向量Vi。

这种无差别式交叉方式,并没有考虑到不同特征之间的共性(同域)与差异性(异域)。

        FFM公式化定义如下:

        对比FM可以发现,二者之间的差异仅在于二阶交叉对应的隐向量。设数据集中Field的数目为F,那么对于每个特征xi拥有F个对应的隐向量,分别应用于与不同域特征进行交叉时。设隐向量维度为k,FFM二阶交叉项参数为nkF。

2. 求解

         由于引入了Field,公式(1)不能像FM那样进行改写,所以FFM模型进行 推断 时的时间复杂度为O(kn*n)。

3. 性能评估

     FFM 训练/推断 时间复杂度都为O(kn*n)。

4. 优缺点

优点:

  • 在高维稀疏性数据集中表现很好。
  • 相对FM模型精度更高,特征刻画更精细。

缺点:

  • 时间开销大。FFM时间复杂度为O(kn*n),FM时间复杂度为 O(kn)。
  • 参数多容易过拟合,必须设置正则化方法,以及早停的训练策略。

5. FFM对于数据集的要求 :

     为了使用FFM方法,所有的特征必须转换成“field_id:feat_id:value”格式,field_id代表特征所属field的编号,feat_id是特征编号,value是特征的值。

1)含有类别特征的数据集,且需要对特征进行二值化处理。

2)越是稀疏的数据集表现效果相较于其他模型更优。

3)FFM比较难应用于纯数值类型的数据集。

数据预处理 :

与FM一样,最好先进行特征归一化,再进行样本归一化。

超参数对于模型的影响 :

  1)FFM的隐向量维度远小于FM的隐向量维度,k对于模型的影响不大。​

​2)正则化系数 ​

如果lambda太大,容易导致模型欠拟合,反之容易过拟合。​

​3)在论文中,使用的是Adagrad优化器,全局学习率eta也是超参数。

如果eta​在一个较小的水平,则可以表现最佳。过大容易导致过拟合。过小容易欠拟合。

模型训练加速:

1)梯度分布计算;2)自适应学习率;3)多核并行计算;4)SSE3指令并行编程;

实验

核心代码如下:

class FFM(object):
    def __init__(self, vec_dim, feat_num, field_num, lr, lamda):
        self.vec_dim = vec_dim
        self.feat_num = feat_num
        self.field_num = field_num
        self.lr = lr
        self.lamda = lamda

        self._build_graph()

    def _build_graph(self):
        self.add_input()
        self.inference()

    def add_input(self):
        self.x = tf.placeholder(tf.float32, shape=[None, self.feat_num], name='input_x')
        self.y = tf.placeholder(tf.float32, shape=[None], name='input_y')

    def inference(self):
        with tf.variable_scope('linear_part'):
            w0 = tf.get_variable(name='bias', shape=[1], dtype=tf.float32)
            self.W = tf.get_variable(name='linear_w', shape=[self.feat_num], dtype=tf.float32)
            self.linear_part = w0 + tf.reduce_sum(tf.multiply(self.x, self.W), axis=1)
        with tf.variable_scope('interaction_part'):
            self.V = tf.get_variable(name='interaction_w', shape=[self.feat_num, self.field_num, self.vec_dim], dtype=tf.float32)
            self.interaction_part = tf.constant(0, dtype=tf.float32)
            for i in range(self.feat_num):
                for j in range(i+1, self.feat_num):
                    self.interaction_part += \
                        tf.reduce_sum(tf.multiply(self.V[i, field_map[j]], self.V[j, field_map[i]])) * \
                        tf.multiply(self.x[:, i], self.x[:, j])

        self.y_logits = self.linear_part + self.interaction_part
        self.y_hat = tf.nn.sigmoid(self.y_logits)
        self.pred_label = tf.cast(self.y_hat > 0.5, tf.int32)
        self.loss = -tf.reduce_mean(self.y*tf.log(self.y_hat+1e-8) + (1-self.y)*tf.log(1-self.y_hat+1e-8))
        self.reg_loss = self.lamda*(tf.reduce_mean(tf.nn.l2_loss(self.W)) + tf.reduce_mean(tf.nn.l2_loss(self.V)))
        self.total_loss = self.loss + self.reg_loss

        self.train_op = tf.train.AdamOptimizer(self.lr).minimize(self.total_loss)

 FFM 训练速度确实很慢=^~^=。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值