FFM原理及python实战[亲测有效]

FFM原理及python实战[亲测有效]基于域的分解机模型(FFM)1、FFM的理解场感知分解机器(Field-awareFactorizationMachine,简称FFM)最初的概念来自于Yu-ChinJuan与其比赛队员,它们借鉴了辣子MichaelJahrer的论文中field概念,提出了FM的升级版模型。通过引入field的概念,FFM把相同性质的特征归于同一个field。给出一下输入数据: …

大家好,欢迎来到IT知识分享网。

基于域的分解机模型(FFM)

目录

1、FFM的理解

2、FFM优化

3、优缺点

4. 使用FFM需要注意的地方

5、python实战


1、FFM的理解

场感知分解机器(Field-aware Factorization Machine ,简称FFM)最初的概念来自于Yu-Chin Juan与其比赛队员,它们借鉴了辣子Michael Jahrer的论文中field概念,提出了FM的升级版模型。通过引入field的概念,FFM把相同性质的特征归于同一个field。

给出一下输入数据:

User

Movie

Genre

Price

YuChin

3Idiots

Comedy, Drama

$9.9

对于上面表格中的genre有两个属性Comedy, Drama,那么这两个特征因该属于一个field—Genre。

在FFM中,每一维特征Xi,针对其它特征的每一种field fj,都会学习一个隐向量Vi,fj。因此,隐向量不仅与特征相关,也与field相关。

假设每条样本的n个特征属于f个field,那么FFM的二次项有nf个隐向量。而在FM模型中,每一维特征的隐向量只有一个。因此可以把FM看作是FFM的特例,即把所有的特征都归属到一个field是的FFM模型。根据FFM的field敏感特性,可以导出其模型表达式:

FFM原理及python实战[亲测有效]

其中,fj是第j个特征所属的field。如果隐向量的长度为k,那么FFM的二交叉项参数就有nfk个,远多于FM模型的nk个。此外,由于隐向量与field相关,FFM的交叉项并不能够像FM那样做化简,其预测复杂度为O(kn^2)。

对于上面的数据来说

PS:对于数值型特征,实际应用中通常会把价格划分为若干个区间(即连续特征离散化),然后再one-hot编码,当然不是所有的连续型特征都要做离散化,比如某广告位、某类广告/商品、抑或某类人群统计的历史CTR(pseudo-CTR)通常无需做离散化。

该条记录可以编码为5个数值特征,即User^YuChin, Movie^3Idiots, Genre^Comedy, Genre^Drama, Price^9.9。其中Genre^Comedy, Genre^Drama属于同一个field。为了说明FFM的样本格式,我们把所有的特征和对应的field映射成整数编号。

 

Field Name

Field Index

Feature Name

Feature Index

User

1

User^YuChin

1

Movie

2

Movie^3Idiots

2

Genre

3

Genre^Comedy

3

Price

4

Genre^Drama

4

 

 

Price^9.9

5

 FFM原理及python实战[亲测有效]

其中,红色表示Field编码,蓝色表示Feature编码,绿色表示样本的组合特征取值。二阶交叉项的系数是通过与Field相关的隐向量的内积得到的,具体可见下图。

FFM原理及python实战[亲测有效]

 

其损失函数定义为:

FFM原理及python实战[亲测有效]

其中m为样本总个数,采用的loss为logloss,y的取值为-1和1。

2、FFM优化

这里使用AdaGrad优化算法去求解参数,因为目前一些研究显示了该算法在矩阵分解上的有效性,矩阵分解属于FFM的一个特例。具体训练方法如下:

在随机梯度的每一步中,对数据点(x,y)进行采样,并更新上面公式中的FFM原理及python实战[亲测有效]{x_{i}}{x_{j}}”>。因为X在CTR中是onehot表示,而且非常稀疏的,这里只更新有非零值的维度。

FFM原理及python实战[亲测有效]

FFM原理及python实战[亲测有效]

使用AdaGrad去优化式子,x是稀疏的,只去更新那些x数据中非0项

对每个隐向量的维度d ,累积梯度平方的和:

FFM原理及python实战[亲测有效]

η是超参数,需要人工去指定, W的初始化是通过从均匀分布[0,1/√k]中随机采样,为了防止√γ的值过大,γ的初始值设置为1。

可以看出,随着迭代的进行,每个参数的历史梯度会慢慢累加,导致每个参数的学习率逐渐减小。另外,每个参数的学习率更新速度是不同的,与其历史梯度有关,根据AdaGrad的特点,对于样本比较稀疏的特征,学习率高于样本比较密集的特征,因此每个参数既可以比较快速达到最优,也不会导致验证误差出现很大的震荡。

 

3、优缺点

FFM优点: 
增加field的概念,同一特征针对不同field使用不同隐向量,模型建模更加准确

FFM缺点: 
计算复杂度比较高,参数个数为nfk,计算复杂度为O(kn2)  

 

4. 使用FFM需要注意的地方

•样本归一化。对样本进行归一化,否则容易造成数据溢出,梯度计算失败

•特征归一化。为了消除不同特征取值范围不同造成的问题,需要对特征进行归一化

•Early stopping。一定要设置该策略,FFM很容易过拟合

•省略零值特征。零值特征对模型没有任何贡献,省略零值特征,可以提高FFM模型训练和预测的速度,这也是稀疏样本采用FFM的显著优势

 

5、python实战

我们这里使用iris_data数据集进行测试

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
#下载数据
iris_data = load_iris()
X = iris_data['data']
y = iris_data['target'] == 2
X_train,X_test,y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=0)
#处理数据,转化成dataframe格式,并转换成整型
data_train=pd.DataFrame(X_train, columns=['x1','x2','x3','x4'])
data_test=pd.DataFrame(X_test, columns=['x1','x2','x3','x4'])

data_train['int1'] = data_train['x1'].map(int)
data_train['int2'] = data_train['x2'].map(int)
data_train['int3'] = data_train['x3'].map(int)
data_train['int4'] = data_train['x4'].map(int)
data_train['clicked'] = y_train*1

data_test['int1'] = data_test['x1'].map(int)
data_test['int2'] = data_test['x2'].map(int)
data_test['int3'] = data_test['x3'].map(int)
data_test['int4'] = data_test['x4'].map(int)
data_test['clicked'] = y_test*1

#整合数据
data_train = data_train[['int1','int2','int3','clicked']]
data_test = data_test[['int1','int2','int3','clicked']]

#转换成libffm format:
#即:label,field_1:index_1:value_1,field_2:index_2:value_2 ...
ffm_fit = FFMFormatPandas()

ffm_train_data = ffm_fit.fit_transform(data_train, y='clicked')
ffm_test_data = ffm_fit.fit_transform(data_test, y='clicked')

import os
cwd = os.getcwd()#获取当前路径
train_data = cwd + '/ffm_train_data.txt'#创建一个TXT文件
test_data = cwd + '/ffm_test_data.txt'#创建一个TXT文件

f=open(train_data,'w')
for line in ffm_train_data:
	data=line+"\n"
	f.write(data)#写入

f1=open(test_data,'w')
for line in ffm_test_data:
    data1 = line+"\n"
    f1.write(data1)#写入

使用xlearn进行训练

#通过 pip 安装 xLearn
- brew install cmake
- sudo pip install xlearn
import xlearn as xl

# Training task
ffm_model = xl.create_ffm()                # Use field-aware factorization machine (ffm)
ffm_model.setTrain("./ffm_train_data.txt")    # Set the path of training dataset
ffm_model.setValidate("./ffm_test_data.txt")  # Set the path of validation dataset

# Parameters:
#  0. task: binary classification
#  1. learning rate: 0.2
#  2. regular lambda: 0.002
#  3. evaluation metric: accuracy
param = {'task':'binary', 'lr':0.2, 'lambda':0.002, 'metric':'acc'}

# Start to train
# The trained model will be stored in model.out
ffm_model.setTXTModel("./irismodel.txt")
ffm_model.fit(param, './irismodel.out')

# Prediction task
ffm_model.setTest("./ffm_test_data.txt")  # Set the path of test dataset
ffm_model.setSigmoid()                 # Convert output to 0-1

# Start to predict
# The output result will be stored in output.txt
ffm_model.predict("./irismodel.out", "./irisoutput.txt")

FFM原理及python实战[亲测有效]

可以看到预测acc=0.91

我们用FM模型做一下对比

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from pyfm import pylibfm
from sklearn.feature_extraction import DictVectorizer

def load_data():
    """
    调用sklearn的iris数据集,筛选正负样本并构造切分训练测试数据集
    """
    iris_data = load_iris()
    X = iris_data['data']
    y = iris_data['target'] == 2
    data = [ {v: k for k, v in dict(zip(i, range(len(i)))).items()}  for i in X]
    X_train,X_test,y_train, y_test = train_test_split(data,y, test_size=0.3, random_state=0)
    return X_train,X_test,y_train, y_test

X_train,X_test,y_train, y_test = load_data()

v = DictVectorizer()
X_train = v.fit_transform(X_train)
X_test = v.transform(X_test)

fm = pylibfm.FM(num_factors=2, 
                num_iter=20, 
                verbose=True, 
                task="classification", 
                initial_learning_rate=0.01, 
                learning_rate_schedule="optimal")

fm.fit(X_train, y_train)

y_preds = fm.predict(X_test)
y_preds_label = y_preds > 0.5
from sklearn.metrics import log_loss,accuracy_score
print ("Validation log loss: %.4f" % log_loss(y_test, y_preds))
print ("accuracy: %.4f" % accuracy_score(y_test, y_preds_label))
Validation log loss: 0.3590
accuracy: 0.7556

而且这里我们FFM的lr=0.2,FM的lr=0.01

FFM确实比FM更精准一些

 

 

参考:

https://zhuanlan.zhihu.com/p/50692817

https://xlearn-doc-cn.readthedocs.io/en/latest/index.html

 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/24639.html

(0)
上一篇 2023-08-17 18:33
下一篇 2023-08-18 20:45

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信