Skip to content

Commit 6368414

Browse files
Arm backend: Add FP8 support to the VGF runtime (#24028)
Change-Id: I48dd7274e17c999e8a7575af7c33459ff1dd475f Signed-off-by: Yufeng Shi <yufeng.shi@arm.com>
1 parent 552e679 commit 6368414

4 files changed

Lines changed: 85 additions & 2 deletions

File tree

‎backends/arm/runtime/VGFSetup.cpp‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ enum class FormatScalarKind {
7272
Sint,
7373
Float,
7474
BFloat,
75+
Float8E4M3,
76+
Float8E5M2,
7577
};
7678

7779
struct FormatInfo {
@@ -134,6 +136,8 @@ static uint32_t get_format_component_count(VkFormat format) {
134136
case VK_FORMAT_R16_SINT:
135137
case VK_FORMAT_R16_SFLOAT:
136138
case VK_FORMAT_R16_SFLOAT_FPENCODING_BFLOAT16_ARM:
139+
case VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E4M3_ARM:
140+
case VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E5M2_ARM:
137141
case VK_FORMAT_R32_UINT:
138142
case VK_FORMAT_R32_SINT:
139143
case VK_FORMAT_R32_SFLOAT:
@@ -190,6 +194,12 @@ static bool get_format_info(VkFormat format, FormatInfo* info) {
190194
case VK_FORMAT_R16_SFLOAT_FPENCODING_BFLOAT16_ARM:
191195
*info = FormatInfo{1, 2, FormatScalarKind::BFloat};
192196
return true;
197+
case VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E4M3_ARM:
198+
*info = FormatInfo{1, 1, FormatScalarKind::Float8E4M3};
199+
return true;
200+
case VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E5M2_ARM:
201+
*info = FormatInfo{1, 1, FormatScalarKind::Float8E5M2};
202+
return true;
193203
case VK_FORMAT_R32_UINT:
194204
*info = FormatInfo{1, 4, FormatScalarKind::Uint};
195205
return true;
@@ -4875,6 +4885,8 @@ static uint32_t get_format_size(VkFormat format) {
48754885
case VK_FORMAT_R8_BOOL_ARM:
48764886
case VK_FORMAT_R8_UINT:
48774887
case VK_FORMAT_R8_SINT:
4888+
case VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E4M3_ARM:
4889+
case VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E5M2_ARM:
48784890
return 1;
48794891
case VK_FORMAT_R16_UINT:
48804892
case VK_FORMAT_R16_SINT:

‎backends/arm/test/misc/test_runner_utils.py‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from typing import Any, cast
1111

1212
import numpy as np
13+
import pytest
1314
import torch
1415
from executorch.backends.arm.test import runner_utils
1516

@@ -321,3 +322,43 @@ def test_add_known_vkml_validation_filters_uses_platform_separator() -> None:
321322
*runner_utils.KNOWN_VKML_VALIDATION_VUIDS,
322323
]
323324
assert filters.count(first_known_vuid) == 1
325+
326+
327+
@pytest.mark.parametrize(
328+
"dtype", [torch.float8_e4m3fn, torch.float8_e5m2, torch.bfloat16]
329+
)
330+
@pytest.mark.parametrize(
331+
"shape, order",
332+
[
333+
((3, 4), (0, 1)),
334+
((1, 3, 4, 5), runner_utils.NHWC_ORDER),
335+
((1, 2, 3, 4, 5), runner_utils.NNHWC_ORDER),
336+
],
337+
)
338+
@pytest.mark.parametrize("symbolic", [False, True])
339+
@pytest.mark.parametrize("opaque", [False, True])
340+
def test_raw_output_preserves_dtype_bytes_and_shape(
341+
monkeypatch, dtype, shape, order, symbolic, opaque
342+
):
343+
storage_dtype = np.uint16 if dtype == torch.bfloat16 else np.uint8
344+
array = np.arange(np.prod(shape), dtype=storage_dtype).reshape(
345+
tuple(shape[index] for index in order)
346+
)
347+
inverse_order = tuple(order.index(index) for index in range(len(shape)))
348+
expected = torch.from_numpy(array).view(dtype).permute(inverse_order).contiguous()
349+
metadata_shape = (object(), *shape[1:]) if symbolic else shape
350+
output_tensor = SimpleNamespace(
351+
shape=metadata_shape, dtype=dtype, dim_order=lambda: order
352+
)
353+
monkeypatch.setattr(
354+
runner_utils, "get_first_fake_tensor", lambda node: output_tensor
355+
)
356+
if opaque:
357+
array = array.view(np.dtype(f"V{array.itemsize}"))
358+
359+
result = runner_utils.numpy_to_torch_tensor(array, None)
360+
361+
assert result.dtype == dtype
362+
assert tuple(result.shape) == shape
363+
assert result.is_contiguous()
364+
torch.testing.assert_close(result.view(torch.uint8), expected.view(torch.uint8))

‎backends/arm/test/ops/test_matmul.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,30 @@ def test_matmul_vgf_no_quant(test_case: test_case_t):
479479
pipeline.run()
480480

481481

482+
@common.parametrize(
483+
"test_case",
484+
test_suite_fp8,
485+
xfails={
486+
"double_input_rand_rand_3d_fp8e5m2": (
487+
"PyTorch lacks the required FP8 CPU kernels for bmm.",
488+
NotImplementedError,
489+
),
490+
},
491+
)
492+
@common.SkipIfNoModelConverter
493+
def test_matmul_vgf_no_quant_fp8(test_case: test_case_t):
494+
test_data = test_case()
495+
pipeline = VgfPipeline[input_t](
496+
test_data.module,
497+
test_data.input_factory(),
498+
aten_op_mm,
499+
list(test_data.exir_ops),
500+
quantize=False,
501+
tosa_extensions=["fp8e4m3", "fp8e5m2"],
502+
)
503+
pipeline.run()
504+
505+
482506
@common.parametrize("test_case", test_suite, xfails=vgf_quant_xfails)
483507
@common.SkipIfNoModelConverter
484508
def test_matmul_vgf_quant(test_case: test_case_t):

‎backends/arm/test/runner_utils.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,14 @@ def is_concrete_shape(shape_like) -> bool:
300300
return all(isinstance(dim, numbers.Integral) for dim in shape_like)
301301

302302
def to_torch_tensor() -> torch.Tensor:
303-
if output_tensor.dtype == torch.bfloat16 or array.dtype.type is np.void:
304-
return torch.frombuffer(array, dtype=output_tensor.dtype)
303+
if (
304+
output_tensor.dtype
305+
in (torch.bfloat16, torch.float8_e4m3fn, torch.float8_e5m2)
306+
or array.dtype.type is np.void
307+
):
308+
return torch.frombuffer(array, dtype=output_tensor.dtype).reshape(
309+
array.shape
310+
)
305311
return torch.from_numpy(array)
306312

307313
if dim_order == NHWC_ORDER:

0 commit comments

Comments
 (0)