DeepFM

1.動機(jī)
對于CTR問題,被證明的最有效的提升任務(wù)表現(xiàn)的策略是特征組合,在CTR問題的探究歷史上來看就是如何更好地學(xué)習(xí)特征組合,進(jìn)而更加精準(zhǔn)地描述數(shù)據(jù)的特點(diǎn)??梢哉f這是基礎(chǔ)推薦模型到深度學(xué)習(xí)推薦模型遵循的一個(gè)主要思想。而特征組合大牛們通過組合二階特征,三階甚至更高階,但是面臨一個(gè)問題就是隨著階數(shù)的提升,復(fù)雜度就呈幾何倍的升高。這樣即使模型的表現(xiàn)更好了,但是推薦系統(tǒng)在實(shí)時(shí)性要求也不能滿足了。所以很多模型的出現(xiàn)都是為了解決另一個(gè)更加深入的問題:如何更高效的學(xué)習(xí)特征組合?

為了解決上述問題,出現(xiàn)了FM與FFM來優(yōu)化LR特征組合較差的一個(gè)問題。并且在這個(gè)時(shí)候科學(xué)家們已經(jīng)發(fā)現(xiàn)了DNN在特征組合方面的優(yōu)勢,所以又出現(xiàn)了FNN和PNN等使用深度神經(jīng)網(wǎng)絡(luò)的模型。但是DNN也存在局限性。

  • = =DNN= = 當(dāng)我們使用DNN網(wǎng)絡(luò)解決推薦問題的時(shí)候存在網(wǎng)絡(luò)參數(shù)過于龐大的問題,這是因?yàn)樵谶M(jìn)行特征處理的時(shí)候我們需要使用one-hot編碼來處理離散特征,這會導(dǎo)致輸入的維度猛增。這里借AI大會上的一張圖片:


    1

    這樣龐大的參數(shù)量也是不實(shí)際的。為了解決DNN參數(shù)量過大的局限性,可以采用非常經(jīng)典的Field思想,將One-Hot特征轉(zhuǎn)換為Dense Vector


    2

此時(shí)通過增加全連接層就可以實(shí)現(xiàn)高階的特征組合,如下圖所示:


3

但是仍然缺少低階組合,于是增加FM來表示低階組合。

  • ==FNN和PNN==
    結(jié)合FM和DNN其實(shí)有兩種方式??梢圆⑿薪Y(jié)合也可以串行結(jié)合。這兩種方式各有幾種代表模型。在DeepFM之前有FNN,雖然在影響力上可能不如DeepFM,但是了解FNN的思想對我們理解DeepFM的特點(diǎn)和優(yōu)點(diǎn)是很有幫助的


    4
  • Wide&Deep
    FNN和PNN模型仍然有一個(gè)比較明顯的尚未解決的缺點(diǎn):對于低階組合特征學(xué)習(xí)到的比較少,這一點(diǎn)主要是由于FM和DNN的串行方式導(dǎo)致的,也就是雖然FM學(xué)到了低階特征組合,但是DNN的全連接結(jié)構(gòu)導(dǎo)致低階特征并不能在DNN的輸出端較好的表現(xiàn)??磥砦覀円呀?jīng)找到問題所在了,將串行方式改進(jìn)成為并行方式能比較好的解決這個(gè)問題。于是Google提出了wide&deep模型,但是如果深入wide&deep的構(gòu)成方式,雖然將整個(gè)模型的結(jié)構(gòu)調(diào)整為了并行結(jié)構(gòu),在實(shí)際的使用中widemodel中的部分需要比較精巧的特征工程,換句話說人工處理對于模型的效果具有比較大的影響。


    5

如上圖所示,該模型仍然存在問題:在Output Units階段直接將低階和高階特征進(jìn)行組合,很容易讓模型最終偏向?qū)W習(xí)到低階或者高階特征,而不能做到很好的結(jié)合。

綜上所述,DeepFM模型橫空出世

2.模型結(jié)構(gòu)與原理


6

前面的Field和Embedding處理的是和前面的方法相同,如上圖所示綠色部分;DeepFM將Wide部分替換為了FM layer如上圖所示藍(lán)色部分,這幅圖其實(shí)有很多需要注意的地方

  • Deep模型部分
  • FM模型部分
  • Sparse Feature中黃色和灰色節(jié)點(diǎn)代表什么意思

2.1 FM
下圖是一個(gè)FM的結(jié)構(gòu)圖,從圖中大致可以看出FM Layer是由一階特征和二階Concatenate到一起再經(jīng)過一個(gè)Sigmoid得到logits,所以在實(shí)現(xiàn)的時(shí)候需要單獨(dú)考慮Linear部分和FM交叉特征部分。
\hat{y}{FM}(x) = w_0+\sum{i=1}^N w_ix_i + \sum_{i=1}^N \sum_{j=i+1}^N v_i^T v_j x_ix_j

7

2.2 Deep


8

Deep Model是為了學(xué)習(xí)高階的特征組合,在上圖中使用全連接的方式將Dense Embedding輸入到Hidden Layer,這里面Dense Embeddings就是為了解決DNN中參數(shù)爆炸的問題,這也是推薦系統(tǒng)中常用的處理方式。

Embedding層的輸出是將所有id類特征對應(yīng)的Embedding向量concat到一起輸入到DNN中。其中v_i表示第i個(gè)field的embedding,m是field的數(shù)量。 z_1=[v_1, v_2, ..., v_m] 上一層的輸出作為下一層的輸入,我們得到: z_L=\sigma(W_{L-1} z_{L-1}+b_{L-1}) 其中\sigma表示激活函數(shù),z, W, b分別表示該層的輸入、權(quán)重和偏置。
最后進(jìn)入DNN部分輸出使用sigmod激活函數(shù)進(jìn)行激活: y_{DNN}=\sigma(W^{L}a^L+b^L)

3.代碼實(shí)現(xiàn)
DeepFM在模型的結(jié)構(gòu)圖中顯示,模型大致由兩部分組成,一部分是FM,還有一部分就是DNN, 而FM又由一階特征部分與二階特征交叉部分組成,所以可以將整個(gè)模型拆成三部分,分別是一階特征處理linear部分,二階特征交叉FM以及DNN的高階特征交叉。在下面的代碼中也能夠清晰的看到這個(gè)結(jié)構(gòu)。此外每一部分可能由是由不同的特征組成,所以在構(gòu)建模型的時(shí)候需要分別對這三部分輸入的特征進(jìn)行選擇。

  • linear_logits: 這部分是有關(guān)于線性計(jì)算,也就是FM的前半部分w1x1+w2x2...wnxn+b的計(jì)算。對于這一塊的計(jì)算,我們用了一個(gè)get_linear_logits函數(shù)實(shí)現(xiàn),后面再說,總之通過這個(gè)函數(shù),我們就可以實(shí)現(xiàn)上面這個(gè)公式的計(jì)算過程,得到linear的輸出, 這部分特征由數(shù)值特征和類別特征的onehot編碼組成的一維向量組成,實(shí)際應(yīng)用中根據(jù)自己的業(yè)務(wù)放置不同的一階特征(這里的dense特征并不是必須的,有可能會將數(shù)值特征進(jìn)行分桶,然后在當(dāng)做類別特征來處理)

  • fm_logits: 這一塊主要是針對離散的特征,首先過embedding,然后使用FM特征交叉的方式,兩兩特征進(jìn)行交叉,得到新的特征向量,最后計(jì)算交叉特征的logits

  • dnn_logits: 這一塊主要是針對離散的特征,首先過embedding,然后將得到的embedding拼接成一個(gè)向量(具體的可以看代碼,也可以看一下下面的模型結(jié)構(gòu)圖),通過dnn學(xué)習(xí)類別特征之間的隱式特征交叉并輸出logits值

def DeepFM(linear_feature_columns, dnn_feature_columns):
    # 構(gòu)建輸入層,即所有特征對應(yīng)的Input()層,這里使用字典的形式返回,方便后續(xù)構(gòu)建模型
    dense_input_dict, sparse_input_dict = build_input_layers(linear_feature_columns + dnn_feature_columns)

    # 將linear部分的特征中sparse特征篩選出來,后面用來做1維的embedding
    linear_sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), linear_feature_columns))

    # 構(gòu)建模型的輸入層,模型的輸入層不能是字典的形式,應(yīng)該將字典的形式轉(zhuǎn)換成列表的形式
    # 注意:這里實(shí)際的輸入與Input()層的對應(yīng),是通過模型輸入時(shí)候的字典數(shù)據(jù)的key與對應(yīng)name的Input層
    input_layers = list(dense_input_dict.values()) + list(sparse_input_dict.values())

    # linear_logits由兩部分組成,分別是dense特征的logits和sparse特征的logits
    linear_logits = get_linear_logits(dense_input_dict, sparse_input_dict, linear_sparse_feature_columns)

    # 構(gòu)建維度為k的embedding層,這里使用字典的形式返回,方便后面搭建模型
    # embedding層用戶構(gòu)建FM交叉部分和DNN的輸入部分
    embedding_layers = build_embedding_layers(dnn_feature_columns, sparse_input_dict, is_linear=False)

    # 將輸入到dnn中的所有sparse特征篩選出來
    dnn_sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), dnn_feature_columns))

    fm_logits = get_fm_logits(sparse_input_dict, dnn_sparse_feature_columns, embedding_layers) # 只考慮二階項(xiàng)

    # 將所有的Embedding都拼起來,一起輸入到dnn中
    dnn_logits = get_dnn_logits(sparse_input_dict, dnn_sparse_feature_columns, embedding_layers)
    
    # 將linear,FM,dnn的logits相加作為最終的logits
    output_logits = Add()([linear_logits, fm_logits, dnn_logits])

    # 這里的激活函數(shù)使用sigmoid
    output_layers = Activation("sigmoid")(output_logits)

    model = Model(input_layers, output_layers)
    return model
9

10
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容