예제 #1
0
def input_from_feature_columns(features,
                               feature_columns,
                               l2_reg,
                               init_std,
                               seed,
                               prefix='',
                               seq_mask_zero=True,
                               support_dense=True,
                               support_group=False,
                               embedding_matrix_dict=None):
    sparse_feature_columns = list(
        filter(lambda x: isinstance(x, SparseFeat),
               feature_columns)) if feature_columns else []
    varlen_sparse_feature_columns = list(
        filter(lambda x: isinstance(x, VarLenSparseFeat),
               feature_columns)) if feature_columns else []
    if embedding_matrix_dict is None:
        embedding_matrix_dict = create_embedding_matrix(
            feature_columns,
            l2_reg,
            init_std,
            seed,
            prefix=prefix,
            seq_mask_zero=seq_mask_zero)

    group_sparse_embedding_dict = embedding_lookup(embedding_matrix_dict,
                                                   features,
                                                   sparse_feature_columns)
    dense_value_list = get_dense_input(features, feature_columns)
    if not support_dense and len(dense_value_list) > 0:
        raise ValueError("DenseFeat is not supported in dnn_feature_columns")

    sequence_embed_dict = varlen_embedding_lookup(
        embedding_matrix_dict, features, varlen_sparse_feature_columns)
    group_varlen_sparse_embedding_dict = get_varlen_pooling_list(
        sequence_embed_dict, features, varlen_sparse_feature_columns)
    group_embedding_dict = mergeDict(group_sparse_embedding_dict,
                                     group_varlen_sparse_embedding_dict)
    if not support_group:
        group_embedding_dict = list(
            chain.from_iterable(group_embedding_dict.values()))
    return group_embedding_dict, dense_value_list
예제 #2
0
def MIND(dnn_feature_columns,
         history_feature_list,
         target_song_size,
         k_max=2,
         dnn_use_bn=False,
         user_hidden_unit=64,
         dnn_activation='relu',
         l2_reg_dnn=0,
         l2_reg_embedding=1e-6,
         dnn_dropout=0,
         init_std=0.0001,
         seed=1024):
    """
    :param dnn_feature_columns: An iterable containing all the features used by deep part of the model.
    :param history_feature_list: list,to indicate  sequence sparse field
    :param target_song_size: int, the total size of the recall songs
    :param k_max: int, the max size of user interest embedding
    :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in deep net
    :param user_hidden_unit: int. user dnn hidden layer size
    :param dnn_activation: Activation function to use in deep net
    :param l2_reg_dnn:  L2 regularizer strength applied to DNN
    :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
    :param dnn_dropout:  float in [0,1), the probability we will drop out a given DNN coordinate.
    :param init_std: float,to use as the initialize std of embedding vector
    :param seed: integer ,to use as random seed.
    :return:
    """
    features = build_input_features(dnn_feature_columns)
    sparse_feature_columns = list(
        filter(lambda x: isinstance(x, SparseFeat),
               dnn_feature_columns)) if dnn_feature_columns else []
    dense_feature_columns = list(
        filter(lambda x: isinstance(x, DenseFeat),
               dnn_feature_columns)) if dnn_feature_columns else []
    varlen_sparse_feature_columns = list(
        filter(lambda x: isinstance(x, VarLenSparseFeat),
               dnn_feature_columns)) if dnn_feature_columns else []
    history_feature_columns = []
    sparse_varlen_feature_columns = []
    history_fc_names = list(map(lambda x: "hist_" + x, history_feature_list))
    for fc in varlen_sparse_feature_columns:
        feature_name = fc.name
        if feature_name in history_fc_names:
            history_feature_columns.append(fc)
        else:
            sparse_varlen_feature_columns.append(fc)

    hist_len = features['hist_len']

    inputs_list = list(features.values())
    embedding_dict = create_embedding_matrix(dnn_feature_columns,
                                             l2_reg_embedding,
                                             init_std,
                                             seed,
                                             prefix="")
    history_emb_list = embedding_lookup(embedding_dict,
                                        features,
                                        history_feature_columns,
                                        history_fc_names,
                                        history_fc_names,
                                        to_list=True)
    history_emb = concat_func(history_emb_list, mask=False)

    target_emb_list = embedding_lookup(embedding_dict,
                                       features,
                                       sparse_feature_columns, ['item'],
                                       history_feature_list,
                                       to_list=True)
    target_emb_tmp = concat_func(target_emb_list, mask=False)
    target_emb_size = target_emb_tmp.get_shape()[-1].value

    target_emb = tf.keras.layers.Lambda(
        shape_target, arguments={'target_emb_size':
                                 target_emb_size})(target_emb_tmp)

    dnn_input_emb_list = embedding_lookup(embedding_dict,
                                          features,
                                          sparse_feature_columns,
                                          mask_feat_list=history_feature_list,
                                          to_list=True)
    sequence_embed_dict = varlen_embedding_lookup(
        embedding_dict, features, sparse_varlen_feature_columns)
    sequence_embed_list = get_varlen_pooling_list(
        sequence_embed_dict,
        features,
        sparse_varlen_feature_columns,
        to_list=True)
    dnn_input_emb_list += sequence_embed_list

    deep_input_emb = concat_func(dnn_input_emb_list)
    user_other_feature = Flatten()(deep_input_emb)

    max_len = history_emb.get_shape()[1].value

    high_capsule = CapsuleLayer(input_units=target_emb_size,
                                out_units=target_emb_size,
                                max_len=max_len,
                                k_max=k_max)((history_emb, hist_len))
    other_feature_tile = tf.keras.layers.Lambda(
        tile_user_otherfeat, arguments={'k_max': k_max})(user_other_feature)

    user_deep_input = Concatenate()(
        [NoMask()(other_feature_tile), high_capsule])

    user_embeddings = DNN((user_hidden_unit, target_emb_size),
                          dnn_activation,
                          l2_reg_dnn,
                          dnn_dropout,
                          dnn_use_bn,
                          seed,
                          name="user_embedding")(user_deep_input)

    k_user = tf.cast(tf.maximum(
        1.,
        tf.minimum(tf.cast(k_max, dtype="float32"),
                   tf.log1p(tf.cast(hist_len, dtype="float32")) / tf.log(2.))),
                     dtype="int64")  # [B,1] forword/Cast_2

    user_embedding_final = DotProductAttentionLayer(
        shape=[target_emb_size, target_emb_size])(
            (user_embeddings, target_emb), seq_length=k_user, max_len=k_max)

    output = SampledSoftmaxLayer(
        target_song_size=target_song_size,
        target_emb_size=target_emb_size)(inputs=(user_embedding_final,
                                                 features['item']))

    model = Model(inputs=inputs_list, outputs=output)
    return model
예제 #3
0
def SDM(user_feature_columns,
        item_feature_columns,
        history_feature_list,
        num_sampled=5,
        units=64,
        rnn_layers=2,
        dropout_rate=0.2,
        rnn_num_res=1,
        num_head=4,
        l2_reg_embedding=1e-6,
        dnn_activation='tanh',
        init_std=0.0001,
        seed=1024):
    """Instantiates the Sequential Deep Matching Model architecture.

    :param user_feature_columns: An iterable containing user's features used by  the model.
    :param item_feature_columns: An iterable containing item's features used by  the model.
    :param history_feature_list: list,to indicate short and prefer sequence sparse field
    :param num_sampled: int, the number of classes to randomly sample per batch.
    :param units: int, dimension for each output layer
    :param rnn_layers: int, layer number of rnn
    :param dropout_rate: float in [0,1), the probability we will drop out a given DNN coordinate.
    :param rnn_num_res: int. The number of residual layers in rnn layers
    :param num_head: int int, the number of attention head
    :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
    :param dnn_activation: Activation function to use in deep net
    :param init_std: float,to use as the initialize std of embedding vector
    :param seed: integer ,to use as random seed.
    :return: A Keras model instance.

    """

    if len(item_feature_columns) > 1:
        raise ValueError("Now MIND only support 1 item feature like item_id")
    item_feature_column = item_feature_columns[0]
    item_feature_name = item_feature_column.name
    item_vocabulary_size = item_feature_columns[0].vocabulary_size

    features = build_input_features(user_feature_columns)

    user_inputs_list = list(features.values())

    sparse_feature_columns = list(
        filter(lambda x: isinstance(x, SparseFeat),
               user_feature_columns)) if user_feature_columns else []
    dense_feature_columns = list(
        filter(lambda x: isinstance(x, DenseFeat),
               user_feature_columns)) if user_feature_columns else []
    if len(dense_feature_columns) != 0:
        raise ValueError("Now SDM don't support dense feature")
    varlen_sparse_feature_columns = list(
        filter(lambda x: isinstance(x, VarLenSparseFeat),
               user_feature_columns)) if user_feature_columns else []

    sparse_varlen_feature_columns = []
    prefer_history_columns = []
    short_history_columns = []

    prefer_fc_names = list(map(lambda x: "prefer_" + x, history_feature_list))
    short_fc_names = list(map(lambda x: "short_" + x, history_feature_list))
    for fc in varlen_sparse_feature_columns:
        feature_name = fc.name
        if feature_name in prefer_fc_names:
            prefer_history_columns.append(fc)

        elif feature_name in short_fc_names:
            short_history_columns.append(fc)
        else:
            sparse_varlen_feature_columns.append(fc)

    embedding_matrix_dict = create_embedding_matrix(user_feature_columns +
                                                    item_feature_columns,
                                                    l2_reg_embedding,
                                                    init_std,
                                                    seed,
                                                    prefix="")

    item_features = build_input_features(item_feature_columns)
    item_inputs_list = list(item_features.values())

    prefer_emb_list = embedding_lookup(embedding_matrix_dict,
                                       features,
                                       prefer_history_columns,
                                       prefer_fc_names,
                                       prefer_fc_names,
                                       to_list=True)  # L^u
    short_emb_list = embedding_lookup(embedding_matrix_dict,
                                      features,
                                      short_history_columns,
                                      short_fc_names,
                                      short_fc_names,
                                      to_list=True)  # S^u
    # dense_value_list = get_dense_input(features, dense_feature_columns)
    user_emb_list = embedding_lookup(embedding_matrix_dict,
                                     features,
                                     sparse_feature_columns,
                                     to_list=True)

    sequence_embed_dict = varlen_embedding_lookup(
        embedding_matrix_dict, features, sparse_varlen_feature_columns)
    sequence_embed_list = get_varlen_pooling_list(
        sequence_embed_dict,
        features,
        sparse_varlen_feature_columns,
        to_list=True)
    user_emb_list += sequence_embed_list  # e^u
    # if len(user_emb_list) > 0 or len(dense_value_list) > 0:
    #     user_emb_feature = combined_dnn_input(user_emb_list, dense_value_list)
    user_emb = concat_func(user_emb_list)
    user_emb_output = Dense(units,
                            activation=dnn_activation,
                            name="user_emb_output")(user_emb)

    prefer_sess_length = features['prefer_sess_length']
    prefer_att_outputs = []
    for i, prefer_emb in enumerate(prefer_emb_list):
        prefer_attention_output = AttentionSequencePoolingLayer(
            dropout_rate=0)([user_emb_output, prefer_emb, prefer_sess_length])
        prefer_att_outputs.append(prefer_attention_output)
    prefer_att_concat = concat_func(prefer_att_outputs)
    prefer_output = Dense(units,
                          activation=dnn_activation,
                          name="prefer_output")(prefer_att_concat)

    short_sess_length = features['short_sess_length']
    short_emb_concat = concat_func(short_emb_list)
    short_emb_input = Dense(units,
                            activation=dnn_activation,
                            name="short_emb_input")(short_emb_concat)

    short_rnn_output = DynamicMultiRNN(
        num_units=units,
        return_sequence=True,
        num_layers=rnn_layers,
        num_residual_layers=rnn_num_res,
        dropout_rate=dropout_rate)([short_emb_input, short_sess_length])

    short_att_output = SelfMultiHeadAttention(
        num_units=units,
        head_num=num_head,
        dropout_rate=dropout_rate,
        future_binding=True,
        use_layer_norm=True)([short_rnn_output, short_sess_length
                              ])  # [batch_size, time, num_units]

    short_output = UserAttention(num_units=units, activation=dnn_activation, use_res=True, dropout_rate=dropout_rate) \
        ([user_emb_output, short_att_output, short_sess_length])

    gate_input = concat_func([prefer_output, short_output, user_emb_output])
    gate = Dense(units, activation='sigmoid')(gate_input)

    gate_output = Lambda(
        lambda x: tf.multiply(x[0], x[1]) + tf.multiply(1 - x[0], x[2]))(
            [gate, short_output, prefer_output])
    gate_output_reshape = Lambda(lambda x: tf.squeeze(x, 1))(gate_output)

    item_index = EmbeddingIndex(list(range(item_vocabulary_size)))(
        item_features[item_feature_name])
    item_embedding_matrix = embedding_matrix_dict[item_feature_name]
    item_embedding_weight = NoMask()(item_embedding_matrix(item_index))

    pooling_item_embedding_weight = PoolingLayer()([item_embedding_weight])

    output = SampledSoftmaxLayer(num_sampled=num_sampled)([
        pooling_item_embedding_weight, gate_output_reshape,
        item_features[item_feature_name]
    ])
    model = Model(inputs=user_inputs_list + item_inputs_list, outputs=output)

    model.__setattr__("user_input", user_inputs_list)
    model.__setattr__("user_embedding", gate_output_reshape)

    model.__setattr__("item_input", item_inputs_list)
    model.__setattr__(
        "item_embedding",
        get_item_embedding(pooling_item_embedding_weight,
                           item_features[item_feature_name]))

    return model
예제 #4
0
def YoutubeDNN(
    user_feature_columns,
    item_feature_columns,
    num_sampled=5,
    user_dnn_hidden_units=(64, 16),
    dnn_activation='relu',
    dnn_use_bn=False,
    l2_reg_dnn=0,
    l2_reg_embedding=1e-6,
    dnn_dropout=0,
    init_std=0.0001,
    seed=1024,
):
    """Instantiates the YoutubeDNN Model architecture.

    :param user_feature_columns: An iterable containing user's features used by  the model.
    :param item_feature_columns: An iterable containing item's features used by  the model.
    :param num_sampled: int, the number of classes to randomly sample per batch.
    :param user_dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of user tower
    :param dnn_activation: Activation function to use in deep net
    :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in deep net
    :param l2_reg_dnn: float. L2 regularizer strength applied to DNN
    :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
    :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate.
    :param init_std: float,to use as the initialize std of embedding vector
    :param seed: integer ,to use as random seed.
    :return: A Keras model instance.

    """

    if len(item_feature_columns) > 1:
        raise ValueError(
            "Now YoutubeNN only support 1 item feature like item_id")
    item_feature_name = item_feature_columns[0].name

    embedding_matrix_dict = create_embedding_matrix(user_feature_columns +
                                                    item_feature_columns,
                                                    l2_reg_embedding,
                                                    init_std,
                                                    seed,
                                                    prefix="")

    user_features = build_input_features(user_feature_columns)
    user_inputs_list = list(user_features.values())
    user_sparse_embedding_list, user_dense_value_list = input_from_feature_columns(
        user_features,
        user_feature_columns,
        l2_reg_embedding,
        init_std,
        seed,
        embedding_matrix_dict=embedding_matrix_dict)
    user_dnn_input = combined_dnn_input(user_sparse_embedding_list,
                                        user_dense_value_list)

    item_features = build_input_features(item_feature_columns)
    item_inputs_list = list(item_features.values())
    user_dnn_out = DNN(
        user_dnn_hidden_units,
        dnn_activation,
        l2_reg_dnn,
        dnn_dropout,
        dnn_use_bn,
        seed,
    )(user_dnn_input)

    item_embedding = embedding_matrix_dict[item_feature_name]

    output = SampledSoftmaxLayer(item_embedding, num_sampled=num_sampled)(
        inputs=(user_dnn_out, item_features[item_feature_name]))
    model = Model(inputs=user_inputs_list + item_inputs_list, outputs=output)

    model.__setattr__("user_input", user_inputs_list)
    model.__setattr__("user_embedding", user_dnn_out)

    model.__setattr__("item_input", item_inputs_list)
    model.__setattr__(
        "item_embedding",
        get_item_embedding(item_embedding, item_features[item_feature_name]))

    return model
예제 #5
0
    def _model_fn(features, labels, mode, config):
        train_flag = (mode == tf.estimator.ModeKeys.TRAIN)
        with variable_scope(DNN_SCOPE_NAME):
            sparse_feature_columns = []
            dense_feature_columns = []
            varlen_sparse_feature_columns = []

            for feat in dnn_feature_columns:

                new_feat_name = list(feat.parse_example_spec.keys())[0]
                if new_feat_name in ['hist_price_id', 'hist_des_id']:
                    varlen_sparse_feature_columns.append(
                        VarLenSparseFeat(SparseFeat(new_feat_name,
                                                    vocabulary_size=100,
                                                    embedding_dim=32,
                                                    use_hash=False),
                                         maxlen=3))
                elif is_embedding(feat):
                    sparse_feature_columns.append(
                        SparseFeat(new_feat_name,
                                   vocabulary_size=feat[0]._num_buckets + 1,
                                   embedding_dim=feat.dimension))
                else:
                    dense_feature_columns.append(DenseFeat(new_feat_name))

            history_feature_columns = []
            sparse_varlen_feature_columns = []
            history_fc_names = list(
                map(lambda x: "hist_" + x, history_feature_list))
            for fc in varlen_sparse_feature_columns:
                feature_name = fc.name
                if feature_name in history_fc_names:
                    history_feature_columns.append(fc)
                else:
                    sparse_varlen_feature_columns.append(fc)
            my_feature_columns = sparse_feature_columns + dense_feature_columns + varlen_sparse_feature_columns
            embedding_dict = create_embedding_matrix(my_feature_columns,
                                                     l2_reg_embedding,
                                                     seed,
                                                     prefix="")

            query_emb_list = embedding_lookup(embedding_dict,
                                              features,
                                              sparse_feature_columns,
                                              history_feature_list,
                                              history_feature_list,
                                              to_list=True)
            print('query_emb_list', query_emb_list)
            print('embedding_dict', embedding_dict)
            print('haha')
            print('history_feature_columns', history_feature_columns)
            print('haha')
            keys_emb_list = embedding_lookup(embedding_dict,
                                             features,
                                             history_feature_columns,
                                             history_fc_names,
                                             history_fc_names,
                                             to_list=True)
            print('keys_emb_list', keys_emb_list)
            dnn_input_emb_list = embedding_lookup(
                embedding_dict,
                features,
                sparse_feature_columns,
                mask_feat_list=history_feature_list,
                to_list=True)
            print('dnn_input_emb_list', dnn_input_emb_list)
            dense_value_list = get_dense_input(features, dense_feature_columns)
            sequence_embed_dict = varlen_embedding_lookup(
                embedding_dict, features, sparse_varlen_feature_columns)
            sequence_embed_list = get_varlen_pooling_list(
                sequence_embed_dict,
                features,
                sparse_varlen_feature_columns,
                to_list=True)

            dnn_input_emb_list += sequence_embed_list

            keys_emb = concat_func(keys_emb_list, mask=True)
            deep_input_emb = concat_func(dnn_input_emb_list)
            query_emb = concat_func(query_emb_list, mask=True)
            hist = AttentionSequencePoolingLayer(
                att_hidden_size,
                att_activation,
                weight_normalization=att_weight_normalization,
                supports_masking=True)([query_emb, keys_emb])

            deep_input_emb = tf.keras.layers.Concatenate()(
                [NoMask()(deep_input_emb), hist])
            deep_input_emb = tf.keras.layers.Flatten()(deep_input_emb)
            dnn_input = combined_dnn_input([deep_input_emb], dense_value_list)
            output = DNN(dnn_hidden_units,
                         dnn_activation,
                         l2_reg_dnn,
                         dnn_dropout,
                         dnn_use_bn,
                         seed=seed)(dnn_input)
            final_logit = tf.keras.layers.Dense(
                1,
                use_bias=False,
                kernel_initializer=tf.keras.initializers.glorot_normal(seed))(
                    output)
        #             logits_list.append(final_logit)
        #         logits = add_func(logits_list)
        #             print(labels)
        #             tf.summary.histogram(final_logit + '/final_logit', final_logit)
        return deepctr_model_fn(features,
                                mode,
                                final_logit,
                                labels,
                                task,
                                linear_optimizer,
                                dnn_optimizer,
                                training_chief_hooks=training_chief_hooks)
예제 #6
0
def DSSM(user_feature_columns,
         item_feature_columns,
         user_dnn_hidden_units=(64, 32),
         item_dnn_hidden_units=(64, 32),
         dnn_activation='tanh',
         dnn_use_bn=False,
         l2_reg_dnn=0,
         l2_reg_embedding=1e-6,
         dnn_dropout=0,
         init_std=0.0001,
         seed=1024,
         metric='cos'):

    embedding_matrix_dict = create_embedding_matrix(user_feature_columns +
                                                    item_feature_columns,
                                                    l2_reg_embedding,
                                                    init_std,
                                                    seed,
                                                    seq_mask_zero=True)

    user_features = build_input_features(user_feature_columns)
    user_inputs_list = list(user_features.values())
    user_sparse_embedding_list, user_dense_value_list = input_from_feature_columns(
        user_features,
        user_feature_columns,
        l2_reg_embedding,
        init_std,
        seed,
        embedding_matrix_dict=embedding_matrix_dict)
    user_dnn_input = combined_dnn_input(user_sparse_embedding_list,
                                        user_dense_value_list)

    item_features = build_input_features(item_feature_columns)
    item_inputs_list = list(item_features.values())
    item_sparse_embedding_list, item_dense_value_list = input_from_feature_columns(
        item_features,
        item_feature_columns,
        l2_reg_embedding,
        init_std,
        seed,
        embedding_matrix_dict=embedding_matrix_dict)
    item_dnn_input = combined_dnn_input(item_sparse_embedding_list,
                                        item_dense_value_list)

    user_dnn_out = DNN(
        user_dnn_hidden_units,
        dnn_activation,
        l2_reg_dnn,
        dnn_dropout,
        dnn_use_bn,
        seed,
    )(user_dnn_input)

    item_dnn_out = DNN(item_dnn_hidden_units, dnn_activation, l2_reg_dnn,
                       dnn_dropout, dnn_use_bn, seed)(item_dnn_input)

    score = Similarity(type=metric)([user_dnn_out, item_dnn_out])

    output = PredictionLayer("binary", False)(score)

    model = Model(inputs=user_inputs_list + item_inputs_list, outputs=output)

    plot_model(model, to_file='dnn.png', show_shapes=True)
    print("go")
    model.__setattr__("user_input", user_inputs_list)
    model.__setattr__("item_input", item_inputs_list)
    model.__setattr__("user_embedding", user_dnn_out)
    model.__setattr__("item_embedding", item_dnn_out)
    return model
예제 #7
0
파일: dssm.py 프로젝트: zwcdp/DeepMatch
def DSSM(user_feature_columns,
         item_feature_columns,
         user_dnn_hidden_units=(64, 32),
         item_dnn_hidden_units=(64, 32),
         dnn_activation='tanh',
         dnn_use_bn=False,
         l2_reg_dnn=0,
         l2_reg_embedding=1e-6,
         dnn_dropout=0,
         init_std=0.0001,
         seed=1024,
         metric='cos'):
    """Instantiates the Deep Structured Semantic Model architecture.

    :param user_feature_columns: An iterable containing user's features used by  the model.
    :param item_feature_columns: An iterable containing item's features used by  the model.
    :param user_dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of user tower
    :param item_dnn_hidden_units: list,list of positive integer or empty list, the layer number and units in each layer of item tower
    :param dnn_activation: Activation function to use in deep net
    :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in deep net
    :param l2_reg_dnn: float. L2 regularizer strength applied to DNN
    :param l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
    :param dnn_dropout: float in [0,1), the probability we will drop out a given DNN coordinate.
    :param init_std: float,to use as the initialize std of embedding vector
    :param seed: integer ,to use as random seed.
    :param metric: str, ``"cos"`` for  cosine  or  ``"ip"`` for inner product
    :return: A Keras model instance.

    """

    embedding_matrix_dict = create_embedding_matrix(user_feature_columns +
                                                    item_feature_columns,
                                                    l2_reg_embedding,
                                                    init_std,
                                                    seed,
                                                    seq_mask_zero=True)

    user_features = build_input_features(user_feature_columns)
    user_inputs_list = list(user_features.values())
    user_sparse_embedding_list, user_dense_value_list = input_from_feature_columns(
        user_features,
        user_feature_columns,
        l2_reg_embedding,
        init_std,
        seed,
        embedding_matrix_dict=embedding_matrix_dict)
    user_dnn_input = combined_dnn_input(user_sparse_embedding_list,
                                        user_dense_value_list)

    item_features = build_input_features(item_feature_columns)
    item_inputs_list = list(item_features.values())
    item_sparse_embedding_list, item_dense_value_list = input_from_feature_columns(
        item_features,
        item_feature_columns,
        l2_reg_embedding,
        init_std,
        seed,
        embedding_matrix_dict=embedding_matrix_dict)
    item_dnn_input = combined_dnn_input(item_sparse_embedding_list,
                                        item_dense_value_list)

    user_dnn_out = DNN(
        user_dnn_hidden_units,
        dnn_activation,
        l2_reg_dnn,
        dnn_dropout,
        dnn_use_bn,
        seed,
    )(user_dnn_input)

    item_dnn_out = DNN(item_dnn_hidden_units, dnn_activation, l2_reg_dnn,
                       dnn_dropout, dnn_use_bn, seed)(item_dnn_input)

    score = Similarity(type=metric)([user_dnn_out, item_dnn_out])

    output = PredictionLayer("binary", False)(score)

    model = Model(inputs=user_inputs_list + item_inputs_list, outputs=output)

    model.__setattr__("user_input", user_inputs_list)
    model.__setattr__("item_input", item_inputs_list)
    model.__setattr__("user_embedding", user_dnn_out)
    model.__setattr__("item_embedding", item_dnn_out)

    return model