<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>LLM Training on Duo&#39;s Tech Blog</title>
    <link>https://duoan.github.io/series/llm-training/</link>
    <description>Recent content in LLM Training on Duo&#39;s Tech Blog</description>
    <image>
      <title>Duo&#39;s Tech Blog</title>
      <url>https://duoan.github.io/images/papermod-cover.png</url>
      <link>https://duoan.github.io/images/papermod-cover.png</link>
    </image>
    <generator>Hugo -- 0.153.1</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 16 Jun 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://duoan.github.io/series/llm-training/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The ZeRO-3 Diagram Most People Remember Is Wrong</title>
      <link>https://duoan.github.io/posts/zero3-intra-layer-partitioning/</link>
      <pubDate>Mon, 16 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/zero3-intra-layer-partitioning/</guid>
      <description>&lt;h1 id=&#34;the-zero-3-diagram-most-people-remember-is-wrong&#34;&gt;The ZeRO-3 Diagram Most People Remember Is Wrong&lt;/h1&gt;
&lt;p&gt;Many engineers first learned ZeRO-3 from an animation that looked like pipeline parallelism.
One GPU owned early layers, another GPU owned later layers, and the active layer block appeared to be broadcast to all other GPUs when needed.
That picture is memorable.
It is also not the right mental model for current DeepSpeed ZeRO-3 training.&lt;/p&gt;
&lt;p&gt;The current steady-state model is intra-layer partitioning.
Each parameter is flattened, padded if necessary, and split across data-parallel ranks.
Before forward or backward compute needs that parameter, ranks AllGather the full parameter.
After gradients are produced, ranks ReduceScatter gradients back to the owning shards.
That is the operational reading of ZeRO-3 from the ZeRO paper (&lt;a href=&#34;https://arxiv.org/abs/1910.02054&#34;&gt;arXiv:1910.02054&lt;/a&gt;) and the current DeepSpeed runtime.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hiding Tensor-Parallel Collectives: AG/RS Overlap in Megatron</title>
      <link>https://duoan.github.io/posts/megatron-tp-comm-overlap/</link>
      <pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/megatron-tp-comm-overlap/</guid>
      <description>&lt;h1 id=&#34;hiding-tensor-parallel-collectives-agrs-overlap-in-megatron&#34;&gt;Hiding Tensor-Parallel Collectives: AG/RS Overlap in Megatron&lt;/h1&gt;
&lt;p&gt;Once Megatron SP is enabled, tensor-parallel communication often appears as AllGather and ReduceScatter rather than a single AllReduce.
That is a memory win because activations can stay sequence-sharded between tensor-parallel regions.
It also creates a scheduling question.
Can the collectives be hidden under GEMM work?
That question sits directly on top of Megatron&amp;rsquo;s tensor/sequence-parallel training path (&lt;a href=&#34;https://arxiv.org/abs/2104.04473&#34;&gt;arXiv:2104.04473&lt;/a&gt;, &lt;a href=&#34;https://arxiv.org/abs/2205.05198&#34;&gt;arXiv:2205.05198&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This post is about that scheduling question.
It complements &lt;a href=&#34;../tensor-parallelism-megatron/&#34;&gt;Megatron tensor parallelism&lt;/a&gt; and &lt;a href=&#34;../sequence-parallelism-megatron-sp/&#34;&gt;Megatron SP&lt;/a&gt;.
The goal is not to memorize every flag in Megatron or Transformer Engine.
The goal is to recognize where the dependency graph allows overlap and where it does not.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sequence Parallelism IV: Megatron Context Parallel and Load-Balanced Rings</title>
      <link>https://duoan.github.io/posts/megatron-context-parallel/</link>
      <pubDate>Mon, 02 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/megatron-context-parallel/</guid>
      <description>&lt;h1 id=&#34;sequence-parallelism-iv-megatron-context-parallel-and-load-balanced-rings&#34;&gt;Sequence Parallelism IV: Megatron Context Parallel and Load-Balanced Rings&lt;/h1&gt;
&lt;p&gt;Megatron Context Parallel, usually shortened to CP, brings long-context attention into Megatron&amp;rsquo;s hybrid-parallel world.
It keeps the familiar tensor, pipeline, and data-parallel axes, then adds a context axis that shards the sequence.
Inside that context group, attention behaves like a ring, borrowing the same blockwise K/V circulation idea as Ring Attention (&lt;a href=&#34;https://arxiv.org/abs/2310.01889&#34;&gt;arXiv:2310.01889&lt;/a&gt;) while staying compatible with Megatron-style tensor and pipeline parallelism (&lt;a href=&#34;https://arxiv.org/abs/2104.04473&#34;&gt;arXiv:2104.04473&lt;/a&gt;).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sequence Parallelism III: Ring Attention for Context That Does Not Fit</title>
      <link>https://duoan.github.io/posts/ring-attention/</link>
      <pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/ring-attention/</guid>
      <description>&lt;h1 id=&#34;sequence-parallelism-iii-ring-attention-for-context-that-does-not-fit&#34;&gt;Sequence Parallelism III: Ring Attention for Context That Does Not Fit&lt;/h1&gt;
&lt;p&gt;Megatron SP reduces replicated activation memory around tensor-parallel blocks.
DeepSpeed Ulysses uses All-to-All to turn sequence shards into head shards for attention.
Ring Attention changes the unit of work again.
It asks each rank to keep a block of queries fixed, then circulate key/value blocks around a ring until every query block has seen every key/value block it needs.
That is the core idea in &lt;em&gt;Ring Attention with Blockwise Transformers for Near-Infinite Context&lt;/em&gt; (&lt;a href=&#34;https://arxiv.org/abs/2310.01889&#34;&gt;arXiv:2310.01889&lt;/a&gt;).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sequence Parallelism II: DeepSpeed Ulysses and All-to-All Attention</title>
      <link>https://duoan.github.io/posts/sequence-parallelism-ulysses/</link>
      <pubDate>Mon, 19 May 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/sequence-parallelism-ulysses/</guid>
      <description>&lt;h1 id=&#34;sequence-parallelism-ii-deepspeed-ulysses-and-all-to-all-attention&#34;&gt;Sequence Parallelism II: DeepSpeed Ulysses and All-to-All Attention&lt;/h1&gt;
&lt;p&gt;Megatron SP is a careful memory optimization around an existing tensor-parallel block.
DeepSpeed Ulysses starts from a different question.
What if each device owns a sequence slice most of the time, but attention temporarily wants each device to own a head slice instead?&lt;/p&gt;
&lt;p&gt;The answer in DeepSpeed Ulysses is an All-to-All transpose (&lt;a href=&#34;https://arxiv.org/abs/2309.14509&#34;&gt;arXiv:2309.14509&lt;/a&gt;).
Before attention, every rank has all heads for a subset of tokens.
After All-to-All, every rank has all tokens for a subset of heads.
That one layout change lets local attention run per head while the rest of the layer can remain sequence-sharded.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Tensor Parallelism in Megatron-LM: Splitting Layers, Not Stacks</title>
      <link>https://duoan.github.io/posts/tensor-parallelism-megatron/</link>
      <pubDate>Sun, 18 May 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/tensor-parallelism-megatron/</guid>
      <description>&lt;h1 id=&#34;tensor-parallelism-in-megatron-lm-splitting-layers-not-stacks&#34;&gt;Tensor Parallelism in Megatron-LM: Splitting Layers, Not Stacks&lt;/h1&gt;
&lt;p&gt;Pipeline parallelism splits a model by depth. Tensor parallelism splits the math inside one layer.&lt;/p&gt;
&lt;p&gt;Megatron-LM made tensor parallelism practical for Transformers by choosing split points that preserve local GEMMs and put collectives only where the algebra requires them. The original Megatron paper introduced the core intra-layer pattern (&lt;a href=&#34;https://arxiv.org/abs/1909.08053&#34;&gt;arXiv:1909.08053&lt;/a&gt;). The later Megatron-LM systems paper showed how that TP axis composes with data and pipeline parallelism at cluster scale (&lt;a href=&#34;https://arxiv.org/abs/2104.04473&#34;&gt;arXiv:2104.04473&lt;/a&gt;).&lt;/p&gt;</description>
    </item>
    <item>
      <title>MoE Internals: DeepSpeed-Megatron Expert Parallel Implementation</title>
      <link>https://duoan.github.io/posts/moe-deepspeed-megatron-internals/</link>
      <pubDate>Sat, 17 May 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/moe-deepspeed-megatron-internals/</guid>
      <description>&lt;h1 id=&#34;moe-internals-deepspeed-megatron-expert-parallel-implementation&#34;&gt;MoE Internals: DeepSpeed-Megatron Expert Parallel Implementation&lt;/h1&gt;
&lt;p&gt;DeepSpeed-Megatron MoE is easy to misread if you only inspect one initialization function. Megatron builds the usual TP, PP, and DP topology. DeepSpeed then wraps the model, finds MoE modules, and gives those modules expert-parallel groups. The topology is split across the training framework and the MoE layer implementation.&lt;/p&gt;
&lt;p&gt;This post connects the pieces: &lt;code&gt;deepspeed.initialize()&lt;/code&gt;, EP groups, expert-DP groups, &lt;code&gt;MoELayer&lt;/code&gt;, and the difference between a DeepSpeed MoE wrapper and a Megatron-integrated SwitchMLP-style module.
For routing, capacity, and All-to-All fundamentals, start with &lt;a href=&#34;../moe-expert-parallelism-principles/&#34;&gt;MoE Parallelism Principles&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sequence Parallelism I: Megatron SP Cuts Activation Memory Along the Sequence</title>
      <link>https://duoan.github.io/posts/sequence-parallelism-megatron-sp/</link>
      <pubDate>Mon, 12 May 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/sequence-parallelism-megatron-sp/</guid>
      <description>&lt;h1 id=&#34;sequence-parallelism-i-megatron-sp-cuts-activation-memory-along-the-sequence&#34;&gt;Sequence Parallelism I: Megatron SP Cuts Activation Memory Along the Sequence&lt;/h1&gt;
&lt;p&gt;Tensor parallelism is usually introduced as a way to make matrix multiplications fit.
That is true, but it hides a second problem.
After the weights are split, many activations are still replicated on every tensor-parallel rank.
For short contexts this is tolerable.
For long contexts it becomes one of the reasons training throughput collapses into activation checkpointing.&lt;/p&gt;
&lt;p&gt;Megatron sequence parallelism, usually shortened to Megatron SP, is a targeted fix from &lt;em&gt;Reducing Activation Recomputation in Large Transformer Models&lt;/em&gt; (&lt;a href=&#34;https://arxiv.org/abs/2205.05198&#34;&gt;arXiv:2205.05198&lt;/a&gt;).
It does not replace tensor parallelism.
It keeps Megatron&amp;rsquo;s column-parallel and row-parallel linear layers, then shards the sequence-local regions that tensor parallelism had left replicated.
The trick is small enough to miss and important enough to change the memory budget of a whole Transformer block.&lt;/p&gt;</description>
    </item>
    <item>
      <title>MoE Parallelism Principles: GShard, Expert Parallel, and All-to-All</title>
      <link>https://duoan.github.io/posts/moe-expert-parallelism-principles/</link>
      <pubDate>Sat, 10 May 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/moe-expert-parallelism-principles/</guid>
      <description>&lt;h1 id=&#34;moe-parallelism-principles-gshard-expert-parallel-and-all-to-all&#34;&gt;MoE Parallelism Principles: GShard, Expert Parallel, and All-to-All&lt;/h1&gt;
&lt;p&gt;Mixture-of-Experts is sparse compute wrapped in a communication problem. The model idea is simple: replace a dense FFN with many expert FFNs and route each token to a few of them. The distributed-training problem starts when those experts live on different GPUs.&lt;/p&gt;
&lt;p&gt;Shazeer et al. introduced the sparsely-gated MoE layer in &lt;a href=&#34;https://arxiv.org/abs/1701.06538&#34;&gt;Outrageously Large Neural Networks&lt;/a&gt;.
GShard made the pattern practical at scale with top-2 routing, capacity, load-balancing loss, and all-to-all dispatch in &lt;a href=&#34;https://arxiv.org/abs/2006.16668&#34;&gt;GShard&lt;/a&gt;.
Switch simplified the router to top-1 in &lt;a href=&#34;https://arxiv.org/abs/2101.03961&#34;&gt;Switch Transformers&lt;/a&gt;.
This post explains the shared systems model underneath them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ZeRO: Partitioning Optimizer State, Gradients, and Parameters</title>
      <link>https://duoan.github.io/posts/zero-redundancy-optimizer/</link>
      <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/zero-redundancy-optimizer/</guid>
      <description>&lt;h1 id=&#34;zero-partitioning-optimizer-state-gradients-and-parameters&#34;&gt;ZeRO: Partitioning Optimizer State, Gradients, and Parameters&lt;/h1&gt;
&lt;p&gt;Plain DDP is clean but wasteful. Every data-parallel rank stores the same parameters, gradients, fp32 master weights, and optimizer moments. At small scale that redundancy is convenient. At LLM scale it is the memory wall.&lt;/p&gt;
&lt;p&gt;ZeRO, the Zero Redundancy Optimizer, keeps data-parallel semantics and removes the redundant storage one category at a time. ZeRO-1 shards optimizer state. ZeRO-2 shards optimizer state and gradients. ZeRO-3 shards optimizer state, gradients, and parameters (&lt;a href=&#34;https://arxiv.org/abs/1910.02054&#34;&gt;arXiv:1910.02054&lt;/a&gt;).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Megatron Internals III: Mixed Precision, Loss Scaling, and Grad Clipping</title>
      <link>https://duoan.github.io/posts/megatron-mixed-precision-training/</link>
      <pubDate>Sat, 26 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/megatron-mixed-precision-training/</guid>
      <description>&lt;h1 id=&#34;megatron-internals-iii-mixed-precision-loss-scaling-and-grad-clipping&#34;&gt;Megatron Internals III: Mixed Precision, Loss Scaling, and Grad Clipping&lt;/h1&gt;
&lt;p&gt;Mixed precision training is not just &amp;ldquo;turn on fp16.&amp;rdquo; It is a state machine: fast low-precision tensors do forward and backward, stable fp32 tensors receive optimizer updates, and every rank agrees whether the step is valid before any shard changes.&lt;/p&gt;
&lt;p&gt;The classic recipe comes from Micikevicius et al., &lt;a href=&#34;https://arxiv.org/abs/1710.03740&#34;&gt;Mixed Precision Training&lt;/a&gt;: use lower precision where hardware is fast, keep fp32 master weights for updates, and use loss scaling when fp16 gradients underflow.
Megatron wraps that recipe around tensor, pipeline, and data parallelism.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Megatron Internals II: Column/Row Parallel Linear and Vocab Parallel Embedding</title>
      <link>https://duoan.github.io/posts/megatron-model-parallel-internals/</link>
      <pubDate>Sat, 19 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/megatron-model-parallel-internals/</guid>
      <description>&lt;h1 id=&#34;megatron-internals-ii-columnrow-parallel-linear-and-vocab-parallel-embedding&#34;&gt;Megatron Internals II: Column/Row Parallel Linear and Vocab Parallel Embedding&lt;/h1&gt;
&lt;p&gt;Tensor parallelism is not &amp;ldquo;split every tensor somehow.&amp;rdquo; In Megatron, it is a small set of layer contracts: which dimension is local, which collective completes the dense math, and which gradient path communicates.&lt;/p&gt;
&lt;p&gt;The original &lt;a href=&#34;https://arxiv.org/abs/1909.08053&#34;&gt;Megatron-LM paper&lt;/a&gt; is still the cleanest starting point: split transformer matrix multiplies so each GPU does useful dense GEMM, then communicate only where the algebra requires it.
This post walks the implementation-level contracts behind &lt;code&gt;ColumnParallelLinear&lt;/code&gt;, &lt;code&gt;RowParallelLinear&lt;/code&gt;, &lt;code&gt;VocabParallelEmbedding&lt;/code&gt;, and parallel cross entropy.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Megatron Internals I: Building the DP / TP / PP Process Groups</title>
      <link>https://duoan.github.io/posts/megatron-distributed-init/</link>
      <pubDate>Sat, 12 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/megatron-distributed-init/</guid>
      <description>&lt;h1 id=&#34;megatron-internals-i-building-the-dp--tp--pp-process-groups&#34;&gt;Megatron Internals I: Building the DP / TP / PP Process Groups&lt;/h1&gt;
&lt;p&gt;Megatron-LM&amp;rsquo;s first trick is not tensor-parallel matmul.
It is rank bookkeeping.
Before the model runs, every process must know the small set of peers it will communicate with for tensor parallelism, pipeline parallelism, data parallelism, embeddings, and optimizer state.&lt;/p&gt;
&lt;p&gt;The original &lt;a href=&#34;https://arxiv.org/abs/1909.08053&#34;&gt;Megatron-LM paper&lt;/a&gt; introduced intra-layer tensor parallelism for transformer training.
The later &lt;a href=&#34;https://arxiv.org/abs/2104.04473&#34;&gt;Megatron-LM scaling paper&lt;/a&gt; put tensor parallelism, pipeline parallelism, and data parallelism into one training system.
This post is the control plane underneath that system: how a flat list of ranks becomes a DP / PP / TP mesh.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Data Parallelism: From Parameter Server to Ring All-Reduce</title>
      <link>https://duoan.github.io/posts/data-parallelism-ddp-ring-allreduce/</link>
      <pubDate>Sun, 06 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/data-parallelism-ddp-ring-allreduce/</guid>
      <description>&lt;h1 id=&#34;data-parallelism-from-parameter-server-to-ring-all-reduce&#34;&gt;Data Parallelism: From Parameter Server to Ring All-Reduce&lt;/h1&gt;
&lt;p&gt;Data parallelism is the default scaling move because it preserves the model program. Every rank owns the same model, sees different examples, computes gradients, and applies the same update.&lt;/p&gt;
&lt;p&gt;The algorithm is simple. The system is not. The whole post is about removing one bottleneck: do not push all gradient traffic through one server when every GPU could be moving bytes at the same time.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Pipeline Parallelism from First Principles: Why GPipe Split the Batch</title>
      <link>https://duoan.github.io/posts/pipeline-parallelism-gpipe/</link>
      <pubDate>Sun, 16 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/pipeline-parallelism-gpipe/</guid>
      <description>&lt;h1 id=&#34;pipeline-parallelism-from-first-principles-why-gpipe-split-the-batch&#34;&gt;Pipeline Parallelism from First Principles: Why GPipe Split the Batch&lt;/h1&gt;
&lt;p&gt;Pipeline parallelism starts with a useful accident: a Transformer is already a chain. If one GPU cannot hold the whole stack, put consecutive blocks on consecutive GPUs and send activations across stage boundaries.&lt;/p&gt;
&lt;p&gt;That solves capacity. It does not solve throughput. A naive layer split turns an expensive cluster into a queue where most devices wait. GPipe&amp;rsquo;s contribution was to make the queue busy by slicing the mini-batch into micro-batches and recomputing activations instead of storing everything (&lt;a href=&#34;https://arxiv.org/abs/1811.06965&#34;&gt;arXiv:1811.06965&lt;/a&gt;).&lt;/p&gt;</description>
    </item>
    <item>
      <title>LLM Training Series: A Systems Map for Distributed Transformers</title>
      <link>https://duoan.github.io/posts/llm-training-series/</link>
      <pubDate>Sun, 02 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://duoan.github.io/posts/llm-training-series/</guid>
      <description>&lt;h1 id=&#34;llm-training-series-a-systems-map-for-distributed-transformers&#34;&gt;LLM Training Series: A Systems Map for Distributed Transformers&lt;/h1&gt;
&lt;p&gt;LLM training stops being &amp;ldquo;run the model on more GPUs&amp;rdquo; the moment one replica no longer fits, one link becomes the step time, or one schedule leaves half the cluster idle. From that point on, the training run is a placement problem.&lt;/p&gt;
&lt;p&gt;The stable question is simple: &lt;strong&gt;which bytes are replicated, which bytes are sharded, and which link moves them on the critical path?&lt;/strong&gt; Data parallelism, tensor parallelism, pipeline parallelism, ZeRO, sequence/context parallelism, and expert parallelism are different answers to that question. The public systems that matter - GPipe, Megatron-LM, DeepSpeed ZeRO, PyTorch DDP, GShard, Switch Transformer, and modern Megatron-Core - all expose the same constraints in different shapes (&lt;a href=&#34;https://arxiv.org/abs/1811.06965&#34;&gt;GPipe&lt;/a&gt;, &lt;a href=&#34;https://arxiv.org/abs/1909.08053&#34;&gt;Megatron-LM&lt;/a&gt;, &lt;a href=&#34;https://arxiv.org/abs/1910.02054&#34;&gt;ZeRO&lt;/a&gt;, &lt;a href=&#34;https://arxiv.org/abs/2006.15704&#34;&gt;PyTorch Distributed&lt;/a&gt;, &lt;a href=&#34;https://arxiv.org/abs/2006.16668&#34;&gt;GShard&lt;/a&gt;, &lt;a href=&#34;https://arxiv.org/abs/2101.03961&#34;&gt;Switch Transformer&lt;/a&gt;).&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
