Exemplo n.º 1
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, 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 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,
                                                    seed=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, seed=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, seed=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=seed)(user_dnn_input)

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

    score = Similarity(type=metric, gamma = 10)([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
Exemplo n.º 2
0
def FM(user_feature_columns, item_feature_columns, l2_reg_embedding=1e-6, init_std=0.0001, seed=1024, metric='cos'):
    """Instantiates the FM 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 l2_reg_embedding: float. L2 regularizer strength applied to embedding vector
    :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,
                                                                                   support_dense=False,
                                                                                   embedding_matrix_dict=embedding_matrix_dict)

    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,
                                                                                   support_dense=False,
                                                                                   embedding_matrix_dict=embedding_matrix_dict)

    user_dnn_input = concat_func(user_sparse_embedding_list, axis=1)
    user_vector_sum = Lambda(lambda x: reduce_sum(x, axis=1, keep_dims=False))(user_dnn_input)

    item_dnn_input = concat_func(item_sparse_embedding_list, axis=1)
    item_vector_sum = Lambda(lambda x: reduce_sum(x, axis=1, keep_dims=False))(item_dnn_input)

    score = Similarity(type=metric)([user_vector_sum, item_vector_sum])

    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__("user_embedding", user_vector_sum)

    model.__setattr__("item_input", item_inputs_list)
    model.__setattr__("item_embedding", item_vector_sum)

    return model
Exemplo n.º 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
Exemplo n.º 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
Exemplo n.º 5
0
def MIND(user_feature_columns,
         item_feature_columns,
         num_sampled=5,
         k_max=2,
         p=1.0,
         dynamic_k=False,
         user_dnn_hidden_units=(64, 32),
         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 MIND 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 k_max: int, the max size of user interest embedding
    :param p: float,the parameter for adjusting the attention distribution in LabelAwareAttention.
    :param dynamic_k: bool, whether or not use dynamic interest number
    :param dnn_use_bn: bool. Whether use BatchNormalization before activation or not in deep net
    :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:  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 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
    item_embedding_dim = item_feature_columns[0].embedding_dim
    # item_index = Input(tensor=tf.constant([list(range(item_vocabulary_size))]))

    history_feature_list = [item_feature_name]

    features = build_input_features(user_feature_columns)
    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 []
    varlen_sparse_feature_columns = list(
        filter(lambda x: isinstance(x, VarLenSparseFeat),
               user_feature_columns)) if user_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)
    seq_max_len = history_feature_columns[0].maxlen
    inputs_list = list(features.values())

    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)

    query_emb_list = embedding_lookup(embedding_matrix_dict,
                                      item_features,
                                      item_feature_columns,
                                      history_feature_list,
                                      history_feature_list,
                                      to_list=True)
    keys_emb_list = embedding_lookup(embedding_matrix_dict,
                                     features,
                                     history_feature_columns,
                                     history_fc_names,
                                     history_fc_names,
                                     to_list=True)
    dnn_input_emb_list = embedding_lookup(embedding_matrix_dict,
                                          features,
                                          sparse_feature_columns,
                                          mask_feat_list=history_feature_list,
                                          to_list=True)
    dense_value_list = get_dense_input(features, dense_feature_columns)

    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)

    dnn_input_emb_list += sequence_embed_list

    # keys_emb = concat_func(keys_emb_list, mask=True)
    # query_emb = concat_func(query_emb_list, mask=True)

    history_emb = PoolingLayer()(NoMask()(keys_emb_list))
    target_emb = PoolingLayer()(NoMask()(query_emb_list))

    # target_emb_size = target_emb.get_shape()[-1].value
    # max_len = history_emb.get_shape()[1].value
    hist_len = features['hist_len']

    high_capsule = CapsuleLayer(input_units=item_embedding_dim,
                                out_units=item_embedding_dim,
                                max_len=seq_max_len,
                                k_max=k_max)((history_emb, hist_len))

    if len(dnn_input_emb_list) > 0 or len(dense_value_list) > 0:
        user_other_feature = combined_dnn_input(dnn_input_emb_list,
                                                dense_value_list)

        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])
    else:
        user_deep_input = high_capsule

    user_embeddings = DNN(user_dnn_hidden_units,
                          dnn_activation,
                          l2_reg_dnn,
                          dnn_dropout,
                          dnn_use_bn,
                          seed,
                          name="user_embedding")(user_deep_input)
    item_inputs_list = list(item_features.values())

    item_embedding_matrix = embedding_matrix_dict[item_feature_name]

    item_index = EmbeddingIndex(list(range(item_vocabulary_size)))(
        item_features[item_feature_name])

    item_embedding_weight = NoMask()(item_embedding_matrix(item_index))

    pooling_item_embedding_weight = PoolingLayer()([item_embedding_weight])

    if dynamic_k:
        user_embedding_final = LabelAwareAttention(
            k_max=k_max,
            pow_p=p,
        )((user_embeddings, target_emb, hist_len))
    else:
        user_embedding_final = LabelAwareAttention(
            k_max=k_max,
            pow_p=p,
        )((user_embeddings, target_emb))

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

    model.__setattr__("user_input", inputs_list)
    model.__setattr__("user_embedding", user_embeddings)

    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
def Mind(user_feature_columns,
         item_feature_columns,
         num_sampled=5,
         k_max=2,
         p=1.0,
         dynamic_k=False,
         user_dnn_hidden_units=(64, 32),
         dnn_activation='relu',
         dnn_use_bn=False,
         l2_reg_dnn=0,
         l2_reg_embedding=1e-6,
         dnn_dropout=0,
         output_activation='linear',
         seed=1024):
    """
        :param k_max: 用户兴趣胶囊的最大个数
    """
    # 目前这里只支持item_feature_columns为1的情况,即只能转入item_id
    if len(item_feature_columns) > 1:
        raise ValueError("Now MIND only support 1 item feature like item_id")

    # 获取item相关的配置参数
    item_feature_column = item_feature_columns[0]
    item_feature_name = item_feature_column.name
    item_vocabulary_size = item_feature_column.vocabulary_size
    item_embedding_dim = item_feature_column.embedding_dim

    behavior_feature_list = [item_feature_name]

    # 为用户特征创建Input层
    user_input_layer_dict = build_input_layers(user_feature_columns)
    item_input_layer_dict = build_input_layers(item_feature_columns)
    # 将Input层转化成列表的形式作为model的输入
    user_input_layers = list(user_input_layer_dict.values())
    item_input_layers = list(item_input_layer_dict.values())

    # 筛选出特征中的sparse特征和dense特征,方便单独处理
    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 []
    varlen_feature_columns = list(
        filter(lambda x: isinstance(x, VarLenSparseFeat),
               user_feature_columns)) if user_feature_columns else []

    # 由于这个变长序列里面只有历史点击文章,没有类别啥的,所以这里直接可以用varlen_feature_columns
    # deepctr这里单独把点击文章这个放到了history_feature_columns
    seq_max_len = varlen_feature_columns[0].maxlen

    # 构建embedding字典
    embedding_layer_dict = build_embedding_layers(user_feature_columns +
                                                  item_feature_columns)

    # 获取当前的行为特征(doc)的embedding,这里面可能又多个类别特征,所以需要pooling下
    query_embed_list = embedding_lookup(behavior_feature_list,
                                        item_input_layer_dict,
                                        embedding_layer_dict)  # 长度为1
    # 获取行为序列(doc_id序列, hist_doc_id) 对应的embedding,这里有可能有多个行为产生了行为序列,所以需要使用列表将其放在一起
    keys_embed_list = embedding_lookup([varlen_feature_columns[0].name],
                                       user_input_layer_dict,
                                       embedding_layer_dict)  # 长度为1

    # 用户离散特征的输入层与embedding层拼接
    dnn_input_emb_list = embedding_lookup(
        [col.name for col in sparse_feature_columns], user_input_layer_dict,
        embedding_layer_dict)

    # 获取dense
    dnn_dense_input = []
    for fc in dense_feature_columns:
        if fc.name != 'hist_len':  # 连续特征不要这个
            dnn_dense_input.append(user_input_layer_dict[fc.name])

    # 把keys_emb_list和query_emb_listpooling操作, 这是因为可能每个商品不仅有id,还可能用类别,品牌等多个embedding向量,这种需要pooling成一个
    history_emb = PoolingLayer()(NoMask()(keys_embed_list))  # (None, 50, 8)
    target_emb = PoolingLayer()(NoMask()(query_embed_list))  # (None, 1, 8)

    hist_len = user_input_layer_dict['hist_len']
    # 胶囊网络
    # (None, 2, 8) 得到了两个兴趣胶囊
    high_capsule = CapsuleLayer(input_units=item_embedding_dim,
                                out_units=item_embedding_dim,
                                max_len=seq_max_len,
                                k_max=k_max)((history_emb, hist_len))

    # 把用户的其他特征拼接到胶囊网络上来
    if len(dnn_input_emb_list) > 0 or len(dnn_dense_input) > 0:
        user_other_feature = combined_dnn_input(dnn_input_emb_list,
                                                dnn_dense_input)
        # (None, 2, 32)   这里会发现其他的用户特征是每个胶囊复制了一份,然后拼接起来
        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])  # (None, 2, 40)
    else:
        user_deep_input = high_capsule

    # 接下来过一个DNN层,获取最终的用户表示向量 如果是三维输入, 那么最后一个维度与w相乘,所以这里如果不自己写,可以用Dense层的列表也可以
    user_embeddings = DNN(user_dnn_hidden_units,
                          dnn_activation,
                          l2_reg_dnn,
                          dnn_dropout,
                          dnn_use_bn,
                          output_activation=output_activation,
                          seed=seed,
                          name="user_embedding")(
                              user_deep_input)  # (None, 2, 8)

    # 接下来,过Label-aware layer
    if dynamic_k:
        user_embedding_final = LabelAwareAttention(
            k_max=k_max,
            pow_p=p,
        )((user_embeddings, target_emb, hist_len))
    else:
        user_embedding_final = LabelAwareAttention(
            k_max=k_max,
            pow_p=p,
        )((user_embeddings, target_emb))

    # 接下来
    item_embedding_matrix = embedding_layer_dict[
        item_feature_name]  # 获取doc_id的embedding层
    item_index = EmbeddingIndex(list(range(item_vocabulary_size)))(
        item_input_layer_dict[item_feature_name])  # 所有doc_id的索引
    item_embedding_weight = NoMask()(
        item_embedding_matrix(item_index))  # 拿到所有item的embedding
    pooling_item_embedding_weight = PoolingLayer()([
        item_embedding_weight
    ])  # 这里依然是当可能不止item_id,或许还有brand_id, cat_id等,需要池化

    # 这里传入的是整个doc_id的embedding, user_embedding, 以及用户点击的doc_id,然后去进行负采样计算损失操作
    output = SampledSoftmaxLayer(num_sampled)([
        pooling_item_embedding_weight, user_embedding_final,
        item_input_layer_dict[item_feature_name]
    ])

    model = Model(inputs=user_input_layers + item_input_layers, outputs=output)

    # 下面是等模型训练完了之后,获取用户和item的embedding
    model.__setattr__("user_input", user_input_layers)
    model.__setattr__("user_embedding", user_embeddings)
    model.__setattr__("item_input", item_input_layers)
    model.__setattr__(
        "item_embedding",
        get_item_embedding(pooling_item_embedding_weight,
                           item_input_layer_dict[item_feature_name]))

    return model
def Sdm(user_feature_columns, item_feature_columns, history_feature_list, num_sampled=5, units=32, rnn_layers=2,
        dropout_rate=0.2, rnn_num_res=1, num_head=4, l2_reg_embedding=1e-6, dnn_activation='tanh', seed=1024):
    """
    :param rnn_num_res: rnn的残差层个数 
    :param history_feature_list: short和long sequence field
    """
    # item_feature目前只支持doc_id, 再加别的就不行了,其实这里可以改造下
    if (len(item_feature_columns)) > 1: 
        raise ValueError("SDM only support 1 item feature like doc_id")
    
    # 获取item_feature的一些属性
    item_feature_column = item_feature_columns[0]
    item_feature_name = item_feature_column.name
    item_vocabulary_size = item_feature_column.vocabulary_size
    
    # 为用户特征创建Input层
    user_input_layer_dict = build_input_layers(user_feature_columns)
    item_input_layer_dict = build_input_layers(item_feature_columns)
    
    # 将Input层转化成列表的形式作为model的输入
    user_input_layers = list(user_input_layer_dict.values())
    item_input_layers = list(item_input_layer_dict.values())
    
    # 筛选出特征中的sparse特征和dense特征,方便单独处理
    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("SDM dont support dense feature")  # 目前不支持Dense feature
    varlen_feature_columns = list(filter(lambda x: isinstance(x, VarLenSparseFeat), user_feature_columns)) if user_feature_columns else []
    
    # 构建embedding字典
    embedding_layer_dict = build_embedding_layers(user_feature_columns+item_feature_columns)
    
    # 拿到短期会话和长期会话列 之前的命名规则在这里起作用
    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_feature_columns:
        if fc.name in prefer_fc_names:
            prefer_history_columns.append(fc)
        elif fc.name in short_fc_names:
            short_history_columns.append(fc)
        else:
            sparse_varlen_feature_columns.append(fc)
    
    # 获取用户的长期行为序列列表 L^u 
    # [<tf.Tensor 'emb_prefer_doc_id_2/Identity:0' shape=(None, 50, 32) dtype=float32>, <tf.Tensor 'emb_prefer_cat1_2/Identity:0' shape=(None, 50, 32) dtype=float32>, <tf.Tensor 'emb_prefer_cat2_2/Identity:0' shape=(None, 50, 32) dtype=float32>]
    prefer_emb_list = embedding_lookup(prefer_fc_names, user_input_layer_dict, embedding_layer_dict)
    # 获取用户的短期序列列表 S^u
    # [<tf.Tensor 'emb_short_doc_id_2/Identity:0' shape=(None, 5, 32) dtype=float32>, <tf.Tensor 'emb_short_cat1_2/Identity:0' shape=(None, 5, 32) dtype=float32>, <tf.Tensor 'emb_short_cat2_2/Identity:0' shape=(None, 5, 32) dtype=float32>]
    short_emb_list = embedding_lookup(short_fc_names, user_input_layer_dict, embedding_layer_dict)
    
    # 用户离散特征的输入层与embedding层拼接 e^u
    user_emb_list = embedding_lookup([col.name for col in sparse_feature_columns], user_input_layer_dict, embedding_layer_dict)
    user_emb = concat_func(user_emb_list)
    user_emb_output = Dense(units, activation=dnn_activation, name='user_emb_output')(user_emb)  # (None, 1, 32)
    
    # 长期序列行为编码
    # 过AttentionSequencePoolingLayer --> Concat --> DNN
    prefer_sess_length = user_input_layer_dict['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)   # (None, 1, 64) <== Concat(item_embedding,cat1_embedding,cat2_embedding)
    prefer_output = Dense(units, activation=dnn_activation, name='prefer_output')(prefer_att_concat)
    # print(prefer_output.shape)   # (None, 1, 32)
    
    # 短期行为序列编码
    short_sess_length = user_input_layer_dict['short_sess_length']
    short_emb_concat = concat_func(short_emb_list)   # (None, 5, 64)   这里注意下, 对于短期序列,描述item的side info信息进行了拼接
    short_emb_input = Dense(units, activation=dnn_activation, name='short_emb_input')(short_emb_concat)  # (None, 5, 32)
    # 过rnn 这里的return_sequence=True, 每个时间步都需要输出h
    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])
    # print(short_rnn_output) # (None, 5, 32)
    # 过MultiHeadAttention  # (None, 5, 32)
    short_att_output = MultiHeadAttention(num_units=units, head_num=num_head, dropout_rate=dropout_rate)([short_rnn_output, short_sess_length]) # (None, 5, 64)
    # user_attention # (None, 1, 32)
    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])
    
    # 门控融合
    gated_input = concat_func([prefer_output, short_output, user_emb_output])
    gate = Dense(units, activation='sigmoid')(gated_input)   # (None, 1, 32)
    
    # temp = tf.multiply(gate, short_output) + tf.multiply(1-gate, prefer_output)  感觉这俩一样?
    gated_output = Lambda(lambda x: tf.multiply(x[0], x[1]) + tf.multiply(1-x[0], x[2]))([gate, short_output, prefer_output])  # [None, 1,32]
    gated_output_reshape = Lambda(lambda x: tf.squeeze(x, 1))(gated_output)  # (None, 32)  这个维度必须要和docembedding层的维度一样,否则后面没法sortmax_loss
    
    # 接下来
    item_embedding_matrix = embedding_layer_dict[item_feature_name]  # 获取doc_id的embedding层
    item_index = EmbeddingIndex(list(range(item_vocabulary_size)))(item_input_layer_dict[item_feature_name]) # 所有doc_id的索引
    item_embedding_weight = NoMask()(item_embedding_matrix(item_index))  # 拿到所有item的embedding
    pooling_item_embedding_weight = PoolingLayer()([item_embedding_weight])  # 这里依然是当可能不止item_id,或许还有brand_id, cat_id等,需要池化
    
    # 这里传入的是整个doc_id的embedding, user_embedding, 以及用户点击的doc_id,然后去进行负采样计算损失操作
    output = SampledSoftmaxLayer(num_sampled)([pooling_item_embedding_weight, gated_output_reshape, item_input_layer_dict[item_feature_name]])
    
    model = Model(inputs=user_input_layers+item_input_layers, outputs=output)
    
    # 下面是等模型训练完了之后,获取用户和item的embedding
    model.__setattr__("user_input", user_input_layers)
    model.__setattr__("user_embedding", gated_output_reshape)  # 用户embedding是取得门控融合的用户向量
    model.__setattr__("item_input", item_input_layers)
    # item_embedding取得pooling_item_embedding_weight, 这个会发现是负采样操作训练的那个embedding矩阵
    model.__setattr__("item_embedding", get_item_embedding(pooling_item_embedding_weight, item_input_layer_dict[item_feature_name]))
    
    return model
Exemplo n.º 8
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
Exemplo n.º 9
0
def DSSM4FatureColumn(user_feature_columns,
                      item_feature_columns,
                      user_inputs_keys,
                      item_inputs_keys,
                      user_dnn_hidden_units=(64, 32),
                      item_dnn_hidden_units=(64, 32),
                      dnn_activation='tanh',
                      dnn_use_bn=False,
                      l2_reg_dnn=0,
                      dnn_dropout=0,
                      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 seed: integer ,to use as random seed.
    :param metric: str, ``"cos"`` for  cosine  or  ``"ip"`` for inner product
    :return: A Keras model instance.

    """

    # #TODO:build_input_features4fc函数增加不同输入维度的方法
    user_features = build_input_features4fc(
        user_inputs_keys)  # Input有不同维度的情况,需要修改该函数
    user_inputs_list = list(user_features.values())

    # #example for output user id or item id, this key must be in tfrecord
    # userid_output_ = tf.identity(user_features.get('userid'))

    user_dnn_input = tf.keras.layers.DenseFeatures(user_feature_columns)(
        user_features)

    item_features = build_input_features4fc(item_inputs_keys)
    item_inputs_list = list(item_features.values())

    item_dnn_input = tf.keras.layers.DenseFeatures(item_feature_columns)(
        item_features)

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

    item_dnn_out = DNN(item_dnn_hidden_units,
                       dnn_activation,
                       l2_reg_dnn,
                       dnn_dropout,
                       dnn_use_bn,
                       seed=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)
    # model.__setattr__("user_ids", userid_output_)

    return model
Exemplo n.º 10
0
def YoutubeDNN(
    user_feature_columns,
    item_feature_columns,
    num_sampled=5,
    user_dnn_hidden_units=(64, 32),
    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
    item_vocabulary_size = item_feature_columns[0].vocabulary_size

    #构建User和 item 的 Embedding dict
    embedding_matrix_dict = create_embedding_matrix(user_feature_columns +
                                                    item_feature_columns,
                                                    l2_reg_embedding,
                                                    init_std,
                                                    seed,
                                                    prefix="")

    #构建 User Input dict
    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 Input dict
    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)

    print(item_features[item_feature_name])
    print(list(range(item_vocabulary_size)))
    item_index = EmbeddingIndex(list(range(item_vocabulary_size)))(
        item_features[item_feature_name])

    item_embedding_matrix = embedding_matrix_dict[item_feature_name]
    print(item_embedding_matrix(item_index))
    item_embedding_weight = NoMask()(item_embedding_matrix(item_index))

    pooling_item_embedding_weight = PoolingLayer()([item_embedding_weight])

    # tf.nn.sampled_softmax_loss,在类别很多的情况下训练softmax分类器的高效的方法。
    # 注意:仅在训练时使用这一采样操作,测试时还是用全部的类别
    output = SampledSoftmaxLayer(num_sampled=num_sampled)([
        pooling_item_embedding_weight, 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(pooling_item_embedding_weight,
                           item_features[item_feature_name]))

    return model