File size: 5,309 Bytes
e9c8366 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | """ssm_patterns β exclude patterns for State-Space Model / linear-attention
layers (Mamba, KDA, RWKV, gated linear attention, etc.).
SSM layers contain parameters that must NOT be quantized through the standard
weight-quantization walker:
- `A_log`, `dt_bias`, `D` β nn.Parameter (not nn.Module): the walker does not
touch them automatically. Documented here for clarity.
- `ShortConvolution` / `conv1d` β custom 1D-conv wrappers (not nn.Conv1d):
not in SUPPORTED_MODULE_TYPES, walker skips them.
- Linear projections feeding the SSM core (`q_proj`, `k_proj`, `b_proj`,
`f_a_proj`, `f_b_proj`) β distorting these breaks the delta rule / recurrent
dynamics. Should be excluded for low-bit formats.
- Output projections (`v_proj`, `o_proj`, `g_proj`, `g_a_proj`, `g_b_proj`)
β less critical: quantizing them is generally safe.
Usage:
from agiws_neural_quant.ssm_patterns import get_ssm_exclude_patterns
excl = get_ssm_exclude_patterns("conservative")
quantize_model(model, format="int4", exclude_modules=excl)
Levels:
conservative β quantize only o_proj (output) inside SSM modules.
moderate β quantize o_proj + v_proj + g_* (output path), keep q/k/b/f.
aggressive β quantize all Linear inside SSM except q_proj/k_proj
(preserve SSM input, quantize output + gating).
full β quantize every Linear (no SSM exclusions; for fp8 / high-bit
where distortion is minimal).
subtree β skip whole SSM modules entirely (for Mamba/RWKV whose module
name contains 'mamba'/'rwkv'/'kda'/'delta_attn'). NOT suitable
for Kimi-K3 where the SSM layer is named `self_attn` (shared
with MLA layers) β use level-based exclude there.
All patterns use fnmatch glob syntax and are matched against the full dotted
module path (e.g. "layers.5.self_attn.q_proj"). Bare names without a leading
`*.` are intentionally omitted β they would never match the dotted path and
would be dead patterns.
"""
from __future__ import annotations
# Full exclusion: skip the entire SSM subtree (any Linear inside).
# Matched against the SSM module name itself. Use for Mamba/RWKV where the
# module has a distinctive name. For Kimi-K3 (SSM layer named `self_attn`,
# shared with MLA), use level-based exclude instead.
SSM_SUBTREE_PATTERNS: tuple[str, ...] = (
"mamba", "*_mamba", "*mamba*",
"rwkv", "*_rwkv", "*rwkv*",
"*delta_attention*", "*delta_attn*",
"*linear_attention*", "*linear_attn*",
"*kda*", "*_kda",
)
# Conservative: quantize only the final output projection inside SSM.
# All other SSM Linear (q/k/v/b/f/g inputs and gating) are excluded.
SSM_CONSERVATIVE_EXCLUDE: tuple[str, ...] = (
"*.self_attn.q_proj",
"*.self_attn.k_proj",
"*.self_attn.v_proj",
"*.self_attn.b_proj",
"*.self_attn.f_a_proj",
"*.self_attn.f_b_proj",
"*.self_attn.g_a_proj",
"*.self_attn.g_b_proj",
"*.self_attn.in_proj",
"*.self_attn.dt_proj",
)
# Moderate: quantize output path (o/v/g), keep SSM input + gating (q/k/b/f).
SSM_MODERATE_EXCLUDE: tuple[str, ...] = (
"*.self_attn.q_proj",
"*.self_attn.k_proj",
"*.self_attn.b_proj",
"*.self_attn.f_a_proj",
"*.self_attn.f_b_proj",
"*.self_attn.in_proj",
"*.self_attn.dt_proj",
)
# Aggressive: quantize all SSM Linear except q/k (preserve SSM input only).
SSM_AGGRESSIVE_EXCLUDE: tuple[str, ...] = (
"*.self_attn.q_proj",
"*.self_attn.k_proj",
"*.self_attn.in_proj",
)
_LEVELS: dict[str, tuple[str, ...] | None] = {
"full": None, # no exclusions
"aggressive": SSM_AGGRESSIVE_EXCLUDE,
"moderate": SSM_MODERATE_EXCLUDE,
"conservative": SSM_CONSERVATIVE_EXCLUDE,
"subtree": SSM_SUBTREE_PATTERNS, # skip whole SSM modules
}
def get_ssm_exclude_patterns(level: str = "conservative") -> list[str]:
"""Return glob patterns to pass to quantize_model(exclude_modules=...).
Args:
level: one of 'conservative', 'moderate', 'aggressive', 'full', 'subtree'.
- conservative (default): keep SSM core + gating, quantize o_proj only.
- moderate: quantize output path (o/v/g), keep SSM input + gating.
- aggressive: quantize all SSM Linear except q/k (SSM input).
- full: no SSM exclusions (empty list).
- subtree: skip whole SSM modules entirely (most conservative,
for Mamba/RWKV; NOT for Kimi-K3 `self_attn`).
Returns:
list of fnmatch glob patterns; empty for 'full'.
"""
if level not in _LEVELS:
raise ValueError(
f"Unknown SSM level {level!r}. Available: {sorted(_LEVELS)}"
)
pats = _LEVELS[level]
return list(pats) if pats is not None else []
def get_ssm_subtree_patterns() -> list[str]:
"""Patterns to skip whole SSM modules (do not recurse into them at all).
Use for Mamba/RWKV. For Kimi-K3 (SSM layer named `self_attn`, shared with
MLA), prefer the level-based exclude instead.
"""
return list(SSM_SUBTREE_PATTERNS)
__all__ = [
"SSM_SUBTREE_PATTERNS",
"SSM_CONSERVATIVE_EXCLUDE",
"SSM_MODERATE_EXCLUDE",
"SSM_AGGRESSIVE_EXCLUDE",
"get_ssm_exclude_patterns",
"get_ssm_subtree_patterns",
] |