Skip to content

Commit dd88936

Browse files
authored
[Dispatch]: dispatch per_token_group_quant_fp8_to_vllm (#1257)
1 parent 0d00131 commit dd88936

3 files changed

Lines changed: 62 additions & 4 deletions

File tree

src/flag_gems/ops/per_token_group_quant_fp8.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def _per_token_group_quant_fp8(
2121
eps,
2222
fp8_min,
2323
fp8_max,
24+
scale_ue8m0,
2425
BLOCK: tl.constexpr,
2526
):
2627
groups_per_row = y_num_columns // group_size
@@ -39,6 +40,10 @@ def _per_token_group_quant_fp8(
3940
y = tl.load(y_ptr + cols, mask=mask, other=0.0).to(tl.float32)
4041
_absmax = tl.maximum(tl.max(tl.abs(y)), eps)
4142
y_s = _absmax / fp8_max
43+
44+
if scale_ue8m0:
45+
y_s = tl.exp2(tl.ceil(tl.log2(tl.maximum(tl.abs(y_s), 1e-10))))
46+
4247
y_q = tl.clamp(y / y_s, fp8_min, fp8_max).to(y_q_ptr.dtype.element_ty)
4348

4449
tl.store(y_q_ptr + cols, y_q, mask=mask)
@@ -57,6 +62,7 @@ def _per_token_group_quant_fp8_colmajor(
5762
eps,
5863
fp8_min,
5964
fp8_max,
65+
scale_ue8m0,
6066
BLOCK: tl.constexpr,
6167
):
6268
groups_per_row = y_num_columns // group_size
@@ -75,6 +81,10 @@ def _per_token_group_quant_fp8_colmajor(
7581
y = tl.load(y_ptr + cols, mask=mask, other=0.0).to(tl.float32)
7682
_absmax = tl.maximum(tl.max(tl.abs(y)), eps)
7783
y_s = _absmax / fp8_max
84+
85+
if scale_ue8m0:
86+
y_s = tl.exp2(tl.ceil(tl.log2(tl.maximum(tl.abs(y_s), 1e-10))))
87+
7888
y_q = tl.clamp(y / y_s, fp8_min, fp8_max).to(y_q_ptr.dtype.element_ty)
7989

8090
tl.store(y_q_ptr + cols, y_q, mask=mask)
@@ -87,6 +97,7 @@ def per_token_group_quant_fp8(
8797
eps: float = 1e-10,
8898
dtype: Optional[torch.dtype] = None,
8999
column_major_scales: bool = False,
100+
scale_ue8m0: bool = False,
90101
) -> Tuple[torch.Tensor, torch.Tensor]:
91102
# dtype: The dype of output tensor. Note that only `torch.float8_e4m3fn`
92103
fp8_dtype = SUPPORTED_FP8_DTYPE if dtype is None else dtype
@@ -126,6 +137,7 @@ def per_token_group_quant_fp8(
126137
eps,
127138
fp8_min=fp8_min,
128139
fp8_max=fp8_max,
140+
scale_ue8m0=scale_ue8m0,
129141
BLOCK=BLOCK,
130142
num_warps=num_warps,
131143
num_stages=num_stages,
@@ -141,6 +153,7 @@ def per_token_group_quant_fp8(
141153
eps,
142154
fp8_min=fp8_min,
143155
fp8_max=fp8_max,
156+
scale_ue8m0=scale_ue8m0,
144157
BLOCK=BLOCK,
145158
num_warps=num_warps,
146159
num_stages=num_stages,

src/flag_gems/patches/patch_vllm_all.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,32 @@ def custom_get_scheduler_metadata(
338338
)
339339

340340

341+
def custom_per_token_group_fp8_quant(
342+
input: torch.Tensor,
343+
output_q: torch.Tensor,
344+
output_s: torch.Tensor,
345+
group_size: int,
346+
eps: float,
347+
fp8_min: float,
348+
fp8_max: float,
349+
scale_ue8m0: bool = False,
350+
):
351+
from flag_gems.ops import per_token_group_quant_fp8
352+
353+
column_major_scales = output_s.stride(0) < output_s.stride(1)
354+
355+
x_q, x_s = per_token_group_quant_fp8(
356+
x=input,
357+
group_size=group_size,
358+
eps=eps,
359+
column_major_scales=column_major_scales,
360+
scale_ue8m0=scale_ue8m0,
361+
)
362+
363+
output_q.copy_(x_q)
364+
output_s.copy_(x_s)
365+
366+
341367
def apply_gems_patches_to_vllm(verbose=True):
342368
import vllm # noqa: F401
343369
from vllm.attention.ops.paged_attn import PagedAttention
@@ -376,3 +402,10 @@ def apply_gems_patches_to_vllm(verbose=True):
376402
"CUDA",
377403
verbose,
378404
)
405+
patch_vllm_lib(
406+
"_C",
407+
"per_token_group_fp8_quant",
408+
custom_per_token_group_fp8_quant,
409+
"CUDA",
410+
verbose,
411+
)

tests/test_special_ops.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,9 @@ def test_accuracy_contiguous(shape, dtype):
12651265
gems_assert_equal(res_out, ref_out)
12661266

12671267

1268-
def native_per_token_group_quant_fp8(x, group_size, eps=1e-10, dtype=None):
1268+
def native_per_token_group_quant_fp8(
1269+
x, group_size, eps=1e-10, dtype=None, scale_ue8m0=False
1270+
):
12691271
if dtype is None:
12701272
dtype = flag_gems.SUPPORTED_FP8_DTYPE
12711273

@@ -1281,6 +1283,9 @@ def native_per_token_group_quant_fp8(x, group_size, eps=1e-10, dtype=None):
12811283
x_ = x.reshape(x.numel() // group_size, group_size)
12821284
amax = x_.abs().max(dim=-1, keepdim=True)[0].clamp(min=eps).to(torch.float32)
12831285
x_s = amax / fp8_max
1286+
if scale_ue8m0:
1287+
min_val = torch.tensor(1e-10, dtype=x_s.dtype, device=x_s.device)
1288+
x_s = torch.exp2(torch.ceil(torch.log2(torch.maximum(x_s.abs(), min_val))))
12841289
x_q = (x_ / x_s).clamp(min=fp8_min, max=fp8_max).to(dtype)
12851290
x_q = x_q.reshape(x.shape)
12861291
x_s = x_s.reshape(x.shape[:-1] + (x.shape[-1] // group_size,))
@@ -1294,14 +1299,21 @@ def native_per_token_group_quant_fp8(x, group_size, eps=1e-10, dtype=None):
12941299
@pytest.mark.parametrize("dtype", FP8_QUANT_SHAPES["DTYPES"])
12951300
@pytest.mark.parametrize("d", FP8_QUANT_SHAPES["D"])
12961301
@pytest.mark.parametrize("num_tokens", FP8_QUANT_SHAPES["NUM_TOKENS"])
1297-
def test_accuracy_per_token_group_quant_fp8(num_tokens, d, dtype, group_size, seed):
1302+
@pytest.mark.parametrize("scale_ue8m0", [True, False])
1303+
def test_accuracy_per_token_group_quant_fp8(
1304+
num_tokens, d, dtype, group_size, seed, scale_ue8m0
1305+
):
12981306
torch.manual_seed(seed)
12991307
x = torch.rand(num_tokens, d, dtype=dtype, device=flag_gems.device)
13001308
ref_x = to_reference(x)
13011309

1302-
ref_out, ref_scale = native_per_token_group_quant_fp8(ref_x, group_size)
1310+
ref_out, ref_scale = native_per_token_group_quant_fp8(
1311+
ref_x, group_size, scale_ue8m0=scale_ue8m0
1312+
)
13031313
with flag_gems.use_gems():
1304-
out, scale = flag_gems.per_token_group_quant_fp8(x, group_size)
1314+
out, scale = flag_gems.per_token_group_quant_fp8(
1315+
x, group_size, scale_ue8m0=scale_ue8m0
1316+
)
13051317

13061318
gems_assert_close(scale, ref_scale, dtype=torch.float32)
13071319

0 commit comments

Comments
 (0)