【推荐系统】DIN源码分析-att(2)

为什么模型中的user_emb矩阵没有使用?

DIN model中为何没有拼接user vector # 64

其他的模型里u_emb也是被hist替换掉了。我对小数据集没有特别强的感觉和经验,生产的时候也很难用上user id的,user id单独还好维度不是很大,但是一旦样本里user id和 目标item id都存在的时候,整个样本的特征表达和区分能力就非常强,比较容易过拟合。不过是听说过有的场景用user id成功的经历,我们的数据体量也非常大了,结论就是要么过拟合要么无效,没有做过多的研究。

DIN的输入只包括商品、类目以及历史行为商品吗?

开源给出的code只是在公开数据集实现的demo,这些数据集没有很丰富的特征。
生产的DIN模型我们是以item为最小的粒度,把item的所有相关的feature 如你说的 品牌 brand、类目 category,还有产品词 product word,店铺 shop,以及一些别的item为key能关联到的feature。把它们的embedding 和item的embedding concat 起来当做是最终item的embedding,这个concat操作也可以变成sum pooling操作,不过效果都是差不多的,concat在我们的场景会好一些。对于用户行为序列的item和预估候选的item都做同样的处理,最终输入模型。

din中的正则化参数

由于Amazon数据集和Movielens数据集的功能维度都不高(约10万),因此所有深度模型(包括我们提出的DIN)都不会遇到严重的过拟合问题。 但是,当涉及包含较高维度稀疏特征的在线广告系统中的Alibaba数据集时,过度拟合将是一个很大的挑战。 例如,当训练具有细粒度特征的深层模型(例如,表1中尺寸为6亿个goods_ids的特征)时,不加正则化会在第一个epochs之后会发生严重的过度拟合,这会导致模型性能迅速下降。 因此,检验几种常用正则化的性能:

  • Dropout:在每一个样本中随机丢弃50%的特征id;
  • Filter:按样本中的出现频率过滤访问的goods_id,仅保留最频繁的那些。剩下的前2000万个goods_id;
  • Regularization in DiFacto:与频繁特征相关的参数不太会被过度正则化;
  • MBA:Mini-Batch Aware regularization method;

Dropout可快速防止过拟合,但会降低收敛速度。 DiFacto中的正则化会以较高的频率对goods_id设置更大的惩罚,其效果要比Filter差。 MBA效果最好。

DIN核心——local activation

att 一般都要进行缩放的,why?

对一个query进行attention

"""
输入有三个
候选广告queries,用户历史行为keys,以及Batch中每个行为的长度。
这里为什么要输入一个keys_length呢,因为每个用户发生过的历史行为是不一样多的,但是输入的keys维度是固定的(都是历史行为最大的长度),
因此我们需要这个长度来计算一个mask,告诉模型哪些行为是没用的,哪些是用来计算用户兴趣分布的。

经过以下几个步骤得到用户的兴趣分布:

将queries变为和keys同样的形状B * T * H
(B指batch的大小,T指用户历史行为的最大长度,H指embedding的维度)

通过三层神经网络得到queries和keys中每个key的权重,并经过softmax进行标准化(不是说不用归一化更能表达用户对query的兴趣分布吗?)

通过weighted sum得到最终用户的历史行为分布
"""

def attention(queries, keys, keys_length):
    '''
    queries:     [B, H] (即i_emb)
    keys:        [B, T, H] (即h_emb)
    keys_length: [B] 即self.sl

    B: batch size;
    T: 用户序列的长度;
    H: embedding size;
    '''
    # shape: [H]
    queries_hidden_units = queries.get_shape().as_list()[-1]
    # [B,H] -> T*[B,H]
    queries = tf.tile(queries, [1, tf.shape(keys)[1]])
    # T*[B,H] ->[B, T, H]
    queries = tf.reshape(queries, [-1, tf.shape(keys)[1], queries_hidden_units])
    # 有差值,有外积 # B*T*4H
    # attention操作,输出维度为[B, T, 4*H]
    din_all = tf.concat([queries, keys, queries - keys, queries * keys], axis=-1)
    # 三层全链接
    # [B, T, 80]
    d_layer_1_all = tf.layers.dense(din_all, 80, activation=tf.nn.sigmoid, name='f1_att', reuse=tf.compat.v1.AUTO_REUSE)
    # [B, T, 40]
    d_layer_2_all = tf.layers.dense(d_layer_1_all, 40, activation=tf.nn.sigmoid, name='f2_att',
                                    reuse=tf.compat.v1.AUTO_REUSE)
    # [B, T, 1]
    d_layer_3_all = tf.layers.dense(d_layer_2_all, 1, activation=None, name='f3_att',
                                    reuse=tf.compat.v1.AUTO_REUSE)  # B*T*1
    # [B, 1, T]
    d_layer_3_all = tf.reshape(d_layer_3_all, [-1, 1, tf.shape(keys)[1]])
    # attention的输出, [B, 1, T]
    outputs = d_layer_3_all  # B*1*T

    # Mask
    # [B, T]
    key_masks = tf.sequence_mask(keys_length, tf.shape(keys)[1])  # [B, T]
    # [B, 1, T]
    key_masks = tf.expand_dims(key_masks, 1)  # [B, 1, T]
    # padding的mask后补一个很小的负数,这样softmax之后就会接近0.
    paddings = tf.ones_like(outputs) * (-2 ** 32 + 1)  # 在补足的地方附上一个很小的值,而不是0
    # [B, 1, T] padding操作,将每个样本序列中空缺的商品都赋值为(-2 ** 32 + 1)
    outputs = tf.where(key_masks, outputs, paddings)  # [B, 1, T]

    # Scale, 这里scale不是很明白
    # att 一般都要进行缩放的,why?
    outputs = outputs / (keys.get_shape().as_list()[-1] ** 0.5)

    # Activation
    # [B, 1, T] #这里的output是attention计算出来的权重,即论文公式(3)里的w,
    outputs = tf.nn.softmax(outputs)  # [B, 1, T]

    # Weighted sum
    # B * 1 * H 三维矩阵相乘,相乘发生在后两维,即 B * (( 1 * T ) * ( T * H ))
    # outputs为最终用户的历史行为分布
    # [B, 1, H]
    outputs = tf.matmul(outputs, keys)

    return outputs

对一批query进行attention

def attention_multi_items(queries, keys, keys_length):
    '''
    queries:     [B, N, H] N is the number of ads
    keys:        [B, T, H]
    keys_length: [B]
    '''
    queries_hidden_units = queries.get_shape().as_list()[-1]
    queries_nums = queries.get_shape().as_list()[1]
    queries = tf.tile(queries, [1, 1, tf.shape(keys)[1]])
    queries = tf.reshape(queries, [-1, queries_nums, tf.shape(keys)[1], queries_hidden_units])  # shape : [B, N, T, H]
    max_len = tf.shape(keys)[1]
    keys = tf.tile(keys, [1, queries_nums, 1])
    keys = tf.reshape(keys, [-1, queries_nums, max_len, queries_hidden_units])  # shape : [B, N, T, H]
    din_all = tf.concat([queries, keys, queries - keys, queries * keys], axis=-1)
    d_layer_1_all = tf.layers.dense(din_all, 80, activation=tf.nn.sigmoid, name='f1_att', reuse=tf.compat.v1.AUTO_REUSE)
    d_layer_2_all = tf.layers.dense(d_layer_1_all, 40, activation=tf.nn.sigmoid, name='f2_att',
                                    reuse=tf.compat.v1.AUTO_REUSE)
    d_layer_3_all = tf.layers.dense(d_layer_2_all, 1, activation=None, name='f3_att', reuse=tf.compat.v1.AUTO_REUSE)
    d_layer_3_all = tf.reshape(d_layer_3_all, [-1, queries_nums, 1, max_len])
    outputs = d_layer_3_all
    # Mask
    key_masks = tf.sequence_mask(keys_length, max_len)  # [B, T]
    key_masks = tf.tile(key_masks, [1, queries_nums])
    key_masks = tf.reshape(key_masks, [-1, queries_nums, 1, max_len])  # shape : [B, N, 1, T]
    paddings = tf.ones_like(outputs) * (-2 ** 32 + 1)
    outputs = tf.where(key_masks, outputs, paddings)  # [B, N, 1, T]

    # Scale
    outputs = outputs / (keys.get_shape().as_list()[-1] ** 0.5)

    # Activation
    outputs = tf.nn.softmax(outputs)  # [B, N, 1, T]
    outputs = tf.reshape(outputs, [-1, 1, max_len])
    keys = tf.reshape(keys, [-1, max_len, queries_hidden_units])
    # print outputs.get_shape().as_list()
    # print keys.get_sahpe().as_list()
    # Weighted sum
    outputs = tf.matmul(outputs, keys)
    outputs = tf.reshape(outputs, [-1, queries_nums, queries_hidden_units])  # [B, N, 1, H]
    print(outputs.get_shape().as_list())
    return outputs

model tf1.15恢复

inference.py

./save_path/
    -| checkpoint
    -| ckpt.data-00000-of-00001
    -| ckpt.index
    -| ckpt.meta
    model = Model(user_count, item_count, cate_count, cate_list, predict_batch_size, predict_ads_num) # model定义要有
    model.restore(sess, 'save_path/ckpt') # 恢复model参数
    """
    saver = tf.train.import_meta_graph('save_path/ckpt.meta')
    model = saver.restore(sess, tf.train.latest_checkpoint("save_path/"))
    """

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值