传统推荐算法(五) FFM模型(2) 原理及实现

传统推荐算法(五) FFM模型(2) 原理及实现文章目录 FFM 写在前面 1 FFM 基本原理 2 注意事项 2 1 省略零值特征 2 2 样本归一化 2 3 特征归一化 2 4 隐向量维度 2 5 参数量 2 6 时间复杂度 2 7SGD 寻优小技巧 3 tensorflow 实现参考公众号 FFM 写

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

写在前面:

FM算法被用来解决解决稀疏数据下的特征组合问题.它的改进有不少.[1]中提出了基于FM的PITF(pairwise interaction tensor factorization)方法做个性化标签推荐.在2012年KDD杯中,PITF的通用版本factor model(论文称为FFMs)[2]被提了出来.而作者认为FFMs只考虑了”用户”,”物品”和”标签”三个特征等一系列问题,而提出了更加通用的FFMs版本FFM(Field-aware Factorization Machines)[3].

1.FFM基本原理

传统推荐算法(五) FFM模型(2) 原理及实现
推荐中的数据one-hot编码后得到的稀疏数据一般如上图所示.每一行是一个样本,每一列就是一个特征,一个样本有多少维,就有多少个特征;维度分为几类(User, Movie, Time…),就有几个field(当然field可以自己定义,不按照样本特征原先的类来).首先回顾一下FM中对特征交叉的处理:
3.png
而FFM做了如下改进:


4.png

f2就是j2所属的那个field,就是one-hot编码前这个特征所在的类.看出来了吧,就是将原先的wj1更加细化,原先的xj1只对应一个隐向量wj1,现在隐向量要看xj2所在的field类进行选择,参数量增加了.

当然了,当xj1和xj2同时不为0时的特征交叉才有意义.代码中也可以根据这个进行优化.



2.注意事项

2.1 省略零值特征

零值特征相乘对结果无影响,实现过程中可以直接省略.

2.2 样本归一化

[8] 中指出,FFM默认是进行样本数据的归一化,否则很容易造成数据inf溢出.因此,样本层面的数据是推荐进行归一化的.

2.3 特征归一化

category类的特征one-hot编码中只取0或1,而continuous类的特征如果不作处理(比如10000),两者量值差距过大,很有可能因为量值差异造成不同特征对模型影响差距很大.

实际上,对于离散特征xi,其相关的隐向量wifj由其他所有非零的xj共同影响,当不同的xj之间量值差异很大,xifj很难同时照顾到”离群点xj”和其他xj.可能因此增加continuous类特征对模型影响,这是不合理的.

2.4 隐向量维度

2.5 参数量

假设样本特征有n维,共有f个field,每个隐向量有k维.那么交叉项的参数量就是nfk.FM中交叉项参数量是nk.但是如2.4所说,FFM的隐向量维度更低.比如FM可能是几十或几百维,FFM就几维或几十维.但当field过多时,还是FFM参数多(一般是这样),而[3]也证明其效果更好.

2.6 时间复杂度

在FM那篇文章中我们分析过,可以使用多重求和的一些公式将交叉项进行优化,将时间复杂度由O(kn2})降到O(kn).这里显然无法做类似优化.因此特征交叉这一部分的时间复杂度就是O(kn2).所以,同样使用SGD,FFM训练时间一般更长(原代码中还有个FM,两者一比,FFM确实慢了不少).

2.7 SGD寻优小技巧

[8] 中讲了几个优化SGD寻优的小技巧,包括梯度分步计算,自适应学习率,OpenMP多核并行计算,SSE3指令并行编程.先保存下来,回头慢慢看(并不会).

3. tensorflow实现

首先看看这个类怎么实现的,里面有三个方法.不到60行代码.

class FFM(object): # field_nums: F = 6 # feature_nums: N = 24 # embedding_size: k= 3 def __init__(self, hparams, df_i, df_v): self.hparams = hparams tf.set_random_seed(self.hparams.seed) self.line_result = self.line_section(df_i, df_v) self.fm_result = self.fm_section(df_i, df_v) print(self.line_result, self.fm_result) self.logits = self.line_result+self.fm_result 

线性项中使用到了df_i,shape为(?, 6), 以及df_v,shape为(?, 6).

样本有6个属性,都只取一个值,所以每个样本有6个非零值.正如文中所说,计算时可只取非零特征值计算进行优化,所以我们看到的df_i和df_v都只有6维,而不是24维.

 def line_section(self, df_i, df_v): ''' # df_i records the positon of i_th feature in 24 # df_v records the value of i_th feature ''' with tf.variable_scope('line'): weights = tf.get_variable('weights', shape=[self.hparams.feature_nums, 1], dtype=tf.float32, initializer=tf.initializers.glorot_uniform()) batch_weights = tf.nn.embedding_lookup(weights, df_i) # (*, 6, 1) batch_weights = tf.squeeze(batch_weights, axis=2) # remove dimensions of size 1 ==> (*, 6) line_result = tf.multiply(df_v, batch_weights, name='line_w_x') biase = tf.get_variable('biase', shape=[1,1], dtype=tf.float32, initializer=tf.initializers.zeros()) line_result = tf.add(tf.reduce_mean(line_result, axis=1, keepdims=True), biase) # (*, 1) return line_result 

看完了常数项和一次项,再看看交叉项,懂了原理后,代码一看就清楚了:

 def fm_section(self, df_i, df_v): with tf.variable_scope('fm'): embedding = tf.get_variable('embedding', shape=[self.hparams.field_nums, self.hparams.feature_nums, self.hparams.embedding_size], dtype=tf.float32, initializer=tf.initializers.random_normal()) fm_result = None for i in range(self.hparams.field_nums): for j in range(i+1, self.hparams.field_nums): vi_fj = tf.nn.embedding_lookup(embedding[j], df_i[:, i]) # (*, k) vj_fi = tf.nn.embedding_lookup(embedding[i], df_i[:, j]) # (*, k) wij = tf.reduce_sum(tf.multiply(vi_fj, vj_fi), axis=1, keepdims=True) # (*, 1) x_i = tf.expand_dims(df_v[:, i], 1) # (*, 1) x_j = tf.expand_dims(df_v[:, j], 1) # (*, 1) xij = tf.multiply(x_i, x_j) # (*, 1) if(fm_result == None): fm_result = tf.multiply(wij, xij) # (*, 1) else: fm_result += tf.multiply(wij, xij) return fm_result 

感兴趣可以跑一下完整代码,有数据集:

https://github.com/wyl6/Recommender-Systems-Samples/tree/master/RecSys%20Traditional/MF/FFM

参考

公众号

更多精彩内容请移步公众号:推荐算法工程师

传统推荐算法(五) FFM模型(2) 原理及实现

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

(0)
上一篇 2025-11-28 16:15
下一篇 2025-11-28 16:26

相关推荐

发表回复

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

关注微信