Repository navigation
Support skip_zeros in the XPU Triton optimizer kernels - #2097
jiqing-feng wants to merge 2 commits into
Conversation
`skip_zeros` leaves a parameter and its optimizer states completely untouched
wherever the gradient is exactly zero. It is useful for sparse/masked gradients
(embeddings, MoE experts that saw no tokens) where a plain optimizer would still
decay those rows towards zero via weight decay and the decaying momentum state.
The XPU/Triton backend raised `NotImplementedError` for it, so any caller that
set the flag hard-failed on XPU while silently working on CUDA.
Triton has no per-lane early exit, so the pre-update values are kept in
registers and selected back in with `tl.where` right before the stores.
`SKIP_ZEROS` is a `tl.constexpr`, so for the default `skip_zeros=False` the
branch is compiled away and the generated kernel is unchanged. An A/B run of
all 14 optimizers x {fp32, fp16} against the unpatched build is bit-identical
(except LARS, whose `atomic_add` norm reduction is non-deterministic on its own)
and the measured step time is within noise at 4M and 64M elements.
Two deliberate differences from the CUDA kernels, which only implement the flag
partially and inconsistently:
* The zero test uses the raw gradient, before weight decay is folded in. CUDA's
32-bit 1-state kernel tests the post-decay gradient, which silently disables
`skip_zeros` for every non-zero parameter as soon as `weight_decay > 0`.
* AdEMAMix 32-bit and the 8-bit 2-state blockwise kernel honour the flag too;
CUDA ignores it there.
The CPU backend silently ignored the flag and produced wrong results; it now
raises `NotImplementedError` like the `default` backend until it is implemented.
6284d52 to
688ace5
Compare
|
Hi @matthewdouglas . Would you please review this PR? Thanks! |
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
|
Thanks for the PR. It seems there's test failures on CUDA, can we please correct this? |
CUDA only partially honors skip_zeros (ignored by the AdEMAMix 32-bit and 8-bit 2-state kernels, and the 32-bit 1-state kernels test for zero after weight decay is folded in), so the bit-exact test fails there. CPU raises NotImplementedError.
|
Fixed. The CUDA failures came from the new |
Motivation
skip_zerosis supported by the CUDA optimizer kernels but raisesNotImplementedErroron XPU. This PR implements it so the XPU backend matches CUDA.Implementation
Triton has no per-lane early exit, so the pre-update values are kept in registers and selected back in with
tl.whereright before the stores.SKIP_ZEROSis atl.constexpr, so the defaultskip_zeros=Falsecompiles the branch away entirely.Covers all four kernels: 32-bit 1-state and 2-state, 8-bit blockwise 1-state and 2-state.
The zero test is applied to the raw gradient, before weight decay is folded in, so the flag stays meaningful when
weight_decay > 0.The CPU backend silently ignored the flag and produced incorrect results; it now raises
NotImplementedErrorlike thedefaultbackend.Tests
Adds
test_skip_zerostotests/test_optim.py, parameterized over 10 optimizers x {fp32, fp16} x available devices. It asserts that elements with a zero gradient are bit-identical to their pre-step values, and that all other elements are bit-identical to theskip_zeros=Falseresult.Validation on Intel BMG
Correctness: 20 new tests pass on XPU. The rest of
tests/test_optim.pyis unchanged (same 30 pre-existingtest_optimizer32bitpaged failures before and after).No change to the default path: an A/B run of 14 optimizers x {fp32, fp16} x 5 steps against the unpatched build produces bit-identical parameters and states. The only exception is LARS, whose
atomic_addnorm reduction is already non-deterministic run-to-run without this patch.No performance impact.