FFM算法解析及Python實現


1. 什么是FFM?

通過引入field的概念,FFM把相同性質的特征歸於同一個field,相當於把FM中已經細分的feature再次進行拆分從而進行特征組合的二分類模型。

2. 為什么需要FFM?

在傳統的線性模型中,每個特征都是獨立的,如果需要考慮特征與特征之間的相互作用,可能需要人工對特征進行交叉組合。非線性SVM可以對特征進行核變換,但是在特征高度稀疏的情況下,並不能很好的進行學習。由於推薦系統是一個高度系數的數據場景,由此產生了FM系列算法,包括FM,FFM,DeepFM等算法。

3. FFM用在哪?

和FM算法一樣,FFM主要應用在推薦算法中的CTR點擊率預估(排序)問題,推薦系統一般可以分成兩個模塊,召回和排序。比如對於電影推薦,召回模塊會針對用戶生成一個推薦電影列表,而排序模塊則負責對這個電影列表根據用戶的興趣做排序。當把FFM算法應用到推薦系統中時,具體地是應用在排序模塊。

4. FFM長什么樣?

FFM模型結構

線性部分大家都很熟悉,非線性部分是FFM的關鍵所在,並且與同樣有非線性部分的FM算法相比,FFM引入了field的概念。因此交叉項與FM算法的<vi , vj>不同,這里的是<vi,fj , vj,fi>

5. FFM交叉項的計算

以下圖網上流傳廣泛的圖為例:

其中,紅色部分對應的是Field,來自於原始特征的個數;
藍色部分對應的是feature,來自於原始特征onehot之后的個數。(連續型特征不用one-hot)
對於特征Feature:User=YuChin,有Movie=3Idiots、Genre=Comedy、Genre=Drama、Price四項要進行交叉組合:

綠色部分為對應特征one-hot之后的值,出現為1,不出現為0。對於連續型變量的處理,這里采用的是使用實際值,當然,也可以對連續型變量離散化處理,再進行one-hot。

6. FFM代碼分析

這里我們的FFM算法是基於Tensorflow實現的。

為什么用Tensorflow呢?觀察二次項,由於field的引入,Vffm需要計算的參數有 nfk 個,遠多於FM模型的 nk個,而且由於每次計算都依賴於乘以的xj的field,所以,無法用fm的計算技巧(ab = 1/2(a+b)^2-a^2-b^2),所以計算復雜度是 O(n^2)。

因此使用Tensorflow的目的是想通過GPU進行計算。同時這也給我們提供了一個思路:如果模型的計算復雜度較高,當不能使用CPU快速完成模型訓練時,可以考慮使用GPU計算。比如Xgboost是已經封裝好可以用在GPU上的算法庫,而那些沒有GPU版本的封裝算法庫時,例如我們此次采用的FFM算法,我們可以借助Tensorflow的GPU版本框架設計算法,並完成模型訓練。

代碼主要分三部分:

build_data.py

主要是完成對原始數據的轉化。主要包括構造特征值對應field的字典。

FFM.py

主要包括線性部分及非線性部分的代碼實現。

tools.py

主要包括訓練集的構造。

這里我們主要分析 FFM.py,也就是模型的構建過程:

首先初始化一些參數,包括:

  • k:隱向量長度
  • f :field個數
  • p:特征值個數
  • 學習率大小
  • 批訓練大小
  • 正則化
  • 模型保存位置等

代碼如下圖所示:

 

然后,構造了一個model類,主要存放:

  • 初始化的一些參數
  • 模型結構
  • 模型訓練op(參數更新)
  • 預測op
  • 模型保存以及載入的op

代碼如下圖所示:

 

之后,對模型構造部分代碼進行分析,可發現模型由兩部分組成,第一部分是下圖紅框內容,其實就是線性表達式 w^Tx+b,其中:

  • b shape(None,1)
  • x shape (batch_size,p)
  • w1 shape(p,1)    注:p為特征值個數

定義變量及初始化后,就可以構造線性模型,代碼如下圖所示:

 

 

然后,定義一個Vffm變量用來存放交叉項的權重,並初始化。因為我們已經了解到Vffm是一個三維向量,所以,v :shape(p,f,k) 。

之后是vi,fj、vj,fi的構造。因為v 有p行,代表共有p個特征值,所以vifj = v[i, feature2field[j]],說人話就是第i個特征值在第j個特征值對應的field上的隱向量。

vjfi 的構造方法類似,所以vivj就可以求出來.然后就是把交叉項累加,然后 reshape 成(batch_size,1)的形狀,以便與線性模型進行矩陣加法計算。

代碼如下圖所示:

  

下圖描述了所有交叉項的隱向量Vffm所處的位置。假設p=16、f=3、k=6,16個項所屬的field為{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 1, 7: 1, 8: 1, 9: 1, 10: 2, 11: 2, 12: 2, 13: 2, 14: 2, 15: 2},共有120個交叉項,vifj和vjfi隱向量分別各有120個。其中:

vifj隱向量: {(3, 0), (11, 2), (2, 1), (6, 2), (5, 1), (7, 2), (4, 0), (1, 2), (12, 2), (8, 1), (2, 2), (4, 1), (1, 1), (3, 2), (0, 0), (13, 2), (8, 2), (7, 1), (4, 2), (1, 0), (14, 2), (0, 1), (9, 2), (6, 1), (3, 1), (2, 0), (5, 2), (0, 2), (10, 2)},共29個不同的隱向量。
vjfi隱向量: {(12, 1), (9, 1), (3, 0), (11, 2), (8, 0), (15, 1), (14, 0), (4, 0), (12, 2), (9, 0), (8, 1), (15, 0), (14, 1), (11, 1), (5, 0), (10, 0), (13, 2), (7, 1), (6, 0), (11, 0), (10, 1), (1, 0), (14, 2), (13, 1), (7, 0), (15, 2), (12, 0), (2, 0), (13, 0)},共29個不同的隱向量。

而vifj和vjfi相加起來共有48個各不相同的隱向量。也就是說,下圖展示的每一個隱向量都有用,即都能在模型中找到,且很多交叉項的隱向量一樣。

舉個栗子:

v1,15代表着第1個特征值在第15個特征值對應的field(field=2)上的隱向量。即v1,15 = v[1, feature2field[15]] = Vffm[1,2] ,其中v1,15的shape = (1,6)。

 

最后,就是loss的定義。這里要注意我們之前在構造訓練集時已經把輸出的(0,1)分類轉化為(-1,1)分類。

核心加重點是關注loss的計算公式,此時的計算公式是-1/1做二分類的時候常用的loss計算方法。

7.  總結

7.1 FFM 算法流程

7.1.1 輸入部分

  1. 類別型特征對應的變量的值映射為0到n-1

  2. 連續型變量保持原樣,不做處理,只需把變量名映射為n即可。(也可按實際情況進行離散化處理)

  3. 根據每一特征所屬的field,構造字典:每一field的取值,例如:field為0,那么{0:0,0:1,0:2} 。key為field,value為變量值或變量名的映射

  4. 構造feature2field字典,本質就是把步驟3中的field字典的k-v交換位置

  5. 最終模型的輸入數據為(None,n+1),其中n個離散變量的特征,取值為0/1,1個連續變量的特征,取值為連續值(需要歸一化)

7.1.2 輸出部分

  1. 輸出y 由0/1分類轉換為-1/1分類

  2. 構造字典{1:n+2,-1:n+3}作為輸出

  3. 構造訓練集需要的字典field_dict,包括輸入數據和輸出數據,例如:{‘c1’:{1008:0,1001:1},'c2':{0:6,1:7}}

7.2 注意事項

  1. 原始FFM論文中的結論:隱向量的維度 k值的調整提升效果不明顯。

  2. 為了使用FFM方法,所有的特征必須轉換成“field_id:feat_id:value”格式,field_id代表特征所屬field的編號,feat_id是特征編號,value是特征的值。

  3. numerical數值型的特征比較容易處理,只需分配單獨的field編號,如用戶評論得分、商品的歷史CTR/CVR等。優點是快速簡單,不需要預處理,但是缺點也很明顯,離群點影響,值的波動大等。因此可對numerical數值型特征采用連續值離散化或分箱下的連續值離散化的方法,將其轉化為categorical類別型特征。

  4. categorical類別型特征需要經過One-Hot編碼成數值型,編碼產生的所有特征同屬於一個field,而特征的值只能是0或1,如用戶的性別、年齡段,商品的品類id等。

  5. 樣本歸一化。FFM默認是進行樣本數據的歸一化,若不進行數據樣本的歸一化,很容易造成數據inf溢出,進而引起梯度計算的nan錯誤。因此,樣本層面的數據是推薦進行歸一化的。

  6. 特征歸一化。CTR/CVR模型采用了多種類型的源特征,包括數值型和categorical類型等。但是,categorical類編碼后的特征取值只有0或1,較大的數值型特征會造成樣本歸一化后categorical類生成特征的值非常小,沒有區分性。例如,一條用戶-商品記錄,用戶為“男”性,商品的銷量是5000個(假設其它特征的值為零),那么歸一化后特征“sex=male”(性別為男)的值略小於0.0002,而“volume”(銷量)的值近似為1。特征“sex=male”在這個樣本中的作用幾乎可以忽略不計,這是相當不合理的。因此,將源數值型特征的值歸一化也是非常必要的。

  7. 省略零值特征。從FFM模型的表達式可以看出,零值特征對模型完全沒有貢獻。包含零值特征的一次項和組合項均為零,對於訓練模型參數或者目標值預估是沒有作用的。因此,可以省去零值特征,提高FFM模型訓練和預測的速度,這也是稀疏樣本采用FFM的顯著優勢。

8. 參考文獻

[1] 深入FFM原理與實踐

[2] FM系列算法解讀(FM+FFM+DeepFM

[3] 推薦算法之FFM:原理及實現簡介

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM