大家好,欢迎来到IT知识分享网。
基于域的分解机模型(FFM)
目录
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敏感特性,可以导出其模型表达式:
其中,fj是第j个特征所属的field。如果隐向量的长度为k,那么FFM的二交叉项参数就有nfk个,远多于FM模型的nk个。此外,由于隐向量与field相关,FFM的交叉项并不能够像FM那样做化简,其预测复杂度为O()。
对于上面的数据来说
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 |
其中,红色表示Field编码,蓝色表示Feature编码,绿色表示样本的组合特征取值。二阶交叉项的系数是通过与Field相关的隐向量的内积得到的,具体可见下图。
其损失函数定义为:
其中m为样本总个数,采用的loss为logloss,y的取值为-1和1。
2、FFM优化
这里使用AdaGrad优化算法去求解参数,因为目前一些研究显示了该算法在矩阵分解上的有效性,矩阵分解属于FFM的一个特例。具体训练方法如下:
在随机梯度的每一步中,对数据点(x,y)进行采样,并更新上面公式中的{x_{i}}{x_{j}}”>。因为X在CTR中是onehot表示,而且非常稀疏的,这里只更新有非零值的维度。
使用AdaGrad去优化式子,x是稀疏的,只去更新那些x数据中非0项
对每个隐向量的维度d ,累积梯度平方的和:
η是超参数,需要人工去指定, 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")
可以看到预测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