深度推薦模型之NFM

1 背景

       FM已經公認是稀疏數據預測中最有效的嵌入方法之一,已經成功用到了像在線廣告,微博檢索,推薦等領域。但是,FM方法的性能受其僅線性和二階交互的限制,現實世界數據的基礎結構是高度非線性的,FM無法勝任各種具有複雜結構和規律性的真實數據。儘管已經提出了高階FM,但它們仍屬於線性模型族,並且據稱難以計量。

       DNN可以有效捕捉特徵的高階交互信息,作者將FM與DNN結合,又引入了雙交互層將二者連接起來,這樣就組合了FM的建模低階特徵交互能力和DNN學習高階特徵交互和非線性的能力,形成了深度學習時代的神經FM模型(NFM)。

2 模型結構與原理

    

       模型利用FM和DNN的優勢來進行稀疏數據建模。NFM將目標估計爲 ,對比FM,前兩項還是原來的,第三項 是NFM用來建模特徵交互的核心,它是一個多層前饋神經網絡。

2.1 Input Layer and Embedding Layer

       輸入層的特徵,文章指定了稀疏離散特徵居多,這種特徵我們也知道一般是先one-hot, 然後會通過embedding,處理成稠密低維的。

2.2 Bi-Interaction Layer

       將嵌入集合  送到Bi-Interaction層,這是將一組嵌入向量轉換爲一個向量的池化操作: ,其中表示兩個向量的元素積操作。顯然,雙向交互池化的輸出是一個 維向量,該向量對嵌入空間中要素之間的二階交互進行編碼。值得指出的是,雙向交互池化沒有引入額外的模型參數,更重要的是,它可以在線性時間內有效地計算出來。可以將上式重新寫成 後面代碼復現NFM就是用的這個公式直接計算,比較簡便且清晰。

2.3 Hidden Layers

       這一層就是全連接的神經網絡, DNN在進行特徵的高層非線性交互上有着天然的學習優勢。

    

       非線性激活函數可以根據需要來指定。

2.4 Prediction Score

       這個就是最後一層的結果直接過一個隱藏層,但注意由於這裏是迴歸問題,沒有加sigmoid激活:

       所以, NFM模型的前向傳播過程總結如下: 這就是NFM模型的全貌, NFM相比較於其他模型的核心創新點是雙向交互層,基於它,實現了FM和DNN的無縫連接,使得DNN可以在底層就學習到包含更多信息的組合特徵,這時候,就會減少DNN的很多負擔,只需要很少的隱藏層就可以學習到高階特徵信息。NFM相比之前的DNN,模型結構更淺,更簡單,但是性能更好,訓練和調參更容易。集合FM二階交叉線性和DNN高階交叉非線性的優勢,非常適合處理稀疏數據的場景任務。在對NFM的真實訓練過程中,也會用到像Dropout和BatchNormalization這樣的技術來緩解過擬合和在過大的改變數據分佈。

3 代碼實現

def NFM(linear_feature_columns, dnn_feature_columns):
    """
    搭建NFM模型,上面已經把所有組塊都寫好了,這裏拼起來就好
    :param linear_feature_columns: A list. 裏面的每個元素是namedtuple(元組的一種擴展類型,同時支持序號和屬性名訪問組件)類型,表示的是linear數據的特徵封裝版
    :param dnn_feature_columns: A list. 裏面的每個元素是namedtuple(元組的一種擴展類型,同時支持序號和屬性名訪問組件)類型,表示的是DNN數據的特徵封裝版
    """
    # 構建輸入層,即所有特徵對應的Input()層, 這裏使用字典的形式返回, 方便後續構建模型
    # 構建模型的輸入層,模型的輸入層不能是字典的形式,應該將字典的形式轉換成列表的形式
    # 注意:這裏實際的輸入與Input()層的對應,是通過模型輸入時候的字典數據的key與對應name的Input層
    dense_input_dict, sparse_input_dict = build_input_layers(linear_feature_columns+dnn_feature_columns)
    input_layers = list(dense_input_dict.values()) + list(sparse_input_dict.values())
    
    # 線性部分的計算 w1x1 + w2x2 + ..wnxn + b部分,dense特徵和sparse兩部分的計算結果組成,具體看上面細節
    linear_logits = get_linear_logits(dense_input_dict, sparse_input_dict, linear_feature_columns)
    
    # DNN部分的計算
    # 首先,在這裏構建DNN部分的embedding層,之所以寫在這裏,是爲了靈活的遷移到其他網絡上,這裏用字典的形式返回
    # embedding層用於構建FM交叉部分以及DNN的輸入部分
    embedding_layers = build_embedding_layers(dnn_feature_columns, sparse_input_dict, is_linear=False)
    
    # 過特徵交叉池化層
    pooling_output = get_bi_interaction_pooling_output(sparse_input_dict, dnn_feature_columns, embedding_layers)
    
    # 加個BatchNormalization
    pooling_output = BatchNormalization()(pooling_output)
    
    # dnn部分的計算
    dnn_logits = get_dnn_logits(pooling_output)
    
    # 線性部分和dnn部分的結果相加,最後再過個sigmoid
    output_logits = Add()([linear_logits, dnn_logits])
    output_layers = Activation("sigmoid")(output_logits)
    
    model = Model(inputs=input_layers, outputs=output_layers)
    
    return model

    

    nfm

4 思考

       NFM中的特徵交互與FM中的特徵交互的異同:NFM的改進在於加入了池化和後續的DNN部分,能夠增強FM部分的表達能力,只要FM把二階學習好了,通過後續DNN捕獲高階交互會更加容易。如果不加入DNN,NFM便退化成FM。雙向交互層替代了原始FM中的向量內積部分,使用元素積操作對二階特徵進行編碼,讓自己的表達能力更加有效。

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章