“ GPU视频处理技术调研报告 ”
本文來自英偉達高級工程師 季光在LiveVideoStack 線上交流分享,并由LiveVideoStack整理而成。分享中季光詳細解析了GPU在視頻編解碼,圖像分析和視頻處理方面的相關技術支持,及實際性能評測數據。可以說是一份詳細的“GPU視頻處理技術調研報告”。
文 / 季光
整理 / LiveVideoStack
直播回放:
https://www.baijiayun.com/web/playback/index?classid=18110798306449&token=KcfWRw-Z3NfhKKZLIMQ5hppFaosTwLmE2fz-KBQwWWbRDuat0iGXznoobLduG-7tCqdH1zJ1Si0
大家好,我是季光,現就職于NVIDIA并擔任高級工程師。我在2014年加入英偉達并負責云游戲基礎設施開發,隨后也曾為Video Codec SDK v8.1應用層開發做出了一些貢獻。如果你是英偉達Video Codec SDK的早期用戶就會發現早期版本的SDK中提供的樣例程序并不易用,其原因在于與此相關的代碼邏輯不清晰且難以復用。當時我們注意到了這些問題并對其進行了修復,使得v8.1版本的SDK有了很大改善。除此之外,我也是DeepStream SDK v1.0的主要開發者。
接下來為大家分享的內容可以說是我站在英偉達技術粉絲的角度撰寫的“GPU視頻處理技術調研報告”,并不代表英偉達官方的觀點。我期待通過分享,為處于技術選型中的用戶提供GPU的采納與部署所需的技術依據與路線,也希望為既有的GPU用戶提供前沿、全面的進階信息與豐富的知識儲備。
1.?NVIDIA GPU 基礎準備
1.1 產品線
在開始正式的分享之前,首先我們有必要了解一下NVIDIA GPU的產品線。英偉達的產品線策略大致可以總結為利用少量的GPU型號衍生出可滿足不同客戶群需求的復雜顯卡產品,盡管我們在消費級、企業級與工作站級都部署有大量顯卡產品,但這些產品內部封裝的GPU種類,型號屈指可數,同一款GPU經過篩選并搭配不同的顯存與驅動就可得到滿足不同需求的產品。2018年8月英偉達發布了新一代圖像處理架構Turing,我們以此架構下的一款全新GPU:TU104為例。經過包裝與校調,TU104可衍生出三檔產品:搭載了8G顯存,面向如游戲玩家等PC用戶設計的消費級顯卡GeForce RTX 2080;搭載了16G顯存,面向企業級用戶設計的Tesla T4與同樣搭載了16G顯存,面向工作站用戶設計的Quadro RTX 5000。其中我們可以看到,相對于企業級與工作站級的專業顯卡,消費級顯卡在顯存上做出了些許舍棄,在某種程度上這樣做也是為了限制這些消費級顯卡在企業級市場的使用。除此之外,我們還有TU102,這是Turing架構GPU中面積最大、功能最強的芯片,所對應的消費級顯卡為旗艦級的GeForce RTX 2080 Ti,工作站級顯卡為Quadro RTX 6000與Quadro RTX 8000;相對而言面積更小、定位中端的TU106,與其對應的消費級產品是GeForce RTX 2070,英偉達會在后續推出使用此芯片的工作站級產品。
1.2 型號選擇
接下來就有一個很實際的問題擺在我們面前:如何尋找最實惠的顯卡型號?我們推薦的考慮指標為單位計算力的價格,如上圖展示的那樣:圖中藍色線擬合使用Maxwell 架構的9系消費級顯卡產品,紅色線擬合使用Pascal架構的10系消費級顯卡產品;縱軸表示產品價格,橫軸表示顯卡算力;也就是說點或線在圖中所處位置越低代表此產品(線)性價比越高。從中我們不難看出,代表比Maxwell架構更先進的Pascal架構的10系產品,其性價比明顯高于9系,這也是開發新一代產品所要達到的目標。而10系顯卡中的1080Ti所處位置最低,性價比最高。我們在選擇顯卡時可重點關注這些高端型號,而一些價格較為便宜的中低端型號產品雖然位于曲線底部有較高性價比,但產品定位導致的顯存等核心參數的低下會嚴重制約這些產品的使用場景,并不推薦使用。
經過調研,我們推薦選擇GeForce RTX 2080作為視頻加速的基礎硬件。作為售價達到6299元人民幣的次旗艦消費級顯卡RTX 2080 ,搭載了型號為TU104的GPU與8G GDDR6顯存。包括46個SM(2944個CUDA核心),穩定運行的時鐘頻率為1.515GHz并可在短時間內超頻到1.71GHz;可穩定達到的計算力為約8920GLOPS,可以說這款產品將成為日后消費級顯卡市場的主流型號。而對比上一代產品中的性價比之王GeForce 1080 Ti,即使售價為5499元人民幣,但搭載了11G顯存的它,其計算力達到了10609GFLOPS。無論是顯存還是計算力,1080Ti都遠高于RTX2080,那么我們為什么依舊推薦選擇采用新一代架構的RTX2080呢?我們通過深入了解GPU的功能及RTX 2080的新特性來回答這個問題。
2.?NVIDIA GPU?
2.1 視頻處理模塊
上圖展示的是GPU中一些與視頻處理相關的模塊,大致可分為三個部分:用于視頻解碼的NVDEC、用于視頻編碼的NVENC、用于計算的CUDA Cores。三者均靠API向應用層提供功能,而Buffer代表連接此三者的顯存。
上圖展示的是與此相關的API架構。最底層為NVENC、NVDEC與CUDA,向上一層為NVIDIA DRIVER;在DRIVER層上我們提供了兩個重要的SDK:與視頻編解碼相關的Video Codec SDK和與圖像處理計算相關的CUDA TOOLKIT,開發者在構造應用時會多次接觸到這兩個SDK;繼續向上,我們還提供了一些更高級的API如集成了Video Codec、FFmpeg等的功能,令開發者可通過FFmpeg命令行使用這些功能或用庫的方式集成至應用中并輕松從軟件Codec切換到硬件Codec;除此之外我們還提供了如DeepStream SDK、cuDNN、TensorRT、cuBLAS、cuSPARSE等計算類型的API。
2.2 GPU編程基礎
為了能夠編好一個GPU程序,我們有必要深入了解一下GPU的編程模型。我們說GPU編程是一種“異構”的編程模式,所謂“異構”是指計算過程并不在CPU內進行而是在一個外在設備(如GPU)內完成,我們需要某種方式將計算所需的必要數據拷貝到此外在設備內并啟動此設備,待計算完成后再將結果取回。上圖左側展示的就是常見的異構計算流程:平時使用的數據都在主存儲存,需要計算時這些數據會被拷貝到GPU的顯存上進行計算,隨后計算完成得到結果后這些數據再被拷貝回主存。如果將這樣的原理落實在代碼層面則是如上圖右側展示的那樣,這段代碼已經非常接近于能夠編譯運行的狀態,所演示的是最基本的GPU計算模式。首先我們在main函數中定義兩個數:代表輸入的a和與代表存入a的平方的輸出結果b。我們專門定義了a和b在顯存上的兩個指針,隨后調用cudaMalloc將指針作為一個參數。將a和b預分配完成后,我們需要通過調用cudaMemcpy把主存上的a拷貝到顯存上的a當中,并通過調用cudaKernel也就是之前定義的square啟動GPU進行運算。計算同時將數據存入顯存的b中,完成計算后再借助cudaMemcpy將顯存的b拷貝回主存的b中并釋放顯存,顯示b中計算結果,這樣便完成了整個計算過程。
總結GPU的編程基礎,首先CUDA SDK提供了最基本的GPU編程API,其中包括負責分配、釋放顯存的cudaMalloc、cudaFree,負責主存和顯存間數據交換的cudaMemcpy,以及關鍵需要自己定義的CUDA kernel。以上展示的是最基礎的CUDA編程模型,絕大多數情況下的CUDA kernel已被英偉達工程師與其他一些開發者實現,我們只需深入理解此模型就可以實現很多事情。這里需要強調一下內存顯存之間數據拷貝的開銷,這部分開銷可以說是很大的。顯存內部拷貝數據所需的帶寬可達每秒上百GB,而主存與顯存間的帶寬即使是高規格的X16 PCI-E3.0也僅有每秒十幾GB,如果PCI-E受限甚至無法達到此指標。我們需要盡量避免主存和顯存之間的拷貝,而像剛才示例中輸入的數據必須來自主存故這種拷貝無法避免。比較合理的是讓GPU計算過程中所需要的數據一直保留在顯存上,直到最終算清結果后再將其拷貝回主存。
3. 圖像處理加速
圖像處理加速其實就是之前我們所舉示例的進階版,我們可以將原始圖像看作是剛才的a,將此圖像載入顯存后利用GPU的并行計算能力處理,而后將處理完成的圖像拷貝回b中,此圖像以內存塊的形式存在于主存與顯存中。這里我推薦大家了解一下NPP庫,其優勢在于實現了圖像處理的常用算法,預先實現了很多常見的CUDA kernel并無需GPU編程,通過API即可直接使用,不過在你嘗試使用之前需要理解主存與顯存之間的數據交換原理。除此之外,如果你有自己編寫CUDA kernel的需求,那么你需要學習CUDA C編程。當然我們也在NVIDIA Codec SDK中提供了縮放、顏色空間轉換等常用算法的樣例代碼,你可以參照這些樣例代碼并根據自己的需求進行修改。入門CUDA C編程較為容易,若是想優化其性能實現極致的處理效果則需要學習很多的知識與積累大量實踐經驗。初期探索只要實現數據一直保留在GPU上的穩定運行,即使未能達到最佳的性能也可以實現非常可觀的加速效果。
4. 視頻解碼
4.1 基礎準備
接下來我想為大家介紹的是視頻解碼。NVIDIA的全產品線支持視頻解碼且沒有并發路數的限制,上圖展示了不同圖形卡支持的視頻格式。我們關心的是圖形卡可達到的視頻解碼能力,以Pascal架構產品中專面向視頻分析推出的Tesla P4為例,對碼率為1.5Mbps的1080P無B幀H264/HEVC的視頻文件進行解碼,其解碼速度可分別達到678/733 FPS;而我之前推薦的新一代Turing架構產品中的RTX2080此項測試的結果和Tesla P4非常接近;如果使用Turing架構的Tesla T4進行相同測試,其H264下的解碼能力翻倍而HEVC下的解碼能力達到了Tesla P3的3倍。這里不得不注意的是,為什么采用相同GPU的消費級顯卡RTX2080和企業級顯卡Tesla T4在解碼能力上會有如此大的差別?其在于消費級顯卡相對于企業級顯卡在部分功能與性能上的舍棄。
4.2 視頻解碼實戰
如果你需要使用FFmpeg命令行實現視頻解碼,可在編譯FFmpeg時添加一些選項如nonfree、cuda、nvenc、cuvid(cuvid是為了兼容性設置的NVDecode的別稱)、Libnpp、等,只要編譯前安裝了cuda SDK,那么編譯出的FFmpeg即附帶相應功能。如果需要使用此命令則指明解碼用NVDecode,其他的與正常使用FFmpeg一般無二。除此之外你也可使用SDK中的樣例程序或NVDecLite,如上圖右側展示的那樣,首先使用NvDecLite定義對象,而后通過外層的While循環每次加載一部分數據,通過內層的While循環解碼若干幀。上圖展示的代碼可完整實現視頻的解碼功能,可見親手編寫一個NVDecode解碼程序并不困難。
5.?視頻編碼
5.1 基礎準備
至于視頻編碼,NVIDIA產品中的Tesla和Quadro沒有并發路數的限制,而消費級的GeForce顯卡則有整個主機限2路的限制。這里的整個主機限制2路與主機上安裝的顯卡數量無關,即使是多顯卡形成的顯卡群也只能實現2路的并發編碼。關于畫質,相對于上一代的Pascal架構接近于x264 medium的預設,本代的Turing可在保持畫質相當的情況下節省10%~20%的碼流,換句話說同碼流下Turing的畫質有了顯著的提高,保持碼流不變的情況下Turing的PSNR提升明顯。值得一提的是,Turing支持了HEVC編碼的B幀,極大提高了HEVC編碼的實用性。關于編碼速度,編碼的速度與參數的設置有關,對于上一代產品Tesla P4而言,將參數設置為高性能HP或高畫質HQ處理1080P H264視頻文件,編碼速度可達到1150與658 FPS。由于目前的驅動還不完善,Turing架構產品的編碼速度比上一代暫時略有所下降,預計新版SDK與配套的驅動將會在2019年年初發布,屆時Turing圖形卡的視頻編碼能力或得到進一步提升。
5.2 畫質比較
上圖表格展示的是Turing架構下RTX2080和Pascal架構下的P6000分別在高畫質與高性能下編碼同碼率視頻文件輸出結果的畫質比較,可以看到新一代Turing產品無論是性能還是效率都高于上一代產品。
5.3 視頻編碼實戰
?
如果你想通過FFmpeg命令行實現視頻編碼,與解碼類似,首先指明編碼使用的Codec再指明所需輸出即可,(即-c:v h.264_nvenc output_file),也可聯合使用NVDecode與NVEncode,添加-hwaccel cuvid選項表示數據一直保留在顯存當中,在Decode完成解碼后立刻將數據交給Encode進行編碼。如果在這里你使用C++直接調用SDK,其代碼也非常簡單。
6. 數據流動與優化
6.1 理想的數據流動
之前我們提到,主存與顯存之間的數據交換代價非常之大。我們希望數據一直存儲在顯存當中,上圖展示的便是這樣一個理想的數據流動過程。首先我們將視頻輸入至顯存中進行解碼,解碼完成后這些數據會被留在顯存中進行中間處理如重采樣等,完成此中間處理后再對視頻進行編碼,編碼完成后將此編碼好的數據傳輸回主存中。中間處理可能會經歷很多步驟,我們希望所有的處理都是由GPU在顯存中完成而不必將這些中間數據拷貝回主存。雖然CUDA編程較易入門但如果你有此方面需求則需要自己編寫CUDA kernel從而盡量將數據保存在顯存當中從而極大提升整個程序的性能表現。但如果此視頻數據并不經過轉碼整個流程,也許在解碼之后我們就需要對其進行視頻分析。下面講講如何實現這種視頻分析。
6.2. 優化思路:神經網絡預測
這里就需要我們借助深度學習的力量也就是神經網絡預測。常見的一些神經網絡預測框架與工具有MXNet、TensorFlow、cuDNN、cuBLAS、TensorRT等。MXNet與TensorFlow已經對GPU有良好的支持,甚至可通過開關切換CPU/GPU;但由于沒有顯存互操作的API,MXNet與TensorFlow無法直接接受一個顯存的指針,也無法銜接NVDecode輸出的顯存數據,這就使得從NVDecode顯存中輸出的數據需先被拷貝到主存再通過MXNet 或TensorFlow的API拷貝回顯存繼而被計算,這也是無奈之舉。我們希望將來NVDecode的功能可被集成到MXNet/TensorFlow中或通過互操作API直接傳輸數據,這也是我們正在探索并期待下一步實現的目標。除此之外,如果你并不使用MXNet和TensorFlow,也可以借助cuDNN和cuBLAS搭建一個神經網絡,其中擁有更基礎的計算API并構建了MXNet和TensorFlow的主要GPU功能;也可接受顯存數據為輸入從而使得NVDecode與cuDNN和cuBLAS無縫銜接。最后我推薦大家使用一下TensorRT工具,其功能是接收訓練好的MXNet和TensorFlow并通過優化加快神經網絡的預測。TensorRT中包括了高度優化的GPU計算代碼,使得開發者方便調用Tensor Core進行加速;相對于效率已經很高的MXNet,TensorFlow可在TensorRT的優化下實現性能更佳的加速:在保持硬件不變的情況下使用TensorRT可實現3~10倍加速,可以說TensorRT是神經網絡預測性能優化的利器。
6.3 優化關鍵:Tensor Core
說了這么多,想必大家一定很好奇Turing架構產品相對于前幾代產品最突出的優勢在哪里,這里就不得不說Turing架構產品中集成的Tensor Core。上圖右側展示的是GPU中的一個SM單元,GPU中的SM單元相當于CPU中的一個核心,也就是說SM才是一個真正意義上的構造單元而CUDA核僅是SM中的一條流水線。觀察此圖我們可以注意到FP32中的每個小方格代表的是一個CUDA核,一個SM中包括64個CUDA核,很顯然我們不能用CUDA核直接與CPU物理核心類比。而一個SM中位于CUDA核旁邊的Tensor Cores共有8個,Tensor核的功能十分強大,可在單個clock中完成4×4矩陣乘加,也就是三個4x4的矩陣A、B、C進行的AxB+C運算。我們知道一個大的矩陣乘法可被切成多個小矩陣進行計算,而后再將計算結果匯總即可得到我們想要的答案。Tensor Code的加入可明顯加快矩陣乘法。
上圖給出了fp16 Tensor Core與fp32 CUDA Core的算力比較結果,并以1080Ti作為基準,可以看到Tensor Core的性能強大。需要強調的是,這里的結果是理想化的實驗室測試數據,在實踐探索中我們可通過優化實際發揮其80%以上的性能,如果像英偉達官方那樣采用GPU匯編盡可能優化可實現90%以上的性能。
7. 總結與評價
最后簡單評價一下NVIDIA的新一代圖像處理器架構Turing,可以說是有創新與舍棄。首先是fp32并沒有大幅度提高,同級的GPU僅提高15%~20%,并且大量的芯片面積用于其它功能;其次在Tesla/Quadro上,解碼速度有了明顯提升,而消費級產品的解碼速度與上一代產品持平;除此之外,更高的編碼質量也得以實現,相對于消費級RTX產品并發路數為2路的限制,Tesla/Quadro產品上并沒有并發路數的限制;最后,高效的Tensor Code加速使得RTX 2080 Ti的Ai計算能力(fp16)約為GTX 1080 Ti(fp32)的7倍。
精品文章推薦
線上分享:
快手QoE指標設計的分析初探
劉歧:FFmpeg Filter深度應用
FFmpeg Maintainer趙軍:FFmpeg關鍵組件與硬件加速
手淘H265編解碼算法與工程優化
傅德良:選擇視頻編碼器的誤區
技術干貨:
騰訊視頻全網清晰度提升攻堅戰
熊貓TV直播H5播放器架構探索
馮迅:YY多媒體實時傳輸系統演進
下一代低延時直播CDN:HLS、RTMP 與UDP +WebRTC
總結
以上是生活随笔為你收集整理的“ GPU视频处理技术调研报告 ”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VMAF:未毕之旅
- 下一篇: 征稿:2018-2019音视频技术回顾与