主頁 >  其他 > Deep Interest Network (DIN)專題4-網路結構部分代碼決議

Deep Interest Network (DIN)專題4-網路結構部分代碼決議

2022-02-09 07:47:16 其他

整體代碼

上節重點分析了資料加載相關代碼,本節將重點分析下模型訓練相關的代碼,整個模型相關部分的代碼如下:

import tensorflow as tf

from Dice import dice

class Model(object):

  def __init__(self, user_count, item_count, cate_count, cate_list, predict_batch_size, predict_ads_num):

    self.u = tf.placeholder(tf.int32, [None,]) # [B] 用戶id
    self.i = tf.placeholder(tf.int32, [None,]) # [B] 推薦商品id
    self.j = tf.placeholder(tf.int32, [None,]) # [B] 
    self.y = tf.placeholder(tf.float32, [None,]) # [B] 是否點擊
    self.hist_i = tf.placeholder(tf.int32, [None, None]) # [B, T] 之前點擊商品id串列
    self.sl = tf.placeholder(tf.int32, [None,]) # [B] 之前點擊商品個數
    self.lr = tf.placeholder(tf.float32, []) # 學習率

    hidden_units = 128

    user_emb_w = tf.get_variable("user_emb_w", [user_count, hidden_units]) # 用戶embedding
    item_emb_w = tf.get_variable("item_emb_w", [item_count, hidden_units // 2]) # 商品embedding
    item_b = tf.get_variable("item_b", [item_count],
                             initializer=tf.constant_initializer(0.0))
    cate_emb_w = tf.get_variable("cate_emb_w", [cate_count, hidden_units // 2])
    cate_list = tf.convert_to_tensor(cate_list, dtype=tf.int64) # 所有商品的分類List

    ic = tf.gather(cate_list, self.i)
    i_emb = tf.concat(values = [
        tf.nn.embedding_lookup(item_emb_w, self.i),
        tf.nn.embedding_lookup(cate_emb_w, ic),
        ], axis=1)
        # 推薦商品i的embedding + 分類embedding B*T,BATCH_SIZE個一維向量,
        # 兩個embedding的向量維度均為hidden_units // 2,故拼接后的embedding向量的維度為hidden_units
    i_b = tf.gather(item_b, self.i)

    jc = tf.gather(cate_list, self.j)
    j_emb = tf.concat([
        tf.nn.embedding_lookup(item_emb_w, self.j),
        tf.nn.embedding_lookup(cate_emb_w, jc),
        ], axis=1)
    j_b = tf.gather(item_b, self.j)

    hc = tf.gather(cate_list, self.hist_i)
    h_emb = tf.concat([
        tf.nn.embedding_lookup(item_emb_w, self.hist_i),
        tf.nn.embedding_lookup(cate_emb_w, hc),
        ], axis=2) # 之前點過商品的embedding + 分類embedding B*N*T,BATCH_SIZE個樣本 * N個訪問記錄 * 一維向量

    hist_i =attention(i_emb, h_emb, self.sl)
    # 放回 [B,1,H],一個Batch每一個樣本都有一個 sum pooling出的embedding向量,
    # embedding向量維度為hidden_units,
    #-- attention end ---
    
    hist_i = tf.layers.batch_normalization(inputs = hist_i)
    hist_i = tf.reshape(hist_i, [-1, hidden_units], name='hist_bn')
    # [B, hidden_units],每一個embedding向量的維度是hidden_units,
    hist_i = tf.layers.dense(hist_i, hidden_units, name='hist_fcn')
    u_emb_i = hist_i
    
    hist_j =attention(j_emb, h_emb, self.sl)
    # 
    #-- attention end ---
    
    # hist_j = tf.layers.batch_normalization(inputs = hist_j)
    hist_j = tf.layers.batch_normalization(inputs = hist_j, reuse=True)
    hist_j = tf.reshape(hist_j, [-1, hidden_units], name='hist_bn')
    hist_j = tf.layers.dense(hist_j, hidden_units, name='hist_fcn', reuse=True)

    u_emb_j = hist_j
    print(u_emb_i.get_shape().as_list())
    print(u_emb_j.get_shape().as_list())
    print(i_emb.get_shape().as_list())
    print(j_emb.get_shape().as_list())
    #-- fcn begin -------
    din_i = tf.concat([u_emb_i, i_emb, u_emb_i * i_emb], axis=-1)
    din_i = tf.layers.batch_normalization(inputs=din_i, name='b1')
    d_layer_1_i = tf.layers.dense(din_i, 80, activation=tf.nn.sigmoid, name='f1')
    #if u want try dice change sigmoid to None and add dice layer like following two lines. You can also find model_dice.py in this folder.
    # d_layer_1_i = tf.layers.dense(din_i, 80, activation=None, name='f1')
    # d_layer_1_i = dice(d_layer_1_i, name='dice_1_i')
    d_layer_2_i = tf.layers.dense(d_layer_1_i, 40, activation=tf.nn.sigmoid, name='f2')
    # d_layer_2_i = tf.layers.dense(d_layer_1_i, 40, activation=None, name='f2')
    # d_layer_2_i = dice(d_layer_2_i, name='dice_2_i')
    d_layer_3_i = tf.layers.dense(d_layer_2_i, 1, activation=None, name='f3')
    din_j = tf.concat([u_emb_j, j_emb, u_emb_j * j_emb], axis=-1)
    din_j = tf.layers.batch_normalization(inputs=din_j, name='b1', reuse=True)
    d_layer_1_j = tf.layers.dense(din_j, 80, activation=tf.nn.sigmoid, name='f1', reuse=True)
    # d_layer_1_j = tf.layers.dense(din_j, 80, activation=None, name='f1', reuse=True)
    # d_layer_1_j = dice(d_layer_1_j, name='dice_1_j')
    d_layer_2_j = tf.layers.dense(d_layer_1_j, 40, activation=tf.nn.sigmoid, name='f2', reuse=True)
    # d_layer_2_j = tf.layers.dense(d_layer_1_j, 40, activation=None, name='f2', reuse=True)
    # d_layer_2_j = dice(d_layer_2_j, name='dice_2_j')
    d_layer_3_j = tf.layers.dense(d_layer_2_j, 1, activation=None, name='f3', reuse=True)
    d_layer_3_i = tf.reshape(d_layer_3_i, [-1])
    d_layer_3_j = tf.reshape(d_layer_3_j, [-1])
    x = i_b - j_b + d_layer_3_i - d_layer_3_j # [B]
    self.logits = i_b + d_layer_3_i
    
    # prediciton for selected items
    # logits for selected item:
    item_emb_all = tf.concat([
        item_emb_w,
        tf.nn.embedding_lookup(cate_emb_w, cate_list)
        ], axis=1)
    item_emb_sub = item_emb_all[:predict_ads_num,:]
    item_emb_sub = tf.expand_dims(item_emb_sub, 0)
    item_emb_sub = tf.tile(item_emb_sub, [predict_batch_size, 1, 1])
    hist_sub =attention_multi_items(item_emb_sub, h_emb, self.sl)
    #-- attention end ---
    
    hist_sub = tf.layers.batch_normalization(inputs = hist_sub, name='hist_bn', reuse=tf.AUTO_REUSE)
    # print hist_sub.get_shape().as_list() 
    hist_sub = tf.reshape(hist_sub, [-1, hidden_units])
    hist_sub = tf.layers.dense(hist_sub, hidden_units, name='hist_fcn', reuse=tf.AUTO_REUSE)

    u_emb_sub = hist_sub
    item_emb_sub = tf.reshape(item_emb_sub, [-1, hidden_units])
    din_sub = tf.concat([u_emb_sub, item_emb_sub, u_emb_sub * item_emb_sub], axis=-1)
    din_sub = tf.layers.batch_normalization(inputs=din_sub, name='b1', reuse=True)
    d_layer_1_sub = tf.layers.dense(din_sub, 80, activation=tf.nn.sigmoid, name='f1', reuse=True)
    #d_layer_1_sub = dice(d_layer_1_sub, name='dice_1_sub')
    d_layer_2_sub = tf.layers.dense(d_layer_1_sub, 40, activation=tf.nn.sigmoid, name='f2', reuse=True)
    #d_layer_2_sub = dice(d_layer_2_sub, name='dice_2_sub')
    d_layer_3_sub = tf.layers.dense(d_layer_2_sub, 1, activation=None, name='f3', reuse=True)
    d_layer_3_sub = tf.reshape(d_layer_3_sub, [-1, predict_ads_num])
    self.logits_sub = tf.sigmoid(item_b[:predict_ads_num] + d_layer_3_sub)
    self.logits_sub = tf.reshape(self.logits_sub, [-1, predict_ads_num, 1])
    #-- fcn end -------

    
    self.mf_auc = tf.reduce_mean(tf.to_float(x > 0))
    self.score_i = tf.sigmoid(i_b + d_layer_3_i)
    self.score_j = tf.sigmoid(j_b + d_layer_3_j)
    self.score_i = tf.reshape(self.score_i, [-1, 1])
    self.score_j = tf.reshape(self.score_j, [-1, 1])
    self.p_and_n = tf.concat([self.score_i, self.score_j], axis=-1)
    print(self.p_and_n.get_shape().as_list())


    # Step variable
    self.global_step = tf.Variable(0, trainable=False, name='global_step')
    self.global_epoch_step = \
        tf.Variable(0, trainable=False, name='global_epoch_step')
    self.global_epoch_step_op = \
        tf.assign(self.global_epoch_step, self.global_epoch_step+1)

    self.loss = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(
            logits=self.logits,
            labels=self.y)
        )

    trainable_params = tf.trainable_variables()
    self.opt = tf.train.GradientDescentOptimizer(learning_rate=self.lr)
    gradients = tf.gradients(self.loss, trainable_params)
    clip_gradients, _ = tf.clip_by_global_norm(gradients, 5)
    self.train_op = self.opt.apply_gradients(
        zip(clip_gradients, trainable_params), global_step=self.global_step)


  def train(self, sess, uij, l):
    loss, _ = sess.run([self.loss, self.train_op], feed_dict={
        self.u: uij[0],
        self.i: uij[1],
        self.y: uij[2],
        self.hist_i: uij[3],
        self.sl: uij[4],
        self.lr: l,
        })
    return loss

  def eval(self, sess, uij):
    u_auc, socre_p_and_n = sess.run([self.mf_auc, self.p_and_n], feed_dict={
        self.u: uij[0],
        self.i: uij[1],
        self.j: uij[2],
        self.hist_i: uij[3],
        self.sl: uij[4],
        })
    return u_auc, socre_p_and_n
  
  def test(self, sess, uij):
    return sess.run(self.logits_sub, feed_dict={
        self.u: uij[0],
        self.i: uij[1],
        self.j: uij[2],
        self.hist_i: uij[3],
        self.sl: uij[4],
        })
  

  def save(self, sess, path):
    saver = tf.train.Saver()
    saver.save(sess, save_path=path)

  def restore(self, sess, path):
    saver = tf.train.Saver()
    saver.restore(sess, save_path=path)

def extract_axis_1(data, ind):
  batch_range = tf.range(tf.shape(data)[0])
  indices = tf.stack([batch_range, ind], axis=1)
  res = tf.gather_nd(data, indices)
  return res

def attention(queries, keys, keys_length):
  '''
    queries:     [B, H] BATCH_SIZE個embedding向量(二維矩陣)
    keys:        [B, T, H] BATCH_SIZE個之前訪問T個商品的embedding向量(三維矩陣)
    keys_length: [B] batch_size里面,每個用戶之前點擊過商品的個數,注意這里和T的區別,T是取的所有里面的最大值,是定長,而這里是非定長的,表示的是實際點擊的商品數,
  '''
  queries_hidden_units = queries.get_shape().as_list()[-1] # 推薦商品的embedding向量維度
  queries = tf.tile(queries, [1, tf.shape(keys)[1]]) # queries的1緯不變,2維擴張為原來的T倍,即之前點擊過的商品數,
  # querise緯度變為 [B, T*H]
  queries = tf.reshape(queries, [-1, tf.shape(keys)[1], queries_hidden_units])
  # 修改querise緯度變為[B, T, H],對于一個推薦商品,其會生成T個重復的相同一個推薦商品的embedding向量,
  din_all = tf.concat([queries, keys, queries-keys, queries*keys], axis=-1)
  # 最后一個維度拼接到一起,拼接后變為 [B, T, 4*H]
  d_layer_1_all = tf.layers.dense(din_all, 80, activation=tf.nn.sigmoid, name='f1_att', reuse=tf.AUTO_REUSE)
  # 第一層網路,輸出[B, T, 80]
  d_layer_2_all = tf.layers.dense(d_layer_1_all, 40, activation=tf.nn.sigmoid, name='f2_att', reuse=tf.AUTO_REUSE)
  # 第二層網路,輸出[B, T, 40]
  d_layer_3_all = tf.layers.dense(d_layer_2_all, 1, activation=None, name='f3_att', reuse=tf.AUTO_REUSE)
  # 第三層網路,輸出[B, T, 1]
  d_layer_3_all = tf.reshape(d_layer_3_all, [-1, 1, tf.shape(keys)[1]])
  outputs = d_layer_3_all
  # 最后的輸出為 [B, 1, T]
  # Mask
  key_masks = tf.sequence_mask(keys_length, tf.shape(keys)[1])   # [B, T]
  # 標識矩陣B * T個點位,哪些是true (存在之前點擊過的商品)哪些是false(不存在之前點擊過的商品)
  #例如:tf.sequence_mask([1, 3, 2], 5),回傳值為:
  # [[True, False, False, False, False],
  #  [True, True, True, False, False],
  #  [True, True, False, False, False]]
  key_masks = tf.expand_dims(key_masks, 1) # [B, 1, T]
  # 緯度變為 [B, 1, T]
  paddings = tf.ones_like(outputs) * (-2 ** 32 + 1)
  # 生成與outputs緯度相同的tensor,緯度為 [B, 1, T],所有值初始化為:-2 ** 32 + 1,之所以如此初始化是因為-2 ** 32 + 1 在softmax中取值無限接近于0.
  outputs = tf.where(key_masks, outputs, paddings)  # [B, 1, T]
  # key_masks對應點如果為true,則賦值為對應outputs點的值,如果為false(不存在的),賦值為對應paddings點的值:-2 ** 32 + 1,
  # Scale
  outputs = outputs / (keys.get_shape().as_list()[-1] ** 0.5)
  # 歸一化處理 outputs = outputs / sqrt(H)
  # Activation
  outputs = tf.nn.softmax(outputs)  # [B, 1, T]
  # softmax,最后T個維度分別表示T個產品和推薦產品的相關性,相關性越高對應softmax輸出值就越大,
  # Weighted sum
  outputs = tf.matmul(outputs, keys)  # [B, 1, H]
  # sum polling: 基于相關性和attention機制,選擇相關性高的embedding向量,
  # 兩個矩陣維度分別為 [B, 1, T] 和 [B, T, H],實際是矩陣的后兩緯相乘:[1,T]*[T,H],第一個[1,T]向量,每一個代表了相關度大小,
  # 相關度越高,對應的歷史點擊商品和當前推薦商品的
  return outputs # 回傳 B * 1 * H

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] # 推薦商品的embedding向量維度
  queries_nums = queries.get_shape().as_list()[1] # 推薦商品的個數
  queries = tf.tile(queries, [1, 1, tf.shape(keys)[1]]) # queries的1維和2維不變,3維擴張為原來的的T倍,T對應之前看過的商品數,
  # [B,N,T*H]
  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], 推薦商品embedding和訪問商品embedding形成一一對應
  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.AUTO_REUSE)
  d_layer_2_all = tf.layers.dense(d_layer_1_all, 40, activation=tf.nn.sigmoid, name='f2_att', reuse=tf.AUTO_REUSE)
  d_layer_3_all = tf.layers.dense(d_layer_2_all, 1, activation=None, name='f3_att', reuse=tf.AUTO_REUSE)
  d_layer_3_all = tf.reshape(d_layer_3_all, [-1, queries_nums, 1, max_len])
  # [B,N,1,T]
  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類初始化建構式__init__中完成定義和初始化,model類呼叫train函式完成訓練,分開來進一步分析代碼:

訓練函式和輸入:

  def train(self, sess, uij, l):
    loss, _ = sess.run([self.loss, self.train_op], feed_dict={
        self.u: uij[0], # 用戶id
        self.i: uij[1], # 推薦商品id
        self.y: uij[2], # 是否點擊該商品
        self.hist_i: uij[3], # 之前點擊商品串列
        self.sl: uij[4], #之前點擊商品個數
        self.lr: l, # 學習率
        })
    return loss

其中,輸入:用戶id商品id是否點擊該商品(label: 0 或者 1)和點擊商品個數均為1維:batch_size(一個batch的樣本數) 大小的向量,而輸入:之前點擊商品串列為2維:batch_size * T(所有batch_size個樣本里點擊過商品最大的個數),輸入tensor與訓練函式的輸入資料對應:

    self.u = tf.placeholder(tf.int32, [None,]) # [B] 用戶id
    self.i = tf.placeholder(tf.int32, [None,]) # [B] 推薦商品id
    self.j = tf.placeholder(tf.int32, [None,]) # [B] 
    self.y = tf.placeholder(tf.float32, [None,]) # [B] 是否點擊
    self.hist_i = tf.placeholder(tf.int32, [None, None]) # [B, T] 之前點擊商品id串列
    self.sl = tf.placeholder(tf.int32, [None,]) # [B] 之前點擊商品個數
    self.lr = tf.placeholder(tf.float32, []) # 學習率

embedding層定義

    hidden_units = 128

    user_emb_w = tf.get_variable("user_emb_w", [user_count, hidden_units]) # 用戶embedding
    item_emb_w = tf.get_variable("item_emb_w", [item_count, hidden_units // 2]) # 商品embedding
    item_b = tf.get_variable("item_b", [item_count],
                             initializer=tf.constant_initializer(0.0))
    cate_emb_w = tf.get_variable("cate_emb_w", [cate_count, hidden_units // 2])
    cate_list = tf.convert_to_tensor(cate_list, dtype=tf.int64) # 所有商品的分類List

embedding層定義如下幾個embedding層:

用戶id的embedding:user_emb_w

商品item id的embedding: item_emb_w

商品分類的embedding:cate_emb_w

以及:

商品item id的embedding的偏置:item_b

所有商品對應的商品分類(大約有幾百個分類,初始化輸入后轉換為固定的tensor):cate_list(1對1分類的List,List索引位置對應商品id編碼,直接通過索引找到商品分類)

embedding特征拼接

    ic = tf.gather(cate_list, self.i)
    i_emb = tf.concat(values = [
        tf.nn.embedding_lookup(item_emb_w, self.i),
        tf.nn.embedding_lookup(cate_emb_w, ic),
        ], axis=1)
        # 推薦商品i的embedding + 分類embedding B*T,BATCH_SIZE個一維向量,
        # 兩個embedding的向量維度均為hidden_units // 2,故拼接后的embedding向量的維度為hidden_units
    i_b = tf.gather(item_b, self.i)

    jc = tf.gather(cate_list, self.j)
    j_emb = tf.concat([
        tf.nn.embedding_lookup(item_emb_w, self.j),
        tf.nn.embedding_lookup(cate_emb_w, jc),
        ], axis=1)
    j_b = tf.gather(item_b, self.j)

    hc = tf.gather(cate_list, self.hist_i)
    h_emb = tf.concat([
        tf.nn.embedding_lookup(item_emb_w, self.hist_i),
        tf.nn.embedding_lookup(cate_emb_w, hc),
        ], axis=2) # 之前點過商品的embedding + 分類embedding B*N*T,BATCH_SIZE個樣本 * N個訪問記錄 * 一維向量

這里,i_emb商品id embedding特征商品分類embedding特征拼接到一起的特征,i_b為對應embedding特征的偏置,其對應維度為: B(BATCH_SIZE)*H(embedding向量維度128),h_emb為之前點擊過的商品id embedding特征分類embedding特征拼接到一起的特征,由于點擊過的商品可能有多個,其緯度為:B(BATCH_SIZE)*T(所有batch_size個樣本里點擊過商品最大的個數)*H(embedding向量維度128),

attention層

attention實作代碼:

    hist_i =attention(i_emb, h_emb, self.sl)
    # 回傳 [B,1,H],一個Batch每一個樣本都有一個 sum pooling出的embedding向量,
    # embedding向量維度為hidden_units,

attention函式定義:

def attention(queries, keys, keys_length):
  '''
    queries:     [B, H] BATCH_SIZE個embedding向量(二維矩陣)
    keys:        [B, T, H] BATCH_SIZE個之前訪問T個商品的embedding向量(三維矩陣)
    keys_length: [B] batch_size里面,每個用戶之前點擊過商品的個數,注意這里和T的區別,T是取的所有里面的最大值,是定長,而這里是非定長的,表示的是實際點擊的商品數,
  '''
  queries_hidden_units = queries.get_shape().as_list()[-1] # 推薦商品的embedding向量維度
  queries = tf.tile(queries, [1, tf.shape(keys)[1]]) # queries的1緯不變,2維擴張為原來的T倍,即之前點擊過的商品數,
  # querise緯度變為 [B, T*H]
  queries = tf.reshape(queries, [-1, tf.shape(keys)[1], queries_hidden_units])
  # 修改querise緯度變為[B, T, H],對于一個推薦商品,其會生成T個重復的相同一個推薦商品的embedding向量,
  din_all = tf.concat([queries, keys, queries-keys, queries*keys], axis=-1)
  # 最后一個維度拼接到一起,拼接后變為 [B, T, 4*H]
  d_layer_1_all = tf.layers.dense(din_all, 80, activation=tf.nn.sigmoid, name='f1_att', reuse=tf.AUTO_REUSE)
  # 第一層網路,輸出[B, T, 80]
  d_layer_2_all = tf.layers.dense(d_layer_1_all, 40, activation=tf.nn.sigmoid, name='f2_att', reuse=tf.AUTO_REUSE)
  # 第二層網路,輸出[B, T, 40]
  d_layer_3_all = tf.layers.dense(d_layer_2_all, 1, activation=None, name='f3_att', reuse=tf.AUTO_REUSE)
  # 第三層網路,輸出[B, T, 1]
  d_layer_3_all = tf.reshape(d_layer_3_all, [-1, 1, tf.shape(keys)[1]])
  outputs = d_layer_3_all
  # 最后的輸出為 [B, 1, T]
  # Mask
  key_masks = tf.sequence_mask(keys_length, tf.shape(keys)[1])   # [B, T]
  # 標識矩陣B * T個點位,哪些是true (存在之前點擊過的商品)哪些是false(不存在之前點擊過的商品)
  #例如:tf.sequence_mask([1, 3, 2], 5),回傳值為:
  # [[True, False, False, False, False],
  #  [True, True, True, False, False],
  #  [True, True, False, False, False]]
  key_masks = tf.expand_dims(key_masks, 1) # [B, 1, T]
  # 緯度變為 [B, 1, T]
  paddings = tf.ones_like(outputs) * (-2 ** 32 + 1)
  # 生成與outputs緯度相同的tensor,緯度為 [B, 1, T],所有值初始化為:-2 ** 32 + 1,之所以如此初始化是因為-2 ** 32 + 1 在softmax中取值無限接近于0.
  outputs = tf.where(key_masks, outputs, paddings)  # [B, 1, T]
  # key_masks對應點如果為true,則賦值為對應outputs點的值,如果為false(不存在的),賦值為對應paddings點的值:-2 ** 32 + 1,
  # Scale
  outputs = outputs / (keys.get_shape().as_list()[-1] ** 0.5)
  # 歸一化處理 outputs = outputs / sqrt(H)
  # Activation
  outputs = tf.nn.softmax(outputs)  # [B, 1, T]
  # softmax,最后T個維度分別表示T個產品和推薦產品的相關性,相關性越高對應softmax輸出值就越大,
  # Weighted sum
  outputs = tf.matmul(outputs, keys)  # [B, 1, H]
  # sum polling: 基于相關性和attention機制,選擇相關性高的embedding向量,
  # 兩個矩陣維度分別為 [B, 1, T] 和 [B, T, H],實際是矩陣的后兩緯相乘:[1,T]*[T,H],第一個[1,T]向量,每一個代表了相關度大小,
  # 相關度越高,對應的歷史點擊商品和當前推薦商品的
  return outputs # 回傳 B * 1 * H

這是論文演算法中最核心的部分,代碼中已經給了詳細注釋,基本原理就是通過一個3層全連接的神經網路來學習當前推薦商品i_emb和之前點擊所有商品的embedding特征h_emb中每一個商品的特征的相關性,這里通過輸入兩個embedding特征的以及它們之間的乘積來增強對特征的學習:

din_all = tf.concat([queries, keys, queries-keys, queries*keys], axis=-1)

隨后,通過softmax生成attention機制,最后通過sum pooling根據相關性選擇出之前點擊過的相關性較高的商品的embedding特征,

全連接層

    hist_i = tf.layers.batch_normalization(inputs = hist_i)
    hist_i = tf.reshape(hist_i, [-1, hidden_units], name='hist_bn')
    # [B, hidden_units],每一個embedding向量的維度是hidden_units,
    hist_i = tf.layers.dense(hist_i, hidden_units, name='hist_fcn')
    u_emb_i = hist_i
 
    din_i = tf.concat([u_emb_i, i_emb, u_emb_i * i_emb], axis=-1)
    din_i = tf.layers.batch_normalization(inputs=din_i, name='b1')
    d_layer_1_i = tf.layers.dense(din_i, 80, activation=tf.nn.sigmoid, name='f1')
    #if u want try dice change sigmoid to None and add dice layer like following two lines. You can also find model_dice.py in this folder.
    # d_layer_1_i = tf.layers.dense(din_i, 80, activation=None, name='f1')
    # d_layer_1_i = dice(d_layer_1_i, name='dice_1_i')
    d_layer_2_i = tf.layers.dense(d_layer_1_i, 40, activation=tf.nn.sigmoid, name='f2')
    # d_layer_2_i = tf.layers.dense(d_layer_1_i, 40, activation=None, name='f2')
    # d_layer_2_i = dice(d_layer_2_i, name='dice_2_i')
    d_layer_3_i = tf.layers.dense(d_layer_2_i, 1, activation=None, name='f3')
    din_j = tf.concat([u_emb_j, j_emb, u_emb_j * j_emb], axis=-1)
    din_j = tf.layers.batch_normalization(inputs=din_j, name='b1', reuse=True)
    d_layer_1_j = tf.layers.dense(din_j, 80, activation=tf.nn.sigmoid, name='f1', reuse=True)
    # d_layer_1_j = tf.layers.dense(din_j, 80, activation=None, name='f1', reuse=True)
    # d_layer_1_j = dice(d_layer_1_j, name='dice_1_j')
    d_layer_2_j = tf.layers.dense(d_layer_1_j, 40, activation=tf.nn.sigmoid, name='f2', reuse=True)
    # d_layer_2_j = tf.layers.dense(d_layer_1_j, 40, activation=None, name='f2', reuse=True)
    # d_layer_2_j = dice(d_layer_2_j, name='dice_2_j')
    d_layer_3_j = tf.layers.dense(d_layer_2_j, 1, activation=None, name='f3', reuse=True)
    d_layer_3_i = tf.reshape(d_layer_3_i, [-1])
    d_layer_3_j = tf.reshape(d_layer_3_j, [-1])
    x = i_b - j_b + d_layer_3_i - d_layer_3_j # [B]
    self.logits = i_b + d_layer_3_i

attention層挑選出的用戶歷史行為特征u_emb_i和商品特征i_emb以及兩特征向量乘積送入全連接網路,最后加入偏置i_b成為最終logistic判定的輸入:

self.logits = i_b + d_layer_3_i

損失函式和訓練

最終損失函式為:

    self.loss = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(
            logits=self.logits,
            labels=self.y)
        )

訓練函式為:

    trainable_params = tf.trainable_variables()
    self.opt = tf.train.GradientDescentOptimizer(learning_rate=self.lr)
    gradients = tf.gradients(self.loss, trainable_params)
    clip_gradients, _ = tf.clip_by_global_norm(gradients, 5) # 避免一次迭代中權重的更新過于迅猛
    self.train_op = self.opt.apply_gradients( 
        zip(clip_gradients, trainable_params), global_step=self.global_step)

這里可以與最開始部分介紹的模型呼叫的訓練函式train()對應上了,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/423557.html

標籤:AI

上一篇:知識圖譜 ——知識存盤與檢索

下一篇:Pyecharts 獵聘招聘資料可視化

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more