Migrate a NeMo training YAML to indexed + resumable Lhotse
Use this skill to port a NeMo training config from streaming/replay-style Lhotse
loading to indexed access plus torchdata.StatefulDataLoader checkpoint/restore.
The migration is fragile because YAML flags, launcher seed policy, index paths,
storage backend, and resume topology all interact.
Core concepts
- Indexed sources need
.idx sidecars for random access into JSONL, tar, and
supported Shar-style data. Build these once per blend/source set.
- For datasets with very many shards, an optional dataset-level
.idxpack
combines existing sidecars into one memory-mapped catalog. Prefer one pack
per independently configured outer input_cfg; do not create one global
pack for an entire mixture.
use_stateful_dataloader: true lets Lightning checkpoint the dataloader
iterator state, but only if seeds, worker counts, and distributed topology are
stable across chunks.
- Training configs must use
force_map_dataset: false so indexed sources
partition across data-parallel ranks and workers without map-style sampler
overhead. Treat force_map_dataset: true for training as not launch-ready
unless the user explicitly approves a temporary exception; every source in the
training iteration graph must be indexed and partition-compatible before
launch.
- Remote audio on AIStore/S3 generally needs
USE_AIS_GET_BATCH=true so audio
fetches are deferred to sample time instead of constructing eager tar readers
for every shard.
Inputs
| input |
required |
source |
purpose |
| Training YAML |
yes |
argument or --config= |
Inspect data.train_ds, data.validation_ds, trainer, exp_manager, and any model fields that affect resume. |
| Launcher script |
no |
argument or auto-detect from project conventions |
Check per-chunk seed policy, resume topology invariance, Python path setup, AIStore env vars, and optional index staging. |
| Data-blend YAML |
no |
resolved from data.train_ds.input_cfg when possible |
Check indexability: compressed paths, non-seekable paths, unsupported extra_fields, slice_length, and mixed indexed/non-indexed chains. |
| Runtime context |
no |
argument, config file, or user-provided notes |
Detect storage backend, AIStore endpoint availability, container constraints, and index mirror destination. |
Outputs
Every output lands in migrate-resumable/<config-stem>/ in the current repo:
| output |
purpose |
migration-report.md |
Findings, rationale, patched fields, and unresolved blockers. |
<config-stem>-resumable.yaml |
Patched training config when safe automatic edits are possible. |
<blend-stem>-resumable.yaml |
Patched blend, only when a blend was inspected and safe changes are possible. |
pre-flight-checklist.md |
User-run steps before submitting training. |
build-indexes-cmd.sh |
One-shot sidecar-build command and, when packs are selected, one conversion command per outer dataset. Use a project wrapper when available, otherwise the generic NeMo scripts. |
Workflow
1. Discover and parse inputs
- Resolve the training YAML path and read it with OmegaConf or a
comment-preserving YAML parser.
- Resolve any referenced blend YAMLs from
data.*.input_cfg. Prefer project
conventions when obvious, but fall back to paths relative to the config.
- If a launcher path is supplied, read it. Otherwise inspect likely project
launchers (
train.py, pretrain.py, shell wrappers, or raw torchrun /
python commands) and pick the closest match.
- If runtime context is supplied, read it for container image, environment
variables, filesystem mounts, worker counts, and AIStore endpoint settings.
- Detect remote storage from source paths (
s3://, ais://, http(s)://) and
local filesystem storage from ordinary absolute or relative paths.
2. Run lint pipeline
Run every relevant check in:
references/option-reference.md
references/conflict-matrix.md
references/failure-modes.md
references/aistore-vs-non-aistore.md when remote storage is present
Each finding should include severity, field/path, current value, recommended
value, and a short rationale.
Severities:
- fatal: automatic patching is not possible; user must preprocess data or
change the source layout.
- error: automatic patching is safe and should be applied.
- warning: context-dependent; emit a report item and optional YAML comment.
- note: informational; no patch.
3. Emit patched YAML and blend
Apply safe error-severity patches. Preserve comments when possible with
ruamel.yaml; otherwise serialize with OmegaConf/YAML and rely on the report for
rationale. For blend edits, never silently drop data: leave an explicit report
entry and comment for every excluded or rewritten source.
4. Generate migration-report.md
Use templates/migration-report.md. Include:
- Summary of storage workflow, counts by severity, and readiness.
- Inputs inspected.
- Findings table.
- Walkthrough for train data, validation data, trainer/exp manager, launcher,
and storage backend.
- Data-blend audit.
- Verification and pre-flight steps.
5. Generate pre-flight-checklist.md
Use templates/pre-flight-checklist.md when present. Required steps:
- Build
.idx sidecars for every training/validation/test blend involved.
- When startup would open many loose sidecars, build and validate one
.idxpack
per supported outer dataset after the sidecars exist. Record the owning
input_cfg entry and output filename explicitly.
- Verify
indexes_root points at the same stable mirror used by the runtime, or
that explicit node-local index staging populates it before training starts.
- If AIStore is in play: verify
aistore SDK availability, AIS_ENDPOINT, and
whether USE_AIS_GET_BATCH or USE_AIS_INDIVIDUAL_GETS is required.
- Verify one invariant seed across resumable chunks.
- Verify
num_workers, world_size, and relevant distributed topology do not
change across resume boundaries.
- Recommend a small smoke ladder: single-node single chunk, single-node resume,
then full topology.
6. Generate build-indexes-cmd.sh
Prefer a project-provided wrapper when one is clearly present. Otherwise emit a
generic command using:
python <NeMo>/scripts/dataloading/build_indexes.py \
--indexes-root <shared-index-mirror> \
--workers <N> \
<blend>.yaml [<validation-blend>.yaml ...]
When an outer dataset is supported and has enough shards to benefit from one
memory map, append a command for that dataset (repeat for every independently
configured outer input_cfg):
python <NeMo>/scripts/dataloading/convert_indexes_to_idxpack.py \
--indexes-root <shared-index-mirror> \
--output <index-pack-root>/<dataset-name>.idxpack \
<dataset-input-cfg>.yaml
Patch the owning outer entry with index_pack: <dataset-name>.idxpack and set
index_pack_root at the dataloader level. Never infer a pack by filename: an
explicit declaration is part of the runtime validation contract. If the
converter rejects a type, keep that adapter on loose sidecars and report it.
If running through a managed runtime or container wrapper, include comments for required
container image, mounts, environment variables, worker count, and any CPU/GPU
container-hook workaround the project requires.
7. Print final summary to chat
Keep the final chat response under 10 lines: output directory, finding counts,
report path, and the next command the user should run.
Knowledge base
references/option-reference.md: field-by-field reference for YAML and
launcher settings.
references/failure-modes.md: known failure signatures, triggers, and fixes.
references/conflict-matrix.md: incompatible option pairs.
references/best-practices.md: priority-ordered checklist.
references/aistore-vs-non-aistore.md: storage workflow selection.
templates/migration-report.md: report template.
templates/pre-flight-checklist.md: checklist template, when present.
scripts/analyze.py: optional static-analysis helper, when present.
Constraints
- Prefer static analysis. Do not launch training, build indexes, prefetch data, or
modify external runtime state unless the user explicitly asks.
- Cross-check recommendations against the actual NeMo/Lhotse code in the user's
checkout when paths are available. Relevant areas are common Lhotse dataloader
config, indexed adapters,
lhotse.indexing, AIStore batch loading, and NeMo
dataloader construction.
- Treat project wrappers as optional conveniences, not as part of the generic
migration contract.
- When evidence is missing, say so. Do not encode project-specific run history
or local experiment names as general guidance.
1---2name: migrate-to-resumable-dataloader3description: This skill should be used when the user asks to "migrate to the resumable dataloader", "switch to indexed Lhotse", "adopt the indexed + resumable pipeline", "make my training resumable", "set up StatefulDataLoader for NeMo/Lhotse", "use index packs", "use AIStore GetBatch", or "convert this YAML to the resumable path". Walks a NeMo training YAML and optional launcher, data blend, and runtime context through the indexed + resumable Lhotse migration; lints interacting fields; auto-patches safe YAML changes; emits a migration report, pre-flight checklist, and index-build command. Static analysis only; never launches training.4---56# Migrate a NeMo training YAML to indexed + resumable Lhotse78Use this skill to port a NeMo training config from streaming/replay-style Lhotse9loading to indexed access plus `torchdata.StatefulDataLoader` checkpoint/restore.10The migration is fragile because YAML flags, launcher seed policy, index paths,11storage backend, and resume topology all interact.1213## Core concepts1415- Indexed sources need `.idx` sidecars for random access into JSONL, tar, and16 supported Shar-style data. Build these once per blend/source set.17- For datasets with very many shards, an optional dataset-level `.idxpack`18 combines existing sidecars into one memory-mapped catalog. Prefer one pack19 per independently configured outer `input_cfg`; do not create one global20 pack for an entire mixture.21- `use_stateful_dataloader: true` lets Lightning checkpoint the dataloader22 iterator state, but only if seeds, worker counts, and distributed topology are23 stable across chunks.24- Training configs must use `force_map_dataset: false` so indexed sources25 partition across data-parallel ranks and workers without map-style sampler26 overhead. Treat `force_map_dataset: true` for training as not launch-ready27 unless the user explicitly approves a temporary exception; every source in the28 training iteration graph must be indexed and partition-compatible before29 launch.30- Remote audio on AIStore/S3 generally needs `USE_AIS_GET_BATCH=true` so audio31 fetches are deferred to sample time instead of constructing eager tar readers32 for every shard.3334## Inputs3536| input | required | source | purpose |37|---|---|---|---|38| Training YAML | yes | argument or `--config=` | Inspect `data.train_ds`, `data.validation_ds`, `trainer`, `exp_manager`, and any model fields that affect resume. |39| Launcher script | no | argument or auto-detect from project conventions | Check per-chunk seed policy, resume topology invariance, Python path setup, AIStore env vars, and optional index staging. |40| Data-blend YAML | no | resolved from `data.train_ds.input_cfg` when possible | Check indexability: compressed paths, non-seekable paths, unsupported `extra_fields`, `slice_length`, and mixed indexed/non-indexed chains. |41| Runtime context | no | argument, config file, or user-provided notes | Detect storage backend, AIStore endpoint availability, container constraints, and index mirror destination. |4243## Outputs4445Every output lands in `migrate-resumable/<config-stem>/` in the current repo:4647| output | purpose |48|---|---|49| `migration-report.md` | Findings, rationale, patched fields, and unresolved blockers. |50| `<config-stem>-resumable.yaml` | Patched training config when safe automatic edits are possible. |51| `<blend-stem>-resumable.yaml` | Patched blend, only when a blend was inspected and safe changes are possible. |52| `pre-flight-checklist.md` | User-run steps before submitting training. |53| `build-indexes-cmd.sh` | One-shot sidecar-build command and, when packs are selected, one conversion command per outer dataset. Use a project wrapper when available, otherwise the generic NeMo scripts. |5455## Workflow5657### 1. Discover and parse inputs58591. Resolve the training YAML path and read it with OmegaConf or a60 comment-preserving YAML parser.612. Resolve any referenced blend YAMLs from `data.*.input_cfg`. Prefer project62 conventions when obvious, but fall back to paths relative to the config.633. If a launcher path is supplied, read it. Otherwise inspect likely project64 launchers (`train.py`, `pretrain.py`, shell wrappers, or raw `torchrun` /65 `python` commands) and pick the closest match.664. If runtime context is supplied, read it for container image, environment67 variables, filesystem mounts, worker counts, and AIStore endpoint settings.685. Detect remote storage from source paths (`s3://`, `ais://`, `http(s)://`) and69 local filesystem storage from ordinary absolute or relative paths.7071### 2. Run lint pipeline7273Run every relevant check in:7475- `references/option-reference.md`76- `references/conflict-matrix.md`77- `references/failure-modes.md`78- `references/aistore-vs-non-aistore.md` when remote storage is present7980Each finding should include severity, field/path, current value, recommended81value, and a short rationale.8283Severities:8485- **fatal**: automatic patching is not possible; user must preprocess data or86 change the source layout.87- **error**: automatic patching is safe and should be applied.88- **warning**: context-dependent; emit a report item and optional YAML comment.89- **note**: informational; no patch.9091### 3. Emit patched YAML and blend9293Apply safe `error`-severity patches. Preserve comments when possible with94`ruamel.yaml`; otherwise serialize with OmegaConf/YAML and rely on the report for95rationale. For blend edits, never silently drop data: leave an explicit report96entry and comment for every excluded or rewritten source.9798### 4. Generate `migration-report.md`99100Use `templates/migration-report.md`. Include:1011021. Summary of storage workflow, counts by severity, and readiness.1032. Inputs inspected.1043. Findings table.1054. Walkthrough for train data, validation data, trainer/exp manager, launcher,106 and storage backend.1075. Data-blend audit.1086. Verification and pre-flight steps.109110### 5. Generate `pre-flight-checklist.md`111112Use `templates/pre-flight-checklist.md` when present. Required steps:113114- Build `.idx` sidecars for every training/validation/test blend involved.115- When startup would open many loose sidecars, build and validate one `.idxpack`116 per supported outer dataset after the sidecars exist. Record the owning117 `input_cfg` entry and output filename explicitly.118- Verify `indexes_root` points at the same stable mirror used by the runtime, or119 that explicit node-local index staging populates it before training starts.120- If AIStore is in play: verify `aistore` SDK availability, `AIS_ENDPOINT`, and121 whether `USE_AIS_GET_BATCH` or `USE_AIS_INDIVIDUAL_GETS` is required.122- Verify one invariant seed across resumable chunks.123- Verify `num_workers`, `world_size`, and relevant distributed topology do not124 change across resume boundaries.125- Recommend a small smoke ladder: single-node single chunk, single-node resume,126 then full topology.127128### 6. Generate `build-indexes-cmd.sh`129130Prefer a project-provided wrapper when one is clearly present. Otherwise emit a131generic command using:132133```bash134python <NeMo>/scripts/dataloading/build_indexes.py \135 --indexes-root <shared-index-mirror> \136 --workers <N> \137 <blend>.yaml [<validation-blend>.yaml ...]138```139140When an outer dataset is supported and has enough shards to benefit from one141memory map, append a command for that dataset (repeat for every independently142configured outer `input_cfg`):143144```bash145python <NeMo>/scripts/dataloading/convert_indexes_to_idxpack.py \146 --indexes-root <shared-index-mirror> \147 --output <index-pack-root>/<dataset-name>.idxpack \148 <dataset-input-cfg>.yaml149```150151Patch the owning outer entry with `index_pack: <dataset-name>.idxpack` and set152`index_pack_root` at the dataloader level. Never infer a pack by filename: an153explicit declaration is part of the runtime validation contract. If the154converter rejects a type, keep that adapter on loose sidecars and report it.155156If running through a managed runtime or container wrapper, include comments for required157container image, mounts, environment variables, worker count, and any CPU/GPU158container-hook workaround the project requires.159160### 7. Print final summary to chat161162Keep the final chat response under 10 lines: output directory, finding counts,163report path, and the next command the user should run.164165## Knowledge base166167- `references/option-reference.md`: field-by-field reference for YAML and168 launcher settings.169- `references/failure-modes.md`: known failure signatures, triggers, and fixes.170- `references/conflict-matrix.md`: incompatible option pairs.171- `references/best-practices.md`: priority-ordered checklist.172- `references/aistore-vs-non-aistore.md`: storage workflow selection.173- `templates/migration-report.md`: report template.174- `templates/pre-flight-checklist.md`: checklist template, when present.175- `scripts/analyze.py`: optional static-analysis helper, when present.176177## Constraints178179- Prefer static analysis. Do not launch training, build indexes, prefetch data, or180 modify external runtime state unless the user explicitly asks.181- Cross-check recommendations against the actual NeMo/Lhotse code in the user's182 checkout when paths are available. Relevant areas are common Lhotse dataloader183 config, indexed adapters, `lhotse.indexing`, AIStore batch loading, and NeMo184 dataloader construction.185- Treat project wrappers as optional conveniences, not as part of the generic186 migration contract.187- When evidence is missing, say so. Do not encode project-specific run history188 or local experiment names as general guidance.