Kernels
superblock22 Claude Opus 4.8 commited on
Commit
0669c49
·
1 Parent(s): 12c06f0

qk_clip: value-only fix — keep original structure, drop per-row rewrite [skip-build]

Browse files

Revert the per-row expand_row_scales restructure. qk_clip keeps its exact
original reshape + named-slice shape; only the multiplied values change:
compute_scales now returns raw per-head γ, and each sub-region is raised to
its exponent inline (q_nope γ^(1-r), q_pe γ, k_nope γ^r, MHA √γ). The q_pe
line is byte-identical to before — it is now correct because scales is raw γ.

muon.py sharded path stays per-head (no per-row vectors); it just applies the
content exponent to match the raw-γ contract, preserving its prior behavior.
The sharded path's pre-existing MLA sub-region limitation (q_pe/v scaled by the
content exponent) is left as-is and documented, not addressed here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

torch-ext/optimizer/muon.py CHANGED
@@ -20,8 +20,7 @@ from .newton_schulz import (COMM_DTYPE, DEFAULT_CHUNK_SIZE_RATIO,
20
  zeropower_via_newtonschulz5,
21
  zeropower_via_newtonschulz5_batched)
22
  from .pipeline import muon_chunk_pipeline, prelaunch_first_gather
23
- from .qk_clip import (compute_scales, expand_row_scales, get_qk_clip_info,
24
- qk_clip)
25
 
26
  logger = logging.getLogger(__name__)
27
 
@@ -480,20 +479,26 @@ class Muon(torch.optim.Optimizer):
480
  p, qk_clip_state, n
481
  ) if qk_clip_state is not None else None
482
  if scales_full is not None:
483
- # Per-row γ**exponent over the whole param, indexed
484
- # by this rank's global row slice. Unlike the old
485
- # per-head form, this scales the MLA sub-regions
486
- # correctly (q_pe → full γ, v rows → untouched).
487
- full_row_scales = expand_row_scales(
488
- scales_full, qk_clip_state)
 
 
 
 
 
 
 
489
  idx0 = local_indices[0]
490
  if isinstance(idx0, slice):
491
- idx0 = torch.arange(
492
- idx0.start or 0,
493
- idx0.stop,
494
- device=full_row_scales.device)
495
- row_scales = full_row_scales[idx0.to(
496
- full_row_scales.device)]
497
  p._local_tensor.mul_(row_scales.view(-1, 1))
498
 
499
  if not batch_params:
@@ -565,20 +570,26 @@ class Muon(torch.optim.Optimizer):
565
  p, qk_clip_state, n
566
  ) if qk_clip_state is not None else None
567
  if scales_full is not None:
568
- # Per-row γ**exponent over the whole param, indexed
569
- # by this rank's global row slice. Unlike the old
570
- # per-head form, this scales the MLA sub-regions
571
- # correctly (q_pe → full γ, v rows → untouched).
572
- full_row_scales = expand_row_scales(
573
- scales_full, qk_clip_state)
 
 
 
 
 
 
 
574
  idx0 = local_indices[0]
575
  if isinstance(idx0, slice):
576
- idx0 = torch.arange(
577
- idx0.start or 0,
578
- idx0.stop,
579
- device=full_row_scales.device)
580
- row_scales = full_row_scales[idx0.to(
581
- full_row_scales.device)]
582
  p._local_tensor.mul_(row_scales.view(-1, 1))
583
 
584
  def _setup_parallel(self, names, params, group, qk_logits):
 
20
  zeropower_via_newtonschulz5,
21
  zeropower_via_newtonschulz5_batched)
22
  from .pipeline import muon_chunk_pipeline, prelaunch_first_gather
23
+ from .qk_clip import compute_scales, get_qk_clip_info, qk_clip
 
24
 
25
  logger = logging.getLogger(__name__)
26
 
 
479
  p, qk_clip_state, n
480
  ) if qk_clip_state is not None else None
481
  if scales_full is not None:
482
+ # scales_full is raw per-head γ; apply the content
483
+ # exponent per head (MHA √γ, wq_b γ^(1-r), wkv_b
484
+ # γ^r). NOTE: this per-head form cannot resolve the
485
+ # MLA rotary/value sub-regions (q_pe → full γ, v
486
+ # untouched) — see qk_clip; the sharded path scales
487
+ # q_pe/v by the content exponent instead.
488
+ if not qk_clip_state.is_mla:
489
+ e = 0.5
490
+ elif qk_clip_state.kind == 'wq_b':
491
+ e = 1.0 - qk_clip_state.k_ratio
492
+ else:
493
+ e = qk_clip_state.k_ratio
494
+ ratio = p.shape[0] // scales_full.shape[0]
495
  idx0 = local_indices[0]
496
  if isinstance(idx0, slice):
497
+ start = idx0.start or 0
498
+ idx0 = torch.arange(start,
499
+ idx0.stop,
500
+ device=scales_full.device)
501
+ row_scales = (scales_full**e)[idx0 // ratio]
 
502
  p._local_tensor.mul_(row_scales.view(-1, 1))
503
 
504
  if not batch_params:
 
570
  p, qk_clip_state, n
571
  ) if qk_clip_state is not None else None
572
  if scales_full is not None:
573
+ # scales_full is raw per-head γ; apply the content
574
+ # exponent per head (MHA √γ, wq_b γ^(1-r), wkv_b
575
+ # γ^r). NOTE: this per-head form cannot resolve the
576
+ # MLA rotary/value sub-regions (q_pe → full γ, v
577
+ # untouched) — see qk_clip; the sharded path scales
578
+ # q_pe/v by the content exponent instead.
579
+ if not qk_clip_state.is_mla:
580
+ e = 0.5
581
+ elif qk_clip_state.kind == 'wq_b':
582
+ e = 1.0 - qk_clip_state.k_ratio
583
+ else:
584
+ e = qk_clip_state.k_ratio
585
+ ratio = p.shape[0] // scales_full.shape[0]
586
  idx0 = local_indices[0]
587
  if isinstance(idx0, slice):
588
+ start = idx0.start or 0
589
+ idx0 = torch.arange(start,
590
+ idx0.stop,
591
+ device=scales_full.device)
592
+ row_scales = (scales_full**e)[idx0 // ratio]
 
593
  p._local_tensor.mul_(row_scales.view(-1, 1))
594
 
595
  def _setup_parallel(self, names, params, group, qk_logits):
torch-ext/optimizer/qk_clip.py CHANGED
@@ -130,9 +130,9 @@ def compute_scales(p, qk_clip_state, name: str = ''):
130
 
131
  Returns a per-head tensor of γ (1.0 for heads under the threshold) if any
132
  head requires clipping, else None. The per-region exponent on γ is NOT
133
- applied here — it is applied at multiply time by ``expand_row_scales`` so
134
- that a single per-head γ can drive different sub-regions (q_nope, q_pe,
135
- k_nope, v) with different exponents. See ``expand_row_scales`` / ``qk_clip``.
136
 
137
  wkv_b with k_ratio=0 returns None: the whole reduction is placed on Q and
138
  the key projection is left unclipped.
@@ -178,37 +178,9 @@ def compute_scales(p, qk_clip_state, name: str = ''):
178
  return scales_full
179
 
180
 
181
- def expand_row_scales(gamma, info):
182
- """Per-head raw γ ([H]) → per-row multiplier ([H*stride]) = γ ** exponent,
183
- where the exponent depends on the row's sub-region within its head.
184
-
185
- Each logit component ends up reduced by exactly γ:
186
- MHA : √γ on every row (√γ · √γ = γ).
187
- MLA q_nope : γ^(1-k_ratio) ┐ content: γ^(1-k_ratio)·γ^k_ratio = γ.
188
- k_nope : γ^k_ratio ┘
189
- MLA q_pe : γ (exponent 1) — the decoupled rotary key is shared and
190
- left unchanged, so the rotary query carries the whole γ for
191
- every k_ratio; γ^(1-k_ratio) here would under-clip rotary.
192
- MLA v rows : γ^0 = 1, i.e. untouched.
193
-
194
- Shared by both apply paths: qk_clip (whole tensor) and the sharded DTensor
195
- path in muon.py (which indexes the returned vector by global row).
196
- """
197
- r, n = info.k_ratio, info.qk_nope_head_dim
198
- if not info.is_mla:
199
- exps = torch.full((info.head_dim, ), 0.5)
200
- elif info.kind == 'wq_b':
201
- exps = torch.cat(
202
- [torch.full((n, ), 1.0 - r),
203
- torch.ones(info.qk_rope_head_dim)])
204
- else: # wkv_b: k_nope → γ^r, v rows → γ^0 = 1
205
- exps = torch.cat([torch.full((n, ), r), torch.zeros(info.v_head_dim)])
206
- exps = exps.to(gamma.device) # [stride]
207
- return (gamma[:, None]**exps[None, :]).reshape(-1) # [H*stride], head-major
208
-
209
-
210
  def qk_clip(p, scales, info):
211
- """Apply QK-clip to a Q/K projection weight, scaling each row by γ**exponent.
 
212
 
213
  Args:
214
  p: Parameter (nn.Parameter or raw tensor).
@@ -216,10 +188,31 @@ def qk_clip(p, scales, info):
216
  unclipped heads, as returned by ``compute_scales``.
217
  info: QKClipInfo with kind, head_dim, k_ratio and MLA sub-head dims.
218
 
219
- The per-region exponent (√γ for MHA; γ^(1-k_ratio)/γ^k_ratio content split;
220
- full γ on the rotary query; value rows untouched) is applied by
221
- ``expand_row_scales``.
 
 
 
 
222
  """
223
  W = p.data if isinstance(p, torch.nn.Parameter) else p
224
- row_scales = expand_row_scales(scales, info) # [num_rows], fp32
225
- W.mul_(row_scales.view(-1, 1)) # in-place downcast to W.dtype
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
  Returns a per-head tensor of γ (1.0 for heads under the threshold) if any
132
  head requires clipping, else None. The per-region exponent on γ is NOT
133
+ applied here — it is applied at multiply time (``qk_clip`` for the whole
134
+ tensor, or the sharded path in muon.py) so that one per-head γ can drive
135
+ different sub-regions (q_nope, q_pe, k_nope, v) with different exponents.
136
 
137
  wkv_b with k_ratio=0 returns None: the whole reduction is placed on Q and
138
  the key projection is left unclipped.
 
178
  return scales_full
179
 
180
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  def qk_clip(p, scales, info):
182
+ """Apply QK-clip to a Q/K projection weight; each sub-region is raised to
183
+ its own exponent so every logit component is reduced by exactly γ.
184
 
185
  Args:
186
  p: Parameter (nn.Parameter or raw tensor).
 
188
  unclipped heads, as returned by ``compute_scales``.
189
  info: QKClipInfo with kind, head_dim, k_ratio and MLA sub-head dims.
190
 
191
+ Exponents:
192
+ MHA : √γ on all rows.
193
+ MLA q_nope : γ^(1-k_ratio), k_nope : γ^k_ratio (content product = γ).
194
+ MLA q_pe : γ (full) — the decoupled rotary key is shared and left
195
+ unchanged, so the rotary query carries the whole γ for
196
+ every k_ratio; γ^(1-k_ratio) here would under-clip rotary.
197
+ MLA v rows : untouched.
198
  """
199
  W = p.data if isinstance(p, torch.nn.Parameter) else p
200
+ r = info.k_ratio
201
+
202
+ if not info.is_mla:
203
+ W.view(-1, info.head_dim, W.shape[1]).mul_((scales**0.5).view(-1, 1, 1))
204
+ return
205
+
206
+ if info.kind == 'wq_b':
207
+ qk_nope = info.qk_nope_head_dim
208
+ qk_head_dim = qk_nope + info.qk_rope_head_dim
209
+ W_3d = W.view(-1, qk_head_dim, W.shape[1]) # [H, qk_head_dim, in_dim]
210
+ W_3d[:, :qk_nope, :].mul_((scales**(1.0 - r)).view(-1, 1, 1)) # q_nope → γ^(1-r)
211
+ W_3d[:, qk_nope:, :].mul_(scales.view(-1, 1, 1)) # q_pe → γ (full)
212
+
213
+ elif info.kind == 'wkv_b':
214
+ qk_nope = info.qk_nope_head_dim
215
+ kv_stride = qk_nope + info.v_head_dim
216
+ W_3d = W.view(-1, kv_stride, W.shape[1]) # [H, kv_stride, in_dim]
217
+ W_3d[:, :qk_nope, :].mul_((scales**r).view(-1, 1, 1)) # k_nope → γ^r
218
+ # v rows: untouched (shared rotary key k_rope is unchanged)