Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/python/py/models/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ def check_extra_options(kv_pairs, execution_provider):
"disable_qkv_fusion",
"prune_lm_head",
]

# Validate quant_mode if provided
if "quant_mode" in kv_pairs:
valid_modes = {"default", "hybrid", "int4"}
if kv_pairs["quant_mode"] not in valid_modes:
raise ValueError(f"quant_mode must be one of {valid_modes}, got '{kv_pairs['quant_mode']}'")
Comment thread
apsonawane marked this conversation as resolved.
Outdated
Comment thread
apsonawane marked this conversation as resolved.
Outdated
for key in bools:
if key in kv_pairs:
if kv_pairs[key] in {"false", "False", "0"}:
Expand Down
35 changes: 27 additions & 8 deletions src/python/py/models/builders/qwen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,15 +1019,34 @@ def __init__(self, config, io_dtype, onnx_dtype, ep, cache_dir, extra_options):
#
# Linear attention recurrence accumulates errors across the full sequence,
# unlike softmax attention which normalizes per-step.
#
# Control via extra_options quant_mode or QWEN35_QUANT_MODE env var:
# "default" - INT8 for all linear attn + MLP layers (original, most accurate)
# "hybrid" - INT8 for linear attn projections only, INT4 for MLPs (balanced)
# "int4" - INT4 for everything (fastest, may degrade quality)
import os
quant_mode = extra_options.get("quant_mode", "") or os.environ.get("QWEN35_QUANT_MODE", "")
Comment thread
apsonawane marked this conversation as resolved.
Outdated
if not quant_mode:
quant_mode = "default"

int8_nodes = {}
for i, lt in enumerate(self.layer_types):
if lt == "linear_attention":
# All linear attention projections: INT8
for proj in ("in_proj_a", "in_proj_b", "in_proj_qkv", "in_proj_z", "out_proj"):
int8_nodes[f"/model/layers.{i}/linear_attn/{proj}/MatMul"] = {"bits": 8}
# MLP projections in linear attention layers: INT8
for proj in ("gate_proj", "up_proj", "down_proj"):
int8_nodes[f"/model/layers.{i}/mlp/{proj}/MatMul"] = {"bits": 8}
if quant_mode == "default":
for i, lt in enumerate(self.layer_types):
Comment thread
apsonawane marked this conversation as resolved.
Outdated
if lt == "linear_attention":
# All linear attention projections: INT8
for proj in ("in_proj_a", "in_proj_b", "in_proj_qkv", "in_proj_z", "out_proj"):
int8_nodes[f"/model/layers.{i}/linear_attn/{proj}/MatMul"] = {"bits": 8}
# MLP projections in linear attention layers: INT8
for proj in ("gate_proj", "up_proj", "down_proj"):
int8_nodes[f"/model/layers.{i}/mlp/{proj}/MatMul"] = {"bits": 8}
elif quant_mode == "hybrid":
for i, lt in enumerate(self.layer_types):
if lt == "linear_attention":
# Only linear attention projections: INT8 (recurrence-sensitive)
for proj in ("in_proj_a", "in_proj_b", "in_proj_qkv", "in_proj_z", "out_proj"):
int8_nodes[f"/model/layers.{i}/linear_attn/{proj}/MatMul"] = {"bits": 8}
# MLP layers stay INT4 (feedforward, no error accumulation)
# quant_mode == "int4": no overrides, everything INT4

if int8_nodes:
algo_config = self.quant_attrs["int4"].get("algo_config")
Expand Down
Loading