xDeepFM架構理解及實現

本文主要是爲了講解xDeepFM的框架,及如何用tensorflow去實現主幹部分,如果需要直接拆箱可用,可以參考:xDeepFM,我的部分代碼也來自於其中,這邊主要是和大家一起對比着看下,xDeepFM到底做了哪些事情?我的工程實現代碼等待我司項目上線穩定後開源。

XDeepFM到底extreme在哪裏?

首先,我在做論壇帖子推薦的時候遇到這麼一個問題(問題真實,問題內容純屬虛構),用戶A:帶有如下標籤[籃球、足球、健身],用戶B:帶有如下標籤[籃球,電腦,蔡徐坤],在使用deepfm做精排的時候,常常會把A和B所看的內容互相推薦,很明顯,A是運動達人,而B是二次元達人,這樣推薦是存在很大問題的。
我在處理的時候,採取了兩種套路:

  • 改變Memorization爲attention網絡,強化feature直接的聯繫,讓B中的電腦與蔡徐坤進行綁定,而不是讓籃球電腦蔡徐坤進行混合綁定,讓Memorization去記憶的時候進行權重傾斜
  • Memorization通常爲低階特徵交互,那我就升高階數,svm告訴我們,在越高的維度上我們越有可能把數據集進行越離散的切分,XDeepFM就相當於把DeepFM中的1維+2維,變成了1維+2維+(l+1)維特徵組合

XDeepFM如何實現的?

網上大多數版本都是甩出的正方體圖+公式,我覺得很不清晰,這邊就不貼了,我直接貼代碼及解釋:

nn_input = tf.reshape(nn_input, shape=[-1, int(field_num), self.hparams.dim])

我們知道,無論是deepfm還是XDeepFM在初始化的時候,都會把feature進行onehotencoding後向量化,然後再壓縮成一個[batch,dim*FIELD_COUNT]的input,這邊只是將其還原成網上常見的正方體的形式:[batch,field_num,dim]

split_tensor0 = tf.split(hidden_nn_layers[0], self.hparams.dim * [1], 2)

這個就是XDeepFM最有意思的地方,我們正常理解都是把特徵按照不同的特徵進行切分組合,在XDeepFM它卻按照dim進行切開然後進行點擊,而且是外積,所以大家難以理解的就在這邊,用數據來說就是:

tf.convert_to_tensor(np.arange(1,13).reshape(2,2,3),dtype=tf.int32)

array([[[ 1,  2,  3],
        [ 4,  5,  6]],

       [[ 7,  8,  9],
        [10, 11, 12]]], dtype=int32)
切割完爲:
[array([[[ 1],
         [ 4]],

        [[ 7],
         [10]]], dtype=int32), 

         array([[[ 2],
         [ 5]],

        [[ 8],
         [11]]], dtype=int32), 

         array([[[ 3],
         [ 6]],

        [[ 9],
         [12]]], dtype=int32)]

這邊沒有按照[1,2,3]這種方式去切分,而是按照[[1],[4]]這種方式,在dim上進行切分。

dot_result_m = tf.matmul(split_tensor0, split_tensor, transpose_b=True)這一步也是很有意思,沒有常規意義上做點擊dot,做的外積,生生的把向量鋪開了:

array([[[[  1,   4],
         [  4,  16]],

        [[ 49,  70],
         [ 70, 100]]],


       [[[  4,  10],
         [ 10,  25]],

        [[ 64,  88],
         [ 88, 121]]],


       [[[  9,  18],
         [ 18,  36]],

        [[ 81, 108],
         [108, 144]]]], dtype=int32)

把剛纔的[[1],[4]]按照外積的形式去處理了,並得到了一個[bacth_size,dim,field_nums[0] * field_nums[-1]]的形式。再通過[1,field_nums[-1] * field_nums[0],output]進行卷積處理相當於在dim的每一維上進行融合,融合的是所有特徵dim的每一維。最後才sum_pooling操作,外接一個輸出層壓縮到1個輸出值。

CIN爲什麼要搞這麼複雜,比deepfm好在哪?

看代碼就知道,剛纔CIN的過程可以進行N次,這裏面的l代表着從0層開始了l次的特徵組合,比起deepfm的2次,對特徵的組合更深,能解釋的空間更爲複雜

CIN很完美嗎?

雖然作者在論文剛開始的時候就吐槽了DCN的低端,認爲DCN其實就是init層的N次交叉,但是我認爲DCN的殘差項保證了特徵的1~l+1特徵都有,而CIN中去除了殘差項,雖然更快了,但是相當於丟棄了1~l階特徵的組合結果,不見得可取

實操經驗分享?

  • XDeepFM比起循環神經網絡是快了不止一個量級的,基於DNN+CNN這種架構下,並行策略保證它很高效的執行速度。
  • 如果是baseline的嘗試,建議優先DeepFM,絕大多數情況下,DeepFM已經滿足了我們的基礎需求。我司實際項目的效果下XDeepFM在離線數據集上目前也只有0.1%的提升,但是代碼量及code review的壓力卻大了很多。
  • 在走XDeepFM的路子時候,可以考慮把DeepFM中的Memorization層加入DIN中的Attention,完全不遜色。

更多代碼內容歡迎follow我的個人Github,如果有任何算法、代碼疑問都歡迎通過郵箱發消息給我。

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