初学推荐系统-04-FM (因子分解机:多特征的二阶特征交叉)

5 FM模型的引入

5.1.1 逻辑回归模型的及其缺点

FM模型其实就是一种思路,具体应用较少。

一般来说做推荐CTR预估时最简单的思路是将特征做线性组合(逻辑回归LR),传入sigmod中得到一个概率值,本质上是一个线性模型;也就是LR的缺点有:

  1. 这是一个线性模型
  2. 每个特征对最终输出的结果独立,需要手动进行特征交叉(xi*xj),比较麻烦。

5.1.2 改进,以及FM的引入

由于LR模型的上述缺陷(主要是手动做特征交叉比较麻烦),干脆就考虑所有的二阶交叉项,也就是将目标函数由原来的

[y = w_0+sum_{i=1}^nw_ix_i ]

改为

[y = w_0+sum_{i=1}^nw_ix_i+sum_{i=1}^{n-1}sum_{i+1}^nw_{ij}x_ix_j ]

但这个式子有一个问题,只有当(x_i)(x_j)均不为0时这个二阶交叉项才会生效,后面这个特征交叉项本质是和多项式核SVM等价的.

FM模型使用了如下的优化函数,事实上做的唯一改动就是把(w_{ij})替换成了(lt v_i,v_jgt),这实际上就有深度学习的意味在里面了,实质上就是给每个(x_i)计算一个embedding,然后将两个向量之间的embedding做内积得到之前所谓的(w_{ij})好处就是这个模型泛化能力强 ,即使两个特征之前从未在训练集中同时出现,我们也不至于像之前一样训练不出(w_{ij}),事实上只需要(x_i)和其他的(x_k)同时出现过就可以计算出(x_i)的embedding:

[y = w_0+sum_{i=1}^nw_ix_i+sum_{i=1}^{n}sum_{i+1}^nlt v_i,v_jgt x_ix_j ]

说明:

  1. (omega_{0})为全局偏置;
  2. (omega_{i})是模型第i个变量的权重;
  3. (omega_{ij} = < v_{i}, v_{j}>) 特征i和j的交叉权重;
  4. (v_{i}) 是第i维特征的隐向量;
  5. $ <cdot, cdot>$ 代表向量点积;
  6. (k(k<<n)) 为隐向量的长度,包含 k 个描述特征的因子。
  7. embedding 有词嵌入的意思,它的其中一个作用是将稀疏向量变成了稠密的向量。

5.3. FM模型的应用

最直接的想法就是直接把FM得到的结果放进sigmoid中输出一个概率值,由此做CTR预估,事实上我们也可以做召回。

由于FM模型是利用两个特征的Embedding做内积得到二阶特征交叉的权重,那么我们可以将训练好的FM特征取出离线存好,之后用来做KNN(邻域算法)向量检索。

工业应用的具体操作步骤:

  • 离线训练好FM模型(学习目标可以是CTR)
  • 将训练好的FM模型Embedding取出
  • 将每个uid对应的Embedding做avg pooling(平均)形成该用户最终的Embedding,item也做同样的操作
  • 将所有的Embedding向量放入Faiss等
  • 线上uid发出请求,取出对应的user embedding,进行检索召回

5.4 调包实现

# -*- coding: utf-8 -*-
# 第一步安装,调包
from pyfm import pylibfm
from sklearn.feature_extraction import DictVectorizer
import numpy as np

if __name__ == '__main__':
    # 第二步:创建训练集并转换成one-hot编码的特征形式
    train = [
        {"user": "1", "item": "5", "age": 19},
        {"user": "2", "item": "43", "age": 33},
        {"user": "3", "item": "20", "age": 55},
        {"user": "4", "item": "10", "age": 20},
    ]
    # DictVectorizer() Transforms lists of feature-value mappings to vectors.
    dv = DictVectorizer()
    X = dv.fit_transform(train)
    print(X.toarray())

    # 第三步:创建标签, 这里简单创建了一个全1的标签:
    y = np.repeat(1.0, X.shape[0])

    # 第四步:训练并预测, 就和调用sklearn的包是一样的用法:
    fm = pylibfm.FM()
    fm.fit(X,y)
    ret= fm.predict(dv.transform({"user": "1", "item": "10", "age": 24}))
    print(ret)

打印结果:

[[19.  0.  0.  0.  1.  1.  0.  0.  0.]
 [33.  0.  0.  1.  0.  0.  1.  0.  0.]
 [55.  0.  1.  0.  0.  0.  0.  1.  0.]
 [20.  1.  0.  0.  0.  0.  0.  0.  1.]]
Creating validation dataset of 0.01 of training for adaptive regularization
-- Epoch 1
Training log loss: 0.36855
[0.99034247]
你不逼自己一把,你永远都不知道自己有多优秀!只有经历了一些事,你才会懂得好好珍惜眼前的时光!
原文地址:https://www.cnblogs.com/zhazhaacmer/p/13888220.html