嗶哩嗶哩超大規(guī)模視頻查重算法與工程優(yōu)化實踐
一、需求背景
當前站內(nèi)存在一定比例的UP主投稿重復、低編輯度的低創(chuàng)視頻投稿的情況。低編輯度重復投稿表現(xiàn)為,相同或不同視頻作者對同一視頻素材進行黑邊、裁剪、渣清、模板、錄屏、變形、濾鏡、模糊填充等不影響內(nèi)容實質的編輯后進行反復投稿,如下圖所示。
圖1:同樣的畫面與文字內(nèi)容,套用不同模板。
圖2:模糊填補、視頻水印、播放器錄屏、
黑邊填補多重嵌套。
圖3:直播錄屏+水印+黑邊多重嵌套。
圖4:包含滑動彈幕、super chat和直播間樣式的具有
復雜干擾的直播間錄屏。
圖5:黑邊+白邊。
同質內(nèi)容的重復投稿加重了安全與社區(qū)審核的負擔,影響了流量分配的公平性,同場景同屏或不同刷展現(xiàn)多個相同內(nèi)容稿件降低了用戶的使用體驗,并且增加了其他任務的機器成本。因此,我們需要引入一套能夠支持B站現(xiàn)有超大規(guī)模視頻量級的視頻檢索系統(tǒng)(下稱撞車系統(tǒng)),對所有新增視頻,在所有歷史視頻庫中進行查重匹配,對低編輯度的視頻進行識別,并對撞車視頻向審核人員給出源視頻的提示,通過該系統(tǒng)對原創(chuàng)作者的權益進行保護。
本文將重點圍繞算法架構優(yōu)化(準召、效果提升)和工程性能加速優(yōu)化(降本增效)兩方面進行抽象與闡述,忽略不對機器性能、資源占用起明顯作用的傳統(tǒng)工程架構設計。我們認為體現(xiàn)內(nèi)容原創(chuàng)度的本質在于視頻畫面與音軌,因此本文不對標題、封面、簡介等額外信息作研討。
二、難點挑戰(zhàn)
視頻查重對模型的準確率和召回率同時有著較高要求,準確率低會影響審核對于撞車環(huán)節(jié)的人力時間成本投入,召回率低會增加推薦系統(tǒng)bad case反饋率。以下幾點為影響模型準確率和召回率的重要因素:
1、 缺乏符合B站視頻數(shù)據(jù)分布的,能表征不同編輯程度的圖像距離的預訓練特征,這要求我們使用B站自己的數(shù)據(jù)對查重場景自研一整套特征提取模型的訓練機制;
2、 為了實現(xiàn)快速推理節(jié)約GPU需求,我們將輸入特征提取模型的分辨率設置為224*224,而B站低編輯度視頻中存在大量通過冗余區(qū)域增強來逃避撞車系統(tǒng)的視頻,這使核心區(qū)域占比過小,分辨率過低,嚴重影響判斷精度,這要求我們設計一套預處理算法,刨除冗余區(qū)域,提取可能為編輯源的畫面主體內(nèi)容;
3、 全站底庫視頻量級大,而返回結果需要在720P每秒一幀視頻產(chǎn)生后的10秒內(nèi)獲取,這要求我們不能使用嚴格的逐幀匹配,而需要通過二階段策略,由一階段先粗篩召回部分候選集壓縮計算量,在二階段實現(xiàn)嚴格精準的片段匹配。同時我們通過自研深度學習推理框架,對接硬件解碼SDK,GPU處理整個預處理流程,CUDA實現(xiàn)音頻特征提取等性能優(yōu)化手段,對各個階段進行工程加速。經(jīng)過優(yōu)化后,目前超過96%的視頻能在審核進入人審頁面后及時給到撞車的判斷結果。
三、整體架構
我們將撞車系統(tǒng)設計為4個子系統(tǒng):版權等下游子系統(tǒng)、撞車系統(tǒng)、超時兜底撞車系統(tǒng)、過濾模塊。
撞車系統(tǒng):
為整個視頻查重系統(tǒng)的主系統(tǒng)。存儲所有B站歷史視頻的特征形成檢索庫,所有新上傳的視頻均需對歷史視頻庫進行檢索與精確的匹配。該系統(tǒng)分為視頻預處理、特征提取、檢索庫粗篩視頻對、片段精確匹配與特征結果落盤這4項子流程,占用整個查重系統(tǒng)中最大的資源量,同時有著最好的準確率與召回率。數(shù)據(jù)流交互過程如圖所示(紅色區(qū)塊),輸入720P每秒截一幀的視頻流,輸出所有落盤特征、實時更新的檢索庫索引與最終的匹配結果。
超時兜底撞車系統(tǒng):
為撞車系統(tǒng)的附屬系統(tǒng),擁有更輕量化的數(shù)據(jù)流和模型結構,用較小的成本對主系統(tǒng)因工程超時導致的漏放進行一定程度的補召回。輸入為視頻前5分鐘等間距30幀的快照截圖與從原始視頻抽取出的音頻流。
下游子系統(tǒng):
應用于版權、黑樣本庫等其他子業(yè)務中。與主系統(tǒng)的完整視頻庫互相獨立,庫更加輕量,不同子業(yè)務可以根據(jù)資源預算選擇不同級別的參數(shù)配置。
過濾模塊:
數(shù)據(jù)流引入稿件視頻信息,為業(yè)務方按需定制后處理過濾規(guī)則。
四、算法優(yōu)化
特征提取優(yōu)化:
撞車系統(tǒng)的特征提取分為圖像前處理策略、模型和訓練方法。我們使用B站視頻幀數(shù)據(jù)通過自監(jiān)督的訓練方式構建了適合B站場景的能表征視頻編輯度距離的embedding提取器,設計了一套核心內(nèi)容框提取器,并在圖像對測試集上通過多種trick進行迭代得到了最優(yōu)解。
圖像前處理策略用于優(yōu)化入庫圖像質量。并不是所有的圖像都是優(yōu)質圖像,低質圖像入庫會對后續(xù)匹配環(huán)節(jié)帶來精度影響。對于特定的圖像,例如畫中畫情形,實際有效畫面在圖像的內(nèi)部,在圖像匹配時希望將有效部分裁剪出來進行匹配。為此我們進行了針對性的處理:用邊緣檢測的方法找出圖像中的明顯邊界,然后將所有邊界組合成一個矩形,將矩形內(nèi)部的圖片從原圖中裁剪出來。
模型的目標是訓練一個特征提取器,能夠將相似圖片的特征拉進,不相似的特征拉遠。特征提取器的網(wǎng)絡結構是ResNet50。具體來說,訓練模型需要標注好的數(shù)據(jù),而一般有兩種方法獲取帶標注的數(shù)據(jù),一種是自己人工標注,另一種是尋找開源的數(shù)據(jù)集。這兩種方法都有各自的缺點:自己人工標注需要花費大量的標注成本,開源數(shù)據(jù)集中的數(shù)據(jù)又和實際的業(yè)務場景相差較大導致遷移后不一定能有很好的效果。所以針對于訓練特征提取器的問題,我們使用了自監(jiān)督的訓練方式來訓練模型,自監(jiān)督訓練方式雖然也會用到標注,但這個標注不需要人為去標,而是通過一些邏輯設計,自動地生成這個標注信息。
具體訓練方法如上圖所示,首先準備一系列圖片作為負樣本集,如第一行所示。這個負樣本集保持足夠大,并且隨著訓練的過程動態(tài)更新。然后輸入一張訓練圖像和它的隨機數(shù)據(jù)增強,如二、三行所示。值得強調的是這個數(shù)據(jù)增強是模擬圖片常見的編輯方式,例如裁剪、翻轉、改變顏色、模糊等等,這兩張圖像可以認為是正樣本對,也可以理解為兩張圖像相似。訓練的過程中將上述提到的圖像通過卷積神經(jīng)網(wǎng)絡提取特征向量,兩張正樣本的特征需要接近,計算兩張圖像的余弦相似度得到 positive logits。同樣的,計算第二行圖像和第一行的負樣本特征的余弦相似度得到負樣本的 negative logits。將positive logits 和 negative logits拼接起來可以得到一個形狀為 1 × (1+k) 的logits向量。而這個向量的含義我們是知道的:其中1是正樣本的相似度,k 為負樣本的相似度。只需要用長度(1+k)的label [1,0,0 ……,0,0]就可以約束,以交叉熵為loss就可以訓練模型了。
在訓練過程中,負樣本的隊列要一直動態(tài)變化,否則模型見過的負樣本太少會影響效果,具體的實現(xiàn)方式是每訓練一張圖像后,將這張圖像放入負樣本隊列的尾部,隊首的圖像出隊列,進入圖像的不同:導致正負樣本的組合都不同。隨著訓練圖像的增加,模型就可以學習什么樣的圖像相似,什么樣的圖像不相似。
為了提升模型的最終效果,在訓練過程中也添加了些提升效果的技巧。例如添加數(shù)據(jù)增強的種類,使用大模型(ViT)作為teacher來蒸餾ResNet50等等,同時為了提升模型的推理速度,我們對模型進行了量化。
為評估模型的特征提取效果,我們準備了一批圖片對作為測試集,包含3萬組正負圖片對。測試方法是評估模型能不能將相似的圖片匹配上,將不相似的圖片區(qū)分出來。在模型迭代過程中,我們首先使用了開源的ImageNet作為baseline,后續(xù)做了MoCo、數(shù)據(jù)增強 (Aug)、輕量ViT蒸餾ResNet50(ViT)、對ViT進行8bit量化加速(Quantize)、大ViT蒸餾ResNet50(ViT_v2)等優(yōu)化,迭代效果逐步提升。
二階段匹配策略:
撞車系統(tǒng)設計了二階段匹配策略,即粗篩和精排。通過該匹配策略,我們能做到在10秒內(nèi)應對數(shù)十億級向量檢索庫做完片段維度的匹配,達到96%的及時率。
在視頻粗篩任務中,對視頻指紋特征在歐氏距離上進行K近鄰召回是一種廣泛應用的篩選方案。隨著向量維度和數(shù)量的增加,直接進行K近鄰搜索會引入極大的計算量和存儲消耗,造成系統(tǒng)性能瓶頸。近似近鄰檢索技術是一種處理大規(guī)模特征檢索任務的有效方案,利用倒排索引、特征量化等手段,在可控的精度損失下,可以獲取遠優(yōu)于暴力檢索的計算速度和更小的向量存儲成本。在近似近鄰檢索時我們采取了積極的壓縮和過濾策略,使用100W+的倒排桶數(shù)量,采用PQ32的方式存儲向量。當前總入庫規(guī)模超過十億級。
對版權視頻檢索業(yè)務,處理單個視頻的查詢?nèi)蝿諘r,對視頻中每幀圖像最相似的10個庫內(nèi)指紋進行計數(shù),可以篩選出指紋庫中相關度最高的5個視頻,將這些視頻發(fā)往精排進行詳細比對??紤]到連續(xù)時間內(nèi),視頻相似度通常較高,指紋入庫采用了2s1f的方式以減少計算和內(nèi)存資源的消耗。對于撞車業(yè)務,直接對均值特征卡閾值進行召回,為保召回率,粗篩階段采取非常寬松的閾值策略,由精排匹配階段保高準確率。
視頻精排任務可以看作兩組視頻序列特征的匹配問題,在由查詢視頻與注冊視頻指紋向量生成的損失矩陣中尋找正確的匹配關系。我們采用的精排策略包含了候選生產(chǎn)和片段過濾兩個步驟。
在進行候選生成時,需要通過相似幀匹配獲得查詢視頻幀與注冊視頻幀的相似關系,形式化的記為,即查詢視頻第幀與記錄視頻第幀存在大于0的相似度。然后利用KNN召回,可獲得如下的視頻幀相似關系。
如上圖所示,在獲取候選的基礎上,通過尋找最長的匹配序列,可以得到初步的匹配關系,即圖中矩形框所代表的查詢視頻與注冊視頻匹配關系,并以此為基礎進行過濾??紤]到損失矩陣中,匹配序列可能存在噪聲的問題,可通過開閉操作、近鄰序列合并等策略進行優(yōu)化。另外視頻序列匹配存在一對多匹配的現(xiàn)象,采用非極大值抑制可以較好的緩解這一問題。由于外部藍色框的抑制,上圖中紅色框所代表的匹配關系將不會出現(xiàn)在最終的匹配結果中。
五、工程性能優(yōu)化
視頻撞車系統(tǒng)主要有兩個計算密集模塊——特征提取和向量檢索。特征提取包含模型推理、視頻解碼、圖像預處理、音頻特征提取等過程,向量檢索又包含了粗排和精排兩個階段。經(jīng)過我們的優(yōu)化,模型效果基本對齊baseline,同時單個視頻端到端處理速度提升3倍多,99分位提升十多倍,優(yōu)化效果顯著。
模型推理
借助部門自研InferX推理框架,視頻撞車的模型(ResNet50)推理相比較LibTorch部署方案在Volta及之后架構的NVIDIA GPU上均有5倍以上加速效果,T4單卡推理QPS超過2000,并且能夠支持更大batch size。我們測試在T4上使用LibTorch進行推理當batch size增大到128時就會出現(xiàn)GPU OOM,而使用InferX進行推理僅需占用2G顯存。我們發(fā)現(xiàn)LibTorch在顯存管理上做得不太好,在使用LibTorch推理時可以通過減少中間變量或使用混合精度來降低顯存占用。
視頻解碼
由于模型推理速度非???,撞車系統(tǒng)鏈路主要耗時分布在其他CPU處理上,視頻解碼便是其中耗時占比最高的環(huán)節(jié)之一。我們基于NvCodec SDK開發(fā)了通用的GPU視頻解碼庫,輸入視頻路徑/鏈接,輸出torch CUDA Tensor,Layout支持CHW/HWC,可以直接用于后續(xù)GPU計算,避免了顯存和內(nèi)存之間的memory copy,實現(xiàn)端到端的All GPU處理方案。解碼庫以視頻路徑/鏈接作為輸入,首先調用ffmpeg對視頻進行解封裝得到碼流,再調用CUVID API使用NVIDIA GPU的硬件解碼器對視頻進行解碼,最后再編寫CUDA Kernel實現(xiàn)色彩空間轉換,如YUV->RGB。為了使得解碼庫更通用,我們使用CUDA實現(xiàn)了多種轉換kernel,如NV12向three-plane YUV420的轉換模版等。由于色彩空間轉換使用CUDA kernel實現(xiàn),因此執(zhí)行時會占用少量流處理器進行計算,可能會影響其他并行執(zhí)行的GPU計算速度,使用中我們發(fā)現(xiàn)一般對GPU占用率小于10%。完成RGB轉換后,可以選擇性進行Layout重排,提供所需的torch CUDA Tensor作為輸出。此外,考慮到某些使用場景下解碼服務和模型服務可能分布在不同節(jié)點,我們也基于NvJPEG支持了視頻解碼后幀以jpeg編碼格式輸出,方便用于網(wǎng)絡傳輸。解碼庫使用Pybind11同時封裝Python接口,更加方便與其他模塊對接使用。
圖像預處理
撞車系統(tǒng)的圖像預處理過程除了常規(guī)的Resize, Normalize操作之外,還包含切黑邊操作。切黑邊算法是基于圖像像素級統(tǒng)計信息來判斷黑邊位置,體現(xiàn)在計算上就是大量的規(guī)約操作, CPU實現(xiàn)速度非常慢。規(guī)約操作的GPU優(yōu)化方式比較常規(guī),使用warp shuffle實現(xiàn)線程束級規(guī)約、借助GPU共享內(nèi)存加速線程塊級規(guī)約、最后使用atomicAdd實現(xiàn)數(shù)據(jù)位于全局內(nèi)存的線程網(wǎng)格規(guī)約,復雜的是針對不同形狀的張量和規(guī)約維度實現(xiàn)特定的優(yōu)化kernel。Resize操作可以直接使用torchvision的GPU版本,但不管使用哪種插值方式,直觀上效果相對于Pillow會更差一些,主要原因是Pillow做了額外的平滑處理。為了實現(xiàn)Pillow的Resize操作,我們在采樣之前也加入卷積濾波,使用torch卷積的GPU版本。Normalize操作計算量很小,直接使用torch操作實現(xiàn),整個預處理均在GPU上執(zhí)行。
音頻特征提取
這里主要介紹音頻淺層特征Log-FilterBank和MFCC計算加速方式。Log-FilterBank計算步驟為:輸入波形->預加重->分幀、加窗->能量譜->梅爾濾波->差分->標準差,取梅爾濾波取log后的fbank特征,將對數(shù)能量帶入離散余弦變換,求出L階的Mel-scale Cepstrum參數(shù)。同樣進行差分、標準差,得到最終MFCC特征。線上原始Base版本使用python_speech_features包計算音頻特征,我們基于C++使用vectorize, unroll, tile, parallelize等一些常規(guī)優(yōu)化手段增強代碼實現(xiàn)的局部性,使用memory pool實現(xiàn)內(nèi)存復用,選擇更高效的內(nèi)存排布方式,借助intel mkl fft將信號轉換為頻域計算能量譜,借助intel mkl GEMM計算filter bank和能量譜矩陣乘, 借助intel mkl fftw3實現(xiàn)DCT及BatchDCT,整體加速效果相比較python版本提升10倍。如果需要對其進一步進行GPU優(yōu)化, GEMM, FFT, DCT這些操作可以直接調用CuBlAS, CuFFT實現(xiàn),CuBLAS在大多數(shù)場景下都有比較好的性能,如果運行在擁有Tensor Core的GPU卡上,還可以使用CUTLASS或者直接使用low-level的WMMA API來更精細化地加速混合精度GEMM計算,它們相比已經(jīng)編譯好的庫CuBLAS擁有更好的靈活性。最后,其他一些計算均可以通過編寫CUDA kernel來實現(xiàn),例如預加重就很適合線程束shuffle指令__shfl_down_sync來實現(xiàn)。
檢索
視頻撞車系統(tǒng)的索引庫規(guī)模達到數(shù)十億級別。這里我們主要基于faiss構建分布式向量檢索系統(tǒng),對索引分片以方便擴展支持更大規(guī)模數(shù)據(jù),增加副本數(shù)來支持更高QPS。由于latency能滿足需求,因此目前索引部署在CPU機器上,一些優(yōu)化策略主要在算法側進行。這塊的GPU優(yōu)化手段第一步可以考慮針對Volta及之后架構借助Tensor Core使用fp16精度計算,在加速計算同時也能節(jié)省顯存;進一步可以考慮基于哈希學習的方法量化為二值編碼,在可以容忍損失一部分精度前提下將浮點乘加操作轉換成異或和popcnt,由于哈希編碼之間的距離在有限的整數(shù)范圍內(nèi),topk階段可以簡單使用基數(shù)排序。也可以先使用直方圖統(tǒng)計篩選出距離topk,再對topk內(nèi)距離進行排序,能夠進一步降低排序計算量。上述topk、基數(shù)排序、直方圖統(tǒng)計在并行計算領域是比較經(jīng)典的問題,很容易用CUDA高效實現(xiàn)。這種方法中哈希學習可以采用有監(jiān)督學習,以pairwise-loss或ranking-loss作為損失函數(shù),量化誤差并不像簡單的二值量化一樣一成不變,而是可以通過訓練來降低。此外哈希編碼極致地壓縮了內(nèi)存/顯存占用,特征向量的32位哈希編碼僅需1個float32存儲空間,使得在一塊普通16G顯存的GPU中進行數(shù)十億規(guī)模特征的向量相似度檢索成為可能。
六、成果總結
本項目歷時兩年多,對比2020年時的baseline,撞車視頻打回量提升約7.5倍,召回率提升約3.75倍,提示量上升至基線的1.7倍,業(yè)務準確率為基線的2.2倍,模型準確率約為88%。人審發(fā)現(xiàn)的機審漏召從日均65個降低至日均5個,為基線的十三分之一。目前該查重系統(tǒng)已為B站安全問題撞車審核、版權機審、高危圖像視頻回掃、同屏推薦去重等業(yè)務提供服務。后續(xù)將持續(xù)對檢索效率、檢索質量進行工程性能、與算法準召指標的優(yōu)化。
本期作者
劉璟
嗶哩嗶哩高級算法工程師
齊竟雄
嗶哩嗶哩高級算法工程師
唐哲
嗶哩嗶哩高級算法工程師
李傲
嗶哩嗶哩資深算法工程師