94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
447 lines
16 KiB
Python
447 lines
16 KiB
Python
import logging
|
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
|
|
import torch
|
|
from tqdm import tqdm
|
|
from tqdm.std import EMA
|
|
|
|
from sglang.srt.layers.int4fp8_utils import (
|
|
pack_int4_to_int32,
|
|
quantize_fp8_scale_tensorwise,
|
|
quantize_int4_scale_columnwise,
|
|
)
|
|
from sglang.srt.layers.moe import MoeRunner, MoeRunnerBackend, MoeRunnerConfig
|
|
from sglang.srt.layers.quantization.base_config import (
|
|
FusedMoEMethodBase,
|
|
QuantizationConfig,
|
|
QuantizeMethodBase,
|
|
)
|
|
from sglang.srt.layers.quantization.fp8 import Fp8LinearMethod
|
|
from sglang.srt.runtime_context import get_parallel
|
|
from sglang.srt.utils import BAR_FORMAT, is_hip, set_weight_attrs
|
|
|
|
if TYPE_CHECKING:
|
|
from sglang.srt.layers.moe.token_dispatcher import DispatchOutput
|
|
|
|
_is_hip = is_hip()
|
|
|
|
|
|
if _is_hip:
|
|
from aiter.ops.shuffle import shuffle_weight
|
|
|
|
ON_GFX950 = "gfx950" in torch.cuda.get_device_properties("cuda").gcnArchName
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def tqdm_reset_no_print(tqdm_bar: tqdm, total=None):
|
|
tqdm_bar.n = 0
|
|
if total is not None:
|
|
tqdm_bar.total = total
|
|
if tqdm_bar.disable:
|
|
return
|
|
tqdm_bar.last_print_n = 0
|
|
tqdm_bar.last_print_t = tqdm_bar.start_t = tqdm_bar._time()
|
|
tqdm_bar._ema_dn = EMA(tqdm_bar.smoothing)
|
|
tqdm_bar._ema_dt = EMA(tqdm_bar.smoothing)
|
|
tqdm_bar._ema_miniters = EMA(tqdm_bar.smoothing)
|
|
|
|
|
|
class QuarkInt4Fp8Config(QuantizationConfig):
|
|
"""Config class for Quark Quantization.
|
|
|
|
- Weight: static, per-channel, symmetric
|
|
- Activation: dynamic, per-token, symmetric
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
is_checkpoint_fp8_serialized: bool = False,
|
|
activation_scheme: str = "dynamic",
|
|
):
|
|
self.is_checkpoint_fp8_serialized = is_checkpoint_fp8_serialized
|
|
self.activation_scheme = activation_scheme
|
|
|
|
if activation_scheme != "dynamic":
|
|
raise NotImplementedError(
|
|
"QuarkInt4Fp8Config only supports activation_scheme='dynamic'."
|
|
)
|
|
|
|
self.weight_block_size = None
|
|
|
|
self.num_quant_layers = 0
|
|
|
|
tp_rank = get_parallel().tp_rank
|
|
|
|
# The weight iterator already has a progress bar on rank=0, account for that.
|
|
position = 1 + tqdm._get_free_pos()
|
|
self.online_quant_progress_bar = tqdm(
|
|
total=0,
|
|
desc=f"Online quark_int4fp8_moe quantization on rank={tp_rank}",
|
|
position=position,
|
|
bar_format=BAR_FORMAT,
|
|
mininterval=2.0,
|
|
)
|
|
|
|
@classmethod
|
|
def get_supported_act_dtypes(cls) -> List[torch.dtype]:
|
|
return [torch.float16, torch.bfloat16]
|
|
|
|
@classmethod
|
|
def get_min_capability(cls) -> int:
|
|
return 70
|
|
|
|
@classmethod
|
|
def get_name(self) -> str:
|
|
return "quark_int4fp8_moe"
|
|
|
|
@classmethod
|
|
def get_config_filenames(cls) -> List[str]:
|
|
return []
|
|
|
|
@classmethod
|
|
def from_config(cls, config: Dict[str, Any]) -> "QuarkInt4Fp8Config":
|
|
return cls()
|
|
|
|
def get_quant_method(
|
|
self,
|
|
layer: torch.nn.Module,
|
|
prefix: str,
|
|
) -> Optional["QuantizeMethodBase"]:
|
|
# TODO: fix circular imports issues in sglang forcing us to import here instead of at
|
|
# the top of file.
|
|
from sglang.srt.layers.linear import LinearBase
|
|
from sglang.srt.layers.moe.fused_moe_triton import FusedMoE
|
|
|
|
if isinstance(layer, LinearBase):
|
|
return Fp8LinearMethod(self)
|
|
elif isinstance(layer, FusedMoE):
|
|
return QuarkInt4Fp8MoEMethod(self)
|
|
|
|
return None
|
|
|
|
def get_scaled_act_names(self) -> List[str]:
|
|
return []
|
|
|
|
|
|
class QuarkInt4Fp8MoEMethod(FusedMoEMethodBase):
|
|
"""MoE method for INT4FP8.
|
|
|
|
Supports loading BF16/FP16 checkpoints, quantizing down to INT4, and dequantizing to FP8 during inference.
|
|
|
|
Args:
|
|
quant_config: The quantization config.
|
|
"""
|
|
|
|
def __init__(self, quant_config):
|
|
self.quant_config = quant_config
|
|
|
|
self.online_quant_progress_bar = self.quant_config.online_quant_progress_bar
|
|
|
|
self.tp_rank = get_parallel().tp_rank
|
|
|
|
if not _is_hip:
|
|
raise NotImplementedError(
|
|
"The quark_int4fp8_moe online quantization scheme is only supported on AMD GPUs."
|
|
)
|
|
|
|
def get_weight_loader(self, layer, original_weight_loader):
|
|
def online_int4_fp8_weight_loader(
|
|
param: torch.nn.Parameter,
|
|
loaded_weight: torch.Tensor,
|
|
weight_name: str,
|
|
shard_id: str,
|
|
expert_id: int,
|
|
):
|
|
if shard_id in ["w1", "w3"]:
|
|
shard_size = self.w13_shard_size
|
|
else:
|
|
shard_size = self.w2_shard_size
|
|
|
|
original_use_presharded_weights = layer.use_presharded_weights
|
|
|
|
if not layer.use_presharded_weights:
|
|
# In case the model is not pre-sharded (most checkpoints on HF Hub),
|
|
# we shard the model here in order to run online quantization on
|
|
# already sharded weights.
|
|
# Some models as `lmzheng/grok-1` are already be sharded.
|
|
layer.use_presharded_weights = True
|
|
|
|
if shard_id in ["w1", "w3"]:
|
|
shard_dim = 0
|
|
loaded_weight = loaded_weight.narrow(
|
|
shard_dim, shard_size * self.tp_rank, shard_size
|
|
)
|
|
else:
|
|
shard_dim = 1
|
|
loaded_weight = loaded_weight.narrow(
|
|
shard_dim, shard_size * self.tp_rank, shard_size
|
|
)
|
|
|
|
# We want to run online quantization on-device for speed purposes.
|
|
loaded_weight = loaded_weight.to(param.device)
|
|
|
|
_, fp8_scale = quantize_fp8_scale_tensorwise(loaded_weight)
|
|
|
|
int4_w, int4_scale = quantize_int4_scale_columnwise(loaded_weight)
|
|
|
|
int4_w = pack_int4_to_int32(int4_w)
|
|
int4_scale /= fp8_scale
|
|
|
|
if shard_id in ["w1", "w3"]:
|
|
if shard_id == "w1":
|
|
shard_slice = slice(0, shard_size)
|
|
idx = 0
|
|
else:
|
|
shard_slice = slice(shard_size, 2 * shard_size)
|
|
idx = 1
|
|
|
|
assert param[expert_id][shard_slice].dtype == int4_w.dtype
|
|
|
|
assert (
|
|
layer.w13_int4_scale[expert_id][shard_slice].shape
|
|
== int4_scale.shape
|
|
)
|
|
assert (
|
|
layer.w13_int4_scale[expert_id][shard_slice].dtype
|
|
== int4_scale.dtype
|
|
)
|
|
|
|
layer.w13_int4_scale[expert_id][shard_slice].copy_(int4_scale)
|
|
|
|
assert layer.w13_fp8_scale[expert_id][idx].shape == fp8_scale.shape
|
|
assert layer.w13_fp8_scale[expert_id][idx].dtype == fp8_scale.dtype
|
|
|
|
layer.w13_fp8_scale[expert_id][idx].copy_(fp8_scale)
|
|
else:
|
|
assert param[expert_id].dtype == int4_w.dtype
|
|
assert param[expert_id].shape == int4_w.shape
|
|
|
|
assert layer.w2_int4_scale[expert_id].shape == int4_scale.shape
|
|
assert layer.w2_int4_scale[expert_id].dtype == int4_scale.dtype
|
|
|
|
layer.w2_int4_scale[expert_id].copy_(int4_scale)
|
|
|
|
assert layer.w2_fp8_scale[expert_id].shape == fp8_scale.shape
|
|
assert layer.w2_fp8_scale[expert_id].dtype == fp8_scale.dtype
|
|
|
|
layer.w2_fp8_scale[expert_id].copy_(fp8_scale)
|
|
|
|
original_weight_loader(
|
|
param,
|
|
int4_w,
|
|
shard_id=shard_id,
|
|
weight_name=weight_name,
|
|
expert_id=expert_id,
|
|
)
|
|
|
|
# Reset `use_presharded_weights` as the same layer may load several different weights.
|
|
layer.use_presharded_weights = original_use_presharded_weights
|
|
|
|
self.online_quant_progress_bar.update(1)
|
|
|
|
return online_int4_fp8_weight_loader
|
|
|
|
def create_weights(
|
|
self,
|
|
layer: torch.nn.Module,
|
|
num_experts: int,
|
|
hidden_size: int,
|
|
intermediate_size_per_partition: int,
|
|
params_dtype: torch.dtype,
|
|
**extra_weight_attrs,
|
|
):
|
|
# TODO: fix circular imports issues in sglang forcing us to import here instead of at
|
|
# the top of file.
|
|
from sglang.srt.layers.moe.fused_moe_triton import FusedMoeWeightScaleSupported
|
|
|
|
# print("intermediate_size_per_partition", intermediate_size_per_partition)
|
|
# fused moe logic already hands TP logic.
|
|
self.w13_shard_size = intermediate_size_per_partition
|
|
self.w2_shard_size = intermediate_size_per_partition
|
|
|
|
assert "weight_loader" in extra_weight_attrs
|
|
original_weight_loader = extra_weight_attrs.get("weight_loader")
|
|
|
|
online_int4fp8_weight_loader = self.get_weight_loader(
|
|
layer, original_weight_loader
|
|
)
|
|
extra_weight_attrs["weight_loader"] = online_int4fp8_weight_loader
|
|
|
|
params_dtype = torch.uint32
|
|
# WEIGHTS
|
|
# INT4 MoE weight - INT32 packed
|
|
w13_weight = torch.nn.Parameter(
|
|
torch.empty(
|
|
num_experts,
|
|
2 * intermediate_size_per_partition,
|
|
hidden_size // 8,
|
|
dtype=params_dtype,
|
|
),
|
|
requires_grad=False,
|
|
)
|
|
w2_weight = torch.nn.Parameter(
|
|
torch.empty(
|
|
num_experts,
|
|
hidden_size,
|
|
intermediate_size_per_partition // 8,
|
|
dtype=params_dtype,
|
|
),
|
|
requires_grad=False,
|
|
)
|
|
layer.register_parameter("w13_weight", w13_weight)
|
|
set_weight_attrs(w13_weight, extra_weight_attrs)
|
|
|
|
layer.register_parameter("w2_weight", w2_weight)
|
|
set_weight_attrs(w2_weight, extra_weight_attrs)
|
|
|
|
# Allocate 2 scales for w1 and w3 respectively.
|
|
# They will be combined to a single scale after weight loading.
|
|
w13_fp8_scale = torch.nn.Parameter(
|
|
torch.ones(num_experts, 2, dtype=torch.float32), requires_grad=False
|
|
)
|
|
w2_fp8_scale = torch.nn.Parameter(
|
|
torch.ones(num_experts, dtype=torch.float32), requires_grad=False
|
|
)
|
|
layer.register_parameter("w13_fp8_scale", w13_fp8_scale)
|
|
layer.register_parameter("w2_fp8_scale", w2_fp8_scale)
|
|
|
|
if _is_hip:
|
|
w13_int4_scale = torch.nn.Parameter(
|
|
torch.ones(
|
|
num_experts,
|
|
2 * intermediate_size_per_partition,
|
|
dtype=torch.float32,
|
|
),
|
|
requires_grad=False,
|
|
)
|
|
w2_int4_scale = torch.nn.Parameter(
|
|
torch.ones(num_experts, hidden_size, dtype=torch.float32),
|
|
requires_grad=False,
|
|
)
|
|
layer.register_parameter("w13_int4_scale", w13_int4_scale)
|
|
layer.register_parameter("w2_int4_scale", w2_int4_scale)
|
|
|
|
extra_weight_attrs.update(
|
|
{"quant_method": FusedMoeWeightScaleSupported.TENSOR.value}
|
|
)
|
|
|
|
set_weight_attrs(w13_fp8_scale, extra_weight_attrs)
|
|
set_weight_attrs(w2_fp8_scale, extra_weight_attrs)
|
|
|
|
# Add the quantization method used (per tensor/grouped/channel)
|
|
# to ensure the weight scales are loaded in properly
|
|
extra_weight_attrs.update(
|
|
{"quant_method": FusedMoeWeightScaleSupported.CHANNEL.value}
|
|
)
|
|
|
|
set_weight_attrs(w13_int4_scale, extra_weight_attrs)
|
|
set_weight_attrs(w2_int4_scale, extra_weight_attrs)
|
|
|
|
w13_input_scale = None
|
|
layer.register_parameter("w13_input_scale", w13_input_scale)
|
|
|
|
w2_input_scale = None
|
|
layer.register_parameter("w2_input_scale", w2_input_scale)
|
|
|
|
# Loading from the checkpoint w1, w2, w3 times the number of experts.
|
|
total = self.online_quant_progress_bar.total + num_experts * 3
|
|
tqdm_reset_no_print(self.online_quant_progress_bar, total=total)
|
|
|
|
def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
|
|
if _is_hip and not ON_GFX950:
|
|
# CDNA3 does not support OCP FP8E4M3FN, but uses FP8E4M3FNUZ.
|
|
# CDNA4 supports OCP FP8E4M3FN.
|
|
layer.w13_int4_scale *= 0.5
|
|
layer.w2_int4_scale *= 0.5
|
|
|
|
layer.w13_fp8_scale *= 2.0
|
|
layer.w2_fp8_scale *= 2.0
|
|
|
|
# TODO: and use_aiter_moe: add after triton kernel added
|
|
# INT4-FP8 (INT4 MoE Weight, FP8 Compute)
|
|
# Weight Permutation
|
|
layer.w13_weight = torch.nn.Parameter(
|
|
shuffle_weight(layer.w13_weight.data, (16, 16)),
|
|
requires_grad=False,
|
|
)
|
|
torch.cuda.empty_cache()
|
|
layer.w2_weight = torch.nn.Parameter(
|
|
shuffle_weight(layer.w2_weight.data, (16, 16)),
|
|
requires_grad=False,
|
|
)
|
|
torch.cuda.empty_cache()
|
|
|
|
# INT4-FP8 : offset INT4 w13_int4_scale to single w13_fp8_scale
|
|
# Fp8 moe kernel needs single fp8 w13_fp8_scale for w13 per expert.
|
|
# We won't do requant each expert's fp8 weight (not direct available),
|
|
# instead we adjust half of INT4 w13_int4_scale numbers
|
|
assert layer.w13_fp8_scale is not None
|
|
shard_size = layer.intermediate_size_per_partition
|
|
max_w13_scales = layer.w13_fp8_scale.max(dim=1).values
|
|
for expert_id in range(layer.num_experts):
|
|
start = 0
|
|
max_w13_scale_fp8 = max_w13_scales[expert_id]
|
|
for shard_id in range(2):
|
|
if layer.w13_fp8_scale[expert_id][shard_id] != max_w13_scale_fp8:
|
|
int4_rescale = (
|
|
layer.w13_fp8_scale[expert_id][shard_id] / max_w13_scale_fp8
|
|
)
|
|
layer.w13_int4_scale[expert_id][
|
|
start : start + shard_size
|
|
] *= int4_rescale
|
|
start += shard_size
|
|
|
|
layer.w13_fp8_scale = torch.nn.Parameter(max_w13_scales, requires_grad=False)
|
|
|
|
# special hack to asm_moe, which takes (weight_int4_scale * weight_scale) as post GEMM scaling
|
|
# optimal design - shall apply per-column weight_int4_scale before GEMM, and weight_scale post
|
|
for expert_id in range(layer.num_experts):
|
|
layer.w13_int4_scale[expert_id] *= max_w13_scales[expert_id]
|
|
layer.w2_int4_scale[expert_id] *= layer.w2_fp8_scale[expert_id]
|
|
|
|
def create_moe_runner(
|
|
self, layer: torch.nn.Module, moe_runner_config: MoeRunnerConfig
|
|
):
|
|
from sglang.srt.layers.moe.utils import (
|
|
get_moe_a2a_backend,
|
|
get_moe_runner_backend,
|
|
)
|
|
|
|
self.moe_runner_config = moe_runner_config
|
|
moe_runner_backend = get_moe_runner_backend()
|
|
if moe_runner_backend.is_auto() and get_moe_a2a_backend().supports_aiter():
|
|
moe_runner_backend = MoeRunnerBackend.AITER
|
|
|
|
if moe_runner_backend.is_aiter():
|
|
self.runner = MoeRunner(moe_runner_backend, moe_runner_config)
|
|
else:
|
|
# TODO(cwan): refactor other backends
|
|
pass
|
|
|
|
def apply(
|
|
self,
|
|
layer: torch.nn.Module,
|
|
dispatch_output: "DispatchOutput",
|
|
) -> torch.Tensor:
|
|
from sglang.srt.layers.moe.moe_runner.aiter import (
|
|
AiterMoeQuantInfo,
|
|
AiterQuantType,
|
|
)
|
|
|
|
moe_runner_config = self.moe_runner_config
|
|
|
|
# TODO: add triton kernel and add check get_bool_env_var("CK_MOE")
|
|
assert (
|
|
not moe_runner_config.no_combine
|
|
), f"no_combine={moe_runner_config.no_combine} is not supported."
|
|
|
|
quant_info = AiterMoeQuantInfo(
|
|
w13_weight=layer.w13_weight,
|
|
w2_weight=layer.w2_weight,
|
|
quant_type=AiterQuantType.PER_TOKEN,
|
|
w13_scale=layer.w13_int4_scale,
|
|
w2_scale=layer.w2_int4_scale,
|
|
)
|
|
return self.runner.run(dispatch_output, quant_info)
|