|
43 | 43 |
|
44 | 44 | from __future__ import annotations |
45 | 45 |
|
| 46 | +import onnx_ir as ir |
46 | 47 | from onnxscript.rewriter._basics import MatchFailureError, MatchResult |
47 | 48 | from onnxscript.rewriter._rewrite_rule import ( |
48 | 49 | RewriteRuleClassBase, |
49 | 50 | RewriteRuleSet, |
50 | 51 | ) |
51 | 52 |
|
| 53 | +from mobius._passes._dtype_utils import initializer_dtype |
| 54 | + |
| 55 | + |
| 56 | +def _propagate_dtype(source: ir.Value, *targets: ir.Value) -> None: |
| 57 | + """Stamp ``source``'s dtype onto rewrite-created intermediate values. |
| 58 | +
|
| 59 | + Values produced by the replacement builder (``op.Concat(...)``, |
| 60 | + ``op.Transpose(...)``) carry no declared type. When those intermediates are |
| 61 | + later folded into initializers, a missing declared type forces the fold |
| 62 | + passes to recover the dtype from ``const_value`` — or, absent that, to |
| 63 | + default to ``FLOAT``, silently widening fp16 weights. Stamping the dtype of |
| 64 | + the parameter the value is derived from keeps the type consistent from the |
| 65 | + point the packed weight is created. |
| 66 | + """ |
| 67 | + dtype = initializer_dtype(source) |
| 68 | + if dtype is None: |
| 69 | + return |
| 70 | + for target in targets: |
| 71 | + target.dtype = dtype |
| 72 | + |
52 | 73 |
|
53 | 74 | def _has_unequal_kv_head_dimensions(k, v, past_key, past_value) -> bool: |
54 | 75 | """Return whether static K/V shapes prove incompatible GQA head dimensions.""" |
@@ -364,6 +385,9 @@ def rewrite( |
364 | 385 | packed_w = op.Concat(q_w, k_w, v_w, axis=0) |
365 | 386 | # Transpose packed weight: (q_out+k_out+v_out, hidden) → (hidden, q_out+k_out+v_out) |
366 | 387 | packed_wt = op.Transpose(packed_w, perm=[1, 0]) |
| 388 | + # Concat/Transpose outputs have no declared type; carry the weight dtype |
| 389 | + # forward so the folded packed initializer keeps the model dtype. |
| 390 | + _propagate_dtype(q_w, packed_w, packed_wt) |
367 | 391 | packed_qkv = op.MatMul(hidden, packed_wt) |
368 | 392 |
|
369 | 393 | # Recover remaining GQA inputs and attributes from the matched node |
@@ -487,10 +511,14 @@ def rewrite( |
487 | 511 | packed_w = op.Concat(q_w, k_w, v_w, axis=0) |
488 | 512 | # Transpose packed weight: (q_out+k_out+v_out, hidden) → (hidden, q_out+k_out+v_out) |
489 | 513 | packed_wt = op.Transpose(packed_w, perm=[1, 0]) |
| 514 | + # Concat/Transpose outputs have no declared type; carry the weight dtype |
| 515 | + # forward so the folded packed initializer keeps the model dtype. |
| 516 | + _propagate_dtype(q_w, packed_w, packed_wt) |
490 | 517 | packed_mm = op.MatMul(hidden, packed_wt) |
491 | 518 |
|
492 | 519 | # Concat biases: (q_out + k_out + v_out,) |
493 | 520 | packed_bias = op.Concat(bias_q, bias_k, bias_v, axis=0) |
| 521 | + _propagate_dtype(bias_q, packed_bias) |
494 | 522 | # GQA has no bias input — the Add stays in the graph. |
495 | 523 | packed_qkv = op.Add(packed_mm, packed_bias) |
496 | 524 |
|
|
0 commit comments