Hub documentation

大規模なデータセットの処理

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

大規模なデータセットの処理

すべてのJobには、ハードウェアフレーバー(hf jobs hardwareでも表示されるEphemeral Storage列)によって設定された固定量のローカルディスクが用意されています。そのディスクにデータセット全体を収める必要はありません。データセットとStorage Bucketsは、Hubからストリーミング、クエリ、マウントのいずれかの方法で直接読み取れるため、1つのJobでディスク容量をはるかに超えるデータを処理できます。このページでは、各オプションと、それぞれをいつ使うべきかについて説明します。

どちらのアプローチにしますか?

  • ディスクに収まる → 通常のload_dataset(...)がそのまま動作します(または、最大 1 TB の一時ディスクまで、より大きなバリエーションを選択するだけです)。
  • 行を反復処理して処理や学習を行う → stream する。
  • Filtered or column-pruned scans → query it directly over hf:// with Polars or DuckDB.
  • ローカルファイルパスを期待するツール → リポジトリをmountし、遅延読み込みで読み取ります。
  • 結果の永続化 → Job が終了しても残るように、Storage Bucket に書き出します。

データセットをストリーミングする

Streamingは、コードがサンプルを消費するにつれて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

ストリームされたデータセットは、遅延評価の.filter()、.map()、.shuffle(buffer_size=...)、および.batch()をサポートするIterableDatasetであり、ディスク容量を超えるデータでの学習のために、そのままPyTorchのDataLoaderやTrainerに渡すことができます。完全なAPIについてはStreamガイドを、単一ノードまたは分散環境でのエンドツーエンドの学習手順についてはExamples & Tutorialsを参照してください。

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 をネイティブでスキャンし、フィルタリングやカラム選択をスキャン処理にプッシュダウンすることで、1 つの Job がメモリやディスクに収まる量をはるかに超えるデータを処理できます。このクエリは、デフォルトの CPU フレーバーで約 28 GB の Parquet を約 4 分で集約します。

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)

このようなスキャンはメモリ制約ではなくネットワーク制約であり、エンジンによってリモート読み取りを並列化する度合いが異なるため、タイミングはライブラリによって異なります。実用上の含意は2つあります。長時間のスキャンでは、--timeoutをデフォルトの30分より大きく設定すること、そして高速化のために作業を複数のJobに分割して並列実行することです。ライブラリごとの例については、Polars、DuckDB、pandasを、hf://経由でbucketsを読み込む方法については、Python data toolsを参照してください(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:// を直接クエリする方が、マウント経由でスキャンするよりも通常数倍速くなります。

Datasets とモデルは読み取り専用でマウントされます。一方、バケットは読み書き可能であり、結果を保存するのに適した場所です。-v の完全な構文については 設定 を、詳細については バケットのアクセスパターン を参照してください。

マウント経由で読み取られたファイルは、Job のエフェメラルディスクにキャッシュされるため、遅延読み込み(1 つずつ読み込む)にするとフットプリントを小さく保つことができます。hf jobs uv run でローカルスクリプトを実行する場合、スクリプトディレクトリは /data にマウントされるため、データは別の場所(例: /mnt/data)にマウントしてください。

結果を保存

Ephemeral disk は Job の終了とともに失われるため、保持したいデータは読み書き可能な Storage Bucket に書き込むか、Hub にデータセットとしてプッシュしてください。DuckDB は hf:// 経由でソースをフィルタリングし、一致したデータをマウントされたバケットに直接書き込むことを 1 つのアウトオブコアクエリで実行できるため、結果をメモリに収める必要はありません:

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)
    """
)

バケットのマウントパス配下に書き込まれたファイルは、Jobが終了した後も保持されます。処理済みデータセットを公開する場合は、代わりにDataset.push_to_hubを使用してください。

実例: Common Crawl をダウンロードせずにクエリする

Common Crawl は、そのアーカイブをバケット commoncrawl/commoncrawl にミラーリングしています。容量は数百 TB に達します。hf:// から WET(プレーンテキスト)シャードを 1 つストリーミングし、パースして 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フレーバーでは約1分で完了し、以下を出力します。

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

関連項目

Update on GitHub