satyrs

yuqing

  • home
  • leetcode
  • bilibili
  • categories
articles links about me
总字数 168.3k

satyrs

yuqing

  • home
  • leetcode
  • bilibili
  • categories

DeepFm

2021-03-08
字数:1.6k字 | 预计阅读时长:7分钟

背景

在推荐领域较流行的深度模型方案:

实战:阿里MLR、阿里DIN、阿里ESSM、京东强化学习推荐、facebook个性化推荐dlrm、Deep Neural Networks for YouTube Recommendations、华为DeepFM、google2016 wide&deep learning、googleDeep&Cross Network等。

DeepFm模型及进化:XDeepFM(deep进化)、AFM(加入attention)、FFM(field-aware)、PNN、FNN、NFM等。

其中,DeepFM在论文中通过大量实验证明,DeepFM的AUC和Logloss都优于目前的最好效果。效率上,DeepFM和目前最优的效果的深度模型相当。在Benchmark数据集和商业数据集上,DeepFM效果超过目前所有模型。

Q1:FM解决什么问题?

1、普通的线性模型,我们都是将各个特征独立考虑的,并没有考虑到特征与特征之间的相互关系。
为了表述特征间的相关性,我们采用多项式模型。

在多项式模型中,特征xi与xj的组合用xixj表示。为了简单起见,我们讨论二阶多项式模型。
2、与线性模型相比,FM的模型就多了后面特征组合的部分。
二项式

Q2:FM参数求解?

1、公式中,组合部分的特征相关参数共有n(n−1)/2个。在数据很稀疏的情况下xi,xj都不为0的情况非常少,这样将导致ωij无法通过训练得出。

为了求出ωij,我们对每一个特征分量xi引入辅助向量Vi=(vi1,vi2,⋯,vik)。然后,利用vivj^T对ωij进行求解。

引入V

2、如何求解V?

推导公式网上到处都有。

3、得到公式推导结果后,对w求导,梯度下降进行训练。

Q3:FFM?

公式:

ffm_gs

举例:

ffm

Q4:why DeepFm?

1、因子分解机(Factorization Machines, FM)通过对于每一维特征的隐变量内积来提取特征组合。最终的结果也非常好。
但是,虽然理论上来讲FM可以对高阶特征组合进行建模,但实际上因为计算复杂度的原因一般都只用到了二阶特征组合。
那么对于高阶的特征组合来说,通过多层的神经网络即DNN去解决。

2、One-hot类型的特征输入到DNN中,会导致网络参数太多。
如何解决这个问题呢,类似于FFM中的思想,将特征分为不同的field:让Dense Vector进行组合,来表示高阶特征。

field

3、但是低阶和高阶特征组合隐含地体现在隐藏层中,如果我们希望把低阶特征组合单独建模,然后融合高阶特征组合。
=>就得到了DeepFm。

Q5:what DeepFm?

1、有两种融合方式,分别为串行和并行的结构。
这里介绍并行结构。

structure
deepfm

2、emb部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#embeddings
#weights['feature_embeddings'] 存放的每一个值其实就是FM中的vik
weights['feature_embeddings'] = tf.Variable(
tf.random_normal([self.feature_size,self.embedding_size],0.0,0.01),
name='feature_embeddings')

weights['feature_bias'] = tf.Variable(tf.random_normal([self.feature_size,1],0.0,1.0),name='feature_bias')


# model
self.embeddings = tf.nn.embedding_lookup(self.weights['feature_embeddings'],self.feat_index) # N * F * K
feat_value = tf.reshape(self.feat_value,shape=[-1,self.field_size,1])
self.embeddings = tf.multiply(self.embeddings,feat_value)

如果是离散值,则embedding lookup之后,每个维度✖️1,连续值则✖️连续值。
✖️后的结果就是公式里的 Vi,f · Xi

3、dnn部分
为了更好的发挥DNN模型学习high-order特征的能力,文中设计了一套子网络结构,将原始的稀疏表示特征映射为稠密的特征向量。
子网络设计时的两个要点:

不同field特征长度不同,但是子网络输出的向量需具有相同维度;
利用FM模型的隐特征向量V作为网络权重初始化来获得子网络输出向量。文中将FM的预训练V向量作为网络权重初始化替换为直接将FM和DNN进行整体联合训练,从而实现了一个端到端的模型。 (即lookup)

4、fm

1
2
3
4
5
6
7
8
9
10
11
12
13
# second order term
# sum-square-part
self.summed_features_emb = tf.reduce_sum(self.embeddings,1) # None * k
self.summed_features_emb_square = tf.square(self.summed_features_emb) # None * K

# squre-sum-part
self.squared_features_emb = tf.square(self.embeddings)
self.squared_sum_features_emb = tf.reduce_sum(self.squared_features_emb, 1) # None * K

#second order
self.y_second_order = 0.5 * tf.subtract(self.summed_features_emb_square,self.squared_sum_features_emb)
self.y_second_order = tf.nn.dropout(self.y_second_order,self.dropout_keep_fm[1])

Q6:扩展,自定义算子?

比如我们输入是每个item的idor一些离散特征时候。需要对离散特征的各个值–>index构建一个table。然后每次输入转换成对应的index,再根据index去tf.nn.embedding_lookup。离散特征对应的weight dict大小,需要给个预估值,大一些,囊括各种离散、连续的取值总数。

这里就可以对tensorflow里的hashtable算子进行扩展。构建一个table,动态增长index,来了一个新的取值,就对应index++。

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Status Find(OpKernelContext* ctx, const Tensor& key, Tensor* value,
const Tensor& default_value) override {
// Grab the input tensor
const V default_val = default_value.flat<V>()(0);

const auto A = key.flat<K>();
// Create an output tensor
auto output_flat = value->flat<V>();

// Set all but the first element of the output tensor to 0.
const int N = A.size();
int pos = 0;

K find_key;
{
tf_shared_lock sl(mu_);
for (; pos < N; pos++) {
find_key = SubtleMustCopyIfIntegral(A(pos));
auto it = table_.find(find_key);
if(it == table_.end()) {
break;
} else {
output_flat(pos) = it->second;
}
}
}

if(pos < N) {
int64_t hsize;
mutex_lock l(mu_);
for(; pos < N; pos++) {
find_key = SubtleMustCopyIfIntegral(A(pos));
auto it = table_.find(find_key);
if(it == table_.end()) {
hsize = table_.size();
if(hsize >= max_size_) {
return errors::ResourceExhausted("max size limit");
}
table_.insert({find_key, hsize});
output_flat(pos) = hsize;
} else {
output_flat(pos) = it->second;
}
}
}

return Status::OK();
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import tensorflow as tf
from dynamic_unique_table import DynamicUniqueTable

table = DynamicUniqueTable(key_dtype=tf.string,
value_dtype=tf.int64,
default_value=-1,
max_ids=100)

with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(table.lookup("asdfetryuijkn")))
print(sess.run(table.lookup("hahahahah")))
print(sess.run(table.export()))
tf.train.Saver().save(sess, 'index_test_model2/')

相关命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
本地:
python pai/main.py --train_tables=./dub_train.csv --test_tables=./dub_test.csv --data_type=file --discrete_size=15 --continue_size=14 --epoch=30 --buckets=./ --save_predict=True
pai:
组件无法支持多张表输入, 直接在odps的sql页面执行:

PAI-name tensorflow1120_ext

-project algo_public
-Dscript='oss://datadrive.oss-cn-shanghai-internal.aliyuncs.com/tmp/tl_deepfm.tar.gz'
-DentryFile='pai/main.py'
-DgpuRequired=100
-Dtables='odps://ypp_recommend/tables/rec_dub_model_train_data_fit_normal,odps://ypp_recommend/tables/rec_dub_model_train_data_eval_normal'
-Dbuckets='oss://datadrive.oss-cn-shanghai-internal.aliyuncs.com/tmp/'
-Darn='acs:ram::1872928906167841:role/aliyunodpspaidefaultrole'
-DossHost="oss-cn-shanghai-internal.aliyuncs.com"
-DuserDefinedParameters="--train_tables=odps://ypp_recommend/tables/rec_dub_model_train_data_fit_normal--test_tables=odps://ypp_recommend/tables/rec_dub_model_train_data_eval_normal--discrete_size=20 --continue_size=49 --data_type=odps --input_need_hash=True --use_input_bn=False --epoch=100"

本文作者: yuqing wang
本文链接: https://satyrswang.github.io/2021/03/08/DeepFm/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!
赏

thanks for tips

支付宝
微信
  • dl
  • dl

扫一扫,分享到微信

微信分享二维码
flink
graphsage
© 2023 yuqing wang
Hexo Theme Yilia by Litten
  • articles
  • links
  • about me

tag:

  • 随笔
  • 算法
  • ml
  • 编程语言
  • python
  • dl
  • 金融经济
  • tensorflow源码
  • 工程
  • spring
  • c++
  • 论文
  • gpu
  • cuda
  • 训诫
  • dubbo
  • es
  • 流处理
  • 大数据
  • java
  • 并发
  • 英文积累
  • linux
  • mac
  • cheetsheet
  • 数据库
  • 索引
  • redis
  • 金融
  • 读后感
  • 分布式
  • 推荐系统
  • 方法论
  • 股市理论
  • 模型框架
  • 计算机
  • leetcode
  • 英文写作
  • 货银
  • 货币政策
  • 商业银行
  • 零散知识点
  • 破站
  • ky

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • github
  • jianshu
  • cnblogs
  • bilibili
  • youtube
  • uva
关心算法、cs、网络、投资, 闲听历史、看史评 wechat satyrsh