chore: import upstream snapshot with attribution
Create PR to main with cherry-pick from release / cherry-pick (push) Failing after 0s
CICD NeMo / pre-flight (push) Failing after 0s
CICD NeMo / configure (push) Has been skipped
Build, validate, and release Neural Modules / pre-flight (push) Failing after 1s
CICD NeMo / code-linting (push) Has been skipped
Build, validate, and release Neural Modules / release (push) Has been skipped
Build, validate, and release Neural Modules / release-summary (push) Has been cancelled
CICD NeMo / cicd-test-container-build (push) Has been cancelled
CICD NeMo / cicd-import-tests (push) Has been cancelled
CICD NeMo / L0_Setup_Test_Data_And_Models (push) Has been cancelled
CICD NeMo / cicd-main-unit-tests (push) Has been cancelled
CICD NeMo / cicd-main-speech (push) Has been cancelled
CICD NeMo / Nemo_CICD_Test (push) Has been cancelled
CICD NeMo / Coverage (e2e) (push) Has been cancelled
CICD NeMo / Coverage (unit-test) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
CICD NeMo / cicd-wait-in-queue (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:28:58 +08:00
commit ba4be087d5
2316 changed files with 2668701 additions and 0 deletions
+544
View File
@@ -0,0 +1,544 @@
Configuration Files
===================
The SpeechLM2 models use YAML configuration files to define model architecture, training parameters, and data settings.
This page describes the configuration structure and important parameters for each model type in the collection.
Configuration Structure
-----------------------
SpeechLM2 configuration files typically have the following high-level structure:
.. code-block:: yaml
model:
# Model architecture settings
...
trainer:
# PyTorch Lightning trainer settings
...
exp_manager:
# Experiment logging settings
...
data:
# Dataset settings
...
SALM Configuration
------------------
The SALM (Speech-Augmented Language Model) configuration includes settings for the pretrained LLM, audio perception module, and training parameters.
See the `SALM paper <https://arxiv.org/abs/2310.09424>`_ for more details.
.. code-block:: yaml
model:
# Pretrained model paths
pretrained_llm: "TinyLlama/TinyLlama_v1.1" # HF model path
pretrained_asr: "stt_en_fastconformer_hybrid_large_streaming_80ms" # NeMo checkpoint name
pretrained_weights: True # Whether to load weights or just architecture
# Fine-tune from a previous training checkpoint (weights only, fresh optimizer)
init_from_checkpoint: null # path to .ckpt, DCP dir, or HF dir
# Special token settings
audio_locator_tag: "<audio>" # Tag to replace with audio embeddings
# Freezing parameters
freeze_params:
- "^llm\\.model\\.layers\\.[0-4]\\..+$" # Regex patterns for parameters to freeze
prevent_freeze_params: [] # Override freeze_params for specific submodules
# Optional LoRA settings for efficient fine-tuning
lora:
task_type: CAUSAL_LM
r: 8
lora_alpha: 32
lora_dropout: 0.1
# Audio perception module configuration
perception:
target: nemo.collections.speechlm2.modules.perception.AudioPerceptionModule
preprocessor:
normalize: 'NA'
encoder:
self_attention_model: rel_pos
att_context_size: [-1, -1]
conv_context_size: regular
conv_norm_type: batch_norm
modality_adapter:
_target_: nemo.collections.asr.modules.ConformerEncoder
feat_in: 1024
feat_out: -1
n_layers: 2
d_model: 1024
subsampling: dw_striding
subsampling_factor: 1
subsampling_conv_channels: 256
causal_downsampling: false
ff_expansion_factor: 4
self_attention_model: rel_pos
n_heads: 8
att_context_size: [-1, -1]
att_context_style: regular
xscaling: true
untie_biases: true
pos_emb_max_len: 5000
conv_kernel_size: 9
conv_norm_type: batch_norm
conv_context_size: null
dropout: 0
dropout_pre_encoder: 0
dropout_emb: 0.0
SALMAutomodel Configuration
----------------------------
The SALMAutomodel configuration extends the SALM configuration with NeMo Automodel
support. The key difference is ``use_nemo_automodel: true`` and the use of
``AutomodelParallelStrategy`` instead of ``DDPStrategy``.
The example below shows a configuration for training with NVIDIA Nemotron Nano V3
MoE as the LLM backbone, with Expert Parallelism across 8 GPUs:
.. code-block:: yaml
model:
use_nemo_automodel: true # Selects SALMAutomodel in salm_train.py
pretrained_llm: nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16
pretrained_asr: "nvidia/canary-1b-flash"
pretrained_weights: True
encoder_chunk_size_seconds: 30.0
freeze_params:
- "^llm\\..+$"
- "^perception\\.preprocessor\\..+$"
- "^perception\\.encoder\\..+$"
prevent_freeze_params: []
# LoRA uses Automodel-native format (not HF PEFT):
# lora:
# dim: 128
# alpha: 256
# dropout: 0.01
# target_modules: ["q_proj", "v_proj"]
perception:
target: nemo.collections.speechlm2.modules.perception.AudioPerceptionModule
output_dim: 2048
modality_adapter:
_target_: nemo.collections.speechlm2.modules.perception.IdentityConnector
d_model: 1024
trainer:
strategy:
_target_: nemo.collections.speechlm2.parts.parallel.AutomodelParallelStrategy
ep_size: 8 # Expert Parallelism across 8 GPUs for MoE
# tp_size: 1
# dp_size: null # inferred
NeMo Automodel applies MoE-specific optimizations automatically when an MoE model
is detected:
* **Grouped GEMM** — fuses expert computations into a single batched matrix multiply
for higher GPU throughput.
* **DeepEP** (Deep Expert Parallelism) — efficient all-to-all expert routing across
GPUs, minimizing communication overhead for MoE layers.
Note the differences from the SALM configuration:
* ``model.use_nemo_automodel: true`` — selects ``SALMAutomodel`` in the training script.
* ``model.pretrained_llm`` can point to MoE models like ``nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16``.
* ``trainer.strategy._target_`` uses ``AutomodelParallelStrategy`` instead of ``ModelParallelStrategy``.
* ``ep_size`` controls Expert Parallelism on the FSDP data-parallel axis — dense layers are sharded via FSDP2, while MoE layers use EP for expert routing on the same GPUs.
* LoRA config uses ``dim``/``alpha`` keys (Automodel native) instead of ``r``/``lora_alpha`` (HF PEFT).
* No ``embed_tokens`` freeze pattern — embeddings stay inside the LLM.
* ``encoder_chunk_size_seconds`` controls long-audio chunking for the speech encoder.
Audio rows longer than this value are split on the time axis, encoded as a chunk
batch, and concatenated back into one embedding sequence before the LLM forward.
Set it to ``null`` to disable chunking.
SALMAutomodel-Specific Options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The SALMAutomodel config exposes a few extra knobs that pass through to NeMo
Automodel. All are optional — defaults preserve standard behavior.
**MoE training:**
.. code-block:: yaml
model:
# MoE auxiliary load-balancing loss coefficient. > 0 to enable.
# Gradients are injected during backward; reported CE loss is unchanged.
aux_loss_coeff: 0.0
# When true, unfreezes Gate.weight so the router can adapt to new data.
# Default false keeps pretrained routing frozen.
train_gate: false
# Per-step expert balance / utilization metrics.
moe_metrics:
enabled: true
mode: brief # "brief" or "detailed"
detailed_every_steps: null # null = every step when mode=detailed
top_k_experts: 5 # top/bottom utilization experts to report
When ``aux_loss_coeff > 0``, SALMAutomodel sets ``MoEAuxLossAutoScaler.main_loss_backward_scale``
to the DP group size at ``on_fit_start`` so FSDP's gradient averaging cancels out and the
net aux-loss gradient scale stays at 1.
**torch.compile:**
.. code-block:: yaml
model:
compile:
enabled: false
mode: default # "default" | "reduce-overhead" | "max-autotune"
fullgraph: false
dynamic: true # Recommended for variable-length audio
backend: null # null = inductor
dynamo_cache_size_limit: 256
**Backend dispatch (attention / linear / norm / MoE kernels):**
.. code-block:: yaml
model:
automodel_backend:
attn: te # "te" | "sdpa" | "flex"
linear: te # "torch" | "te"
rms_norm: torch_fp32 # "torch" | "torch_fp32" | "te"
rope_fusion: true
experts: torch_mm # "torch" | "te" | "gmm" | "torch_mm"
dispatcher: deepep # "torch" | "deepep" | "hybridep" | "uccl_ep"
dispatcher_num_sms: 20
# Pin SDPA kernel when automodel_backend.attn=sdpa.
# E.g. ["flash_attention"] forces FA2 and errors if unavailable.
sdpa_method: null
Defaults come from Automodel's ``BackendConfig`` and auto-select TransformerEngine /
DeepEP when available; override here to pin a specific backend (for example,
``attn: sdpa`` to bypass TE).
**Packed sequences (THD):**
.. code-block:: yaml
model:
packed_sequences: true # default false (right-padded BSHD path)
automodel_backend:
attn: te # THD path dispatches TE varlen FlashAttention
When ``packed_sequences`` is true, ``SALMAutomodel.prepare_inputs`` packs
each minibatch into a single flat ``[T_total, H]`` sequence with a
``cu_seqlens`` index instead of right-padding to ``[B, T_max, H]``.
``SALMAutomodel`` then forwards the THD metadata (``qkv_format``,
``cu_seqlens``, ``position_ids``, ``max_seqlen``) through ``forward()`` to
the LLM. The TE attention preprocessor splits the singular ``max_seqlen``
into the ``max_seqlen_q`` / ``max_seqlen_kv`` pair that
``DotProductAttention`` requires for ``qkv_format="thd"``. The packing also
rounds each utterance's flat length up to a multiple of ``2 * cp_size`` so
the same THD batch satisfies TE's CP DualChunkSwap contract — see the
"Context Parallelism (CP)" subsection in
:doc:`training_and_scaling` for the recommended pairing with ``cp_size > 1``.
Padding overhead drops from ``O(B * (T_max - T_avg))`` to
``O(per-utt rounding to 2*cp_size)``. Throughput improvement scales with
the variance of utterance lengths in your bucketing.
DuplexS2SModel Configuration
-----------------------------
The DuplexS2SModel adds speech generation capabilities to the configuration:
.. code-block:: yaml
model:
# Pretrained model paths
pretrained_llm: "TinyLlama/TinyLlama_v1.1"
pretrained_audio_codec: "path/to/audio_codec.nemo"
pretrained_asr: "stt_en_fastconformer_hybrid_large_streaming_80ms"
scoring_asr: "stt_en_fastconformer_transducer_large" # used only in validation
# Loss weights
audio_loss_weight: 4
text_loss_weight: 3
# Perception module config (similar to SALM)
perception:
# ... (similar to SALM perception module)
DuplexS2SSpeechDecoderModel Configuration
-----------------------------------------
The DuplexS2SSpeechDecoderModel is similar to DuplexS2SModel, but focuses on an additional speech generation transformer decoder:
.. code-block:: yaml
model:
# Pretrained model paths
pretrained_llm: "TinyLlama/TinyLlama_v1.1"
pretrained_audio_codec: "path/to/audio_codec.nemo"
pretrained_asr: "stt_en_fastconformer_hybrid_large_streaming_80ms"
# Speech decoder settings
speech_decoder:
target: nemo.collections.speechlm2.modules.speech_generation.TransformerARSpeechDecoder
d_model: 1024
n_layers: 12
n_heads: 16
d_kv: 64
d_ff: 4096
max_seq_len: 2048
dropout: 0.1
layernorm_epsilon: 1e-5
activation_function: "gelu_new"
init_method_std: 0.02
use_cache: True
# ... other settings
DuplexSTTModel Configuration
--------------------------------------
The DuplexSTTModel is a speech-to-text model that processes duplex audio conversations and generates agent text responses:
.. code-block:: yaml
model:
# Pretrained model paths
pretrained_llm: "TinyLlama/TinyLlama_v1.1"
pretrained_asr: "stt_en_fastconformer_hybrid_large_streaming_80ms"
# ... other settings
Trainer Configuration
---------------------
The trainer section contains PyTorch Lightning Trainer settings:
.. code-block:: yaml
trainer:
devices: 1
num_nodes: 1
accelerator: gpu
precision: bf16-true
logger: false
enable_checkpointing: false # handled by exp_manager
replace_sampler_ddp: false # handled by lhotse
max_epochs: null
max_steps: 100000
log_every_n_steps: 10
val_check_interval: 2000
accumulate_grad_batches: 1
gradient_clip_val: 1.0
Experiment Manager Configuration
--------------------------------
The exp_manager section contains settings for experiment logging and model checkpointing:
.. code-block:: yaml
exp_manager:
explicit_log_dir: path/to/output_dir
exp_dir: null
name: ${name}
create_wandb_logger: false # set to true if you want to use wandb
wandb_logger_kwargs:
project: null
name: null
resume_if_exists: true
resume_ignore_no_checkpoint: true
create_checkpoint_callback: true
checkpoint_callback_params:
monitor: val_loss
filename: "{step}" # checkpoint name will be step=<step>.ckpt
save_top_k: 1
mode: min
create_tensorboard_logger: false # set to true if you want to use tensorboard
version: null
Data Configuration
------------------
The data section defines dataset paths, preprocessing, and data loading parameters:
.. code-block:: yaml
data:
train_ds:
sample_rate: ${data.target_sample_rate}
input_cfg:
- type: lhotse_shar
shar_path: /path/to/train_data
seed: 42
shard_seed: "randomized"
num_workers: 4
batch_size: 16
# Optional bucketing settings
# batch_duration: 100
# bucket_duration_bins: [8.94766,10.1551,11.64118,19.30376,42.85]
# use_bucketing: true
# num_buckets: 5
# bucket_buffer_size: 5000
validation_ds:
datasets:
val_set_name:
shar_path: /path/to/validation_data
sample_rate: ${data.target_sample_rate}
batch_size: 1
seed: 42
shard_seed: "randomized"
Depending on the model, there may be additional options available under ``data`` namespace that are passed to the corresponding Dataset class.
For example, S2S models have:
.. code-block:: yaml
data:
frame_length: 0.08
source_sample_rate: 16000
target_sample_rate: 22050
input_roles: ["user", "User"]
output_roles: ["agent", "Assistant"]
train_ds: ...
Important Configuration Parameters
-----------------------------------
Model Parameters
^^^^^^^^^^^^^^^^
- **pretrained_llm**: Path to the pretrained HuggingFace LLM
- **pretrained_asr**: Name of the pretrained NeMo ASR model used for perception
- **encoder_chunk_size_seconds**: Speech-encoder chunk size in seconds for long audio inputs
(supported by both ``SALM`` and ``SALMAutomodel``). Leave as ``null`` to encode each audio
row directly
- **pretrained_audio_codec**: Path to the pretrained audio codec model (for speech generation)
- **init_from_checkpoint**: Path to a training checkpoint to initialize model weights from (see :ref:`fine-tuning-from-checkpoint` below)
- **freeze_params**: Regex patterns of parameters to freeze during training
- **audio_loss_weight/text_loss_weight**: Weighting of different loss components
Perception Module
^^^^^^^^^^^^^^^^^
- **self_attention_model**: Type of attention mechanism ("rel_pos" or "abs_pos")
- **att_context_size**: Context window size for attention ([left, right])
- **conv_context_size**: Context type for convolutions ("causal" or "regular")
- **n_layers**: Number of encoder layers
- **d_model**: Model dimension size
Data Parameters
^^^^^^^^^^^^^^^
- **frame_length**: Frame duration in seconds
- **source_sample_rate/target_sample_rate**: Sample rates for input/output audio
- **input_roles/output_roles**: Speaker roles for input and output
- **batch_size**: Number of samples per batch
- **use_bucketing**: Whether to use length-based bucketing for efficient batching
Example Configuration Files
---------------------------
Example configurations for all model types can be found in the example directory:
- SALM: `examples/speechlm2/conf/salm.yaml`
- SALMAutomodel: `examples/speechlm2/conf/salm_automodel.yaml`
- DuplexS2SModel: `examples/speechlm2/conf/s2s_duplex.yaml`
- DuplexS2SSpeechDecoderModel: `examples/speechlm2/conf/s2s_duplex_speech_decoder.yaml`
- DuplexSTTModel: `examples/speechlm2/conf/duplex_stt.yaml`
Using Configuration Files
-------------------------
You can use these configurations with the training scripts by specifying the config path:
.. code-block:: bash
# Train SALM model
python examples/speechlm2/salm_train.py \
--config-path=conf \
--config-name=salm
# Train SALMAutomodel
python examples/speechlm2/salm_train.py \
--config-name=salm_automodel
You can also override configuration values from the command line:
.. code-block:: bash
python examples/speechlm2/salm_train.py \
--config-path=conf \
--config-name=salm \
model.pretrained_llm="different/llm/path" \
trainer.max_steps=1000 \
data.train_ds.batch_size=8
.. _fine-tuning-from-checkpoint:
Fine-Tuning from a Previous Checkpoint
---------------------------------------
To start a new training run initialized from a previous checkpoint — with a fresh
optimizer, LR scheduler, and step counter — set ``model.init_from_checkpoint``:
.. code-block:: yaml
model:
init_from_checkpoint: /path/to/checkpoints/step=6375.ckpt
Or pass it as a Hydra override:
.. code-block:: bash
python examples/speechlm2/salm_train.py \
--config-name=salm_automodel \
++model.init_from_checkpoint=/path/to/checkpoints/step=6375.ckpt
This differs from ``exp_manager.resume_from_checkpoint`` which restores the
**full** training state (optimizer, scheduler, step counter) to continue an
interrupted run. ``init_from_checkpoint`` only loads model weights, giving you a
clean starting point for fine-tuning on different data or with different
hyperparameters.
Supported Checkpoint Formats
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Three checkpoint formats are supported:
* **Distributed checkpoints (DCP)**: Directories with a ``.metadata`` file, produced
by ``ModelParallelStrategy`` / ``AutomodelParallelStrategy``. This is the default
format when training with FSDP2 or TP. DCP loading handles automatic resharding
when the parallelism configuration differs between the source and target runs.
* **HuggingFace model directories**: Directories containing ``model.safetensors``,
such as the output of ``to_hf.py``.
* **Single-file checkpoints**: Standard ``.ckpt`` or ``.pt`` files with a
``state_dict`` key.
The model architecture is still defined by ``pretrained_llm`` and ``pretrained_asr``
(needed for config and tokenizer initialization), but all weights are overridden by
the checkpoint.
This feature works with both ``SALM`` and ``SALMAutomodel``.
.. note::
``init_from_checkpoint`` requires the source and target models to use the
same model class (e.g., both ``SALMAutomodel``). Cross-model loading
(e.g., ``SALM`` checkpoint into ``SALMAutomodel``) will encounter state dict
key mismatches because the two classes structure the embedding layer differently.
+453
View File
@@ -0,0 +1,453 @@
Datasets
========
The speechlm2 collection supports datasets that contain both audio and text data for training models that can understand speech and generate appropriate responses.
This section describes the dataset format, preparation, and usage with the speechlm2 models.
Dataset Format
--------------
Duplex S2S models use the Lhotse framework for audio data management. The primary datasets used are:
1. **DuplexS2SDataset**: For general duplex speech-to-speech models
2. **SALMDataset**: Specifically for the Speech-Augmented Language Model (SALM), which processes speech+text and outputs text.
3. **DuplexSTTDataset**: For the DuplexSTTModel, which processes conversational audio and generates text responses.
4. **DuplexEARTTSDataset**: Dataset for Duplex EARTTS model, extending DuplexS2SDataset with additional output fields for TTS, including audio prompting. It optionally prepends an audio prompt (speaker reference) to target_audio, which is used to initialize speaker conditioning in the EARTTS model. The dataset provides audio_prompt, audio_prompt_lens, non_prompt_mask, aligned_attention_mask, and aligned_position_ids, and supports custom speaker reference audio through the context_audio field, while preserving full compatibility with the original data format.
DuplexS2S Dataset Structure
^^^^^^^^^^^^^^^^^^^^^^^^^^^
A typical dataset for speechlm2 models consists of:
1. **Audio files**: Contains source audio (input speech) and possibly target audio (output speech)
2. **Text transcriptions**: Associated text for both input and output speech
3. **Role identifiers**: To distinguish between speakers (e.g., "user" vs "agent")
The dataset organization is built around the concept of conversation turns, with each turn containing audio and text from either a user or an agent/assistant.
The datasets are primarily managed using Lhotse's CutSet format, which provides efficient handling of audio data and annotations. A typical Lhotse manifest includes:
- Audio recording information (path, duration, sample rate)
- Supervision information (transcripts, speaker roles, timing)
- Optional additional annotations
Example of a Lhotse cut:
.. code-block:: python
{
"id": "conversation_1",
"start": 0,
"duration": 10.7,
"channel": 0,
"supervisions": [
{
"id": "conversation_1_turn_0",
"text": "Can you help me with this problem?",
"start": 0,
"duration": 5.2,
"speaker": "user"
},
{
"id": "conversation_1_turn_1",
"text": "I can help you with that.",
"start": 5.2,
"duration": 3.1,
"speaker": "assistant"
}
],
"recording": {
"id": "conversation_1_user",
"path": "/path/to/audio/conversation_1_user.wav",
"sampling_rate": 16000,
"num_samples": 171200,
"duration": 10.7
},
"custom": {
"target_audio": {
"id": "conversation_1_assistant",
"path": "/path/to/audio/conversation_1_assistant.wav",
"sampling_rate": 22050,
"num_samples": 235935,
"duration": 10.7
}
}
}
The DuplexS2SDataset performs several key operations when processing data:
1. **Turn Identification**: Each cut contains a list of `supervisions` with objects of type `lhotse.SupervisionSegment` that represent conversation turns with corresponding text and speaker information.
2. **Speaker Role Separation**: The text of each supervision is tokenized and identified as the model's output (when `supervision.speaker` is in `output_roles`, e.g., "agent" or "Assistant") or the model's input (when in `input_roles`, e.g., "user" or "User").
3. **Token Sequence Generation**:
- `target_tokens` and `source_tokens` arrays are created with a length equal to `lhotse.utils.compute_num_frames(cut.duration, frame_length, cut.sampling_rate)`
- The `frame_length` parameter (typically 80ms) determines the temporal resolution of token assignments
- Each token is assigned to a position based on its corresponding audio segment's timing
4. **Token Offset Calculation**:
- The starting position for each turn's tokens is determined using `lhotse.utils.compute_num_frames(supervision.start, frame_length)`
- This ensures tokens are aligned with their corresponding audio segments
5. **Length Validation**:
- If token sequences are too long compared to the audio duration, warnings are emitted
- Tokens that extend beyond the audio length are truncated
This process ensures that the model can correctly align audio input with corresponding text, and learn to generate appropriate responses based on the conversation context.
DuplexS2SDataset
****************
This dataset class is designed for models that handle both speech understanding and speech generation. It processes audio inputs and prepares them for the model along with corresponding text.
.. code-block:: python
from nemo.collections.speechlm2.data import DuplexS2SDataset
dataset = DuplexS2SDataset(
tokenizer=model.tokenizer, # Text tokenizer
frame_length=0.08, # Frame length in seconds
source_sample_rate=16000, # Input audio sample rate
target_sample_rate=22050, # Output audio sample rate
input_roles=["user", "User"], # Roles considered as input
output_roles=["agent", "Assistant"] # Roles considered as output
)
SALMDataset Structure
^^^^^^^^^^^^^^^^^^^^^
Data used for SALM can be either regular speech-to-text data (in any NeMo or Lhotse format), or a dataset of multi-turn conversions.
For the most part, please refer to :doc:`the ASR datasets documentation <../asr/datasets>` for details on data formats and multimodal dataloading.
When using speech-to-text data, you'll need read it with a special ``lhotse_as_conversation`` data reader
that creates a two-turn, query+response, multi-modal conversation data types out of regular Lhotse cuts.
This approach makes SALM training more flexible, allowing straightforward combination of single-turn and multi-turn data.
Each audio turn is represented as a single token, defined in ``audio_locator_tag`` property, and automatically added to the model's tokenizer inside model code.
This token is replaced during the training/generation pass with its corresponding audio segment representation.
Example YAML configuration using existing ASR datasets with ``lhotse_as_conversation``:
.. code-block:: yaml
data:
train_ds:
prompt_format: "llama3" # Choose based on your model
token_equivalent_duration: 0.08
input_cfg:
# Example 1: Using standard ASR Lhotse manifests (JSONL)
- type: lhotse_as_conversation
cuts_path: /path/to/librispeech_train_clean_100.jsonl.gz
audio_locator_tag: "<|audioplaceholder|>"
tags:
context: "Transcribe the following audio:"
# Optional system prompt can be uncommented
# system_prompt: "You are a helpful assistant that transcribes audio accurately."
# Example 2: Using tarred NeMo manifests
- type: lhotse_as_conversation
manifest_filepath: /path/to/tedlium_train_manifest.jsonl.gz
tarred_audio_filepaths: /path/to/tedlium_shards/shard-{000000..000009}.tar
audio_locator_tag: "<|audioplaceholder|>"
tags:
context: "Write down what is said in this recording:"
# Example 3: Using Lhotse SHAR format
- type: lhotse_as_conversation
shar_path: /path/to/fisher_shar/
audio_locator_tag: "<|audioplaceholder|>"
tags:
context: "Listen to this clip and write a transcript:"
# ... other settings
Alternatively, one can provide an existing YAML file with their dataset composition and wrap
it in a ``lhotse_as_conversation`` reader as follows:
.. code-block:: yaml
data:
train_ds:
input_cfg:
- type: lhotse_as_conversation
input_cfg: /path/to/dataset_config.yaml
audio_locator_tag: "<|audioplaceholder|>"
tags:
context: "Transcribe the following audio:"
# Optional system prompt can be uncommented
# system_prompt: "You are a helpful assistant that transcribes audio accurately."
The ``lhotse_as_conversation`` reader automatically creates a two-turn conversation from each ASR example:
1. Optionally, if ``system_prompt`` tag is provided, it's added as a special system turn for LLM models that support system prompts.
2. A user turn containing the audio and a text context (from the ``context`` tag)
3. An assistant turn containing the transcription (from the cut's supervision text)
If a ``context`` tag is provided in the configuration, it's added as a text turn before the audio.
SALMDataset
***********
This dataset class is specialized for the SALM model, which focuses on understanding speech input and generating text output.
.. code-block:: python
from nemo.collections.speechlm2.data import SALMDataset
dataset = SALMDataset(
tokenizer=model.tokenizer, # Text tokenizer
)
AIStore GetBatch (multimodal conversations) (experimental)
**********************************************************
`AIStore GetBatch <https://docs.nvidia.com/aistore/get_batch>`_ is a server-side
batched object-fetch API; see the `paper <https://arxiv.org/html/2602.22434v1>`_
for the design and motivation.
For tarred multimodal conversation manifests (``NeMoMultimodalConversationJsonlAdapter``
and ``NeMoMultimodalConversationShareGPTJsonlAdapter``), set the environment variable
``USE_AIS_GET_BATCH=true`` to enable AIStore GetBatch loading:
.. code-block:: bash
USE_AIS_GET_BATCH=true python examples/speechlm2/salm_train.py \
--config-name=salm_automodel ...
When enabled:
* The adapters skip opening tar files and instead build URL-backed cuts whose
``AudioSource`` points at the per-shard audio location (the JSONL ``value``
field is trusted to match the tar layout).
* ``SALMDataset`` constructs its loader as
``AudioSamples(use_batch_loader=True, fault_tolerant=True, mono_downmix=True)``,
which issues a single batched fetch per minibatch instead of per-cut reads.
* ``collate_conversation_audio_fault_tolerant`` delegates loading and collation
to ``AudioSamples`` and drops every conversation whose cuts didn't survive
the fetch — preserving the legacy fault-tolerant semantics.
Leave the env var unset to keep the original tar-iterating loader.
DuplexSTTDataset
****************
This dataset class is specialized for the DuplexSTTModel, which processes duplex conversational audio and generates text responses. Unlike DuplexS2SDataset which outputs speech, this dataset prepares data for speech-to-text conversion in duplex conversations.
.. code-block:: python
from nemo.collections.speechlm2.data import DuplexSTTDataset
dataset = DuplexSTTDataset(
tokenizer=model.tokenizer, # Text tokenizer
frame_length=0.08, # Frame length for audio processing
source_sample_rate=16000, # Audio sample rate
input_roles=["User"], # Roles to use as input
output_roles=["Assistant"], # Roles to generate text for
)
DataModule
----------
The DataModule class in the speechlm2 collection manages dataset loading, preparation, and batching for PyTorch Lightning training:
.. code-block:: python
from nemo.collections.speechlm2.data import DataModule
datamodule = DataModule(
cfg_data, # Configuration dictionary for data
tokenizer=model.tokenizer, # Text tokenizer
dataset=dataset # Instance of DuplexS2SDataset, DuplexSTTDataset, or SALMDataset
)
The DataModule takes care of:
1. Setting up proper data parallel ranks for dataloaders
2. Instantiating the dataloaders with configuration from YAML
3. Managing multiple datasets for validation/testing
Bucketing for Efficient Training
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The DataModule supports bucketing for more efficient training. Bucketing groups samples of similar lengths together, which reduces padding and improves training efficiency. The key bucketing parameters are:
1. **batch_duration**: Target cumulative duration (in seconds) of samples in a batch
2. **bucket_duration_bins**: List of duration thresholds for bucketing
3. **use_bucketing**: Flag to enable/disable bucketing
4. **num_buckets**: Number of buckets to create
5. **bucket_buffer_size**: Number of samples to load into memory for bucket assignment
Example bucketing configuration:
.. code-block:: yaml
train_ds:
# ... other settings
batch_duration: 100 # Target 100 seconds per batch
bucket_duration_bins: [8.94766, 10.1551, 11.64118, 19.30376, 42.85] # Duration thresholds
use_bucketing: true # Enable bucketing
num_buckets: 5 # Create 5 buckets
bucket_buffer_size: 5000 # Buffer size for bucket assignment
When bucketing is enabled:
1. Samples are grouped into buckets based on their duration
2. Each batch contains samples from the same bucket
3. The actual batch size can vary to maintain a consistent total duration
4. The target batch_duration ensures efficient GPU memory usage
Bucketing helps to:
- Reduce padding and increase effective batch size
- Improve training efficiency and convergence
- Manage memory usage with variable-length inputs
Data Configuration
------------------
A typical data configuration in YAML includes:
.. code-block:: yaml
data:
train_ds:
sample_rate: ${data.target_sample_rate}
input_cfg:
- type: lhotse_shar
shar_path: /path/to/train_data
seed: 42
shard_seed: "randomized"
num_workers: 4
# Optional bucketing settings
batch_duration: 100
bucket_duration_bins: [8.94766, 10.1551, 11.64118, 19.30376, 42.85]
use_bucketing: true
num_buckets: 5
bucket_buffer_size: 5000
# batch_size: 4 # alternative to bucketing
validation_ds:
datasets:
val_set_name_0:
shar_path: /path/to/validation_data_0
val_set_name_1:
shar_path: /path/to/validation_data_1
sample_rate: ${data.target_sample_rate}
batch_size: 4
seed: 42
shard_seed: "randomized"
Note that the actual dataset paths and blend are defined by the YAML config, not Python code. This makes it easy to change the dataset composition without modifying the code.
To learn more about the YAML data config, see :ref:`the Extended multi-dataset configuration format <asr-dataset-config-format>` section in the ASR documentation.
Preparing S2S Datasets
----------------------
Creating Lhotse Manifests
^^^^^^^^^^^^^^^^^^^^^^^^^
To prepare your own dataset, you'll need to create Lhotse manifests from your audio files and transcripts:
.. code-block:: python
from lhotse import CutSet, Recording, SupervisionSegment
# Create a recording for user and assistant
recording_user = Recording(
id="conversation_1_user",
path="/path/to/audio/conversation_1_user.wav",
sampling_rate=16000,
num_samples=171200,
duration=10.7
)
recording_assistant = Recording(
id="conversation_1_assistant",
path="/path/to/audio/conversation_1_assistant.wav",
sampling_rate=22050,
num_samples=235935,
duration=10.7
)
# Create supervision for this recording
supervisions = [
SupervisionSegment(
id="conversation_1_turn_0",
recording_id="conversation_1",
start=0,
duration=5.2,
text="Can you help me with this problem?",
speaker="user"
),
SupervisionSegment(
id="conversation_1_turn_1",
recording_id="conversation_1",
start=5.5,
duration=3.1,
text="I can help you with that.",
speaker="assistant"
),
]
# Create a CutSet
# The assistant's response is located in target_audio field which makes it easy to replace
# when using multiple models or speakers for synthetic data generation.
cut = recording.to_cut()
cut.supervisions = supervisions
cut.target_audio = recording_assistant
cutset = CutSet([cut])
# Save to disk
cutset.to_file("path/to/manifest.jsonl.gz")
Converting to SHAR Format
^^^^^^^^^^^^^^^^^^^^^^^^^
For efficient training, it's recommended to convert your Lhotse manifests to SHAR (SHarded ARchive) format:
.. code-block:: python
from lhotse import CutSet
from lhotse.shar import SharWriter
cutset = CutSet.from_file("path/to/manifest.jsonl.gz")
cutset.to_shar("path/to/train_shar", fields={"recording": "flac", "target_audio": "flac"}, shard_size=100)
Training with Prepared Datasets
-------------------------------
Once your datasets are prepared, you can use them to train a model:
.. code-block:: python
# Load configuration
config_path = "path/to/config.yaml"
cfg = OmegaConf.load(config_path)
# The training data paths are available in the config file:
# cfg.data.train_ds.input_cfg[0].shar_path = "path/to/train_shar"
# Create dataset and datamodule
dataset = DuplexS2SDataset(
tokenizer=model.tokenizer,
frame_length=cfg.data.frame_length,
source_sample_rate=cfg.data.source_sample_rate,
target_sample_rate=cfg.data.target_sample_rate,
input_roles=cfg.data.input_roles,
output_roles=cfg.data.output_roles,
)
datamodule = DataModule(cfg.data, tokenizer=model.tokenizer, dataset=dataset)
# Train the model
trainer.fit(model, datamodule)
Example S2S Datasets
--------------------
While there are no publicly available datasets specifically formatted for Duplex S2S models yet, you can adapt conversation datasets with audio recordings such as:
1. Fisher Corpus
2. Switchboard Corpus
3. CallHome
4. Synthetic conversation datasets generated using TTS
You would need to format these datasets as Lhotse manifests with appropriate speaker role annotations to use them with the speechlm2 S2S models.
+399
View File
@@ -0,0 +1,399 @@
SpeechLM2
================================
.. note::
The SpeechLM2 collection is still in active development and the code is likely to keep changing.
.. note::
Install your chosen compatible PyTorch stack first, then install SpeechLM2 with
``uv pip install 'nemo-toolkit[speechlm2]'`` (or, from a source checkout, ``uv pip install -e '.[speechlm2]'``)
to get all required dependencies including NeMo Automodel. See :ref:`installation` for details.
SpeechLM2 refers to a collection that augments pre-trained Large Language Models (LLMs) with speech understanding and generation capabilities.
This collection is designed to be compact, efficient, and to support easy swapping of different LLMs backed by HuggingFace AutoModel or NeMo Automodel.
It has a first-class support for using dynamic batch sizes via Lhotse and various model parallelism techniques (e.g., FSDP2, Tensor Parallel, Sequence Parallel) via PyTorch DTensor API.
We currently support six main model types:
* **SALM** (Speech-Augmented Language Model) - a simple but effective approach to augmenting pre-trained LLMs with speech understanding capabilities. Available in two variants:
* ``SALM`` — uses HuggingFace Transformers for the LLM backbone with optional HF PEFT LoRA.
* ``SALMAutomodel`` — uses `NeMo Automodel <https://github.com/NVIDIA-NeMo/Automodel>`_ for the LLM backbone with native LoRA, advanced parallelism (FSDP2, TP, SP, EP via ``AutomodelParallelStrategy``), and MoE optimizations (Grouped GEMM, DeepEP) for efficient training with models like `NVIDIA Nemotron Nano V3 <https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16>`_.
* **DuplexS2SModel** - a full-duplex speech-to-speech model with an ASR encoder, directly predicting discrete audio codes.
* **DuplexS2SSpeechDecoderModel** - a variant of DuplexS2SModel with a separate transformer decoder for speech generation.
* **DuplexEARTTS** - a ready-to-use duplex text-to-speech model that supports user interruption via a special text interruption token.
* **DuplexSTTModel** - a decoder model to generate agent text in duplex, in response to both user speech and text inputs.
* **NemotronVoiceChat** - an *inference-only* pipeline that seamlessly merges `DuplexSTTModel` and `DuplexEARTTS` to deliver an end-to-end, full-duplex conversational agent with high-fidelity speech generation.
Using Pretrained Models
-----------------------
After :ref:`installing NeMo<installation>`, you can load and use a pretrained speechlm2 model as follows:
.. code-block:: python
import nemo.collections.speechlm2 as slm
# Load a pretrained SALM model
model = slm.models.SALM.from_pretrained("model_name_or_path")
# Set model to evaluation mode
model = model.eval()
Inference with Pretrained Models
--------------------------------
SALM
****
You can run inference using the loaded pretrained SALM model:
.. code-block:: python
import torch
import soundfile as sf
from nemo.collections.audio.parts.utils.transforms import resample
import nemo.collections.speechlm2 as slm
model = slm.models.SALM.from_pretrained("path/to/pretrained_checkpoint").eval()
# Load audio file
audio_path = "path/to/audio.wav"
audio_signal, sample_rate = sf.read(audio_path)
audio_signal = torch.tensor(audio_signal).unsqueeze(0)
# Resample if needed
if sample_rate != 16000: # Most models expect 16kHz audio
audio_signal = resample(audio_signal, sample_rate, 16000)
sample_rate = 16000
# Prepare audio for model
audio_signal = audio_signal.to(model.device)
audio_len = torch.tensor([audio_signal.shape[1]], device=model.device)
# Create a prompt for SALM model inference
# The audio_locator_tag is a special token that will be replaced with audio embeddings
prompt = [{"role": "user", "content": f"{model.audio_locator_tag}"}]
# Generate response
with torch.inference_mode():
output = model.generate(
prompts=[prompt],
audios=audio_signal,
audio_lens=audio_len,
generation_config=None # You can customize generation parameters here
)
# Process the output tokens
response = model.tokenizer.ids_to_text(output[0])
print(f"Model response: {response}")
SALMAutomodel
*************
``SALMAutomodel`` is the NeMo Automodel variant of SALM. It enables efficient training of
Speech LLMs with MoE architectures like `NVIDIA Nemotron Nano V3 <https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16>`_
using MoE-specific optimizations (Grouped GEMM, DeepEP). It uses deferred initialization
(``configure_model()``) and supports distributed training and inference via
``AutomodelParallelStrategy``.
.. code-block:: python
import torch
import nemo.collections.speechlm2 as slm
from nemo.collections.speechlm2.parts.parallel import setup_distributed
# Initialize distributed and create an Automodel-compatible device mesh with EP=2.
# setup_distributed delegates mesh creation to nemo_automodel, which builds
# the full (pp, dp_replicate, dp_shard, cp, tp) mesh with MoE submeshes.
strategy = setup_distributed(ep_size=2)
# Load a pretrained SALMAutomodel with the Automodel device mesh
model = slm.models.SALMAutomodel.from_pretrained(
"path/to/checkpoint",
device_mesh=strategy.device_mesh,
distributed_config=strategy.distributed_config,
moe_config=strategy.moe_config,
moe_mesh=strategy.moe_mesh,
).eval()
# Inference is identical to SALM
with torch.inference_mode():
output = model.generate(
prompts=[prompt],
audios=audio_signal,
audio_lens=audio_len,
)
DuplexS2SModel
**************
You can run inference using the loaded pretrained DuplexS2SModel:
.. code-block:: python
import torch
import soundfile as sf
from nemo.collections.audio.parts.utils.transforms import resample
import nemo.collections.speechlm2 as slm
model = slm.models.DuplexS2SModel.from_pretrained("path/to/pretrained_checkpoint").eval()
# Load audio file
audio_path = "path/to/audio.wav"
audio_signal, sample_rate = sf.read(audio_path)
audio_signal = torch.tensor(audio_signal).unsqueeze(0)
# Resample if needed
if sample_rate != 16000: # Most models expect 16kHz audio
audio_signal = resample(audio_signal, sample_rate, 16000)
sample_rate = 16000
# Prepare audio for model
audio_signal = audio_signal.to(model.device)
audio_len = torch.tensor([audio_signal.shape[1]], device=model.device)
# Run offline inference
results = model.offline_inference(
input_signal=audio_signal,
input_signal_lens=audio_len
)
# Decode text and audio tokens
transcription = results["text"][0]
audio = results["audio"][0]
DuplexSTTModel
**************
You can run inference using the loaded pretrained DuplexSTTModel:
.. code-block:: python
import torch
import soundfile as sf
from nemo.collections.audio.parts.utils.transforms import resample
import nemo.collections.speechlm2 as slm
model = slm.models.DuplexSTTModel.from_pretrained("path/to/pretrained_checkpoint").eval()
# Load audio file
audio_path = "path/to/audio.wav"
audio_signal, sample_rate = sf.read(audio_path)
audio_signal = torch.tensor(audio_signal).unsqueeze(0)
# Resample if needed
if sample_rate != 16000:
audio_signal = resample(audio_signal, sample_rate, 16000)
sample_rate = 16000
# Prepare audio for model
audio_signal = audio_signal.to(model.device)
audio_len = torch.tensor([audio_signal.shape[1]], device=model.device)
# Run offline inference - generates text output only
results = model.offline_inference(
input_signal=audio_signal,
input_signal_lens=audio_len
)
# Decode text tokens
transcription = results["text"][0]
print(f"Transcription: {transcription}")
DuplexEARTTS
************
Because `DuplexEARTTS` relies on precise token padding and EOS placement to handle potential user interruptions, inference and evaluation are handled via the `duplex_eartts_eval.py` script following the MagpieTTS dataset format recipe.
The evaluation script processes a `JSONL` file where each line is a dictionary containing the text, the reference audio for the speaker, and the desired output audio filename.
**JSONL Format Examples:**
Single-Turn format (evaluates a continuous string):
.. code-block:: json
{"text": "Like really quickly and then they run off.", "context_audio_filepath": "speaker_1.wav", "audio_filepath": "audio_1.wav"}
Multi-Turn format (evaluates sequential conversational turns, padded incrementally):
.. code-block:: json
{"text": ["Yes.", "Sure.", "Right.", "I get what youre saying."], "context_audio_filepath": "speaker_2.wav", "audio_filepath": "audio_2.wav"}
**Running the Evaluation/Inference Script:**
.. code-block:: bash
python examples/speechlm2/duplex_eartts_eval.py \
--config-path=conf/ \
--config-name=duplex_eartts.yaml \
++checkpoint_path=/path/to/duplex_eartts/model.ckpt \
++datasets_json_path=/path/to/evalset_config.jsonl \
++out_dir=/path/to/output/audio_samples/ \
++user_custom_speaker_reference=/path/to/optional_override_speaker.wav
The script will decode the text, apply the target speaker conditioning, generate the resulting audio waveforms into `out_dir`, and compute ASR intelligibility metrics (CER/WER) on the generated speech.
NemotronVoiceChat
*****************
You can evaluate and run full-duplex inference using the `NemotronVoiceChat` pipeline. This model natively chains the `DuplexSTTModel` with the `DuplexEARTTS` speech decoder for an end-to-end response:
.. code-block:: python
import torch
import soundfile as sf
from nemo.collections.audio.parts.utils.transforms import resample
import nemo.collections.speechlm2 as slm
model = slm.models.NemotronVoiceChat.from_pretrained("path/to/pretrained_checkpoint").eval()
# Load user audio prompt
audio_path = "path/to/user_audio.wav"
audio_signal, sample_rate = sf.read(audio_path)
audio_signal = torch.tensor(audio_signal).unsqueeze(0)
# Resample to the source_sample_rate (usually 16kHz for STT perception)
if sample_rate != 16000:
audio_signal = resample(audio_signal, sample_rate, 16000)
sample_rate = 16000
# Prepare audio for model
audio_signal = audio_signal.to(model.device)
audio_len = torch.tensor([audio_signal.shape[1]], device=model.device)
# (Optional) Load an explicit speaker reference audio to condition the agent's voice
# speaker_audio, _ = sf.read("path/to/speaker_reference.wav")
# speaker_audio = torch.tensor(speaker_audio).unsqueeze(0).to(model.device)
# speaker_len = torch.tensor([speaker_audio.shape[1]], device=model.device)
# Note: If an explicit audio reference is not passed into `offline_inference`,
# the model relies on the internal config parameters:
# 1. model.cfg.inference_speaker_name (Highest priority preset, e.g., 'Megan')
# 2. model.cfg.inference_speaker_reference (Fallback audio file path)
# Run full offline inference
results = model.offline_inference(
input_signal=audio_signal,
input_signal_lens=audio_len,
# speaker_audio=speaker_audio, # Pass speaker reference if available
# speaker_audio_lens=speaker_len
)
# Decode the predicted text and generated speech waveform
generated_text = results["text"][0]
generated_speech = results["audio"][0]
print(f"Agent response: {generated_text}")
# generated_speech can now be saved or played (sampled at model.target_sample_rate)
Training a Model
----------------
This example demonstrates how to train a SALM model.
.. note::
**NemotronVoiceChat is an inference-only class.** It does not implement a `training_step` and cannot be trained using the pipeline below. To update its underlying capabilities, you must train the `DuplexSTTModel` and `DuplexEARTTS` models independently.
.. code-block:: python
from omegaconf import OmegaConf
import torch
from lightning.pytorch import Trainer
from lightning.pytorch.strategies import ModelParallelStrategy
import nemo.collections.speechlm2 as slm
from nemo.collections.speechlm2.data import SALMDataset, DataModule
from nemo.utils.exp_manager import exp_manager
# Load configuration
config_path = "path/to/config.yaml" # E.g., from examples/speechlm2/conf/salm.yaml
cfg = OmegaConf.load(config_path)
# Initialize PyTorch Lightning trainer
trainer = Trainer(
max_steps=100000,
accelerator="gpu",
devices=1,
precision="bf16-true",
strategy=ModelParallelStrategy(data_parallel_size=2, tensor_parallel_size=1),
limit_train_batches=1000,
val_check_interval=1000,
use_distributed_sampler=False,
logger=False,
enable_checkpointing=False,
)
# Set up experiment manager for logging
exp_manager(trainer, cfg.get("exp_manager", None))
# Initialize model with configuration
model = slm.models.SALM(OmegaConf.to_container(cfg.model, resolve=True))
# Create dataset and datamodule
dataset = SALMDataset(tokenizer=model.tokenizer)
datamodule = DataModule(cfg.data, tokenizer=model.tokenizer, dataset=dataset)
# Train the model
trainer.fit(model, datamodule)
Example Using Command-Line Training Script
------------------------------------------
Alternatively, you can train a model using the provided training scripts in the examples directory:
.. code-block:: bash
# Train a SALM model
python examples/speechlm2/salm_train.py \
--config-path=examples/speechlm2/conf \
--config-name=salm
# For SALM inference/evaluation
python examples/speechlm2/salm_eval.py \
pretrained_name=/path/to/checkpoint \
inputs=/path/to/test_manifest \
batch_size=64 \
max_new_tokens=128 \
output_manifest=generations.jsonl
To train the SALMAutomodel variant (with NeMo Automodel backend), use the ``salm_automodel`` config:
.. code-block:: bash
# Train SALMAutomodel with NVIDIA Nemotron Nano V3 MoE backbone on 8 GPUs
torchrun --nproc_per_node=8 examples/speechlm2/salm_train.py \
--config-name=salm_automodel \
model.pretrained_llm=nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16
The ``salm_automodel.yaml`` config sets ``model.use_nemo_automodel: true``, which selects the
``SALMAutomodel`` class. This variant supports ``AutomodelParallelStrategy`` for FSDP2/TP/EP
parallelism and MoE optimizations (Grouped GEMM, DeepEP).
For more detailed information on training at scale, model parallelism, and SLURM-based training, see :doc:`training and scaling <training_and_scaling>`.
Collection Structure
--------------------
The speechlm2 collection is organized into the following key components:
- **Models**: Contains implementations of DuplexS2SModel, DuplexS2SSpeechDecoderModel, DuplexSTTModel, SALM, SALMAutomodel, DuplexEARTTS, and the inference-only NemotronVoiceChat.
- **Modules**: Contains audio perception and speech generation modules.
- **Data**: Includes dataset classes and data loading utilities.
SpeechLM2 Documentation
-----------------------
For more information, see additional sections in the SpeechLM2 docs:
.. toctree::
:maxdepth: 1
models
datasets
configs
training_and_scaling
+341
View File
@@ -0,0 +1,341 @@
Models
======
The Duplex Speech-to-Speech (S2S) collection consists of several model architectures designed to enable conversational AI systems with speech understanding and generation capabilities. These models combine audio perception components with language models and speech synthesis to create end-to-end speech-to-speech systems.
Core Model Architectures
------------------------
The collection includes the following core model architectures:
DuplexEARTTS
^^^^^^^^^^^^
DuplexEARTTS is a streaming text-to-speech model designed for duplex speech-to-speech systems. It focuses on low-latency, fully streamable speech generation by converting text tokens into audio representations in real time.
The architecture is based on the Streaming TTS model proposed in `Audio Flamingo 3 <https://arxiv.org/abs/2507.08128>`_, with several extensions for duplex interaction:
* **Gated fusion of text and audio representations**: (`GatedProjectedSumRMSNorm`), enabling better multimodal integration.
* **Subword-aware embeddings**: (`SubwordFlagEmbedding`) to improve pronunciation for words composed of multiple text tokens.
* **Custom BOS/EOS embeddings**: (`BOSEOSEmbedding`) for interruption-aware, multi-turn duplex generation.
Key components:
* **RVQVAEModel**: An RVQ-based neural audio codec that compresses speech into discrete acoustic tokens using a convolutional encoder and reconstructs high-quality audio via a convolutional decoder.
* **RVQEARTTSModel**: A streaming speech generation model that predicts multiple RVQ codebooks in parallel using a Mixture-of-Gaussians (MoG) prediction head. It produces audio tokens autoregressively from text representations with minimal latency.
DuplexEARTTS is particularly useful for:
* Duplex speech-to-speech systems requiring interruption-aware synthesis.
* Low-latency text-to-speech generation.
* Real-time conversational agents with streamed audio output.
SALM (Speech-Augmented Language Model)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SALM is a speech-augmented language model that integrates an audio perception module with a pre-trained LLM. The model is designed to understand speech input and generate text responses.
This is an implementation of the `SALM paper <https://arxiv.org/abs/2310.09424>`_.
Key components:
* **Audio Perception Module**: Processes audio inputs and converts them into embeddings that can be understood by the LLM. This module leverages a pre-trained ASR model's encoder.
* **LLM**: A pre-trained large language model that receives the audio embeddings and generates appropriate text responses.
* **Audio Locator Tag**: A special token that serves as a placeholder in the input text, which gets replaced with the audio embeddings during processing.
SALM is particularly useful for:
* Speech-to-text applications where high-quality text generation is required
* Speech understanding tasks that benefit from the contextual understanding of an LLM
* Applications that need to handle mixed text and speech inputs
SALMAutomodel (NeMo Automodel variant)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SALMAutomodel is a variant of SALM that replaces HuggingFace Transformers with
`NeMo Automodel <https://github.com/NVIDIA-NeMo/Automodel>`_ for the LLM backbone.
It provides the same speech-augmented language model capabilities with additional
benefits for distributed training and inference — especially with Mixture-of-Experts
(MoE) models like `NVIDIA Nemotron Nano V3 <https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16>`_.
Key differences from SALM:
* **Deferred initialization**: The LLM and perception module are not loaded until
``configure_model()`` is called, enabling memory-efficient distributed loading
where each GPU only loads its own shard.
* **Native LoRA**: Uses NeMo Automodel's built-in LoRA instead of HuggingFace PEFT.
LoRA is applied before FSDP2 sharding for correct meta-device handling.
* **AutomodelParallelStrategy**: Integrates with a custom Lightning strategy that
delegates device mesh creation to NeMo Automodel, supporting FSDP2, TP, PP, CP,
EP (MoE), and HSDP.
* **MoE optimizations**: NeMo Automodel provides first-class support for
Mixture-of-Experts architectures with **Grouped GEMM** (fused expert computation
for higher throughput) and **DeepEP** (Deep Expert Parallelism for efficient
all-to-all expert routing across GPUs). This makes it possible to efficiently
train Speech LLMs using MoE backbones like NVIDIA Nemotron Nano V3 (30B total,
3B active parameters).
* **Embedding stays in LLM**: Unlike SALM (which moves ``embed_tokens`` out of the
LLM to avoid FSDP/TP hook issues), SALMAutomodel keeps embeddings inside the LLM
and uses ``F.embedding`` with explicit DTensor handling.
* **Encoder chunking**: Long audio inputs can be split into fixed-duration chunks
for the speech encoder, batched through the perception forward, and concatenated
back into one embedding sequence before the LLM forward. This is controlled by
``model.encoder_chunk_size_seconds`` in ``salm_automodel.yaml``; set it to
``null`` to encode each audio row directly. The same knob is also available in
``SALM`` via ``model.encoder_chunk_size_seconds`` in ``salm.yaml`` (defaults to
``null`` there to preserve existing behavior).
SALMAutomodel is particularly useful for:
* Efficient training of Speech LLMs with MoE backbones (e.g., Nemotron Nano V3)
* Large-scale distributed training with advanced parallelism strategies (FSDP2 with EP for MoE, TP)
* Models that benefit from native Automodel LoRA integration
* Inference with model parallelism (TP/EP)
DuplexS2SModel
^^^^^^^^^^^^^^
The DuplexS2SModel extends the SALM architecture to enable full speech-to-speech capabilities, adding the ability to generate speech output.
Key components:
* **Audio Perception Module**: Processes audio inputs into embeddings for the LLM.
* **LLM**: Processes audio embeddings and generates text or audio token responses.
* **Audio Codec**: Converts discrete audio tokens into speech waveforms.
* **Audio Head**: Predicts audio tokens for speech generation.
* **Embed Audio Tokens**: Embedding layers for audio token representation.
This model is particularly useful for:
* Complete conversational agents that can listen and respond with speech
* Voice assistants and interactive dialogue systems
* Applications requiring natural-sounding spoken responses
DuplexS2SSpeechDecoderModel
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This model focuses on the speech generation aspect of the duplex system, optimizing the decoder for high-quality speech output.
Key components:
* **Audio Perception Module**: Similar to other models, processes audio into embeddings.
* **Speech Decoder**: A specialized component for generating high-quality speech from text or audio representations.
* **TransformerARSpeechDecoder**: An autoregressive transformer-based decoder for speech generation.
This model is particularly useful for:
* Applications focusing on high-quality speech synthesis
* Systems where speech generation quality is the primary concern
* Specialized voice output applications
DuplexSTTModel
^^^^^^^^^^^^^^
This model focuses on speech-to-text conversion in duplex conversations, processing both user speech and generating agent text responses.
Key components:
* **Audio Perception Module**: Processes audio inputs into embeddings for the LLM.
* **LLM**: Processes audio embeddings and generates text responses.
* **Tokenizer**: Converts LLM outputs into readable text.
This model is particularly useful for:
* Speech-to-text applications in conversational settings
* Duplex systems where text responses are needed instead of speech
* Applications requiring transcript generation from spoken dialogue
NemotronVoiceChat
^^^^^^^^^^^^^^^^^
NemotronVoiceChat is an **inference-only**, end-to-end Duplex Speech-to-Speech pipeline. It achieves full-duplex conversational capabilities by seamlessly merging the `DuplexSTTModel` with the `DuplexEARTTS` model.
Because it is designed exclusively for evaluation, offline inference, and validation workflows (no training step is implemented), it is highly optimized for executing the full perception-generation-synthesis loop.
Key components:
* **DuplexSTTModel**: Handles the streaming audio perception and text response generation.
* **DuplexEARTTS**: Serves as the autoregressive speech decoder, generating high-fidelity audio from the STT model's text tokens in a streamable fashion.
This model is particularly useful for:
* End-to-end evaluation of the complete speech-to-speech pipeline.
* Offline speech-to-speech inference workflows.
Model Components
----------------
Audio Perception Module
^^^^^^^^^^^^^^^^^^^^^^^
The audio perception module is responsible for converting speech signals into embeddings that can be processed by language models. It typically consists of:
1. **Preprocessor**: Converts raw audio waveforms into spectral features
2. **Encoder**: Processes these features to create meaningful representations
3. **Modality Adapter**: Adapts the encoder outputs to be compatible with the LLM's input space
Speech Generation
^^^^^^^^^^^^^^^^^
Speech generation components convert text or token representations back into speech. The collection offers:
1. **TransformerARSpeechDecoder**: An autoregressive transformer-based speech decoder
2. **Audio Codec Integration**: Works with audio codecs to generate natural speech from discrete tokens
3. **DuplexEARTTS**: A ready-to-use duplex text-to-speech model that supports user interruption via a special text interruption token. The model integrates an RVQ-based audio codec with a streaming speech generation module to enable low-latency, real-time synthesis.
Implementation Details
----------------------
The DuplexS2SModel implementation contains several key methods that handle different aspects of the model's functionality:
Model Initialization
^^^^^^^^^^^^^^^^^^^^
The constructor (`__init__`) initializes the following components:
1. **Pretrained ASR encoder/perception**: Loads a pretrained NeMo ASR model and adapts it for audio perception
2. **LLM**: Loads a pretrained language model using HuggingFace's AutoModel
3. **Audio codec**: Loads a pretrained NeMo audio codec for speech generation
4. **Token prediction heads**: Adds separate heads for text token and audio token prediction
Forward Method
^^^^^^^^^^^^^^
The `forward` method:
1. Accepts input representations (sum of audio perception and text embedding outputs)
2. Runs an offline forward pass through the language model
3. Generates logits from both text and audio token prediction heads
4. Returns these logits for loss computation
Training Step
^^^^^^^^^^^^^
The `training_step` method:
1. Builds input representations using the `prepare_inputs` method
2. Runs the `forward` method to get text and audio logits
3. Computes losses for both text and audio tokens
4. Logs training metrics (loss, learning rate, etc.)
5. Returns the loss for backpropagation
Prepare Inputs
^^^^^^^^^^^^^^
The `prepare_inputs` method:
1. Processes source audio through the perception module (with gradients enabled)
2. Processes target audio through the audio codec (with gradients disabled)
3. Truncates source/target audio and target text sequences to have the same sequence length, if needed
4. Performs additional truncation for sequence lengths to be divisible by tensor parallelism world size (if enabled)
5. Returns a dictionary with input and label tensors for training
.. code-block:: python
def prepare_inputs(self, batch):
# Process source audio through perception
audio_embs, audio_emb_lens = self.perception(
input_signal=batch["source_audio"],
input_signal_length=batch["source_audio_lens"]
)
# Process target audio through codec (no gradients)
with torch.no_grad():
target_audio_tokens, target_audio_token_lens = self.audio_codec.encode(batch["target_audio"], batch["target_audio_lens"])
# Truncate sequences if needed
# ... (truncation logic)
# Embed text tokens and combine them with audio representations
# ... (text embedding logic)
# Return processed inputs and labels
return {
"audio_embeds": audio_embs,
"input_embeds": input_embeds,
"attention_mask": attention_mask,
"target_text_ids": target_text_ids,
"target_audio_ids": target_audio_ids,
}
Validation
^^^^^^^^^^
The validation process:
1. Clears GPU memory to avoid OOM issues
2. Loads a scoring ASR model into GPU for evaluation
3. Initializes metric aggregation for each dataset
4. Processes each validation dataset separately
5. Computes BLEU scores for text and ASR-decoded audio
6. Logs and clears metrics after validation is complete
Scaling Support
---------------
The DuplexS2SModel includes a `configure_model` method that sets up model parallelism for large-scale training. This method:
1. Detects the parallelism strategy from the trainer's device mesh
2. Applies Fully Sharded Data Parallel (FSDP) sharding to appropriate modules
3. Applies Tensor Parallelism (TP) and Sequence Parallelism (SP) when configured
4. Handles model-specific adaptations for different LLM architectures
The scaling approach supports:
* Pure FSDP2 for distributing parameters across GPUs
* Pure TP/SP for splitting computation across GPUs
* 2D parallelism combining both approaches
Pretrained Model Usage
----------------------
All models in the speechlm2 collection can be instantiated from pretrained checkpoints:
.. code-block:: python
import nemo.collections.speechlm2 as slm
# Load SALM model
salm_model = slm.models.SALM.from_pretrained("path/to/checkpoint")
# Load SALMAutomodel
salm_automodel = slm.models.SALMAutomodel.from_pretrained("path/to/checkpoint")
# Load DuplexS2SModel
duplex_model = slm.models.DuplexS2SModel.from_pretrained("path/to/checkpoint")
# Load DuplexS2SSpeechDecoderModel
speech_decoder_model = slm.models.DuplexS2SSpeechDecoderModel.from_pretrained("path/to/checkpoint")
# Load DuplexSTTModel
stt_model = slm.models.DuplexSTTModel.from_pretrained("path/to/checkpoint")
# Load DuplexEARTTS
ear_tts_model = slm.models.DuplexEARTTS.from_pretrained("path/to/checkpoint")
# Load NemotronVoiceChat (Inference Only)
voicechat_model = slm.models.NemotronVoiceChat.from_pretrained("path/to/checkpoint")
Fine-Tuning from a Checkpoint
------------------------------
To fine-tune a model starting from a previous training checkpoint (with a fresh
optimizer and step counter), set ``model.init_from_checkpoint`` in the config:
.. code-block:: python
# Via Hydra override:
# ++model.init_from_checkpoint=/path/to/step=6375.ckpt
This loads only model weights from the checkpoint — optimizer state, LR scheduler,
and training step are discarded. Supports DCP directories (from FSDP2/TP training),
HuggingFace directories, and single-file ``.ckpt`` files. Works with both ``SALM``
and ``SALMAutomodel``.
See :ref:`fine-tuning-from-checkpoint` in the configuration documentation for full
details.
Model Configuration
-------------------
All models in this collection use a configuration-based approach, where a YAML configuration file specifies the model architecture, components, and training parameters. See the :doc:`configurations documentation <configs>` for details on these configuration files.
For information about scaling and training these models at scale, see the :doc:`training and scaling documentation <training_and_scaling>`.
@@ -0,0 +1,332 @@
Training and Scaling
====================
This page provides detailed information on training speechlm2 models, including setup requirements, running experiments at scale, debugging, and parallelism strategies.
Running Experiments
-------------------
The speechlm2 collection includes several scripts to facilitate running experiments, especially on SLURM-based clusters.
SLURM Job Submission
^^^^^^^^^^^^^^^^^^^^
For training on SLURM clusters, use the following workflow:
.. code-block:: bash
# Submit 8 consecutive jobs with random seeds
scripts/speechlm2/auto_launcher_with_seed.sh -n8 s2s_tinyllama_repro.sub
The ``auto_launcher_with_seed.sh`` script:
1. Generates a random seed for each submitted job
2. Leverages ``shard_seed="randomized"`` in Lhotse to ensure each data parallel rank is seeded differently
3. Ensures each tensor parallel rank is seeded identically
SLURM Submission Script
^^^^^^^^^^^^^^^^^^^^^^^
Example ``s2s_tinyllama_repro.sub`` script:
.. code-block:: bash
#!/bin/bash
#SBATCH --job-name=s2s_training
#SBATCH --nodes=4
#SBATCH --ntasks-per-node=8
#SBATCH --gres=gpu:8
#SBATCH --time=24:00:00
#SBATCH --exclusive
#SBATCH --output=s2s_tinyllama_repro_%j.out
# Check that the global random seed base is provided
if [ -z "$1" ]; then
echo "Usage: $0 <global_random_seed_base>"
exit 1
fi
SEED=${1}
EXP_NAME="s2s_training"
RESULTS_DIR="results/${EXP_NAME}"
srun --ntasks=${SLURM_NTASKS} --ntasks-per-node=${SLURM_NTASKS_PER_NODE} \
python -u examples/speechlm2/s2s_duplex_train.py \
--config-path=/path/to/config/dir \
--config-name=s2s_training.yaml \
exp_manager.name=${EXP_NAME} \
exp_manager.wandb_logger_kwargs.name=${EXP_NAME} \
trainer.num_nodes=$SLURM_JOB_NUM_NODES \
exp_manager.explicit_log_dir=${RESULTS_DIR} \
data.train_ds.seed=$SEED \
data.validation_ds.seed=$SEED
Configuration Files
^^^^^^^^^^^^^^^^^^^
The main configuration file (``s2s_training.yaml``) contains all model, training, and data parameters. See :doc:`configs` for more details. It's recommended to copy and modify this file rather than overriding options in the SLURM script to maintain versioning and configuration clarity.
Debugging
---------
Running Locally with torchrun
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For local debugging and profiling, use ``torchrun``:
.. code-block:: bash
# Run with 4 GPUs locally
torchrun --nproc_per_node=4 examples/speechlm2/s2s_duplex_train.py \
--config-path=/path/to/config/dir \
--config-name=s2s_training.yaml
Scaling Strategies
------------------
The speechlm2 collection includes support for model parallelism to scale training to large models across multiple GPUs.
Model Parallel Strategies
^^^^^^^^^^^^^^^^^^^^^^^^^
The collection supports multiple parallelism strategies:
1. **Fully Sharded Data Parallel (FSDP2)**: Distributes model parameters across GPUs
2. **Tensor Parallelism (TP)**: Splits individual tensors across GPUs
3. **Sequence Parallelism (SP)**: Splits sequence processing across GPUs
4. **2D Parallelism**: Combination of FSDP2 with TP/SP
AutomodelParallelStrategy (SALMAutomodel)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For ``SALMAutomodel``, the collection provides ``AutomodelParallelStrategy`` which
delegates device mesh creation and parallelism to NeMo Automodel. This strategy
supports FSDP2, TP, PP, CP, EP (MoE), and HSDP.
.. code-block:: yaml
trainer:
strategy:
_target_: nemo.collections.speechlm2.parts.parallel.AutomodelParallelStrategy
dp_size: null # inferred from world_size / other dims
dp_replicate_size: 1 # HSDP replication group size
tp_size: 1
pp_size: 1
cp_size: 1
ep_size: 8 # Expert parallelism for MoE models
# Activation checkpointing — two independent knobs:
activation_checkpointing_llm: false # LLM transformer blocks
activation_checkpointing_perception: false # speech encoder layers
The model's ``configure_model()`` receives the device mesh and passes it to
Automodel's ``from_pretrained`` for memory-efficient loading (each GPU only
loads its own shard).
The speech encoder / perception module currently only supports FSDP2 (controlled via ``dp_size``).
Activation Checkpointing
""""""""""""""""""""""""
``AutomodelParallelStrategy`` exposes two independent activation-checkpointing knobs:
* ``activation_checkpointing_llm`` — single switch covering both the non-EP FSDP2
path (forces ``FSDP2Config.activation_checkpointing=True``) and the EP/MoE
parallelizer path (passed through as a separate runtime arg). Use this for
MoE LLMs whether ``ep_size`` is 1 or larger.
* ``activation_checkpointing_perception`` — wraps each transformer layer in
``perception.encoder.layers`` (and the Conformer ``pre_encode`` front-end when
it isn't a bare ``nn.Linear``) with ``checkpoint_wrapper`` *before* FSDP2
sharding. Implemented in ``AudioPerceptionModule.set_activation_checkpointing``.
Both default to ``false``. Toggle them independently to trade compute for
memory at either end of the model. They are SALMAutomodel-specific knobs (the
HF Transformers SALM path uses HuggingFace's own gradient-checkpointing API).
.. note::
Expert Parallelism (EP) reuses the FSDP2 data-parallel axis (``dp_size``).
Dense layers are sharded via FSDP2, while MoE expert layers use EP for
all-to-all expert routing — both operate on the same set of GPUs.
Setting ``ep_size`` controls how many GPUs participate in expert routing;
it does not add a separate dimension.
Training with MoE LLM Backbones
""""""""""""""""""""""""""""""""
SALMAutomodel enables efficient training of Speech LLMs with Mixture-of-Experts
backbones like `NVIDIA Nemotron Nano V3 <https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16>`_
(30B total parameters, 3B active). NeMo Automodel provides two key MoE
optimizations:
* **Grouped GEMM**: Fuses all expert computations within a single MoE layer into
one batched matrix multiplication, maximizing GPU utilization and throughput.
* **DeepEP** (Deep Expert Parallelism): An efficient all-to-all communication
primitive for routing tokens to experts across GPUs, significantly reducing the
communication overhead of Expert Parallelism.
Example: training SALMAutomodel with Nemotron Nano V3 on 8 GPUs with EP=8:
.. code-block:: bash
torchrun --nproc_per_node=8 examples/speechlm2/salm_train.py \
--config-name=salm_automodel \
model.pretrained_llm=nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16 \
trainer.strategy.ep_size=8
For distributed inference, launch with ``torchrun``:
.. code-block:: bash
torchrun --nproc_per_node=8 examples/speechlm2/salm_eval.py \
pretrained_name=path/to/checkpoint \
inputs=path/to/manifest \
ep_size=2
Packed Sequences (THD)
""""""""""""""""""""""
``SALMAutomodel`` supports an opt-in packed-sequence (``THD``) training and
validation path that concatenates per-utterance text + audio embeddings into
a single flat ``[T_total, H]`` sequence with a ``cu_seqlens`` index, instead
of right-padding into the standard ``[B, T_max, H]`` (``BSHD``) layout. TE's
varlen FlashAttention then operates segment-by-segment without ever attending
across utterances, and Mamba's ``seq_idx`` is derived from the same
``cu_seqlens`` so SSM state resets at document boundaries.
For variable-length speech batches the padding overhead is substantial — the
``BSHD`` layout pays ``B * (T_max - T_avg)`` wasted compute per minibatch,
``THD`` pays only the per-utterance rounding to a multiple of ``2*cp_size``
(needed for TE's CP DualChunkSwap pattern). Throughput improvement scales
with the variance of utterance lengths.
Enable per-batch:
.. code-block:: yaml
model:
packed_sequences: true # opt-in; default false (BSHD)
automodel_backend:
attn: te # THD path requires TE attention
When ``packed_sequences`` is unset, the existing BSHD path is used unchanged.
Generate / inference always uses BSHD (it doesn't go through ``prepare_inputs``).
Context Parallelism (CP)
""""""""""""""""""""""""
``SALMAutomodel`` supports context parallelism for long-audio training on
hybrid Mamba/attention LLMs (e.g. Nemotron-V3). CP shards the sequence
dimension across GPUs so per-rank activations and KV-cache memory scale as
``T / cp_size`` instead of ``T``; attention layers go through TE's
DualChunkSwap pattern and Mamba mixers go through hidden-parallel
all-to-all (``MambaContextParallel`` in NeMo Automodel).
Enable via the strategy:
.. code-block:: yaml
trainer:
strategy:
_target_: nemo.collections.speechlm2.parts.parallel.AutomodelParallelStrategy
cp_size: 2 # context parallel size; must divide num_heads of every Mamba block
ep_size: 2 # may share the same ranks as CP
**The THD packed-sequence path is the only supported configuration under
CP.** Each utterance is its own attention segment and the per-utterance
sequence rounding aligns naturally with CP's ``2*cp_size`` requirement.
.. warning::
**BSHD + CP is not supported.** TE's fused-attention CP path supports
``causal`` but not ``padding_causal``, so the right-pad mask must be
dropped before the LLM. With the mask dropped, pad K/V leak into
real-token attention through the causal mask and the gradient through
the LoRA / projection parameters becomes ``NaN`` after the first
optimizer step (validated empirically: BSHD + CP=2 + EP=2 on a 2-GPU
run produces ``loss=4.62`` at step 1 then ``loss=nan`` from step 2
onwards). This is independent of the TE/cuDNN backward issue
documented below — setting ``NVTE_FUSED_ATTN=0`` does not fix it.
Set ``model.packed_sequences: true`` to use the THD path instead.
.. note::
**CP-safe data loading is automatic.** The speechlm2 datamodule wraps
the Lhotse loader in
:class:`~nemo.collections.common.data.lhotse.broadcasting.BroadcastingDataLoader`,
so under CP/TP every batch is constructed once on the DP source rank
(``cp_rank == 0`` and ``tp_rank == 0``) and broadcast to its sub-mesh
peers. This eliminates per-rank Lhotse non-determinism (``concurrent_bucketing``,
worker scheduling jitter, etc.) as a source of NCCL deadlocks under CP.
See :doc:`/dataloaders` for the standalone API.
.. note::
**TE/THD exploding-gradients workaround on some GPUs.** On certain GPU
architectures (notably Blackwell ``sm_120``), the cuDNN backend that
TransformerEngine 2.14 picks for ``qkv_format="thd"`` with
``attn_mask_type="padding_causal"`` returns correct forward activations
but gradients amplified 8×–960× per layer. Compounded across the LLM's
attention stack this drives gradients to ``1e22``-magnitudes at step 0,
the gradient-clip-by-norm computes ``1.0 / inf = 0``, and Adam's moments
eventually NaN. Force TE to dispatch FlashAttention instead of cuDNN by
setting ``NVTE_FUSED_ATTN=0`` in the launcher environment (requires
``flash-attn`` to be installed for your GPU arch). The FlashAttention
THD/``padding_causal`` backward is gradient-correct on the same shapes.
To configure parallelism, modify the ``trainer.strategy`` section in your YAML config:
.. code-block:: yaml
trainer:
strategy:
_target_: nemo.core.ModelParallelStrategy
find_unused_parameters: False
data_parallel: 1 # World size for data parallelism (FSDP2)
tensor_parallel: 8 # World size for tensor parallelism
devices: 8
num_nodes: 1
accelerator: gpu
precision: bf16-true
The model's ``configure_model`` method automatically sets up the appropriate parallelization based on this configuration.
FSDP2 Configuration (HF Automodel)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For Fully Sharded Data Parallel training:
1. Set ``data_parallel`` to the number of GPUs you want to use for data parallelism
2. Set ``tensor_parallel`` to 1 (disabled)
FSDP2 shards the model parameters across GPUs, all-gathers them for forward/backward passes, and then de-allocates after computation. This allows training of larger models with limited GPU memory.
See `PyTorch FSDP2 <https://pytorch.org/docs/stable/distributed.fsdp.fully_shard.html>`_ for more details.
Tensor Parallelism Configuration (HF Automodel)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For Tensor Parallelism:
1. Set ``tensor_parallel`` to the number of GPUs you want to use for tensor parallelism
2. Set ``data_parallel`` to 1 (or higher for 2D parallelism)
The ``parallelize_module`` function applies a parallelization plan to specific model components, like splitting attention heads or embedding dimensions across GPUs.
See `PyTorch TP <https://pytorch.org/docs/stable/distributed.tensor.parallel.html>`_ for more details.
Implementation Details
----------------------
The core implementation of model parallelism is in the ``configure_model`` method of the model classes. Key aspects include:
1. **Module Sharding**: Calling ``fully_shard`` on modules to distribute parameters across data parallel ranks
2. **Parallelization Plans**: Creating and applying plans that specify how different layers should be parallelized
3. **Model-Specific Adaptations**: Handling architectural differences between different LLMs
Advanced Usage
--------------
Script Customization
^^^^^^^^^^^^^^^^^^^^
When customizing the training scripts, keep these points in mind:
1. **Path Overrides**: Override paths in the YAML configuration files with your own, as needed
2. **W&B Keys**: Update Weights & Biases API keys in configuration files
3. **Batch Size Tuning**: Adjust batch size based on your GPU memory and model size