日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時間:2024/1/17 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 机器学习算法实现解析:libFM之libFM的训练过程之SGD的方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本節(jié)主要介紹的是libFM源碼分析的第五部分之一——libFM的訓(xùn)練過程之SGD的方法。

5.1、基于梯度的模型訓(xùn)練方法

在libFM中,提供了兩大類的模型訓(xùn)練方法,一類是基于梯度的訓(xùn)練方法,另一類是基于MCMC的模型訓(xùn)練方法。對于基于梯度的訓(xùn)練方法,其類為fm_learn_sgd類,其父類為fm_learn類,主要關(guān)系為:

?


?

fm_learn_sgd類是所有基于梯度的訓(xùn)練方法的父類,其具體的代碼如下所示:

#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;// 迭代次數(shù)double learn_rate;// 學(xué)習(xí)率DVector<double> learn_rates;// 多個學(xué)習(xí)率 // 初始化virtual void init() { fm_learn::init(); learn_rates.setSize(3);// 設(shè)置學(xué)習(xí)率// sum.setSize(fm->num_factor); // sum_sqr.setSize(fm->num_factor);} // 利用梯度下降法進(jìn)行更新,具體的訓(xùn)練的過程在其子類中virtual void learn(Data& train, Data& test) { fm_learn::learn(train, test);// 該函數(shù)并沒有具體實(shí)現(xiàn)// 輸出運(yùn)行時的參數(shù),包括:學(xué)習(xí)率,迭代次數(shù)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) {// 判斷relationthrow "relations are not supported with SGD";}std::cout.flush();// 刷新}// SGD重新修正fm模型的權(quán)重void SGD(sparse_row<DATA_FLOAT> &x, const double multiplier, DVector<double> &sum) {fm_SGD(fm, learn_rate, x, multiplier, sum);// 調(diào)用fm_sgd中的fm_SGD函數(shù)} // debug函數(shù),主要用于打印中間結(jié)果void debug() {std::cout << "num_iter=" << num_iter << std::endl;fm_learn::debug(); }// 對數(shù)據(jù)進(jìn)行預(yù)測virtual void predict(Data& data, DVector<double>& out) {assert(data.data->getNumRows() == out.dim);// 判斷樣本個數(shù)是否相等for (data.data->begin(); !data.data->end(); data.data->next()) {double p = predict_case(data);// 得到線性項(xiàng)和交叉項(xiàng)的和,調(diào)用的是fm_learn中的方法if (task == TASK_REGRESSION ) {// 回歸任務(wù)p = std::min(max_target, p);p = std::max(min_target, p);} else if (task == TASK_CLASSIFICATION) {// 分類任務(wù)p = 1.0/(1.0 + exp(-p));// Sigmoid函數(shù)處理} else {// 異常處理throw "task not supported";}out(data.data->getRowIndex()) = p;} } };

在fm_learn_sgd類中,主要包括五個函數(shù),分別為:初始化init函數(shù),訓(xùn)練learn函數(shù),SGD訓(xùn)練SGD函數(shù),debug的debug函數(shù)和預(yù)測predict函數(shù)。

5.1.1、初始化init函數(shù)

在初始化中,對學(xué)習(xí)率的大小進(jìn)行了初始化,同時繼承了父類中的初始化方法。

5.1.2、訓(xùn)練learn函數(shù)

在learn函數(shù)中,沒有具體的訓(xùn)練的過程,只是對訓(xùn)練中需要用到的參數(shù)進(jìn)行輸出,具體的訓(xùn)練的過程在其對應(yīng)的子類中定義,如fm_learn_sgd_element類和fm_learn_sgd_element_adapt_reg類。

5.1.3、SGD訓(xùn)練SGD函數(shù)

SGD函數(shù)使用的是fm_sgd.h文件中的fm_SGD函數(shù)。fm_SGD函數(shù)是利用梯度下降法對模型中的參數(shù)進(jìn)行調(diào)整,以得到最終的模型中的參數(shù)。在利用梯度下降法對模型中的參數(shù)進(jìn)行調(diào)整的過程中,假設(shè)損失函數(shù)為ll,那么,對于回歸問題來說,其損失函數(shù)為:

?

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

?

對于二分類問題,其損失函數(shù)為:

?

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

?

其中,σσ為Sigmoid函數(shù):

?

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

?

對于σ(x)σ(x),其導(dǎo)函數(shù)為:

?

σ′=σ(1?σ)σ′=σ(1?σ)

?

在可用SGD更新的過程中,首先需要計(jì)算損失函數(shù)的梯度,因此,對應(yīng)于上述的回歸問題和二分類問題,其中回歸問題的損失函數(shù)的梯度為:

?

?l?θ=(y^(i)?y(i))??y^(i)?θ?l?θ=(y^(i)?y(i))??y^(i)?θ

?

分類問題的損失函數(shù)的梯度為:

?

?l?θ=(σ(y^(i)y(i))?1)?y(i)??y^(i)?θ?l?θ=(σ(y^(i)y(i))?1)?y(i)??y^(i)?θ

?

其中,λλ稱為正則化參數(shù),在具體的應(yīng)用中,通常加上L2L2正則,即:

?

?l?θ+λθ?l?θ+λθ

?

在定義好上述的計(jì)算方法后,其核心的問題是如何計(jì)算?y^(i)?θ?y^(i)?θ,在“機(jī)器學(xué)習(xí)算法實(shí)現(xiàn)解析——libFM之libFM的模型處理部分”中已知:

?

y^:=w0+∑i=1nwixi+∑i=1n?1∑j=i+1n?vi,vj?xixjy^:=w0+∑i=1nwixi+∑i=1n?1∑j=i+1n?vi,vj?xixj

?

因此,當(dāng)y^y^分別對w0w0,wiwi以及vi,fvi,f求偏導(dǎo)時,其結(jié)果分別為:

?

?y^?θ=???????1xixi(∑j=1xjvj,f?xivi,f)?if?θ=w0?if?θ=wi?if?θ=vi,f?y^?θ={1?if?θ=w0xi?if?θ=wixi(∑j=1xjvj,f?xivi,f)?if?θ=vi,f

?

在利用梯度的方法中,其參數(shù)θθ的更新方法為:

?

θ=θ?η?(?l?θ+λθ)θ=θ?η?(?l?θ+λθ)

?

其中,ηη為學(xué)習(xí)率,在libFM中,其具體的代碼如下所示:

// 利用SGD更新模型的參數(shù) void fm_SGD(fm_model* fm, const double& learn_rate, sparse_row<DATA_FLOAT> &x, const double multiplier, DVector<double> &sum) {// 1、常數(shù)項(xiàng)的修正if (fm->k0) {double& w0 = fm->w0;w0 -= learn_rate * (multiplier + fm->reg0 * w0);}// 2、一次項(xiàng)的修正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、交叉項(xiàng)的修正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);}} }

以上的更新的過程分別對應(yīng)著上面的更新公式,其中multiplier變量分別對應(yīng)著回歸中的(y^(i)?y(i))(y^(i)?y(i))和分類中的(σ(y^(i)y(i))?1)?y(i)(σ(y^(i)y(i))?1)?y(i)。

5.1.4、預(yù)測predict函數(shù)

predict函數(shù)用于對樣本進(jìn)行預(yù)測,這里使用到了predict_case函數(shù),該函數(shù)在“機(jī)器學(xué)習(xí)算法實(shí)現(xiàn)解析——libFM之libFM的訓(xùn)練過程概述”中有詳細(xì)的說明,得到值后,分別對回歸問題和分類問題做處理,在回歸問題中,主要是防止超出最大值和最小值,在分類問題中,將其值放入Sigmoid函數(shù),得到最終的結(jié)果。

5.2、SGD的訓(xùn)練方法

隨機(jī)梯度下降法(Stochastic Gradient Descent ,SGD)是一種簡單有效的優(yōu)化方法。對于梯度下降法的更多內(nèi)容,可以參見“梯度下降優(yōu)化算法綜述”。在利用SGD對FM模型訓(xùn)練的過程如下圖所示:

?


?

在libFM中,SGD的實(shí)現(xiàn)在fm_learn_sgd_element.h文件中。在該文件中,定義了fm_learn_sgd_element類,fm_learn_sgd_element類繼承自fm_learn_sgd類,主要實(shí)現(xiàn)了fm_learn_sgd類中的learn方法,具體的程序代碼如下所示:

#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訓(xùn)練FM模型virtual void learn(Data& train, Data& test) {fm_learn_sgd::learn(train, test);// 輸出參數(shù)信息std::cout << "SGD: DON'T FORGET TO SHUFFLE THE ROWS IN TRAINING DATA TO GET THE BEST RESULTS." << std::endl; // SGDfor (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);// 得到樣本的預(yù)測值double mult = 0;// 損失函數(shù)的導(dǎo)數(shù)if (task == 0) {// 回歸p = std::min(max_target, p);p = std::max(min_target, p);// loss=(y_ori-y_pre)^2mult = -(train.target(train.data->getRowIndex())-p);// 對損失函數(shù)求導(dǎo)} else if (task == 1) {// 分類// lossmult = -train.target(train.data->getRowIndex())*(1.0-1.0/(1.0+exp(-train.target(train.data->getRowIndex())*p)));}// 利用梯度下降法對參數(shù)進(jìn)行學(xué)習(xí)SGD(train.data->getRow(), mult, sum); } iteration_time = (getusertime() - iteration_time);// 記錄時間差// evaluate函數(shù)是調(diào)用的fm_learn類中的方法double rmse_train = evaluate(train);// 對訓(xùn)練結(jié)果評估double rmse_test = evaluate(test);// 將模型應(yīng)用在測試數(shù)據(jù)上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函數(shù)中,實(shí)現(xiàn)了SGD訓(xùn)練FM模型的主要過程,在實(shí)現(xiàn)的過程中,分別調(diào)用了SGD函數(shù)和evaluate函數(shù),其中SGD函數(shù)如上面的5.1.3、SGD訓(xùn)練SGD函數(shù)小節(jié)所示,利用SGD函數(shù)對FM模型中的參數(shù)進(jìn)行更新,evaluate函數(shù)如“機(jī)器學(xué)習(xí)算法實(shí)現(xiàn)解析——libFM之libFM的訓(xùn)練過程概述”中所示,evaluate函數(shù)用于評估學(xué)習(xí)出的模型的效果。其中mult變量分別對應(yīng)著回歸中的(y^(i)?y(i))(y^(i)?y(i))和分類中的(σ(y^(i)y(i))?1)?y(i)(σ(y^(i)y(i))?1)?y(i)。

參考文獻(xiàn)

  • 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.

--------------------- 本文來自 zhiyong_will 的CSDN 博客 ,全文地址請點(diǎn)擊:https://blog.csdn.net/google19890102/article/details/72866334?utm_source=copy

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的机器学习算法实现解析:libFM之libFM的训练过程之SGD的方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。