Skip to content

Honor adam_w_mode in the CPU multi_tensor_adam binding - #8307

Open
PKUWZP wants to merge 2 commits into
masterfrom
cpu-adam-mode-fix
Open

Honor adam_w_mode in the CPU multi_tensor_adam binding#8307
PKUWZP wants to merge 2 commits into
masterfrom
cpu-adam-mode-fix

Conversation

@PKUWZP

@PKUWZP PKUWZP commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

The CPU fused_adam extension created its Adam_Optimizer once with default arguments and ignored the mode parameter entirely (csrc/cpu/adam/fused_adam.cpp), so FusedAdam(adam_w_mode=False) on the CPU backend always applied decoupled (AdamW) weight decay instead of L2. Everything else (lr, betas, eps, weight_decay, bias correction) is already passed per call via ds_adam_step; only the AdamW-vs-L2 flag is fixed at construction. The fix keeps one optimizer instance per mode (mode 1 == AdamW, matching the CUDA kernel's ADAM_MODE_1).

Also trims test_fused_adam_matches_torch to fp32: its bf16 cases compared against torch.optim running bf16 math, while the fused kernels compute in fp32 — never a valid reference. Low-precision dtypes get an explicit fp32-math reference test in the FusedAdam rework (#8300).

How this surfaced

Split out of #8303 at @delock's request: after a master merge, cpu-torch-latest failed on test_fused_adam_matches_torch[fp32-adam] (98.7% of elements mismatched — systematic, not tolerance noise), and the investigation traced it to this binding. The fix was verified green on cpu-torch-latest in #8303's CI (run 32695...) before being extracted here.

Validation

The CPU fused_adam extension created its Adam_Optimizer once with
default arguments and ignored the mode parameter, so FusedAdam on the
CPU backend always applied decoupled (AdamW) weight decay even when
constructed with adam_w_mode=False. Keep one optimizer instance per
mode instead; everything else is already passed per call.

This surfaced as cpu-torch-latest failures in the fp32-adam case of
test_fused_adam_matches_torch. The test's bf16 cases are dropped:
torch.optim in bf16 does its math in bf16 while the fused kernels
compute in fp32, so it was never a valid bf16 reference. Low-precision
dtypes get an explicit fp32-math reference in the FusedAdam rework.

Signed-off-by: PKUWZP <zhipeng.rainbowserie@gmail.com>
(cherry picked from commit a746b27)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1e17e84f2b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread csrc/cpu/adam/fused_adam.cpp
@FU-max-boop

Copy link
Copy Markdown
Contributor

CI triage note: modal-torch-latest tested the exact head 1e17e84. Because csrc/** is a run-all trigger, it ran the full tests/unit/v1 suite (1232 items), not the changed CPU Adam test. The run reached 97% without an Adam-related failure, then exited 137 almost exactly at the controller's 3600-second Modal Sandbox lifetime; the unrelated test_offload_activation case was marked failed only after its xdist worker was forcibly terminated.

The same 1232-item full suite passed on the base SHA in 2479.20 seconds (run 32692693729), and cpu-torch-latest passed on this exact head (job 97354322902). The failed Modal job therefore looks like a full-suite lifetime timeout rather than evidence of an Adam regression. A rerun should distinguish runtime/order variance; if it recurs, the shared 3600-second Sandbox lifetime may need more headroom.

static bool initialized[2] = {false, false};
const int optimizer_id = mode;
if (!initialized[mode]) {
create_adam_optimizer(optimizer_id, 1e-3f, 0.9f, 0.999f, 1e-8f, 0.0f, mode == 1);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Are these '1e-3f, 0.9f, 0.999f, 1e-8f, 0.0f' value place holder? If they are better define a macro as place holder and put it here.

@tohtana tohtana left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The fix looks good to me, thank you @PKUWZP! This is important to unblock the CI.

I noticed that the new regression test is not run in CPU CI on hosts without fp16 support. This means its coverage can vary depending on the underlying GitHub Actions runner hardware. As I understand it, this bug had existed for a long time but remained hidden because the runners being used did not support fp16, causing the entire test module to be skipped.

Could we scope the fp16 skip to TestAdamConfigs only, while leaving test_fused_adam_matches_torch eligible to run on CPU regardless of fp16 support?

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.

4 participants