DeepFM2

本文介绍了一种结合了深度学习和因子分解机优点的推荐系统模型——DeepFM模型。该模型通过Embedding层将稀疏特征转化为稠密向量,并通过线性组合、交叉项以及深层神经网络预测目标变量,适用于点击率预估等任务。
部署运行你感兴趣的模型镜像
from __future__ import print_function

import tensorflow as tf

from .base import TFBaseModel
from .utils import tf_weighted_sigmoid_ce_with_logits
'''
structure:
Embedding=> LR|FM|MLP=>sum all result
'''

class DeepFM(TFBaseModel):
    def __init__(self, feature_dim_dict, embedding_size=4,
                 use_cross=True, hidden_size=[], l2_reg_w=0.00002, l2_reg_V=0.00002,
                 init_std=0.0001, seed=1024, keep_prob=0.5,
                 checkpoint_path=None, ):

        super(DeepFM, self).__init__(
            seed=seed, checkpoint_path=checkpoint_path, )
        if not isinstance(feature_dim_dict,
                          dict) or "sparse" not in feature_dim_dict or "dense" not in feature_dim_dict:
            raise ValueError(
                "feature_dim must be a dict like {'sparse':{'field_1':4,'field_2':3,'field_3':2},'dense':['field_5',]}")

        field_dim = len(feature_dim_dict["sparse"])
        feature_dim = [v for k, v in feature_dim_dict["sparse"].items()]
        continuous_dim = len(feature_dim_dict["dense"])
        self.params = locals()
        self._build_graph()

    def _get_output_target(self, ):
        return tf.sigmoid(self.logit)

    def _get_optimizer_loss(self, loss):
        if loss == "logloss":
            return self.log_loss
        if loss == "mse":
            return self.mse_loss

    def _build_graph(self, ):
        with self.graph.as_default():  # , tf.device('/cpu:0'):

            self._create_placeholders()
            self._create_variable()
            self._forward_pass()
            self._create_loss()

    def _get_input_data(self, ):
        if self.params['continuous_dim'] == 0:
            return self.placeholders['X_sparse']
        else:
            return self.placeholders['X_sparse'], self.placeholders['X_dense']

    def _get_input_target(self, ):
        return self.placeholders['Y']

    def _create_placeholders(self, ):
        self.placeholders = {}
        self.placeholders['X_sparse'] = tf.placeholder(
            tf.int32, shape=[None, self.params['field_dim']], name='input_X_sparse')
        self.placeholders['X_dense'] = tf.placeholder(
            tf.float32, shape=[None, self.params['continuous_dim']], name='input_X_dense')

        self.placeholders['Y'] = tf.placeholder(
            tf.float32, shape=[None, ], name='input_Y')
        # addd
        # self.placeholders['continuous_bias'] = tf.placeholder(
        #    tf.float32, shape=[None, self.params['continuous_dim']], name='input_bias')
        # -----
        self.train_flag = tf.placeholder(tf.bool, name='train_flag')

    def _create_variable(self, ):

        self.b = tf.get_variable(name='bias', initializer=tf.constant(0.0), )
        # TODO:  self.init_std/ math.sqrt(float(dim))  #self.params['feature_dim']

        self.sparse_embeddings = [tf.get_variable(name='embed_cate' + str(i) + '-' + feat,
                                                  initializer=tf.random_normal(
                                                      [self.params["feature_dim_dict"]["sparse"][feat],
                                                       self.params['embedding_size']],
                                                      stddev=self.params['init_std'])) for i, feat in
                                  enumerate(self.params["feature_dim_dict"]["sparse"])]
        self.linear_embeddings = [tf.get_variable(name='embed_linear' + str(i) + '-' + feat,
                                                  initializer=tf.random_normal(
                                                      [self.params["feature_dim_dict"]["sparse"][feat], 1],
                                                      stddev=self.params['init_std'])) for i, feat in
                                  enumerate(self.params["feature_dim_dict"]["sparse"])]

        # TODO: normal
        self._l2_reg_w = tf.constant(
            self.params['l2_reg_w'], shape=(1,), name='l2_reg_w')
        self._l2_reg_V = tf.constant(
            self.params['l2_reg_V'], shape=(1,), name='l2_reg_V')

    def _forward_pass(self, ):

        def inverted_dropout(fc, keep_prob):
            return tf.divide(tf.nn.dropout(fc, keep_prob), keep_prob)

        with tf.name_scope("linear_term"):
            linear_term_list = [tf.nn.embedding_lookup(self.linear_embeddings[i], self.placeholders['X_sparse'][:, i])
                                for i in range(self.params["field_dim"])]
            linear_term = tf.reduce_sum(tf.concat(linear_term_list, axis=-1), axis=(1,))

        with tf.name_scope("cross_term"):
            ###
            # print(self.placeholders['X_sparse'][:,0])
            embed_list = [tf.nn.embedding_lookup(self.sparse_embeddings[i], self.placeholders['X_sparse'][:, i]) for i
                          in range(self.params["field_dim"])]
            # print(embed_list)
            embeds = tf.concat(embed_list, axis=1)
            embeds = tf.reshape(embeds, (-1, self.params['field_dim'], self.params['embedding_size']))
            temp_a = tf.reduce_sum(
                tf.matmul(embeds, embeds, transpose_b=True), axis=(1, 2))
            temp_b = tf.reduce_sum(tf.square(embeds), axis=(1, 2))
            cross_term = 0.5 * (temp_a - temp_b)

        deep_input = embeds
        with tf.name_scope('deep_network'):

            # if self.params["continuous_dim"] > 0:
            #     if self.params["continuous_dim"] == 1:
            #         continuous_list = self.placeholders['X_dense']
            #     else:
            #         continuous_list = tf.concat(self.placeholders['X_dense'])
            #     print(tf.layers.flatten(embeds),continuous_list)
            #     deep_input = tf.concat([tf.layers.flatten(embeds), continuous_list],axis=-1)

            if len(self.params['hidden_size']) > 0:
                fc_input = tf.reshape(
                    deep_input, (-1, self.params['field_dim'] * self.params['embedding_size']))
                if self.params['continuous_dim'] > 0:
                    fc_input = tf.concat(
                        [fc_input, self.placeholders['X_dense']], axis=1)
                for l in range(len(self.params['hidden_size'])):
                    fc = tf.contrib.layers.fully_connected(fc_input, self.params['hidden_size'][l],
                                                           activation_fn=tf.nn.relu,
                                                           weights_initializer=tf.truncated_normal_initializer(
                                                               stddev=self.params['init_std']),
                                                           )
                    if l < len(self.params['hidden_size']) - 1:
                        fc = tf.cond(self.train_flag, lambda: inverted_dropout(
                            fc, self.params['keep_prob']), lambda: fc)

                    fc_input = fc

                nn_logit = tf.contrib.layers.fully_connected(fc_input, 1, activation_fn=None,
                                                             weights_initializer=tf.truncated_normal_initializer(
                                                                 stddev=self.params['init_std']),
                                                             )
                nn_logit = tf.reshape(nn_logit, (-1,))

        with tf.name_scope("model_logit"):
            self.logit = self.b + linear_term
            if self.params['use_cross']:
                self.logit += cross_term
            if len(self.params['hidden_size']) > 0:
                self.logit += nn_logit

    def _create_loss(self, ):
        l2_reg_w_loss = 0  # 1 * self._l2_reg_w * tf.nn.l2_loss(self.single_embedding)
        l2_reg_V_loss = 0  # 1 * self._l2_reg_V * tf.nn.l2_loss(self.embeddings)
        # tf.contrib.layers.l2_regularizer()

        # self.log_loss = tf.reduce_sum(tf.multiply(tf.nn.sigmoid_cross_entropy_with_logits(
        #    labels=self.placeholders['Y'], logits=self.logit),self.sample_weight))  # weighted total_loss

        self.log_loss = tf.reduce_sum(tf_weighted_sigmoid_ce_with_logits(
            self.placeholders['Y'], self.logit, self.sample_weight))
        self.mse_loss = tf.squared_difference(
            self.placeholders['Y'], self.logit)

        # self.loss = self.log_loss  # + l2_reg_w_loss
        if self.params['use_cross']:
            # self.loss += l2_reg_V_loss
            pass


if __name__ == '__main__':
    model = DeepFM({"sparse": {"field1": 4, "field2": 3}, "dense": []})
    model.compile('adam', )
    print('DeepFM compile done')

 

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值