• 初学推荐系统-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]
    
    你不逼自己一把,你永远都不知道自己有多优秀!只有经历了一些事,你才会懂得好好珍惜眼前的时光!
  • 相关阅读:
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 802 找到最终的安全状态 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    Java实现 LeetCode 803 打砖块 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    Java实现 LeetCode 803 打砖块 (DFS)
    Java实现 LeetCode 804 唯一摩尔斯密码词 (暴力)
    英文标点
    post sharp 与log4net 结合使用,含执行源码 转拷
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/13888220.html
Copyright © 2020-2023  润新知