Skip to content

Commit 28ae861

Browse files
committed
add DeekSeek and Kimi-K2;support per-tensor and w4a8;support batch calibration in fp8 low_memory_run
1 parent 6d8dac5 commit 28ae861

25 files changed

Lines changed: 2797 additions & 74 deletions

angelslim/compressor/quant/core/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
from .config import * # noqa: F401 F403
1616
from .hook import DiTHook, PTQHook # noqa: F401
1717
from .metrics import mse_loss, snr_loss # noqa: F401
18-
from .packing_utils import dequantize_gemm # noqa: F401
18+
from .packing_utils import dequantize_gemm, pack_weight_to_int8 # noqa: F401
1919
from .quant_func import * # noqa: F401 F403
2020
from .sample_func import EMASampler, MultiStepSampler # noqa: F401
21+
from .save import Deepseekv3HfPTQSave # noqa: F401
2122
from .save import PTQPTMSave # noqa: F401
23+
from .save import PTQSaveTRTLLM # noqa: F401
2224
from .save import PTQSaveVllmHF # noqa: F401
2325
from .save import PTQTorchSave # noqa: F401
2426
from .save import PTQvLLMSaveHF # noqa: F401

angelslim/compressor/quant/core/config.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,33 @@ def __init__(self, config, global_config=None):
136136
"ignore_layers": quantization_args.ignore_layers,
137137
}
138138
self.hidden_size = global_config.hidden_size
139+
elif "w4a8" in self.quant_algo:
140+
is_dynamic = "dynamic" if "dynamic" in self.quant_algo else "static"
141+
assert (
142+
is_dynamic or act_quant_method is not None
143+
), "[OpenSlim][Error] fp8_static need act_quant_method"
144+
self.act_observer = (
145+
ACT_OBSERVERS_CLASS[act_quant_method]
146+
if "static" in is_dynamic
147+
else None
148+
)
149+
self.weight_observer = WEIGHT_OBSERVERS_CLASS[weight_quant_method]
150+
self.kv_cache_observer = None
151+
group_size = (
152+
128
153+
if quantization_args.quant_method["group_size"] == -1
154+
else quantization_args.quant_method["group_size"]
155+
)
156+
self.quant_algo_info = {
157+
"w": f"int4_{weight_quant_method}",
158+
"w_group_size": group_size,
159+
"ignore_layers": quantization_args.ignore_layers,
160+
}
161+
if act_quant_method is not None:
162+
self.quant_algo_info["a"] = f"fp8_{act_quant_method}-{is_dynamic}"
163+
self.hidden_size = global_config.hidden_size
164+
self.model_arch_type = global_config.model_arch_type
165+
self.low_memory = config.quantization.low_memory
139166

140167
if "smooth" in self.quant_helpers:
141168
self.smooth_alpha = quantization_args.smooth_alpha

angelslim/compressor/quant/core/packing_utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import numpy as np
1516
import torch
1617

1718
AWQ_ORDER = [0, 2, 4, 6, 1, 3, 5, 7]
@@ -115,3 +116,21 @@ def dequantize_gemm(qweight, qzeros, scales, bits, group_size):
115116
iweight = (iweight - izeros) * scales
116117

117118
return iweight
119+
120+
121+
def pack_weight_to_int8(weight):
122+
weight = weight.t().contiguous().cpu()
123+
weight = weight.to(torch.float32).numpy().astype(np.int8)
124+
125+
i = 0
126+
row = 0
127+
packed_weight = np.zeros((weight.shape[0] // 2, weight.shape[1]), dtype=np.int8)
128+
while row < packed_weight.shape[0]:
129+
for j in range(i, i + (8 // 4)):
130+
packed_weight[row] |= (weight[j] & 0x0F) << (4 * (j - i))
131+
i += 8 // 4
132+
row += 1
133+
134+
packed_weight = packed_weight.astype(np.int8)
135+
packed_weight = torch.from_numpy(packed_weight).t().contiguous()
136+
return packed_weight

angelslim/compressor/quant/core/quant_func.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
from typing import Tuple
1616

1717
import torch
18+
import triton
19+
import triton.language as tl
1820

1921
from .metrics import mse_loss
2022

@@ -314,3 +316,67 @@ def tensor_quant_dequant_fp8(x, scale, bits=8, mantissa_bit=3, sign_bits=1):
314316
)
315317
quant_dequant_x *= scale
316318
return quant_dequant_x
319+
320+
321+
# This function is copied from DeepSeek-V3 (MIT License):
322+
# Copyright (c) 2023 DeepSeek-AI
323+
# Original source: https://github.com/deepseek-ai/DeepSeek-V3
324+
@triton.jit
325+
def weight_dequant_kernel(x_ptr, s_ptr, y_ptr, M, N, BLOCK_SIZE: tl.constexpr):
326+
"""
327+
Dequantizes weights using the provided scaling factors and stores the result.
328+
329+
Args:
330+
x_ptr (tl.pointer): Pointer to the quantized weights.
331+
s_ptr (tl.pointer): Pointer to the scaling factors.
332+
y_ptr (tl.pointer): Pointer to the output buffer for dequantized weights.
333+
M (int): Number of rows in the weight matrix.
334+
N (int): Number of columns in the weight matrix.
335+
BLOCK_SIZE (tl.constexpr): Size of the block for tiling.
336+
337+
Returns:
338+
None
339+
"""
340+
pid_m = tl.program_id(axis=0)
341+
pid_n = tl.program_id(axis=1)
342+
n = tl.cdiv(N, BLOCK_SIZE)
343+
offs_m = pid_m * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
344+
offs_n = pid_n * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
345+
offs = offs_m[:, None] * N + offs_n[None, :]
346+
mask = (offs_m[:, None] < M) & (offs_n[None, :] < N)
347+
x = tl.load(x_ptr + offs, mask=mask).to(tl.float32)
348+
s = tl.load(s_ptr + pid_m * n + pid_n)
349+
y = x * s
350+
tl.store(y_ptr + offs, y, mask=mask)
351+
352+
353+
# This function is copied from DeepSeek-V3 (MIT License):
354+
# Copyright (c) 2023 DeepSeek-AI
355+
# Original source: https://github.com/deepseek-ai/DeepSeek-V3
356+
def weight_dequant(
357+
x: torch.Tensor, s: torch.Tensor, block_size: int = 128
358+
) -> torch.Tensor:
359+
"""
360+
Dequantizes the given weight tensor using the provided scale tensor.
361+
362+
Args:
363+
x (torch.Tensor): The quantized weight tensor of shape (M, N).
364+
s (torch.Tensor): The scale tensor of shape (M, N).
365+
block_size (int, optional): The block size to use for dequantization. Defaults to 128. # noqa: E501
366+
367+
Returns:
368+
torch.Tensor: The dequantized weight tensor of the same shape as `x`.
369+
370+
Raises:
371+
AssertionError: If `x` or `s` are not contiguous or if their dimensions are not 2. # noqa: E501
372+
"""
373+
assert x.is_contiguous() and s.is_contiguous(), "Input tensors must be contiguous"
374+
assert x.dim() == 2 and s.dim() == 2, "Input tensors must have 2 dimensions"
375+
M, N = x.size()
376+
y = torch.empty_like(x, dtype=torch.get_default_dtype())
377+
grid = lambda meta: ( # noqa: E731
378+
triton.cdiv(M, meta["BLOCK_SIZE"]),
379+
triton.cdiv(N, meta["BLOCK_SIZE"]),
380+
)
381+
weight_dequant_kernel[grid](x, s, y, M, N, BLOCK_SIZE=block_size)
382+
return y

0 commit comments

Comments
 (0)