Where an optical transform engine would sit in a data-, tensor- and pipeline-parallel training cluster, what a mask rewritten every optimizer step costs against the digital step time, why layer-major scheduling fights pipelines and activation memory, the static Amdahl bound at cluster scale, why the optimizer's frequency transforms (DeMo) are worth bytes on the link rather than FLOPs, and what a measured experiment and simulation say about computing a fixed frequency band in transit, within and across data centres.
Concepts used here, and where they are explained. Each links to a glossary entry: this series glossary, or the Fourier Optics for Inference glossary for the physics and the inference concepts it already explains.
Deck 01 counted the transform work in a training step; deck 02 looked at how optics trains itself. This deck asks the systems question: if every accelerator in a training cluster had a Fourier-optical transform engine beside it (FOptInf 01 for the physics), what would a training step look like, and would it be shorter?
Short answer: at today's mask rates the engine lengthens the step rather than shortening it, and the frequency transform that genuinely helps a training cluster (DeMo's DCT of the momentum) is worth link bytes, not FLOPs. All numbers come from results.md, written by analysis/train_flop_share.py; the step size (1,048,576 tokens), the cluster (64 GPUs at 400 TFLOP/s sustained) and the device (2-megapixel DMD at 1,031 Hz) are illustrative.
One optimizer step processes a global batch (here 1,048,576 tokens) and ends with a single weight update. Four phases, of which only the first two contain transforms:
| Phase | What it does | What it costs | Transform work? |
|---|---|---|---|
| Forward | Every layer on every sequence; activations kept (or checkpointed) for the backward | About 2 FLOPs per parameter per token | Long convolutions: FFT, times H, IFFT |
| Backward | Activation gradients (dX) and weight gradients (dW), layer by layer in reverse | About twice the forward: the 6N rule | FFT of G; dU = IFFT(G·conj(H)); dH += G·conj(U) |
| Gradient sync | Data-parallel replicas sum their gradients: an all-reduce, or a reduce-scatter and all-gather when optimizer state is sharded (ZeRO, Rajbhandari et al., arXiv:1910.02054) | Bytes on the network, proportional to the parameters | None, unless the gradients are compressed (slide 11) |
| Optimizer | AdamW's element-wise update of weights and moments | Memory-bound element-wise work (not counted) | None for AdamW; small DCTs for DeMo |
The FLOP ledger is checked against the 6N rule: for the transformer variant it gives 46.64 GFLOP per token at 2,048 tokens and 70.80 at 32,768, a ratio of 1.0000 to 6N plus the attention term (results.md §1).
The weights change at the end of every step. An inference engine's Fourier-plane masks hold the same filter spectra for the life of a deployment; a training engine's masks are stale after each update and must be written again before the next step's forward pass.
Suppose each accelerator has a transform engine beside it that takes the FFTs and weight-masked products of the layers that accelerator owns. What each engine's mask must hold depends on how the model is split:
| Parallelism | What it splits | Each engine's mask holds |
|---|---|---|
| Data | The batch, across replicas | The whole model's spectra, in every replica: mask writes are replicated, not divided |
| Tensor (Megatron-LM, Shoeybi et al., arXiv:1909.08053) | Each layer's matrices across GPUs | A slice of each layer; Hyena's per-channel long convolutions split by channel with no extra communication |
| Pipeline | Layers into stages | Only its stage's layers |
| Sequence / context | The sequence dimension | A long convolution needs the whole sequence: splitting it turns one FFT into a distributed FFT with an all-to-all |
Megatron's own sequence parallelism splits only the norm and dropout regions along the sequence (Korthikanti et al., arXiv:2205.05198), which a long convolution would tolerate; splitting the convolution itself would not suit an engine that transforms whole rows at once.
A 2-megapixel mask holds a small fraction of the model's filter spectra (FOptInf 02, “Fourier-Plane Mask Capacity”), so an engine cycles through frames as it walks the layers. In inference that cycle serves each batch with fixed weights. In training the weights are new every step, and the backward pass needs them again:
| Variant | Sequence | Sequences / step | Digital step time | Weight-mask frames (fwd + bwd) | Time |
|---|---|---|---|---|---|
| Hyena-2 | 2,048 | 512 | 2.05 s | 538 | 0.52 s |
| Hyena-2 | 8,192 | 128 | 2.05 s | 2,148 | 2.08 s |
| Hyena-2 + block-circulant weights | 2,048 | 512 | 0.15 s | 554 | 0.54 s |
| Hyena-2 + block-circulant weights | 8,192 | 128 | 0.15 s | 2,164 | 2.10 s |
Source: results.md, section “4. Holding the masks”. Illustrative: 2-megapixel DMD at 1,031 Hz, one complex value per pixel (optimistic); 64 GPUs at 400 TFLOP/s; layer-major order.
Per-token step FLOPs and static shares are embedded from results.json for the four sequence lengths the analysis covers; mask values use the same formula as its mask_budget(). At the defaults the explorer reproduces the slide 04 table.
The model, stated plainly. Digital step = per-token step FLOPs × tokens ÷ (GPUs × TFLOP/s), with GPU time proportional to FLOPs (FFTs at the matmul rate). Removable = static share × step: the engine does the static work in zero time. Each engine holds the masks of 1/k of the model (k = tensor × pipeline degree) and writes them twice per pass (forward and backward): 2 × ⌈values ÷ (k × pixels)⌉ frames. Layer-major makes one pass per step; sequence-major makes one per microbatch of m sequences on each of the GPUs ÷ k replicas. Not overlapped (conservative): step − removable + mask time. Fully overlapped: the larger of (step − removable) and mask time. Per-token FLOPs and shares are those at 1,048,576 tokens, held fixed for other step sizes (an approximation: the once-per-step filter transforms shift them slightly at long sequences). The data-by-data figure is what writing the weight gradient's conj(U) masks would cost, spread evenly over all engines.
Layer-major order passes every sequence of the step through one layer, with that layer's spectra on the mask, before moving on: one write per layer per direction per step. It is the order the slide 04 numbers assume, and the opposite of how large models are trained.
| Schedule | Mask passes per step, per engine | Activations held |
|---|---|---|
| Layer-major, whole step | 1 (forward) + 1 (backward) | The whole step's |
| GPipe, m microbatches | m forward + m backward | All m microbatches per stage (less with recomputation) |
| 1F1B, m microbatches | m forward + m backward, interleaved: the mask flips between H and conj H every microbatch | About p microbatches per stage |
Pipeline parallelism does help in one way: a stage's engine holds only its stage's layers, so each pass has fewer frames (the model-parallel degree in the explorer). It does not help enough: for Hyena-2 at 2,048 tokens even one of 32 stages has more spectra than a 2-megapixel mask holds, so each microbatch still costs frames.
Gradient accumulation already splits an optimizer step into rounds whose gradients are summed before one update. Run each round layer-major over its sequences and the trade is explicit:
A GPU reads each layer's weights from HBM as it needs them and can switch layers between kernels. The mask is a weight store that changes only 1,031 times a second on the illustrative device, which is why scheduling, not FLOPs, decides this engine's fate in training.
The filter gradient dH = IFFT(Σ G·conj(U)) multiplies two spectra that both depend on the sequence (the gradient of a convolution is a correlation). With block-circulant weights the weight gradient conj(X)·G depends on every token. Either way, a mask would carry data, and would be new for every sequence or token:
| Variant | Sequence | Data-by-data frames per step | Time (one device) | Data-by-data part of optical work |
|---|---|---|---|---|
| Hyena-2 | 2,048 | 137,507 | 133 s | 2.32% |
| Hyena-2 | 8,192 | 137,456 | 133 s | 2.01% |
| Hyena-2 + block-circulant weights | 2,048 | 397,218 | 385 s | 20.98% |
| Hyena-2 + block-circulant weights | 8,192 | 397,168 | 385 s | 20.49% |
Source: results.md, sections 2 and 4 (illustrative device as before).
Static share = FFTs plus the weight-masked products, over all step FLOPs: what an engine with once-per-step masks could take (glossary). If that work became free, the step would be at most 1/(1−share) faster.
| Variant | Sequence | Fwd share | Step share | Static share | Amdahl (static) |
|---|---|---|---|---|---|
| Transformer (Llama-3-8B) | any | 0.00% | 0.00% | 0.00% | 1.000x |
| Hyena-2 | 2,048 | 0.20% | 0.14% | 0.13% | 1.001x |
| Hyena-2 | 32,768 | 0.27% | 0.18% | 0.18% | 1.002x |
| Hybrid 1:3 attention:Hyena | 2,048 | 0.15% | 0.10% | 0.10% | 1.001x |
| Hybrid 1:3 attention:Hyena | 32,768 | 0.18% | 0.12% | 0.12% | 1.001x |
| Hyena-2 + block-circulant weights | 2,048 | 13.99% | 12.06% | 9.53% | 1.105x |
| Hyena-2 + block-circulant weights | 32,768 | 14.75% | 12.59% | 10.07% | 1.112x |
Source: results.md, section “2. A training step”
A bound of 1.105–1.112x is not nothing at cluster scale: it is roughly a tenth of a training run's GPU-hours, which for a large run is a large bill. That is the case for writing it down. The case against is everything the bound leaves out:
At most a tenth of the GPU time, for the most transform-heavy and least established model, against an extra optical subsystem on every accelerator. The same tenth could be bought by adding about a tenth more GPUs, with no new model architecture, no mask schedule and no analogue precision budget.
AdamW's update is element-wise and memory-bound: no transforms. One recent optimizer does use them. DeMo (Peng, Quesnelle, Kingma, “DeMo: Decoupled Momentum Optimization”, arXiv:2411.19870, 2024) lets each worker keep its own momentum, takes a DCT of it in small chunks, sends only the largest coefficients (top-k) to the other workers, and removes what it sent from its local momentum. The slow components stay local, decoupled from the exchange.
| Parameters | DeMo transform FLOPs per step | Step FLOPs (transformer, 4,096) | Share |
|---|---|---|---|
| 8,029,995,008 | 2.409e+11 | 5.059e+16 | 4.76e-06 |
Source: results.md, section “3. The optimizer step and DeMo”: a DCT and an inverse DCT per chunk of 64, at the real-FFT cost.
DeMo as measured. The Compute in Transit experiment (CiT 04) ran it on a 15.8M-parameter GPT (8 layers, width 384, context 256) on TinyStories, with 8 simulated workers of 8 sequences each per step for 3,000 steps. Its mechanics, step by step:
Payload is not wire bytes. A ring all-reduce of B bytes sends 2(N−1)/N·B per worker, whatever N is; DeMo's workers pick different coefficients, so they all-gather instead, and a ring all-gather of P bytes per worker sends (N−1)·P, which grows with N. On 8 workers, per worker per step (BF16 values):
| Configuration | Collective | Payload (bytes) | vs dense | Wire (bytes) | vs dense |
|---|---|---|---|---|---|
| A AdamW | all-reduce | 31,666,944 | 1.0x | 55,417,152 | 1.0x |
| B DeMo, top-k | all-gather | 3,957,960 | 8.0x | 27,705,720 | 2.0x |
| C DeMo, fixed band (slide 12) | all-gather | 1,979,184 | 16.0x | 13,854,288 | 4.0x |
Source: the experiment's results.md, section 1 (results site, “What each worker sends”). Top-k's payload counts each index at the bytes a position within a chunk needs; the reference code sends int64 indices, 9,895,920 bytes per step, 2.5x the compact count.
Gradient compression is an established line of work: sparsification (Deep Gradient Compression, Lin et al., arXiv:1712.01887), low-rank updates (PowerSGD, Vogels et al., arXiv:1905.13727) and DeMo's DCT. All of them compress at the worker. Could the transform run in the link's data path instead, on bytes that have to move anyway?
Why a fixed band. A photonic link module (Kundu et al., arXiv:2608.21536) can run the transform but not the comparisons top-k needs to find the largest coefficients. A fixed band, the same 1/16 of positions in every chunk every step, needs no comparisons, sends no indices (16x smaller payload, against top-k's 8x), and puts every worker's values at the same positions. The Compute in Transit experiment measured what that substitution costs, on the same 15.8M-parameter model:
| Configuration | Seeds | Final validation loss | Steps to 3.158 |
|---|---|---|---|
| A AdamW | 3 | 1.646 ± 0.005 | 400 |
| B DeMo, top-k, 2-D 64×64 | 3 | 1.785 ± 0.007 | 400 |
| C fixed low band, 1-D 256-point | 3 | 3.124 ± 0.008 | 2,667 |
| C fixed low band, 1-D 64-point | 1 | 3.137 | 2,800 |
| C fixed low band, 2-D 64×64 | 3 | 3.158 ± 0.009 | not every seed |
| D calibrated band, 2-D 64×64 | 3 | 3.087 ± 0.027 | 2,533 |
| F fixed zig-zag band, 2-D 64×64 | 1 | 3.028 | 2,200 |
| F fixed high band, 2-D 64×64 | 1 | 3.244 | not reached |
| F fixed random band, 2-D 64×64 | 1 | 2.700 | 1,200 |
Source: the experiment's results.md, section 1 and “Steps to reach a loss” (loss curves, steps ladder). Steps are the first evaluation (every 200 steps) at or below the target, the mean over seeds; 3.158 is the 2-D low band's own final loss.
Why it loses: captured energy. The share of a tensor's energy (its squared DCT coefficients) a selector keeps at the same k. On worker 0's momentum, averaged after step 200:
| Chunks | Top-k | Low band | Zig-zag | High band | Random |
|---|---|---|---|---|---|
| 2-D 64×64 | 0.643 | 0.013 | 0.022 | 0.063 | 0.065 |
| 1-D 256-point | 0.429 | 0.146 | 0.146 | 0.045 | 0.049 |
Source: the experiment's results.md, section 2, runs C, tensor “momentum”, group “all” (results site, “Why a fixed band loses”). A random set keeps about the keep fraction, 1/16.
A DCT is linear, so the sum of the workers' bands is the band of the summed delta: unlike top-k, a fixed band can be summed rather than gathered. That gives three places to compute it, beside the measured C (band on the GPU, all-gathered):
| Variant | Where the band is computed | Wire / step, 8 workers in one DC (bytes) | Status |
|---|---|---|---|
| C′ | On the GPU, then a ring all-reduce of the band (linear summing in the transform domain) | 3,463,572 | Hypothetical: not run |
| E | In each worker's pluggable link module, then all-gathered | 13,854,288 | Emulated optics, one seed per setting |
| E′ | At each data centre's switch, summed there (in-network aggregation); the dense delta goes up to the switch, only the band sum crosses the WAN | 31,666,944 | Hypothetical: not run |
Source: the simulation's results.md, section 1. C′ and E′ reuse C's and E's measured steps, because summing the band gives the same update as gathering it.
The emulated optics (E). The first design, with the input full scale fixed after calibration and error feedback that removed the exact band, diverged in all six runs (final losses 11.153 to 558.834): the optics' errors were never corrected and the sign update turned a repeated bias into full steps the wrong way. The fix was to feed back the band actually sent, which each sender sees in the all-gather. Repaired, 8 planes: ENOB 6 ends at 3.423, ENOB 8 at 3.017, ENOB 10 at 2.878; perfect optics at 3.141. The best is still 1.09 above top-k (results site, “ENOB and bit planes”). That the repaired optics needs fewer steps than the exact band (1,800 to 3.158 at ENOB 8, against 2,667) is a hypothesis from single seeds.
When it pays: break-even WAN bandwidth (2 data centres of 4 workers; time to 3.158; transform not charged to the module):
| Comparison | Faster below |
|---|---|
| E (pluggable, all-gather) against AdamW or top-k | Never, over 0.1–1,000 GB/s |
| E′ (switch) against AdamW, E's steps | 1.57 GB/s (12.5 Gb/s) |
| E′ against AdamW, the exact band's steps | 0.83 GB/s (6.64 Gb/s) |
| E′ against top-k, E's steps | 0.461 GB/s (3.69 Gb/s) |
| C′ (GPU all-reduce of the band) against AdamW | 6.58 GB/s (52.7 Gb/s) |
| C′ against top-k | 0.799 GB/s (6.39 Gb/s) |
| E′ against C′, both on the exact band's steps | Never in range |
Source: the simulation's results.md, sections 7a and 11 (results site, break-even; CiT 05).
C′ and E′ were never run; the module's coefficients are illustrative except its 9.7 W static power (Kundu et al.); the optics noise model is the series' own; everything rests on one 15.8M-parameter model and 8 workers. The photonics here is a link module computing a band on bytes in flight, not a Fourier engine computing beside the GPU, and the mapping is the Compute in Transit series' own, not any company's.
Saved bytes matter most where the link is slowest: data-parallel workers split across data centres, syncing over a WAN. The training-transit simulation takes the experiment's bytes and measured steps to a loss and asks how long, and how much energy, each way of syncing needs to reach 3.158. Background on where training's bytes go: CiT 02.
| Variant (2 DC × 4, 100 GbE) | Step (ms) | Steps to 3.158 | Time (s) | Energy (kJ) | Module share | Step, WAN load 0.9 (ms) |
|---|---|---|---|---|---|---|
| A AdamW, all-reduce | 4.075 | 400 | 1.63 | 1.95 | 0.0% | 26.291 |
| B DeMo top-k, all-gather | 2.315 | 400 | 0.93 | 1.38 | 0.0% | 12.929 |
| C band on the GPU, all-gather | 1.443 | 2,667 | 3.85 | 7.27 | 0.0% | 6.552 |
| C′ band on the GPU, all-reduce (hyp.) | 0.810 | 2,667 | 2.16 | 5.90 | 0.0% | 2.975 |
| E pluggable, all-gather [high] | 4.880 | 1,800 | 8.78 | 10.68 | 7.8% | – |
| E′ summed at the switch (hyp.) [free] | 3.726 | 1,800 | 6.71 | 8.87 | 7.2% | 5.442 |
Source: the simulation's results.md, sections 2, 5 and 9 (results site, explorer; shared WAN). [high]: module budget 99 GFLOP/s, transform charged; [free]: transform not charged. E's steps are the single-seed ENOB 8 run; the queueing column is the discrete-event engine's mean over 200 syncs, not run for E.
The experiment ran one model size and synced every step. Holding its steps to 3.158 fixed, the simulation gives (2 DC × 4, 100 GbE, seconds to 3.158):
| Variant | Sync every step | Every 10 (DiLoCo-style) | Every 100 (DiLoCo-style) | Llama-3-8B shape, every step |
|---|---|---|---|---|
| A AdamW | 1.63 | 0.34 | 0.21 | 806.45 |
| B DeMo top-k | 0.93 | 0.27 | 0.20 | 453.35 |
| C′ band, GPU all-reduce (hyp.) | 2.16 | 1.40 | 1.32 | 961.04 |
| E′ switch (hyp.) [free] | 6.71 | 1.47 | 0.94 | 3,345.04 |
Source: the simulation's results.md, section 10 (results site, extrapolations). Syncing every H steps assumes the steps to a loss are unchanged, which DiLoCo (Douillard et al., arXiv:2311.08455) does not promise, since it changes the optimizer too. The model-size row scales bytes and compute with the parameter count. Summary: “What the simulation says”.
Rarer syncs shrink the communication the band saves, and with it the band's only advantage: E′ is behind AdamW at every H. At the Llama-3-8B shape the order is unchanged: top-k first, the in-transit variants last, bound by the module.
| Work | Why a Fourier transform engine does not help |
|---|---|
| Dense matmuls and attention, forward and backward | Not transforms; the bulk of every step (slide 09) |
| Weight gradients in the Fourier domain | Data-by-data: a new mask per sequence or token (slide 08) |
| Gradient all-reduce, reduce-scatter, all-gather | Bytes, not FLOPs; photonic links move them but compute nothing |
| AdamW and other element-wise optimizers | Element-wise and memory-bound |
| DeMo's DCTs | 4.76e-06 of the step in 64-point transforms: too small (slide 11) |
| A fixed band in place of top-k, so a link module can compute it | Loses convergence: 3.124–3.158 final loss against 1.785 for top-k on the 15.8M-parameter model; at 2-D 64×64 it keeps 0.013 of the momentum's energy to top-k's 0.643 (slide 12) |
| The band in a pluggable link module | Never breaks even with AdamW or top-k over 0.1–1,000 GB/s of WAN; its compute budget is the bottleneck (slide 13) |
| The band summed at the switch | Pays only below a few GB/s of WAN (1.57 GB/s against AdamW, 0.461 against top-k, on single-seed steps), and a GPU all-reduce of the band (C′) does better with no module (slide 13) |
| Microbatched pipelines (GPipe, 1F1B) | A mask pass per microbatch; the mask flips between forward and backward spectra (slide 06) |
| Activation recomputation | Repeats the forward transforms and, usually, the mask pass |
| Long convolutions split by sequence parallelism | A distributed FFT with an all-to-all, not one optical pass |
| Gradient precision | FP8 E5M2 gradients need about 5.3–5.8 ENOB and BF16 about 10.3–10.7 (results.md §5; deck 02) |
And the costs that apply even where it maps: a mask rewritten every step, conversions per value, static power on every accelerator for the whole run, and one engine per data-parallel replica because the masks are replicated.
For this deck and for the series: