机器学习算法实现解析——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);
};
FM模型的一般形式如下所示:
其中,w0为常数项系数,wi为一次项系数,vi和vj为交叉项系数。对于交叉项系数vi,其具体的形式为:
在FM模型的定义中,首先需要分别定义三个参数:w0,w和v。其次,需要定义模型中需要使用到的函数,包括初始化init
函数和预测predict
函数。
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中,fm_model类
中实现了两种预测函数,分别为:
double predict(sparse_row<FM_FLOAT>& x);
double predict(sparse_row<FM_FLOAT>& x, DVector<double> &sum, DVector<double> &sum_sqr);
两者的区别主要是下面的函数多了两个参数,一个是sum,另一个是sum_sqr,这两个参数分别对应着交叉项计算过程中的两项。
FM模型中的计算方法为:
其中,对于交叉项的计算,在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.
机器学习算法实现解析——libFM之libFM的模型处理部分的更多相关文章
- 机器学习算法实现解析——libFM之libFM的训练过程之Adaptive Regularization
本节主要介绍的是libFM源码分析的第五部分之二--libFM的训练过程之Adaptive Regularization的方法. 5.3.Adaptive Regularization的训练方法 5. ...
- 机器学习算法实现解析——libFM之libFM的训练过程之SGD的方法
本节主要介绍的是libFM源码分析的第五部分之一--libFM的训练过程之SGD的方法. 5.1.基于梯度的模型训练方法 在libFM中,提供了两大类的模型训练方法,一类是基于梯度的训练方法,另一类是 ...
- 机器学习算法实现解析——libFM之libFM的训练过程概述
本节主要介绍的是libFM源码分析的第四部分--libFM的训练. FM模型的训练是FM模型的核心的部分. 4.1.libFM中训练过程的实现 在FM模型的训练过程中,libFM源码中共提供了四种训练 ...
- 机器学习算法实现解析——word2vec源代码解析
在阅读本文之前,建议首先阅读"简单易学的机器学习算法--word2vec的算法原理"(眼下还没公布).掌握例如以下的几个概念: 什么是统计语言模型 神经概率语言模型的网络结构 CB ...
- scikit-learn中的机器学习算法封装——kNN
接前面 https://www.cnblogs.com/Liuyt-61/p/11738399.html 回过头来看这张图,什么是机器学习?就是将训练数据集喂给机器学习算法,在上面kNN算法中就是将特 ...
- 机器学习算法与Python实践之(四)支持向量机(SVM)实现
机器学习算法与Python实践之(四)支持向量机(SVM)实现 机器学习算法与Python实践之(四)支持向量机(SVM)实现 zouxy09@qq.com http://blog.csdn.net/ ...
- 机器学习算法与Python实践之(五)k均值聚类(k-means)
机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学 ...
- 机器学习算法与Python实践之(七)逻辑回归(Logistic Regression)
http://blog.csdn.net/zouxy09/article/details/20319673 机器学习算法与Python实践之(七)逻辑回归(Logistic Regression) z ...
- 机器学习算法( 五、Logistic回归算法)
一.概述 这会是激动人心的一章,因为我们将首次接触到最优化算法.仔细想想就会发现,其实我们日常生活中遇到过很多最优化问题,比如如何在最短时间内从A点到达B点?如何投入最少工作量却获得最大的效益?如何设 ...
随机推荐
- yum安装mysql5.6
1.检查系统是否安装其他版本的MYSQL数据 yum list installed | grep mysql yum -y remove mysql-libs.x86_64 2.安装及配置 wget ...
- Python(名称空间、函数嵌套、函数对象)
一.名称空间: 名称空间 定义:存放名字和值的绑定关系 内置名称空间 python自带的名字,如print.int.str 解释器启动就会生效 全局名称空间 文件级别定义的名字,都会放 ...
- Delphi 正则表达式起步
Delphi 正则表达式起步 在 Delphi 中使用正则表达式, 目前 PerlRegEx 应该是首选, 准备彻底而细致地研究它. 官方网站: http://www.regular-expressi ...
- python之路 JavaScript基础
一.JavaScript简介 JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为 浏览器的一部分,广泛用于客户端 ...
- HDU - 6393 Traffic Network in Numazu (LCA+RMQ+树状数组)
这道题相当于将这两题结合: http://poj.org/problem?id=2763 http://codeforces.com/gym/101808/problem/K 题意:有N各点N条边的带 ...
- NIO复习02
Selector 1. Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管 ...
- ijkplayer实现IMediaDataSource
由于ijkplayer不能识别android.resource类型的资源在播放raw中的文件的时候用IjkMediaPlayer不能正常播放,实现IMediaDataSource为IjkMediaPl ...
- Apache 服务常用命令
# 查看编译的模块文件httpd -lapachectl -l # 查看apache版本信息,操作系统位数,apr版本 httpd -Vapachectl -V # 查看编译过的模块,并查看哪一个是 ...
- java-json与js-json转化
js中将字符串转换成json的三种方式http://www.jb51.net/article/25987.htm JAVA对象转换为JSON字符串 http://blog.163.com/zzf_fl ...
- SqlServer、oracle、mysql分页的实现
我们在编写MIS系统和Web应用程序等系统时,都涉及到与数据库的交互,如果数据库中数据量很大的话,一次检索所有的记录,会占用系统很大的资源,因此我们常常采用,需要多少数据就只从数据库中取多少条记录,即 ...