兴趣点推荐代码_推荐系统模型阿⾥⽤户兴趣模型(附完整代
码)
项⽬地址:StephenBo-China/recommendation_system_sort_model
阿⾥天池数据集地址:数据集-阿⾥云天池
最近由于⼯作需要⽤tensorflow2.0复现了下阿⾥的兴趣模型,本⽂将先对论⽂进⾏描述,再介绍如何使⽤tensorflow2.0进⾏复现。建议阅读本⽂前先读⼀遍论⽂,本⽂的论⽂解析部分可作为辅助。
⼀、论⽂解析:
Ba Model:
ba model⽐较简单,就是将⽤户历史⾏为序列的各个商品的类别特征embedding之后,与⾮类别特征concat后进⼊pooling层(sum pooling与average pooling均可,具体可根据实际情况进⾏调整);pooling后与embedding后的⽤户画像特征及⽬标商品特征⼀起concat 后进⼊最后的MLP得到最终的分类结果。
1. Embedding Layer:
input: high dimensional binary vectors
ouput: low dimensional dence reprentations
pursuit对于第i个category特征来说,该特征有K个不同类别的值,我们希望将它embedding到D维,则:
为第i个特征的词典, 为第j个类别的embedding后的向量。具体的embedding的其他⽅法可阅读embedding相关的paper。
2. Pooling Layer:
由于MLP的输⼊层必须是固定长度的节点数,但是不同⽤户的历史⾏为序列长度不同,因⽽我们没有办法直接对⾏为序列特征进⾏concat,为了使得embedding后的⾏为序列长度相同,我们可以采⽤pooling操作让⾏为序列产出的特征长度相同,pooling可使⽤sum pooling或average pooling。sum对emebdding后的⾏为序列的各个item求和,average对embedding后的⾏为序列的各个item求均值得到。
3. MLP:
输⼊为concat(⽤户画像特征,pooling(embedding(历史⾏为序列)),⽬标商品特征)的全连接神经⽹络,最终使⽤softmax得到最终分类结果。loss采⽤log loss。
Ba Mode存在的问题:
1. pooling直接处理⽤户历史⾏为序列会有信息丢失:
Ba模型中直接对多个Embedding向量进⾏等权的sum-pooling,这种⽅法肯定会带来信息的丢失,⽽且相对重要的Embedding向量也⽆法完全突出⾃⼰所包含的信息。ba model中使⽤average pooling或者sum pooling对emebdding后的历史⾏为序列进⾏处理,对不同⽤户的⾏为序列得到同长度的MLP输⼊。但是这样做对于⾏为序列内的所有内容都是⼀视同仁的,不利于⽤户兴趣的表达。⽐较简单的⽅法是将embedding后的向量直接展开,但是这样会增加embedding层的学习权重,容易导致过拟合(个⼈理解,这样做不但会增加训练权重,且依然不能表达⽤户的兴趣信息,但是论⽂中是这样说的)。
2. 如何让Ba Model的pooling层产出能够表达出⽤户兴趣信息?
⽤Attention给pooling添加权重后求和,让模型更加关注有⽤的信息。因为在⽤户的历史⾏为序列中,展现item的数量要多于点击item,如果直接对⾏为序列等权sum pooling,展现序列贡献的信息要更多,但是点击item更加能体现⽤户的实际兴趣,因⽽加权后进⾏pooling 可以提取出更多的兴趣信息。
待用咖啡DIN:
1. DIN创新点:
(1) weighted-sum pooling:
a. weighted-sum pooling⽅法:
在历史⾏为序列进⼊pooling前,加⼊attention层,计算出⾏为序列中不同item的权重a_i后,再使⽤如下公式得到sum pooling的结果:
babu
其中, 为embedding后的⽤户⾏为序列;
是emebdding后⽬标商品的特征向量;
为attention层产出结果。
本⽂attention不使⽤传统的attention⽅法,需单独维护⼀个全连接神经⽹络得到最终attention结果,attention神经⽹络的输⼊为:⾏为序列中的每个item组合上⽬标商品的特征concat后作为输⼊,输出为各个item的权重。即⽤全连接层得到⾏为序列各个item的attention权重后,直接使⽤attention的权重向量与emebdding后⾏为序列做矩阵乘法即可得到
。
attention的神经⽹络结构如下图所⽰:
b. weighted-sum pooling为什么不⽤传统attenion⽅法:
传统⽅法使⽤softmax获得attention产出的权重被遗弃,因为传统⽅法使得attention的权重求和为1,这样求得的权重并不是⽤户兴趣的分布估计,采⽤神经⽹络最终使⽤sigmoid或其他激活函数得到序列attention权重分布,从⽽获得对⽤户兴趣的权重估计更适⽤于⽤户兴趣的表⽰。⽐如⼀个⽤户历史⾏为序列中90%都是⾐服,10%是电⼦产品。如果⽬标商品是t恤和⼿机的话,传统attention⽅法会使得t恤的
⾼于⼿机,因为⽤户的⾏为序列中⼤部分都是⾐服,但是⽤户购买⼿机与否与他购买⾐服与否是没有直接关联的,因⽽不能⽤传统的⽅法直接求softmax,softmax使得⾏为序列中的各个item都有了关联从⽽得出了商品权重。实际使⽤时可尝试最后激活函数使⽤softmax与sigmoid分别看效果后进⾏选择。
2. Dice激活函数:
可也看到,每⼀个yi对应了⼀个概率值pi。pi的计算主要分为两步:将yi进⾏标准化和进⾏sigmoid变换。
Dice激活函数与batch normalisation⼀样都是⽤来解决Internal Covariate Shift问题。
3. Mini-batch Aware Regularization:
商品id等需要embedding的特征,有些特征⾮常稀疏,导致embedding的训练参数过多,很容易造成过拟合。⽤户对于商品的数据符合长尾定律,也就是说有些id只出现了⼏次,⽽以下部分id会出现很多次,这样训练过程中就加⼊了更多噪声,使得模型更容易过拟合。因⽽需要正则化的⽅法来防⽌过拟合,但是由于DIN的⼤部分训练权重都是由embedding贡献的,直接加⼊L1正则或者L2正则的话会提⾼模型训练的复杂度(对于⼀个mini-batch来说,在没有L2正则时,梯度下降只需要更新embedding中的⾮0参数,但是加⼊L2正则由于要计算L2-norm,则需要对所有的参数进⾏计算)。因⽽论⽂提出了mini-batch regularization的⽅法,让模型⾃适应各个embedding feature的正则化强度。
最终推导出的权重更新公式如下:
由于Mini-batch Aware Regularization是⽣效在embedding层的权重更新中,且只有在需要embeddingyishu
的特征⾮常稀疏时,才需要该正则化⽅法,因⽽本⽂直接使⽤tensorflow⾃带的embedding层,只要输⼊特征不是⾮常稀疏,不⽤该⽅法不会影响到模型最终效果。
⼆、实现:禽流感最新消息
模型⾃定义层:
1.weighted-sum pooling:
Attention层输⼊为⾏为序列与target item组合后的特征,由于⼀个batch下的⾏为序列长度不同,因⽽给长度不⾜最⼤长度的补
1padding后,输⼊到全连接神经⽹络,最后通过sigmoid激活函数得到a(i)的值,在⽤得到的权重向量与embedding后的⾏为序列矩阵做矩阵乘法即得到了权重乘以各个item后求和pooling的结果。
class attention(tf.keras.layers.Layer):
def __init__(lf, keys_dim):
super(attention, lf).__init__()
attract
lf.keys_dim = keys_dim
lf.fc = tf.keras.Sequential()
bearingpointlf.fc.add(layers.BatchNormalization())浙江经济师考试
lf.fc.add(layers.Den(100, activation="sigmoid"))
lf.fc.add(layers.ReLU())
lf.fc.add(layers.Den(50, activation="sigmoid"))
lf.fc.add(layers.ReLU())
教父英文小说lf.fc.add(layers.Den(1, activation=None))
def call(lf, queries, keys, keys_length):
#Attention
queries = tf.pand_dims(queries, 1), [1, tf.shape(keys)[1], 1])
din_all = tf.concat([queries, keys, queries-keys, queries*keys], axis=-1)
outputs = tf.transpo(lf.fc(din_all), [0,2,1])
key_masks = tf.quence_mask(keys_length, max(keys_length), dtype=tf.bool)
key_masks = tf.expand_dims(key_masks, 1)
paddings = tf.ones_like(outputs) * (-2 ** 32 + 1)
outputs = tf.where(key_masks, outputs, paddings)
outputs = outputs / (lf.keys_dim ** 0.5)
#outputs = tf.keras.activations.softmax(outputs, -1)
outputs = tf.keras.activations.sigmoid(outputs)
#Sum Pooling
outputs = tf.squeeze(tf.matmul(outputs, keys))
print("outputs:" + str(outputs.numpy().shape))
return outputs
2.Dice激活函数:
class dice(tf.keras.layers.Layer):
def __init__(lf, feat_dim):
super(dice, lf).__init__()
lf.feat_dim = feat_dim
lf.alphas= tf.s([feat_dim]), dtype=tf.float32)
lf.beta = tf.s([feat_dim]), dtype=tf.float32)
lf.bn = tf.keras.layers.BatchNormalization(center=Fal, scale=Fal)
def call(lf, _x, axis=-1, epsilon=0.000000001):
reduction_axes = list(range(len(_x.get_shape())))
del reduction_axes[axis]
broadcast_shape = [1] * len(_x.get_shape())
broadcast_shape[axis] = lf.feat_dim
mean = tf.reduce_mean(_x, axis=reduction_axes)
brodcast_mean = tf.reshape(mean, broadcast_shape)
std = tf.reduce_mean(tf.square(_x - brodcast_mean) + epsilon, axis=reduction_axes)商务关系
std = tf.sqrt(std)
brodcast_std = tf.reshape(std, broadcast_shape)
x_normed = lf.bn(_x)
x_p = tf.keras.activations.sigmoid(lf.beta * x_normed)
return lf.alphas * (1.0 - x_p) * _x + x_p * _x
整体实现:
除了weighted-sum pooling为din的⾃定义层,其余均为tensorflow包含层,直接通过论⽂中模型结构构造整个模型即可: