DFlash and DFlash2 draft training#
Use examples/speechlm2/dflash_train.py with conf/dflash.yaml to train a
compact DFlash or DFlash2 draft against a frozen, audio-conditioned
SALMAutomodel target. The YAML inherits SALM’s target, data, and trainer
defaults from salm_automodel.yaml and adds the dflash settings. Choose
dflash.variant (dflash or dflash2) and provide a reserved
dflash.mask_token_id. The entry point trains and exports draft-only weights while
preserving SALM’s audio-placeholder expansion. The shipped DFlash2 settings mirror Automodel’s
recipe, including its two-tap grouped dynamic convolution, top-16 rank-256 path selector, and
separately normalized backbone and selector losses. num_anchors limits sampled blocks per row;
packed THD batches use one row per rank. For non-packed BSHD batches, up to
batch_size * num_anchors blocks are allocated per rank; reduce num_anchors when using larger batches.
Packed-document boundaries are enforced by document-local anchor selection, attention masks, and position IDs.
Both variants use dense draft logits (DFlash2 needs them for candidate selection), with
use_fused_linear_ce=false. This integration supports BSHD and packed THD batches with
tp_size=pp_size=cp_size=1 and does not directly load the published packed NVFP4 inference
checkpoint into BF16 training modules.
Target features are captured with SALM’s original padding; before the draft forward,
leading padding is moved to the end of each row so it cannot enter a draft context.
trainer.precision controls both target and draft dtypes during training. For BF16
training, either the shipped bf16-flash or bf16-automodel trainer precision
is supported. Target inference backend compatibility is validated before constructing the draft.
The frozen target runs in the configured parameter dtype without TE FP8 autocast.
Packed decoder inputs are supported; packed audio-encoder execution
(model.packed_encoder_sequences / model.packed_encoder_cp) is not enabled by this entry point.
dflash.lr defaults to 6e-4 with AdamW and no scheduler. To reproduce an adaptation
schedule, supply dflash.optimizer and dflash.lr_scheduler explicitly; for example:
dflash:
optimizer:
_target_: torch.optim.AdamW
lr: 1.5e-4
betas: [0.9, 0.999]
eps: 1e-8
weight_decay: 0.0
lr_scheduler:
_target_: nemo.core.optim.lr_scheduler.CosineAnnealing
warmup_steps: 500
min_lr: 1e-6
max_steps: 8000
For a frozen target initialized from a Hugging Face directory after FSDP sharding,
model.init_from_checkpoint_strict=true (default) requires every model parameter
in that checkpoint. Set it to false only for intentional partial initialization.
To warm-start a draft, set dflash.init_from_pretrained to a local HuggingFace
draft export matching the configured architecture. Loading rejects missing,
unexpected, or mismatched weights. This initializes draft weights only; optimizer,
scheduler, and step counters start fresh. The frozen target is still selected
independently with the model’s checkpoint settings.
The shipped recipe defaults to dflash.label_source=target_argmax, supervising
the draft with the frozen backbone’s greedy next-token predictions under the
original, teacher-forced context. Set dflash.label_source=ground_truth to use
reference tokens instead. These are hard labels, not soft-logit distillation or generated
rollouts. The input tokens and audio-conditioned hidden features remain the
original context. Labels use the final-normalized state at the preceding token;
packed document boundaries and padding never supply a predecessor. Only
supervised positions are projected, in chunks bounded by
dflash.target_argmax_chunk_size (default 128), so full-sequence vocabulary
logits are not retained. Draft features still use pre-final-normalization layer
outputs. Validation uses the same configured label source.
Offline model-generated labels are also supported through the dataset-label path.
Put the generated transcripts in the dataset’s supervised assistant responses and
set dflash.label_source=ground_truth. Here ground_truth means the supplied
dataset tokens; they may be human references or model predictions. For ordinary
lhotse_as_conversation ASR data, the response comes from
cut.supervisions[0].text (NeMo ASR manifest text before conversion).
Preserve audio alignment and prompt context, and write a separate manifest so the
original references remain available for evaluation. For example, with the data
configuration pointing to the generated-label manifest:
dflash:
variant: dflash2
label_source: ground_truth
The target still computes hidden features online, now under the generated response
context. This uses the same training path as reference labels. Selecting
target_argmax instead recomputes labels under that context and overrides the
supplied response tokens as supervision. See
.claude/skills/train-dflash/SKILL.md for the generated-label preparation workflow.
For projection-only adaptation of a pretrained DFlash2 draft, set
dflash.projection_only=true with dflash.init_from_pretrained. Only the
input feature projection fc.weight is trainable; the target, draft decoder,
norms, convolutions, and candidate selector remain frozen. Gradients still flow
through the frozen draft into the projection, including with activation
checkpointing. The optimizer contains only trainable parameters, while draft
checkpoints and Hugging Face exports retain all draft weights.
For example, to adapt a compatible block8 DFlash2 export to block16:
dflash:
variant: dflash2
init_from_pretrained: /path/to/block8-draft
block_size: 16
label_source: target_argmax
target_argmax_chunk_size: 128
projection_only: true
use_fused_linear_ce: false
Use this as an override to dflash.yaml, preserving the
warm-start architecture and target-layer taps. The configured block size is
used for training and saved in the exported draft config; strict loading still
requires every weight shape to match. Set projection_only=false to train
the full draft. A weights-only warm start can change block size; resuming a
training checkpoint instead requires the same optimizer parameter selection.
Launching training#
Supply the same target and data overrides used for SALM training. For example, with a compatible BF16 target checkpoint and pretrained draft:
torchrun --nproc_per_node=8 examples/speechlm2/dflash_train.py \
--config-name=dflash \
model.init_from_checkpoint=/path/to/target-checkpoint \
dflash.init_from_pretrained=/path/to/compatible-draft \
dflash.block_size=16 \
dflash.label_source=target_argmax
Use +run_validate_only=true for validation without training. Ordinary SALM
training continues to use salm_train.py and salm_automodel.yaml.