再论推荐特征与embedding生成
文 | 水哥
源 | 知乎
Saying
1. 工業(yè)特征處理和學(xué)術(shù)特征處理存在巨大差異,這里建議同學(xué)們一定認(rèn)真閱讀。這個(gè)差異可能引發(fā)未來(lái)各種方法落地的矛盾。
2. full embedding在概念上和one-hot的操作等價(jià),但在操作上省略了這個(gè)過(guò)程。
3. hash是最省事的,一切特征轉(zhuǎn)string,一切string轉(zhuǎn)hash。
4. 在embedding分解這里沒(méi)有融入一些語(yǔ)義信息是比較遺憾的,如果有萬(wàn)能的知友看完后搞出來(lái)了請(qǐng)給我一個(gè)致謝。
這是 【從零單排推薦系統(tǒng)】 系列的第17講,承載上一講,這里要詳細(xì)聊聊特征生成和取embedding的過(guò)程是怎么樣的。需要注意的是,這一講的東西可能會(huì)構(gòu)成學(xué)術(shù)界和工業(yè)界最大差異的兩個(gè)地方。在閱讀論文的時(shí)候,判斷其中所講的東西有多大概率能在實(shí)踐中work,有兩個(gè)參考問(wèn)題:(1)該論文的特征機(jī)制如何處理源源不斷的新的特征或者新的ID?(2)該論文的訓(xùn)練機(jī)制是否與online learning的習(xí)慣沖突? 根據(jù)我個(gè)人的經(jīng)驗(yàn),和上面兩個(gè)點(diǎn)有沖突的方案難以在工業(yè)實(shí)踐中帶來(lái)提升,即使費(fèi)了勁把這兩個(gè)問(wèn)題解決了,最后效果可能也是平的。
具體來(lái)講,特征處理就是一個(gè)典型的學(xué)界/工業(yè)界有裂痕的例子,本講會(huì)回到embedding+DNN這個(gè)范式的上面部分,聊一聊特征的生成方式和業(yè)界對(duì)于embedding的一些重新思考。
特征生成
在學(xué)術(shù)研究中,有很多特征本身就是類別(categorical)特征,比如城市,枚舉國(guó)內(nèi)的所有城市,你一定在其中之一。我們往往把各類ID也看做類別特征,比如總共有1000個(gè)用戶,這次遇到的用戶是哪一類。與類別特征直接相關(guān)的處理方式就是先變成one-hot的向量(只有屬于的那一個(gè)bin是1,其他的都是0),在經(jīng)過(guò)一個(gè)矩陣 轉(zhuǎn)化到浮點(diǎn)向量參與后面的處理。舉個(gè)例子,我們?cè)谟脩魝?cè)有性別,User ID,城市三種特征。在科研情景中,我們就有三個(gè)one-hot的特征,每一個(gè)都通過(guò)乘以矩陣 轉(zhuǎn)化為embedding,如下圖所示:
或者也可以把他們組合成multi-hot的向量,然后用一個(gè)統(tǒng)一的大 來(lái)映射。這是典型的科研場(chǎng)景下的問(wèn)題描述形式。
工業(yè)界的處理方式大致符合上面的操作,但和常見學(xué)術(shù)論文有一個(gè)區(qū)別是,并不存在一個(gè)真正的one-hot特征,更不存在從one-hot特征乘以 再映射到向量的過(guò)程。這是大部分同學(xué),或是初學(xué)者最容易不理解的地方。首先,在大型工業(yè)場(chǎng)景下,會(huì)源源不斷出現(xiàn)新的item,新的用戶,新的ID,原先的one-hot和 必須得不斷擴(kuò)充。但是這個(gè)過(guò)程并沒(méi)有什么必要性,在one-hot乘以權(quán)重這個(gè)操作中,實(shí)際上就是取出了 1對(duì)應(yīng)的 的那一列而已,等于0的那些列根本就沒(méi)用。那我們干脆新出現(xiàn)哪個(gè)1,給它分配一個(gè)列向量就好了。這也就是embedding look-up table的操作。所以說(shuō)工業(yè)實(shí)現(xiàn)概念上和one-hot一樣,操作上不一樣。
第二個(gè)區(qū)別是特征高度ID化,一切特征都可以是ID,原來(lái)不是ID的特征也轉(zhuǎn)向ID。由于沒(méi)有one-hot這個(gè)過(guò)程,還需要一個(gè)東西記錄非0出現(xiàn)的位置,這個(gè)位置就可以看作是所有特征的ID。比如城市這個(gè)特征,我們可以把第一個(gè)出現(xiàn)的特征記為cityID=1,第二個(gè)出現(xiàn)的記為cityID=2等等。但是這樣又會(huì)遇到一個(gè)問(wèn)題:目前增長(zhǎng)到哪了是需要記錄的,而且需要在各個(gè)機(jī)器中互相傳遞,否則A機(jī)器上新出現(xiàn)了一個(gè),你定義為第11,但是在B機(jī)器中出現(xiàn)可能是第13個(gè),這就出問(wèn)題了。如果要針對(duì)這個(gè)同步的問(wèn)題做處理,那么又得在機(jī)器之間做通信,比較麻煩。防止這個(gè)問(wèn)題的做法就是對(duì)特征本身做hash,將得到的數(shù)字作為它的ID。只要每臺(tái)機(jī)器用的hash算法一樣,出來(lái)的值就是一樣的。
用hash還有第二個(gè)動(dòng)機(jī),就是其實(shí)我們也不希望ID是無(wú)限增長(zhǎng)的。使用hash之后可以保證所有特征一定都在某個(gè)空間中不會(huì)出現(xiàn)意外。所以有一種做法是,我們給一種特征分配一個(gè)編號(hào),稱為Slot ID,每一個(gè)特征的取值,我們hash后得到一個(gè)ID,稱為FID(feature ID),在一個(gè)n位的二進(jìn)制數(shù)字中,前k位用slot ID的二進(jìn)制表示填充,后面n-k位用FID填充,組成一個(gè)整體數(shù)字,作為這個(gè)feature的最終表示。經(jīng)過(guò)這個(gè)操作,可以保證每一個(gè)特征的取值,都有唯一的取值(如果不考慮碰撞的話)。
hash表示的最大好處是它可以處理(至少是處理,處理的好不好是另一回事)所有類型的特征,只要你是能寫出來(lái)的,就可以用string表示,只要你能用string表示,你就能hash。實(shí)際中完全可以先全部hash跑起來(lái),然后再細(xì)分有些特征需不需要特別處理。
既然是使用hash,那么不可避免的會(huì)遇到碰撞的問(wèn)題。原則上,我們不希望有任何兩個(gè)不一樣的特征被hash到同一個(gè)ID上,所以會(huì)盡量選擇好的算法比如cityhash。但是問(wèn)題也沒(méi)有那么嚴(yán)重,很多特征都有生命周期。像廣告中的item ID,預(yù)算沒(méi)了,不投放了,可以認(rèn)為那個(gè)ID沒(méi)啥用了。可以設(shè)計(jì)遺忘機(jī)制。當(dāng)我算出一個(gè)ID之后,看到記錄上一次算出這個(gè)ID是很早之前了,就可以再次初始化embedding讓一切重新開始。
Embedding壓縮與分解
embedding+DNN是一個(gè)“頭重腳輕”的方案,幾乎所有的內(nèi)存消耗都?jí)涸趀mbedding的存儲(chǔ)上面。如果是按照one-hot那樣,內(nèi)存會(huì)隨著時(shí)間線性增加,這是一個(gè)很大的消耗。
如果按照上面說(shuō)的hash的方法,可以避免內(nèi)存線性增大,總的內(nèi)存消耗和我們開的空間大小有關(guān)。但問(wèn)題是既然是hash,就一定有碰撞。如果空間設(shè)的很大,碰撞概率低,效果好,但內(nèi)存大;反之若空間開的很小,那么碰撞概率就會(huì)增大,對(duì)效果有不好的影響。有沒(méi)有方法可以做巧妙的權(quán)衡?
這種動(dòng)機(jī)在近兩年引領(lǐng)了一波新的風(fēng)潮,一種直接的思路是把一個(gè)大的ID,拆解成數(shù)個(gè)小的ID的組合[1]。然后最終的embedding也是在這兩個(gè)小ID的embedding上做某種操作得到的。我們會(huì)想到可能有兩個(gè)大ID在某一個(gè)小ID中出現(xiàn)了碰撞,但是只要最終的表示中,另一個(gè)小ID不同,我們就認(rèn)為最終的表示是不同的。
首先介紹的是一個(gè)Facebook發(fā)表在KDD2020上的方案,把一個(gè)大的ID拆解成商+余數(shù)的組合。比如一種特征的ID取值介于1-1000000之間。完全保存這種特征的embedding需要 的空間,這里 代表平均的特征維度。我可以找一個(gè)除數(shù) ,然后把特征ID唯一的表示為原始ID除以 后得到的商和余數(shù)。 這里就選1000,商會(huì)有大約1000種取值,而余數(shù)也是有大約1000種。然后原始特征的embedding,現(xiàn)在表示為商和余數(shù)的兩個(gè)embedding的組合(可以是拼接,也可以是加起來(lái)或者element-wise乘)。由于商和余數(shù)各自只有1000種選擇,現(xiàn)在整個(gè)空間壓縮到了2000,相比于1000000,有500倍的壓縮!這個(gè)壓縮是一個(gè)平方級(jí)的減小。
當(dāng)然,我們會(huì)有疑問(wèn),2001和2002這兩個(gè)ID,算下來(lái)商是一樣的,那不就意味著有一半的embedding都是一樣的嗎?是的,所以這個(gè)方法一定會(huì)帶來(lái)性能折損,實(shí)驗(yàn)部分也能體現(xiàn)的出來(lái)。但是這個(gè)方法在實(shí)驗(yàn)中比直接hash到2000要好。
沿著上面的思路,還可以有更加通用的方案:分成固定的若干個(gè)互補(bǔ)分區(qū)。比如上面的商和余數(shù)的方案,還可以對(duì)余數(shù)再取 的商和余數(shù),一直往下。也可以拿出這個(gè)ID范圍內(nèi)的所有質(zhì)數(shù),把能整除某個(gè)質(zhì)數(shù)的放一起等等。綜合下來(lái),對(duì)原始復(fù)雜度是指數(shù)級(jí)的衰減。
類似的方法也有今年CIKM的一個(gè)方法[2],通過(guò)控制二進(jìn)制表示來(lái)壓縮空間,但這些方法有一個(gè)沒(méi)有解決的問(wèn)題是分配到多個(gè)分區(qū)的過(guò)程沒(méi)有什么邏輯依據(jù),缺乏“語(yǔ)義”。2001和2002因?yàn)樯桃粯?#xff0c;所以前半段embedding都是一樣的,但是它們也有可能是兩個(gè)完全沒(méi)有聯(lián)系的特征,那有一半embedding都一樣就不太合理了。根據(jù)我們?cè)贔M那幾講中提到的觀點(diǎn),embedding還是要承載一些語(yǔ)義信息的。期望中應(yīng)該是類型上更接近的特征,共享的概率越大,反之亦然。現(xiàn)在還沒(méi)有看到有工作涉及這方面,看到這里的讀者可以趕緊動(dòng)手?jǐn)€paper了!
其實(shí)embedding壓縮還涉及一個(gè)方向是Network Architecture Search(NAS),后面在熱點(diǎn)篇里面專門做介紹,這里簡(jiǎn)單提一下也是可以給各個(gè)不同的特征分配不同的權(quán)重。
總結(jié)一下,無(wú)論什么樣的壓縮方案,肯定都會(huì)對(duì)效果有影響,畢竟天下沒(méi)有免費(fèi)的午餐。但是選用什么樣的方案就是根據(jù)環(huán)境的。在業(yè)務(wù)還沒(méi)完全起來(lái)的時(shí)候,用一些embedding壓縮的方案是性價(jià)比較高的選擇。
Deep Hash Embedding(DHE[3])
回到最開始的問(wèn)題,我們說(shuō)embedding占用的空間那么大,其本質(zhì)原因在什么地方呢?在于我們把原始特征表示為one-hot的,不是0就是1的表示方式當(dāng)然是需要很大維度才能表示的。如果我們有一個(gè)非學(xué)習(xí)性的方法一上來(lái)就把特征ID表示成浮點(diǎn)數(shù)會(huì)怎么樣?如果能表示成一段浮點(diǎn)數(shù)的向量會(huì)怎么樣?
如果找到了這樣的方法,后面的事情是水到渠成的:可以就地接一個(gè)MLP,把前面的特征表示變換到一般要用的embedding,再接下面的DNN,這樣空間的占用一下就下來(lái)了!如下圖所示:
在第一步圖上也強(qiáng)調(diào)了是non-learnable的,對(duì)應(yīng)左邊的look-up table需要占 的空間,而右邊的MLP就少非常多了,這樣就大大減小了存儲(chǔ)消耗。那么怎么把一個(gè)原始的ID變成浮點(diǎn)向量呢?首先可以考慮變成整型的向量,我們可以聯(lián)想到,不同的hash方式可以得到不同的int,同一種hash加不同的種子也可以做到這一點(diǎn)。
當(dāng)使用各種hash方法/種子拼出一個(gè)高維的整數(shù)向量后,再做歸一化+高斯化就可以得到所需要的浮點(diǎn)數(shù)向量,把這個(gè)向量送入下面的“decode” MLP即可。
這個(gè)方案的另外一個(gè)考慮是基于沖突,上面講的hash方法其實(shí)都是存在沖突可能性的。即使是上面商+余數(shù)的方案,表面上看最終的embedding不一樣,但是局部的沖突可能很大。而使用了許許多多hash方法的結(jié)果后,再經(jīng)過(guò)網(wǎng)絡(luò)變換,最終到了embedding表示這里,沖突的概率就很小了。有一個(gè)缺點(diǎn)是,由于embedding也是網(wǎng)絡(luò)生成的了,一點(diǎn)參數(shù)的變化會(huì)引起全局特征漂移,這樣對(duì)記憶性的原則有影響,因此論文中的實(shí)驗(yàn)還是沒(méi)有打過(guò)完全不沖突的look-up table。
這個(gè)文章很有意思,它是完全根據(jù)實(shí)際應(yīng)用場(chǎng)景遇到的問(wèn)題提出的方案。如果這條路真的能走得深而且work的話可能會(huì)是一個(gè)很有前途的方向,還有不少可以做的事情。
下期預(yù)告
推薦系統(tǒng)精排之鋒(12):DIN+DIEN,機(jī)器學(xué)習(xí)唯一指定漲點(diǎn)技Attention
往期回顧
召回 粗排 精排,如何各司其職?
拍不完的腦袋:推薦系統(tǒng)打壓保送重排策略
簡(jiǎn)單復(fù)讀機(jī)LR如何成為推薦系統(tǒng)精排之鋒?
召回粗排精排-級(jí)聯(lián)漏斗(上)
召回粗排精排-級(jí)聯(lián)漏斗(下)
推薦系統(tǒng)精排:看阿里媽媽再試線性模型
推薦精排之鋒:FM的一小步,泛化的一大步
推薦中使用FNN/PNN/ONN/NFM優(yōu)化特征交叉
聊聊推薦系統(tǒng)的高階特征交叉問(wèn)題
真正的高階特征交叉:xDeepFM與DCN-V2
GBDT是如何成為推薦系統(tǒng)頂級(jí)工具人的?
DNN與推薦兩大門派,一念神魔,功不唐捐
后臺(tái)回復(fù)關(guān)鍵詞【入群】
加入賣萌屋NLP/IR/Rec與求職討論群
后臺(tái)回復(fù)關(guān)鍵詞【頂會(huì)】
獲取ACL、CIKM等各大頂會(huì)論文集!
?
[1]Compositional Embeddings Using Complementary Partitions for Memory-Efficient Recommendation Systems,KDD,2020 https://arxiv.org/pdf/1909.02107.pdf
[2]Binary Code based Hash Embedding for Web-scale Applications,CIKM,2021 https://dl.acm.org/doi/pdf/10.1145/3459637.3482065
[3]Learning to Embed Categorical Features without Embedding Tables for Recommendation,KDD,2021 https://arxiv.org/pdf/2010.10784.pdf
總結(jié)
以上是生活随笔為你收集整理的再论推荐特征与embedding生成的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: NLP预训练之路——从word2vec,
- 下一篇: 别再搞纯文本了!多模文档理解更被时代需要