• <xmp id="om0om">
  • <table id="om0om"><noscript id="om0om"></noscript></table>
  • 數據科學

    RAPIDS 與 Dask 結合實現多 GPU 數據分析的高效實踐指南

    隨著我們向更密集的計算基礎設施邁進,擁有更多的計算、更多的 GPU、加速網絡等,多 GPU 訓練和分析變得越來越流行。隨著開發者和從業者從 CPU 集群轉向 GPU 集群,我們需要工具和最佳實踐。RAPIDS 是一套開源的 GPU 加速數據科學和 AI 庫。借助 Spark Dask 等工具,這些庫可以輕松地針對更大的工作負載進行橫向擴展。本博文簡要概述了 RAPIDS Dask,并重點介紹了多 GPU 數據分析的三種最佳實踐。

    在使用 GPU 實現最高性能時,用戶通常會面臨內存壓力和穩定性問題。雖然 GPU 在計算方面比 CPU 更強大,但與系統內存相比,GPU 的內存通常更少。例如,GPU 工作負載通常在核外場景中執行,此時 GPU 內存小于一次處理工作負載所需的內存總量。此外,CUDA 生態系統提供了 多種類型的內存 ,用于不同的目的和應用。

    Dask 是什么?

    Dask 是一個高度靈活的開源分布式 Python 庫。 Dask 可以幫助擴展復雜的自定義 Python 代碼,但更重要的是,它可以使用 Dask-Array Dask-Dataframe 擴展數組和 Dataframe 工作負載。 RAPIDS 使用 Dask-DataFrame 幫助擴展 GPU ETL 和 ML 工作負載,例如 Dask-cuDF 和 cuML/XGBoost,并采用類似 Pandas 的界面。

    df = dd.read_parquet("/my/parquet/dataset/")
    agg = df.groupby('B').sum()
    agg.compute()

    適用于 CPU 和 GPU 的 Dask 最佳實踐?

    Dask 的眾多優勢之一是用戶可以同時面向 CPU 和 GPU 后端 。然而,開發兩個代碼庫(一個用于 CPU,另一個用于 GPU)非常耗時且難以維護。Dask 支持在 CPU 和 GPU 后端之間輕松切換。

    與 PyTorch 配置設備的機制類似:

    device = 'cuda' if torch.cuda.is_available() else 'cpu'

    Dask 還可以配置后端目標:

    # GPU Backends
    dask.config.set({"array.backend": "cupy"})
    dask.config.set({"dataframe.backend": "cudf"})
     
    # CPU Backends
    dask.config.set({"array.backend": "numpy"})
    dask.config.set({"dataframe.backend": "pandas"})
     
    # Configure with Environment Variables
    DASK_DATAFRAME__BACKEND=cudf

    現在,我們可以輕松開發代碼,而無需調用 特定的 后端 I/O 指令,也無需以與硬件無關的方式編寫分布式 Python 分析代碼:

    # Dataframe Example with
    dask.config.set({“dataframe.backend”: “cudf”}):    
        ddf = dd.read_parquet('example.parquet')    
        res = ddf.groupby("col").agg({'stats': ['sum', 'min', 'mean']})
        res.compute()

    通過使用這種簡單的 CPU/GPU 設置,Dask-RAPIDS 用戶可以輕松地針對這兩種設備進行開發,而不會產生任何開發開銷。更完整的示例是, NeMo 中的數據管護框架通過此機制支持 CPU/GPU 部署

    集群和內存配置?

    數據工作流既是計算密集型應用,也是內存密集型應用。配置和管理分布式應用程序使用內存的方式可能意味著完成作業與失敗之間的區別。如果不使用“正確的”內存,工作流程很容易導致性能損失,甚至更糟糕的是,由于內存不足(OOM)錯誤而導致故障。挑選“正確”的內存并配置分布式系統具有挑戰性,通常需要高水平的專業知識,并且可能需要進行耗時的基準測試。在對性能和內存分配/碎片進行多次實驗后,我們發現以下配置是各種基于表格的工作負載(例如常見的 ETL(過濾器、連接、聚合等)和重復數據刪除(NeMo Curator))的良好起點。

    dask cuda worker  <SCHEDULER:IP> --rmm-async  --rmm-pool-size <POOL_SIZE>  --enable-cudf-spill

    使用 RMM 選項:rmm-asyncrmm-pool-size 可以顯著提高性能和穩定性。

    rmm-async 使用底層 cudaMallocAsync 內存分配器,可大大減少內存碎片,但性能成本微乎其微。內存碎片很容易導致 OOM 錯誤。如需深入了解,請參閱 CUDA 流有序內存分配器 博客系列的 第 1 部分 第 2 部分

    rmm-pool-size 參數預先分配 GPU 上的 GPU 內存池。與原始 CUDA 分配 (直接 cudaMalloc) 相比,通過預分配內存池,進行子分配的性能顯著提升。這在很大程度上是由于 GPU 內存分配和銷毀 (free) 的成本相當高,而且對于數據應用,在工作流中可能會進行成千上萬 (如果不是數百萬) 的 alloc/free 調用,并且總體而言會降低性能。

    將數據從設備轉移到主機,即“溢出”功能不僅僅是實現一次。溢出通常可以實施,但通常會犧牲性能。Dask-CUDA 和 cuDF 有幾種 溢出機制 device-memory-limitmemory-limitjit-unspillenable-cudf–spillenable-cudf-spill 支持 cuDF 內部 溢出到主機內存 的功能。cuDF 的內部溢出機制將在對象或中間產品所需的內存超過 GPU 可用內存時,將數據(cuDF 緩沖區)從設備移至主機。我們發現,對于基于表格的工作負載,與其他 Dask-CUDA 選項(包括 --device-memory-limit)相比,使用 enable-cudf-spill 通常更快、更穩定。

    加速網絡?

    如上所述,密集多 GPU 系統通過 NVLink 使用加速網絡進行架構設計。借助 Grace Blackwell 和最新的 NVLink ,我們可以獲得 900 GB/s 的雙向帶寬。常見的 ETL 例程,如 join、shuffle 等,需要在多臺設備上移動數據——CPU 和 GPU 之間的溢出對于核外算法也至關重要。在這些密集系統上使用 NVLink 對于實現更高的性能至關重要。這些硬件系統可以在啟用 UCX 的 Dask 中輕松啟用:

    # Single Node Cluster
    cluster = LocalCUDACluster(protocol="ucx")
     
     
    # CLI
    dask-cuda-worker <SCHEDULER_IP> --protocol ucx

    結束語

    通過為 Dask CUDA 工作器配置最佳內存設置并啟用 UCX 加速網絡,用戶可以實現穩定的核外 GPU 計算和最大性能。此外,通過使用 Dask 的數組和 dataframe 后端選項,可以輕松實現對 CPU 和 GPU 等多硬件后端的支持。

    有關如何更好地使用 Dask RAPIDS 的文檔和其他詳細信息,我們建議您閱讀 Dask-cuDF Dask-CUDA 最佳實踐 文檔。

    ?

    0

    標簽

    人人超碰97caoporen国产