diff --git a/.git_bin_path b/.git_bin_path index 640d0441b..9dc118a47 100644 --- a/.git_bin_path +++ b/.git_bin_path @@ -38,7 +38,7 @@ {"leaf_name": "data/test/movielens_1m", "leaf_file": ["data/test/movielens_1m/ml_test_data", "data/test/movielens_1m/ml_train_data"]} {"leaf_name": "data/test/mt_ckpt", "leaf_file": ["data/test/mt_ckpt/model.ckpt-100.data-00000-of-00001", "data/test/mt_ckpt/model.ckpt-100.index", "data/test/mt_ckpt/model.ckpt-100.meta"]} {"leaf_name": "data/test/rtp", "leaf_file": ["data/test/rtp/taobao_fg_pred.out", "data/test/rtp/taobao_test_bucketize_feature.txt", "data/test/rtp/taobao_test_feature.txt", "data/test/rtp/taobao_test_input.txt", "data/test/rtp/taobao_train_bucketize_feature.txt", "data/test/rtp/taobao_train_feature.txt", "data/test/rtp/taobao_train_input.txt", "data/test/rtp/taobao_valid.csv", "data/test/rtp/taobao_valid_feature.txt"]} -{"leaf_name": "data/test/tb_data", "leaf_file": ["data/test/tb_data/taobao_ad_feature_gl", "data/test/tb_data/taobao_clk_edge_gl", "data/test/tb_data/taobao_multi_seq_test_data", "data/test/tb_data/taobao_multi_seq_train_data", "data/test/tb_data/taobao_noclk_edge_gl", "data/test/tb_data/taobao_test_data", "data/test/tb_data/taobao_test_data_compress.gz", "data/test/tb_data/taobao_test_data_for_expr", "data/test/tb_data/taobao_test_data_kd", "data/test/tb_data/taobao_test_data_remap_label", "data/test/tb_data/taobao_train_data", "data/test/tb_data/taobao_train_data_for_expr", "data/test/tb_data/taobao_train_data_kd", "data/test/tb_data/taobao_train_data_remap_label", "data/test/tb_data/taobao_user_profile_gl"]} +{"leaf_name": "data/test/tb_data", "leaf_file": ["data/test/tb_data/taobao_ad_feature_gl", "data/test/tb_data/taobao_clk_edge_gl", "data/test/tb_data/taobao_multi_seq_test_data", "data/test/tb_data/taobao_multi_seq_train_data", "data/test/tb_data/taobao_noclk_edge_gl", "data/test/tb_data/taobao_pdn_fake_test_data", "data/test/tb_data/taobao_pdn_fake_train_data", "data/test/tb_data/taobao_test_data", "data/test/tb_data/taobao_test_data_compress.gz", "data/test/tb_data/taobao_test_data_for_expr", "data/test/tb_data/taobao_test_data_kd", "data/test/tb_data/taobao_test_data_remap_label", "data/test/tb_data/taobao_train_data", "data/test/tb_data/taobao_train_data_for_expr", "data/test/tb_data/taobao_train_data_kd", "data/test/tb_data/taobao_train_data_remap_label", "data/test/tb_data/taobao_user_profile_gl"]} {"leaf_name": "data/test/tb_data/hard_negative_sampler_edge", "leaf_file": ["data/test/tb_data/hard_negative_sampler_edge/taobao_noclk_edge_gl.csv"]} {"leaf_name": "data/test/tb_data/hard_negative_sampler_item", "leaf_file": ["data/test/tb_data/hard_negative_sampler_item/taobao_ad_feature_gl.csv"]} {"leaf_name": "data/test/tb_data/hard_negative_sampler_user", "leaf_file": ["data/test/tb_data/hard_negative_sampler_user/taobao_user_profile_gl.csv"]} diff --git a/.git_bin_url b/.git_bin_url index 22c8ef187..18eeef0d3 100644 --- a/.git_bin_url +++ b/.git_bin_url @@ -38,7 +38,7 @@ {"leaf_path": "data/test/movielens_1m", "sig": "99badbeec64f2fcabe0dfa1d2bfd8fb5", "remote_path": "data/git_oss_sample_data/data_test_movielens_1m_99badbeec64f2fcabe0dfa1d2bfd8fb5"} {"leaf_path": "data/test/mt_ckpt", "sig": "803499f48e2df5e51ce5606e9649c6d4", "remote_path": "data/git_oss_sample_data/data_test_mt_ckpt_803499f48e2df5e51ce5606e9649c6d4"} {"leaf_path": "data/test/rtp", "sig": "76cda60582617ddbb7cd5a49eb68a4b9", "remote_path": "data/git_oss_sample_data/data_test_rtp_76cda60582617ddbb7cd5a49eb68a4b9"} -{"leaf_path": "data/test/tb_data", "sig": "f1279ca42de1734be321e88f85775d5f", "remote_path": "data/git_oss_sample_data/data_test_tb_data_f1279ca42de1734be321e88f85775d5f"} +{"leaf_path": "data/test/tb_data", "sig": "b1579db090d72b3b70b59ba3c7692701", "remote_path": "data/git_oss_sample_data/data_test_tb_data_b1579db090d72b3b70b59ba3c7692701"} {"leaf_path": "data/test/tb_data/hard_negative_sampler_edge", "sig": "48f994681d719a2546ec4003fcbc638c", "remote_path": "data/git_oss_sample_data/data_test_tb_data_hard_negative_sampler_edge_48f994681d719a2546ec4003fcbc638c"} {"leaf_path": "data/test/tb_data/hard_negative_sampler_item", "sig": "f23a9eb9457c14a8e57b455804b1f013", "remote_path": "data/git_oss_sample_data/data_test_tb_data_hard_negative_sampler_item_f23a9eb9457c14a8e57b455804b1f013"} {"leaf_path": "data/test/tb_data/hard_negative_sampler_user", "sig": "23514156eae5a4250ac1d0a118883430", "remote_path": "data/git_oss_sample_data/data_test_tb_data_hard_negative_sampler_user_23514156eae5a4250ac1d0a118883430"} diff --git a/.gitattributes b/.gitattributes index 5e7dc28eb..ad3f947ef 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,7 @@ data/test/inference/fg_export_multi/variables/variables.index filter=lfs diff=lf data/test/inference/tb_multitower_export/assets/pipeline.config filter=lfs diff=lfs merge=lfs -text data/test/latest_ckpt_test/model.ckpt-500.meta filter=lfs diff=lfs merge=lfs -text data/test/tb_data/taobao_test_data filter=lfs diff=lfs merge=lfs -text +data/test/tb_data/taobao_pdn_fake_test_data filter=lfs diff=lfs merge=lfs -text data/test/tb_data/taobao_multi_seq_test_data filter=lfs diff=lfs merge=lfs -text data/test/test.csv filter=lfs diff=lfs merge=lfs -text data/test/inference/tb_multitower_placeholder_rename_export/assets/pipeline.config filter=lfs diff=lfs merge=lfs -text @@ -16,6 +17,7 @@ data/test/criteo_sample.tfrecord filter=lfs diff=lfs merge=lfs -text data/test/rtp/taobao_valid.csv filter=lfs diff=lfs merge=lfs -text data/test/rtp/taobao_train_feature.txt filter=lfs diff=lfs merge=lfs -text data/test/tb_data/taobao_train_data filter=lfs diff=lfs merge=lfs -text +data/test/tb_data/taobao_pdn_fake_train_data filter=lfs diff=lfs merge=lfs -text data/test/tb_data/taobao_multi_seq_train_data filter=lfs diff=lfs merge=lfs -text data/test/inference/fg_export_single/variables/variables.index filter=lfs diff=lfs merge=lfs -text data/test/inference/lookup_data_test80.csv filter=lfs diff=lfs merge=lfs -text diff --git a/README.md b/README.md index 90184a3d2..3293e5e2e 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Running Platform: ### A variety of models -- [DSSM](docs/source/models/dssm.md) / [MIND](docs/source/models/mind.md) / [DropoutNet](docs/source/models/dropoutnet.md) / [CoMetricLearningI2I](docs/source/models/co_metric_learning_i2i.md) +- [DSSM](docs/source/models/dssm.md) / [MIND](docs/source/models/mind.md) / [DropoutNet](docs/source/models/dropoutnet.md) / [CoMetricLearningI2I](docs/source/models/co_metric_learning_i2i.md) / [PDN](docs/source/models/pdn.md) - [W&D](docs/source/models/wide_and_deep.md) / [DeepFM](docs/source/models/deepfm.md) / [MultiTower](docs/source/models/multi_tower.md) / [DCN](docs/source/models/dcn.md) / [FiBiNet](docs/source/models/fibinet.md) / [MaskNet](docs/source/models/masknet.md) - [DIN](docs/source/models/din.md) / [BST](docs/source/models/bst.md) - [MMoE](docs/source/models/mmoe.md) / [ESMM](docs/source/models/esmm.md) / [DBMTL](docs/source/models/dbmtl.md) / [PLE](docs/source/models/ple.md) diff --git a/docs/images/models/pdn.jpg b/docs/images/models/pdn.jpg new file mode 100644 index 000000000..8a29f94a3 Binary files /dev/null and b/docs/images/models/pdn.jpg differ diff --git a/docs/images/models/pdn_1.png b/docs/images/models/pdn_1.png new file mode 100644 index 000000000..66ca91ccb Binary files /dev/null and b/docs/images/models/pdn_1.png differ diff --git a/docs/source/intro.md b/docs/source/intro.md index 34cb2582a..b24764fad 100644 --- a/docs/source/intro.md +++ b/docs/source/intro.md @@ -46,7 +46,7 @@ EasyRec implements state of the art machine learning models used in common recom ### A variety of models -- [DSSM](models/dssm.md) / [MIND](models/mind.md) / [DropoutNet](models/dropoutnet.md) / [CoMetricLearningI2I](models/co_metric_learning_i2i.md) +- [DSSM](models/dssm.md) / [MIND](models/mind.md) / [DropoutNet](models/dropoutnet.md) / [CoMetricLearningI2I](models/co_metric_learning_i2i.md) / [PDN](models/pdn.md) - [W&D](models/wide_and_deep.md) / [DeepFM](models/deepfm.md) / [MultiTower](models/multi_tower.md) / [DCN](models/dcn.md) / [DIN](models/din.md) / [BST](models/bst.md) - [MMoE](models/mmoe.md) / [ESMM](models/esmm.md) / [DBMTL](models/dbmtl.md) / [PLE](models/ple.md) - [CMBF](models/cmbf.md) / [UNITER](models/uniter.md) diff --git a/docs/source/models/pdn.md b/docs/source/models/pdn.md new file mode 100644 index 000000000..9b74cc6f1 --- /dev/null +++ b/docs/source/models/pdn.md @@ -0,0 +1,114 @@ +# PDN + +### 简介 + +在推荐系统的召回阶段,工业界常多采用 基于Item的协同过滤 (Item-based CF) 和 基于embedding的检索 (EBR)。然而,Item-based CF很难满足个性化,而EBR则很难满足多样性。 + +论文中提出了一种新颖的匹配架构——基于路径的深度网络(Path-based Deep Network, PDN), 它可以结合个性化和多样性来提高匹配性能。 + +具体来说,PDN由两个模块组成:Trigger Net和Similarity Net(SimNet,与下文一致)。 PDN 利用 Trigger Net 来捕获用户对其每个交互item的兴趣,并利用 SimNet 根据这些item的特征和共现信息来评估每个交互item与目标item之间的相似度。 + +用户和目标item之间的最终相关性是通过明确考虑用户的不同兴趣来计算的,即聚合相关两跳路径的相关权重(路径的一跳对应于user - trigger item交互,另一跳对应于trigger item - target item相关性)。 + +![pdn.png](../../images/models/pdn.jpg) +(图片来自参考论文) + +### 配置说明 + +#### PDN + +```protobuf +model_config { + model_class: "PDN" + feature_groups: { + group_name: 'u2i_seq' + feature_names: 'event_type_seq' + } + feature_groups: { + group_name: 'i_seq' + feature_names: 'tag_category_list' + } + feature_groups: { + group_name: 'i2i_seq' + feature_names: 'i2i_rnk' + } + feature_groups: { + group_name: 'user' + feature_names: 'user_id' + feature_names: 'cms_segid' + wide_deep:DEEP + } + feature_groups: { + group_name: "item" + feature_names: 'adgroup_id' + feature_names: 'cate_id' + wide_deep:DEEP + } + feature_groups { + group_name: 'bias' + feature_names: 'position' + } + + pdn { + user_dnn { + hidden_units: [128, 64, 32] + } + item_dnn { + hidden_units: [128, 64, 32] + } + u2i_dnn { + hidden_units: [64, 32] + } + i2i_dnn { + hidden_units: [128, 64, 32] + } + trigger_dnn { + hidden_units: [64, 32, 1] + } + sim_dnn { + hidden_units: [64, 32, 1] + } + bias_dnn { + hidden_units: [32, 32, 1] + } + + l2_regularization: 1e-6 + } + embedding_regularization: 5e-6 +} +``` + +- model_class: 'PDN', 不需要修改 + +- feature_groups: 需要六个feature_group: u2i_seq, i_seq, i2i_seq, user, item 和 bias. + + **group name不能变, 且u2i_seq, i_seq, i2i_seq的输入均为Sequence Feature.** + + 特征说明可以参考下图 + ![pdn_1.png](../../images/models/pdn_1.png) + + - u2i_seq: u用户对交互过的trigger物品的行为侧信息的序列,如 event_type, click_time等 + - i_seq: 用户交互过的trigger物品的相关特征的序列,如 category, brand等 + - i2i_seq: trigger物品到target物品的统计特征和共现特征,如 是否同品牌, swing_score等 + - user: 用户侧相关特征,如 age, sex等 + - item: 物品侧相关特征,如 category, brand等 + - bias: 导致选择性偏差的特征(位置信息等),如 position等 + +- pdn: pdn模型相关的参数 + + - user_dnn:构造DNN编码user特征信息转换为向量 + - item_dnn:构造DNN编码item特征信息转换为向量 + - u2i_dnn:构造DNN编码user to trigger item的行为特征信息转换为向量 + - i2i_dnn:构造DNN编码trigger item to target item特征转换为向量 + - trigger_dnn:构造TriggerNet DNN计算user对每个交互item的喜爱程度来捕获user的多峰兴趣 + - sim_dnn:构造SimNet DNN基于item信息和共现信息计算trigger item与target item的相似度 + - bias_dnn (可选):基于会导致选择性偏差的特征(位置信息等)训练一个浅层DNN + - embedding_regularization: 对embedding部分加regularization,防止overfit + +### 示例Config + +[PDN_demo.config](../../../samples/model_config/pdn_on_taobao.config) + +### 参考论文 + +[PDN](https://arxiv.org/abs/2105.08246) diff --git a/easy_rec/python/model/pdn.py b/easy_rec/python/model/pdn.py new file mode 100644 index 000000000..7325beb1c --- /dev/null +++ b/easy_rec/python/model/pdn.py @@ -0,0 +1,203 @@ +# -*- encoding:utf-8 -*- +# Copyright (c) Alibaba, Inc. and its affiliates. + +import tensorflow as tf + +from easy_rec.python.layers import dnn +from easy_rec.python.model.match_model import MatchModel +from easy_rec.python.protos.simi_pb2 import Similarity + +if tf.__version__ >= '2.0': + tf = tf.compat.v1 +losses = tf.losses +metrics = tf.metrics + + +class PDN(MatchModel): + + def __init__(self, + model_config, + feature_configs, + features, + labels=None, + is_training=False): + super(PDN, self).__init__(model_config, feature_configs, features, labels, + is_training) + assert self._model_config.WhichOneof('model') == 'pdn', \ + 'invalid model config: %s' % self._model_config.WhichOneof('model') + self._model_config = self._model_config.pdn + + self._user_features, _ = self._input_layer(self._feature_dict, 'user') + self._item_features, _ = self._input_layer(self._feature_dict, 'item') + + if self._input_layer.has_group('bias'): + self._bias_features, _ = self._input_layer(self._feature_dict, 'bias') + else: + self._bias_features = None + + self._u2i_seq, self._seq_len = self._get_seq_features('u2i_seq') + self._i_seq, _ = self._get_seq_features('i_seq') + self._i2i_seq, _ = self._get_seq_features('i2i_seq') + + def build_predict_graph(self): + trigger_out = self._build_trigger_net() + sim_out = self._build_similarity_net() + logits = tf.multiply(sim_out, trigger_out) + + seq_mask = tf.to_float( + tf.sequence_mask(self._seq_len, + tf.shape(sim_out)[1])) + logits = tf.reduce_sum(logits * seq_mask[:, :, None], axis=1) + + direct_logits = self._build_direct_net() + if direct_logits is not None: + logits += direct_logits + + bias_logits = self._build_bias_net() + if bias_logits is not None: + logits += bias_logits + + logits = tf.squeeze(logits, axis=1) + probs = 1 - tf.exp(-logits) # map [0, inf) to [0, 1) + + self._prediction_dict['probs'] = probs + self._prediction_dict['logits'] = tf.log( + tf.clip_by_value(probs, 1e-8, 1 - 1e-8)) + return self._prediction_dict + + def _get_seq_features(self, name): + seqs, _, _ = self._input_layer(self._feature_dict, name, is_combine=False) + seq_len = seqs[0][1] + seq = tf.concat([x[0] for x in seqs], axis=2) + return seq, seq_len + + def _build_trigger_net(self): + user_dnn_layer = dnn.DNN(self._model_config.user_dnn, self._l2_reg, + 'user_dnn', self._is_training) + user_fea = user_dnn_layer(self._user_features) + + trigger_seq = tf.concat([self._u2i_seq, self._i_seq], axis=2) + u2i_dnn_layer = dnn.DNN(self._model_config.u2i_dnn, self._l2_reg, 'u2i_dnn', + self._is_training) + trigger_seq_fea = u2i_dnn_layer(trigger_seq) + + trigger_merge_fea = trigger_seq_fea + user_fea[:, None, :] + trigger_dnn_layer = dnn.DNN( + self._model_config.trigger_dnn, + self._l2_reg, + 'trigger_dnn', + self._is_training, + last_layer_no_activation=True, + last_layer_no_batch_norm=True) + + # output: N x seq_len x d, d is usually set to 1 + trigger_out = trigger_dnn_layer(trigger_merge_fea) + # exp(x): map (-inf, inf) to (0, inf) + trigger_out = tf.exp(trigger_out) + + self._prediction_dict['trigger_out'] = tf.reduce_join( + tf.reduce_join( + tf.as_string(trigger_out, precision=4, shortest=True), + axis=2, + separator=','), + axis=1, + separator=';') + return trigger_out + + def _build_similarity_net(self): + item_dnn_layer = dnn.DNN(self._model_config.item_dnn, self._l2_reg, + 'item_dnn', self._is_training) + item_fea = item_dnn_layer(self._item_features) + + sim_side_dnn_layer = dnn.DNN(self._model_config.i2i_dnn, self._l2_reg, + 'i2i_dnn', self._is_training) + sim_seq_fea = sim_side_dnn_layer(self._i_seq) + + sim_seq_cross = sim_seq_fea * item_fea[:, None, :] + + item_fea_tile = tf.tile(item_fea[:, None, :], + [1, tf.shape(sim_seq_fea)[1], 1]) + + sim_seq_concat = tf.concat( + [sim_seq_cross, sim_seq_cross, self._i2i_seq, item_fea_tile], axis=2) + sim_dnn_layer = dnn.DNN( + self._model_config.sim_dnn, + self._l2_reg, + 'sim_dnn', + self._is_training, + last_layer_no_activation=True, + last_layer_no_batch_norm=True) + # output: N x seq_len x 1 + sim_out = sim_dnn_layer(sim_seq_concat) + # exp(x): map (-inf, inf) to (0, inf) + sim_out = tf.exp(sim_out) + + self._prediction_dict['sim_out'] = tf.reduce_join( + tf.reduce_join( + tf.as_string(sim_out, precision=4, shortest=True), + axis=2, + separator=','), + axis=1, + separator=';') + return sim_out + + def _build_direct_net(self): + if self._model_config.HasField('direct_user_dnn') and \ + self._model_config.HasField('direct_item_dnn'): + direct_user_layer = dnn.DNN( + self._model_config.direct_user_dnn, + 'direct_user_dnn', + self._is_training, + last_layer_no_activation=True, + last_layer_no_batch_norm=True) + direct_user_out = direct_user_layer(self._user_features) + direct_item_layer = dnn.DNN( + self._model_config.direct_item_dnn, + 'direct_item_dnn', + self._is_training, + last_layer_no_activation=True, + last_layer_no_batch_norm=True) + direct_item_out = direct_item_layer(self._item_features) + + if self._model_config.simi_func == Similarity.COSINE: + direct_user_out = self.norm(direct_user_out) + direct_item_out = self.norm(direct_item_out) + + self._prediction_dict['direct_user_embedding'] = direct_user_out + self._prediction_dict['direct_item_embedding'] = direct_item_out + direct_logits = tf.reduce_sum(direct_user_out * direct_item_out, axis=1) + + if self._model_config.scale_simi: + sim_w = tf.get_variable( + 'direct_net/sim_w', + dtype=tf.float32, + shape=(1), + initializer=tf.ones_initializer()) + sim_b = tf.get_variable( + 'direct_net/sim_b', + dtype=tf.float32, + shape=(1), + initializer=tf.zeros_initializer()) + direct_logits = direct_logits * tf.abs(sim_w) + sim_b + + return tf.nn.softplus(direct_logits) + else: + return None + + def _build_bias_net(self): + if self._model_config.HasField('bias_dnn'): + assert self._bias_features is not None, 'bias group must be defined' + bias_dnn_layer = dnn.DNN( + self._model_config.bias_dnn, + self._l2_reg, + 'bias_dnn', + self._is_training, + last_layer_no_activation=True, + last_layer_no_batch_norm=True) + bias_logits = bias_dnn_layer(self._bias_features) + return tf.nn.softplus(bias_logits) + else: + return None + + def get_outputs(self): + return ['logits', 'probs', 'trigger_out', 'sim_out'] diff --git a/easy_rec/python/protos/easy_rec_model.proto b/easy_rec/python/protos/easy_rec_model.proto index 76506d710..b0f79fe0f 100644 --- a/easy_rec/python/protos/easy_rec_model.proto +++ b/easy_rec/python/protos/easy_rec_model.proto @@ -26,6 +26,7 @@ import "easy_rec/python/protos/rocket_launching.proto"; import "easy_rec/python/protos/variational_dropout.proto"; import "easy_rec/python/protos/multi_tower_recall.proto"; import "easy_rec/python/protos/tower.proto"; +import "easy_rec/python/protos/pdn.proto"; // for input performance test message DummyModel { @@ -82,6 +83,7 @@ message EasyRecModel { MIND mind = 202; DropoutNet dropoutnet = 203; CoMetricLearningI2I metric_learning = 204; + PDN pdn = 205; MMoE mmoe = 301; ESMM esmm = 302; diff --git a/easy_rec/python/protos/pdn.proto b/easy_rec/python/protos/pdn.proto new file mode 100644 index 000000000..dba0852b9 --- /dev/null +++ b/easy_rec/python/protos/pdn.proto @@ -0,0 +1,48 @@ +syntax = "proto2"; +package protos; + +import "easy_rec/python/protos/dnn.proto"; +import "easy_rec/python/protos/simi.proto"; + +// requires 3 sequence groups: +// u2i: user behavior info on intereacted item sequence +// i_seq: trigger item side info sequence +// i2i: trigger item and target item co-occurance info + +message PDN { + // encode user info + required DNN user_dnn = 1; + // encode target item info + required DNN item_dnn = 2; + + // encode u2i seq info + required DNN u2i_dnn = 3; + + // produce trigger score + required DNN trigger_dnn = 4; + + // encode trigger item seqs to target item co-occurance info + required DNN i2i_dnn = 5; + + // produce sim score + required DNN sim_dnn = 6; + + // direct net user_dnn + optional DNN direct_user_dnn = 7; + + // direct net item_dnn + optional DNN direct_item_dnn = 8; + + // for direct net, similar to DSSM + optional Similarity simi_func = 9 [default=COSINE]; + + // for direct net + optional bool scale_simi = 10 [default = true]; + + // bias net dnn + optional DNN bias_dnn = 11; + + optional string item_id = 12; + + optional float l2_regularization = 13 [default=1e-6]; +} diff --git a/easy_rec/python/test/train_eval_test.py b/easy_rec/python/test/train_eval_test.py index 087c90cd8..550fa3cb1 100644 --- a/easy_rec/python/test/train_eval_test.py +++ b/easy_rec/python/test/train_eval_test.py @@ -1143,6 +1143,11 @@ def test_horovod(self): use_hvd=True) self.assertTrue(self._success) + def test_pdn(self): + self._success = test_utils.test_single_train_eval( + 'samples/model_config/pdn_on_taobao.config', self._test_dir) + self.assertTrue(self._success) + if __name__ == '__main__': tf.test.main() diff --git a/samples/model_config/pdn_on_taobao.config b/samples/model_config/pdn_on_taobao.config new file mode 100644 index 000000000..2add9ddcb --- /dev/null +++ b/samples/model_config/pdn_on_taobao.config @@ -0,0 +1,327 @@ +# Note: this is just a demo using faked data. + +train_input_path: "data/test/tb_data/taobao_pdn_fake_train_data" +eval_input_path: "data/test/tb_data/taobao_pdn_fake_test_data" +model_dir: "experiments/pdn_on_taobao" + +train_config { + log_step_count_steps: 5 + optimizer_config: { + adam_optimizer: { + learning_rate: { + exponential_decay_learning_rate { + initial_learning_rate: 0.001 + decay_steps: 1000 + decay_factor: 0.5 + min_learning_rate: 0.00001 + } + } + } + use_moving_average: false + } + save_summary_steps: 5 + num_steps: 2000 +} + +eval_config { + metrics_set: { + auc {} + } +} + +data_config { + input_fields { + input_name:'clk' + input_type: INT32 + } + input_fields { + input_name:'buy' + input_type: INT32 + } + input_fields { + input_name: 'pid' + input_type: STRING + } + input_fields { + input_name: 'adgroup_id' + input_type: STRING + } + input_fields { + input_name: 'cate_id' + input_type: STRING + } + input_fields { + input_name: 'campaign_id' + input_type: STRING + } + input_fields { + input_name: 'customer' + input_type: STRING + } + input_fields { + input_name: 'brand' + input_type: STRING + } + input_fields { + input_name: 'user_id' + input_type: STRING + } + input_fields { + input_name: 'cms_segid' + input_type: STRING + } + input_fields { + input_name: 'cms_group_id' + input_type: STRING + } + input_fields { + input_name: 'final_gender_code' + input_type: STRING + } + input_fields { + input_name: 'age_level' + input_type: STRING + } + input_fields { + input_name: 'pvalue_level' + input_type: STRING + } + input_fields { + input_name: 'shopping_level' + input_type: STRING + } + input_fields { + input_name: 'occupation' + input_type: STRING + } + input_fields { + input_name: 'new_user_class_level' + input_type: STRING + } + input_fields { + input_name: 'tag_category_list' + input_type: STRING + } + input_fields { + input_name: 'tag_brand_list' + input_type: STRING + } + input_fields { + input_name: 'price' + input_type: INT32 + } + input_fields { + input_name: "i2i_rnk" + input_type: STRING + } + input_fields { + input_name: "event_type_seq" + input_type: STRING + } + + label_fields: 'clk' + batch_size: 512 + num_epochs: 1 + prefetch_size: 32 + input_type: CSVInput +} + +feature_configs : { + input_names: 'pid' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10 +} +feature_configs : { + input_names: 'adgroup_id' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 100000 +} +feature_configs : { + input_names: 'cate_id' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10000 +} +feature_configs : { + input_names: 'campaign_id' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 100000 +} +feature_configs : { + input_names: 'customer' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 100000 +} +feature_configs : { + input_names: 'brand' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 100000 +} +feature_configs : { + input_names: 'user_id' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 100000 +} +feature_configs : { + input_names: 'cms_segid' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 100 +} +feature_configs : { + input_names: 'cms_group_id' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 100 +} +feature_configs : { + input_names: 'final_gender_code' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10 +} +feature_configs : { + input_names: 'age_level' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10 +} +feature_configs : { + input_names: 'pvalue_level' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10 +} +feature_configs : { + input_names: 'shopping_level' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10 +} +feature_configs : { + input_names: 'occupation' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10 +} +feature_configs : { + input_names: 'new_user_class_level' + feature_type: IdFeature + embedding_dim: 16 + hash_bucket_size: 10 +} +feature_configs : { + input_names: 'tag_category_list' + feature_type: SequenceFeature + separator: '|' + hash_bucket_size: 100000 + embedding_dim: 16 +} +feature_configs : { + input_names: 'event_type_seq' + feature_type: SequenceFeature + separator: '|' + hash_bucket_size: 100000 + embedding_dim: 16 +} +feature_configs : { + input_names: 'tag_brand_list' + feature_type: SequenceFeature + separator: '|' + hash_bucket_size: 100000 + embedding_dim: 16 +} +feature_configs : { + input_names: 'price' + feature_type: IdFeature + embedding_dim: 16 + num_buckets: 50 +} +feature_configs { + input_names: 'i2i_rnk' + feature_type: SequenceFeature + separator: '|' + num_buckets: 128 + embedding_dim: 16 +} + +model_config:{ + model_class: "PDN" + feature_groups: { + group_name: 'u2i_seq' + feature_names: 'event_type_seq' + } + feature_groups: { + group_name: 'i_seq' + feature_names: 'tag_category_list' + feature_names: 'tag_brand_list' + } + feature_groups: { + group_name: 'i2i_seq' + feature_names: 'i2i_rnk' + } + feature_groups: { + group_name: 'user' + feature_names: 'user_id' + feature_names: 'cms_segid' + feature_names: 'cms_group_id' + feature_names: 'age_level' + feature_names: 'pvalue_level' + feature_names: 'shopping_level' + feature_names: 'occupation' + feature_names: 'new_user_class_level' + wide_deep:DEEP + } + feature_groups: { + group_name: "item" + feature_names: 'adgroup_id' + feature_names: 'cate_id' + feature_names: 'campaign_id' + feature_names: 'customer' + feature_names: 'brand' + wide_deep:DEEP + } + feature_groups { + group_name: 'bias' + feature_names: 'user_id' + feature_names: 'cms_segid' + feature_names: 'cms_group_id' + feature_names: 'age_level' + } + + pdn { + user_dnn { + hidden_units: [128, 64, 32] + } + item_dnn { + hidden_units: [128, 64, 32] + } + u2i_dnn { + hidden_units: [64, 32] + } + trigger_dnn { + hidden_units: [64, 32, 1] + } + i2i_dnn { + hidden_units: [128, 64, 32] + } + sim_dnn { + hidden_units: [64, 32, 1] + } + bias_dnn { + hidden_units: [32, 32, 1] + } + + l2_regularization: 1e-6 + } + embedding_regularization: 5e-5 +} + +export_config { +}