机器学习算法实现解析——libFM之libFM的模型处理部分

本节主要介绍的是libFM源码分析的第三部分——libFM的模型处理。

3.1、libFM中FM模型的定义

libFM模型的定义过程中主要包括模型中参数的设置及其初始化,利用模型对样本进行预测。在libFM中,首先定义FM模型,在fm_model类中实现对FM模型的定义,fm_model类在“\libfm-1.42.src\src\fm_core\fm_model.h”中。在定义fm_model类之前,使用到了一些数据类:

#include "../util/matrix.h"
#include "../util/fmatrix.h"

#include "fm_data.h"

数据类的具体定义在“机器学习算法实现解析——libFM之libFM的数据处理部分”中定义。fm_model类的代码如下所示:

// fm_model模型类
class fm_model {
    private:
        DVector<double> m_sum, m_sum_sqr;// 分别对应着交叉项的中的两项
    public: //fm模型中的参数
        double w0;// 常数项
        DVectorDouble w;// 一次项的系数
        DMatrixDouble v;// 交叉项的系数矩阵

    public:
        // 属性
        // the following values should be set:
        uint num_attribute;// 特征的个数

        bool k0, k1;// 是否包含常数项和一次项
        int num_factor;// 交叉项因子的个数

        double reg0;// 常数项的正则参数
        double regw, regv;// 一次项和交叉项的正则系数

        double init_stdev;// 初始化参数时的方差
        double init_mean;// 初始化参数时的均值

        // 函数
        fm_model();// 构造函数,主要完成参数的初始化
        void debug();// debug函数
        void init();// 初始化函数,主要用于生成各维度系数的初始值
        // 对样本进行预测
        double predict(sparse_row<FM_FLOAT>& x);
        double predict(sparse_row<FM_FLOAT>& x, DVector<double> &sum, DVector<double> &sum_sqr);
};

3.2、FM的初始化

完成FM模型初始化过程主要包括两个部分:

  • 构造函数fm_model()
  • init()函数

构造函数fm_model()的具体实现如下所示:

// fm_model类的构造函数
fm_model::fm_model() {
    num_factor = 0;// 交叉项中因子的个数
    init_mean = 0;// 初始化的均值
    init_stdev = 0.01;// 初始化的方差
    reg0 = 0.0;// 常数项的正则化参数
    regw = 0.0;// 一次项的正则化参数
    regv = 0.0;// 交叉项的正则化参数 
    k0 = true;// 是否包含常数项
    k1 = true;// 是否包含一次项
}

init()函数的具体实现如下所示:

// 初始化fm模型的函数
void fm_model::init() {
    w0 = 0;// 常数项的系数
    w.setSize(num_attribute);// 设置一次项系数的个数
    v.setSize(num_factor, num_attribute);// 设置交叉项的矩阵大小
    w.init(0);// 初始化一次项系数为0
    v.init(init_mean, init_stdev);// 按照均值和方差初始化交叉项系数
    // 交叉项中的两个参数,设置其大小为num_factor
    m_sum.setSize(num_factor);
    m_sum_sqr.setSize(num_factor);
}

在初始化的过程中,除了基本的数据类型外,还涉及到自定义的三种数据类型,分别为:DVectorDouble,DMatrixDouble和DVector,这三种数据类型在“机器学习算法实现解析——libFM之libFM的数据处理部分”中有详细说明。

3.3、利用FM模型对样本进行预测

利用上面的计算公式,libFM中的两个函数的实现如下所示:

// 对样本进行预测,其中x表示的是一行样本
double fm_model::predict(sparse_row<FM_FLOAT>& x) {
    return predict(x, m_sum, m_sum_sqr);        
}

double fm_model::predict(sparse_row<FM_FLOAT>& x, DVector<double> &sum, DVector<double> &sum_sqr) {
    double result = 0;// 最终的结果
    // 第一部分
    if (k0) {// 常数项 
        result += w0;
    }

    // 第二部分
    if (k1) {// 一次项
        for (uint i = 0; i < x.size; i++) {// 对样本中的每一个特征
            assert(x.data[i].id < num_attribute);// 验证样本的正确性
            // w * x
            result += w(x.data[i].id) * x.data[i].value;
        }
    }

    // 第三部分
    // 交叉项,对应着公式,有两重循环
    for (int f = 0; f < num_factor; f++) {// 外层循环
        sum(f) = 0;
        sum_sqr(f) = 0;
        for (uint i = 0; i < x.size; i++) {
            double d = v(f,x.data[i].id) * x.data[i].value;
            sum(f) += d;
            sum_sqr(f) += d*d;
        }
        result += 0.5 * (sum(f)*sum(f) - sum_sqr(f));// 得到交叉项的值
    }
    return result;
}

在交叉项的计算过程中,sum(f)和sum_sqr(f)与公式中的对应关系为:

3.4、其他

剩下的代码便是debug函数,debug函数用于打印中间的结果,其具体的代码如下所示:

// debug函数,主要用于输出中间调试的结果
void fm_model::debug() {
    std::cout << "num_attributes=" << num_attribute << std::endl;// 特征的个数
    std::cout << "use w0=" << k0 << std::endl;//是否包含常数项
    std::cout << "use w1=" << k1 << std::endl;//是否包含一次项
    std::cout << "dim v =" << num_factor << std::endl;//交叉项中因子的个数
    std::cout << "reg_w0=" << reg0 << std::endl;//常数项的正则化参数
    std::cout << "reg_w=" << regw << std::endl;//一次项的正则化参数
    std::cout << "reg_v=" << regv << std::endl;//交叉项的正则化参数
    std::cout << "init ~ N(" << init_mean << "," << init_stdev << ")" << std::endl;//初始化的均值和初始化的方差
}

参考文献

  • Rendle S. Factorization Machines[C]// IEEE International Conference on Data Mining. IEEE Computer Society, 2010:995-1000.
  • Rendle S. Factorization Machines with libFM[M]. ACM, 2012.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python爬虫实战

感知机初探

感知机模型的假设空间:定义在特征空间中的所有线性分类模型(linear classification model)或线性分类器(linear classifie...

881
来自专栏机器学习养成记

随机森林(R语言)

随机森林可处理大量输入变量,并且可以得到变量重要性排序,在实际中,有广泛应用。本文简要展示R语言实现随机森林的示例代码,并通过F值判断模型效果。

2314
来自专栏用户2442861的专栏

python感知机实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haluoluo211/article/d...

3134
来自专栏null的专栏

简单易学的机器学习算法——K-Means++算法

一、K-Means算法存在的问题 由于K-Means算法的简单且易于实现,因此K-Means算法得到了很多的应用,但是从K-Means算法的过程中发现,K-Me...

3755
来自专栏机器学习算法原理与实践

感知机原理小结

    感知机可以说是最古老的分类方法之一了,在1957年就已经提出。今天看来它的分类模型在大多数时候泛化能力不强,但是它的原理却值得好好研究。因为研究透了感知...

862
来自专栏机器学习养成记

特征工程(一):前向逐步回归(R语言)

“ 建模过程中,选择合适的特征集合,可以帮助控制模型复杂度,防止过拟合等问题。为了选取最佳的特征集合,可以遍历所有的列组合,找出效果最佳的集合,但这样需要大量的...

41111
来自专栏Petrichor的专栏

opencv: 获取 图像属性 (源码)

  说明了读取的图片是一张 大小 为 (424, 600, 3) ,数据类型 为 uint8 ,像素总数 为 763200 的图片。

2151
来自专栏AI科技评论

开发 | 手把手教你用 TensorFlow 实现卷积神经网络(附代码)

AI科技评论按:本文作者徐凯文,原文载于作者个人博客,已获授权。 在知乎上看到一段介绍卷积神经网络的文章,感觉讲的特别直观明了,我整理了一下。首先介绍原理部分。...

3908
来自专栏小鹏的专栏

感知机--模型与策略

看到模型和策略,应该很快联想到了李航的《统计学习方法》,统计学习方法的三要素定义为:模型、策略、算法。 感知机 感知机是二分类的线性分类模型,输入为实例的...

2125
来自专栏闪电gogogo的专栏

《统计学习方法》笔记二 感知机

感知机(perceptron)是二分类的线性分类模型,输入为实例的特征向量,输出为实例的类别,取±1。感知机对应与输入空间中将实例划分为正负两类的分离超平面,属...

822

扫码关注云+社区

领取腾讯云代金券