Multi-GPU
This guide covers advanced training configurations for multi-GPU setups using Axolotl.
Overview
When training on multiple GPUs, Axolotl supports 3 sharding/parallelism strategies. Additionally, you can layer specific optimization features on top of that strategy.
You generally cannot combine these strategies; they are mutually exclusive.
- DeepSpeed: Powerful optimization library, supports ZeRO stages 1-3.
- FSDP (Fully Sharded Data Parallel): PyTorch’s native sharding implementation (Recommended).
- DDP (Distributed Data Parallel): PyTorch’s native parallelism implementation (Default if neither of the above are selected).
These features can often be combined with the strategies above:
- Context Parallelism (CP): Splits long sequences across GPUs (Ringmaster under FSDP2; DeepSpeed Ulysses under DeepSpeed).
- FSDP + QLoRA: Combines 4-bit quantization with FSDP (Specific to FSDP).
DeepSpeed
Configuration
Add to your YAML config:
deepspeed: deepspeed_configs/zero1.jsonUsage
# Fetch deepspeed configs (if not already present)
axolotl fetch deepspeed_configs
# Passing arg via config
axolotl train config.yml
# Passing arg via cli
axolotl train config.yml --deepspeed deepspeed_configs/zero1.jsonZeRO Stages
We provide default configurations for:
- ZeRO Stage 1 (
zero1.json) - ZeRO Stage 1 with torch compile (
zero1_torch_compile.json) - ZeRO Stage 2 (
zero2.json) - ZeRO Stage 3 (
zero3.json) - ZeRO Stage 3 with bf16 (
zero3_bf16.json) - ZeRO Stage 3 with bf16 and CPU offload params(
zero3_bf16_cpuoffload_params.json) - ZeRO Stage 3 with bf16 and CPU offload params and optimizer (
zero3_bf16_cpuoffload_all.json)
Choose the configuration that offloads the least amount to memory while still being able to fit on VRAM for best performance.
Start from Stage 1 -> Stage 2 -> Stage 3.
Fully Sharded Data Parallel (FSDP)
FSDP allows you to shard model parameters, gradients, and optimizer states across data parallel workers.
Only FSDP2 is supported. FSDP1 has been removed, and setting fsdp_version: 1 raises an error.
Configuration
fsdp_version: 2
fsdp_config:
offload_params: false
cpu_ram_efficient_loading: true
auto_wrap_policy: TRANSFORMER_BASED_WRAP
transformer_layer_cls_to_wrap: Qwen3DecoderLayer
state_dict_type: FULL_STATE_DICT
reshard_after_forward: trueWhen using auto_wrap_policy: SIZE_BASED_WRAP, set min_num_params to the minimum parameter count a module must have to be wrapped (e.g. 100000000).
With peft_ensure_weight_tying: true, tied embedding LoRA adapters and their output-head consumers stay in the root FSDP group under either wrapping policy. This keeps the shared parameters available for both uses and combines their gradients before FSDP/HSDP reduction. These weights remain gathered across the root forward, which can use more memory than separately wrapping the embedding and head. The root group follows the configured distributed mesh, including CP/EP data axes and TP on other layers. Keep the tied embedding and output head out of the tensor-parallel plan; TP-sharded adapters on those modules are rejected.
Full checkpoints and resume
fsdp_config.state_dict_type: FULL_STATE_DICT saves a single gathered model checkpoint and optimizer.bin. With expert parallelism, both checkpoints include every EP group’s experts. Restore selects each rank’s expert ownership before applying its FSDP/HSDP shard, including the different row and column packing of expert LoRA factors. LoRA/QLoRA Trainer checkpoints save only the adapter tensors; the frozen base model is loaded separately. Model-only intermediate checkpoints also write pytorch_model_fsdp.bin so Trainer uses the ownership-aware FSDP restore path.
For adamw_torch_8bit, the full optimizer file records quantized codes, block scales, lookup tables, and shard ownership. Resuming with the same layout preserves these exactly. Changing the mesh is supported when the saved blocks remain compatible with the new optimizer shards. A change that regroups blocks with different scales raises a restore-time error; it does not silently requantize optimizer state or disallow the training configuration.
Full checkpoints assemble tensors on rank 0’s CPU and use bounded GPU transfer buffers. Rank 0 therefore needs enough host memory for the complete checkpoint state. Adapter-only runs gather PEFT export state, including frozen adapter factors, saved modules, and required embeddings, without materializing other frozen base weights.
Native full bitsandbytes checkpoints preserve each EP owner’s packed weights and quantization metadata in a versioned pytorch_model_fsdp.bin payload. Resume supports rank rearrangements and compatible data-parallel resharding, but requires the same EP ownership ranges. Changing EP grouping requires an explicit checkpoint conversion. These files are training checkpoints; Hugging Face adapter exports retain their usual format. Generic Accelerator.get_state_dict() cannot represent packed EP weights and their owner-specific quantization metadata as an ordinary state dict, so it raises a collective error. Use the native save_fsdp_model() checkpoint path or Trainer adapter export instead. Ownership-aware full checkpoints support 4-bit dense weights and 4-bit or 8-bit parametrized experts; dense Int8Params in this path are rejected.
Final adapter exports use ordinary PEFT keys and gather every expert into the base model’s global layout. Models with fused expert parameters retain that adapter layout; this is separate from bitsandbytes quantization packing. Full-model Hugging Face exports use the original checkpoint conversion mapping, which unpacks fused Mixtral experts into separate w1, w2, and w3 weights. Final exports do not include the native resume file.
FSDP + QLoRA
For combining FSDP with QLoRA, see our dedicated guide.
With quantize_moe_experts: true and expert parallelism, EP slices the packed bitsandbytes expert weights and their block scales together. Double-quantized scales remain compressed when shard boundaries align. If only a nested scale block crosses a boundary, EP unpacks those scales without dequantizing or requantizing the weights. Expert slices must align with the weight quantization blocks. The packed parameters and quantization metadata stay on the same device, and FSDP wraps them on the expert mesh.
Migrating from FSDP1 to FSDP2
FSDP1 has been removed. fsdp_version: 1 and the bare top-level fsdp: list are rejected, and fsdp_version defaults to 2.
To migrate an FSDP1 config, replace the fsdp: list with fsdp_config: and follow the config field mapping below to update field names.
Config mapping
| FSDP1 | FSDP2 |
|---|---|
| fsdp_sharding_strategy | reshard_after_forward |
| fsdp_backward_prefetch_policy | REMOVED (dropped with a warning) |
| fsdp_backward_prefetch | REMOVED (dropped with a warning) |
| fsdp_forward_prefetch | REMOVED (rejected with an error) |
| fsdp_sync_module_states | REMOVED (dropped with a warning) |
| fsdp_limit_all_gathers | REMOVED (dropped with a warning) |
| fsdp_cpu_ram_efficient_loading | cpu_ram_efficient_loading |
| fsdp_state_dict_type | state_dict_type |
| fsdp_use_orig_params | REMOVED (dropped with a warning; FSDP2 always trains original parameters) |
| fsdp_activation_checkpointing | activation_checkpointing |
For more details, please see the migration guide in the torchtitan repo. In Axolotl, if you were using the following FSDP1 config:
fsdp_version: 1
fsdp_config:
fsdp_offload_params: false
fsdp_cpu_ram_efficient_loading: true
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
fsdp_transformer_layer_cls_to_wrap: Qwen3DecoderLayer
fsdp_state_dict_type: FULL_STATE_DICT
fsdp_sharding_strategy: FULL_SHARDYou can migrate to the following FSDP2 config:
fsdp_version: 2
fsdp_config:
offload_params: false
cpu_ram_efficient_loading: true
auto_wrap_policy: TRANSFORMER_BASED_WRAP
transformer_layer_cls_to_wrap: Qwen3DecoderLayer
state_dict_type: FULL_STATE_DICT
reshard_after_forward: trueContext parallelism
We support context parallelism (CP; other frameworks call the same thing sequence parallelism) via
axolotl-ringmaster (context_parallel_size),
which prefers Ulysses head-parallel attention and falls back to Ring attention for the
remainder of the CP degree. This allows one to split up sequences across GPUs, which is
useful in the event that a single sequence causes OOM errors during model training. Under
DeepSpeed the same key maps onto DeepSpeed’s Ulysses (ALST) implementation through accelerate.
See our dedicated guide for more information.
Performance Optimization
Liger Kernel Integration
Please see docs for more info.
Troubleshooting
NCCL Issues
For NCCL-related problems, see our NCCL troubleshooting guide.
Common Problems
- Reduce
micro_batch_size - Reduce
eval_batch_size - Adjust
gradient_accumulation_steps - Consider using a higher ZeRO stage
- Start with DeepSpeed ZeRO-2
- Monitor loss values
- Check learning rates
For more detailed troubleshooting, see our debugging guide.