使用din_fcn_attention模块实现的一个demo

时间:2021-02-23 01:05:58

DIN-FCN-Attention模型是一种基于深度学习的推荐模型,主要用于解决推荐系统中的商品推荐问题。DIN-FCN-Attention模型首先将用户历史行为序列中的每个商品通过嵌入层映射成一个固定大小的向量表示;然后,将用户特征向量和商品特征向量拼接在一起,输入到一个多层感知机(MLP)中,学习用户和商品之间的交互特征;接着,将交互特征输入到一个全连接神经网络(FCN)中,通过多个隐藏层对特征进行非线性变换;最后,使用Attention机制,将用户特征向量和商品特征向量的乘积与用户历史行为序列中每个商品的嵌入向量进行加权求和,得到一个加权和向量,表示用户和商品之间的关系。

import tensorflow as tf
import numpy as np
np.random.seed(2)
def din_fcn_attention(query,facts,attention_size,mask,stag='null',mode='SUM',softmax_stag=1,time_major=False,return_alphas=False,forCnn=False):
    if isinstance(facts,tuple):
        #In case of Bi-RNN,concatenate the forward and the backward RNN outputs
        facts = tf.concat(facts,2)
        print('query_size mismatch!')
        query=tf.concat(values=[query,query],axis=1)


    if time_major:
        #(T,B,D) => (B,T,D)
        facts=tf.transpose(facts,[1,0,2])
    mask=tf.equal(mask,tf.ones_like(mask))
    facts_size=facts.get_shape().as_list()[-1]
    query_size=query.get_shape().as_list()[-1]
    query=tf.layers.dense(query,facts_size,activation=None,name='f1'+stag)
    query=prelu(query)

    queries=tf.tile(query,[1,tf.shape(facts)[1]])
    queries=tf.reshape(queries,tf.shape(facts))
    din_all=tf.concat([queries,facts,queries-facts,queries*facts],axis=-1)
    d_layer_1_all=tf.layers.dense(din_all,attention_size,activation=tf.nn.sigmoid,name='f1_att'+stag)
    d_layer_2_all=tf.layers.dense(d_layer_1_all,40,activation=tf.nn.sigmoid,name='f2_att'+stag)
    d_layer_3_all=tf.layers.dense(d_layer_2_all,1,activation=None,name='f3_att'+stag)
    d_layer_3_all=tf.reshape(d_layer_3_all,[-1,1,tf.shape(facts)[1]])#[B,1,T]
    scores=d_layer_3_all
    #Mask
    #key_masks=tf.sequence_mask(facts_length,tf.shape(facts)[1])  #[B,T]
    key_masks=tf.expand_dims(mask,1)#[B,1,T]
    paddings = tf.ones_like(scores)*(-2**32+1)
    if not forCnn:
        scores=tf.where(key_masks,scores,paddings)#[B,1,T]

    #Scale
    #scores=scores/(facts.get_shape().as_list()[-1]**0.5)

    #Activation
    if softmax_stag:
        scores=tf.nn.softmax(scores)

    #Weighted sum
    if mode=='SUM':
        output=tf.matmul(scores,facts)
        #output=tf.reshpe(output,[-1,tf.shape(facts[1]])
    else:
        scores=tf.reshape(scores,[-1,tf.shape(facts)[1]])
        output=facts*tf.expand_dims(scores,-1)
        output=tf.reshape(output,tf.shape(facts))
    if return_alphas:
        return output, scores
    return output

def prelu(_x,scope=''):
    """parameteric ReLU activation"""
    with tf.variable_scope(name_or_scope=scope,default_name="prelu",):#ha  learnable parameters
        _alpha=tf.get_variable("prelu_"+scope,shape=_x.get_shape()[-1],
                               dtype=_x.dtype,initializer=tf.constant_initializer(0.1))
        return tf.maximum(0.0,_x)+_alpha*tf.minimum(0.0,_x)

user_features=np.random.rand(4,32)
item_features=np.random.randn(4,32)

#construct the graph of computation
input_user=tf.placeholder(tf.float32,shape=[None,32],name='input_user')
input_items=tf.placeholder(tf.float32,shape=[None,None,32],name='input_items')
mask_items=tf.placeholder(tf.int32,shape=[None,None],name='mask_items')
output=din_fcn_attention(query=input_user,facts=input_items,attention_size=80,mask=mask_items,mode='SUM',softmax_stag=1)
#initializer the session and run the computation graph
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    #compute the interests
    scores=sess.run(output,feed_dict={input_user:user_features,
                                      input_items:item_features[:,np.newaxis,:],
                                      mask_items:np.ones([4,1],dtype=np.int32)
                                      })
    best_item=np.argmax(scores)
    print('Best item index:',best_item)
    print("np.argmax:",np.argmax(np.reshape(item_features,(-1,))))
    print("np.max:",np.max(np.reshape(item_features,(-1,))))
    print('Best item features:',np.reshape(item_features,(-1,))[best_item])
  

输出:

Best item index: 73
np.argmax: 73
np.max: 1.985485260327859
Best item features: 1.985485260327859

其中,该函数的输入参数包括:

  • query的形状为(batch_size, embedding_size),其中batch_size是一个批次中样本的数量,embedding_size是嵌入向量的维度。query表示要计算注意力分数的向量,通常是用户的特征向量。

  • facts的形状为(batch_size, sequence_length, embedding_size),其中sequence_length是序列的长度,表示一个用户的历史行为序列长度。facts表示所有历史行为的嵌入向量,通常是一个三维张量。

  • mask的形状为(batch_size, sequence_length),其中mask是一个二元张量,用于指示哪些历史行为是有效的。如果mask中某个位置上的值为1,则表示对应的历史行为有效;如果为0,则表示对应的历史行为无效。mask的形状与facts的形状相同,但是只有两个维度,没有嵌入向量的维度。

  • 需要注意的是,query和facts的形状可以根据具体的应用场景进行调整,但是在din_fcn_attention()函数中,上述形状是默认的形状。在实际应用中,需要根据具体情况进行调整。

  • attention_size:attention 模型的隐藏层大小。

  • stag:变量作用域名称。

  • mode:attention 模型的计算方式,可以为 ‘SUM’ 或者 ‘PRODUCT’。

  • softmax_stag:softmax 分类器的标记,用于控制是否启用 softmax 分类器。

  • time_major:一个布尔值,表示是否按时间步主要处理张量。

  • return_alphas:一个布尔值,表示是否返回注意力权重。

  • forCnn:一个布尔值,表示是否为卷积神经网络的输入。