DCN2


import tensorflow as tf
from .base import TFBaseModel
from .utils import tf_weighted_sigmoid_ce_with_logits

'''
structure
Embedding=>Cross|Deep=>stack result=>Fully connect
'''

class DeepCrossNetwork(TFBaseModel):
    def __init__(self, feature_dim_dict, embedding_size=4,
                 cross_layer_num=1, hidden_size=[], use_batchnorm=True, deep_l2_reg=0.00002,
                 init_std=0.001, seed=1024, keep_prob=0.5,
                 checkpoint_path=None):
        super(DeepCrossNetwork, 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',]}")
        if len(feature_dim_dict["dense"]) > 0:
            raise ValueError("Now tf DCN doesn't support dense input")
        self.field_dim = len(feature_dim_dict["sparse"])
        self.feature_dim = feature_dim_dict
        self.embedding_size = embedding_size

        self.deep_l2_reg = deep_l2_reg
        self.init_std = init_std

        self.seed = seed
        self.keep_prob = keep_prob
        self.cross_layer_num = cross_layer_num
        self.hidden_size = hidden_size
        self.use_batchnorm = use_batchnorm
        # self.params = locals()
        self._build_graph()

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

    def _get_input_data(self, ):
        return self.X

    def _get_input_target(self, ):
        return self.Y

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

    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 _create_placeholders(self, ):

        self.X = tf.placeholder(
            tf.int32, shape=[None, self.field_dim], name='input_X')
        self.Y = tf.placeholder(tf.float32, shape=[None, ], name='input_Y')

        self.train_flag = tf.placeholder(tf.bool, name='train_flag')

    def _create_variable(self, ):

        self.b = tf.Variable(tf.constant(0.0), name='bias')
        # TODO:  self.init_std/ math.sqrt(float(dim))
        self.embedding_list = []
        self.total_size = self.field_dim * self.embedding_size

        self.sparse_embeddings = [tf.get_variable(name='embed_cate' + str(i) + '-' + feat,
                                                  initializer=tf.random_normal(
                                                      [self.feature_dim["sparse"][feat],
                                                       min(self.embedding_size,
                                                           6 * pow(self.feature_dim["sparse"][feat], 0.25))],
                                                      stddev=self.init_std)) for i, feat in
                                  enumerate(self.feature_dim["sparse"])]

        self.cross_layer_weight = [
            tf.Variable(tf.random_normal([self.total_size, 1], stddev=self.init_std, seed=self.seed)) for i in
            range(self.cross_layer_num)]
        self.cross_layer_bias = [
            tf.Variable(tf.random_normal([self.total_size, 1], stddev=self.init_std, seed=self.seed)) for i in
            range(self.cross_layer_num)]

    def f_cross_l(self, x_l, w_l, b_l):
        dot = tf.matmul(self._x_0, x_l, transpose_b=True)
        return tf.tensordot(dot, w_l, 1) + b_l

    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("cross_network"):
            # embeds = []
            # for i in range(len(self.feature_list)):
            #    temp = tf.nn.embedding_lookup(self.embedding_list[i], self.X[:, i], )
            #    embeds.append(temp)
            # embeds = tf.concat(embeds, axis=1)
            # embeds = tf.nn.embedding_lookup(
            #    self.embeddings, self.X, partition_strategy='div')
            embed_list = [tf.nn.embedding_lookup(self.sparse_embeddings[i], self.X[:, i]) for i in
                          range(self.field_dim)]

            embeds = tf.concat(embed_list, axis=-1)
            self._x_0 = tf.reshape(embeds, (-1, self.total_size, 1))
            x_l = self._x_0
            for l in range(self.cross_layer_num):
                x_l = self.f_cross_l(
                    x_l, self.cross_layer_weight[l], self.cross_layer_bias[l]) + x_l

            cross_network_out = tf.reshape(x_l, (-1, self.total_size))

        with tf.name_scope('deep_network'):
            if len(self.hidden_size) > 0:
                fc_input = tf.reshape(
                    embeds, (-1, self.field_dim * self.embedding_size))

                for l in range(len(self.hidden_size)):
                    if self.use_batchnorm:
                        weight = tf.get_variable(name='deep_weight' + str(l),
                                                 shape=[fc_input.get_shape().as_list()[1], self.hidden_size[l]],
                                                 initializer=tf.random_normal_initializer(stddev=self.init_std,
                                                                                          seed=self.seed))
                        # bias = tf.Variable(0.0,name='bias'+str(l))
                        H = tf.matmul(fc_input, weight)  # ,bias
                        H_hat = tf.layers.batch_normalization(H, training=self.train_flag)
                        fc = tf.nn.relu(H_hat)
                    else:
                        fc = tf.contrib.layers.fully_connected(fc_input, self.hidden_size[l],
                                                               activation_fn=tf.nn.relu,
                                                               weights_initializer=tf.truncated_normal_initializer(
                                                                   stddev=self.init_std),
                                                               weights_regularizer=tf.contrib.layers.l2_regularizer(
                                                                   self.deep_l2_reg))
                    if l < len(self.hidden_size) - 1:
                        fc = tf.cond(self.train_flag, lambda: inverted_dropout(
                            fc, self.keep_prob), lambda: fc)
                    fc_input = fc
                deep_network_out = fc_input

        with tf.name_scope("combination_output_layer"):
            x_stack = cross_network_out
            if len(self.hidden_size) > 0:
                x_stack = tf.concat([x_stack, deep_network_out], axis=1)

            self.logit = tf.contrib.layers.fully_connected(x_stack, 1, activation_fn=None,
                                                           weights_initializer=tf.truncated_normal_initializer(
                                                               stddev=self.init_std),
                                                           weights_regularizer=None)
            self.logit = tf.reshape(self.logit, (-1,))

    def _create_loss(self, ):

        self.log_loss = tf.reduce_sum(tf_weighted_sigmoid_ce_with_logits(
            labels=self.Y, logits=self.logit, sample_weight=self.sample_weight))  # total_loss
        self.mse_loss = tf.squared_difference(
            self.Y, self.logit)
        # TODO: tf.summary.FileWriter
        # tf.summary.scalar('loss',self.log_loss)
        # self.merged = tf.summary.merge_all()
        # self.train_writer = tf.summary.FileWriter('../check/DCN/train',self.graph)
        # test_writer = tf.summary.FileWriter('../check/DCN/test')
        # https://www.tensorflow.org/get_started/summaries_and_tensorboard


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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值