{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2026-06-24-accelerating-transformers-fine-tuning-with-nvidia-nemo/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "HuggingFace Transformers has become the foundation of the open-source AI ecosystem, and the recent [Transformers v5](https://github.com/huggingface/transformers/releases/tag/v5.0.0) release strengthened it with first-class support for Mixture-of-Experts (MoE) models, now the dominant architecture for [frontier models](https://www.nvidia.com/en-us/glossary/frontier-models/). v5 ships the MoE foundations: expert backends, dynamic weight loading, and distributed execution that make MoE extensible and easy to build on.\n\n[NVIDIA NeMo AutoModel](https://github.com/NVIDIA-NeMo/Automodel) is an open library part of the [NVIDIA NeMo framework](https://github.com/NVIDIA-NeMo) for building custom generative AI models at scale. NeMo AutoModel builds cleanly on top of v5, adding Expert Parallelism, DeepEP fused all-to-all dispatch, and TransformerEngine kernels, and it leans on v5's dynamic weight loading to bring those optimizations to a broad and growing set of model families. The payoff is **3.4-3.7x higher training throughput** and **29-32% less GPU memory** on fine-tuning MoE models than native Transformers v5, using the same from\\_pretrained() API: a single import line, with no other code changes.\n\nThis blog details how this combination works and how users can fine-tune MoE models faster without changing their APIs.\n\n## Background\n\nThe rise of MoE models has introduced new challenges to efficient training: Routing tokens across hundreds of experts, fusing expert matmuls into a single kernel, sharding weights across GPUs, and overlapping communication with computation all require infrastructure beyond what a general-purpose library provides out of the box.\n\n[Transformers v5](https://github.com/huggingface/transformers/releases/tag/v5.0.0) (“v5”) introduced first-class MoE support such as [expert backends](https://huggingface.co/docs/transformers/en/experts_interface), [dynamic weight loading](https://huggingface.co/docs/transformers/en/weightconverter), and tensor parallel plans for distributed execution. In addition, v5 made distributed training first-class by integrating PyTorch's DeviceMesh directly into from\\_pretrained().\n\n[NeMo AutoModel](https://github.com/NVIDIA-NeMo/Automodel) builds on top of v5 by subclassing AutoModelForCausalLM, and adding Expert Parallelism (EP), DeepEP fused all-to-all dispatch, and TransformerEngine kernels. DeepEP is the piece v5 doesn't have yet: it overlaps communication with expert compute. And because NeMo AutoModel rides v5's reversible weight conversion to load each model, it can focus its engineering on these reusable core ops instead of per-model checkpoint plumbing, while save\\_pretrained() still emits standard HF checkpoints that tools like vLLM and SGLang can load.\n\nThe next section walks through how the two work together and the performance gains we measured, from full fine-tuning [NVIDIA Nemotron 3 Ultra 550B A55B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16) across 16 nodes down to single-node models such as Qwen3-30B-A3B and [Nemotron 3 Nano 30B A3B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16).\n\n## NeMo AutoModel: Same API, More Performance\n\nOne of NeMo AutoModel's goals is API compatibility with HuggingFace Transformers to enable open-source community. NeMoAutoModelForCausalLM subclasses AutoModelForCausalLM, so any code that works with HF models works with AutoModel too.\n\nHere's what loading a model looks like in both. Only the import changes:\n\n[![nemo_and_hf](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/VTPq2Wp-RrEcP1eGUJxao.png)](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/VTPq2Wp-RrEcP1eGUJxao.png)\n\nThat single import does a lot of work. For popular MoE architectures like Qwen3, [NVIDIA Nemotron](https://developer.nvidia.com/nemotron), GPT-OSS, and DeepSeek V3, NeMo AutoModel ships [hand-tuned implementations](https://github.com/NVIDIA-NeMo/Automodel/blob/main/nemo_automodel/_transformers/registry.py) with TransformerEngine attention, fused linear layers, and custom expert kernels. For everything else, it falls back to vanilla HF while still applying optimizations like [Liger kernel](https://github.com/linkedin/Liger-Kernel) patching, among others. And whichever path it takes, the resulting model is ready to scale: pass a device\\_mesh and you have multi-GPU training without further rewrites.\n\nWhere NeMo AutoModel really shines is scaling MoE models to multi-GPU training. To train [Nemotron 3 Nano 30B A3B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16) with Expert Parallelism across 8 GPUs, one adds the distributed mesh configuration:\n\n```py\nimport os\nimport torch\nimport torch.distributed as dist\nfrom nemo_automodel import NeMoAutoModelForCausalLM\nfrom nemo_automodel.recipes._dist_utils import create_distributed_setup_from_config\n\ndist.init_process_group(backend=\"nccl\")\ntorch.manual_seed(0)\ntorch.cuda.set_device(int(os.environ.get(\"LOCAL_RANK\", 0)))\n\ndist_setup = create_distributed_setup_from_config(\n    {\n        \"strategy\": \"fsdp2\",\n        \"ep_size\": 8,\n    },\n)\n\nmodel = NeMoAutoModelForCausalLM.from_pretrained(\n    \"nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16\",\n    dtype=torch.bfloat16,\n    distributed_setup=dist_setup,\n)\n\ndist.destroy_process_group()\n```\n\nThis gives speed, scalability and memory-optimizations with FSDP2, Expert Parallelism, TransformerEngine kernels and DeepEP dispatch, all from a from\\_pretrained() call.\n\n## Performance Comparison\n\nWe evaluated NeMo AutoModel in two regimes: full fine-tuning a frontier-scale 550B model across 16 nodes, and training two 30B MoE models on a single node. The 550B result shows why Expert Parallelism is essential at scale; the 30B results quantify the per-GPU speedup over Transformers v5.\n\n### Nemotron 3 Ultra 550B A55B (full fine-tune, multi-node)\n\n[Nemotron 3 Ultra 550B A55B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16) is a 550B-parameter hybrid model shipping with Mamba2, LatentMoE, and Multi-Token Prediction (MTP). We benchmark a **full fine-tune**: every parameter is updated and the Adam optimizer state is materialized, which at this scale spans **16 H100 nodes (128 GPUs)**.\n\n**Methodology:**\n\n| Parameter          | Value                                                     |\n| ------------------ | --------------------------------------------------------- |\n| Hardware           | 16x H100 80GB (128 GPUs)                                  |\n| Expert Parallelism | EP=64                                                     |\n| Local batch size   | 2                                                         |\n| Sequence length    | 4,096                                                     |\n| Features           | MTP, activation checkpointing, fused linear cross-entropy |\n| Kernels            | DeepEP dispatch + torch\\_mm experts + TransformerEngine   |\n\n| Metric        | NeMo AutoModel (EP=64) |\n| ------------- | ---------------------- |\n| TPS/GPU (avg) | 815                    |\n| TFLOP/s/GPU   | \\~293                  |\n| Peak Memory   | 58.2 GiB               |\n\n**Why there is no Transformers v5 column.** Transformers v5 runs out of memory at this scale, so there is no v5 number to report here. AutoModel's Expert Parallelism shards the experts across GPUs to bring the footprint within budget, which is what lets the full fine-tune run. The 30B comparisons below show the same advantage where v5 fits.\n\n### Single-node 30B MoE benchmarks\n\nWe benchmarked three approaches on a single node with 8x H100 80GB GPUs: HF Transformers v4 (hub code), HF Transformers v5 (with best available optimizations), and NeMo AutoModel (EP=8 + custom kernels).\n\n**Methodology:**\n\n| Parameter        | Value                      |\n| ---------------- | -------------------------- |\n| Hardware         | 8x H100 80GB (single node) |\n| Sequence length  | 4,096                      |\n| Local batch size | 1                          |\n\n**A note on the routing gate.** The NeMo AutoModel numbers below use a balanced routing gate, which forces tokens to be distributed uniformly across experts. This emulates the *ideal* operating point an MoE is trained toward: a well-trained model's load-balancing loss drives expert utilization to near-uniform, so balanced routing reflects the steady-state a real workload converges to (and removes the straggler noise that random dummy tokens otherwise inject into expert parallelism). v4/v5 run their native router on the same dummy tokens. The balanced gate therefore measures NeMo AutoModel at its target MoE operating point, and the v4/v5 columns reflect their out-of-the-box behavior.\n\n[![nemo_automodel_blog_chart_mockup_v5](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/rbCVgV6a18c4UcDsiWfZN.png)](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/rbCVgV6a18c4UcDsiWfZN.png)\n\n### Qwen3-30B-A3B\n\n| Metric           | v4       | v5 (FA2 + grouped\\_mm) | NeMo AutoModel (EP=8) | v5 → NeMo AutoModel |\n| ---------------- | -------- | ---------------------- | --------------------- | ------------------- |\n| TPS/GPU (avg)    | deadlock | 3,075                  | 11,340                | **3.69x**           |\n| Peak Memory      | —        | 68.2 GiB               | 48.1 GiB              | **-29%**            |\n| Avg Forward+Loss | —        | 582 ms                 | 194 ms                | 3.00x               |\n| Avg Backward     | —        | 758 ms                 | 178 ms                | 4.26x               |\n\n**Why v4 deadlocks:** Transformers v4 stores Qwen3 MoE experts as a ModuleList of 128 individual MLP modules, each separately FSDP-wrapped. The forward pass uses a data-dependent loop that only iterates experts that received tokens. With different data per rank, different ranks skip different experts, causing mismatched FSDP AllGather/ReduceScatter collectives and an indefinite hang. Transformers v5 fixes this by storing experts as fused 3D parameter tensors (no per-expert modules, no per-expert FSDP collectives).\n\n### Nemotron 3 Nano 30B A3B\n\n| Metric           | v4 (hub code) | v5 (FA2 + grouped\\_mm + Mamba CUDA) | NeMo AutoModel (EP=8) | v5 → NeMo AutoModel |\n| ---------------- | ------------- | ----------------------------------- | --------------------- | ------------------- |\n| TPS/GPU (avg)    | 1,807         | 4,583                               | 15,421                | **3.36x**           |\n| Peak Memory      | 61.9 GiB      | 62.1 GiB                            | 42.5 GiB              | **-32%**            |\n| Avg Forward+Loss | 1,024 ms      | 283 ms                              | 109 ms                | 2.60x               |\n| Avg Backward     | 1,246 ms      | 611 ms                              | 157 ms                | 3.89x               |\n\n**v4 config:** trust\\_remote\\_code=True (NVIDIA's hub modeling code). The hub code's expert loop is FSDP-safe (iterates all experts regardless of token assignment), so it doesn't deadlock like Qwen3 v4.\n\n### Where the speedup comes from\n\nThe 3.4-3.7x speedup from NeMo AutoModel over Transformers v5 comes from three sources:\n\n1. **Expert Parallelism reduces memory pressure.** EP=8 distributes expert weights across GPUs, cutting the per-GPU MoE footprint by 8x. For Qwen3, this drops peak memory from 68.2 GiB to 48.1 GiB (-29%). For Nemotron Nano, it drops from 62.1 GiB to 42.5 GiB (-32%), freeing headroom for larger batch sizes or longer sequences.\n\n2. **DeepEP fuses communication with computation.** Instead of separate AllGather/ReduceScatter collectives for expert routing, DeepEP fuses token dispatch and combines into optimized GPU kernels, overlapping communication with expert computation.\n\n3. **TransformerEngine kernels accelerate core operations.** TE's fused attention, linear layers, and RMSNorm implementations provide consistent speedups over their PyTorch/Flash Attention equivalents across all layer types, not just MoE layers.\n\n## Transformers v5 Features Leveraged by HuggingFace AutoModel\n\n### Expert Backends\n\nOne of the most impactful features in Transformers v5 is the [experts\\_implementation](https://huggingface.co/docs/transformers/en/experts_interface) parameter, which includes three expert backends:\n\n| Backend     | Description                                                                      | Best for                                                          |\n| ----------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------- |\n| eager       | For-loop over selected experts                                                   | Debugging, compatibility, and correctness. Also available for v4. |\n| batched\\_mm | Duplicates expert params, single batched GEMM via torch.bmm                      | Small inputs, fast with torch.compile. Added for v5               |\n| grouped\\_mm | Orders tokens by expert, single grouped GEMM via torch.nn.functional.grouped\\_mm | Training (memory efficient, no param duplication). Added for v5.  |\n\nThe grouped\\_mm backend is the key training optimization: instead of looping over experts one by one, it sorts tokens by their assigned expert and executes a single fused grouped matrix multiplication.\n\nNeMo AutoModel takes this further. For models with custom implementations, it uses DeepEP fused all-to-all dispatch combined with grouped GEMM kernels and TransformerEngine linear layers. The progression looks like:\n\n```\nv4 (eager for-loop) → v5 (grouped_mm) → NeMo AutoModel (DeepEP + GMM + TE)\n```\n\nIn NeMo AutoModel, the expert backend is configured through BackendConfig:\n\n```py\nfrom nemo_automodel.components.models.common.utils import BackendConfig\n\nbackend = BackendConfig(\n    attn=\"te\",           # TransformerEngine attention\n    linear=\"te\",         # TransformerEngine linear layers\n    experts=\"torch_mm\",  # Grouped expert matmul\n    dispatcher=\"deepep\", # DeepEP fused all-to-all\n)\n```\n\n## Expert Parallelism and DeepEP\n\nTransformers v5 also ships an [Expert Parallelism path](https://huggingface.co/docs/transformers/en/expert_parallelism). It shards expert weights across GPUs. The [GroupedGemmParallel](https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/integrations/tensor_parallel.py#L1078) style loads only each device's local experts, and [RouterParallel](https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/integrations/tensor_parallel.py#L1123) routes tokens and combines results with an all\\_reduce. It's neatly built on v5's existing tensor-parallel machinery. Enabling it makes the model's tp\\_plan return its [expert plan](https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/modeling_utils.py#L1448), so expert parallelism shares the device budget with data parallelism (ep × dp = world\\_size). For the single-node 30B benchmarks here, we found plain data-parallel v5 (dp=8, ep=1) to be the fastest v5 configuration, so that's the v5 setup we report.\n\nNeMo AutoModel takes a complementary approach tuned for multi-GPU MoE training. It makes EP its own parallelism dimension, a dedicated moe\\_mesh alongside (rather than carved from) the data-parallel mesh, using PyTorch's DTensor with Shard(0). Because the expert mesh is orthogonal to data parallelism, the two compose on the same devices. On 8 GPUs NeMo AutoModel runs ep=8 and dp=8 together, so every GPU trains on its own data shard while holding only 1/8 of the experts. Expert weights are physically sharded across GPUs along the expert dimension.\n\n```py\n# From nemo_automodel/components/moe/parallelizer.py\nfrom torch.distributed.tensor import Shard, distribute_tensor\n\n# Each GPU holds only 1/ep_size of the expert weights\ndistribute_tensor(param, device_mesh, [Shard(0)])\n```\n\nWith ep\\_size=8 on 8 GPUs, each GPU holds only 1/8 of the expert parameters. For a model like Nemotron-3-Nano-30B-A3B with ~55 GiB of expert weights, EP reduces the per-GPU expert footprint from ~55 GiB to ~6.8 GiB, making training possible where FSDP-only approaches run out of memory.\n\nOn top of EP, NeMo AutoModel integrates [DeepEP](https://github.com/deepseek-ai/DeepEP) that fuses the token routing into optimized GPU kernels, and delivers significant speedups when combined with grouped GEMM for grouped expert computation. In our [large-scale MoE benchmarks](https://github.com/NVIDIA-NeMo/Automodel/discussions/916), DeepEP + grouped GEMM reduced cost per iteration by 47% on the full DeepSeek V3 671B model compared to all-gather + looped expert baselines.\n\n### Dynamic Weight Loading\n\nTransformers v5 also introduced a [dynamic weight loading](https://huggingface.co/docs/transformers/en/weightconverter) system through WeightConverter and WeightRenaming. This enables MoE checkpoint to be stored in fused 3D tensors for more efficient execution. The WeightConverter applies composable operations to transform checkpoint tensors on-the-fly during from\\_pretrained().\n\nNeMo AutoModel is a direct consumer of this v5 API. Over [20 model types](https://github.com/NVIDIA-NeMo/Automodel/blob/main/nemo_automodel/components/checkpoint/conversion_mapping.py) use this mechanism through MODELS\\_REQUIRING\\_TENSOR\\_MERGING, including Mixtral, Qwen2 MoE, Qwen3 MoE, DeepSeek V2/V3, OLMoE, and more. The conversions are fully reversible: save\\_pretrained() produces standard HF-format checkpoints that any downstream tool can load.\n\n## Getting Started\n\nTo try NeMo AutoModel, please visit our official documentation page to [get started](https://docs.nvidia.com/nemo/automodel/latest/get-started/installation).\n\nFor more details, see:\n\n- [NeMo AutoModel HuggingFace API Compatibility Guide](https://docs.nvidia.com/nemo/automodel/latest/get-started/hf-compatibility)\n- [NeMo AutoModel Model Coverage](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/overview)\n- [NeMo AutoModel Performance Summary](https://docs.nvidia.com/nemo/automodel/latest/performance/performance-summary)\n- [NeMo AutoModel on HuggingFace](https://huggingface.co/docs/transformers/en/community_integrations/nemo_automodel_finetuning)\n\n## Conclusion\n\nNVIDIA NeMo AutoModel is the natural next step for HuggingFace users scaling up model training. By building directly on Transformers v5, AutoModel provides a zero-friction upgrade path: change one import line and get a model instance that is more than three times as fast.\n\nOn Qwen3-30B-A3B and Nemotron 3 Nano 30B-A3B, this delivers 3.4-3.7x higher training throughput with 29-32% less GPU memory compared to the best Transformers v5 configuration. And because true Expert Parallelism shards experts across GPUs, the same path scales up to full fine-tuning a 550B model like Nemotron 3 Ultra across 16 nodes, the regime where Expert Parallelism becomes essential to fit the model in memory. Because NeMo AutoModel checkpoints are standard HF-format safetensors, you can deploy them on inference frameworks like vLLM and SGLang.\n\nThe code, configs, and benchmark scripts are all available in the [NeMo AutoModel repository](https://github.com/NVIDIA-NeMo/Automodel/tree/blog/transformers-v5-automodel/blog_experiments).\n\n## Acknowledgements\n\nCore contributors to this work, listed alphabetically by last name: Adil Asif, Hemil Desai, Alexandros Koumparoulis, and Huiying Li.\n",
  "authors": [],
  "captured_at": "2026-10-19T01:26:53.998049939+00:00",
  "category": "ai",
  "content_html": "<p>HuggingFace Transformers has become the foundation of the open-source AI ecosystem, and the recent <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/transformers/releases/tag/v5.0.0\">Transformers v5</a> release strengthened it with first-class support for Mixture-of-Experts (MoE) models, now the dominant architecture for <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.nvidia.com/en-us/glossary/frontier-models/\">frontier models</a>. v5 ships the MoE foundations: expert backends, dynamic weight loading, and distributed execution that make MoE extensible and easy to build on.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/NVIDIA-NeMo/Automodel\">NVIDIA NeMo AutoModel</a> is an open library part of the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/NVIDIA-NeMo\">NVIDIA NeMo framework</a> for building custom generative AI models at scale. NeMo AutoModel builds cleanly on top of v5, adding Expert Parallelism, DeepEP fused all-to-all dispatch, and TransformerEngine kernels, and it leans on v5's dynamic weight loading to bring those optimizations to a broad and growing set of model families. The payoff is <strong>3.4-3.7x higher training throughput</strong> and <strong>29-32% less GPU memory</strong> on fine-tuning MoE models than native Transformers v5, using the same from_pretrained() API: a single import line, with no other code changes.</p>\n<p>This blog details how this combination works and how users can fine-tune MoE models faster without changing their APIs.</p>\n<h2>Background</h2>\n<p>The rise of MoE models has introduced new challenges to efficient training: Routing tokens across hundreds of experts, fusing expert matmuls into a single kernel, sharding weights across GPUs, and overlapping communication with computation all require infrastructure beyond what a general-purpose library provides out of the box.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/transformers/releases/tag/v5.0.0\">Transformers v5</a> (“v5”) introduced first-class MoE support such as <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/transformers/en/experts_interface\">expert backends</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/transformers/en/weightconverter\">dynamic weight loading</a>, and tensor parallel plans for distributed execution. In addition, v5 made distributed training first-class by integrating PyTorch's DeviceMesh directly into from_pretrained().</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/NVIDIA-NeMo/Automodel\">NeMo AutoModel</a> builds on top of v5 by subclassing AutoModelForCausalLM, and adding Expert Parallelism (EP), DeepEP fused all-to-all dispatch, and TransformerEngine kernels. DeepEP is the piece v5 doesn't have yet: it overlaps communication with expert compute. And because NeMo AutoModel rides v5's reversible weight conversion to load each model, it can focus its engineering on these reusable core ops instead of per-model checkpoint plumbing, while save_pretrained() still emits standard HF checkpoints that tools like vLLM and SGLang can load.</p>\n<p>The next section walks through how the two work together and the performance gains we measured, from full fine-tuning <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16\">NVIDIA Nemotron 3 Ultra 550B A55B</a> across 16 nodes down to single-node models such as Qwen3-30B-A3B and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16\">Nemotron 3 Nano 30B A3B</a>.</p>\n<h2>NeMo AutoModel: Same API, More Performance</h2>\n<p>One of NeMo AutoModel's goals is API compatibility with HuggingFace Transformers to enable open-source community. NeMoAutoModelForCausalLM subclasses AutoModelForCausalLM, so any code that works with HF models works with AutoModel too.</p>\n<p>Here's what loading a model looks like in both. Only the import changes:</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/VTPq2Wp-RrEcP1eGUJxao.png\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/VTPq2Wp-RrEcP1eGUJxao.png\" alt=\"nemo_and_hf\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<p>That single import does a lot of work. For popular MoE architectures like Qwen3, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://developer.nvidia.com/nemotron\">NVIDIA Nemotron</a>, GPT-OSS, and DeepSeek V3, NeMo AutoModel ships <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/NVIDIA-NeMo/Automodel/blob/main/nemo_automodel/_transformers/registry.py\">hand-tuned implementations</a> with TransformerEngine attention, fused linear layers, and custom expert kernels. For everything else, it falls back to vanilla HF while still applying optimizations like <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/linkedin/Liger-Kernel\">Liger kernel</a> patching, among others. And whichever path it takes, the resulting model is ready to scale: pass a device_mesh and you have multi-GPU training without further rewrites.</p>\n<p>Where NeMo AutoModel really shines is scaling MoE models to multi-GPU training. To train <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16\">Nemotron 3 Nano 30B A3B</a> with Expert Parallelism across 8 GPUs, one adds the distributed mesh configuration:</p>\n<pre><code class=\"language-py\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">os</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">distributed</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dist</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">nemo_automodel</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">NeMoAutoModelForCausalLM</span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">nemo_automodel</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">recipes</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">_dist_utils</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">create_distributed_setup_from_config</span></span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dist</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">init_process_group</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">backend</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">nccl<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">manual_seed</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">cuda</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">set_device</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">int</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">os</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">environ</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">get</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">LOCAL_RANK<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dist_setup</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">create_distributed_setup_from_config</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">strategy<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">fsdp2<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n        <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">ep_size<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">8</span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span>\n    <span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">NeMoAutoModelForCausalLM</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">from_pretrained</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">dtype</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">bfloat16</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">distributed_setup</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dist_setup</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dist</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">destroy_process_group</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>This gives speed, scalability and memory-optimizations with FSDP2, Expert Parallelism, TransformerEngine kernels and DeepEP dispatch, all from a from_pretrained() call.</p>\n<h2>Performance Comparison</h2>\n<p>We evaluated NeMo AutoModel in two regimes: full fine-tuning a frontier-scale 550B model across 16 nodes, and training two 30B MoE models on a single node. The 550B result shows why Expert Parallelism is essential at scale; the 30B results quantify the per-GPU speedup over Transformers v5.</p>\n<h3>Nemotron 3 Ultra 550B A55B (full fine-tune, multi-node)</h3>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16\">Nemotron 3 Ultra 550B A55B</a> is a 550B-parameter hybrid model shipping with Mamba2, LatentMoE, and Multi-Token Prediction (MTP). We benchmark a <strong>full fine-tune</strong>: every parameter is updated and the Adam optimizer state is materialized, which at this scale spans <strong>16 H100 nodes (128 GPUs)</strong>.</p>\n<p><strong>Methodology:</strong></p>\n<table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Value</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Hardware</td>\n<td>16x H100 80GB (128 GPUs)</td>\n</tr>\n<tr>\n<td>Expert Parallelism</td>\n<td>EP=64</td>\n</tr>\n<tr>\n<td>Local batch size</td>\n<td>2</td>\n</tr>\n<tr>\n<td>Sequence length</td>\n<td>4,096</td>\n</tr>\n<tr>\n<td>Features</td>\n<td>MTP, activation checkpointing, fused linear cross-entropy</td>\n</tr>\n<tr>\n<td>Kernels</td>\n<td>DeepEP dispatch + torch_mm experts + TransformerEngine</td>\n</tr>\n</tbody>\n</table>\n<table>\n<thead>\n<tr>\n<th>Metric</th>\n<th>NeMo AutoModel (EP=64)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>TPS/GPU (avg)</td>\n<td>815</td>\n</tr>\n<tr>\n<td>TFLOP/s/GPU</td>\n<td>~293</td>\n</tr>\n<tr>\n<td>Peak Memory</td>\n<td>58.2 GiB</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Why there is no Transformers v5 column.</strong> Transformers v5 runs out of memory at this scale, so there is no v5 number to report here. AutoModel's Expert Parallelism shards the experts across GPUs to bring the footprint within budget, which is what lets the full fine-tune run. The 30B comparisons below show the same advantage where v5 fits.</p>\n<h3>Single-node 30B MoE benchmarks</h3>\n<p>We benchmarked three approaches on a single node with 8x H100 80GB GPUs: HF Transformers v4 (hub code), HF Transformers v5 (with best available optimizations), and NeMo AutoModel (EP=8 + custom kernels).</p>\n<p><strong>Methodology:</strong></p>\n<table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Value</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Hardware</td>\n<td>8x H100 80GB (single node)</td>\n</tr>\n<tr>\n<td>Sequence length</td>\n<td>4,096</td>\n</tr>\n<tr>\n<td>Local batch size</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>\n<p><strong>A note on the routing gate.</strong> The NeMo AutoModel numbers below use a balanced routing gate, which forces tokens to be distributed uniformly across experts. This emulates the <em>ideal</em> operating point an MoE is trained toward: a well-trained model's load-balancing loss drives expert utilization to near-uniform, so balanced routing reflects the steady-state a real workload converges to (and removes the straggler noise that random dummy tokens otherwise inject into expert parallelism). v4/v5 run their native router on the same dummy tokens. The balanced gate therefore measures NeMo AutoModel at its target MoE operating point, and the v4/v5 columns reflect their out-of-the-box behavior.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/rbCVgV6a18c4UcDsiWfZN.png\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/rbCVgV6a18c4UcDsiWfZN.png\" alt=\"nemo_automodel_blog_chart_mockup_v5\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<h3>Qwen3-30B-A3B</h3>\n<table>\n<thead>\n<tr>\n<th>Metric</th>\n<th>v4</th>\n<th>v5 (FA2 + grouped_mm)</th>\n<th>NeMo AutoModel (EP=8)</th>\n<th>v5 → NeMo AutoModel</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>TPS/GPU (avg)</td>\n<td>deadlock</td>\n<td>3,075</td>\n<td>11,340</td>\n<td><strong>3.69x</strong></td>\n</tr>\n<tr>\n<td>Peak Memory</td>\n<td>—</td>\n<td>68.2 GiB</td>\n<td>48.1 GiB</td>\n<td><strong>-29%</strong></td>\n</tr>\n<tr>\n<td>Avg Forward+Loss</td>\n<td>—</td>\n<td>582 ms</td>\n<td>194 ms</td>\n<td>3.00x</td>\n</tr>\n<tr>\n<td>Avg Backward</td>\n<td>—</td>\n<td>758 ms</td>\n<td>178 ms</td>\n<td>4.26x</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Why v4 deadlocks:</strong> Transformers v4 stores Qwen3 MoE experts as a ModuleList of 128 individual MLP modules, each separately FSDP-wrapped. The forward pass uses a data-dependent loop that only iterates experts that received tokens. With different data per rank, different ranks skip different experts, causing mismatched FSDP AllGather/ReduceScatter collectives and an indefinite hang. Transformers v5 fixes this by storing experts as fused 3D parameter tensors (no per-expert modules, no per-expert FSDP collectives).</p>\n<h3>Nemotron 3 Nano 30B A3B</h3>\n<table>\n<thead>\n<tr>\n<th>Metric</th>\n<th>v4 (hub code)</th>\n<th>v5 (FA2 + grouped_mm + Mamba CUDA)</th>\n<th>NeMo AutoModel (EP=8)</th>\n<th>v5 → NeMo AutoModel</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>TPS/GPU (avg)</td>\n<td>1,807</td>\n<td>4,583</td>\n<td>15,421</td>\n<td><strong>3.36x</strong></td>\n</tr>\n<tr>\n<td>Peak Memory</td>\n<td>61.9 GiB</td>\n<td>62.1 GiB</td>\n<td>42.5 GiB</td>\n<td><strong>-32%</strong></td>\n</tr>\n<tr>\n<td>Avg Forward+Loss</td>\n<td>1,024 ms</td>\n<td>283 ms</td>\n<td>109 ms</td>\n<td>2.60x</td>\n</tr>\n<tr>\n<td>Avg Backward</td>\n<td>1,246 ms</td>\n<td>611 ms</td>\n<td>157 ms</td>\n<td>3.89x</td>\n</tr>\n</tbody>\n</table>\n<p><strong>v4 config:</strong> trust_remote_code=True (NVIDIA's hub modeling code). The hub code's expert loop is FSDP-safe (iterates all experts regardless of token assignment), so it doesn't deadlock like Qwen3 v4.</p>\n<h3>Where the speedup comes from</h3>\n<p>The 3.4-3.7x speedup from NeMo AutoModel over Transformers v5 comes from three sources:</p>\n<ol>\n<li>\n<p><strong>Expert Parallelism reduces memory pressure.</strong> EP=8 distributes expert weights across GPUs, cutting the per-GPU MoE footprint by 8x. For Qwen3, this drops peak memory from 68.2 GiB to 48.1 GiB (-29%). For Nemotron Nano, it drops from 62.1 GiB to 42.5 GiB (-32%), freeing headroom for larger batch sizes or longer sequences.</p>\n</li>\n<li>\n<p><strong>DeepEP fuses communication with computation.</strong> Instead of separate AllGather/ReduceScatter collectives for expert routing, DeepEP fuses token dispatch and combines into optimized GPU kernels, overlapping communication with expert computation.</p>\n</li>\n<li>\n<p><strong>TransformerEngine kernels accelerate core operations.</strong> TE's fused attention, linear layers, and RMSNorm implementations provide consistent speedups over their PyTorch/Flash Attention equivalents across all layer types, not just MoE layers.</p>\n</li>\n</ol>\n<h2>Transformers v5 Features Leveraged by HuggingFace AutoModel</h2>\n<h3>Expert Backends</h3>\n<p>One of the most impactful features in Transformers v5 is the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/transformers/en/experts_interface\">experts_implementation</a> parameter, which includes three expert backends:</p>\n<table>\n<thead>\n<tr>\n<th>Backend</th>\n<th>Description</th>\n<th>Best for</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>eager</td>\n<td>For-loop over selected experts</td>\n<td>Debugging, compatibility, and correctness. Also available for v4.</td>\n</tr>\n<tr>\n<td>batched_mm</td>\n<td>Duplicates expert params, single batched GEMM via torch.bmm</td>\n<td>Small inputs, fast with torch.compile. Added for v5</td>\n</tr>\n<tr>\n<td>grouped_mm</td>\n<td>Orders tokens by expert, single grouped GEMM via torch.nn.functional.grouped_mm</td>\n<td>Training (memory efficient, no param duplication). Added for v5.</td>\n</tr>\n</tbody>\n</table>\n<p>The grouped_mm backend is the key training optimization: instead of looping over experts one by one, it sorts tokens by their assigned expert and executes a single fused grouped matrix multiplication.</p>\n<p>NeMo AutoModel takes this further. For models with custom implementations, it uses DeepEP fused all-to-all dispatch combined with grouped GEMM kernels and TransformerEngine linear layers. The progression looks like:</p>\n<pre><code><span class=\"code-snippet\">v4 (eager for-loop) → v5 (grouped_mm) → NeMo AutoModel (DeepEP + GMM + TE)\n</span></code></pre>\n<p>In NeMo AutoModel, the expert backend is configured through BackendConfig:</p>\n<pre><code class=\"language-py\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">nemo_automodel</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">components</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">models</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">common</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">utils</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">BackendConfig</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">backend</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">BackendConfig</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-variable syntax-parameter syntax-python\">attn</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">te<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>           <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> TransformerEngine attention\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">linear</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">te<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>         <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> TransformerEngine linear layers\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">experts</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">torch_mm<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>  <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Grouped expert matmul\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">dispatcher</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">deepep<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> DeepEP fused all-to-all\n</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<h2>Expert Parallelism and DeepEP</h2>\n<p>Transformers v5 also ships an <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/transformers/en/expert_parallelism\">Expert Parallelism path</a>. It shards expert weights across GPUs. The <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/integrations/tensor_parallel.py#L1078\">GroupedGemmParallel</a> style loads only each device's local experts, and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/integrations/tensor_parallel.py#L1123\">RouterParallel</a> routes tokens and combines results with an all_reduce. It's neatly built on v5's existing tensor-parallel machinery. Enabling it makes the model's tp_plan return its <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/modeling_utils.py#L1448\">expert plan</a>, so expert parallelism shares the device budget with data parallelism (ep × dp = world_size). For the single-node 30B benchmarks here, we found plain data-parallel v5 (dp=8, ep=1) to be the fastest v5 configuration, so that's the v5 setup we report.</p>\n<p>NeMo AutoModel takes a complementary approach tuned for multi-GPU MoE training. It makes EP its own parallelism dimension, a dedicated moe_mesh alongside (rather than carved from) the data-parallel mesh, using PyTorch's DTensor with Shard(0). Because the expert mesh is orthogonal to data parallelism, the two compose on the same devices. On 8 GPUs NeMo AutoModel runs ep=8 and dp=8 together, so every GPU trains on its own data shard while holding only 1/8 of the experts. Expert weights are physically sharded across GPUs along the expert dimension.</p>\n<pre><code class=\"language-py\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> From nemo_automodel/components/moe/parallelizer.py\n</span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">torch</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">distributed</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-import-name syntax-python\">tensor</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">Shard</span><span class=\"syntax-punctuation syntax-separator syntax-import-list syntax-python\">,</span> <span class=\"syntax-meta syntax-generic-name syntax-python\">distribute_tensor</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Each GPU holds only 1/ep_size of the expert weights\n</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">distribute_tensor</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">param</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">device_mesh</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Shard</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>With ep_size=8 on 8 GPUs, each GPU holds only 1/8 of the expert parameters. For a model like Nemotron-3-Nano-30B-A3B with ~55 GiB of expert weights, EP reduces the per-GPU expert footprint from ~55 GiB to ~6.8 GiB, making training possible where FSDP-only approaches run out of memory.</p>\n<p>On top of EP, NeMo AutoModel integrates <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/deepseek-ai/DeepEP\">DeepEP</a> that fuses the token routing into optimized GPU kernels, and delivers significant speedups when combined with grouped GEMM for grouped expert computation. In our <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/NVIDIA-NeMo/Automodel/discussions/916\">large-scale MoE benchmarks</a>, DeepEP + grouped GEMM reduced cost per iteration by 47% on the full DeepSeek V3 671B model compared to all-gather + looped expert baselines.</p>\n<h3>Dynamic Weight Loading</h3>\n<p>Transformers v5 also introduced a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/transformers/en/weightconverter\">dynamic weight loading</a> system through WeightConverter and WeightRenaming. This enables MoE checkpoint to be stored in fused 3D tensors for more efficient execution. The WeightConverter applies composable operations to transform checkpoint tensors on-the-fly during from_pretrained().</p>\n<p>NeMo AutoModel is a direct consumer of this v5 API. Over <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/NVIDIA-NeMo/Automodel/blob/main/nemo_automodel/components/checkpoint/conversion_mapping.py\">20 model types</a> use this mechanism through MODELS_REQUIRING_TENSOR_MERGING, including Mixtral, Qwen2 MoE, Qwen3 MoE, DeepSeek V2/V3, OLMoE, and more. The conversions are fully reversible: save_pretrained() produces standard HF-format checkpoints that any downstream tool can load.</p>\n<h2>Getting Started</h2>\n<p>To try NeMo AutoModel, please visit our official documentation page to <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.nvidia.com/nemo/automodel/latest/get-started/installation\">get started</a>.</p>\n<p>For more details, see:</p>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.nvidia.com/nemo/automodel/latest/get-started/hf-compatibility\">NeMo AutoModel HuggingFace API Compatibility Guide</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.nvidia.com/nemo/automodel/latest/model-coverage/overview\">NeMo AutoModel Model Coverage</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.nvidia.com/nemo/automodel/latest/performance/performance-summary\">NeMo AutoModel Performance Summary</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/transformers/en/community_integrations/nemo_automodel_finetuning\">NeMo AutoModel on HuggingFace</a></li>\n</ul>\n<h2>Conclusion</h2>\n<p>NVIDIA NeMo AutoModel is the natural next step for HuggingFace users scaling up model training. By building directly on Transformers v5, AutoModel provides a zero-friction upgrade path: change one import line and get a model instance that is more than three times as fast.</p>\n<p>On Qwen3-30B-A3B and Nemotron 3 Nano 30B-A3B, this delivers 3.4-3.7x higher training throughput with 29-32% less GPU memory compared to the best Transformers v5 configuration. And because true Expert Parallelism shards experts across GPUs, the same path scales up to full fine-tuning a 550B model like Nemotron 3 Ultra across 16 nodes, the regime where Expert Parallelism becomes essential to fit the model in memory. Because NeMo AutoModel checkpoints are standard HF-format safetensors, you can deploy them on inference frameworks like vLLM and SGLang.</p>\n<p>The code, configs, and benchmark scripts are all available in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/NVIDIA-NeMo/Automodel/tree/blog/transformers-v5-automodel/blog_experiments\">NeMo AutoModel repository</a>.</p>\n<h2>Acknowledgements</h2>\n<p>Core contributors to this work, listed alphabetically by last name: Adil Asif, Hemil Desai, Alexandros Koumparoulis, and Huiying Li.</p>\n",
  "content_markdown": "HuggingFace Transformers has become the foundation of the open-source AI ecosystem, and the recent [Transformers v5](https://github.com/huggingface/transformers/releases/tag/v5.0.0) release strengthened it with first-class support for Mixture-of-Experts (MoE) models, now the dominant architecture for [frontier models](https://www.nvidia.com/en-us/glossary/frontier-models/). v5 ships the MoE foundations: expert backends, dynamic weight loading, and distributed execution that make MoE extensible and easy to build on.\n\n[NVIDIA NeMo AutoModel](https://github.com/NVIDIA-NeMo/Automodel) is an open library part of the [NVIDIA NeMo framework](https://github.com/NVIDIA-NeMo) for building custom generative AI models at scale. NeMo AutoModel builds cleanly on top of v5, adding Expert Parallelism, DeepEP fused all-to-all dispatch, and TransformerEngine kernels, and it leans on v5's dynamic weight loading to bring those optimizations to a broad and growing set of model families. The payoff is **3.4-3.7x higher training throughput** and **29-32% less GPU memory** on fine-tuning MoE models than native Transformers v5, using the same from\\_pretrained() API: a single import line, with no other code changes.\n\nThis blog details how this combination works and how users can fine-tune MoE models faster without changing their APIs.\n\n## Background\n\nThe rise of MoE models has introduced new challenges to efficient training: Routing tokens across hundreds of experts, fusing expert matmuls into a single kernel, sharding weights across GPUs, and overlapping communication with computation all require infrastructure beyond what a general-purpose library provides out of the box.\n\n[Transformers v5](https://github.com/huggingface/transformers/releases/tag/v5.0.0) (“v5”) introduced first-class MoE support such as [expert backends](https://huggingface.co/docs/transformers/en/experts_interface), [dynamic weight loading](https://huggingface.co/docs/transformers/en/weightconverter), and tensor parallel plans for distributed execution. In addition, v5 made distributed training first-class by integrating PyTorch's DeviceMesh directly into from\\_pretrained().\n\n[NeMo AutoModel](https://github.com/NVIDIA-NeMo/Automodel) builds on top of v5 by subclassing AutoModelForCausalLM, and adding Expert Parallelism (EP), DeepEP fused all-to-all dispatch, and TransformerEngine kernels. DeepEP is the piece v5 doesn't have yet: it overlaps communication with expert compute. And because NeMo AutoModel rides v5's reversible weight conversion to load each model, it can focus its engineering on these reusable core ops instead of per-model checkpoint plumbing, while save\\_pretrained() still emits standard HF checkpoints that tools like vLLM and SGLang can load.\n\nThe next section walks through how the two work together and the performance gains we measured, from full fine-tuning [NVIDIA Nemotron 3 Ultra 550B A55B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16) across 16 nodes down to single-node models such as Qwen3-30B-A3B and [Nemotron 3 Nano 30B A3B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16).\n\n## NeMo AutoModel: Same API, More Performance\n\nOne of NeMo AutoModel's goals is API compatibility with HuggingFace Transformers to enable open-source community. NeMoAutoModelForCausalLM subclasses AutoModelForCausalLM, so any code that works with HF models works with AutoModel too.\n\nHere's what loading a model looks like in both. Only the import changes:\n\n[![nemo_and_hf](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/VTPq2Wp-RrEcP1eGUJxao.png)](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/VTPq2Wp-RrEcP1eGUJxao.png)\n\nThat single import does a lot of work. For popular MoE architectures like Qwen3, [NVIDIA Nemotron](https://developer.nvidia.com/nemotron), GPT-OSS, and DeepSeek V3, NeMo AutoModel ships [hand-tuned implementations](https://github.com/NVIDIA-NeMo/Automodel/blob/main/nemo_automodel/_transformers/registry.py) with TransformerEngine attention, fused linear layers, and custom expert kernels. For everything else, it falls back to vanilla HF while still applying optimizations like [Liger kernel](https://github.com/linkedin/Liger-Kernel) patching, among others. And whichever path it takes, the resulting model is ready to scale: pass a device\\_mesh and you have multi-GPU training without further rewrites.\n\nWhere NeMo AutoModel really shines is scaling MoE models to multi-GPU training. To train [Nemotron 3 Nano 30B A3B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16) with Expert Parallelism across 8 GPUs, one adds the distributed mesh configuration:\n\n```py\nimport os\nimport torch\nimport torch.distributed as dist\nfrom nemo_automodel import NeMoAutoModelForCausalLM\nfrom nemo_automodel.recipes._dist_utils import create_distributed_setup_from_config\n\ndist.init_process_group(backend=\"nccl\")\ntorch.manual_seed(0)\ntorch.cuda.set_device(int(os.environ.get(\"LOCAL_RANK\", 0)))\n\ndist_setup = create_distributed_setup_from_config(\n    {\n        \"strategy\": \"fsdp2\",\n        \"ep_size\": 8,\n    },\n)\n\nmodel = NeMoAutoModelForCausalLM.from_pretrained(\n    \"nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16\",\n    dtype=torch.bfloat16,\n    distributed_setup=dist_setup,\n)\n\ndist.destroy_process_group()\n```\n\nThis gives speed, scalability and memory-optimizations with FSDP2, Expert Parallelism, TransformerEngine kernels and DeepEP dispatch, all from a from\\_pretrained() call.\n\n## Performance Comparison\n\nWe evaluated NeMo AutoModel in two regimes: full fine-tuning a frontier-scale 550B model across 16 nodes, and training two 30B MoE models on a single node. The 550B result shows why Expert Parallelism is essential at scale; the 30B results quantify the per-GPU speedup over Transformers v5.\n\n### Nemotron 3 Ultra 550B A55B (full fine-tune, multi-node)\n\n[Nemotron 3 Ultra 550B A55B](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16) is a 550B-parameter hybrid model shipping with Mamba2, LatentMoE, and Multi-Token Prediction (MTP). We benchmark a **full fine-tune**: every parameter is updated and the Adam optimizer state is materialized, which at this scale spans **16 H100 nodes (128 GPUs)**.\n\n**Methodology:**\n\n| Parameter          | Value                                                     |\n| ------------------ | --------------------------------------------------------- |\n| Hardware           | 16x H100 80GB (128 GPUs)                                  |\n| Expert Parallelism | EP=64                                                     |\n| Local batch size   | 2                                                         |\n| Sequence length    | 4,096                                                     |\n| Features           | MTP, activation checkpointing, fused linear cross-entropy |\n| Kernels            | DeepEP dispatch + torch\\_mm experts + TransformerEngine   |\n\n| Metric        | NeMo AutoModel (EP=64) |\n| ------------- | ---------------------- |\n| TPS/GPU (avg) | 815                    |\n| TFLOP/s/GPU   | \\~293                  |\n| Peak Memory   | 58.2 GiB               |\n\n**Why there is no Transformers v5 column.** Transformers v5 runs out of memory at this scale, so there is no v5 number to report here. AutoModel's Expert Parallelism shards the experts across GPUs to bring the footprint within budget, which is what lets the full fine-tune run. The 30B comparisons below show the same advantage where v5 fits.\n\n### Single-node 30B MoE benchmarks\n\nWe benchmarked three approaches on a single node with 8x H100 80GB GPUs: HF Transformers v4 (hub code), HF Transformers v5 (with best available optimizations), and NeMo AutoModel (EP=8 + custom kernels).\n\n**Methodology:**\n\n| Parameter        | Value                      |\n| ---------------- | -------------------------- |\n| Hardware         | 8x H100 80GB (single node) |\n| Sequence length  | 4,096                      |\n| Local batch size | 1                          |\n\n**A note on the routing gate.** The NeMo AutoModel numbers below use a balanced routing gate, which forces tokens to be distributed uniformly across experts. This emulates the *ideal* operating point an MoE is trained toward: a well-trained model's load-balancing loss drives expert utilization to near-uniform, so balanced routing reflects the steady-state a real workload converges to (and removes the straggler noise that random dummy tokens otherwise inject into expert parallelism). v4/v5 run their native router on the same dummy tokens. The balanced gate therefore measures NeMo AutoModel at its target MoE operating point, and the v4/v5 columns reflect their out-of-the-box behavior.\n\n[![nemo_automodel_blog_chart_mockup_v5](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/rbCVgV6a18c4UcDsiWfZN.png)](https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/rbCVgV6a18c4UcDsiWfZN.png)\n\n### Qwen3-30B-A3B\n\n| Metric           | v4       | v5 (FA2 + grouped\\_mm) | NeMo AutoModel (EP=8) | v5 → NeMo AutoModel |\n| ---------------- | -------- | ---------------------- | --------------------- | ------------------- |\n| TPS/GPU (avg)    | deadlock | 3,075                  | 11,340                | **3.69x**           |\n| Peak Memory      | —        | 68.2 GiB               | 48.1 GiB              | **-29%**            |\n| Avg Forward+Loss | —        | 582 ms                 | 194 ms                | 3.00x               |\n| Avg Backward     | —        | 758 ms                 | 178 ms                | 4.26x               |\n\n**Why v4 deadlocks:** Transformers v4 stores Qwen3 MoE experts as a ModuleList of 128 individual MLP modules, each separately FSDP-wrapped. The forward pass uses a data-dependent loop that only iterates experts that received tokens. With different data per rank, different ranks skip different experts, causing mismatched FSDP AllGather/ReduceScatter collectives and an indefinite hang. Transformers v5 fixes this by storing experts as fused 3D parameter tensors (no per-expert modules, no per-expert FSDP collectives).\n\n### Nemotron 3 Nano 30B A3B\n\n| Metric           | v4 (hub code) | v5 (FA2 + grouped\\_mm + Mamba CUDA) | NeMo AutoModel (EP=8) | v5 → NeMo AutoModel |\n| ---------------- | ------------- | ----------------------------------- | --------------------- | ------------------- |\n| TPS/GPU (avg)    | 1,807         | 4,583                               | 15,421                | **3.36x**           |\n| Peak Memory      | 61.9 GiB      | 62.1 GiB                            | 42.5 GiB              | **-32%**            |\n| Avg Forward+Loss | 1,024 ms      | 283 ms                              | 109 ms                | 2.60x               |\n| Avg Backward     | 1,246 ms      | 611 ms                              | 157 ms                | 3.89x               |\n\n**v4 config:** trust\\_remote\\_code=True (NVIDIA's hub modeling code). The hub code's expert loop is FSDP-safe (iterates all experts regardless of token assignment), so it doesn't deadlock like Qwen3 v4.\n\n### Where the speedup comes from\n\nThe 3.4-3.7x speedup from NeMo AutoModel over Transformers v5 comes from three sources:\n\n1. **Expert Parallelism reduces memory pressure.** EP=8 distributes expert weights across GPUs, cutting the per-GPU MoE footprint by 8x. For Qwen3, this drops peak memory from 68.2 GiB to 48.1 GiB (-29%). For Nemotron Nano, it drops from 62.1 GiB to 42.5 GiB (-32%), freeing headroom for larger batch sizes or longer sequences.\n\n2. **DeepEP fuses communication with computation.** Instead of separate AllGather/ReduceScatter collectives for expert routing, DeepEP fuses token dispatch and combines into optimized GPU kernels, overlapping communication with expert computation.\n\n3. **TransformerEngine kernels accelerate core operations.** TE's fused attention, linear layers, and RMSNorm implementations provide consistent speedups over their PyTorch/Flash Attention equivalents across all layer types, not just MoE layers.\n\n## Transformers v5 Features Leveraged by HuggingFace AutoModel\n\n### Expert Backends\n\nOne of the most impactful features in Transformers v5 is the [experts\\_implementation](https://huggingface.co/docs/transformers/en/experts_interface) parameter, which includes three expert backends:\n\n| Backend     | Description                                                                      | Best for                                                          |\n| ----------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------- |\n| eager       | For-loop over selected experts                                                   | Debugging, compatibility, and correctness. Also available for v4. |\n| batched\\_mm | Duplicates expert params, single batched GEMM via torch.bmm                      | Small inputs, fast with torch.compile. Added for v5               |\n| grouped\\_mm | Orders tokens by expert, single grouped GEMM via torch.nn.functional.grouped\\_mm | Training (memory efficient, no param duplication). Added for v5.  |\n\nThe grouped\\_mm backend is the key training optimization: instead of looping over experts one by one, it sorts tokens by their assigned expert and executes a single fused grouped matrix multiplication.\n\nNeMo AutoModel takes this further. For models with custom implementations, it uses DeepEP fused all-to-all dispatch combined with grouped GEMM kernels and TransformerEngine linear layers. The progression looks like:\n\n```\nv4 (eager for-loop) → v5 (grouped_mm) → NeMo AutoModel (DeepEP + GMM + TE)\n```\n\nIn NeMo AutoModel, the expert backend is configured through BackendConfig:\n\n```py\nfrom nemo_automodel.components.models.common.utils import BackendConfig\n\nbackend = BackendConfig(\n    attn=\"te\",           # TransformerEngine attention\n    linear=\"te\",         # TransformerEngine linear layers\n    experts=\"torch_mm\",  # Grouped expert matmul\n    dispatcher=\"deepep\", # DeepEP fused all-to-all\n)\n```\n\n## Expert Parallelism and DeepEP\n\nTransformers v5 also ships an [Expert Parallelism path](https://huggingface.co/docs/transformers/en/expert_parallelism). It shards expert weights across GPUs. The [GroupedGemmParallel](https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/integrations/tensor_parallel.py#L1078) style loads only each device's local experts, and [RouterParallel](https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/integrations/tensor_parallel.py#L1123) routes tokens and combines results with an all\\_reduce. It's neatly built on v5's existing tensor-parallel machinery. Enabling it makes the model's tp\\_plan return its [expert plan](https://github.com/huggingface/transformers/blob/v5.10.2/src/transformers/modeling_utils.py#L1448), so expert parallelism shares the device budget with data parallelism (ep × dp = world\\_size). For the single-node 30B benchmarks here, we found plain data-parallel v5 (dp=8, ep=1) to be the fastest v5 configuration, so that's the v5 setup we report.\n\nNeMo AutoModel takes a complementary approach tuned for multi-GPU MoE training. It makes EP its own parallelism dimension, a dedicated moe\\_mesh alongside (rather than carved from) the data-parallel mesh, using PyTorch's DTensor with Shard(0). Because the expert mesh is orthogonal to data parallelism, the two compose on the same devices. On 8 GPUs NeMo AutoModel runs ep=8 and dp=8 together, so every GPU trains on its own data shard while holding only 1/8 of the experts. Expert weights are physically sharded across GPUs along the expert dimension.\n\n```py\n# From nemo_automodel/components/moe/parallelizer.py\nfrom torch.distributed.tensor import Shard, distribute_tensor\n\n# Each GPU holds only 1/ep_size of the expert weights\ndistribute_tensor(param, device_mesh, [Shard(0)])\n```\n\nWith ep\\_size=8 on 8 GPUs, each GPU holds only 1/8 of the expert parameters. For a model like Nemotron-3-Nano-30B-A3B with ~55 GiB of expert weights, EP reduces the per-GPU expert footprint from ~55 GiB to ~6.8 GiB, making training possible where FSDP-only approaches run out of memory.\n\nOn top of EP, NeMo AutoModel integrates [DeepEP](https://github.com/deepseek-ai/DeepEP) that fuses the token routing into optimized GPU kernels, and delivers significant speedups when combined with grouped GEMM for grouped expert computation. In our [large-scale MoE benchmarks](https://github.com/NVIDIA-NeMo/Automodel/discussions/916), DeepEP + grouped GEMM reduced cost per iteration by 47% on the full DeepSeek V3 671B model compared to all-gather + looped expert baselines.\n\n### Dynamic Weight Loading\n\nTransformers v5 also introduced a [dynamic weight loading](https://huggingface.co/docs/transformers/en/weightconverter) system through WeightConverter and WeightRenaming. This enables MoE checkpoint to be stored in fused 3D tensors for more efficient execution. The WeightConverter applies composable operations to transform checkpoint tensors on-the-fly during from\\_pretrained().\n\nNeMo AutoModel is a direct consumer of this v5 API. Over [20 model types](https://github.com/NVIDIA-NeMo/Automodel/blob/main/nemo_automodel/components/checkpoint/conversion_mapping.py) use this mechanism through MODELS\\_REQUIRING\\_TENSOR\\_MERGING, including Mixtral, Qwen2 MoE, Qwen3 MoE, DeepSeek V2/V3, OLMoE, and more. The conversions are fully reversible: save\\_pretrained() produces standard HF-format checkpoints that any downstream tool can load.\n\n## Getting Started\n\nTo try NeMo AutoModel, please visit our official documentation page to [get started](https://docs.nvidia.com/nemo/automodel/latest/get-started/installation).\n\nFor more details, see:\n\n- [NeMo AutoModel HuggingFace API Compatibility Guide](https://docs.nvidia.com/nemo/automodel/latest/get-started/hf-compatibility)\n- [NeMo AutoModel Model Coverage](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/overview)\n- [NeMo AutoModel Performance Summary](https://docs.nvidia.com/nemo/automodel/latest/performance/performance-summary)\n- [NeMo AutoModel on HuggingFace](https://huggingface.co/docs/transformers/en/community_integrations/nemo_automodel_finetuning)\n\n## Conclusion\n\nNVIDIA NeMo AutoModel is the natural next step for HuggingFace users scaling up model training. By building directly on Transformers v5, AutoModel provides a zero-friction upgrade path: change one import line and get a model instance that is more than three times as fast.\n\nOn Qwen3-30B-A3B and Nemotron 3 Nano 30B-A3B, this delivers 3.4-3.7x higher training throughput with 29-32% less GPU memory compared to the best Transformers v5 configuration. And because true Expert Parallelism shards experts across GPUs, the same path scales up to full fine-tuning a 550B model like Nemotron 3 Ultra across 16 nodes, the regime where Expert Parallelism becomes essential to fit the model in memory. Because NeMo AutoModel checkpoints are standard HF-format safetensors, you can deploy them on inference frameworks like vLLM and SGLang.\n\nThe code, configs, and benchmark scripts are all available in the [NeMo AutoModel repository](https://github.com/NVIDIA-NeMo/Automodel/tree/blog/transformers-v5-automodel/blog_experiments).\n\n## Acknowledgements\n\nCore contributors to this work, listed alphabetically by last name: Adil Asif, Hemil Desai, Alexandros Koumparoulis, and Huiying Li.\n",
  "dateCreated": "2026-10-19T01:26:53.998049939+00:00",
  "date_created": "2026-06-24T16:00:13+00:00",
  "date_modified": "2026-06-24T16:00:13+00:00",
  "date_published": "2026-06-24T16:00:13+00:00",
  "description": "HuggingFace Transformers has become the foundation of the open-source AI ecosystem, and the recent Transformers v5 release strengthened it with first-class support for Mixture-of-Experts (MoE) models, now the dominant architecture for…",
  "external_url": "https://huggingface.co/blog/nvidia/accelerating-fine-tuning-nvidia-nemo-automodel",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/huggingface-co/2026/06/2026-06-24-accelerating-transformers-fine-tuning-with-nvidia-nemo.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/huggingface-co/2026/06/2026-06-24-accelerating-transformers-fine-tuning-with-nvidia-nemo.md"
  },
  "id": "urn:aggr:item:ce16aea042744b8d90ea7b0d8b05be5dc42fecb7",
  "isBasedOn": {
    "@id": "https://huggingface.co/blog/nvidia/accelerating-fine-tuning-nvidia-nemo-automodel"
  },
  "mainEntity": {
    "@id": "https://huggingface.co/blog/nvidia/accelerating-fine-tuning-nvidia-nemo-automodel",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2026-06-24-accelerating-transformers-fine-tuning-with-nvidia-nemo/#webpage"
    },
    "dateModified": "2026-06-24T16:00:13+00:00",
    "datePublished": "2026-06-24T16:00:13+00:00",
    "headline": "Accelerating Transformers Fine-Tuning with NVIDIA NeMo AutoModel",
    "image": {
      "@type": "ImageObject",
      "caption": null,
      "height": 90,
      "url": "https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/1N4GjIYBsZ6RCReRx_qBB.png",
      "width": 160
    },
    "timeRequired": "PT10M",
    "url": "https://huggingface.co/blog/nvidia/accelerating-fine-tuning-nvidia-nemo-automodel",
    "wordCount": 2170
  },
  "name": "Archived snapshot: Accelerating Transformers Fine-Tuning with NVIDIA NeMo AutoModel",
  "preview": {
    "alt": null,
    "color": null,
    "height": 90,
    "placeholder": {
      "data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
      "hash": ""
    },
    "url": "https://cdn-uploads.huggingface.co/production/uploads/690d0a6c2c5acfe0e1f4777d/1N4GjIYBsZ6RCReRx_qBB.png",
    "width": 160
  },
  "reading_minutes": 10,
  "replicated_at": null,
  "source": "huggingface-co",
  "source_name": "Hugging Face - Blog",
  "summary": null,
  "tags": [],
  "temporalCoverage": "2026-10-19T01:26:53.998049939+00:00",
  "title": "Accelerating Transformers Fine-Tuning with NVIDIA NeMo AutoModel",
  "url": "https://aggr.aymericbeaumet.com/items/huggingface-co/2026-06-24-accelerating-transformers-fine-tuning-with-nvidia-nemo/",
  "word_count": 2170
}