首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >机器学习算法实现解析——libFM之libFM的训练过程之SGD的方法

机器学习算法实现解析——libFM之libFM的训练过程之SGD的方法

作者头像
felixzhao
发布于 2019-01-31 08:22:17
发布于 2019-01-31 08:22:17
53900
代码可运行
举报
文章被收录于专栏:null的专栏null的专栏
运行总次数:0
代码可运行

本节主要介绍的是libFM源码分析的第五部分之一——libFM的训练过程之SGD的方法。

5.1、基于梯度的模型训练方法

在libFM中,提供了两大类的模型训练方法,一类是基于梯度的训练方法,另一类是基于MCMC的模型训练方法。对于基于梯度的训练方法,其类为fm_learn_sgd类,其父类为fm_learn类,主要关系为:

fm_learn_sgd类是所有基于梯度的训练方法的父类,其具体的代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "fm_learn.h"
#include "../../fm_core/fm_sgd.h"

// 继承自fm_learn
class fm_learn_sgd: public fm_learn {
    protected:
        //DVector<double> sum, sum_sqr;
    public:
        int num_iter;// 迭代次数
        double learn_rate;// 学习率
        DVector<double> learn_rates;// 多个学习率        

        // 初始化
        virtual void init() {       
            fm_learn::init();   
            learn_rates.setSize(3);// 设置学习率
        //  sum.setSize(fm->num_factor);        
        //  sum_sqr.setSize(fm->num_factor);
        }       

        // 利用梯度下降法进行更新,具体的训练的过程在其子类中
        virtual void learn(Data& train, Data& test) { 
            fm_learn::learn(train, test);// 该函数并没有具体实现
            // 输出运行时的参数,包括:学习率,迭代次数
            std::cout << "learnrate=" << learn_rate << std::endl;
            std::cout << "learnrates=" << learn_rates(0) << "," << learn_rates(1) << "," << learn_rates(2) << std::endl;
            std::cout << "#iterations=" << num_iter << std::endl;

            if (train.relation.dim > 0) {// 判断relation
                throw "relations are not supported with SGD";
            }
            std::cout.flush();// 刷新
        }

        // SGD重新修正fm模型的权重
        void SGD(sparse_row<DATA_FLOAT> &x, const double multiplier, DVector<double> &sum) {
            fm_SGD(fm, learn_rate, x, multiplier, sum);// 调用fm_sgd中的fm_SGD函数
        } 

        // debug函数,主要用于打印中间结果
        void debug() {
            std::cout << "num_iter=" << num_iter << std::endl;
            fm_learn::debug();          
        }

        // 对数据进行预测
        virtual void predict(Data& data, DVector<double>& out) {
            assert(data.data->getNumRows() == out.dim);// 判断样本个数是否相等
            for (data.data->begin(); !data.data->end(); data.data->next()) {
                double p = predict_case(data);// 得到线性项和交叉项的和,调用的是fm_learn中的方法
                if (task == TASK_REGRESSION ) {// 回归任务
                    p = std::min(max_target, p);
                    p = std::max(min_target, p);
                } else if (task == TASK_CLASSIFICATION) {// 分类任务
                    p = 1.0/(1.0 + exp(-p));// Sigmoid函数处理
                } else {// 异常处理
                    throw "task not supported";
                }
                out(data.data->getRowIndex()) = p;
            }               
        } 

};

fm_learn_sgd类中,主要包括五个函数,分别为:初始化init函数,训练learn函数,SGD训练SGD函数,debug的debug函数和预测predict函数。

5.1.1、初始化init函数

在初始化中,对学习率的大小进行了初始化,同时继承了父类中的初始化方法。

5.1.2、训练learn函数

learn函数中,没有具体的训练的过程,只是对训练中需要用到的参数进行输出,具体的训练的过程在其对应的子类中定义,如fm_learn_sgd_element类和fm_learn_sgd_element_adapt_reg类。

5.1.3、SGD训练SGD函数

SGD函数使用的是fm_sgd.h文件中的fm_SGD函数。fm_SGD函数是利用梯度下降法对模型中的参数进行调整,以得到最终的模型中的参数。在利用梯度下降法对模型中的参数进行调整的过程中,假设损失函数为ll,那么,对于回归问题来说,其损失函数为:

l=12(y^(i)−y(i))2

l=\frac{1}{2}\left ( \hat{y}^{(i)}-y^{(i)} \right )^2

对于二分类问题,其损失函数为:

l=−lnσ(y^(i)y(i))

l=-ln\sigma \left ( \hat{y}^{(i)}y^{(i)} \right )

其中,σ\sigma 为Sigmoid函数:

σ(x)=11+e(−x)

\sigma \left ( x \right )=\frac{1}{1+e^{\left ( -x \right )}}

对于σ(x)\sigma \left ( x \right ),其导函数为:

σ′=σ(1−σ)

{\sigma }'=\sigma \left ( 1-\sigma \right )

在可用SGD更新的过程中,首先需要计算损失函数的梯度,因此,对应于上述的回归问题和二分类问题,其中回归问题的损失函数的梯度为:

∂l∂θ=(y^(i)−y(i))⋅∂y^(i)∂θ

\frac{\partial l}{\partial \theta }=\left ( \hat{y}^{(i)}-y^{(i)} \right )\cdot \frac{\partial \hat{y}^{(i)}}{\partial \theta }

分类问题的损失函数的梯度为:

∂l∂θ=(σ(y^(i)y(i))−1)⋅y(i)⋅∂y^(i)∂θ

\frac{\partial l}{\partial \theta }=\left ( \sigma \left ( \hat{y}^{(i)}y^{(i)} \right )-1 \right )\cdot y^{(i)}\cdot \frac{\partial \hat{y}^{(i)}}{\partial \theta }

其中,λ\lambda 称为正则化参数,在具体的应用中,通常加上L2L_2正则,即:

∂l∂θ+λθ

\frac{\partial l}{\partial \theta }+\lambda \theta

在定义好上述的计算方法后,其核心的问题是如何计算∂y^(i)∂θ\frac{\partial \hat{y}^{(i)}}{\partial \theta },在“机器学习算法实现解析——libFM之libFM的模型处理部分”中已知:

y^:=w0+∑i=1nwixi+∑i=1n−1∑j=i+1n⟨vi,vj⟩xixj

\hat{y}:=w_0+\sum_{i=1}^{n}w_ix_i+\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}\left \langle \mathbf{v}_i,\mathbf{v}_j \right \rangle x_ix_j

因此,当y^\hat{y}分别对w0w_0,wiw_i以及vi,fv_{i,f}求偏导时,其结果分别为:

∂y^∂θ=⎧⎩⎨⎪⎪⎪⎪1xixi(∑j=1xjvj,f−xivi,f) if θ=w0 if θ=wi if θ=vi,f

\frac{\partial \hat{y}}{\partial \theta }=\begin{cases} 1 & \text{ if } \theta = w_0\ x_i & \text{ if } \theta = w_i\ x_i\left ( \sum _{j=1}x_jv_{j,f}-x_iv_{i,f} \right ) & \text{ if } \theta = v_{i,f} \end{cases}

在利用梯度的方法中,其参数θ\theta 的更新方法为:

θ=θ−η⋅(∂l∂θ+λθ)

\theta = \theta - \eta \cdot \left ( \frac{\partial l}{\partial \theta }+\lambda \theta \right )

其中,η \eta 为学习率,在libFM中,其具体的代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 利用SGD更新模型的参数
void fm_SGD(fm_model* fm, const double& learn_rate, sparse_row<DATA_FLOAT> &x, const double multiplier, DVector<double> &sum) {
    // 1、常数项的修正
    if (fm->k0) {
        double& w0 = fm->w0;
        w0 -= learn_rate * (multiplier + fm->reg0 * w0);
    }
    // 2、一次项的修正
    if (fm->k1) {
        for (uint i = 0; i < x.size; i++) {
            double& w = fm->w(x.data[i].id);
            w -= learn_rate * (multiplier * x.data[i].value + fm->regw * w);
        }
    }
    // 3、交叉项的修正
    for (int f = 0; f < fm->num_factor; f++) {
        for (uint i = 0; i < x.size; i++) {
            double& v = fm->v(f,x.data[i].id);
            double grad = sum(f) * x.data[i].value - v * x.data[i].value * x.data[i].value; 
            v -= learn_rate * (multiplier * grad + fm->regv * v);
        }
    }   
}

以上的更新的过程分别对应着上面的更新公式,其中multiplier变量分别对应着回归中的(y^(i)−y(i))\left ( \hat{y}^{(i)}-y^{(i)} \right )和分类中的(σ(y^(i)y(i))−1)⋅y(i)\left ( \sigma \left ( \hat{y}^{(i)}y^{(i)} \right )-1 \right )\cdot y^{(i)}。

5.1.4、预测predict函数

predict函数用于对样本进行预测,这里使用到了predict_case函数,该函数在“机器学习算法实现解析——libFM之libFM的训练过程概述”中有详细的说明,得到值后,分别对回归问题和分类问题做处理,在回归问题中,主要是防止超出最大值和最小值,在分类问题中,将其值放入Sigmoid函数,得到最终的结果。

5.2、SGD的训练方法

随机梯度下降法(Stochastic Gradient Descent ,SGD)是一种简单有效的优化方法。对于梯度下降法的更多内容,可以参见“梯度下降优化算法综述”。在利用SGD对FM模型训练的过程如下图所示:

在libFM中,SGD的实现在fm_learn_sgd_element.h文件中。在该文件中,定义了fm_learn_sgd_element类,fm_learn_sgd_element类继承自fm_learn_sgd类,主要实现了fm_learn_sgd类中的learn方法,具体的程序代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "fm_learn_sgd.h"

// 继承了fm_learn_sgd
class fm_learn_sgd_element: public fm_learn_sgd {
    public:
        // 初始化
        virtual void init() {
            fm_learn_sgd::init();
            // 日志输出
            if (log != NULL) {
                log->addField("rmse_train", std::numeric_limits<double>::quiet_NaN());
            }
        }
        // 利用SGD训练FM模型
        virtual void learn(Data& train, Data& test) {
            fm_learn_sgd::learn(train, test);// 输出参数信息

            std::cout << "SGD: DON'T FORGET TO SHUFFLE THE ROWS IN TRAINING DATA TO GET THE BEST RESULTS." << std::endl; 
            // SGD
            for (int i = 0; i < num_iter; i++) {// 开始迭代,每一轮的迭代过程
                double iteration_time = getusertime();// 记录开始的时间
                for (train.data->begin(); !train.data->end(); train.data->next()) {// 对于每一个样本
                    double p = fm->predict(train.data->getRow(), sum, sum_sqr);// 得到样本的预测值
                    double mult = 0;// 损失函数的导数
                    if (task == 0) {// 回归
                        p = std::min(max_target, p);
                        p = std::max(min_target, p);
                        // loss=(y_ori-y_pre)^2
                        mult = -(train.target(train.data->getRowIndex())-p);// 对损失函数求导
                    } else if (task == 1) {// 分类
                        // loss
                        mult = -train.target(train.data->getRowIndex())*(1.0-1.0/(1.0+exp(-train.target(train.data->getRowIndex())*p)));
                    }
                    // 利用梯度下降法对参数进行学习
                    SGD(train.data->getRow(), mult, sum);                   
                }               
                iteration_time = (getusertime() - iteration_time);// 记录时间差
                // evaluate函数是调用的fm_learn类中的方法
                double rmse_train = evaluate(train);// 对训练结果评估
                double rmse_test = evaluate(test);// 将模型应用在测试数据上
                std::cout << "#Iter=" << std::setw(3) << i << "\tTrain=" << rmse_train << "\tTest=" << rmse_test << std::endl;
                // 日志输出
                if (log != NULL) {
                    log->log("rmse_train", rmse_train);
                    log->log("time_learn", iteration_time);
                    log->newLine();
                }
            }       
        }

};

learn函数中,实现了SGD训练FM模型的主要过程,在实现的过程中,分别调用了SGD函数和evaluate函数,其中SGD函数如上面的5.1.3、SGD训练SGD函数小节所示,利用SGD函数对FM模型中的参数进行更新,evaluate函数如“机器学习算法实现解析——libFM之libFM的训练过程概述”中所示,evaluate函数用于评估学习出的模型的效果。其中mult变量分别对应着回归中的(y^(i)−y(i))\left ( \hat{y}^{(i)}-y^{(i)} \right )和分类中的(σ(y^(i)y(i))−1)⋅y(i)\left ( \sigma \left ( \hat{y}^{(i)}y^{(i)} \right )-1 \right )\cdot y^{(i)}。

参考文献

  • Rendle S. Factorization MachinesC// IEEE International Conference on Data Mining. IEEE Computer Society, 2010:995-1000.
  • Rendle S. Factorization Machines with libFMM. ACM, 2012.
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年06月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
机器学习算法实现解析——libFM之libFM的训练过程之SGD的方法
本节主要介绍的是libFM源码分析的第五部分之一——libFM的训练过程之SGD的方法。 5.1、基于梯度的模型训练方法 在libFM中,提供了两大类的模型训练方法,一类是基于梯度的训练方法,另一类是
felixzhao
2018/03/20
1.3K0
机器学习算法实现解析——libFM之libFM的训练过程之SGD的方法
机器学习算法实现解析——libFM之libFM的训练过程之Adaptive Regularization
本节主要介绍的是libFM源码分析的第五部分之二——libFM的训练过程之Adaptive Regularization的方法。
felixzhao
2019/01/31
7070
机器学习算法实现解析——libFM之libFM的训练过程之Adaptive Regularization
机器学习算法实现解析——libFM之libFM的训练过程之Adaptive Regularization
本节主要介绍的是libFM源码分析的第五部分之二——libFM的训练过程之Adaptive Regularization的方法。 5.3、Adaptive Regularization的训练方法 5.3.1、SGD的优劣 在“机器学习算法实现解析——libFM之libFM的训练过程之SGD的方法”中已经介绍了基于SGD的FM模型的训练方法,SGD的方法的最大优点是其训练过程很简单,只需在计算的过程中求解损失函数对每一个参数的偏导数,从而实现对模型参数的修改。 我们都知道,FM模型对正则化参数的选择比较敏感,
felixzhao
2018/03/20
1.5K0
机器学习算法实现解析——libFM之libFM的训练过程之Adaptive Regularization
机器学习算法实现解析——libFM之libFM的训练过程概述
本节主要介绍的是libFM源码分析的第四部分——libFM的训练。 FM模型的训练是FM模型的核心的部分。 4.1、libFM中训练过程的实现 在FM模型的训练过程中,libFM源码中共提供了四种训练的方法,分别为:Stochastic Gradient Descent(SGD),Adaptive SGD(ASGD),Alternating Least Squares(ALS)和Markov Chain Monte Carlo(MCMC),其中ALS是MCMC的特殊形式,实际上其实现的就是SGD,ASGD和
felixzhao
2018/03/20
1.6K0
机器学习算法实现解析——libFM之libFM的训练过程概述
机器学习算法实现解析——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 "../u
felixzhao
2018/03/20
1.5K0
机器学习算法实现解析——libFM之libFM的模型处理部分
【机器学习-监督学习】双线性模型
  从本文开始,我们介绍参数化模型中的非线性模型。在前几篇文章中,我们介绍了线性回归与逻辑斯谛回归模型。这两个模型都有一个共同的特征:包含线性预测因子
Francek Chen
2025/01/22
2860
【机器学习-监督学习】双线性模型
【机器学习基础】线性回归
  本文将逐步引入一些数学工具,讲解另一个较为简单的机器学习算法——线性回归(linear regression)。与上一篇文章介绍的k近邻算法不同,线性回归是一种基于数学模型的算法,其首先假设数据集中的样本与标签之间存在线性关系,再建立线性模型求解该关系中的各个参数。在实际生活中,线性回归算法因为其简单易算,在统计学、经济学、天文学、物理学等领域中都有着广泛应用。下面,我们从线性回归的数学描述开始,讲解线性回归的原理和实践。
Francek Chen
2025/01/22
3330
【机器学习基础】线性回归
「Machine Learning」梯度下降
一个风和日丽的周末,你成功登顶了泰山之巅,然而此时的喜悦还未尽兴。你却突然感觉肚子一阵隐痛,大事不妙💩。然后,坏消息是最近的厕所也在山下。
曼亚灿
2023/05/23
8640
「Machine Learning」梯度下降
简单易学的机器学习算法——梯度提升决策树GBDT
梯度提升决策树(Gradient Boosting Decision Tree,GBDT)算法是近年来被提及比较多的一个算法,这主要得益于其算法的性能,以及该算法在各类数据挖掘以及机器学习比赛中的卓越表现,有很多人对GBDT算法进行了开源代码的开发,比较火的是陈天奇的XGBoost和微软的LightGBM。
felixzhao
2019/01/31
7260
简单易学的机器学习算法——梯度提升决策树GBDT
【机器学习-监督学习】集成学习与梯度提升决策树
  本文将会首先介绍集成学习的思路以及一些常用的集成学习方法,然后介绍梯度提升决策树模型。在前面的文章中,我们讲解了许多不同的机器学习算法,每个算法都有其独特的优缺点。同时,对于同一个任务,往往有多种算法可以将其解决。例如我们要将平面上的一些点分类,假设算法一和算法二的正确率是75%,算法三是50%。3种算法都已经通过调参达到了其最优表现,已经无法再进一步了。那么,我们是否能通过组合这些算法,得到比75%更高的正确率呢?看上去组合之后,算法三会拖算法一和二的后腿,反而会拉低整体表现,更别说提升了。然而,我们考虑表1中的例子。
Francek Chen
2025/01/22
2210
【机器学习-监督学习】集成学习与梯度提升决策树
图解机器学习总结——2、回归
回归指的是对于训练数据集{xi,yi}\left \{\mathbf{ x}_i,y_i \right \},其中,yiy_i是连续值。用过学习,找到函数fθ(x)f_\theta \left ( \mathbf{ x}\right ),使得:
felixzhao
2019/02/14
4760
Factorization Machine
Factorization Machine [1] 是一种预测模型,广泛用于推荐系统,优点有: 适用于 SVM 无法应付的稀疏数据 FM (2-way) 比 LR 多了二阶 kernel,适用于大数据,线性复杂度,可以用 primal objective 而不是 dual objective 优化(如 SVM) 通用的预测模型,适用于任何实数特征。 下面是 [1] 的学习笔记。 Factorization Machine 假设训练数据集 DD 是高度稀疏的 D=\{(\textbf x^{(1)}, y^{
刘笑江
2018/05/28
5160
【机器学习与实现】逻辑回归分析
回归:因变量取连续值。例如一台4核CPU,3G内存的手机,跑分估计会是多少? 分类:因变量取离散值。例如这台手机的性能应分为哪一类 (高性能还是低性能) ?
Francek Chen
2025/01/23
2770
【机器学习与实现】逻辑回归分析
【机器学习与实现】线性回归分析
如果回归分析中包括两个或两个以上的自变量,且因变量和自变量之间是线性关系,则称为多元线性回归分析。
Francek Chen
2025/01/22
1490
【机器学习与实现】线性回归分析
【机器学习-监督学习】神经网络与多层感知机
  本文将会介绍机器学习中最重要的内容之一——神经网络(neural network,NN),它是深度学习的基础。神经网络的名称来源于生物中的神经元。自有计算机以来,人们就希望能让计算机具有和人类一样的智能,因此,许多研究者将目光放到了人类的大脑结构上。作为生物神经系统的基本单元,神经元在形成智能的过程中起到了关键作用。神经元的结构并不复杂,简单来说,神经元由树突、轴突和细胞体构成。图1是神经元的结构示意图。由其他神经元传来的神经脉冲在细胞间通过神经递质传输。神经递质被树突接收后,相应的神经信号传给细胞体,由细胞体进行处理并积累。当积累神经递质的兴奋性超过了某个阈值,就会触发一个动作电位,将新的信号传至轴突末梢的突触,释放神经递质给下一个神经元。生物的智能、运动等几乎所有生命活动的控制信号都由这些看似简单的神经元进行传输。
Francek Chen
2025/01/22
4470
【机器学习-监督学习】神经网络与多层感知机
图解机器学习 | XGBoost模型详解
教程地址:http://www.showmeai.tech/tutorials/34
ShowMeAI
2022/03/10
4.8K0
图解机器学习 | XGBoost模型详解
梯度下降法
梯度下降法(Gradient Descent)不是一种机器学习算法,而是是一种基于搜索的最优化方法,作用是最小化一个损失函数,例如在线性回归过程中,可以用梯度下降法来最小化损失函数,同样的,也可以用梯度上升法来最大化一个效用函数。
Hsinyan
2022/06/19
7320
梯度下降法
机器学习算法Python实现
目录 一、线性回归 1、代价函数 2、梯度下降算法 3、均值归一化 4、最终运行结果 5、使用scikit-learn库中的线性模型实现 二、逻辑回归 1、代价函数 2、梯度 3、正则化 4、S型函数(即) 5、映射为多项式 6、使用的优化方法 7、运行结果 8、使用scikit-learn库中的逻辑回归模型实现 逻辑回归_手写数字识别_OneVsAll 1、随机显示100个数字 2、OneVsAll 3、手写数字识别 4、预测 5、运行结果 6、使用scikit-learn库中的逻辑回归模型实现 三、BP
企鹅号小编
2018/01/09
2.4K0
机器学习算法Python实现
机器学习笔记-coursera
\(A\)是矩阵 \(x_i\) 是单位特征向量 \(\lambda_i\)是特征值 \(\Lambda\) 是矩阵特征值
列夫托尔斯昊
2020/08/25
9210
机器学习笔记-coursera
神经网络
在说神经网络之前,我们讨论一下神经元(Neurons),它是神经网络的基本单元。神经元先获得输入,然后执行某些数学运算后,再产生一个输出。比如一个2输入神经元的例子:
EltonZheng
2021/01/26
6140
神经网络
推荐阅读
相关推荐
机器学习算法实现解析——libFM之libFM的训练过程之SGD的方法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档