吞吐提升30倍:CV流水線走向全端並行化

WBOY
發布: 2023-04-11 16:37:03
轉載
1532 人瀏覽過

吞吐提升30倍:CV流水線走向全端並行化

引言

史丹佛教授、Tcl 語言發明者John Ousterhout 曾寫過一本書《軟體設計的哲學》,系統討論了軟體設計的通用原則和方法論,整書的核心觀點是:軟體設計的核心在於降低複雜性。

實際上,這個觀點也適用於涉及底層硬體適配的軟體設計。

以視覺模型開發為例,以往視覺模型開發過程中,人們一般會更加關注模型本身的最佳化來提升速度與效果。而對於影像前處理(預處理)和後處理階段,人們則很少關注。

當模型計算即模型訓練和推理主階段的效率越來越高時,影像的前後處理階段癒發成為影像處理任務的效能瓶頸。

吞吐提升30倍:CV流水線走向全端並行化

#具體而言,在傳統的映像處理流程中,前後處理部分通常都是用CPU 來運作的,這會導致整個流程中50% 到90% 以上的工作負荷都和前後處理相關,從而它們會成為整個演算法流程的效能瓶頸。

一、主流CV庫的限制

上述問題是目前市面上的主流CV 庫在應用場景上的主要局限性,也就是說,對底層硬體依賴的不一致性導致了複雜性和效能瓶頸。正如 John Ousterhout 總結複雜性原因時所道:複雜性源自於依賴性。

吞吐提升30倍:CV流水線走向全端並行化

#主流的圖像處理庫OpenCV,其應用場景非常廣泛,但在實際使用的時候也會面臨一些問題。

例如用 OpenCV 的 CPU 版本先做訓練再做推理的時候,在推理階段可能需要一個效能比較高的版本。

因為在訓練場景裡,前後處理與模型推理可以在時間上進行覆蓋,從而覆蓋前處理的時間。但推理管線中,模型只包含前向推理,且經過 Tensor RT 加速後耗時急劇減小,這時前處理的耗時佔比會非常高,難以被模型推理所覆蓋。

要減少推理場景的耗時,提高推理場景的效能,一般會用 OpenCV 的 GPU 版本進行加速。

但是 OpenCV 的 CPU 版本和 GPU 版本之間可能會出現結果不一致的情況。典型的例子是 resize 算子,在 CPU 版本和 GPU 版本上對於差值的計算方式是不一致的。

OpenCV 在訓練和推理的時候會使用不同版本的算子,在訓練的時候一般用CPU,因為其CPU 算子覆蓋度比較高,在推理的時候一般用GPU,因為性能比較好。因此,這也會導致結果對齊的問題。也就是說,用 CPU 做模型訓練,並用 GPU 做模型推理的時候,會導致最終的輸出結果無法對齊。

其次,部分 GPU 算符的效能會退化。在 OpenCV 中,部分 GPU 算子本身的耗時比較大,進而導致整個算子的效能回退,甚至差於 CPU 版本。

第三,OpenCV 的 GPU 運算子覆蓋度是有限的,部分算子只有 CPU 版本。還有一些 GPU 算子在參數、資料型別等方面的覆蓋度也沒有 CPU 版本高,進而帶來使用上的限制。

最後,如果在使用中將 CPU 算子和 GPU 算子互動使用,就會帶來大量的 CPU 和 GPU 之間的資料拷貝和同步操作,進而導致整體的加速效能不夠高。

另外一個常用的影像處理庫是 TorchVision。

TorchVision 在做模型推理的時候,有些算子缺乏 C 接口,從而在調用的時候缺乏靈活性。如果要產生 C 版本,則必須透過 TorchScript 產生。這會導致使用上的許多不便,因為在流程中間插入其它庫的算子來互動使用會帶來額外開銷和工作量。 TorchVision 還有一個缺點是算子的覆蓋度不高。

以上就是目前的主流 CV 函式庫的限制。

二、統一CV 管線

既然前後處理的效能瓶頸主要在於使用CPU 運算,而模型計算階段使用GPU 的技術已經越來越成熟。

那麼,一個很自然的解決方案是,用 GPU 對前後處理進行加速,對整個演算法管線將會有非常大的效能提升。

為此,NVIDIA英偉達攜手字節跳動開源了映像預處理算子庫 CV-CUDA。 CV-CUDA 能有效率地在 GPU 上運行,算子速度能達到 OpenCV 的約一百倍。

2023 年1 月15 日,9:30-11:30,由NVIDIA英偉達主辦的『CV-CUDA 首次公開課』,邀請了來自NVIDIA英偉達、位元組跳動、新浪微博的3位技術專家(張毅、盛一耀、龐鋒),就相關主題進行深度分享,本文彙整了三位專家的演講精華。 吞吐提升30倍:CV流水線走向全端並行化

採用 GPU 替換 CPU 有許多好處。首先,前後處理的算子遷移到 GPU 上以後,可以提高算子的運算效率。

其次,由於所有的流程都是在 GPU 上進行的,可以減少 CPU 和 GPU 之間的資料拷貝。

最後,把 CPU 的負載移轉到 GPU 上後,可以降低 CPU 的負載,將 CPU 用來處理它需要很複雜邏輯的任務。

吞吐提升30倍:CV流水線走向全端並行化

將整個流程遷移到GPU 上後,對於整個管線可以帶來近30 倍的提升,從而節省計算開銷,降低營運成本。

透過圖中資料比較可以看到,在相同的伺服器和參數配置下,對於30fps 1080p 視訊串流,OpenCV 最多可以開2-3 個並行流,PyTorch(CPU)最多可以開1.5 個並行流,而CV-CUDA 最多可以開60 個並行流。可以看出整體效能提升程度非常大,涉及的前處理算符有 resize、padding、normalize 等,後處理算符有 crop、resize、compose 等。

三、非同步化

為什麼GPU 可以適應前後處理的加速需求? 得益於模型運算與前後處理之間的非同步化,並與 GPU 的平行運算能力相適應。

吞吐提升30倍:CV流水線走向全端並行化

我們以模型訓練和模型推理的預處理非同步化分別進行說明。

1、模型訓練的預處理非同步化

吞吐提升30倍:CV流水線走向全端並行化

模型訓練可以分成兩個部分,第一個是資料準備,第二個是模型計算。

#

目前主流的機器學習框架,例如 PyTorch、TensorFlow,它們在資料準備和模型計算之間是非同步的。以 PyTorch 為例,會開啟多個子進程進行資料的準備。

如圖所示,其包含兩個狀態,即模型計算和資料準備,兩者存在時間先後關係,例如當D0 完成之後,就可以進行B0,以此類推。

從效能角度來看,我們預期資料準備的速度能夠跟得上模型計算的速度。但實際情況中,一些資料讀取和資料預處理過程的耗時很長,導致相應的模型計算在進行前有一定的空窗期,從而導致 GPU 利用率下降。

資料準備可以分成資料讀取和資料預處理,這兩個階段可以串列執行,也可以並行執行,例如在PyTorch 的框架下是串行執行的。

影響資料讀取的效能因素很多,例如資料儲存媒體、儲存格式、平行度、執行進程數等。

相較之下,資料預處理的效能影響因素比較簡單,就是並行度 #。並行度越高,資料預處理的效能越好。也就是說,讓資料預處理與模型計算非同步化,並提高資料預處理的平行度,可以提高資料預處理的效能。

2、模型推理的預處理異步化

吞吐提升30倍:CV流水線走向全端並行化

在模型推理階段,其表現有兩個指標,第一個是吞吐,第二個是延時。在某種程度上,這兩個指標是彼此互斥的。

對於單一 query 而言,當 server 接收到資料之後,會進行資料的預處理,再進行模型推理。所以對於單一 query 而言,某種程度上它是一個串列的過程。

但這樣做在效率上是很低的,會浪費很多運算資源。為了提高吞吐量,許多推理引擎會採用和訓練階段一樣的策略,將資料準備和模型計算非同步化。在資料準備階段,會累積一定量的 query,組合成一個 batch,再進行後續的計算,以提高整體的吞吐量。

從吞吐而言,模型推理和模型訓練是比較類似的。把資料預處理階段從 CPU 搬到 GPU 上,可以得到吞吐上的收益。

同時,從延時的角度來看,對於每個 query 語句,如果能夠減少預處理過程所花費的時間,對於每條 query 而言,其延時也會得到相應的縮短。

模型推理還有一個特點是,其模型計算量比較小,因為只涉及前向計算,不涉及後向計算。這意味著模型推理對資料預處理的需求更高。

3、核心問題:CPU 資源競爭

假設有足夠的CPU 資源用於運算,理論上預處理不會成為效能瓶頸。因為一旦發現效能跟不上,只需要增加進程做預處理操作即#可。

因此,只有當 CPU 出現資源競爭的時候,資料預處理才可能成為效能瓶頸。

在實際業務中,CPU 資源競爭的情況是很常見的,這會導致後續訓練和推理階段中 GPU 利用率降低,進而訓練速度降低。

隨著 GPU 算力不斷增加,可以預見,對資料準備階段的速度要求會越來越高。

為此,將預處理部分搬上 GPU,來緩解 CPU 資源競爭問題,提高 GPU 利用率,就成了很自然的選擇。

整體而言,這種設計降低了系統的複雜性,將模型管線的主體與 GPU 直接適配,對於提高 GPU 和 CPU 的利用率都能帶來很大的好處。同時,它也避免了不同版本之間的結果對齊問題,減少了依賴性,符合 John Ousterhout 提出的軟體設計原則。

四、 CV-CUDA

#把預處理、後處理過程搬上GPU 需要滿足多個條件。

第一是其效能至少比 CPU好。這主要基於 GPU 的高並發運算能力。

第二是對預處理的加速,不能造成對其它流程例如模型推理的負面影響。對於第二個需求,CV-CUDA 的每個算子都留有stream 和CUDA 顯存的接口,從而可以更合理地配置GPU的資源,使得在GPU 上運行這些預處理算子的時候,不會過於影響到模型計算本身。

第三,網路企業中有非常多樣化的業務需求,涉及的模型種類很多,相應的預處理邏輯也是種類繁多,因此預處理算子需要開發成客製化的,從而有更大的靈活性來實現複雜的邏輯。

吞吐提升30倍:CV流水線走向全端並行化

總體而言,CV-CUDA 從硬體、軟體、演算法、語言等方面對模型管線中的前後處理階段進行了加速,以及整個管線的統一性。

1、硬體

硬體方面,CV-CUDA 基於GPU 的平行運算能力,能夠大幅提高前後處理的速度和吞吐,減少模型計算的等待時間,提高GPU 的使用率。

CV-CUDA 支援 Batch 和 Variable Shape 模式。 Batch模式支援批次處理,可以充分發揮 GPU 的平行特性,而 OpenCV 不管是 CPU 或 GPU 版本都只能對單張圖片進行呼叫。

Variable Shape 模式是指在一個batch當中,每張圖片的長度和寬度可以不一樣。網路上的圖片一般長寬都是不一致的,主流框架的做法是把長和寬分別 resize 到同一個大小,再對同一長寬的圖片打包為一個 batch,再對 batch 進行處理。 CV-CUDA 可以直接把不同長度和寬度的影像直接放在一個 batch 中處理,不僅能提升效率,使用上也很方便。

Variable Shape 的另外一層意義是在對影像進行處理的時候,可以指定每張圖片的某些參數,例如 rotate,對一個batch的影像可以指定每張圖片的旋轉角度。

2、軟體

軟體方面,CV-CUDA 開發了大量的軟體優化方法來做進一步的優化,包括效能優化(例如訪存優化)和資源利用優化(例如顯存預先分配),從而可以有效地運行在雲端的訓練和推理場景中。

首先是顯存預先分配設定。 OpenCV在 呼叫 GPU 版本的時候,部分算子會在內部執行 cudaMalloc,這會導致耗時大量增加。在 CV-CUDA 中,所有的顯存預先分配都是在初始化階段執行,而在訓練和推理階段,不會進行任何顯存分配操作,進而提高效率。

其次,所有的算符都是非同步操作的。 CV-CUDA 對大量kernel進行了融合,從而減少 kernel 的數量,進而減少 kernel 的啟動時間以及資料拷貝擦做,提高整體運作的效率。

第三,CV-CUDA 也對訪存進行了最佳化,例如合併訪存、向量化讀寫等,提高頻寬的利用率,還利用shared memory 來提高訪存讀寫效率。

#

最後,CV-CUDA 在計算上也做了很多優化,像是 fast math、warp reduce/block reduce 等。

3、演算法

演算法方面,CV-CUDA 的算符都是獨立設計的、客製化的,因此可以支持非常複雜的邏輯實現,並且方便進行使用和調試。

如何理解獨立設計?影像處理庫的算子呼叫有兩種形式,一種是整體性的pipeline 形式,只能取得pipeline 的結果,例如DALI,另一種是模組化的獨立算子的形式,可以取得每一個算子的單獨結果,如OpenCV。 CV-CUDA 採用了和 OpenCV 相同的呼叫形式,在使用和調試上會比較方便。

4、語言

語言方面,CV-CUDA 支援豐富的API,可以無縫將前後處理銜接訓練和推理場景。

這些API包括常用的C、C 、Python 的介面等,這使得我們可以同時支援訓練和推理場景,它也支援PyTorch、TensorRT 的接口,在未來,CV-CUDA 也將支援Triton、TensorFlow、JAX 等介面。

推理階段,可以直接用Python 或C 的介面進行推理,只要保證推理的時候將前後處理、模型、GPU 放在一個stream 上即可。

五、應用案例

#透過展示CV-CUDA 在NVIDIA 英偉達、字節跳動、新浪微博的應用案例,我們可以體會到CV-CUDA 帶來的效能提升有多顯著。

吞吐提升30倍:CV流水線走向全端並行化

#首先是 NVIDIA英偉達所展示的圖片分類案例。

在圖片分類的管線中,首先是JPEG decode,其對圖片進行解碼;綠色部分是前處理步驟,包含resize、convert data type、 normalize 和reformat;藍色部分是使用PyTorch 的前向推理過程,最後對分類的結果進行評分和排序。

吞吐提升30倍:CV流水線走向全端並行化

#將CV-CUDA 與OpenCV 的CPU 版本與GPU 版本進行效能對比可以發現,OpenCV 的GPU 版本相比於CPU 版本能得到較大的效能提升,而透過應用CV-CUDA,又能將效能翻倍。例如OpenCV 的CPU 算子每毫秒處理的圖片數是22 張,GPU 算子每毫秒處理的圖片數是200 多張,CV-CUDA 則每毫秒可以處理500 多張圖片,其吞吐量為OpenCV 的CPU版本的20 多倍,是GPU 版本的兩倍,效能提升很明顯。

其次是位元組跳動展示的 OCR1、OCR2、視訊多模態三個案例。

吞吐提升30倍:CV流水線走向全端並行化

在模型訓練上,可以看到在OCR1、OCR2、視訊多模態三個任務上,使用了CV-CUDA 後獲得了50% 到100% 的效能效益。

#

為什麼有這麼大的效能效益?實際上這三個任務比較大的一個共同點是,它們的圖片預處理邏輯非常複雜,例如decode、resize、crop 等,而且這些還是大類,實際上每個算子類中還可能有很多小類別或子類別預處理。對於這三個任務而言,其涉及到預處理鏈路上的資料增強種類可能就有十幾種,所以其對於CPU 的計算壓力非常大,如果能把這部分計算搬到GPU上,CPU 的資源競爭就會明顯下降,整體吞吐也能提高很多。

最後是新浪微博展示的影片處理案例。

吞吐提升30倍:CV流水線走向全端並行化

#對於視訊處理流程,傳統的做法是先將視訊影格在CPU 環境中解碼,把原始的位元組流解碼成圖片數據,再做一些常規操作,例如resize、crop 等,再把數據上傳到GPU 上做具體的模型計算。

吞吐提升30倍:CV流水線走向全端並行化

#而CV-CUDA 的處理方式是將CPU 解碼之後放在記憶體中的位元組流上傳到GPU 上,且預處理也位於GPU 上,從而跟模型計算進行無縫銜接,不需要從顯存和記憶體之間的拷貝操作。

吞吐提升30倍:CV流水線走向全端並行化

#圖中給出了採用OpenCV(奇數)和CV-CUDA(偶數)各自的處理時間,藍色指的是模型的消耗時間,橘色指的是解碼的消耗時間,綠色指的是預處理的消耗時間。

OpenCV 可分為 CPU 解碼與 GPU 解碼兩種模式,CV-CUDA 只採用 GPU 解碼模式。

可以看到,對於 CPU 解碼的 OpenCV,OpenCV 的解碼和預處理都比 CV-CUDA 的耗時高得多。

吞吐提升30倍:CV流水線走向全端並行化

#再看OpenCV 採用GPU 解碼的情況,可以看到,OpenCV 和CV- CUDA 在模型和解碼部分的耗時是接近的,而預處理方面仍然差距很大。

吞吐提升30倍:CV流水線走向全端並行化

#在pipeline 整體對比上,CV-CUDA 也有很明顯的優勢,一方面CV-CUDA 更能節省CPU 資源,也就是將GPU 使用率打滿的情況下,CV-CUDA 只需要OpenCV 的10%CPU 配置;同時,CV-CUDA 也更節省GPU 資源,在整體pipeline 上,CV- CUDA 效率提升70%。

六、未來展望

#CV-CUDA 在模型訓練和推理階段都能有效地解決CPU資源競爭的問題,從而能夠提高模型訓練和推理的效率。

但如何正確理解 CV-CUDA 的優勢?需要理解其發揮作用的根本前提,而其優勢相對於 CPU、OpenCV 並不是絕對的。

首先, CV-CUDA 其實也不是萬靈藥。例如在模型訓練階段,如果瓶頸不是在預處理上,而是在資料讀取、模型推理上。這時候,如果用 CV-CUDA 來取代原來的預處理方案,實際上也是沒有任何用處的。

此外,在使用 CV-CUDA 的過程中,如果對預處理邏輯合理分配 CPU 和 GPU 的工作量,實際上有時候能夠達到更好的效能效果。

例如,CPU 仍然可以進行圖片解碼和 resize,resize 之後再放到 GPU 上處理。

為什麼要把解碼和 resize 放到 CPU 上做?首先,對於圖片解碼而言,其實 GPU 的硬解碼單元是有限的。其次,對 resize 而言,通常情況下,resize 都會把一張較大的圖片,轉換成一張較小的圖片。

如果在 resize 之前,把資料拷貝到 GPU 上,可能會佔用很多的顯存資料搬運的頻寬。

當然,CPU 與 GPU 之間的工作量具體怎麼分配,還是需要結合實際情況來判斷的。

而最重要的原則是,不要將 CPU 和 GPU 之間的運算交替穿插進行,因為跨 device 傳輸資料都是有開銷的。如果交替過於頻繁,反而可能將計算本身帶來的收益抹平,進而導致效能不增反降。

2022 年12 月,CV-CUDA 發布了alpha 版本,其中包含20 多個算子,例如常用的Flip、Rotate、Perspective、Resize 等。

目前OpenCV 的算子更多,有數千個算子,CV-CUDA 目前只對比較常用的算子進行加速,後續會不斷增加新的算子。

今年 3 月 CV-CUDA 也會發表 beta 版本,會增加 20 多的算子,達到 50 多個算子。 beta 版本將包含一些非常用的算子,例如 ConvexHull、FindContours 等。

吞吐提升30倍:CV流水線走向全端並行化

#七、

#回過頭來看CV-CUDA 的設計方案,可以發現,背後並沒有太複雜的原理,甚至可以說一目了然。

從複雜性的角度,這可以說是 CV-CUDA 的優點。 《軟體設計的哲學》提過一個判斷軟體複雜性的原則──如果一個軟體系統難以理解和修改,那就很複雜;如果很容易理解和修改,那就很簡單。

可以將CV-CUDA 的有效性理解為,模型計算階段與GPU 的適配性,帶動了前後處理階段與GPU 的適配性。而這個趨勢,其實才剛開始。

#

以上是吞吐提升30倍:CV流水線走向全端並行化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:51cto.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!