← TinyGPT · docs · devlog · roadmap · speedup
source: docs/hf_datasets_integration.md · view on GitHub ↗

HuggingFace Datasets Hub integration

tinygpt download-dataset and tinygpt list-datasets give the on-device agent-factory direct access to HuggingFace’s 100k+ dataset hub. This document covers how to use them, how the format adapter works, the curated registry of “good” datasets by specialist type, and the caveats.

Why this matters. Training data is the bottleneck for any finetuning effort. The HF Hub is where everyone publishes — xLAM and Hermes for function-calling, OpenHermes-2.5 / UltraChat for instruction-following, UltraFeedback for DPO, OpenMathReasoning for math, OpenThoughts for chain-of-thought. Without a clean local pipeline to pull and convert these, every user reinvents one. This module is that pipeline.


Quick start

# Browse the curated registry (no network).
tinygpt list-datasets
tinygpt list-datasets --specialist tool-calling
tinygpt list-datasets --info Salesforce/xlam-function-calling-60k

# Resolve + download. Auto-detects schema and converts to JSONL.
tinygpt download-dataset hf://datasets/yahma/alpaca-cleaned

# Force a target format if auto-detect picks the wrong one.
tinygpt download-dataset hf://datasets/OpenHermes-2.5 --format sft

# Cap shards for a quick sanity test.
tinygpt download-dataset Salesforce/xlam-function-calling-60k --max-files 1

# Inspect (no download) — print file list and predicted schema.
tinygpt download-dataset hf://datasets/argilla/ultrafeedback-binarized-preferences-cleaned --inspect

# Field aliasing for unusual schemas.
tinygpt download-dataset some-owner/some-dataset --map question:instruction,solution:response

Output lands at ~/.cache/tinygpt/datasets/<owner>/<name>/corpus.jsonl (or corpus.txt for plain format), unless --out is given.


What the CLI does

  1. Hits GET https://huggingface.co/api/datasets/<id> to resolve the dataset and list its siblings (files in the repo).
  2. Filters siblings to data shards (JSONL/JSON/parquet/arrow/csv); skips READMEs, dataset_infos, licenses, .gitattributes.
  3. Streams each shard via https://huggingface.co/datasets/<id>/resolve/main/<filename>, writing to the local cache. Existing files with matching size are skipped (resume).
  4. Sniffs the first row of the first decodable shard and picks a target format via FormatDetector. The user can override with --format and --map.
  5. Iterates all shards, converts each row to a CorpusRecord, and writes the result as newline-delimited JSONL (or plain text for .plain if --out ends in .txt).

Format adapter logic

The adapter looks at one row and ranks three target formats:

FormatOutput schemaTrigger
sft{instruction, input?, response}row has instruction/prompt/question + response/completion/answer/output
dpo{prompt, chosen, rejected}row has chosen + rejected (string OR chat-array)
plainone example per linerow has text/content/document

Detection order

  1. DPO (highest specificity) — if chosen and rejected are both present, it’s a preference dataset. If prompt is missing but chosen is a chat array, we extract the prompt from the ShareGPT-style [{role, content}] structure.
  2. SFT — if an instruction-like field and a response-like field are both present, it’s an SFT corpus.
  3. ShareGPT-style SFT — if conversations or messages is a [{role, content}] (or ShareGPT [{from, value}]) array, we collapse it to (joinedPriorTurns, lastAssistant).
  4. Plain — single text-ish field falls back to pretraining text.
  5. Last-ditch — if exactly one string-valued field exists, treat it as plain text with low confidence (< 0.6); the user is prompted to re-run with explicit flags.

Field aliases (case-insensitive)

CanonicalAliases tried
instructioninstruction, prompt, question, query, input_text
inputinput, context, background
responseresponse, completion, answer, output, target, label, responses
prompt (dpo)prompt, question, instruction, query
chosenchosen, chosen_response, preferred, win, winner
rejectedrejected, rejected_response, dispreferred, loss, loser
texttext, content, document, raw_text, body

When the detector picks the wrong column (rare, but happens with unusual schemas), pass --map src_field:canonical_field,.... For example:

tinygpt download-dataset some-owner/some-dataset \
  --format sft \
  --map problem:instruction,solution:response

Non-string values

If a row field is a JSON object or array rather than a string (e.g. function-calling datasets store tool definitions and tool calls as JSON), the adapter serialises it to canonical JSON with sorted keys. Downstream SFT trainers see deterministic strings.


Curated registry (tinygpt list-datasets)

The registry lives in native-mac/Sources/TinyGPTData/DatasetRegistry.swift. Today it has 22 entries across 8 specialist categories.

SpecialistDatasets
tool-callingSalesforce/xlam-function-calling-60k, NousResearch/hermes-function-calling-v1, Locutusque/function-calling-chatml
debuggerprinceton-nlp/SWE-bench (+ Verified), bigcode/commitpack
codebigcode/the-stack-smol, open-r1/codeforces-cots, iamtarun/python_code_instructions_18k_alpaca
mathnvidia/OpenMathReasoning, AI-MO/NuminaMath-CoT, meta-math/MetaMathQA
reasoningopen-thoughts/OpenThoughts-114k, open-thoughts/OpenThoughts2-1M
instructteknium/OpenHermes-2.5, HuggingFaceH4/ultrachat_200k, yahma/alpaca-cleaned
preferenceargilla/ultrafeedback-binarized-preferences-cleaned, HuggingFaceH4/ultrafeedback_binarized, Intel/orca_dpo_pairs
generalroneneldan/TinyStories, HuggingFaceFW/fineweb-edu

Adding a new entry is a one-line addition to DatasetRegistry.all — fill in id, specialists, format, approxSize, license, notes.


Caching


Authentication (gated / private datasets)

export HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxx

The token is sent as Authorization: Bearer $HF_TOKEN on every request. Get one at https://huggingface.co/settings/tokens.

Without HF_TOKEN:


Caveats

Parquet decoding is not yet implemented

Apple ships no parquet decoder and the spec is non-trivial (mixed encodings, dictionary pages, snappy/zstd compression). For now:

Follow-up: wrap Apple’s compression APIs + a minimal parquet column-reader to land native parquet. Tracked separately.

Streaming for huge datasets

For datasets >100 MB the URLSession streaming download writes straight to disk as bytes arrive — memory stays bounded. The conversion phase reads the file streaming line-by-line (1 MiB chunks). However, for parquet, full streaming requires a column reader — not yet supported.

Schema drift

HF dataset cards drift more than model cards. The adapter:

File-size estimates

/api/datasets/<id> doesn’t always include sibling sizes for older snapshots — the inspect view shows ? in that case. The download still works (URLSession streams without knowing total size first); we just can’t show a percentage.

Curated-registry license check

Every registry entry has a license field. Some are permissive (MIT / Apache-2.0); some are NC-only (CC BY-NC 4.0 for xLAM and yahma/alpaca-cleaned) — be aware before training a commercial model. tinygpt list-datasets --info <id> shows the license.


Architecture

native-mac/Sources/TinyGPTData/
  HFDatasets.swift          - HF Hub API client (URLSession + JSON)
  CorpusFormat.swift        - format types + detector + JSONL writer
  RowReader.swift           - shard readers (JSONL/JSON now; parquet TODO)
  DatasetRegistry.swift     - curated catalog by specialist

native-mac/Sources/TinyGPT/
  DownloadDataset.swift     - `tinygpt download-dataset` CLI
  ListDatasets.swift        - `tinygpt list-datasets` CLI

TinyGPTData is intentionally a pure-Foundation library. It depends on nothing else in the project, so it can be unit-tested without MLX and so the download-dataset / list-datasets CLI subcommands launch fast (no MLX initialisation).

The CLI subcommands live under pre-switch shims in Sources/TinyGPT/TinyGPT.swift (matching the existing convention used by score-bench, train-heads, prune-*, gptq). The shim gets removed when TODO(hf-datasets-merge) is resolved.


Future work