Files
wehub-resource-sync ba4be087d5
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
chore: import upstream snapshot with attribution
2026-07-13 13:28:58 +08:00

333 lines
14 KiB
ReStructuredText
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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