在現今資訊化時代中,圖像或視覺內容早已成為日常生活中承載資訊最主要的載體,深度學習模型憑藉著對視覺內容強大的理解能力,能對其進行各種處理與優化。
然而在以往的視覺模型開發與應用中,我們更關注模型本身的最佳化,提升其速度與效果。相反,對於影像的預處理與後處理階段,很少認真思考如何優化它們。所以,當模型計算效率越來越高,反觀影像的預處理與後處理,沒想到它們竟成了整個影像任務的瓶頸。
為了解決這樣的瓶頸,NVIDIA 攜手字節跳機學習團隊開源眾多圖像預處理算子庫CV-CUDA,它們能高效地運行在 GPU 上,算子速度能達到 OpenCV(運行在 CPU)的百倍左右。如果我們使用 CV-CUDA 作為後端取代OpenCV 和 TorchVision,整個推理的吞吐量可以達到原來的二十多倍。此外,不僅是速度的提升,同時在效果上 CV-CUDA 在計算精度上已經對齊了OpenCV,因此訓練推理能無縫銜接,大大降低工程師的工作量。
以影像背景模糊演算法為例,將CV-CUDA取代 OpenCV作為影像預/後處理的後端,整個推理過程吞吐量可增加20 多倍。
如果小夥伴們想試試更快、更好用的視覺預處理函式庫,可以試試這個開源工具。 開源位址:https://github.com/CVCUDA/CV-CUDA
許多涉及工程與產品的演算法工程師都知道,雖然我們常常只討論模型結構和訓練任務這類「前沿研究」,但實際要做成一個可靠的產品,中間會遇到很多工程問題,反而模型訓練是最輕鬆的一環了。
影像預處理就是這樣的工程難題,我們也許在實驗或訓練中只是簡單地呼叫一些API 對影像進行幾何變換、濾波、色彩變換等等,很可能並不是特別在意。但是當我們重新思考整個推理流程時會發現,影像預處理已經成為了效能瓶頸,尤其是對於預處理過程複雜的視覺任務。
這樣的效能瓶頸,主要體現在 CPU 。一般而言,對於常規的影像處理流程,我們都會先在CPU 上進行預處理,然後再放到 GPU 運作模型,最後又會回到 CPU,並可能需要做一些後處理。
以影像背景模糊演算法為例,常規的影像處理流程中預後處理主要在CPU 完成,佔據整體90% 的工作負載,其已成為該任務的瓶頸。
因此對於視訊應用,或 3D 影像建模等複雜場景,因為影像幀的數量或影像資訊足夠大,預處理過程足夠複雜,且延遲要求夠低,優化預/後處理算子就已經迫在眉睫了。一個更好地做法,當然是替換掉 OpenCV,使用更快的解決方案。
為什麼 OpenCV #仍不夠好?
在 CV 中,應用最廣泛的影像處理庫當然就是長久維護的OpenCV 了,它擁有非常廣泛的影像處理操作,基本上能滿足各種視覺任務的預/後處理所需。但隨著影像任務負載的加大,它的速度已經有點慢慢跟不上了,因為OpenCV 絕大多數影像操作都是 CPU 實現,缺少 GPU 實現,或是 GPU 實現本來就存在一些問題。
在NVIDIA與位元組跳動演算法同學的研發經驗中,他們發現OpenCV 中那些少數有 GPU 實現的算符有三大問題:
比如說第一個問題結果精確度無法對齊,NVIDIA與位元組跳動演算法同學會發現,當我們在訓練時OpenCV 某個算子使用了 CPU,但是推理階段考慮到效能問題,換而使用OpenCV對應的GPU 算子,也許CPU 和 GPU 結果精確度無法對齊,導致整個推理過程中精確度上的異常。當出現這樣的問題,要嘛換回 CPU 實現,要嘛需要費很多精力才有可能重新對齊精準度,是個不好處理的難題。
既然 OpenCV 仍不夠好,可能有讀者會問,那Torchvision 呢?它其實會面臨和 OpenCV 一樣的問題,除此之外,工程師部署模型為了效率更可能使用 C 實現推理過程,因此將沒辦法使用Torchvision而需要轉向 OpenCV 這樣的 C 視覺庫,這不就帶來了另一個難題:對齊Torchvision與OpenCV的精確度。
總的來說,目前視覺任務在 CPU 上的預/後處理已經成為了瓶頸,然而當前OpenCV 之類的傳統工具也沒辦法很好地處理。因此,將作業遷移到GPU 上,完全基於CUDA實現的高效能影像處理算子庫 CV-CUDA,就成為了新的解決方案。
完全在 GPU 上進行預處理與後處理,將大幅降低影像處理部分的CPU 瓶頸。
作為基於 CUDA 的預/後處理算子庫,演算法工程師可能最期待的是三點:夠快、夠通用、夠易用。 NVIDIA 與位元組跳動的機器學習團隊共同開發的 CV-CUDA 正好能滿足這三點,利用 GPU 並行運算能力提升算子速度,對齊OpenCV 操作結果足夠通用,對接 C /Python 介面足夠易用。
CV-CUDA的速度
##CV-CUDA的快,首先體現在高效的算子實現,畢竟是NVIDIA 寫的,CUDA 平行計算程式碼肯定經過大量的最佳化的。其次是它支援大量操作,這就能充分利用GPU設備的運算能力,相較於 CPU 上一張張影像串列執行,批量操作肯定是快很多的。最後,也得益於CV-CUDA 適配的 Volta、Turing、Ampere 等 GPU 架構,並在各 GPU 的 CUDA kernel 層面進行了效能上的高度最佳化,進而獲得最好的效果。也就是說,用的 GPU 卡越好,其加速能力越誇張。 如前文的背景模糊吞吐量加速比圖,如果採用CV-CUDA 取代 OpenCV 和 TorchVision 的前後處理後,整個推理流程的吞吐率提升20 多倍。其中預處理對影像做 Resize、Padding、Image2Tensor 等操作,後處理預測結果所做的Tensor2Mask、Crop、Resize、Denoise 等操作。
在同一個運算節點上(2x Intel Xeon Platinum 8168 CPUs,1x NVIDIA A100 GPU),以 30fps 的幀率處理 1080p 視頻,並採用不同 CV 庫所能支援的最大的平行流數。測試採用了 4 個進程,每個進程 batchSize 為 64。 對於單一算子的效能,NVIDIA和位元組跳動的小夥伴也做了效能測試,許多運算子在GPU 上的吞吐量都能達到 CPU 的百倍。
圖片大小為480*360,CPU 選擇為Intel(R) Core(TM) i9-7900X,BatchSize 大小為1,進程數為1
#儘管預/後處理算子很多都不是單純的矩陣乘法等運算,為了達到上述高效率的效能,CV-CUDA 其實做了許多算子層面的最佳化。例如採用大量的 kernel 融合策略,減少了 kernel launch 和 global memory 的存取時間;優化訪存以提升資料讀取和寫入效率;所有算子均採用非同步處理的方式,以減少同步等待的耗時等等。
CV-CUDA的通用與彈性
##運算結果的穩定,對於實際的工程可太重要了,就比如常見的 Resize 操作,OpenCV、OpenCV-gpu 以及 Torchvision 的實現方式都不一樣,那從訓練到部署,就會多很多工作量以對齊結果。 CV-CUDA在設計之初,就考慮到當前影像處理庫中,許多工程師習慣使用 OpenCV 的 CPU 版本,因此在設計算子時,不管是函數參數還是影像處理結果上,盡可能對齊 OpenCV CPU 版本的算符。因此從OpenCV 遷移到 CV-CUDA,只需要少量改變就能獲得一致的運算結果,模型也就不必要重新訓練。
此外,CV-CUDA是從算子層面設計的,因此不論模型的預/後處理流程是什麼樣的,其都能自由組合,具有很高的靈活性。
位元組跳動機器學習團隊表示,在企業內部訓練的模型多,需要的預處理邏輯也多種多樣有許多客製化的預處理邏輯需求。 CV-CUDA 的彈性確保每個 OP 都支援 stream 物件和顯存物件(Buffer和Tensor類,內部儲存了顯存指標)的傳入,以便更有彈性地配置對應的 GPU 資源。每個 op 設計開發時,既兼顧了通用性,也能按需提供客製化接口,能夠涵蓋圖片類預處理的各種需求。
CV-CUDA的易用
##可能很多工程師會想著,CV-CUDA 涉及到底層 CUDA 算子,那麼用起來應該比較費勁?但其實不然,即使不依賴更上層的 API,CV-CUDA本身底層也會提供 等結構體,提供Allocator 類,這樣在 C 上調起來也不麻煩。此外,往更上層,CV-CUDA 提供了 PyTorch、OpenCV 和 Pillow 的資料轉換介面,工程師能快速地以先前熟悉的方式進行算子替換與呼叫。 此外,因為CV-CUDA同時擁有 C 接口與 Python 接口,它能同時用於訓練與服務部署場景,在訓練時用Python 接口跟快速地驗證模型能力,在部署時利用C 接口進行更高效地預測。 CV-CUDA免於繁瑣的預處理結果對齊流程,並提高了整體流程的效率。
CV-CUDA進行 Resize 的 C 介面 實戰,
CV-CUDA如果我們在訓練過程中使用CV-CUDA的 Python 接口,那其實使用起來就會很簡單,只需要簡單幾步就能將原本在 CPU 上的預處理作業都遷移到 GPU 。 以圖片分類為例,基本上我們在預處理階段需要將圖片解碼為張量,並進行裁切以符合模型輸入大小,裁切完後還要將像素值轉換為浮點資料類型並做歸一化,之後傳到深度學習模型就能進行前向傳播了。以下我們將從一些簡單的程式碼區塊,體驗CV-CUDA 是如何對圖片進行預處理,如何與Pytorch互動。
常規影像辨識的預處理流程,使用CV-CUDA會將預處理過程與模型運算都統一放在GPU 上運作。 # 如下在使用 torchvision 的 API 載入圖片到 GPU之後,Torch Tensor 類型能直接透過 as_tensor 轉換為CV-CUDA 物件 nvcvInputTensor,這樣就能直接呼叫程式設定在 GPU 中完成影像的各種變換。 如下幾行程式碼將藉助 CV-CUDA 在 GPU 中完成影像辨識的預處理程序:裁切影像並對像素進行歸一化。其中resize() 將影像張量轉換為模型的輸入張量尺寸;convertto()將像素值轉換為單精確度浮點值;normalize()將歸一化像素值,以令取值範圍更適合模型進行訓練。 現在藉助 CV-CUDA 的各種 API,影像分類任務的預處理已經都做完了,其能有效率地在GPU 上完成並行計算,並且很方便地整合到PyTorch 這類主流深度學習架構的建模流程中。剩下的,只需要將CV-CUDA物件nvcvPreprocessedTensor 轉換為Torch Tensor 類型就能饋送到模型了,這一步同樣很簡單,轉換只需一行程式碼: #透過這個簡單的例子,很容易發現CV-CUDA 確實很容易就嵌入正常的模型訓練邏輯中。如果讀者希望了解更多的使用細節,還是可以查閱前文CV-CUDA的開源位址。 CV-CUDA實際上已經經過了實際業務上的檢驗。在視覺任務,尤其是影像有較複雜的預處理過程的任務,利用 GPU 龐大的算力進行預處理,能有效提神模型訓練與推理的效率。 CV-CUDA 目前在抖音團體內部的多個線上線下場景得到了應用,例如搜尋多模態,圖片分類等。 在位元組跳動 OCR 與視訊多模態任務上,透過使用CV-CUDA,整體訓練速度能提升 1 到 2 倍(注意:是模型整體訓練速度的提升) 在推理過程也一樣,位元組跳機學習團隊表示,在一個搜尋多模態任務中使用 CV-CUDA 後,整體的上線吞吐量比於用 CPU 做預處理時有了 2 倍多的提升。值得注意的是,這裡的 CPU基線結果本來就經過多核心高度最佳化,且此任務所涉及的預處理邏輯較簡單,但使用 CV-CUDA 之後加速效果依然非常明顯。
CV-CUDA 各種預處理操作的使用與 OpenCV 或 Torchvision中的沒有太大區別,只不過簡單調個方法,其背後就已經在 GPU 上完成運算了。
CV-CUDA對實際業務的提升
位元組跳機學習團隊表示,CV-CUDA 在內部的使用能顯著提升訓練與推理的表現。例如在訓練方面,位元組跳動一個視訊相關的多模態任務,其預處理部分既有多幀視訊的解碼,也有很多的資料增強,導致這部分邏輯很複雜。複雜的預處理邏輯導致 CPU 多核心表現在訓練時仍跟不上,因此採用CV-CUDA將所有 CPU 上的預處理邏輯遷移到 GPU,整體訓練速度獲得了 90%的加速。注意這可是整體訓練速度上的提升,而不只是預處理部分的提速。
速度上足夠高效以打破視覺任務中的預處理瓶頸,再加上使用也簡單靈活,CV-CUDA 已經證明了在實際應用場景中能很大程度地提升模型推理與訓練效果,所以要是讀者們的視覺任務同樣受限於預處理效率,那就試試最新開源的CV-CUDA吧。
以上是影像預處理庫CV-CUDA開源了,打破預處理瓶頸,提升推理吞吐量20多倍的詳細內容。更多資訊請關注PHP中文網其他相關文章!