推荐算法之FM

1.模型原理

因子分解机模型(Factorization Machine)出现之前的传统的处理方法是人工特征工程加上线性模型(如逻辑回归Logistic Regression)。为了提高模型效果,关键技术是找到到用户点击行为背后隐含的特征组合。如男性、大学生用户往往会点击游戏类广告,因此 “男性且是大学生且是游戏类” 的特征组合就是一个关键特征。但这本质仍是线性模型,其假设函数表示成内积形式一般为:
y l i n e a r = σ ( < w ⃗ , x ⃗ > ) y_{linear} = \sigma(<\vec{w},\vec{x}>) ylinear=σ(<w ,x >)

其中 x ⃗ \vec{x} x 为特征向量, w ⃗ \vec{w} w 为权重向量, σ \sigma σ为sigmoid函数。

FM
人工进行特征组合通常会存在诸多困难,如特征爆炸、特征难以被识别、组合特征难以设计等。为了让模型自动地考虑特征之间的二阶组合信息,线性模型推广为二阶多项式 2 d − P o l y n o m i a l 2d−Polynomial 2dPolynomial模型:
y p o l y = σ ( < w ⃗ , x ⃗ > + ∑ i = 1 n ∑ j = 1 n w i j ⋅ x i ⋅ y i ) y_{poly}=\sigma\big(<\vec{w},\vec{x}>+\sum_{i=1}^n\sum_{j=1}^nw_{ij}\cdot x_i \cdot y_i\big) ypoly=σ(<w ,x >+i=1nj=1nwijxiyi)
就是对特征两两相乘(组合)构成新特征(离散化之后其实就是“且”操作),并对每个新特征分配独立的权重,通过机器学习来自动得到这些权重。将其写成矩阵形式为:
y p o l y = σ ( w ⃗ T ⋅ x ⃗ + x ⃗ T ⋅ W ( 2 ) ⋅ x ⃗ ) y_{poly}=\sigma(\vec{w}^T \cdot \vec{x}+ \vec{x}^T \cdot W^{(2)} \cdot \vec{x}) ypoly=σ(w Tx +x TW(2)x )
其中 W ( 2 ) W^{(2)} W(2)为二阶特征组合的权重矩阵,是对称矩阵。而这个矩阵参数非常多,为 O ( n 2 ) O (n^2) O(n2) 。为了降低该矩阵的维度,可以将其因子分解(Factorization)为两个低维(比如 n ∗ k n∗k nk)矩阵的相乘。则此时W矩阵的参数就大幅降低,为 O ( n k ) O(nk) O(nk)。公式如下:
W ( 2 ) = W T ⋅ W W^{(2)} = W^T \cdot W W(2)=WTW
FM的矩阵形式公式如下:
y F M = σ ( w ⃗ T ⋅ x ⃗ + x ⃗ T ⋅ W T ⋅ W ⋅ x ⃗ ) y_{FM} = \sigma\big(\vec{w}^T \cdot \vec{x}+ \vec{x}^T \cdot W^T \cdot W \cdot \vec{x}\big) yFM=σ(w Tx +x TWTWx )
内积的形式:
y F M = σ ( < w ⃗ , x ⃗ > + < W ⋅ x ⃗ , W ⋅ x ⃗ > ) y_{FM} = \sigma(<\vec{w} , \vec{x}>+<{W} \cdot \vec{x},{W} \cdot \vec{x}>) yFM=σ(<w ,x >+<Wx ,Wx >)
可以将上式进一步改写成求和式的形式:
y F M = σ ( < w ⃗ , x ⃗ > + ∑ i = 1 n ∑ j = 1 n < x i ⋅ v j ⃗ , x j ⋅ v j ⃗ > ) y_{FM} = \sigma \big(<\vec{w} ,\vec{x}> +\sum_{i=1}^n\sum_{j=1}^n<x_i \cdot \vec{v_j},x_j \cdot \vec{v_j}>\big) yFM=σ(<w ,x >+i=1nj=1n<xivj ,xjvj >)
其中向量 v i ⃗ \vec{v_i} vi 是矩阵W 的第i列。为了去除重复项与特征平方项,上式可以进一步改写成更为常见的FM公式:
y F M = σ ( < w ⃗ , x ⃗ > + ∑ i = 1 n ∑ j = 1 n < v j ⃗ , v j ⃗ > x i ⋅ x j ) y_{FM} = \sigma \Big(<\vec{w} ,\vec{x}> +\sum_{i=1}^n\sum_{j=1}^n< \vec{v_j} ,\vec{v_j}>x_i \cdot x_j \Big) yFM=σ(<w ,x >+i=1nj=1n<vj ,vj >xixj)
对比二阶多项式模型,FM模型中特征两两相乘(组合)的权重是相互不独立的,它是一种参数较少但表达力强的模型。

本质上,FM引入隐向量,与矩阵分解用隐向量代表用户和物品的做法异曲同工。隐向量的引用使FM能更好地解决数据稀疏性的问题。

在工程方面,FM同样可以使用梯度下降法进行学习,不失灵活性和实时性,较容易实现线上服务。

2. 延伸

2.1 对比MLP+Embedding

FM公式的矩阵内积为 < w ⃗ , x ⃗ > + < W ⋅ x ⃗ , W ⋅ x ⃗ > <\vec{w} , \vec{x}>+<{W} \cdot \vec{x},{W} \cdot \vec{x}> <w ,x >+<Wx ,Wx >,发现 W ⋅ x ⃗ W \cdot \vec{x} Wx 部分就是将离散系数特征通过矩阵乘法降维成一个低维稠密向量。这个过程对神经网络来说就叫做embedding。

2.2 领域信息Field

对不同领域的离散特征分别进行嵌入,之后再进行二阶特征的向量内积。

3. FM的Tensorflow实现

class FM(Model):
    def __init__(self, input_dim=None, output_dim=1, factor_order=10, init_path=None, opt_algo='gd', learning_rate=1e-2,
                 l2_w=0, l2_v=0, random_seed=None):
        Model.__init__(self)
        # 一次、二次交叉、偏置项
        init_vars = [('w', [input_dim, output_dim], 'xavier', dtype),
                     ('v', [input_dim, factor_order], 'xavier', dtype),
                     ('b', [output_dim], 'zero', dtype)]
        self.graph = tf.Graph()
        with self.graph.as_default():
            if random_seed is not None:
                tf.set_random_seed(random_seed)
            self.X = tf.sparse_placeholder(dtype)
            self.y = tf.placeholder(dtype)
            self.vars = init_var_map(init_vars, init_path)

            w = self.vars['w']
            v = self.vars['v']
            b = self.vars['b']
            
            # [(x1+x2+x3)^2 - (x1^2+x2^2+x3^2)]/2
            # 先计算所有的交叉项,再减去平方项(自己和自己相乘)
            X_square = tf.SparseTensor(self.X.indices, tf.square(self.X.values), tf.to_int64(tf.shape(self.X)))
            xv = tf.square(tf.sparse_tensor_dense_matmul(self.X, v))
            p = 0.5 * tf.reshape(
                tf.reduce_sum(xv - tf.sparse_tensor_dense_matmul(X_square, tf.square(v)), 1),
                [-1, output_dim])
            xw = tf.sparse_tensor_dense_matmul(self.X, w)
            logits = tf.reshape(xw + b + p, [-1])
            self.y_prob = tf.sigmoid(logits)

            self.loss = tf.reduce_mean(
                tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=self.y)) + \
                        l2_w * tf.nn.l2_loss(xw) + \
                        l2_v * tf.nn.l2_loss(xv)
            self.optimizer = get_optimizer(opt_algo, learning_rate, self.loss)

            #GPU设定
            config = tf.ConfigProto()
            config.gpu_options.allow_growth = True
            self.sess = tf.Session(config=config)
            # 图中所有variable初始化
            tf.global_variables_initializer().run(session=self.sess)

3. 参考

  • 王喆,深度学习推荐系统
  • 寒小阳博客
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值