開發與維運

愛奇藝視頻推薦領域的ANN實踐

本文內容來自於
由阿里雲開發者社區 x 達摩院領航舉辦的3月20日向量檢索專場Meetup講師演講內容

講師介紹
張吉
愛奇藝深度學習雲研發工程師

一、背景介紹

(一)推薦系統

圖片 1.png

推薦系統是現在互聯網發展一個比較重要的基石,上圖左邊是愛奇藝手機端的應用,右邊是 PC 端的 Web 頁面。可以看到,很多劇都是通過推薦而來的,隨著數據量的發展,用戶的搜索習慣也改變了。原來用戶有目的性搜索,如今更希望系統進行主動的智能推薦,提升用戶體驗,目前推薦系統在愛奇藝裡佔據重要地位。

(二)推薦系統框架

圖片 2.png

愛奇藝推薦系統框架分為三段,呈現漏斗型的結構。所有候選集即愛奇藝視頻庫,先過濾出一些當下熱劇,然後建一個索引。通過召回階段,將數據從百萬量級篩選到千量級的規模,接著經過排序階段,排出十量級的劇最後推送給用戶。

本文主要分享的是基於 ANN 做的召回階段,對於召回的要求是速度快和數據量大。

二、工程實踐

(一)算法選型

圖片 3.png

算法選型選的是 YouTubeNet,做的是 User-Item 的召回,選取它是因為模型召回效果較好。它下邊是一些用戶的向量,通過拼接用戶向量形成分類網絡,最後分類出來的這一層對應愛奇藝的視頻,最終形成 User-Item 的推薦,在訓練階段就是一個千百萬級別的分類器。

最後的 Serving 階段比較有挑戰,因為召回階段難以在線計算整個神經網絡的推理,因此在Serving 階段用 ANN 的方式,然後近似地把全連接之後的數據取 Topk 的過程,用 ANN 做近似。
我們把網絡倒數第二層看做用戶向量,分類裡面矩陣的權重看做視頻向量,

圖片 4.png

普通召回

把網絡倒數第二層看做用戶向量,分類裡面矩陣的權重看做視頻向量,在計算的時候,假如是一個5維的用戶向量,然後它跟視頻向量做全連接乘法,最後得到的視頻向量比如有100萬條,則得出100萬的視頻得分,代表的是100萬個視頻。這時候再取一個 Topk,最後得到的是希望召回的視頻ID,這就是通常情況下召回的推理過程。

*圖片 5.png
ANN 方式召回

用 ANN 的方式就比較巧妙,因為向量檢索可以選擇用內積的形式來做距離度量方式,矩陣層其實也是內積,這兩個近似等價。

也就是說 YouTubeNe t在 Serving 的時候,把全連接全乘完之後的結果再取 Topk 的過程,轉化成了一個用內積形式做度量,直接做 ANN 近似召回的過程,所以在 Serving 階段就使得千百萬級別的全連接的效率是得到了一定保證。

(二)Serving結構

圖片 6.png

如上圖所示,Serving 結構模型分為三段,第一段是 DNN 用戶銷量的在線推理,第二部分通過用戶向量做 ANN 的召回,然後推送給後邊排序的是每一個視頻的 ID 還有對應的得分。

圖片 7.png

我們在做的過程中,面臨以下三個問題:
1) 整體模型如何更新
整個模型分為用戶向量生成的 DNN 推理部分,還有 ANN 索引庫部分,這兩個其實是從同一個模型裡拆出來的,因此在真正 Serving,包括更新的時候,一定要保證 DNN 和 ANN 的版本一定要是同一個模型拆出來的,否則在真正計算的時候,它們不在一個向量空間裡,算出來就都是錯誤的數據。
2)Serving 效率
召回對整體性能有一定要求,如果請求端自己先請求 DNN 然後再返回,接著再去請求一個獨立的 ANN 服務,中間存在一些網絡開銷。
3)接口與 TF Serving 一致
我們對外提供的是 TF Serving 接口,不改這個接口的話對整體的技術棧沒有影響,上線效率高,不需要額外做接口方面的開發。

基於這三點,我們設計了兩個方案。

方案一:

圖片 8.png

第一個方案把整個 ANN 的這部分,相當於對前面的請求方給它屏蔽掉。用 DNN 之後,直接拿到用戶向量去 ANN 做向量的檢索。DNN 部分選用 Tensorflow,ANN 部分選用 Milvus,Milvus 的優點有文檔豐富、封裝完善和開箱即用。

圖片 9.png

上圖為方案一整體結構,Milvus 有 C++ 的 SDK,在用的時候,推薦量大概在百萬到千萬級別,單個容器下面容量可以滿足,因此先都在單個容器裡面。

容器裡包含了兩個進程,一個是 TF Serving,負責 DNN 的編碼,裡邊有 Milvus 的一個裝置,然後 Milvus 請求同一個容器內部的 ANN 服務。對於外部來說,整體的接口還是 TF Serving,並沒有改變接口。容器內部減少了一些網絡上的開銷,整體上性能較為良好。

  • Tensorflow Serving 改造

Tensorflow Serving 就是一個 Tensorflow Runtime 的封裝,主要是做 RPC 的請求處理和模型管理方面的工作。

圖片 10.png

紅框中是整個 Tensorflow Serving 在運行推理時,最核心的函數叫 RunPredict,裡邊包了一層 Tensorflow Runtime,然後把對應的 Return proto 進行解析,最後再統一回傳給請求方。

圖片 11.png

我們在這個函數裡邊加了一層 Milvus SDK RPC,通過 Tensorflow Runtime 拿出來的用戶向量,直接在這邊就封裝成 Milvus 的請求,然後去請求本地 ANN 服務。然後再返回 Proto 時候,會返回對應的 ID 和得分。

  • 改造步驟總結如下:

1)檢查簽名
2)解析 proto
3)TF Runtime 計算
4)解封 proto

  • 模型升級

圖片 12.png

如上圖所示,2個Version1 是現在正在服務的一些模型。由於我們這是一個只讀的場景,相當於在線服務時加載的是已經訓練好的索引,Tensorflow 有這個模型動態加載的能力,但是 Milvus 目前沒有,所以通過整體進行 AB 切換的方式來升級。

升級 Version2 的時候,會先啟動一個 Version2,當 Version2 就緒時,會把 Version1 摘掉,通過 CONSUL 保證服務的發現性。

這裡存在一個缺點,在請求的時候,Version1 和 Version2 會存在一些混亂的情況,混亂程度取決於升級的時間,如果升級得快,可能抖動就不會很大,如果升級得慢就會受到一些影響。

方案優點:開發速度快
方案缺點:不夠靈活、模型版本難以管理。

  • Milvus 場景&配置

圖片 13.png

對於Milvus我們做了一些簡單的配置:

1)只讀場景
2)數據在百萬級別
3)索引文件可共享

由於我們是一個只讀場景,所以希望在線 Serving 時可以直接加載離線訓練好的 Milvus 索引,相當於在真正建索引的時候,是有一個專門創建索引的 Milvus 容器不斷地去創建索引,然後把這些 Milvus 所創建的索引都匯到對應的網絡存儲上,在 Serving 的時候只需要拉下來,然後做加載就可以了。

  • TF serving 與 Milvus 結合

圖片 14.png

TF serving 靜態編譯 GRPC,Protobuf
Milvus 靜態編譯 GRPC,Protobuf

在做TF Serving 和 Milvus 結合的時候,因為這兩者都是用到了 GRPC,而且都是靜態編譯,如果放到同一個進程裡面,由於兩者的 GRPC 版本不一樣,會導致一些問題,比如數據格式轉換等。
因此我們將 GRPC 的版本統一為 Tensorflow Serving 的1.19.1版本,之後就可以在 Tensorflow 版本里面調用 Milvus 的服務。

  • 業務需求

結合方案一的優缺點,後續產生了如下業務需求:

需求一:召回後重排序
許多算法人員反饋,召回之後如果結合一些業務指標,對召回再進行一次重排序,效果會有所提升。而且對於召回而言,在很多召回引擎中,召回 Top3 版跟 Top5 版所需時間相差無幾。因此可以召回 Top5 版,然後再進行一次重排序,這樣效果會提升很多。

需求二:召回模型帶版本
召回模型帶版本的話,後續可以對模型版本進行管理。

需求三:前置過濾
在愛奇藝視頻中,有的視頻是用戶已經觀看過的,因此在召回時希望過濾掉這一部分視頻,從而不會給用戶進行重複推薦,提升用戶體驗。

結合以上三個需求,我們做了方案二。

方案二

圖片 15.png

如上圖所示,在原來的基礎上,除了 DNN 部分是原生的 Tensorflow 之外,我們把 ANN 也放到了 Tensorflow 的 Runtime 中。

如果都在計算圖中的話,剩下的一些其他邏輯,例如重排序,對於算法人員而言整體就比較簡單了。除了一些業務指標之外,也可以用簡單的樹模型根據用戶的 Feature 做一次再重排序。而且如果都集中到 Tensorflow 裡邊,對外接口也是一致的,對於整個技術棧,貼合度也會更高一些。

  • 方案二技術選型

基於以上方案,我們需要把 ANN 的這個功能做成一個OP,因此選取了 Hnswlib,它有三個優點:
1)性能好
2)線程模型簡單
3)Head only

  • 方案二結構

圖片 16.png

方案二使用 HNSW OP 創建計算圖,升級部署與純 TF Serving 一致。
RunPredict有的邏輯都放在了 Tensorflow Runtime 中,這也符合 Tensorflow Serving 設計的初衷,因為它更多的是處理 RPC 請求與模型管理的工作。

優缺點
**優點:可支持更靈活的邏輯,模型版本易於管理
缺點:ANN OP需要開發**

  • 模型升級

圖片 17.png

整體的模型升級部分與 Tensorflow 一樣,是熱升級的模式。

比如這個 Tensorflow 有兩個版本 Version1 跟 Version2,然後大家都在請求 Version2。這個時候如果觸發一次升級,容器會分先後,大家都會去加載 Version3,整體都加載完之後,就可以都切到 Version3了。通過熱升級的方式,整個模型易於管理。

  • 整體 Serving 工作流

圖片 18.png

作為一個基礎的 AI 平臺,為用戶提供的服務不止是 Serving,也會提供訓練與模型管理方面的工作,整體 Serving 的工作流主要分為4個部分。

首先用戶上傳訓練好的模型,接著觸發創建索引的任務,這個任務基於方案一或方案二會產生不同的索引。如果是 Milvus 則會創建 Milvus 的索引,如果是定製的 OP,會把這個圖轉換成HNSW OP 的圖,然後把創建好的索引或轉換好的圖上傳到網絡存儲上。

在真正 Serving 時,有一個全局唯一的 Version,通過 Version 指定網絡存儲下載對應的模型/索引,下載完之後就可以進行在線 Serving。

HNSW OP 性能測試

圖片 19.png

HNSW OP 性能測試(純 ANN)

圖片 20.png

如果是對 YouTubeNet 做 Serving,把前面的 DNN 去掉,就變成一個純召回服務。基於這種情況,我們去測了 sift 模型,測下來準確率為95.35%。

上圖是單次請求的在線 Serving 數據,併發數代表同時請求的 euclidean 數量,Wait time 代表單個請求的時間間隔。可以看到,併發度20與40的測試結果裡,除了 QPS 和 CPU 利用率翻倍以外,延遲分位點等數據大致相同,Tensorflow 對併發擴展處理優秀。

HNSW OP 性能測試(YoutubeNet)

圖片 23.png
圖片 24.png


“ AI 檢索技術博客” 由阿里巴巴達摩院系統 AI 實驗室創立,
掃碼關注 “ AI 檢索技術博客” 公眾號,
獲取更多技術乾貨文章、AI 檢索領域 Meetup 動態。

qrcode_for_gh_e1b0e5dea42d_430.jpg

Leave a Reply

Your email address will not be published. Required fields are marked *