diff --git a/models/rank/deepfm/readme.md b/models/rank/deepfm/readme.md index 4c7cfbdeb7abc7a5c876cc683525c25d0835d89a..e5e43331de1de9b540af19aaefe07ffbe489514d 100644 --- a/models/rank/deepfm/readme.md +++ b/models/rank/deepfm/readme.md @@ -43,6 +43,10 @@ year={2017} } ``` +在全量数据下模型的指标如下: +| 模型 | auc | batch_size | thread_num| epoch_num| Time of each epoch | +| :------| :------ | :------| :------ | :------| :------ | :------ | +| deepFM | 0.8044 | 1024 | 10 | 2 | 约3.5小时 | ## 数据准备 ### 数据来源 训练及测试数据集选用[Display Advertising Challenge](https://www.kaggle.com/c/criteo-display-ad-challenge/)所用的Criteo数据集。该数据集包括两部分:训练集和测试集。训练集包含一段时间内Criteo的部分流量,测试集则对应训练数据后一天的广告点击流量。 @@ -74,6 +78,28 @@ os : windows/linux/macos ``` python -m paddlerec.run -m models/rank/deepfm/config.yaml ``` +使用样例数据快速跑通的结果实例: +``` +PaddleRec: Runner train_runner Begin +Executor Mode: train +processor_register begin +Running SingleInstance. +Running SingleNetwork. +Warning:please make sure there are no hidden files in the dataset folder and check these hidden files:[] +Running SingleStartup. +Running SingleRunner. +2020-09-24 03:45:57,924-INFO: [Train] batch: 1, time_each_interval: 2.22s, BATCH_AUC: [0.43357143 0.4689441 0.43859649 0.42124542 0.44302615 0.44444444 + 0.48305085 0.47866667 0.48032407 0.45833333], AUC: [0.43357143 0.4562963 0.43859649 0.47866667 0.44302615 0.44444444 + 0.48305085 0.4562963 0.49451754 0.45833333] +epoch 0 done, use time: 2.38709902763, global metrics: BATCH_AUC=2.2195661068, AUC=[0.43357143 0.4689441 0.43859649 0.42124542 0.44302615 0.44444444 + 0.48305085 0.47866667 0.48032407 0.45833333] +2020-09-24 03:45:59,023-INFO: [Train] batch: 1, time_each_interval: 0.07s, BATCH_AUC: [0.4570095 0.45771188 0.45467121 0.47039474 0.46313874 0.45297619 + 0.46199579 0.45470861 0.47237934 0.47326632], AUC: [0.4570095 0.45771188 0.45575717 0.47039474 0.46313874 0.45297619 + 0.46199579 0.45470861 0.47237934 0.47326632] +epoch 1 done, use time: 0.0733981132507, global metrics: BATCH_AUC=0.0677909851074, AUC=[0.4570095 0.45771188 0.45467121 0.47039474 0.46313874 0.45297619 + 0.46199579 0.45470861 0.47237934 0.47326632] +PaddleRec Finish +``` ## 模型组网 @@ -88,102 +114,37 @@ $$Out=sigmoid(b + \sum^{N}_{i=1}W_iX_i + \sum^{N-1}_{i=1}\sum^{N}_{j=i+1}W_{ij}X 用公式表示如下: $$\sum^{N}_{i=1}W_iX_i$$ -```python -first_weights_re = fluid.embedding( - input=feat_idx, - is_sparse=True, - is_distributed=is_distributed, - dtype='float32', - size=[self.sparse_feature_number + 1, 1], - padding_idx=0, - param_attr=fluid.ParamAttr( - initializer=fluid.initializer.TruncatedNormalInitializer( - loc=0.0, scale=init_value_), - regularizer=fluid.regularizer.L1DecayRegularizer(self.reg))) -first_weights = fluid.layers.reshape(first_weights_re,shape=[-1, self.num_field, 1]) # None * num_field * 1 -y_first_order = fluid.layers.reduce_sum((first_weights * feat_value),1) -``` - ### 二阶项部分 二阶项部分主要实现了公式中的交叉项部分,也就是特征的组合部分。Wij求解的思路是通过矩阵分解的方法。所有的二次项参数Wij可以组成一个对称阵W,那么这个矩阵就可以分解为 $W=V^TV$,V 的第 i 列便是第 i 维特征的隐向量。交叉项的展开式如下: $$\sum^{N-1}_{i=1}\sum^{N}_{j=i+1}W_{ij}X_iX_j =1/2\sum^{k}_{j=1}((\sum^{N}_{i=1}W_iX_i)^2-\sum^{N}_{i=1}W_i^2X_i^2)$$ - -```python -feat_embeddings_re = fluid.embedding( - input=feat_idx, - is_sparse=True, - is_distributed=is_distributed, - dtype='float32', - size=[self.sparse_feature_number + 1, self.sparse_feature_dim], - padding_idx=0, - param_attr=fluid.ParamAttr( - initializer=fluid.initializer.TruncatedNormalInitializer( - loc=0.0, - scale=init_value_ / - math.sqrt(float(self.sparse_feature_dim))))) -feat_embeddings = fluid.layers.reshape( - feat_embeddings_re, - shape=[-1, self.num_field, self.sparse_feature_dim]) # None * num_field * embedding_size -# None * num_field * embedding_size -feat_embeddings = feat_embeddings * feat_value - # sum_square part -summed_features_emb = fluid.layers.reduce_sum(feat_embeddings, 1) # None * embedding_size -summed_features_emb_square = fluid.layers.square(summed_features_emb) # None * embedding_size - # square_sum part -squared_features_emb = fluid.layers.square(feat_embeddings) # None * num_field * embedding_size -squared_sum_features_emb = fluid.layers.reduce_sum(squared_features_emb, 1) # None * embedding_size -y_second_order = 0.5 * fluid.layers.reduce_sum(summed_features_emb_square - squared_sum_features_emb,1,keep_dim=True) # None * 1 -``` - -### dnn部分 -相比fm模型,我们去除了fm模型中的偏移量,而加入了dnn部分作为特征间的高阶组合,通过并行的方式组合fm和dnn两种方法,两者共用底层的embedding数据。dnn部分的主要组成为三个全连接层,每层FC的输出维度都为400,每层FC都后接一个relu激活函数,每层FC的初始化方式为符合正态分布的随机初始化. -最后接了一层输出维度为1的fc层,方便与fm部分综合计算预测值。 -```python -y_dnn = fluid.layers.reshape(feat_embeddings, [-1, self.num_field * self.sparse_feature_dim]) -for s in self.layer_sizes: - y_dnn = fluid.layers.fc( - input=y_dnn, - size=s, - act=self.act, - param_attr=fluid.ParamAttr( - initializer=fluid.initializer.TruncatedNormalInitializer( - loc=0.0, scale=init_value_ / math.sqrt(float(10)))), - bias_attr=fluid.ParamAttr( - initializer=fluid.initializer.TruncatedNormalInitializer( - loc=0.0, scale=init_value_))) -y_dnn = fluid.layers.fc( - input=y_dnn, - size=1, - act=None, - param_attr=fluid.ParamAttr( - initializer=fluid.initializer.TruncatedNormalInitializer( - loc=0.0, scale=init_value_)), - bias_attr=fluid.ParamAttr( - initializer=fluid.initializer.TruncatedNormalInitializer( - loc=0.0, scale=init_value_))) - -``` - ### Loss及Auc计算 - 预测的结果将FM的一阶项部分,二阶项部分以及dnn部分相加,再通过激活函数sigmoid给出,为了得到每条样本分属于正负样本的概率,我们将预测结果和`1-predict`合并起来得到predict_2d,以便接下来计算auc。 - 每条样本的损失为负对数损失值,label的数据类型将转化为float输入。 - 该batch的损失`avg_cost`是各条样本的损失之和 - 我们同时还会计算预测的auc,auc的结果由`fluid.layers.auc()`给出,该层的返回值有三个,分别是全局auc: `auc_var`,当前batch的auc: `batch_auc_var`,以及auc_states: `_`,auc_states包含了`batch_stat_pos, batch_stat_neg, stat_pos, stat_neg`信息。 -```python -self.predict = fluid.layers.sigmoid(y_first_order + y_second_order +y_dnn) -cost = fluid.layers.log_loss( - input=self.predict, label=fluid.layers.cast(self.label, "float32")) -avg_cost = fluid.layers.reduce_sum(cost) -self._cost = avg_cost -predict_2d = fluid.layers.concat([1 - self.predict, self.predict], 1) -label_int = fluid.layers.cast(self.label, 'int64') -auc_var, batch_auc_var, _ = fluid.layers.auc(input=predict_2d, - label=label_int, - slide_steps=0) -``` - 完成上述组网后,我们最终可以通过训练拿到`auc`指标。 + +## 效果复现 +为了方便使用者能够快速的跑通每一个模型,我们在每个模型下都提供了样例数据。如果需要复现readme中的效果,请按如下步骤依次操作即可。 +1. 确认您当前所在目录为PaddleRec/models/rank/deepfm +2. 在data目录下运行数据一键处理脚本,命令如下: +``` +cd data +sh run.sh +cd .. +``` +3. 退回deepfm目录中,打开文件config.yaml,更改其中的参数 +将workspace改为您当前的绝对路径。(可用pwd命令获取绝对路径) +将train_sample中的batch_size从5改为1024 +将train_sample中的data_path改为{workspace}/data/slot_train_data +将infer_sample中的batch_size从5改为1024 +将infer_sample中的data_path改为{workspace}/data/slot_test_data +4. 开始训练。运行命令启动训练即可得到相应auc指标 +``` +python -m paddlerec.run -m ./config.yaml +``` +5. 全量数据的训练结果示例如下: ``` PaddleRec: Runner infer_runner Begin Executor Mode: infer @@ -211,26 +172,6 @@ Infer infer_phase of epoch 1 done, use time: 1764.81796193, global metrics: AUC= PaddleRec Finish ``` -## 效果复现 -为了方便使用者能够快速的跑通每一个模型,我们在每个模型下都提供了样例数据。如果需要复现readme中的效果,请按如下步骤依次操作即可。 -1. 确认您当前所在目录为PaddleRec/models/rank/deepfm -2. 在data目录下运行数据一键处理脚本,命令如下: -``` -cd data -sh run.sh -cd .. -``` -3. 退回deepfm目录中,打开文件config.yaml,更改其中的参数 -将workspace改为您当前的绝对路径。(可用pwd命令获取绝对路径) -将train_sample中的batch_size从5改为512 -将train_sample中的data_path改为{workspace}/data/slot_train_data -将infer_sample中的batch_size从5改为512 -将infer_sample中的data_path改为{workspace}/data/slot_test_data -4. 开始训练。运行命令启动训练即可得到相应auc指标 -``` -python -m paddlerec.run -m ./config.yaml -``` - ## 进阶使用 ## FAQ