20 min

Datasets sind auch Repos

Ein Datensatz mit hunderten Gigabyte ist ansehbar und benutzbar, ohne dass ein einziges Byte auf deiner Platte landet.

Meilenstein Fünf Zeilen aus einem großen Datensatz sind im Streaming gelesen, und dein eigener Mini-Datensatz liegt mit funktionierendem Viewer auf dem Hub.

Die Hälfte des Hubs besteht aus Datensätzen, und die meisten Einsteiger sehen sie nie. Dabei ist genau dort der Trick zu Hause, der Datensätze von Modellen unterscheidet: Du kannst sie benutzen, ohne sie zu haben.

Der Viewer - hineinsehen, bevor du etwas lädst

Öffne einen beliebigen Datensatz, zum Beispiel stanfordnlp/imdbExtern - Öffnet in neuem Tab. Unter der Beschreibung siehst du eine Tabelle mit echten Zeilen, dazu Filter, eine Volltextsuche und Verteilungen je Spalte.

Das ist der Dataset Viewer, und er ist mehr als eine Vorschau. Er beantwortet in dreißig Sekunden die Fragen, für die man sonst 20 GB herunterlädt und ein Notebook aufmacht: Welche Spalten gibt es? Sind die Labels ausgeglichen? Wie lang sind die Texte wirklich? Steht da Müll drin?

Oben stehen die Splits - meist train, test, manchmal validation. Es sind getrennte Dateisätze desselben Repos, keine Filter.

Schritt 1 - Benutzen, ohne herunterzuladen

bash
pip install -U datasets

Der übliche Weg lädt alles:

from datasets import load_dataset

ds = load_dataset("stanfordnlp/imdb", split="train")   # lädt und cached alles
print(ds[0])

Der andere Weg lädt nichts:

from datasets import load_dataset

ds = load_dataset("stanfordnlp/imdb", split="train", streaming=True)
for beispiel in ds.take(5):
    print(beispiel["label"], beispiel["text"][:80])

streaming=True gibt dir kein Dataset, sondern ein IterableDataset: Es holt sich Blöcke über HTTP, während du darüber läufst, und legt nichts auf deiner Platte ab. Du kannst nicht mehr ds[42] schreiben und len(ds) gibt es auch nicht - dafür kannst du mit einem Datensatz arbeiten, der größer ist als deine Festplatte.

Beide Wege vertragen .map(), .filter() und .shuffle() - beim Streaming werden diese Schritte faul angewandt, also erst beim Durchlaufen:

kurz = ds.filter(lambda b: len(b["text"]) < 500).map(
    lambda b: {"laenge": len(b["text"])}
)
print(next(iter(kurz)))

Schritt 2 - Der eigene Datensatz

Jetzt die andere Richtung. Ein Datensatz-Repo anzulegen ist keine große Sache - push_to_hub() erledigt Repo-Erstellung, Konvertierung nach Parquet und Upload in einem Aufruf.

Nimm etwas Kleines und Eigenes. Zum Beispiel eine Handvoll deutscher Sätze mit einem Label:

# mein_dataset.py
from datasets import Dataset

zeilen = {
    "text": [
        "Die Lieferung kam drei Wochen zu spät.",
        "Vielen Dank, alles hat einwandfrei geklappt.",
        "Das Gerät war beim Auspacken bereits beschädigt.",
        "Sehr freundlicher Support, gerne wieder.",
    ],
    "label": [1, 0, 1, 0],   # 1 = Beschwerde
}

ds = Dataset.from_dict(zeilen)
ds.push_to_hub("deinbenutzername/beschwerden-mini")
bash
python mein_dataset.py

Dafür braucht dein Token Schreibrechte - der Moment aus Kapitel 02, in dem das zweite, mächtigere Token zum Einsatz kommt. Wenn du kein öffentliches Repo willst: push_to_hub("…", private=True).

Nach ein bis zwei Minuten steht der Datensatz unter huggingface.co/datasets/deinbenutzername/beschwerden-mini - mit Viewer, weil push_to_hub von sich aus Parquet schreibt.

Schritt 3 - Die Karte schreiben

Ein Datensatz ohne Beschreibung ist für jeden anderen wertlos, und für dich in sechs Monaten auch. Bearbeite die README.md des Repos direkt im Browser und beantworte vier Fragen:

  1. Woher kommen die Daten? Selbst geschrieben, gesammelt, aus einer anderen Quelle abgeleitet?
  2. Was bedeuten die Spalten? label: 1 = Beschwerde ist eine Zeile und spart jedem Leser zehn Minuten.
  3. Unter welcher Lizenz stehen sie? Das Feld license: im YAML-Kopf.
  4. Wofür sind sie nicht geeignet? Vier handgeschriebene Sätze sind kein Benchmark. Sag es dazu.

Schritt 4 - Wieder abholen

Der Kreis schließt sich, und zwar sichtbar:

from datasets import load_dataset

meins = load_dataset("deinbenutzername/beschwerden-mini", split="train")
print(meins)
print(meins[0])

Dein Datensatz verhält sich jetzt exakt wie stanfordnlp/imdb. Das ist der eigentliche Punkt des Hubs: Es gibt keine zweite Klasse. Dieselben Werkzeuge, dieselben Aufrufe, derselbe Viewer - egal ob das Repo von einem Forschungslabor kommt oder aus deinem Terminal von vor fünf Minuten.

Der Meilenstein

Zwei Nachweise:

  • Ein Skript, das mit streaming=True fünf Zeilen aus einem großen, öffentlichen Datensatz ausgibt - und du -sh ~/.cache/huggingface ist danach nicht nennenswert gewachsen.
  • Eine URL auf deinen eigenen Datensatz, bei der der Viewer Zeilen anzeigt und die README erklärt, was die Spalten bedeuten.