11. Datasets¶
Runnable companion:
examples/08_workset_to_dataset.py
Everything so far read through a live workset, which is what exploring wants. It is also what training does not want: a source that can answer differently tomorrow cannot be reproduced.
A dataset is a named, frozen workset. Converting resolves the membership once, at that instant, and freezes the result under a name.
Convert¶
dataset = client.convert_workset_to_dataset(
workset.workset_id,
"voice_train_v1",
shard_plan=ShardPlan(shard_size=1000),
)
ready = client.wait_for_dataset("voice_train_v1", timeout_seconds=1800)
ready.lifecycle_state # "ready"
for sample in SampleStream.from_dataset(
"voice_train_v1", keys=["audio.wav", "transcript.txt"], client=client
):
...
Sources, filters and key groups come from the workset, so the dataset is that
workset frozen — you are keeping it, not redefining it. Override key_groups=
only for a different download grouping, and scalars= to record constants
alongside the data ({"sample_rate": 24000}).
Conversion is worker-deferred: it returns a planning dataset and a worker
materializes membership, order and shard plan. wait_for_dataset polls to
ready. The workset stays live and usable afterwards; nothing consumed it.
What freezing buys¶
| Workset | Dataset | |
|---|---|---|
| Membership | re-resolved per read | fixed at conversion |
| A store that grows | shows up | does not |
| Name | none | required, unique |
| Reproducible | no | yes |
| Splits | not possible | yes (chapter 12) |
| Reading | SampleStream.from_workset |
SampleStream.from_dataset |
Import 1000 more samples into the store, and the workset yields them on the next read while the dataset does not. That is the guarantee, not staleness: a dataset opened a year from now yields the same samples in the same order.
from_dataset also has less to do than from_workset: a dataset's shard plan is
already materialized, so opening one is a couple of indexed reads and the first
network cost lands at the first sample, not at open. keys= is optional here —
omit it to read every key the dataset defines, and
client.get_dataset(name).key_groups lists them.
Naming a workset is converting it¶
There is one freeze verb and one way to keep a workset. There is no "save this workset", no pinning, no TTL to extend: worksets are unnamed and ephemeral by construction, and the moment you want a name, you want a dataset.
The working order is therefore: select freely, read, refine, convert the one you keep.
create_workset ──read──▶ refine ──read──▶ convert_workset_to_dataset ──▶ train
(free) (free) (materialized, named)
Retention¶
A dataset holds a tracked dependency on the stores it reads, which is what keeps its bytes alive. That dictates teardown order: delete the dataset before the store it reads. Deleting the store first returns 409 while a protecting dataset depends on it.
Downloading it¶
Datasets can be pulled to local tars — for an offline machine, an archive, or a non-Python consumer:
datavo dataset get voice_train_v1
datavo dataset pull voice_train_v1 --output-dir ./downloaded/train
That writes one tar per shard, one directory per key group; add --key-group to
pull only some. For normal training you do not need it: SampleStream.from_dataset streams and caches the
same shards on demand (shard cache).
Pitfalls¶
- Opening a
planningdataset. Conversion is worker-deferred; wait forready. - Reusing a name. Dataset names are unique and datasets are frozen. A changed
workset is a new dataset name — version them (
voice_train_v1,_v2). - Converting to escape a slow read. Both paths stream the same cached shards; convert for reproducibility, not for speed.
- Deleting the store first. Archive and delete the dataset, then the store.
- Converting too early. A dataset is permanent and named. While you are still changing your mind, stay on the workset — it costs nothing.
Next: 12. Splits and evaluation — cut train/val/test and compare runs.