|
| 1 | +# -*- coding:utf-8 -*- |
| 2 | +""" |
| 3 | +Author: |
| 4 | + |
| 5 | +
|
| 6 | +Reference: |
| 7 | + [1] Chen, B., Wang, Y., Liu, et al. Enhancing Explicit and Implicit Feature Interactions via Information Sharing for Parallel Deep CTR Models. CIKM, 2021, October (https://dlp-kdd.github.io/assets/pdf/DLP-KDD_2021_paper_12.pdf) |
| 8 | +""" |
| 9 | +import tensorflow as tf |
| 10 | +from tensorflow.python.keras.layers import Dense, Lambda, Reshape, Concatenate |
| 11 | +from tensorflow.python.keras.models import Model |
| 12 | + |
| 13 | +from ..feature_column import build_input_features, get_linear_logit, input_from_feature_columns |
| 14 | +from ..layers.core import PredictionLayer, DNN, RegulationLayer |
| 15 | +from ..layers.interaction import CrossNet, BridgeLayer |
| 16 | +from ..layers.utils import add_func, concat_func |
| 17 | + |
| 18 | + |
| 19 | +def EDCN(linear_feature_columns, |
| 20 | + dnn_feature_columns, |
| 21 | + bridge_type='attention_pooling', |
| 22 | + tau=0.1, |
| 23 | + use_dense_features=True, |
| 24 | + cross_num=2, |
| 25 | + cross_parameterization='vector', |
| 26 | + l2_reg_linear=1e-5, |
| 27 | + l2_reg_embedding=1e-5, |
| 28 | + l2_reg_cross=1e-5, |
| 29 | + l2_reg_dnn=0, |
| 30 | + seed=10000, |
| 31 | + dnn_dropout=0, |
| 32 | + dnn_use_bn=False, |
| 33 | + dnn_activation='relu', |
| 34 | + task='binary'): |
| 35 | + """Instantiates the Enhanced Deep&Cross Network architecture. |
| 36 | + :param linear_feature_columns: An iterable containing all the features used by linear part of the model. |
| 37 | + :param dnn_feature_columns: An iterable containing all the features used by deep part of the model. |
| 38 | + :param bridge_type: The type of bridge interaction, one of 'pointwise_addition', 'hadamard_product', 'concatenation', 'attention_pooling' |
| 39 | + :param tau: Positive float, the temperature coefficient to control distribution of field-wise gating unit |
| 40 | + :param use_dense_features: Whether to use dense features, if True, dense feature will be projected to sparse embedding space |
| 41 | + :param cross_num: positive integet,cross layer number |
| 42 | + :param cross_parameterization: str, ``"vector"`` or ``"matrix"``, how to parameterize the cross network. |
| 43 | + :param l2_reg_linear: float. L2 regularizer strength applied to linear part |
| 44 | + :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector |
| 45 | + :param l2_reg_cross: float. L2 regularizer strength applied to cross net |
| 46 | + :param l2_reg_dnn: float. L2 regularizer strength applied to DNN |
| 47 | + :param seed: integer ,to use as random seed. |
| 48 | + :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate. |
| 49 | + :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not DNN |
| 50 | + :param dnn_activation: Activation function to use in DNN |
| 51 | + :param task: str, ``"binary"`` for binary logloss or ``"regression"`` for regression loss |
| 52 | + :return: A Keras model instance. |
| 53 | +
|
| 54 | + """ |
| 55 | + if cross_num == 0: |
| 56 | + raise ValueError("Cross layer num must > 0") |
| 57 | + |
| 58 | + print('EDCN brige type: ', bridge_type) |
| 59 | + |
| 60 | + features = build_input_features(dnn_feature_columns) |
| 61 | + inputs_list = list(features.values()) |
| 62 | + |
| 63 | + linear_logit = get_linear_logit(features, |
| 64 | + linear_feature_columns, |
| 65 | + seed=seed, |
| 66 | + prefix='linear', |
| 67 | + l2_reg=l2_reg_linear) |
| 68 | + |
| 69 | + sparse_embedding_list, dense_value_list = input_from_feature_columns( |
| 70 | + features, dnn_feature_columns, l2_reg_embedding, seed) |
| 71 | + |
| 72 | + # project dense value to sparse embedding space, generate a new field feature |
| 73 | + sparse_embedding_dim = int(sparse_embedding_list[0].shape[-1]) |
| 74 | + if use_dense_features: |
| 75 | + dense_value_feild = concat_func(dense_value_list) |
| 76 | + dense_value_feild = Dense(sparse_embedding_dim, dnn_activation)(dense_value_feild) |
| 77 | + dense_value_feild = Lambda(lambda x: tf.expand_dims(x, axis=1))(dense_value_feild) |
| 78 | + sparse_embedding_list.append(dense_value_feild) |
| 79 | + |
| 80 | + deep_in = concat_func(sparse_embedding_list, axis=1) |
| 81 | + cross_in = concat_func(sparse_embedding_list, axis=1) |
| 82 | + field_size = len(sparse_embedding_list) |
| 83 | + cross_dim = field_size * int(cross_in[0].shape[-1]) |
| 84 | + |
| 85 | + for i in range(cross_num): |
| 86 | + deep_in = RegulationLayer(tau)(deep_in) |
| 87 | + cross_in = RegulationLayer(tau)(cross_in) |
| 88 | + cross_out = CrossNet(1, parameterization=cross_parameterization, |
| 89 | + l2_reg=l2_reg_cross)(deep_in) |
| 90 | + deep_out = DNN([cross_dim], dnn_activation, l2_reg_dnn, |
| 91 | + dnn_dropout, dnn_use_bn, seed=seed)(cross_in) |
| 92 | + |
| 93 | + bridge_out = BridgeLayer(bridge_type)([cross_out, deep_out]) |
| 94 | + bridge_out_list = Reshape([field_size, sparse_embedding_dim])(bridge_out) |
| 95 | + |
| 96 | + deep_in = bridge_out_list |
| 97 | + cross_in = bridge_out_list |
| 98 | + |
| 99 | + stack_out = Concatenate()([cross_out, deep_out, bridge_out]) |
| 100 | + final_logit = Dense(1, use_bias=False)(stack_out) |
| 101 | + |
| 102 | + final_logit = add_func([final_logit, linear_logit]) |
| 103 | + output = PredictionLayer(task)(final_logit) |
| 104 | + |
| 105 | + model = Model(inputs=inputs_list, outputs=final_logit) |
| 106 | + |
| 107 | + return model |
0 commit comments