Skip to content

test: pin AdaLNContinuous scale/shift order and gradients (PRPUNDIT-17) - #1087

Closed
jiagaoxiang wants to merge 8 commits into
AMD-AGI:mainfrom
jiagaoxiang:testgap/PRPUNDIT-17
Closed

test: pin AdaLNContinuous scale/shift order and gradients (PRPUNDIT-17)#1087
jiagaoxiang wants to merge 8 commits into
AMD-AGI:mainfrom
jiagaoxiang:testgap/PRPUNDIT-17

Conversation

@jiagaoxiang

@jiagaoxiang jiagaoxiang commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

This PR was created by dougljia via Test Gap Resolver.

Summary

  • Extends tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py with CPU TestAdaLNContinuousForwardPlainOps: independent norm(x) * (1 + scale) + shift oracle, zero-modulation LayerNorm reduction, and NeMo chunk order (first half = scale, second half = shift).
  • Adds a fused-path CUDA check against the same formula, plus a backward-flow assertion on x and cond.
  • Existing CUDA shape / invalid-norm tests are unchanged.

Closes test gap PRPUNDIT-17.

Test plan

  • GPU CI: pytest tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py (plain-ops CPU class + fused CUDA class; needs megatron.core)
  • black --check / isort --profile black on the edited file

Closes PRPUNDIT-17. Plain-ops oracle plus fused-path CUDA check for
NeMo chunk order, plus a backward-flow assertion.
Copilot AI lite review requested due to automatic review settings September 3, 2026 16:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new fused CUDA coverage validates forward numerics but does not exercise the fused custom op’s backward path, leaving the “pin gradients” goal only partially covered.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds targeted unit tests to lock in AdaLNContinuous’s modulation semantics (scale/shift chunk order and the norm(x) * (1 + scale) + shift formula) and to expand coverage to a CPU “plain ops” execution path in the Flux/Megatron diffusion stack.

Changes:

  • Add a CUDA test asserting the fused AdaLNContinuous forward path matches the plain-ops formula (NeMo chunk order).
  • Add a new CPU-only test class that validates the plain-ops branch numerics (manual oracle, zero-modulation reduction to LayerNorm, chunk order).
  • Add a backward-flow assertion for gradients reaching both x and cond in the plain-ops branch.
File summaries
File Description
tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py Extends AdaLNContinuous unit tests with fused-forward formula checking and new CPU plain-ops correctness/gradient checks.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +153 to +161
torch.manual_seed(0)
x = torch.randn(ATTENTION_SEQ_LEN, BATCH_SIZE_QUAD, HIDDEN_DIM_FLUX).cuda()
cond = torch.randn(BATCH_SIZE_QUAD, HIDDEN_DIM_FLUX).cuda()

output = adaln(x, cond)
emb = adaln.adaLN_modulation(cond)
scale, shift = torch.chunk(emb, 2, dim=1)
expected = adaln.norm(x) * (1 + scale) + shift
assert torch.allclose(output, expected, atol=1e-5, rtol=1e-5)
Copilot review flagged that the fused-forward test only checked
forward numerics, leaving the "pin gradients" goal covered only by
the CPU plain-ops path (which doesn't exercise the
primus::fused_ln_modulate custom autograd op). Add a CUDA test that
runs backward() through the fused path and asserts finite, nonzero
gradients reach both x and cond, mirroring the existing CPU backward
test.
Copilot AI review requested due to automatic review settings September 3, 2026 17:58

@jiagaoxiang jiagaoxiang left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed the Copilot finding inline; see the thread reply for details.

emb = adaln.adaLN_modulation(cond)
scale, shift = torch.chunk(emb, 2, dim=1)
expected = adaln.norm(x) * (1 + scale) + shift
assert torch.allclose(output, expected, atol=1e-5, rtol=1e-5)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestIntel PR Steward: Good catch — taken. Added test_fused_forward_backward_reaches_input_and_conditioning to TestAdaLNContinuous (pushed in a4b9621), which runs .sum().backward() through the fused CUDA primus::fused_ln_modulate path and asserts finite, nonzero gradients reach both x and cond, mirroring the existing CPU plain-ops backward test.

@jiagaoxiang

Copy link
Copy Markdown
Collaborator Author

TestIntel PR Steward: Follow-up on this poll:

  1. Copilot review comment (fused-path gradients not covered): addressed. Pushed a4b9621, which adds TestAdaLNContinuous.test_fused_forward_backward_reaches_input_and_conditioning — a CUDA backward-flow assertion through the primus::fused_ln_modulate custom op, mirroring the existing CPU plain-ops backward test. Replied on the thread with details.

  2. build-docker (3.12) CI failure: not caused by this PR. The job builds the image fine and then fails at docker login -u tasimage -p ${{ secrets.PRIMUS_DOCKER_HUB_TOKEN }} with flag needs an argument: 'p' in -p — i.e. the secret resolves empty. This is expected behavior for pull_request runs triggered from a fork (GitHub doesn't expose repo secrets to fork PR workflows), and I see the same build-docker failure on every other open testgap/* PR right now, so this is a repo/workflow-level CI configuration issue, not something introduced by this test-only change. Rerunning won't help (it's not a flake — the secret will still be empty), and .github/workflows/ci.yaml is out of scope for a test PR, so I'm leaving it for a human to fix (e.g. skip the Docker Hub push step for fork-originated pull_request runs). Flagging so a maintainer can take a look; not merging until it's resolved and a human approves.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The PR is test-only and the added coverage aligns with the stated goal, with only minor test determinism/oracle-strength nits noted.

Review details

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py:155

  • torch.manual_seed(0) is called after constructing AdaLNContinuous(...), so the module parameter initialization isn’t seeded and the test can be less deterministic than intended (especially if fused-vs-plain numeric deltas depend on modulation weight distribution). Move the seed call before creating adaln so both parameters and inputs are reproducible.

This issue also appears on line 206 of the same file.
tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py:217

  • The test name suggests the LayerNorm portion is computed “manually”, but the expected value currently uses adaln.norm(x) (the module under test). Using torch.nn.functional.layer_norm here makes the oracle independent of adaln.norm implementation details and aligns better with the test intent.

tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py:211

  • Same determinism issue as the fused test: torch.manual_seed(0) happens after AdaLNContinuous(...) is constructed, so the module initialization isn’t seeded. If the goal is fully reproducible CPU plain-ops behavior, seed before instantiating adaln.
        config = self._make_config()
        adaln = AdaLNContinuous(config, conditioning_embedding_dim=HIDDEN_DIM_FLUX, modulation_bias=False)

        torch.manual_seed(0)
        x = torch.randn(ATTENTION_SEQ_LEN, BATCH_SIZE_QUAD, HIDDEN_DIM_FLUX)
        cond = torch.randn(BATCH_SIZE_QUAD, HIDDEN_DIM_FLUX)
  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

… tests

Copilot flagged that torch.manual_seed(0) ran after AdaLNContinuous(...)
construction in test_fused_forward_matches_plain_ops_formula and
test_forward_matches_manual_layernorm_and_modulate, so the modulation
Linear's parameter init wasn't covered by the seed. Move the seed call
before construction in both so the whole test (module init + inputs) is
reproducible.
Copilot AI review requested due to automatic review settings September 3, 2026 18:07
The previous snippet-based commit (899c316) miscounted the replaced
line range and left a duplicated `cond = torch.randn(...)` line.
Drop the stray duplicate.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There is an accidental duplicate output = adaln(x, cond) call in the new CPU test that should be removed to avoid confusion and unnecessary work.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment on lines +212 to +213
output = adaln(x, cond)
output = adaln(x, cond)
The previous snippet-based fix (bf5ed50) removed a duplicated `cond =
torch.randn(...)` line but missed a duplicate `output = adaln(x, cond)`
call left in test_forward_matches_manual_layernorm_and_modulate by the
same line-range mistake. Drop the redundant second call.
Copilot AI review requested due to automatic review settings September 3, 2026 18:11
My prior snippet-based edit inserted a bare literal "213" line and
still left the duplicate `output = adaln(x, cond)` call in place,
which would be a SyntaxError. Remove both, leaving a single call.
@jiagaoxiang

Copy link
Copy Markdown
Collaborator Author

TestIntel PR Steward: Follow-up on this poll:

  • Copilot's second review (18:04) flagged three nits, folded into its "suppressed comments" summary rather than posted as new inline threads: (1)/(2) torch.manual_seed(0) running after AdaLNContinuous(...) construction in two tests, so module init wasn't covered by the seed, and (3) the zero-modulation LayerNorm oracle should use an independent F.layer_norm rather than adaln.norm(x). Checking the current head, (3) was already independent (torch.nn.functional.layer_norm), and (1)/(2) had already been fixed by moving the seed calls before construction (commit 899c316).
  • However, that same edit (and its follow-up bf5ed50) left the file broken: a stray literal 213 line and a duplicated output = adaln(x, cond) call in test_forward_matches_manual_layernorm_and_modulate — a leftover from a miscounted line-range edit, which would have been a SyntaxError/dead code at collection time. I removed both in 676f83e and confirmed the file now parses cleanly (ast.parse on the raw blob).
  • Net effect: PR head is now 676f83e, single non-duplicated call, all three Copilot nits addressed, no functional/test changes beyond the cleanup.

Still holding off on merge: mergeable_state is blocked (no human approval yet), and the build-docker (3.12) job is still expected to fail for this fork PR (empty PRIMUS_DOCKER_HUB_TOKEN secret on fork-triggered pull_request runs — a repo/workflow config issue out of scope for this test-only change, as flagged earlier). Will merge once a human approves and the in-scope checks are green.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new backward tests use a loss (output.sum()) that can yield exactly-zero gradients under LayerNorm in common edge conditions (e.g., if modulation is zero/constant), making the gradient-flow assertions fragile.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py:177

  • Using .sum().backward() can produce exactly-zero gradients when the modulation happens to be zero/constant (e.g., if AdaLNContinuous ever adopts AdaLN-style zero-init), because LayerNorm(x) has zero-mean per token so LayerNorm(x).sum() is a constant. This makes the test fragile and can fail for the wrong reason; prefer a loss that can’t cancel under LayerNorm and explicitly force nonzero modulation weights so cond must receive gradient.

This issue also appears on line 253 of the same file.

tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py:258

  • This backward test also uses .sum().backward(), which can yield a constant-zero loss (and thus exactly-zero gradients) if the modulation becomes zero/constant (e.g., future zero-init). To make the test robust and ensure cond genuinely influences the output, force a nonzero modulation weight and use a non-canceling loss like output.pow(2).sum().
        config = self._make_config()
        adaln = AdaLNContinuous(config, conditioning_embedding_dim=HIDDEN_DIM_FLUX, modulation_bias=False)
        x = torch.randn(ATTENTION_SEQ_LEN, BATCH_SIZE_QUAD, HIDDEN_DIM_FLUX, requires_grad=True)
        cond = torch.randn(BATCH_SIZE_QUAD, HIDDEN_DIM_FLUX, requires_grad=True)

        adaln(x, cond).sum().backward()
  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

…tions

Copilot review (PR AMD-AGI#1087) flagged that `.sum().backward()` can yield an
exactly-zero gradient under LayerNorm's zero-mean-per-token property if
modulation ever becomes zero/constant (e.g. a future zero-init), making
the gradient-flow assertions fragile for the wrong reason. Switch both
backward tests to `.pow(2).sum().backward()`, which cannot cancel to
zero unless every output element is exactly zero.
Copilot AI review requested due to automatic review settings September 3, 2026 18:22
@jiagaoxiang

Copy link
Copy Markdown
Collaborator Author

TestIntel PR Steward: Follow-up on this poll:

  • Copilot's latest review (18:16, review #5105322135) flagged that .sum().backward() in both backward-flow tests (test_fused_forward_backward_reaches_input_and_conditioning and test_forward_backward_reaches_input_and_modulation) can yield an exactly-zero gradient under LayerNorm's zero-mean-per-token property if modulation ever becomes zero/constant (e.g. a hypothetical future zero-init), making the assertions fragile. This was folded into Copilot's summary rather than posted as inline threads, so replying here instead.
  • Addressed: pushed 2263a45, switching both backward tests to .pow(2).sum().backward(), which cannot cancel to zero unless every output element is exactly zero — same intent, more robust loss, no other changes.
  • Still holding off on merge: no human approval yet (mergeable_state was blocked), and build-docker (3.12) is still expected to fail on this fork PR for the reason already flagged (empty PRIMUS_DOCKER_HUB_TOKEN secret on fork-triggered pull_request runs — repo/workflow config issue, out of scope for this test-only change). Will merge once a human approves and in-scope checks are green.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new “fused” CUDA tests do not currently assert that the fused dispatch path is actually being exercised, so they can pass while leaving fused forward/backward behavior untested.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py:153

  • These tests are intended to validate the fused CUDA path, but they don’t currently assert that the module is actually dispatching to the fused custom op. If a future change flips the default to the non-fused (or plain-ops) branch, this test would still pass and stop protecting the fused kernel behavior. Add an explicit assertion that fused dispatch is enabled.

tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py:171

  • Same as the forward test: this gradient-flow test should assert it is exercising the fused CUDA path. Otherwise it can silently become a plain-ops / non-fused test while still passing, leaving the fused backward untested.
        adaln = AdaLNContinuous(config, conditioning_embedding_dim=HIDDEN_DIM_FLUX).cuda()
  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Addresses Copilot review feedback (review #5105410572): the fused
forward/backward tests validated numerics but never confirmed the
module actually dispatched to primus::fused_ln_modulate, so a future
default flip to the plain-ops branch could silently stop exercising
the fused kernel while these tests kept passing.
Copilot AI review requested due to automatic review settings September 3, 2026 18:32
@jiagaoxiang

Copy link
Copy Markdown
Collaborator Author

TestIntel PR Steward: Follow-up on this poll:

  • Copilot's latest review (18:26, review #5105410572) flagged that the fused CUDA tests (test_fused_forward_matches_plain_ops_formula, test_fused_forward_backward_reaches_input_and_conditioning) never asserted the module was actually dispatching to the fused primus::fused_ln_modulate custom op — so a future flip of the default to the plain-ops branch would silently stop exercising the fused kernel while these tests kept passing.
  • Addressed: pushed 70e8655, adding assert adaln.use_fused_ln_modulate, "expected fused CUDA dispatch (adaln_plain_ops=False)" right after construction in both fused tests. No other changes.
  • Still holding off on merge: mergeable_state is blocked (no human approval yet), and build-docker (3.12) is still expected to fail on this fork PR for the reason flagged in earlier follow-ups (empty PRIMUS_DOCKER_HUB_TOKEN secret on fork-triggered pull_request runs — a repo/workflow config issue out of scope for this test-only change, and observed on every other open testgap/* PR). Will merge once a human approves and the in-scope checks are green.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes are isolated to unit tests and the added assertions align with the implementation contract for AdaLNContinuous’s formula, chunk ordering, and gradient propagation.

Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@jiagaoxiang

Copy link
Copy Markdown
Collaborator Author

Superseded by same-repo PR #1100 (head AMD-AGI:testgap/PRPUNDIT-17) so Primus-CI-TAS receives Docker Hub credentials and can run torch unit tests. Closing this fork PR.

@jiagaoxiang jiagaoxiang closed this Sep 4, 2026
Xiaoming-AMD added a commit that referenced this pull request Sep 6, 2026
…7) (#1100)

Same-repo refile of #1087 so Primus-CI-TAS runs against `AMD-AGI/Primus`
(fork PRs do not receive Docker Hub credentials, so `build-docker` /
torch unit tests never ran).

This PR was created by dougljia via Test Gap Resolver.

## Summary
- Extends
`tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py`
with CPU `TestAdaLNContinuousForwardPlainOps`: independent `norm(x) * (1
+ scale) + shift` oracle, zero-modulation LayerNorm reduction, and NeMo
chunk order (first half = scale, second half = shift).
- Adds a fused-path CUDA check against the same formula, plus a
backward-flow assertion on `x` and `cond`.
- Existing CUDA shape / invalid-norm tests are unchanged.

Closes test gap **PRPUNDIT-17**.

## Test plan
- [ ] GPU CI: `pytest
tests/unit_tests/backends/megatron/diffusion/test_flux_normalization.py`
(plain-ops CPU class + fused CUDA class; needs `megatron.core`)
- [x] `black --check` / `isort --profile black` on the edited file

---------

Co-authored-by: Xiaoming-AMD <Xiaoming.Peng@amd.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants