天天看點

基于深度學習的推薦(六):CTR預估經典模型NFM

文章目錄

    • 公衆号
    • 前言
    • NFM模型
    • 代碼實戰
    • 參考

公衆号

關注公衆号:推薦算法工程師,輸入"進群",加入交流群,和小夥伴們一起讨論機器學習,深度學習,推薦算法.

基于深度學習的推薦(六):CTR預估經典模型NFM

前言

早期做特征工程的時候,采用人工或決策樹等來選擇特征,然而這些方法無法學習到訓練集中沒有出現的特征組合.而近幾年出現的基于embedding的方法,可以學習到訓練集中沒有出現的組合,作者将embedding方法歸為兩類,一類是FM這種線性模型,之前介紹過的FNN就是利用FM作為初始化的embedding;另一類是基于神經網絡的非線性模型,NFM(Neural Factorization Machine)則是将兩種embedding結合起來.NFM是發表在SIGIR 2017上的文章,出現在深度學習與推薦系統結合的初期,模型相對較為簡單,可以拿來練習tensorflow.

論文位址:https://arxiv.org/pdf/1708.05027.pdf

NFM模型

首先來回顧下FM模型:

基于深度學習的推薦(六):CTR預估經典模型NFM

設embedding向量次元為k,其中的二階交叉項可以進行優化:

基于深度學習的推薦(六):CTR預估經典模型NFM

交叉項得到的是一個值,如果去掉最外面那層求和,得到一個k維的向量.這個k維的向量就是所謂的"Bi-Interaction Layer"的結果:

基于深度學習的推薦(六):CTR預估經典模型NFM

将這個向量輸入全連接配接層,得到預測結果f(x),而最終的預估公式就是:

基于深度學習的推薦(六):CTR預估經典模型NFM

此時再看模型一目了然:

基于深度學習的推薦(六):CTR預估經典模型NFM

代碼實戰

這部分代碼改自之前AFM的代碼,有興趣可以自己改改試一試,挺簡單的.其中interaction layer的實作提供了優化前和優化後兩種寫法,可以運作下比較比較時間,差距蠻大.簡單看看幾個關鍵點的實作,首先是embedding layer:

with tf.name_scope('Embedding_Layer'):
    self.embeddings = tf.nn.embedding_lookup(self.weights['feature_embeddings'], self.feature_index)  # [None, field_size, embedding_size]
    feat_value = tf.reshape(self.feature_value, shape=[-1, self.field_size, 1])  # [None, field_size, 1]
    self.embeddings = tf.multiply(self.embeddings, feat_value)  # [None, field_size, embedding_size]
           

然後是預測公式的線性部分:

with tf.name_scope('linear_part'):
    self.linear_part = tf.nn.embedding_lookup(self.weights['linear_w'],self.feature_index)  # [None, field_size, 1]
    self.linear_part = tf.reduce_sum(tf.multiply(self.linear_part, feat_value), axis=2)  # [None, field_size]
    self.linear_part = tf.nn.dropout(self.linear_part, self.dropout_keep_fm[0])  # [None, field_size]
    self.linear_out = tf.reduce_sum(self.linear_part, axis=1, keep_dims=True) # [None, 1]
    self.w0 = tf.multiply(self.biases['w0'], tf.ones_like(self.linear_out)) # [None, 1]
           

B-Interaction Layer這一層的實作比較簡單:

with tf.variable_scope('interaction_layer'):
    self.sum_square_emb = tf.square(tf.reduce_sum(self.embeddings, axis=1)) # [None, embedding_size]
    self.square_sum_emb = tf.reduce_sum(tf.square(self.embeddings), axis=1) # [None, embedding_size]
    self.fully_out = 0.5 * tf.subtract(self.sum_square_emb, self.square_sum_emb) # [None, embedding_size]
           

然後就是後面的全連接配接層和最後的預測結果:

with tf.name_scope('fully_layer'):
    for i in range(len(self.deep_layers)):
        self.fully_out = tf.add(tf.matmul(self.fully_out, self.weights[i]), self.biases[i])
        self.fully_out = self.deep_layers_activation(self.fully_out)
        if(self.batch_norm):
            self.fully_out = self.batch_norm_layer(self.fully_out, self.train_phase)
        self.fully_out = tf.nn.dropout(self.fully_out, keep_prob=self.dropout_fm[i])

with tf.name_scope('out'):
    self.out = tf.add_n([self.w0, self.linear_out, self.fully_out]) # # yAFM = w0 + wx + f(x)
           

參考代碼:

afm代碼

nfm如何實作

完整資料和代碼:

nfm完整代碼和資料連結

參考

[1] https://arxiv.org/pdf/1708.05027.pdf

[2] https://github.com/faychu/nfm/blob/master/NeuralFM.py

繼續閱讀