深度學(xué)習(xí)模型需要使用大量數(shù)據(jù)進(jìn)行培訓(xùn),以獲得準(zhǔn)確的結(jié)果。由于各種原因,例如不同的存儲格式、壓縮、數(shù)據(jù)格式和大小,以及高質(zhì)量數(shù)據(jù)的數(shù)量有限,原始數(shù)據(jù)通常無法直接輸入神經(jīng)網(wǎng)絡(luò)。
解決這些問題需要大量的數(shù)據(jù)準(zhǔn)備和預(yù)處理步驟,從加載、解碼、解壓縮到調(diào)整大小、格式轉(zhuǎn)換和各種數(shù)據(jù)擴(kuò)充。
深度學(xué)習(xí)框架,如 TensorFlow 、 PyTorch 、 MXNet 等,為一些預(yù)處理步驟提供了本地實現(xiàn)。由于使用特定于框架的數(shù)據(jù)格式、轉(zhuǎn)換的可用性以及不同框架之間的實現(xiàn)差異,這通常會帶來可移植性問題。
CPU 瓶頸
直到最近,深度學(xué)習(xí)工作負(fù)載的數(shù)據(jù)預(yù)處理才引起人們的關(guān)注,因為訓(xùn)練復(fù)雜模型所需的巨大計算資源使其黯然失色。因此,由于 OpenCV 、 Pillow 或 Librosa 等庫的簡單性、靈活性和可用性,預(yù)處理任務(wù)通常用于在 CPU 上運(yùn)行。
NVIDIA 伏特和 NVIDIA 安培體系結(jié)構(gòu)中引入的 GPU 體系結(jié)構(gòu)的最新進(jìn)展顯著提高了深度學(xué)習(xí)任務(wù)中的 GPU 吞吐量。特別是,半精度算法與張量核加速某些類型的 FP16 矩陣計算,這對培訓(xùn)DNNs非常有用。密集的多 GPU 系統(tǒng),如 NVIDIA DGX-2和DGX A100訓(xùn)練模型的速度遠(yuǎn)遠(yuǎn)快于輸入管道提供的數(shù)據(jù),使 GPU 缺少數(shù)據(jù)。
今天的 DL 應(yīng)用程序包括由許多串行操作組成的復(fù)雜、多階段的數(shù)據(jù)處理管道。依賴 CPU 處理這些管道會限制性能和可擴(kuò)展性。在圖 1 中,可以觀察到數(shù)據(jù)預(yù)處理對 ResNet-50 網(wǎng)絡(luò)訓(xùn)練吞吐量的影響。在左側(cè),我們可以看到在 CPU 上運(yùn)行的用于數(shù)據(jù)加載和預(yù)處理的框架工具時網(wǎng)絡(luò)的吞吐量。在右側(cè),我們可以看到相同網(wǎng)絡(luò)的性能,而不受數(shù)據(jù)加載和預(yù)處理的影響,用合成數(shù)據(jù)替換。當(dāng)比較不同的數(shù)據(jù)預(yù)處理工具時,這種測量可以用作理論上限。
圖 1 : ResNet-50 網(wǎng)絡(luò)的數(shù)據(jù)預(yù)處理對總體訓(xùn)練吞吐量的影響。
大理來營救
NVIDIA 數(shù)據(jù)加載庫( DALI )是我們致力于為上述數(shù)據(jù)管道問題找到可擴(kuò)展和可移植解決方案的結(jié)果。 DALI 是一組高度優(yōu)化的構(gòu)建塊和執(zhí)行引擎,用于加速深度學(xué)習(xí)( DL )應(yīng)用程序的輸入數(shù)據(jù)預(yù)處理(見圖 2 )。 DALI 為加速不同的數(shù)據(jù)管道提供了性能和靈活性。
圖 2 : DALI 概述及其在 DL 應(yīng)用程序中作為加速數(shù)據(jù)加載和預(yù)處理工具的使用。
DALI 為各種深度學(xué)習(xí)應(yīng)用程序(如分類或檢測)提供數(shù)據(jù)處理原語,并支持不同的數(shù)據(jù)域,包括圖像、視頻、音頻和體積數(shù)據(jù)。
支持的輸入格式包括最常用的圖像文件格式( JPEG 、 PNG 、 TIFF 、 BMP 、 JPEG2000 、 NETPBM )、 NumPy 陣列、使用多種編解碼器編碼的視頻文件( H 。 264 、 HEVC 、 VP8 、 VP9 、 MJPEG )以及音頻文件( WAV 、 OGG 、 FLAC )。
DALI 的一個重要特性是插件,它可以作為框架本機(jī)數(shù)據(jù)集的插入式替換。目前, DALI 帶有 MxNET PyTorch 、 TensorFlow 和 PaddlePaddle 的插件。只要使用不同的數(shù)據(jù)迭代器包裝器,就可以一次性定義 DALI 管道,并與任何受支持的框架一起使用。
除此之外, DALI 本機(jī)支持特定框架中使用的不同存儲格式(例如, Caffe 和 Caffe2 中的 LMDB 、 MXNet 中的 RecordIO 、 TensorFlow 中的 TFRecord )。這允許我們使用任何受支持的數(shù)據(jù)格式,而不管使用的是何種 DL 框架。例如,我們可以對模型使用 MXNet ,同時將數(shù)據(jù)保存在 TFRecord (原生 TensorFlow 數(shù)據(jù)格式)中。
通過在 Python 中配置外部數(shù)據(jù)源,或使用自定義運(yùn)算符進(jìn)行擴(kuò)展,可以輕松地為特定項目定制 DALI 。最后,DALI是一個開源項目,因此您可以輕松地對其進(jìn)行擴(kuò)展和調(diào)整,以滿足您的特定需求。
大理關(guān)鍵概念
DALI 中的主要實體是數(shù)據(jù)處理pipeline。管道由operators連接的數(shù)據(jù)節(jié)點的符號圖定義。每個操作符通常獲得一個或多個輸入,應(yīng)用某種數(shù)據(jù)處理,并產(chǎn)生一個或多個輸出。有一些特殊類型的運(yùn)算符不接受任何輸入并產(chǎn)生輸出。這些特殊操作符就像一個數(shù)據(jù)源——讀卡器、隨機(jī)數(shù)生成器和外部_源都屬于這一類。管道定義在 Python 中使用命令式語言表示,與當(dāng)前大多數(shù)深度學(xué)習(xí)框架一樣,但以異步方式運(yùn)行。
構(gòu)建完成后,管道實例可以通過調(diào)用管道的 run 方法顯式運(yùn)行,也可以使用特定于目標(biāo)深度學(xué)習(xí)框架的數(shù)據(jù)迭代器包裝。
DALI 為各種處理操作員提供 CPU 和 GPU 實現(xiàn)。 CPU 或 GPU 實現(xiàn)的可用性取決于運(yùn)營商的性質(zhì)。確保檢查文檔中是否有支持的操作的最新列表,因為每個版本都會對其進(jìn)行擴(kuò)展。
DALI 運(yùn)營商要求將輸入數(shù)據(jù)放置在與運(yùn)營商后端相同的設(shè)備上。具有混合后端的運(yùn)算符是一種特殊類型的運(yùn)算符,用于接收 CPU 內(nèi)存中的輸入和 GPU 內(nèi)存中的輸出數(shù)據(jù)。出于性能原因,無法訪問 DALI 管道中從 GPU 到 CPU 內(nèi)存的數(shù)據(jù)傳輸。
雖然 DALI 的大部分好處是在將處理卸載到 GPU 時實現(xiàn)的,但有時在 CPU 上保持部分操作運(yùn)行是有益的。特別是在 CPU 與 GPU 比率較高的系統(tǒng)中,或在 GPU 完全被模型占用的情況下。用戶可以嘗試 CPU / GPU 位置,以逐個找到最佳位置。
圖 3 : DALI 管道的示例。數(shù)據(jù)加載到 CPU 上,然后使用混合后端操作符進(jìn)行解碼,該操作符在 GPU 內(nèi)存上輸出解碼圖像,然后在 GPU 上對其進(jìn)行大小調(diào)整和擴(kuò)充。
如前所述, DALI 的執(zhí)行是異步的,這允許數(shù)據(jù)預(yù)取,也就是說,在請求批數(shù)據(jù)之前提前準(zhǔn)備批數(shù)據(jù),以便框架始終為下一次迭代準(zhǔn)備好數(shù)據(jù)。 DALI 使用可配置的預(yù)取隊列長度為用戶透明地處理數(shù)據(jù)預(yù)取。數(shù)據(jù)預(yù)取有助于隱藏預(yù)處理的延遲,當(dāng)處理時間在迭代中發(fā)生顯著變化時,這一點很重要(見圖 4 )。
圖 4 :數(shù)據(jù)預(yù)取示例,預(yù)取隊列深度為 2 。較長迭代(第 4 批)的延遲因提前計算而被隱藏。
如何使用大理
定義 DALI 管道的最簡單方法是使用pipeline_def Python 裝飾器。為了創(chuàng)建管道,我們定義了一個函數(shù),在該函數(shù)中實例化并連接所需的運(yùn)算符,并返回相關(guān)的輸出。然后用pipeline_def來裝飾它。
from nvidia.dali import pipeline_def, fn
@pipeline_def
def simple_pipeline():
jpegs, labels = fn.readers.file(file_root=image_dir,
random_shuffle=True,
name="Reader")
images = fn.decoders.image(jpegs)
return images, labels
在這個示例管道中,沒有什么值得注意的事情。第一個操作符是文件讀取器,它發(fā)現(xiàn)并加載目錄中包含的文件。讀取器輸出文件的內(nèi)容(在本例中為編碼的 JPEG )和從目錄結(jié)構(gòu)推斷的標(biāo)簽。我們還啟用了隨機(jī)洗牌并為 reader 實例命名,這在稍后與框架迭代器集成時非常重要。第二個運(yùn)算符是圖像解碼器。
下一步是實例化simple_pipeline對象并構(gòu)建它以實際構(gòu)建圖形。在管道實例化過程中,我們還定義了批大小、用于數(shù)據(jù)處理的 CPU 線程數(shù)以及 GPU 設(shè)備序號。
pipe = simple_pipeline(batch_size=32, num_threads=3, device_id=0)
pipe.build()
此時,管道已準(zhǔn)備好使用。我們可以通過調(diào)用 run 方法獲得一批數(shù)據(jù)。
images, labels = pipe.run()
現(xiàn)在,讓我們添加一些數(shù)據(jù)增強(qiáng),例如,以隨機(jī)角度旋轉(zhuǎn)每個圖像。要生成隨機(jī)角度,我們可以使用random.uniform
,并旋轉(zhuǎn)rotation
:
@pipeline_def()
def rotate_pipeline():
jpegs, labels = fn.readers.file(file_root=image_dir,
random_shuffle=True,
name="Reader")
images = fn.decoders.image(jpegs)
angle = fn.random.uniform(range=(-10.0, 10.0))
rotated_images = fn.rotate(images, angle=angle, fill_value=0)
return rotated_images, labels
將計算卸載到 GPU
我們現(xiàn)在可以修改我們的簡單_管道,以便它使用.gpu()執(zhí)行擴(kuò)充。 DALI 使這種轉(zhuǎn)變非常容易。唯一改變的是rotate運(yùn)算符的定義。我們只需要將device參數(shù)設(shè)置為“gpu”,并確保通過調(diào)用 GPU 將其輸入傳輸?shù)?GPU 。
self.rotate = fn.rotate(images.gpu(), angle=angle, device="gpu")
為了使事情更簡單,我們甚至可以省略device
參數(shù),讓 DALI 直接從輸入位置推斷出運(yùn)算符。
self.rotate = fn.rotate(images.gpu(), angle=angle)
也就是說,simple_pipeline
現(xiàn)在在 GPU 上執(zhí)行旋轉(zhuǎn)。請記住,生成的圖像也會分配到 GPU 內(nèi)存中,這通常是我們想要的,因為模型需要 GPU 內(nèi)存中的數(shù)據(jù)。在任何情況下,運(yùn)行管道后將數(shù)據(jù)復(fù)制回 CPU 內(nèi)存都可以通過調(diào)用Pipeline.run
返回的對象as_cpu
輕松實現(xiàn)。
images, labels = pipe.run()
images_host = images.as_cpu()
框架集成
與不同深度學(xué)習(xí)框架的無縫互操作性代表了 DALI 的最佳功能之一。例如,要將您的管道與 PyTorch 模型一起使用,我們可以通過使用DALIClassificationIterator包裝它來輕松實現(xiàn)。對于更一般的情況,例如任意數(shù)量的管道輸出,請使用DALIGenericIterator。
from nvidia.dali.plugin.pytorch import DALIGenericIterator
train_loader = DALIClassificationIterator([pipe], reader_name='Reader')
注意參數(shù)reader_name
,該值與reader
實例的 name 參數(shù)匹配。迭代器將使用該讀取器作為一個歷元中樣本數(shù)的信息源。
我們現(xiàn)在可以枚舉train_loader
實例并將數(shù)據(jù)批提供給模型。
for i, data in enumerate(train_loader):
images = data[0]["data"]
target = data[0]["label"].squeeze(-1).long()
# model training
關(guān)于框架集成的更多信息可以在文檔的框架插件部分中找到。
推理中的達(dá)利
為訓(xùn)練和推理提供數(shù)據(jù)處理步驟的等效定義對于獲得良好的精度結(jié)果至關(guān)重要。多虧了 NVIDIA Triton 推理服務(wù)器及其專用的大理后端,我們現(xiàn)在可以輕松地將 DALI 管道部署到推理應(yīng)用程序,使數(shù)據(jù)管道完全可移植。在圖 6 所示的體系結(jié)構(gòu)中, DALI 管道作為 Triton 集成模型的一部分進(jìn)行部署。這種配置有兩個主要優(yōu)點。首先,數(shù)據(jù)處理是在服務(wù)器中執(zhí)行的,通常是一臺比客戶機(jī)功能更強(qiáng)大的機(jī)器。第二個好處是數(shù)據(jù)可以被壓縮后發(fā)送到服務(wù)器,這節(jié)省了網(wǎng)絡(luò)帶寬。
圖 6 : DALI 在推理配置中,帶有 NVIDIA Triton 推理服務(wù)器和用于服務(wù)器端預(yù)處理的 DALI 后端。
請務(wù)必查看我們的專用文章使用 NVIDIA Triton 推理服務(wù)器和 NVIDIA DALI 加速推理,詳細(xì)介紹此主題。
達(dá)利對績效的影響
NVIDIA 展示了 DALI 對 SSD 、 ResNet-50 和 RNN-T 的實現(xiàn),這是我們的MLPerf基準(zhǔn)成功中的一個促成因素。
讓我們比較一下使用 DALI 和使用框架的本機(jī)解決方案時 ResNet-50 網(wǎng)絡(luò)的訓(xùn)練吞吐量。在圖 7 中,我們可以看到與圖 1 中所示類似的比較,這一次顯示了將 DALI 作為選項之一用于數(shù)據(jù)加載和預(yù)處理的結(jié)果。我們可以看到 DALI 的訓(xùn)練吞吐量如何更接近理論上限(合成示例)。
圖 7 : ResNet-50 網(wǎng)絡(luò)不同預(yù)處理方法的訓(xùn)練性能比較。
現(xiàn)在讓我們看看 DALI 如何影響 Triton 服務(wù)器中 Resnet50 推理的性能。圖 8 顯示了脫機(jī)預(yù)處理的平均推斷請求延遲,這意味著在啟動請求之前數(shù)據(jù)已經(jīng)過預(yù)處理,以及聯(lián)機(jī)服務(wù)器端預(yù)處理。所花費的時間細(xì)分為通信開銷、數(shù)據(jù)預(yù)處理和模型推理。由于解碼數(shù)據(jù)的大小較大,預(yù)處理請求的延遲會受到通信開銷的嚴(yán)重影響。因此,服務(wù)器端預(yù)處理比離線預(yù)處理快,即使前者在度量中包含數(shù)據(jù)預(yù)處理時間。
圖 8 : Resnet50 模型推斷的平均請求延遲(越低越好)比較。這些數(shù)字是使用 NVIDIA / Triton 服務(wù)器在 DGX A100 機(jī)器上使用單個 GPU 收集的: 21 。 07-py3 容器。
今天就從 DALI 開始吧
您可以下載預(yù)構(gòu)建和測試的 DALI pip 包的最新版本。]:、MXNetMXNet的 NVIDIA GPU 云( NGC )容器已集成 DALI 。您可以查看許多examples并閱讀最新的發(fā)行說明,以獲取新功能和增強(qiáng)功能的詳細(xì)列表。
關(guān)于作者
Joaquin Anton Guirao 是 NVIDIA 深度學(xué)習(xí)框架團(tuán)隊的高級軟件工程師,專注于 NVIDIA DALI
Rafal Banas 是 NVIDIA 的軟件開發(fā)工程師。他致力于 DALI 項目,專注于推理用例。拉法在華沙大學(xué)獲得計算機(jī)科學(xué)學(xué)士學(xué)位。
Krzysztof ??cki 是 NVIDIA 的高級軟件開發(fā)工程師,在 DALI 工作。他以前的工作包括為 GPU 和 SIMD 體系結(jié)構(gòu)編寫高度優(yōu)化的數(shù)據(jù)處理代碼,重點關(guān)注計算機(jī)視覺和圖像處理應(yīng)用。
Janusz Lisiecki 是 NVIDIA 的深度學(xué)習(xí)經(jīng)理,致力于快速數(shù)據(jù)管道。他過去的經(jīng)驗涵蓋從面向大眾消費市場的嵌入式系統(tǒng)到高性能硬件軟件數(shù)據(jù)處理解決方案。
Albert Wolant 是軟件開發(fā)工程師,在 NVIDIA 的 DALI 團(tuán)隊工作。他在深度學(xué)習(xí)和 GP GPU 軟件開發(fā)方面都有經(jīng)驗。他在并行算法和數(shù)據(jù)結(jié)構(gòu)方面做了一些研究工作。
Micha? Zientkiewicz 是 NVIDIA 的高級軟件工程師,目前正在開發(fā) DALI 。他的專業(yè)背景包括 GPU 編程、圖像處理和編譯器開發(fā)。米莎先生在華沙工業(yè)大學(xué)獲得計算機(jī)科學(xué)碩士學(xué)位。
Kamil Tokarski 是 NVIDIA 的軟件工程師,在 DALI 團(tuán)隊工作,熱衷于深度學(xué)習(xí)和密碼學(xué)。
Micha? Szo?ucha 是 NVIDIA 的軟件工程師,從事圖像處理和深度學(xué)習(xí)項目。曾與移動 3D 技術(shù)合作。熱衷于使波蘭民間傳說適應(yīng)現(xiàn)代接受者的認(rèn)知。
審核編輯:郭婷
-
gpu
+關(guān)注
關(guān)注
28文章
4753瀏覽量
129065 -
python
+關(guān)注
關(guān)注
56文章
4799瀏覽量
84817 -
深度學(xué)習(xí)
+關(guān)注
關(guān)注
73文章
5507瀏覽量
121292
發(fā)布評論請先 登錄
相關(guān)推薦
評論