Skip to content

feat(ffn): add deterministic distributed Triton FFN for ROCm - #325

Open
frank-2077 wants to merge 21 commits into
RL-Align:codex/ws2-rocm-strict-attentionfrom
frank-2077:feat/rocm-strict-ffn
Open

feat(ffn): add deterministic distributed Triton FFN for ROCm#325
frank-2077 wants to merge 21 commits into
RL-Align:codex/ws2-rocm-strict-attentionfrom
frank-2077:feat/rocm-strict-ffn

Conversation

@frank-2077

@frank-2077 frank-2077 commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds a ROCm-native deterministic distributed Qwen3 FFN implemented in
Triton. It supports FFN forward/backward across tensor parallelism (TP), context
parallelism (CP), and sequence parallelism (SP), with fixed-order RCCL tensor
transport.

Note

Validation is operator-only. It uses seeded tensors and does not load or
benchmark a model, checkpoint, tokenizer, dataset, or serving engine.

Comparison contract

The three experiments are intentionally independent:

Question Baseline Metric
Does distributed execution preserve determinism? This PR's deterministic Triton FFN at TP=1 Element mismatch count for forward output, training output, dHidden, and dWeights; acceptance is 0
What is the deterministic performance cost? Official Hugging Face Transformers Qwen3MLP at TP=1 Median FFN latency only; no accuracy comparison is mixed into the speed result
What is the simple FP16 precision observation? Official Qwen3MLP at TP=1 in FP32 FP16 output relative-L2, max-absolute, and mean-absolute error

Native ROCm/RCCL is not used as a numerical-accuracy reference in this report.

Design

  • Implement the bias-free gated Qwen3 FFN directly with ROCm-native Triton
    kernels; there is no CUDA-generated HIP source in this PR.
  • Use a canonical FP32-leaf/BF16-node midpoint reduction tree in deterministic
    GEMM and preserve BF16 stage boundaries in forward and backward.
  • Make each contiguous TP K shard the same subtree used by TP=1.
  • Use RCCL for fixed rank-order tensor transport, followed by a fixed balanced
    BF16 rank reduction tree.
  • Gather complete CP token sequences before weight-gradient GEMMs so their K
    tree matches CP=1.
  • Support TP all-reduce, SP all-gather/reduce-scatter, CP all-gather, and all
    corresponding backward paths.

Operator test matrix

Weights use Hugging Face [out, in] layout. No model-level benchmark and no
separate gate/up/down projection benchmark is included.

Experiment Shape / dtype Parallel configurations
Single-GPU FFN speed (M,H,I)=(1/8/32,4096,12288), BF16 Triton TP1 vs official Qwen3MLP TP1; forward and forward+backward
Distributed FFN speed (M,H,I)=(32,4096,12288), BF16 TP2, TP2+SP, TP4, TP2+CP2, TP2+CP2+SP, TP8, TP4+CP2, TP4+CP2+SP; every row vs official TP1
Distributed exactness Same full logical input and weights, BF16 Every TP/CP/SP layout vs deterministic Triton TP1 exact slices
FP16/FP32 observation (M,H,I)=(8,4096,12288) Official Qwen3MLP TP1 FP16 vs the same operator in FP32

ROCm environment

Item Value
GPU 8 × AMD Instinct MI300X
Architecture gfx942
PyTorch 2.12.0+rocm7.14.0a20260608
ROCm runtime 7.14.60850
Transformers 5.10.4
Benchmark implementation commit 08f47d97d0443c5998b8da6b41a22fdf3848da8f
Result and figure commit e64abab

Correctness results

Validation Result
Single-GPU FFN plus real RCCL TP/CP/SP topology suite 17 passed
Formal TP/CP/SP forward output vs Triton TP1 0 mismatch
Formal TP/CP/SP training output vs Triton TP1 0 mismatch
Formal TP/CP/SP dHidden vs Triton TP1 0 mismatch
Formal TP/CP/SP sharded dWeights vs Triton TP1 0 mismatch
Repeated execution and training/inference forward 0 mismatch

Commands used:

NCCL_IB_DISABLE=1 pytest -q \
  tests/test_qwen_ffn.py \
  tests/distributed/test_qwen_ffn_topology.py

NCCL_IB_DISABLE=1 python benchmarks/benchmark_rocm_ffn.py \
  --warmup 3 \
  --samples 10 \
  --training-samples 5 \
  --output-dir benchmarks/results/pr325_rocm_mi300x

Performance results

All speed numbers compare complete FFN calls. The official baseline is upstream
Transformers Qwen3MLP with unsharded weights and input at TP=1. Distributed
timing uses synchronized wall time and the slowest rank per sample. These rows
compare speed only.

Scope Deterministic Triton / official Qwen3MLP TP1 median latency
Single GPU, forward, M=1/8/32 9.03-22.86x
Single GPU, forward+backward, M=1/8/32 7.38-11.56x
Distributed, forward, eight TP/CP/SP layouts 8.76-15.79x
Distributed, forward+backward, eight TP/CP/SP layouts 7.45-14.06x

The separate dtype observation runs only official Qwen3MLP TP1:

Candidate Reference Relative L2 Max abs Mean abs
FP16 FP32 6.544e-4 (0.06544%) 2.046e-6 3.742e-7

Full combined report ·
Raw JSON

Single-GPU official TP1 versus Triton speed

Topology mismatch versus Triton TP1

Distributed official TP1 versus Triton speed

Communication overlap assessment

The reported implementation serializes dependencies; the measurements do not
claim communication/computation overlap.

  • Forward SP all-gather must complete before gate/up computation, and the final
    TP reduction consumes the down-projection output. These are hard dependencies.
  • In backward, the gate and up contributions to dHidden are independent until
    their final ordered addition. A future implementation can reduce one on a
    second stream while computing the other.
  • That optimization must preserve rank order, the reduction tree, wait points,
    BF16 stage boundaries, and gate-then-up addition order. It is accepted only if
    every TP1 mismatch column remains zero.

Communication implementation provenance

The ROCm deterministic communication operator used by this PR is adopted from PR #357. The current path uses the optimized HIP IPC fixed-tree implementation with RCCL fallback, including the packed reduce_scatter_many path for the independent sequence-parallel FFN backward lanes.

The checked benchmark report records this implementation provenance and keeps the main performance figure as a four-way same-topology comparison without adding a PR-specific series.

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 55fdfad2-b558-497e-9970-7c0456410f6a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@Flink-ddd
Flink-ddd changed the base branch from codex/ws2-rocm-strict-attention to main August 21, 2026 15:37
@frank-2077
frank-2077 changed the base branch from main to codex/ws2-rocm-strict-attention August 21, 2026 15:40
@frank-2077 frank-2077 changed the title feat(ffn): add deterministic ROCm Qwen3 FFN path feat(ffn): add deterministic distributed Triton FFN for ROCm Aug 23, 2026
@frank-2077 frank-2077 added the platform: rocm Specific tasks specific to AMD graphics cards (such as CK, bpreshuffle/FA) label Aug 27, 2026
zhangj1an added a commit that referenced this pull request Aug 29, 2026
Applies the PR #325 / #328 measurement matrix and presentation to the strict ROCm
Attention path: their timing and accuracy helpers, their spawned distributed world,
and their figure style, so the three reports read side by side. Operator-only, no
checkpoint; Qwen3-8B shapes (Hq=32, Hkv=8, D=128).

Headline: the Triton core is bit-identical to _C.deterministic_attention_* on all
eight (dtype, sequence) cases -- out, lse, dQ, dK and dV, zero mismatched elements.

TP-degree invariance reproduces PR #319 on independent inputs and shows why the
per-KV-group launch schedule is load-bearing. Raw AITER is non-invariant at 5 of 12
(S, TP) points, up to 7.8e-03 out max-abs, and which points fail is shape-dependent:
S=512 and S=4096/TP=2 both look clean. The per-KV-group schedule is bitwise at 12/12.

Distributed CP runs the real AG/RS schedule -- all-gather Q/K/V and position ids,
strict core on the full sequence, reduce-scatter (out, lse) -- and is bitwise against
CP=1 on all six topologies including the 8-rank TP=2/CP=2 x2-replica case.

Three things the numbers say that were not obvious:
- the strict production core is faster than SDPA at S=4096 forward (0.81x), so the
  bitwise arrangements cost almost nothing on the production path;
- AITER's backward peaks at 16.6 GiB at S=4096, 4x the materializing reference core;
- both deterministic cores are closer to an FP64 oracle than SDPA or AITER.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01824WkgMDxtBKD4Ex2NkfYA
zhangj1an added a commit that referenced this pull request Aug 29, 2026
Three gaps, all found by comparing against what PR #325 actually plots and by
walking the code paths an H100 run would take.

Charts. PR #325's most distinctive figure is a mismatch heatmap (topology x tensor
category, annotated, RdYlGn), and we had no equivalent even though the data was
already collected. exactness_matrix.png adds it: Triton-vs-reference on the left,
CP-topology-vs-CP=1 on the right. Cells that were never measured (fp16 gradients)
render as "n/m" on grey rather than 0, which would read as measured-and-equal. The
distributed chart also had no baseline, so it could not show what the transport
costs; it is now grouped bars against CP=1, which puts AG/RS at 2.2-3.3x.

Host support. Timing falls back to wall clock and peak memory to an RSS high-water
delta from /proc when there is no device, and NativeAttentionOp joins as
pytorch-native -- the one non-SDPA path that also runs on the host. --device
selects, and the GPU-only sections are skipped rather than failed.

CUDA support, which the H100 run would otherwise have hit head-on. AITER does not
exist there, so strict-fa4 (StrictFlashAttention4Core) is the production core on
CUDA; TritonDeterministicAttentionOp raises on CUDA by design, so it is now built
with require_bitwise_libm=BITWISE_LIBM_PARITY and measured without claiming parity;
and the distributed case had StrictRocmAiterCKAttentionCore and the RCCL transport
hard-coded, which would have failed every CP topology on an H100 -- it now dispatches
on torch.version.hip. reference-hip is renamed reference-native, since on CUDA that
same .cu is not a HIP build.

--compare-with LABEL=PATH merges another platform's results.json into the report, so
mi300x, cpu and h100 runs land in one table with a Platform column; a missing row
means the backend cannot exist there, not that it failed.

Verified on ROCm after the refactor: all six CP topologies still bitwise against
CP=1 with transport reported as rccl_ag_rs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01824WkgMDxtBKD4Ex2NkfYA
Port the HIP IPC fixed-tree transport and packed reduce-scatter path from PR RL-Align#357, with RCCL fallback and focused ROCm coverage.
Record the PR RL-Align#357 collective measurements, preserve the four-way same-topology comparison, and publish the refreshed MI300X artifacts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform: rocm Specific tasks specific to AMD graphics cards (such as CK, bpreshuffle/FA)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant