Skip to content
KernelIndex
Search⌘K

submission 629606

nozom1ff · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

No package. Vendor the mirrored source: 170 lines, June 9 Researcher Reciprocity License v1.0.

submission_advanced.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-amd-mxfp4-mm-629606?include=source"
interfacepython
Compatibility
measured onAMD Instinct MI355X
declared hardwareAMD Instinct MI355X
architecturesgfx950
dtypesbf16, mxfp4

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
AMD MXFP4 GEMMsuite of 6 cases
AMD Instinct MI355X
24.2µs
#968 of 1143
2026-03-25

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:a97c339ace034ac0f0e992a06d9baae890958092349b8254e1a065590ff3e20b
license declaredunknown
license concludedunknown
authorsnozom1ff
imported2026-08-26

Techniques

Extracted from the mirrored source by pattern, never inferred. Each row cites its line.

fp4Advanced FP4 quant + FP4 GEMM with custom HIP kernels for MI355X.

Kernel source

submission_advanced.py170 lines
#!POPCORN leaderboard amd-mxfp4-mm
#!POPCORN gpu MI355X

"""
Advanced FP4 quant + FP4 GEMM with custom HIP kernels for MI355X.
This version includes optional custom quantization kernel for better performance.
"""
from task import input_t, output_t

import os
# Set ROCm architecture before importing torch
os.environ['PYTORCH_ROCM_ARCH'] = 'gfx942'
os.environ['CXX'] = 'clang++'

import torch
import aiter
from aiter import dtypes
from aiter.ops.triton.quant import dynamic_mxfp4_quant
from aiter.utility.fp4_utils import e8m0_shuffle

# Try to use custom HIP kernel for quantization (fallback to aiter if compilation fails)
USE_CUSTOM_QUANT = False  # Set to True to enable custom HIP quant kernel

if USE_CUSTOM_QUANT:
    try:
        from torch.utils.cpp_extension import load_inline

        HIP_QUANT_SRC = """
#include <hip/hip_runtime.h>
#include <hip/amd_detail/amd_hip_bf16.h>

// MXFP4 quantization kernel: per-1x32 grouping with e8m0 scale
// Each block processes multiple groups of 32 elements
__global__ void mxfp4_quant_kernel(
    const __hip_bfloat16* __restrict__ input,
    uint8_t* __restrict__ output_fp4,
    uint8_t* __restrict__ output_scale,
    int M, int K
) {
    // Group size for per-1x32 quantization
    const int GROUP_SIZE = 32;

    int group_idx = blockIdx.x * blockDim.x + threadIdx.x;
    int total_groups = M * ((K + GROUP_SIZE - 1) / GROUP_SIZE);

    if (group_idx >= total_groups) return;

    int row = group_idx / ((K + GROUP_SIZE - 1) / GROUP_SIZE);
    int col_group = group_idx % ((K + GROUP_SIZE - 1) / GROUP_SIZE);
    int col_start = col_group * GROUP_SIZE;

    // Find max absolute value in group for scale calculation
    float max_abs = 0.0f;
    for (int i = 0; i < GROUP_SIZE && (col_start + i) < K; ++i) {
        float val = __bfloat162float(input[row * K + col_start + i]);
        max_abs = fmaxf(max_abs, fabsf(val));
    }

    // Calculate e8m0 scale (exponent only, 8-bit)
    // Scale = 2^exponent where exponent = floor(log2(max_abs)) - 2 (for FP4 range)
    uint8_t scale_e8m0 = 0;
    if (max_abs > 0.0f) {
        int exp = (int)floorf(log2f(max_abs)) - 2;
        scale_e8m0 = (uint8_t)(exp + 127);  // e8m0 bias
    }

    output_scale[group_idx] = scale_e8m0;

    // Quantize each element to FP4
    float scale_val = exp2f((float)(scale_e8m0) - 127.0f);
    float inv_scale = scale_val > 0.0f ? 1.0f / scale_val : 0.0f;

    // Pack 2 FP4 values per byte
    for (int i = 0; i < GROUP_SIZE && (col_start + i) < K; i += 2) {
        uint8_t packed = 0;
        for (int j = 0; j < 2 && (col_start + i + j) < K; ++j) {
            float val = __bfloat162float(input[row * K + col_start + i + j]);
            float scaled = val * inv_scale;
            // Simple FP4 quantization (simplified - actual MXFP4 has specific encoding)
            int quantized = (int)roundf(scaled * 6.0f);  // Scale to FP4 range
            quantized = max(-6, min(6, quantized));      // Clamp
            uint8_t fp4_bits = (uint8_t)(quantized + 8); // Offset to unsigned
            if (j == 0) {
                packed = fp4_bits & 0x0F;
            } else {
                packed |= (fp4_bits & 0x0F) << 4;
            }
        }
        output_fp4[row * ((K + 1) / 2) + (col_start + i) / 2] = packed;
    }
}

torch::Tensor mxfp4_quant(torch::Tensor input) {
    int M = input.size(0);
    int K = input.size(1);

    auto output_fp4 = torch::empty({M, (K + 1) / 2}, torch::dtype(torch::kUInt8).device(input.device()));
    auto output_scale = torch::empty({M, (K + 31) / 32}, torch::dtype(torch::kUInt8).device(input.device()));

    const int threads = 256;
    int total_groups = M * ((K + 31) / 32);
    const int blocks = (total_groups + threads - 1) / threads;

    mxfp4_quant_kernel<<<blocks, threads>>>(
        reinterpret_cast<const __hip_bfloat16*>(input.data_ptr<at::BFloat16>()),
        output_fp4.data_ptr<uint8_t>(),
        output_scale.data_ptr<uint8_t>(),
        M, K
    );

    return torch::stack({output_fp4, output_scale});
}
"""

        CPP_SRC = """
torch::Tensor mxfp4_quant(torch::Tensor input);
"""

        _hip_module = load_inline(
            name='mxfp4_quant_module',
            cpp_sources=[CPP_SRC],
            cuda_sources=[HIP_QUANT_SRC],
            functions=['mxfp4_quant'],
            verbose=True,
            extra_cuda_cflags=["--offload-arch=gfx942", "-std=c++20", "-O3"],
        )

        def _custom_quant_mxfp4(x):
            result = _hip_module.mxfp4_quant(x)
            return result[0].view(dtypes.fp4x2), result[1].view(dtypes.fp8_e8m0)

        _quant_func = _custom_quant_mxfp4
        print("Custom HIP quant kernel loaded successfully")

    except Exception as e:
        print(f"Failed to load custom HIP kernel, falling back to aiter: {e}")
        USE_CUSTOM_QUANT = False


def _aiter_quant_mxfp4(x: torch.Tensor) -> tuple:
    """MXFP4 quantization using aiter library."""
    x_fp4, bs_e8m0 = dynamic_mxfp4_quant(x)
    bs_e8m0 = e8m0_shuffle(bs_e8m0)
    return x_fp4.view(dtypes.fp4x2), bs_e8m0.view(dtypes.fp8_e8m0)


# Select quantization function
_quant_mxfp4 = _custom_quant_mxfp4 if USE_CUSTOM_QUANT else _aiter_quant_mxfp4


def custom_kernel(data: input_t) -> output_t:
    """
    MXFP4 GEMM with optimized quantization.
    Uses custom HIP kernel if available, otherwise falls back to aiter.
    """
    A, _, _, B_shuffle, B_scale_sh = data

    # Quantize A to MXFP4
    A_q, A_scale_sh = _quant_mxfp4(A)

    # 4-bit GEMM
    return aiter.gemm_a4w4(
        A_q,
        B_shuffle,
        A_scale_sh,
        B_scale_sh,
        dtype=dtypes.bf16,
        bpreshuffle=True,
    )
scrolls · 170 lines total

Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0

Best evidence level for this revision: reported

JSON