模型吞噬特徵工程
本文已投中心公眾號。特徵工程是機器學習成敗的關鍵一步,其意義一點都不比模型低。巨集觀層面來說,模型水平決定了機器學習的上限,特徵工程水平決定了能接近上限多少。而對於具體問題層面,特徵工程水平決定了機器學習在這個問題上的上限,模型決定了能接近上限多少。
但是特徵工程和模型並不是涇渭分明。比如,那些年間工業界風起雲湧了那麼多 Learning to Rank 的模型,最終都變成了特徵。另外一方面,那些年間工業界那麼多下里巴人的特徵工程技巧,被模型吞噬,變成陽春白雪模型的一部分。今天我們只聊一聊特徵工程到模型的轉化。
一、特徵工程簡介
我個人認為,特徵工程可以分為兩個階段。1)準備資料,也就是根據領域知識拉取相應的資料,並且進行資料清洗。比如我們認為星期幾對人們感興趣的文章有影響,那麼我們構造樣本時,就會把星期幾的特徵放進去,並進行缺失值處理等等資料清洗的工作。2)資料變化,也就是各種歸一化、取 Log 、離散化、特徵組合交叉等等操作。資料變換目的是為了規整資料量綱和挖掘資料內部規律,從而增強資料表示。
當然,有不少朋友認為資料準備不是特徵工程。認為只有資料變化部分才是特徵工程。我的想法是這樣的。很多時候,加合理而重要的特徵是特徵工程的重要內容之一。加特徵這個操作同時涉及到資料準備和資料變化。資料變化又分為五個部分:
-
特徵提取,直接使用資料準備得到的原始特徵,或者根據原始特徵計算新特徵。
-
特徵變換,比如歸一化、離散化和取 Log,是將一個特徵值變換為特徵值。
-
特徵組合,其中最著名的特徵組合就是高階特徵交叉。比如,我們將使用者性別和商品顏色進行交叉,得到性別_顏色特徵,能很好的刻畫不同性別使用者對不同顏色商品的偏好。
-
特徵選擇,就是選擇合適的特徵,刪除冗餘特徵。
-
特徵 ID 化,機器學習模型接受的例項一般是稠密或者稀疏的特徵向量,這就需要我們將特徵進行排列並賦予 ID。我把特徵 ID 化也算進特徵工程裡來了。不然特徵工程和模型之間還有一層特徵 ID 化,太麻煩了。
資料變化的三個部分並不是嚴格按照 1,2,3,4,5 的順序進行的,而是按照個人程式設計時的喜好進行的。我們說模型正在越來越多地將特徵工程吸收進模型,當然說的是資料變化部分,也就是特徵變換、特徵組合和特徵 ID 化。資料準備是不可能納入模型的。
二、特徵提取
特徵提取變成模型一部分最著名的例子便是 CNN 了。
抽取圖片特徵最直觀辦法就是拿著模板匹配。比如最著名的例子——分辨圖中是貓還是狗,如果我們沒有深度學習模型也沒有計算機視覺知識,我們能想到的辦法:1)人肉選取一定大小的貓和狗的典型部位,即模板,比如貓和狗的鼻子、爪子、耳朵和尾巴等等;2)滑動一個和模板大小一致的視窗逐步掃描圖片,計算視窗內圖片和模板的匹配程度;3)每一個模板的不同視窗的匹配程度取最大值,得到長度為模板個數的特徵向量;4)將這個特徵向量扔到分類模型中預測。
在實際研究和工作中,直觀的模板匹配想法是做不出來的,難點在於如何有效地選擇模板。但這種特徵提取思路被 CNN 內化了,模板對應卷積核,取最大值對應最大池化,分類模型對應全連線層[8]。
唯一不同的是,CNN 可以通過聯合學習自動得到卷積核。也就是說,CNN 其實是將特徵提取納入模型中了。
另一個自動提取特徵的模型是 CatBoost。CatBoost 號稱是能處理類別特徵的梯度提升樹。實際上 CatBoost 是自動提取了不同類別對應的標籤值的比率(計算公式經過優化),得到連續比率值作為特徵。
三、特徵變換
我們確實很少看到,試圖將取 Log 、取平方、開根號、Scaling、Dummy 化、 離散化和 歸一化等等特徵變換手段,變成模型一部分的工作。但也不是不存在這方面的工作。
首先取 Log、取平方和開根號都是不需要額外引數的數學操作。只要資料夠,機器夠,我肯定都直接要了。沒有看到工作讓模型自動決定要不要開 取 Log、取平方和開根號等操作的。
其次 Scaling。Scaling 沒有歸一化優雅和魯棒(太容易受異常值的影響),在工業場景中出現得比較少,一般都是自己程式碼處理了。
然後 Dummy 化。Dummy 化是離散型別特徵的必選項,連續特徵的必不選項(其實也是有奇技淫巧可以用的)。
再然後離散化。模型自動離散化,好像真沒有。
最後歸一化。模型自動對資料進行歸一化,好像也沒有。
四、特徵組合
線上性模型為主的時代,因為線性模型不能處理非線性高階特徵,因此我們發展了一套特徵交叉的特徵工程技巧。比如,我們將使用者性別和商品顏色進行交叉,得到性別_顏色特徵,能很好的刻畫不同性別使用者對不同顏色商品的偏好。
為了自動進行特徵交叉,人們發明了 Factorization Machine (FM) 演算法,演算法的公式如下所示
FM 相對線性模型除了每個特徵有一個權重 w 之外,還有一個向量權重 v 。兩個向量權重內積乘特徵值,就表示交叉特徵的貢獻。通過這個操作,FM 模型將交叉特徵納入到模型中。作為 FM 的進一步發展,人們又發明了 Field-aware Factorization Machines (FFM),其公式如下圖所示。
FFM 認為特徵都屬於不同的 Fields, 比如性別屬於使用者 Field,顏色屬於物品 Field,時間屬於上下文 Field,好友資訊屬於社交 Field。 FFM 中每個特徵都有 n 個向量權重,其中 n 是 Fields 個數。計算交叉特徵時,會用對方特徵的 Field 所對應的向量權重。這樣做是為了更好地刻畫不同特徵的互動資訊。
沿著將特徵組合納入模型的思路,在大規模線性模型時代,LR 開啟了 FM -> FFM 的進化路線。進入深度學習時代, DNN 複製了大規模線性模型的進化之路,開啟了 W&D -> DCN -> DeepFM -> DeepFFM 的進化。這一切進化的原動力,便是將特徵組合納入到模型。
上面是一個成功的故事,現在講一個不成功的故事。為了自動挖掘特徵組合, Facebook 在 2014年介紹了通過 GBDT + LR 的方案 [4](XGBoost 是 GBDT 的後續發展)。 XGBoost + LR 融合方式原理很簡單。先用資料訓練一個 XGBoost 模型,然後將訓練資料中的例項給 XGBoost 模型得到例項的葉子節點,然後將葉子節點當做特徵訓練一個 LR 模型。XGBoost + LR 的結構如下所示。
XGBoost 的葉子節點代表了不同特徵的高階組合,本來也是一個強大模型自動完成特徵組合的故事。但是根據 [5] 的觀點,目前 XGBoost + LR 並沒有發展出自己的進化之路,XGBoost 只是成為了提取更多組合特徵的工具。我個人認為原因在 XGBoost 和 LR 以及深度學習模型,不能像 CNN 特徵提取器和分類模型一樣聯合訓練,XGBoost 等樹模型是通過葉子節點分裂進行訓練,LR 以及深度學習基於梯度進行訓練。但是這個故事並沒有結束,現在人們繼續探索樹模型和深度學習模型的融合之路 [6]。
五、特徵選擇
我們手動進行特徵選擇,一般是利用各種指標給特徵排序,選擇 Top K 的特徵作為選擇特徵。我們使用的大部分模型演算法已經 特徵選擇納入其中, 將一直在一定意義上進行自動特徵選擇。
從機器學習的很早期,模型就開始關注各種正則, 比如著名 L1 Norm 和 L2 Norm。L1 Norm 和 L2 Norm 能夠使得出現頻率很低或者不相關的特徵的權重很低,特別是 L1 Norm 非常傾向於讓這類特徵權值為 0 。 L1 Norm 在自動特徵選擇上如此成功,以致於人們選擇特徵直接用 L1 Norm 做。
進入深度學習時代, 模型依然很關注正則項。除了 L1 Norm 和 L2 Norm 之外,深度學習模型還發展出了 dropout 和 dropconnect 正則項。
我個人覺得,正是因為機器學習從很早期到大規模應用的現代,一直關注減少模型複雜度各種理論和實踐,在相當程度上做了特徵選擇的工作,才是得特徵選擇長期處於發育不良的狀態。比如我們做大規模 CTR 預估,處理好的特徵不做刷選,直接扔到模型裡訓練。即使有冗餘特徵,我們也會覺得模型內在 “特徵選擇” 機制能處理得七七八八。
六、特徵 ID 化
特徵 ID 化將特徵進行排列並賦予 ID。比如特徵性別男的 ID 是 12,我們就將特徵性別男放到特徵向量第 12 位。在演算法層面,模型沒有將特徵 ID 化納入到模型本身。但是在工程角度上,特徵 ID 化是模型模組的一部分。 特徵 ID 化只有兩種方法:
方法一建立一個大的 map,將特徵名作 key, 特徵 id 作 value。不同版本的模型,用到的特徵很可能不太一樣,所以同一個特徵名對應的特徵 id 很可能是不一致的。因此真實生產環境要求訓練程式將產生的模型和 map 同時儲存到某個目錄,線上預測服務將模型和 map 都載入完畢才開始對外提供服務。這個機制在邏輯上將模型和 map 看成一體的。一般這個機制是有工程師自己保證的。
然後我們看到了 Tensorflow 的 Feature Column。Feature Column 的一個重要好處,就是將這套機制封裝,對工程師不可見。工程師在寫訓練時,看到的是特徵名;在呼叫深度學習服務時,用的也是特徵名。當然 Feature Column 也不是完美的,Feature Column 內部是轉成稠密向量。因此用 Feature Column 處理 id 類特徵,就會產生巨大的浪費。
在 Tensorflow 中的程式設計體驗來說, Feature Column 幾乎可以看成計算圖的一部分。工程上,模型把這部分特徵 ID 化工作納入來了。
方法二用一個 hash 函式將特徵名映射出特徵。這個方法好處不用再維護一個巨大的 map, 但必須解決 hash 衝突的問題。
在大規模線性模型時代,hash 函式生成一個 int64 數字作為特徵位,以此來解決衝突問題。 雜湊值衝突機率類似於 生日問題。 k 個均勻分佈在 2^64 範圍的特徵雜湊值發生衝突的概率為:
1-exp^{-k(k-1)/2^64}
衝突機率就非常小了。在衝突率很小的情況下,即使有衝突也不影響模型效能。
這種解決衝突的方法只能用於支援特徵位取值範圍很大的大規模稀疏特徵的模型,比如線性模型。但是 XGBoost 等一類的樹模型和 DNN 等深度學習模型,就用不了了。對了深度學習模型,有人希望 Tensorflow 在工程上實現類似下圖的功能[1,2]。
這個功能什麼意思呢?意思就是使用傳統 HashTable 技術解決衝突,然後將整個 HashTable 變成模型的一部分(可訓練)。有獨立開發者實現了部分功能,可惜碰到了 Tensorflow 2.0 的大升級,被擱置下來了[3]。Tensorflow 2.0 大升級將對全部 lookup 類 API 進行審視。這也是工程上,模型納入特徵 ID 化的工作。
七、總結
一般實踐中,除了資料準備之外, 我們在演算法層面需要關注的特徵工程 有特徵提取、特徵變換和特徵組合;在工程層面需要關注的有特徵提取、特徵變換、特徵組合和特徵 ID 化。因為一般模型有控制複雜度的機制,相當於一定意義上進行自動特徵選擇,特徵選擇一般不需要關心。
特徵工程和模型並不是涇渭分明。那些年間工業界那麼多下里巴人的特徵工程技巧,被模型吞噬,變成陽春白雪模型的一部分。這也是模型進化的原動力之一。
參考資料
1. https://github.com/tensorflow/tensorflow/issues/24539
2. https://github.com/tensorflow/tensorflow/issues/19324
3. https://github.com/tensorflow/tensorflow/pull/24915
4. Practical Lessons from Predicting Clicks on Ads at Facebook
5.
https://mp.weixin.qq.com/s?__biz=MzI2MDIxMjQyMg==&mid=2653584249&idx=1&sn=f5056c9fe83376b173826f6d044f8e79&chksm=f1b3c8d0c6c441c6d45052fec0cbef4cff9c8d83fa426d6ff26bab64bad0e5b0e3e4b4afdab2&token=1421968141&lang=zh_CN#rd
6. Deep Neural Decision Trees
7.Instance Normalization: The Missing Ingredient for Fast Stylization
8.https://mp.weixin.qq.com/s?__biz=MzI2MDIxMjQyMg==&mid=2653584337&idx=1&sn=0172d34805fefa25551b5a93add62cab&chksm=f1b3c878c6c4416eeb1784c1c0798b2fa47f097b412038a966106031b3650cc1bcc9fb5225d4&token=1421968141&lang=zh_CN#rd