博客 / 詳情

返回

流式數據集:效率提升 100 倍!

快速瞭解(TLDR)

現在只需一行代碼,就能通過 load_dataset('dataset', streaming=True) 以流式方式加載數據集,無需下載!

無需複雜配置、不佔磁盤空間、不再擔心 “磁盤已滿” 或 429 請求過多錯誤,立即開始訓練 TB 級數據集!
性能非常強勁:在 64×H100、256 個併發 worker 環境下,流式加載速度甚至超過本地 SSD!
我們優化後的流式系統:請求數減少 100 倍 → 數據解析速度提升 10 倍 → 樣本處理速度翻倍 → 即使在 256 個併發 worker 下也 0 崩潰。

數據流式加載可視化

在機器學習中,特別是在處理 TB 級別的數據時,數據加載一直是個大難題。我們自己在訓練 SmolLM3 時也深有體會,有段時間每次訓練前都得等上 3 小時下載數據。

雖然 datasets 庫早就支持流式加載,但在大規模訓練中依然面臨瓶頸。今天,這一切都變了 🔥。我們花了幾個月優化後端,全面提升流式數據集的速度與效率。

那我們到底做了哪些優化?⤵️

一樣簡單的 API,更強大的性能

首先最重要的一點:改進後的接口依然兼容原來的用法。你只需要加上 streaming=True,就能流式加載 Hugging Face 上的任意數據集,依舊簡單直接。🚀

from datasets import load_dataset

# Stream a dataset instead of downloading it
dataset = load_dataset("HuggingFaceM4/FineVisionMax", split="train", streaming=True)
# Get the first example
print(next(iter(dataset)))

全球成千上萬的 AI 開發者每天都在使用 datasets,現在他們無需改動任何代碼,就能直接享受到更高的性能。

問題挑戰:大規模流式加載

流式加載一直是快速瞭解數據集的好方法,但在訓練模型時,大多數人仍然選擇將數據預先下載到本地,或使用 S3 等雲存儲——我們在訓練 SmolVLM 時也是這麼做的。

我們希望改變這種情況,於是在開發 nanoVLM 時,嘗試直接從 Hugging Face Hub 進行流式讀取。

但很快就遇到一個嚴重問題:一次測試運行在不到一分鐘的時間內發出了超過 10 萬個請求,結果我們的 IP 被 Hub 屏蔽了!😅

問題的根源在於:每個 DataLoader 的 worker 都在獨立初始化數據集,這導致大量冗餘請求,形成了“請求風暴”,其中大部分其實是沒必要的。

於是我們對啓動邏輯進行了深度優化,最終將啓動請求量減少了 100 倍。總體性能提升如下:

  • 數據文件解析速度:提升 10 倍
  • 啓動請求效率:提高最多 100 倍
  • 流式速度:提升最多 2 倍
  • 在途請求效率:提升最多 2 倍

技術揭秘:我們具體改了什麼?

我們主要優化了兩個階段:啓動階段流式加載階段

1. 啓動優化 ⚡️

初始的數據文件解析階段會觸發大量請求。我們進行了以下兩項關鍵優化:

  • 持久化數據文件緩存:現在所有 DataLoader worker 會共享數據文件列表緩存。第一個 worker 從 Hub 獲取文件列表,其餘 worker 直接從本地緩存中讀取,從而幾乎完全消除啓動階段的請求,大幅縮短加載時間,徹底告別“請求風暴”。

  • 優化文件解析邏輯:我們精簡了初始 worker 向 Hub 請求文件列表的 API 調用數量,將多個請求進行打包處理,進一步降低啓動延遲

2. 流式加載優化 🏎️

為了提升訓練過程中的流式吞吐量,我們新增了兩個關鍵功能:

  • Parquet 數據預取(Prefetching):我們為 Parquet 格式的數據集啓用了預取功能。這意味着,在模型處理當前數據塊的同時,datasets 庫會在後台提前加載下一塊數據。這樣可以讓整個數據管道始終保持“滿負荷”,確保 GPU 不會因等待數據而處於空閒狀態,大大提升訓練效率。

  • 可配置緩衝機制(Buffering):針對高級用户,我們開放了緩衝區的配置參數,支持自定義設置預取數量和數據塊大小,方便根據自身硬件和網絡情況進行 I/O 優化。

以下是如何將默認流式請求大小從 32MiB 提升到 128MiB,並啓用預取的示例代碼:

import pyarrow
import pyarrow.dataset

fragment_scan_options = pyarrow.dataset.ParquetFragmentScanOptions(
    cache_options=pyarrow.CacheOptions(
        prefetch_limit=1,
        range_size_limit=128 << 20
    ),
)
ds = load_dataset(parquet_dataset_id, streaming=True, fragment_scan_options=fragment_scan_options)

通過這些優化,你的數據加載速度可以提升一倍,訓練效率更高!

為什麼比 S3 還快?背後是 Xet 技術

Hugging Face 使用了 Xet 存儲系統:這是一種去重式存儲方案,上傳和下載速度極快。與傳統遠程存儲不同,Xet 會跳過重複數據,只傳輸獨特內容。

比如,在 Hugging Face 上傳大型數據集時,Xet 的去重機制大幅減少了數據傳輸量,上傳更快;數據一上傳完,就可以立即開始流式讀取。

對於 Parquet 文件,Xet 利用 Parquet 內容定義切塊(CDC) 來實現去重,進一步加快傳輸速度。

此外,我們還推出了 pyspark_huggingface 包,支持 Spark 直接讀寫 HF 數據集,內置對 Parquet CDC 和 Xet 的支持,大幅加快大數據處理。

想自定義流式管道?可以!

有些數據格式 datasets 庫還不支持,或者你希望獲得更高的控制權,我們也提供了強大的自定義流式能力。

huggingface_hub 庫中的 HfFileSystem 可高效讀取遠程數據集文件:

from huggingface_hub import HfFileSystem

path = f"hf://datasets/{dataset_id}/{path_in_repo}"
with HfFileSystem().open(path) as f:
    # loop with .read() or .readline() to stream data
    # or do random access with .seek()

HfFileSystem 傳入 PyTorch 的 DataLoader 時,會複用 .ls().glob() 的緩存結果,從而避免在列舉數據文件時產生額外的網絡請求,進一步提升流式加載的效率和穩定性。

極限測試:我們把它用在 nanoVLM 上了!

目前我們正在使用這些流式優化功能訓練下一代 SmolVLM 模型。得益於新改進,流式加載比我們集羣上的多層硬盤系統還要快,幾乎等同於從本地 SSD 讀取數據的速度

過去,為了避免慢速網絡,我們還要把數據拷貝到本地 SSD——整個過程花費 3 小時。而現在,直接流式加載,訓練馬上開始!

更多細節請看:nanoVLM GitHub

快速上手,立見成效

這些強大的新功能已經集成到 datasetshuggingface_hub 庫中。想要體驗全新的流式加載性能,只需升級你的庫版本,並查閲官方文檔即可開始使用:

pip install --upgrade datasets huggingface_hub

為慶祝這一更新,我們已將 FineVision 所有數據源合併並預先打亂成一個統一數據集:FineVisionMax。你可以直接用它來訓練 VLM 模型,無需手動處理多個數據集!

from datasets import load_dataset

# Stream a dataset instead of downloading it
dataset = load_dataset("HuggingFaceM4/FineVisionMax", split="train", streaming=True)
# Get the first example
print(next(iter(dataset)))

想了解我們是如何大規模運行的?歡迎查看:nanoVLM 項目

祝你流式加載愉快!🤗

英文原文: https://huggingface.co/blog/streaming-datasets

原文作者: Andres Marafioti, Quentin Lhoest, ben burtenshaw, Pedro Cuenca, merve

譯者: Luke, Hugging Face Fellow

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.