Repository navigation
feat(adaln): add indexed CUDA/Triton modulation and explicit strict qualification #621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
hongleng
wants to merge
37
commits into
RL-Align:test-qwenimage
Choose a base branch
from
hongleng:feat/adaln-indexed
base: test-qwenimage
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
d666d31
WIP #386: add AdaLN modulation WS1 implementations and tests
hongleng da269ee
test: cover AdaLN padding and batch invariance
hongleng 28ea057
test: validate AdaLN native CUDA acceptance
hongleng 649dcd7
feat: add explicit AdaLN indexed fallback
hongleng f38ba6f
Enhance AdaLN Modulation with Thread Configuration and Synchronizatio…
hongleng a566b16
fix(adaln): close shared precision and validation gaps
hongleng 4677419
feat(test): enhance AdaLN tests with CUDA thread configurations and d…
hongleng 8e1e99e
feat(adaln): implement independent CPU affine VJP and enhance gradien…
hongleng e2c36d3
Remove CUDA 12.6 installation and verification scripts
hongleng 0988fab
Implement strict dispatch for AdaLN modulation and enhance backend ob…
hongleng b31a814
refactor(adaln): migrate WS1 operator to upstream layout
hongleng 42e965b
refactor(adaln): remove local legacy compatibility entries
hongleng 8fb3180
test(adaln): include runtime dispatch tests in CI pipeline
hongleng d84d12f
refactor(ci): remove AdaLN CPU contract and reference tests from CI p…
hongleng 538f4f4
refactor(ci): remove obsolete test paths from WS1 GPU workflow
hongleng 11fb8f8
fix(adaln): rename shift and scale variables to dshift and dscale in …
hongleng 90b467a
feat(adaln): implement _center_and_rstd function for mean and rstd ca…
hongleng 903943a
fix(numerical): correct string formatting in error messages for contr…
hongleng c139bbf
refactor(adaln): streamline backend provenance handling and validatio…
hongleng 50f3397
refactor(adaln): update arithmetic profile handling and simplify test…
hongleng 3837c4f
refactor(validation): keep AdaLN policy out of generic operator checks
hongleng ebd5e6f
refactor(validation): restore unrelated operator specs to baseline
hongleng 111aa44
docs(validation): add H100 validation runbook for AdaLN modulation
hongleng aefd69a
docs(adaln): record H100 acceptance and indexed follow-up
hongleng b2eabc9
fix(adaln): reject Triton inputs beyond int32 addressing
hongleng c394895
test(adaln): require Triton for large-hidden resolution assertion
hongleng beb5bff
docs(adaln): qualify S specialization and review validation evidence
hongleng d18c4c2
test(adaln): align dispatch test ownership with parent
hongleng dd550ec
feat(adaln): add small FP32 indexed CUDA forward and backward
hongleng d079f7c
test(adaln): cover indexed CUDA gradient semantics
hongleng b32cc62
test(adaln): strengthen indexed cancellation checks and simplify fixt…
hongleng 872ea7c
feat(adaln): expand indexed CUDA input domain
hongleng d6c894d
feat(adaln): implement indexed Triton forward and backward
hongleng 5490223
feat(adaln): add default-closed indexed strict activation
hongleng f23b389
style(adaln): apply CI-pinned Black and isort formatting
hongleng 05f8221
fix(adaln): guard Triton devices and clarify validation backends
hongleng 496324d
feat(tests): add CLI tests for optional CUDA extension handling
hongleng File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
246 changes: 246 additions & 0 deletions
246
benchmarks/operators/norm/benchmark_adaln_modulation.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,246 @@ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # Copyright (c) 2026 RL-Kernel Contributors | ||
| """Compare AdaLN backends on Qwen-Image image-token lengths. | ||
|
|
||
| Run with --real for S=4096/6889/6032, H=3072. These S values are derived | ||
| from 8x VAE downsampling and 2x2 latent packing, not specified by #386. | ||
| """ | ||
|
|
||
| import argparse | ||
| import contextlib | ||
| import hashlib | ||
| import json | ||
| import platform | ||
| import statistics | ||
| import subprocess | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| import torch | ||
|
|
||
| REPO_ROOT = Path(__file__).resolve().parents[3] | ||
| if str(REPO_ROOT) not in sys.path: | ||
| sys.path.insert(0, str(REPO_ROOT)) | ||
|
|
||
|
|
||
| def layer_norm_baseline(x, modulation, *, eps=1e-6): | ||
| """Ordinary PyTorch math for accuracy/performance, without a replay claim.""" | ||
| shift, scale, _ = modulation.float().chunk(3, dim=-1) | ||
| norm = torch.nn.functional.layer_norm(x.float(), (x.shape[-1],), eps=eps) | ||
| return ( | ||
| (norm * (1.0 + scale[:, None]) + shift[:, None]).to(x.dtype), | ||
| modulation[:, None, 2 * x.shape[-1] :], | ||
| ) | ||
|
|
||
|
|
||
| def _bench(op, x, modulation, *, backward, warmup, repeat): | ||
| def run(): | ||
| x.grad = modulation.grad = None | ||
| if backward: | ||
| y, gate = op(x, modulation) | ||
| torch.autograd.backward((y, gate), (torch.ones_like(y), torch.ones_like(gate))) | ||
| else: | ||
| with torch.no_grad(): | ||
| op(x, modulation) | ||
|
|
||
| for _ in range(warmup): | ||
| run() | ||
| torch.cuda.synchronize() | ||
| torch.cuda.reset_peak_memory_stats() | ||
| allocated_before = torch.cuda.memory_allocated() | ||
| samples = [] | ||
| for _ in range(repeat): | ||
| start, end = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True) | ||
| start.record() | ||
| run() | ||
| end.record() | ||
| end.synchronize() | ||
| samples.append(start.elapsed_time(end)) | ||
| return { | ||
| "median_ms": statistics.median(samples), | ||
| "samples_ms": samples, | ||
| "peak_allocated_bytes": torch.cuda.max_memory_allocated(), | ||
| "allocated_before_samples_bytes": allocated_before, | ||
| } | ||
|
|
||
|
|
||
| def parse_args(argv=None): | ||
| parser = argparse.ArgumentParser() | ||
| parser.add_argument("--real", action="store_true", help="run all three Qwen-Image resolutions") | ||
| parser.add_argument("--warmup", type=int, default=3) | ||
| parser.add_argument("--repeat", type=int, default=10) | ||
| parser.add_argument("--dtype", choices=("bf16", "fp32"), default="bf16") | ||
| parser.add_argument("--seed", type=int, default=386) | ||
| parser.add_argument("--json", action="store_true", help="emit one JSON report on stdout") | ||
| args = parser.parse_args(argv) | ||
| if args.warmup < 0 or args.repeat < 1: | ||
| parser.error("warmup must be nonnegative and repeat must be positive") | ||
| return args | ||
|
|
||
|
|
||
| def _command_output(command): | ||
| try: | ||
| return subprocess.check_output( | ||
| command, cwd=REPO_ROOT, text=True, stderr=subprocess.DEVNULL, timeout=5 | ||
| ).strip() | ||
| except (OSError, subprocess.SubprocessError): | ||
| return None | ||
|
|
||
|
|
||
| def _sha256(path): | ||
| if not path or not Path(path).is_file(): | ||
| return None | ||
| with open(path, "rb") as source: | ||
| digest = hashlib.sha256() | ||
| for chunk in iter(lambda: source.read(1024 * 1024), b""): | ||
| digest.update(chunk) | ||
| return digest.hexdigest() | ||
|
|
||
|
|
||
| def main(argv=None): | ||
| args = parse_args(argv) | ||
| if not torch.cuda.is_available(): | ||
| raise SystemExit("CUDA device required") | ||
| # Imports and extension diagnostics must not corrupt the JSON stdout stream. | ||
| with contextlib.redirect_stdout(sys.stderr): | ||
| from rl_engine.reference.norm.adaln_modulation import NativeAdaLNModulationOp | ||
| from rl_engine.runtime.adaln import SHARED_PROFILE, AdaLNDispatch | ||
|
|
||
| backends = [("pytorch", NativeAdaLNModulationOp())] | ||
| skipped = [] | ||
| try: | ||
| from rl_engine.backends.shared.triton.norm.adaln_modulation import ( | ||
| TritonAdaLNModulationOp, | ||
| ) | ||
|
|
||
| backends.append(("triton", TritonAdaLNModulationOp())) | ||
| except ImportError as exc: | ||
| skipped.append({"backend": "triton", "reason": str(exc)}) | ||
| try: | ||
| from rl_engine.backends.cuda.norm.adaln_modulation import CudaAdaLNModulationOp | ||
|
|
||
| backends.append(("cuda", CudaAdaLNModulationOp())) | ||
| except RuntimeError as exc: | ||
| skipped.append({"backend": "cuda", "reason": str(exc)}) | ||
| try: | ||
| import triton | ||
|
|
||
| triton_version = triton.__version__ | ||
| except ImportError: | ||
| triton_version = None | ||
| environment = { | ||
| "gpu": torch.cuda.get_device_name(), | ||
| "device": str(torch.cuda.current_device()), | ||
| "capability": list(torch.cuda.get_device_capability()), | ||
| "cuda_runtime": torch.version.cuda, | ||
| "torch": torch.__version__, | ||
| "python": platform.python_version(), | ||
| "triton": triton_version, | ||
| "driver_inventory": _command_output( | ||
| ["nvidia-smi", "--query-gpu=uuid,name,driver_version", "--format=csv,noheader"] | ||
| ), | ||
| "source_revision": _command_output(["git", "rev-parse", "HEAD"]), | ||
| "source_status": _command_output(["git", "status", "--porcelain=v1"]), | ||
| } | ||
| source_paths = [ | ||
| "benchmarks/operators/norm/benchmark_adaln_modulation.py", | ||
| "rl_engine/runtime/adaln.py", | ||
| "rl_engine/reference/norm/adaln_modulation.py", | ||
| "rl_engine/backends/cuda/norm/adaln_modulation.py", | ||
| "rl_engine/backends/shared/triton/norm/adaln_modulation.py", | ||
| "rl_engine/ops/autograd/vjp_fp32.py", | ||
| "csrc/cuda/norm/adaln_modulation.cu", | ||
| "csrc/bindings/ops.cpp", | ||
| "setup.py", | ||
| "build_tools/extensions.py", | ||
| ] | ||
| environment["source_sha256"] = {path: _sha256(REPO_ROOT / path) for path in source_paths} | ||
| backends = [ | ||
| ( | ||
| name, | ||
| AdaLNDispatch( | ||
| op, | ||
| { | ||
| "requested_backend": name, | ||
| "fallback": False, | ||
| "fallback_reason": None, | ||
| "arithmetic_profile": SHARED_PROFILE, | ||
| }, | ||
| hidden=3072, | ||
| ), | ||
| ) | ||
| for name, op in backends | ||
| ] | ||
| backends.append(("layer_norm_baseline", layer_norm_baseline)) | ||
| dtype = torch.bfloat16 if args.dtype == "bf16" else torch.float32 | ||
| generator = torch.Generator(device="cuda").manual_seed(args.seed) | ||
| results = [] | ||
| sizes = (4096, 6889, 6032) if args.real else (64,) | ||
| for seq in sizes: | ||
| x = torch.randn( | ||
| 1, seq, 3072, device="cuda", dtype=dtype, generator=generator, requires_grad=True | ||
| ) | ||
| modulation = torch.randn( | ||
| 1, 9216, device="cuda", dtype=dtype, generator=generator, requires_grad=True | ||
| ) | ||
| for name, op in backends: | ||
| # Observe outside timing; retain the original bare-operator event interval. | ||
| with torch.no_grad(): | ||
| op(x, modulation) | ||
| trace = ( | ||
| dict(op.trace) | ||
| if isinstance(op, AdaLNDispatch) | ||
| else { | ||
| "actual_backend": "pytorch", | ||
| "arithmetic_profile": "ordinary-layer-norm", | ||
| "observation": "successful_forward", | ||
| "strict": False, | ||
| "profiler_observed": False, | ||
| "fallback": False, | ||
| } | ||
| ) | ||
| trace["binary_sha256"] = _sha256(trace.get("binary_path")) | ||
| timed_op = op.implementation if isinstance(op, AdaLNDispatch) else op | ||
| for backward in (False, True): | ||
| measured = _bench( | ||
| timed_op, | ||
| x, | ||
| modulation, | ||
| backward=backward, | ||
| warmup=args.warmup, | ||
| repeat=args.repeat, | ||
| ) | ||
| results.append( | ||
| { | ||
| "backend": name, | ||
| "shape": list(x.shape), | ||
| "backward": backward, | ||
| "trace": trace, | ||
| **measured, | ||
| } | ||
| ) | ||
| report = { | ||
| "schema_version": "adaln-benchmark-v1", | ||
| "environment": environment, | ||
| "dtype": args.dtype, | ||
| "seed": args.seed, | ||
| "warmup": args.warmup, | ||
| "repeat": args.repeat, | ||
| "timing": "CUDA events; forward or autograd forward+backward including ones_like upstreams", | ||
| "skipped_backends": skipped, | ||
| "results": results, | ||
| } | ||
| if args.json: | ||
| print(json.dumps(report, indent=2)) | ||
| else: | ||
| print(json.dumps({key: value for key, value in report.items() if key != "results"})) | ||
| for result in results: | ||
| print( | ||
| f"S={result['shape'][1]} backend={result['backend']} " | ||
| f"backward={result['backward']} median_ms={result['median_ms']:.3f} " | ||
| f"peak_MB={result['peak_allocated_bytes'] / 2**20:.1f}" | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.