Spaces:
Running on Zero
Running on Zero
| # Copyright 2025 Tencent Inc. All Rights Reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| from typing import Tuple | |
| import torch | |
| import triton | |
| import triton.language as tl | |
| # quant function for per-group fp8 activation | |
| # https://github.com/sgl-project/sglang/ | |
| # blob/a167fd0bcb9ef4b0f4331a109e40c8cdc770b026/python/sglang/srt/layers/ | |
| # quantization/fp8_kernel.py#L116 | |
| def _per_token_group_quant_fp8( | |
| y_ptr, | |
| y_q_ptr, | |
| y_s_ptr, | |
| y_stride, | |
| N, | |
| eps, | |
| fp8_min, | |
| fp8_max, | |
| BLOCK: tl.constexpr, | |
| ): | |
| """A Triton-accelerated function for per-token-group quantization.""" | |
| g_id = tl.program_id(0) | |
| y_ptr += g_id * y_stride | |
| y_q_ptr += g_id * y_stride | |
| y_s_ptr += g_id | |
| cols = tl.arange(0, BLOCK) | |
| mask = cols < N | |
| y = tl.load(y_ptr + cols, mask=mask, other=0.0).to(tl.float32) | |
| _absmax = tl.maximum(tl.max(tl.abs(y)), eps) | |
| y_s = _absmax / fp8_max | |
| y_s_inv = 1.0 / y_s | |
| y_q = tl.clamp(y * y_s_inv, fp8_min, fp8_max).to(y_q_ptr.dtype.element_ty) | |
| tl.store(y_q_ptr + cols, y_q, mask=mask) | |
| tl.store(y_s_ptr, y_s) | |
| def _per_token_group_quant_fp8_colmajor( | |
| y_ptr, | |
| y_q_ptr, | |
| y_s_ptr, | |
| group_size, | |
| y_num_columns, | |
| y_s_col_stride, | |
| eps, | |
| fp8_min, | |
| fp8_max, | |
| BLOCK: tl.constexpr, | |
| ): | |
| """A Triton-accelerated function for per-token-group quantization.""" | |
| g_id = tl.program_id(0) | |
| y_ptr += g_id * group_size | |
| y_q_ptr += g_id * group_size | |
| blocks_per_row = y_num_columns // group_size | |
| scale_col = g_id % blocks_per_row | |
| scale_row = g_id // blocks_per_row | |
| y_s_ptr += scale_col * y_s_col_stride + scale_row | |
| cols = tl.arange(0, BLOCK) | |
| mask = cols < group_size | |
| y = tl.load(y_ptr + cols, mask=mask, other=0.0).to(tl.float32) | |
| _absmax = tl.maximum(tl.max(tl.abs(y)), eps) | |
| y_s = _absmax / fp8_max | |
| y_q = tl.clamp(y / y_s, fp8_min, fp8_max).to(y_q_ptr.dtype.element_ty) | |
| tl.store(y_q_ptr + cols, y_q, mask=mask) | |
| tl.store(y_s_ptr, y_s) | |
| def fp8_per_token_group_quant_triton( | |
| x: torch.Tensor, | |
| group_size: int, | |
| eps: float = 1e-10, | |
| dtype: torch.dtype = torch.float8_e4m3fn, | |
| column_major_scales: bool = False, | |
| scale_tma_aligned: bool = False, | |
| ) -> Tuple[torch.Tensor, torch.Tensor]: | |
| """Function to perform per-token-group quantization on an input tensor `x`.""" | |
| assert ( | |
| x.shape[-1] % group_size == 0 | |
| ), "the last dimension of `x` cannot be divisible by `group_size`" | |
| assert x.is_contiguous(), "`x` is not contiguous" | |
| finfo = torch.finfo(dtype) | |
| fp8_max = finfo.max | |
| fp8_min = -fp8_max | |
| x_q = torch.empty_like(x, device=x.device, dtype=dtype) | |
| M = x.numel() // group_size | |
| N = group_size | |
| if column_major_scales: | |
| if scale_tma_aligned: | |
| aligned_size = (x.shape[-2] + 3) // 4 * 4 | |
| x_s = torch.empty( | |
| x.shape[:-2] + (x.shape[-1] // group_size, aligned_size), | |
| device=x.device, | |
| dtype=torch.float32, | |
| ).permute(-1, -2)[: x.shape[-2], :] | |
| else: | |
| x_s = torch.empty( | |
| (x.shape[-1] // group_size,) + x.shape[:-1], | |
| device=x.device, | |
| dtype=torch.float32, | |
| ).permute(-1, -2) | |
| else: | |
| x_s = torch.empty( | |
| x.shape[:-1] + (x.shape[-1] // group_size,), | |
| device=x.device, | |
| dtype=torch.float32, | |
| ) | |
| BLOCK = triton.next_power_of_2(N) | |
| num_warps = min(max(BLOCK // 256, 1), 8) | |
| num_stages = 1 | |
| if column_major_scales: | |
| _per_token_group_quant_fp8_colmajor[(M,)]( | |
| x, | |
| x_q, | |
| x_s, | |
| group_size, | |
| x.shape[1], | |
| x_s.stride(1), | |
| eps, | |
| fp8_min=fp8_min, | |
| fp8_max=fp8_max, | |
| BLOCK=BLOCK, | |
| num_warps=num_warps, | |
| num_stages=num_stages, | |
| ) | |
| else: | |
| _per_token_group_quant_fp8[(M,)]( | |
| x, | |
| x_q, | |
| x_s, | |
| group_size, | |
| N, | |
| eps, | |
| fp8_min=fp8_min, | |
| fp8_max=fp8_max, | |
| BLOCK=BLOCK, | |
| num_warps=num_warps, | |
| num_stages=num_stages, | |
| ) | |
| return x_q, x_s | |