隨着深度學習在圖像、語言、廣告點擊率預估等各個領域不斷髮展,不少團隊開始探索深度學習技術在業務層面的實踐與應用。而在廣告CTR預估方面,新模型也是層出不窮: Wide and Deep[1]、DeepCross Network[2]、DeepFM[3]、xDeepFM[4],美團不少篇深度學習博客也作了詳細的介紹。可是,當離線模型須要上線時,就會碰見各類新的問題: 離線模型性能可否知足線上要求、模型預估如何鑲入到原有工程系統等等。只有準確的理解深度學習框架,才能更好地將深度學習部署到線上,從而兼容原工程系統、知足線上性能要求。算法
本文首先介紹下美團平臺用戶增加組業務場景及離線訓練流程,而後主要介紹咱們使用TensorFlow Serving部署WDL模型到線上的全過程,以及如何優化線上服務性能,但願能對你們有所啓發。後端
在廣告精排的場景下,針對每一個用戶,最多會有幾百個廣告召回,模型根據用戶特徵與每個廣告相關特徵,分別預估該用戶對每條廣告的點擊率,從而進行排序。因爲廣告交易平臺(AdExchange)對於DSP的超時時間限制,咱們的排序模塊平均響應時間必須控制在10ms之內,同時美團DSP須要根據預估點擊率參與實時競價,所以對模型預估性能要求比較高。性能優化
離線數據方面,咱們使用Spark生成TensorFlow[5]原生態的數據格式tfrecord,加快數據讀取。微信
模型方面,使用經典的Wide and Deep模型,特徵包括用戶維度特徵、場景維度特徵、商品維度特徵。Wide 部分有 80多特徵輸入,Deep部分有60多特徵輸入,通過Embedding輸入層大約有600維度,以後是3層256等寬全鏈接,模型參數一共有35萬參數,對應導出模型文件大小大約11M。網絡
離線訓練方面,使用TensorFlow同步 + Backup Workers[6]的分佈式框架,解決異步更新延遲和同步更新性能慢的問題。多線程
在分佈式ps參數分配方面,使用GreedyLoadBalancing方式,根據預估參數大小分配參數,取代Round Robin取模分配的方法,可使各個PS負載均衡。架構
計算設備方面,咱們發現只使用CPU而不使用GPU,訓練速度會更快,這主要是由於儘管GPU計算上性能可能會提高,可是卻增長了CPU與GPU之間數據傳輸的開銷,當模型計算並不太複雜時,使用CPU效果會更好些。負載均衡
同時咱們使用了Estimator高級API,將數據讀取、分佈式訓練、模型驗證、TensorFlow Serving模型導出進行封裝。
使用Estimator的主要好處在於:框架
TensorFlow Serving是一個用於機器學習模型Serving的高性能開源庫,它能夠將訓練好的機器學習模型部署到線上,使用gRPC做爲接口接受外部調用。TensorFlow Serving支持模型熱更新與自動模型版本管理,具備很是靈活的特色。機器學習
下圖爲TensorFlow Serving整個框架圖。Client端會不斷給Manager發送請求,Manager會根據版本管理策略管理模型更新,並將最新的模型計算結果返回給Client端。
TensorFlow Serving架構,圖片來源於TensorFlow Serving官方文檔
美團內部由數據平臺提供專門TensorFlow Serving經過YARN分佈式地跑在集羣上,其週期性地掃描HDFS路徑來檢查模型版本,並自動進行更新。固然,每一臺本地機器均可以安裝TensorFlow Serving進行試驗。
在咱們站外廣告精排的場景下,每來一位用戶時,線上請求端會把該用戶和召回所得100個廣告的全部信息,轉化成模型輸入格式,而後做爲一個Batch發送給TensorFlow Serving,TensorFlow Serving接受請求後,通過計算獲得CTR預估值,再返回給請求端。
部署TensorFlow Serving的初版時,QPS大約200時,打包請求須要5ms,網絡開銷須要固定3ms左右,僅模型預估計算須要10ms,整個過程的TP50線大約18ms,性能徹底達不到線上的要求。接下來詳細介紹下咱們性能優化的過程。
線上請求端優化主要是對一百個廣告進行並行處理,咱們使用OpenMP多線程並行處理數據,將請求時間性能從5ms下降到2ms左右。
#pragma omp parallel for for (int i = 0; i < request->ad_feat_size(); ++i) { tensorflow::Example example; data_processing(); }
在沒有進行優化以前,模型的輸入是未進行處理的原格式數據,例如,渠道特徵取值可能爲:'渠道1'、'渠道2' 這樣的string格式,而後在模型裏面作One Hot處理。
最初模型使用了大量的高階tf.feature_column對數據進行處理, 轉爲One Hot和embedding格式。 使用tf.feature_column的好處是,輸入時不須要對原數據作任何處理,能夠經過feature_column API在模型內部對特徵作不少經常使用的處理,例如:tf.feature_column.bucketized_column能夠作分桶,tf.feature_column.crossed_column能夠對類別特徵作特徵交叉。但特徵處理的壓力就放在了模型裏。
爲了進一步分析使用feature_column的耗時,咱們使用tf.profiler工具,對整個離線訓練流程耗時作了分析。在Estimator框架下使用tf.profiler是很是方便的,只需加一行代碼便可。
with tf.contrib.tfprof.ProfileContext(job_dir + ‘/tmp/train_dir’) as pctx: estimator = tf.estimator.Estimator(model_fn=get_model_fn(job_dir), config=run_config, params=hparams)
下圖爲使用tf.profiler,網絡在向前傳播的耗時分佈圖,能夠看出使用feature_column API的特徵處理耗費了很大時間。
優化前profiler記錄, 前向傳播的耗時佔總訓練時間55.78%,主要耗費在feature_column OPS對原始數據的預處理
爲了解決特徵在模型內作處理耗時大的問題,咱們在處理離線數據時,把全部string格式的原生數據,提早作好One Hot的映射,而且把映射關係落到本地feature_index文件,進而供線上線下使用。這樣就至關於把本來須要在模型端計算One Hot的過程省略掉,替代爲使用詞典作O(1)的查找。同時在構建模型時候,使用更多性能有保證的低階API替代feature_column這樣的高階API。下圖爲性能優化後,前向傳播耗時在整個訓練流程的佔比。能夠看出,前向傳播的耗時佔比下降了不少。
優化後profiler記錄,前向傳播耗時佔總訓練時間39.53%
TensorFlow採用有向數據流圖來表達整個計算過程,其中Node表明着操做(OPS),數據經過Tensor的方式來表達,不一樣Node間有向的邊表示數據流動方向,整個圖就是有向的數據流圖。
XLA(Accelerated Linear Algebra)是一種專門對TensorFlow中線性代數運算進行優化的編譯器,當打開JIT(Just In Time)編譯模式時,便會使用XLA編譯器。整個編譯流程以下圖所示:
TensorFlow計算流程
首先TensorFlow整個計算圖會通過優化,圖中冗餘的計算會被剪掉。HLO(High Level Optimizer)會將優化後的計算圖 生成HLO的原始操做,XLA編譯器會對HLO的原始操做進行一些優化,最後交給LLVM IR根據不一樣的後端設備,生成不一樣的機器代碼。
JIT的使用,有助於LLVM IR根據 HLO原始操做生成 更高效的機器碼;同時,對於多個可融合的HLO原始操做,會融合成一個更加高效的計算操做。可是JIT的編譯是在代碼運行時進行編譯,這也意味着運行代碼時會有一部分額外的編譯開銷。
網絡結構、Batch Size對JIT性能影響[7]
上圖顯示爲不一樣網絡結構,不一樣Batch Size下使用JIT編譯後與不使用JIT編譯的耗時之比。能夠看出,較大的Batch Size性能優化比較明顯,層數與神經元個數變化對JIT編譯優化影響不大。
在實際的應用中,具體效果會因網絡結構、模型參數、硬件設備等緣由而異。
通過上述一系列的性能優化,模型預估時間從開始的10ms下降到1.1ms,請求時間從5ms降到2ms。整個流程從打包發送請求到收到結果,耗時大約6ms。
模型計算時間相關參數:QPS:1308,50line:1.1ms,999line:3.0ms。下面四個圖分別爲:耗時分佈圖顯示大部分耗時控制在1ms內;請求次數顯示每分鐘請求大約8萬次,摺合QPS爲1308;平均耗時時間爲1.1ms;成功率爲100%
經過監控發現,當模型進行更新時,會有大量的請求超時。以下圖所示,每次更新都會致使有大量請求超時,對系統的影響較大。經過TensorFlow Serving日誌和代碼分析發現,超時問題主要源於兩個方面,一方面,更新、加載模型和處理TensorFlow Serving請求的線程共用一個線程池,致使切換模型時候沒法處理請求;另外一方面,模型加載後,計算圖採用Lazy Initialization方式,致使第一次請求須要等待計算圖初始化。
模型切換致使請求超時
問題一主要是由於加載和卸載模型線程池配置問題,在源代碼中:
uint32 num_load_threads = 0; uint32 num_unload_threads = 0;
這兩個參數默認爲 0,表示不使用獨立線程池,和Serving Manager在同一個線程中運行。修改爲1即可以有效解決此問題。
模型加載的核心操做爲RestoreOp,包括從存儲讀取模型文件、分配內存、查找對應的Variable等操做,其經過調用Session的run方法來執行。而默認狀況下,一個進程內的全部Session的運算均使用同一個線程池。因此致使模型加載過程當中加載操做和處理Serving請求的運算使用同一線程池,致使Serving請求延遲。解決方法是經過配置文件設置,可構造多個線程池,模型加載時指定使用獨立的線程池執行加載操做。
對於問題二,模型首次運行耗時較長的問題,採用在模型加載完成後提早進行一次Warm Up運算的方法,能夠避免在請求時運算影響請求性能。這裏使用Warm Up的方法是,根據導出模型時設置的Signature,拿出輸入數據的類型,而後構造出假的輸入數據來初始化模型。
經過上述兩方面的優化,模型切換後請求延遲問題獲得很好的解決。以下圖所示,切換模型時毛刺由原來的84ms下降爲4ms左右。
優化後模型切換後,毛刺下降
本文主要介紹了用戶增加組基於Tensorflow Serving在深度學習線上預估的探索,對性能問題的定位、分析、解決;最終實現了高性能、穩定性強、支持各類深度學習模型的在線服務。
在具有完整的離線訓練與在線預估框架基礎以後,咱們將會加快策略的快速迭代。在模型方面,咱們能夠快速嘗試新的模型,嘗試將強化學習與競價結合;在性能方面,結合工程要求,咱們會對TensorFlow的圖優化、底層操做算子、操做融合等方面作進一步的探索;除此以外,TensorFlow Serving的預估功能能夠用於模型分析,谷歌也基於此推出What-If-Tools來幫助模型開發者對模型深刻分析。最後,咱們也會結合模型分析,對數據、特徵再作從新的審視。
[1] Cheng, H. T., Koc, L., Harmsen, J., Shaked, T., Chandra, T., Aradhye, H., ... & Anil, R. (2016, September). Wide & deep learning for recommender systems. In Proceedings of the 1st Workshop on Deep Learning for Recommender Systems (pp. 7-10). ACM.
[2] Wang, R., Fu, B., Fu, G., & Wang, M. (2017, August). Deep & cross network for ad click predictions. In Proceedings of the ADKDD'17 (p. 12). ACM.
[3] Guo, H., Tang, R., Ye, Y., Li, Z., & He, X. (2017). Deepfm: a factorization-machine based neural network for ctr prediction. arXiv preprint arXiv:1703.04247.
[4] Lian, J., Zhou, X., Zhang, F., Chen, Z., Xie, X., & Sun, G. (2018). xDeepFM: Combining Explicit and Implicit Feature Interactions for Recommender Systems. arXiv preprint arXiv:1803.05170.
[5] Abadi, M., Barham, P., Chen, J., Chen, Z., Davis, A., Dean, J., ... & Kudlur, M. (2016, November). TensorFlow: a system for large-scale machine learning. In OSDI (Vol. 16, pp. 265-283).
[6] Goyal, P., Dollár, P., Girshick, R., Noordhuis, P., Wesolowski, L., Kyrola, A., ... & He, K. (2017). Accurate, large minibatch SGD: training imagenet in 1 hour. arXiv preprint arXiv:1706.02677.
[7] Neill, R., Drebes, A., Pop, A. (2018). Performance Analysis of Just-in-Time Compilation for Training TensorFlow Multi-Layer Perceptrons.
仲達,2017年畢業於美國羅徹斯特大學數據科學專業,後在加州灣區Stentor Technology Company工做,2018年加入美團,主要負責用戶增加組深度學習、強化學習落地業務場景工做。
鴻傑,2015年加入美團點評。美團平臺與酒旅事業羣用戶增加組算法負責人,曾就任於阿里,主要致力於經過機器學習提高美團點評平臺的活躍用戶數,做爲技術負責人,主導了美團DSP廣告投放、站內拉新等項目的算法工做,有效提高營銷效率,下降營銷成本。
廷穩,2015年加入美團點評。在美團點評離線計算方向前後從事YARN資源調度及GPU計算平臺建設工做。
美團DSP是美團在線數字營銷的核心業務方向,加入咱們,你能夠親身參與打造和優化一個可觸達億級用戶的營銷平臺,並引導他們的生活娛樂決策。同時,你也會直面如何精準,高效,低成本營銷的挑戰,也有機會接觸到計算廣告領域前沿的AI算法體系和大數據解決方案。你會和美團營銷技術團隊一塊兒推進創建流量運營生態,支持酒旅、外賣、到店、打車、金融等業務繼續快速的發展。咱們誠邀有激情、有想法、有經驗、有能力的你,和咱們一塊兒並肩奮鬥!參與美團點評站外廣告投放體系的實現,基於大規模用戶行爲數據,優化在線廣告算法,提高DAU,ROI, 提升在線廣告的相關度、投放效果。歡迎郵件wuhongjie#meituan.com諮詢。
發現文章有錯誤、對內容有疑問,均可以關注美團技術團隊微信公衆號(meituantech),在後臺給咱們留言。咱們每週會挑選出一位熱心小夥伴,送上一份精美的小禮品。快來掃碼關注咱們吧!