Skip to content

How to Make LLM Training Faster with Unsloth and NVIDIA

Unsloth + NVIDIA report three independent training-loop optimizations that compose to ~25% faster end-to-end LLM training on top of Unsloth’s existing 2–5× speedup, with no accuracy loss. The unifying theme is removing per-layer host-device synchronization or copy-compute serialization from the hot path: (1) cache packed-sequence attention metadata once per batch instead of rebuilding it per layer; (2) double-buffer activation reloads from pinned CPU memory so backward compute and copy overlap; (3) replace per-expert torch.where with one bincount + sorted-offsets in GPT-OSS MoE routing. Reported gains on B200 Blackwell: +43.3% forward on Qwen3-14B QLoRA SFT, +6.7–8.4% step time on 8B/14B dense, and +23%/+13% forward/backward on GPT-OSS routing. Akshat’s note flags (1) and (3) as already done at Luma and (2) — the double-buffered activation reload — as the worth-stealing item.

  • For packed-sequence training, packed-sequence metadata (cu_seqlens, max_seqlen, SDPA mask structure, xFormers block masks) is identical across all L transformer layers within a fixed batch, but the standard PyTorch path rebuilds it per layer; rebuilding forces device-to-host synchronization that recurs L times [§Packed-sequence metadata caching].
  • Caching the metadata + derived attention structures per device for the current packed batch yields +43.3% forward / +5.8% backward / +14.3% per-batch step on Qwen3-14B QLoRA SFT [§Packed-sequence metadata caching, summary table].
  • Microbenchmark on B200 attributes the per-layer cost to ~13.7 ms of SDPA packed-mask rebuild (the host-visible metadata sync is only ~0.2 ms); the saved-time model T_saved ≈ (L-1)·m predicts 199 ms saved/step at 16 layers on Llama-3.2-1B and 319 ms/step at 28 layers on Qwen3-0.6B, matching observed step-time reductions of 11.5% and 14.8% [§Packed-sequence metadata caching].
  • Smart checkpointing with single-buffer pinned-CPU activation offload serializes copy and backward compute: per-layer cost ≈ T_copy + T_compute. Double buffering preloads the next layer’s activation into buffer B while backward runs on buffer A, reducing the middle-layers’ per-step cost to max(T_copy, T_compute) [§Double-buffered checkpoint reload].
  • Measured gains on B200 with double-buffered checkpoint reload: +8.40% steps/s at 8B, +6.70% at 14B, +4.61% at 32B, with only +0.23–0.47 GB extra VRAM; final losses unchanged [§Double-buffered checkpoint reload, summary table].
  • Bandwidth check: pinned-memory H2D measured at 55.7 GB/s (PCIe ceiling 64 GB/s); a single activation reload is on the order of 4–8 ms, and hiding ~30–60 such reloads across a few dozen checkpointed layers accounts for the observed 200–280 ms saved per step at 8B–32B [§Double-buffered checkpoint reload].
  • In the PyTorch native_torch GPT-OSS MoE routing path, the naive for expert_idx in range(num_experts): token_idx, _ = torch.where(router_indices == expert_idx) issues one data-dependent dynamic query per expert, forcing a CPU-GPU sync that scales as num_experts; replacing it with one bincount + argsort + per-expert offsets reduces the dynamic-query overhead to O(1) [§GPT-OSS MoE routing with bincount].
  • Reported gains for the GPT-OSS MoE routing fix: ~10–15% in end-to-end team validation, +23% forward / +13% backward on the targeted routing path; applies to any MoE using the native_torch backend [§GPT-OSS MoE routing with bincount].
  • Shared design lesson: once the main math kernels (attention, GEMM, MoE expert FFN) are optimized, the remaining gains come from removing per-layer coordination work — repeated metadata reconstruction, copy/compute serialization, and dynamic-shape queries — from the hot path [§Why this works, summary table].

Three independent changes, each addressing a distinct synchronization or serialization pattern in PyTorch-style training:

  1. Packed-sequence metadata caching. For a packed batch with boundary information B = {lengths, cu_seqlens, max_seqlen, mask structure}, build B and the derived SDPA / xFormers attention structures once and cache them per device; every transformer layer in the forward pass reuses the cached structures instead of triggering a rebuild that forces a device-to-host sync. Time model: T_uncached ≈ L·(A + s) collapses to T_cached ≈ L·A + s, saving (L-1)·s.
  2. Double-buffered checkpoint reload. Activations offloaded to pinned CPU memory are reloaded across the PCIe bus during backward. With a single staging buffer, the copy stream and compute stream serialize. With two buffers, the copy stream stages layer i+1 into buffer B while the compute stream runs backward on layer i from buffer A, then swaps. Implementation includes pinning guarantees, fallbacks when activation size exceeds buffer capacity, and a wait on the first/last layer where the pipeline can’t overlap. Saved time ≈ (L-1)·min(T_copy, T_compute).
  3. GPT-OSS MoE routing with bincount. The naive loop calls torch.where(router_indices == expert_idx) once per expert; the output shape is data-dependent, which forces a CPU-GPU sync per iteration. The fix is to (a) argsort the routing indices once, (b) bincount to get tokens per expert, (c) compute prefix-sum offsets, then dispatch experts via slicing the sorted index array. Dynamic-query overhead drops from O(num_experts) to O(1).

All three optimizations auto-enable on RTX laptops, data-center GPUs, and DGX Spark on Unsloth update.

Headline numbers, all reported by Unsloth on Blackwell-class hardware unless noted:

  • Qwen3-14B QLoRA SFT with packed-sequence metadata caching: +43.3% forward, +5.8% backward, +14.3% per-batch step.
  • Llama-3.2-1B (16 layers): ~199 ms saved/step, 11.5% lower end-to-end step time.
  • Qwen3-0.6B (28 layers): ~319 ms saved/step, 14.8% lower end-to-end step time.
  • Dense models with double-buffered checkpoint reload (B200): 8B 0.3739 → 0.4053 steps/s (+8.40%), 14B 0.2245 → 0.2395 steps/s (+6.70%), 32B 0.1979 → 0.2070 steps/s (+4.61%). VRAM overhead +0.23–0.47 GB. Final losses unchanged.
  • GPT-OSS MoE routing: ~10–15% in team validation, +23% forward / +13% backward on the targeted routing path.

Composing all three lands the ~25% headline. Each gain is consistent with the wall-clock saved-time models the blog derives from microbenchmarks (mask-rebuild cost, pinned-memory bandwidth, dynamic-query count).

Each of the three optimizations is the same template — “find a per-layer or per-expert host-device synchronization that’s hiding in the glue code around the main kernels, and amortize it” — applied to a different surface of the training loop. The GPT-OSS routing fix in particular is structurally the same template as the IO-Aware Kernel Design line of work (FlashSampling: Fast and Memory-Efficient Exact Sampling, Flash-KMeans: Fast and Memory-Efficient Exact K-Means): identify a hot-path op whose overhead scales with a quantity that should be O(1) and exploit an algebraic decomposition (argsort + bincount in place of repeated dynamic where) to make it so. The MoE half also connects to MoE Routing Design‘s broader concern that standard MoE implementations carry rigid biases — here a systems bias (the per-expert PyTorch loop) on top of the algorithmic ones Routing-Free Mixture-of-Experts and Demons in the Detail: On Implementing Load Balancing Loss for Training Specialized Mixture-of-Expert Models critique.

The double-buffered checkpoint-reload is the genuinely novel item — Akshat’s note flags it as worth doing — and it complements LoRA-/QLoRA-centric workflows like the ones tracked in Parameter-Efficient Finetuning by attacking the systems cost of activation checkpointing rather than the parameter count. Its size is bounded by min(T_copy, T_compute) per layer, so it pays best on larger dense models where backward compute is substantial but not yet dominant — exactly the regime where Luma trains.