圖解廣告及推薦系統(tǒng)架構(gòu)流程
廣告和推薦系統(tǒng)是機(jī)器學(xué)習(xí)是最成熟的應(yīng)用領(lǐng)域。那么廣告和推薦系統(tǒng)是怎么在線上部署機(jī)器學(xué)習(xí)模型的呢?
1. 預(yù)測函數(shù)上線
剛剛學(xué)習(xí)機(jī)器學(xué)習(xí)時候,我認(rèn)為廣告和推薦系統(tǒng)過程如下圖所示:
- 線下部分,從用戶和廣告(物品)屬性抽取用戶和物品特征,將抽取的特征合并進(jìn)日志生成訓(xùn)練數(shù)據(jù),訓(xùn)練機(jī)器學(xué)習(xí)模型;
- 線上部分,來了一個請求,從用戶和廣告(物品)屬性抽取請求中的用戶和物品的特征,將這些特征合并請求生成預(yù)測實例,用線上模型得到預(yù)測結(jié)果。
但是這個架構(gòu)有兩個問題:
(1) 從用戶和廣告(物品)屬性抽取特征的程序有線上線下兩套,這兩套程序必須保持完全一致。但由于調(diào)參的原因,特征抽取是機(jī)器學(xué)習(xí)系統(tǒng)中最經(jīng)常發(fā)生變化的模塊。經(jīng)常變化的模塊需要保持一致,這很困難。
那么我們能不能強(qiáng)行地用一套程序呢?比如,我們把特征抽取和特征處理模塊寫成 .so 文件。這樣也有問題:線下要求快速變化以方便工程師調(diào)特征,可能會使用一些訓(xùn)練框架(比如 Spark);
線上要求程序快速實時,要求工程師編碼嚴(yán)謹(jǐn)。寫成嚴(yán)謹(jǐn)?shù)?.so 文件,能夠保證線上的需求,但無法快速變化,也不能在 Spark 上使用。
(2) 線上特征抽取要求非??焖?,特別在線上吞吐量很大的情況。但有些重度特征不可能在短時間內(nèi)抽取出來,比如廣告的歷史點(diǎn)擊率(生成這個特征需要遍歷一段時間的點(diǎn)擊日志)。
在讀書期間,這兩個問題困擾了我很久, 直到我知道了神器 Redis。Redis 是一個開源內(nèi)存數(shù)據(jù)庫,支持集群模式、持久化和 Key-Value 數(shù)據(jù)結(jié)構(gòu)。
在使用時,我們可以將 Redis 看成一個巨大的哈希表。Redis 在后臺開發(fā)中經(jīng)常用作 cache 服務(wù)器, 后來被工程師們用于廣告和推薦系統(tǒng)中的特征服務(wù)器。
工程師將用戶和廣告(物品)的 ID 作為 Key,將用戶和廣告(物品)的特征作為 Value 存入 Redis,這樣線上程序只需要用戶和廣告(物品)的 ID 就能知道特征。
引入 Redis 之后,廣告和推薦系統(tǒng)過程如下所示:
- 線下部分,從用戶和廣告(物品)屬性抽取用戶和廣告(物品)特征,把抽取的特征合并進(jìn)日志生成訓(xùn)練數(shù)據(jù)用于訓(xùn)練機(jī),并把抽取的特征上載到線上 Redis 服務(wù)器;
- 線上部分,來了一個請求,從 Redis 服務(wù)器取出用戶和廣告(物品)特征,將特征合并進(jìn)請求生成預(yù)測實例,用線上模型得到預(yù)測結(jié)果。
這種架構(gòu)還有一個變種:在線下抽取特征之后不生成訓(xùn)練數(shù)據(jù)而是直接送到 Redis,在線上用 Storm 實時拼接訓(xùn)練數(shù)據(jù)。但我對這個變種的前因后果不太了解,就不展開討論了。
這種架構(gòu)將預(yù)測函數(shù)(也就是訓(xùn)練出來的模型)部署在線上。為了和下面的架構(gòu)區(qū)分開來,我們將這種架構(gòu)稱為預(yù)測函數(shù)上線架構(gòu)。
2. 預(yù)測結(jié)果上線
了解預(yù)測函數(shù)上線架構(gòu)之后,我將之作為廣告和推薦系統(tǒng)線上部署模型的 “正統(tǒng)”。 因此當(dāng)我接觸到另一種架構(gòu)時,我內(nèi)心是拒絕的。
這種架構(gòu)的要點(diǎn)在于把預(yù)測結(jié)果上線,具體過程如下所示:
- 在線上,從用戶和廣告(物品)屬性抽取用戶和物品特征,將抽取的特征合并進(jìn)日志生成訓(xùn)練數(shù)據(jù),訓(xùn)練機(jī)器學(xué)習(xí)模型;將幾乎所有可能的請求合并特征,進(jìn)而生成預(yù)測實例,用模型得到預(yù)測結(jié)果;
- 線上就很簡單了,接入線下傳過來的預(yù)測結(jié)果。這里稍微難理解的是 “窮盡幾乎所有可能的請求”,疑惑那么多可能的請求怎么可能窮盡呢?微博廣告系統(tǒng)(虛構(gòu)的)所有可能的請求貌似很多,但每個用戶只需要匹配若干個廣告就行了。因此微博廣告系統(tǒng)的預(yù)測結(jié)果 “userid,adid1,adid2…,adidn” 上載到線上,一旦線上傳一個 userid 請求展示廣告,線上模塊就按照一定的邏輯返回預(yù)測結(jié)果中這個用戶對應(yīng)的廣告。
這種架構(gòu)是將預(yù)測結(jié)果部署到線上,我們將之稱為預(yù)測結(jié)果上線架構(gòu)。
慢慢地我也開始明白預(yù)測結(jié)果上線的好處了。預(yù)測結(jié)果上線架構(gòu)將機(jī)器學(xué)習(xí)全過程和絕大部分控制邏輯都搬到線下,規(guī)避了線上的各種隱患。這樣不那么厲害的工程師用不那么厲害的機(jī)器也能搞定線上模塊了,畢竟線上模塊只需要實現(xiàn)少量的控制邏輯和展示。這大大降低了建立一個廣告系統(tǒng)或者推薦系統(tǒng)的難度。
我正式工作之后,組里支持運(yùn)營活動的推薦系統(tǒng)采用了預(yù)測結(jié)果上線的架構(gòu)。我發(fā)現(xiàn)有不少時間浪費(fèi)在重跑數(shù)據(jù)上,原因在于有時需要臨時增加或者刪除物品。一旦增加或者刪除物品,預(yù)測結(jié)果上線的推薦系統(tǒng)就需要重新生成預(yù)測數(shù)據(jù)(因此之前跑的數(shù)據(jù)要么沒有要加的物品,要么有要刪的數(shù)據(jù))。
另外一個問題就是預(yù)測結(jié)果上線架構(gòu)有延時性:今天線上展示的是昨天準(zhǔn)備的預(yù)測結(jié)果,今天準(zhǔn)備的預(yù)測結(jié)果要等明天才能展示,這會導(dǎo)致節(jié)奏慢一些。***還有一個問題,預(yù)測結(jié)果上線架構(gòu)只適用于幾乎所有可能的請求能夠窮盡的場景。比如,預(yù)測結(jié)果上線架構(gòu)不適用于搜索廣告系統(tǒng),因為搜索廣告系統(tǒng)不能窮盡所有可能的請求。
3. 總結(jié)
預(yù)測函數(shù)上線架構(gòu)能夠覆蓋預(yù)測結(jié)果上線架構(gòu)的適用場景,但是預(yù)測結(jié)果上線架構(gòu)不能夠覆蓋預(yù)測函數(shù)上線架構(gòu)的適用場景。同時預(yù)測函數(shù)上線架構(gòu)更具靈活性。預(yù)測函數(shù)上線架構(gòu)不愧為部署機(jī)器學(xué)習(xí)模型的 “堂堂正正” 之法。
預(yù)測結(jié)果上線架構(gòu)的好處就是難度比較低。預(yù)測結(jié)果上線架構(gòu)將機(jī)器學(xué)習(xí)全過程和絕大部分控制邏輯,規(guī)避了線上的各種隱患。在機(jī)器、時間和人力等各種條件不充足的情況,預(yù)測結(jié)果上線架構(gòu)不失為一個好的選擇。預(yù)測結(jié)果上線架構(gòu)是 “劍走偏鋒” 的機(jī)器學(xué)習(xí)模型部署之法。兵法有云:以正合以奇勝,選擇哪一種架構(gòu)還是需要仔細(xì)的分析和權(quán)衡。
【本文為51CTO專欄作者“王森豐”的原創(chuàng)稿件,轉(zhuǎn)載請注明出處】