Hub documentation

处理大型数据集

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

处理大型数据集

每个 Job 都配有固定大小的本地磁盘,由其 硬件规格(即 Ephemeral Storage 列,也可通过 hf jobs hardware 查看)决定。您无需将整个数据集放入该磁盘才能进行处理:数据集和 Storage Buckets 可以直接从 Hub 读取——支持流式读取、查询或挂载——因此单个 Job 可以处理远超其磁盘容量的数据。本页将介绍这些选项以及各自的适用场景。

选择哪种方法?

  • 可放入磁盘 → 直接运行普通的 load_dataset(...) 即可(或者选择更大的规格——最高支持 1 TB 的临时磁盘)。
  • 逐行迭代、处理或训练 → 将其 stream 化。
  • 经过过滤或列裁剪的扫描 → 使用 Polars 或 DuckDB 直接在 hf:// 上查询。
  • 期望本地文件路径的工具 → 挂载 该仓库并延迟读取。
  • 持久化结果 → 将其写入 Storage Bucket,以便在 Job 结束后仍然保留。

流式传输数据集

流式读取会在代码消费示例时从 Hub 获取数据——无需下载,无需本地副本,并且可扩展至多 TB 数据集。最近的版本使其效率提高了多达 100 倍,在跨多个工作进程进行训练时,性能可与本地 SSD 相媲美:

from datasets import load_dataset

ds = load_dataset("HuggingFaceFW/fineweb-edu", "sample-10BT", split="train", streaming=True)
for example in ds.take(1000):
    ...  # streams in as you iterate, nothing hits disk

流式数据集是一种 IterableDataset,支持惰性 .filter()、.map()、.shuffle(buffer_size=...) 和 .batch(),可以直接传递给 PyTorch DataLoader 或 Trainer,用于训练比磁盘容量更大的数据。完整的 API 请参阅 Stream 指南,单节点或分布式环境的端到端训练教程请参阅 示例与教程。

在分布式环境中,使用 Spark 也可以实现流式处理:

import pyspark_huggingface

df = spark.read.format("huggingface").option("config", "sample-10BT").load("HuggingFaceFW/fineweb-edu")

生成的 Spark 数据帧是分布式的:每个工作节点从自己的文件子集中进行流式读取。有关读取、写入以及高效过滤行和列的示例,请参阅 Spark 文档。

在 hf:// 上读取和过滤

许多数据库可以直接通过 hf:// 路径读取 Hub 数据集——Polars、DuckDB 和 pandas 均能原生扫描 Hub Parquet,并将过滤条件和列选择下推至扫描层,因此单个 Job 可处理远超内存或磁盘容量的数据。以下查询在默认 CPU 配置下,约四分钟即可汇总约 28 GB 的 Parquet 数据:

import polars as pl

agg = (
    pl.scan_parquet("hf://datasets/HuggingFaceFW/fineweb-edu/sample/10BT/*.parquet")
    .filter(pl.col("int_score") >= 4)
    .group_by("int_score")
    .agg(pl.len().alias("docs"), pl.col("token_count").sum().alias("tokens"))
    .sort("int_score")
    .collect()
)
print(agg)

此类扫描受网络限制而非内存限制,且各引擎在并行化远程读取方面的激进程度不同,因此耗时因库而异。两个实用建议:对于长时间扫描,请将 --timeout 设置为高于默认的 30 分钟;并将工作拆分到多个并行运行的 Job 中以提升速度。请参阅 Polars、DuckDB 和 pandas 获取各库的示例,以及 Python data tools 了解如何通过 hf:// 读取 buckets(该方式经由 HfFileSystem 处理)。

挂载数据集、模型或存储桶

使用 -v / --volume 将仓库或存储桶挂载到 Job 的本地路径;文件会在代码读取时通过网络按需获取,因此任何读取本地文件的工具都能直接使用:

hf jobs uv run --flavor cpu-upgrade \
  -v hf://datasets/HuggingFaceFW/fineweb-edu:/mnt/data \
  process.py
# /// script
# dependencies = ["polars"]
# ///
# process.py — the mounted repo is just a directory of files
from pathlib import Path

import polars as pl

for path in Path("/mnt/data/sample/10BT").glob("*.parquet"):
    shard = pl.read_parquet(path)
    ...  # process one shard at a time, write results out

当文件被整体读取时——例如模型权重、音频或图像文件、归档文件——或者当工具仅接受文件路径时,挂载是自然的选择。对于大型多文件 Parquet 扫描,通过 直接在 hf:// 上查询 通常比通过挂载进行扫描快数倍。

数据集和模型以只读方式挂载;存储桶为读写模式,因此是保存结果的理想位置。有关完整的-v语法,请参阅配置;有关详细信息,请参阅存储桶访问模式。

通过挂载读取的文件会缓存在 Job 的临时磁盘上,因此采用惰性读取(一次读取一个文件)可以保持占用空间较小。使用 hf jobs uv run 运行本地脚本时,脚本目录会挂载到 /data,因此请将数据挂载到其他位置(例如 /mnt/data)。

保存结果

临时磁盘不会在 Job 结束后保留,因此请将需要保留的内容写入以读写方式挂载的 Storage Bucket,或将其作为数据集推送到 Hub。DuckDB 可以通过 hf:// 对源数据进行过滤,并在一个外存查询中直接将匹配结果写入已挂载的存储桶,因此结果无需全部装入内存:

hf jobs uv run --flavor cpu-upgrade --timeout 1h \
  -v hf://buckets/username/my-output:/mnt/out \
  filter.py
# /// script
# dependencies = ["duckdb"]
# ///
# filter.py — scan ~28 GB of Parquet, keep only the matching rows
import duckdb

duckdb.sql(
    """
    COPY (
        SELECT text, url, token_count
        FROM 'hf://datasets/HuggingFaceFW/fineweb-edu/sample/10BT/*.parquet'
        WHERE int_score >= 4 AND token_count >= 4000
    ) TO '/mnt/out/result.parquet' (FORMAT parquet)
    """
)

写入到存储桶挂载路径下的文件在作业结束后会保留。若要发布处理后的数据集,请改用 Dataset.push_to_hub。

实战示例:查询 Common Crawl 而无需下载

Common Crawl 将其归档镜像到存储桶 commoncrawl/commoncrawl——容量达数百 TB。直接从 hf:// 流式读取一个 WET(纯文本)分片,对其进行解析,并使用 DuckDB 进行查询;由于 gzip 是顺序读取且会提前停止,因此传输的数据量仅为几 MB:

# /// script
# requires-python = ">=3.11"
# dependencies = ["huggingface_hub>=1.9", "fastwarc>=0.15", "duckdb>=1.0"]
# ///
import duckdb
from fastwarc.warc import ArchiveIterator, WarcRecordType
from huggingface_hub import hffs

WET = (
    "buckets/commoncrawl/commoncrawl/crawl-data/CC-MAIN-2026-17/"
    "segments/1775805908305.14/wet/"
    "CC-MAIN-20260410081153-20260410111153-00000.warc.wet.gz"
)

rows = []
with hffs.open(WET, "rb") as f:
    for rec in ArchiveIterator(f, record_types=WarcRecordType.conversion):
        lang = (rec.headers.get("WARC-Identified-Content-Language", "") or "und").split(",")[0]
        rows.append((rec.headers.get("WARC-Target-URI", ""), lang, len(rec.reader.read())))
        if len(rows) >= 5000:
            break

con = duckdb.connect()
con.execute("CREATE TABLE wet(url VARCHAR, lang VARCHAR, n_chars BIGINT)")
con.executemany("INSERT INTO wet VALUES (?,?,?)", rows)
con.sql("SELECT lang, count(*) AS docs FROM wet GROUP BY lang ORDER BY docs DESC LIMIT 10").show()

使用 hf jobs uv run cc_wet.py 运行它——在默认的 CPU 规格上大约一分钟即可完成,并输出:

┌─────────┬───────┐
│  lang   │ docs  │
│ varchar │ int64 │
├─────────┼───────┤
│ eng     │  1974 │
│ zho     │   586 │
│ rus     │   434 │
│ jpn     │   244 │
│ …       │    …  │
└─────────┴───────┘

另请参阅

Update on GitHub