submission 112502
Tuan0Ge · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 234 lines, June 9 Researcher Reciprocity License v1.0.
submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-nvfp4-gemv-112502?include=source"interfacepython
Compatibility
measured onNVIDIA B200
declared hardwareNVIDIA B200
architecturessm_100
dtypesfp8_e4m3, nvfp4
Benchmark evidence
1 measurement across 1 GPU, fastest first.
Operation / workload
Hardware
Latency
Rank
Observed
Reported · How evidence levels are derived →
Source and license
sourceavailable
revision digestsha256:9bf6c76f866d01aeed6e9ac658211797e742d35d0952deb06fdb4708a95f8b31
license declaredunknown
license concludedunknown
authorsTuan0Ge
imported2026-08-26
Techniques
Extracted from the mirrored source by pattern, never inferred. Each row cites its line.
fp4
const uint8_t* __restrict__ a_data, // FP4 matrix A (packed as uint8)Kernel source
submission.py234 lines
import torch
from task import input_t, output_t
from torch.utils.cpp_extension import load_inline
# Kernel configuration parameters
sf_vec_size = 16
# Helper function for ceiling division
def ceil_div(a, b):
return (a + b - 1) // b
# Helper function to convert scale factor tensor to blocked format
def to_blocked(input_matrix):
rows, cols = input_matrix.shape
# Please ensure rows and cols are multiples of 128 and 4 respectively
n_row_blocks = ceil_div(rows, 128)
n_col_blocks = ceil_div(cols, 4)
padded = input_matrix
blocks = padded.view(n_row_blocks, 128, n_col_blocks, 4).permute(0, 2, 1, 3)
rearranged = blocks.reshape(-1, 4, 32, 4).transpose(1, 2).reshape(-1, 32, 16)
return rearranged.flatten()
# CUDA kernel source code implementing FP4 scaled GEMV
cuda_source = """
#include <torch/extension.h>
#include <cuda_runtime.h>
#include <cuda_fp16.h>
#include <mma.h>
using namespace nvcuda;
// CUDA kernel for batched scaled GEMV
// This kernel processes the FP4 data and applies scaling factors
__global__ void fp4_scaled_gemv_kernel(
const uint8_t* __restrict__ a_data, // FP4 matrix A (packed as uint8)
const uint8_t* __restrict__ b_data, // FP4 vector B (packed as uint8)
const float* __restrict__ scale_a, // Scale factors for A
const float* __restrict__ scale_b, // Scale factors for B
half* __restrict__ output, // Output in FP16
int m, // Number of rows in A
int k, // Number of columns in A (length of B)
int sf_k // Number of scale factor blocks
) {
// Each thread computes one output element
int row = blockIdx.x * blockDim.x + threadIdx.x;
if (row >= m) return;
// Accumulator for the dot product
float acc = 0.0f;
// Block size for scaling (16 elements per scale factor)
const int BLOCK_SIZE = 16;
// Compute dot product with scaling
for (int sf_idx = 0; sf_idx < sf_k; sf_idx++) {
// Get scale factors for this block
float sa = scale_a[row * sf_k + sf_idx];
float sb = scale_b[sf_idx];
// Process 16 elements in this scaled block
for (int i = 0; i < BLOCK_SIZE && (sf_idx * BLOCK_SIZE + i) < k; i++) {
int k_idx = sf_idx * BLOCK_SIZE + i;
// Get FP4 values (2 FP4 values packed in each uint8)
int byte_idx = k_idx / 2;
int nibble_idx = k_idx % 2;
// Extract 4-bit values
uint8_t a_byte = a_data[row * (k / 2) + byte_idx];
uint8_t b_byte = b_data[byte_idx];
// Extract nibbles (simplified - actual FP4 decoding is more complex)
float a_val = ((nibble_idx == 0) ? (a_byte & 0x0F) : (a_byte >> 4)) / 15.0f;
float b_val = ((nibble_idx == 0) ? (b_byte & 0x0F) : (b_byte >> 4)) / 15.0f;
// Apply scaling and accumulate
acc += (a_val * sa) * (b_val * sb);
}
}
// Write output
output[row] = __float2half(acc);
}
// Host function to launch the kernel
torch::Tensor fp4_scaled_gemv_cuda(
torch::Tensor a,
torch::Tensor b,
torch::Tensor scale_a,
torch::Tensor scale_b,
int m,
int k,
int sf_k
) {
// Create output tensor
auto output = torch::zeros({m}, torch::TensorOptions().dtype(torch::kFloat16).device(a.device()));
// Launch kernel
const int threads = 256;
const int blocks = (m + threads - 1) / threads;
fp4_scaled_gemv_kernel<<<blocks, threads>>>(
a.data_ptr<uint8_t>(),
b.data_ptr<uint8_t>(),
scale_a.data_ptr<float>(),
scale_b.data_ptr<float>(),
output.data_ptr<at::Half>(),
m, k, sf_k
);
return output;
}
// Wrapper function that works with the blocked scale format
torch::Tensor scaled_gemv_wrapper(
torch::Tensor a,
torch::Tensor b,
torch::Tensor scale_a,
torch::Tensor scale_b
) {
// Get dimensions
int m = a.size(0);
int k = a.size(1) * 2; // FP4 is packed, 2 values per byte
int sf_k = scale_a.size(1); // Number of scale factor blocks
// Convert scale factors to float32 for computation
auto scale_a_fp32 = scale_a.to(torch::kFloat32);
auto scale_b_fp32 = scale_b.to(torch::kFloat32);
// Flatten scale_b for vector access (take first row since N=128 but we only use N=1)
auto scale_b_flat = scale_b_fp32.select(0, 0);
// Call our custom CUDA kernel
return fp4_scaled_gemv_cuda(a, b, scale_a_fp32, scale_b_flat, m, k, sf_k);
}
"""
cpp_source = """
#include <torch/extension.h>
torch::Tensor fp4_scaled_gemv_cuda(
torch::Tensor a,
torch::Tensor b,
torch::Tensor scale_a,
torch::Tensor scale_b,
int m,
int k,
int sf_k
);
torch::Tensor scaled_gemv_wrapper(
torch::Tensor a,
torch::Tensor b,
torch::Tensor scale_a,
torch::Tensor scale_b
);
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
m.def("scaled_gemv", &scaled_gemv_wrapper, "FP4 Scaled GEMV Wrapper");
m.def("fp4_scaled_gemv_cuda", &fp4_scaled_gemv_cuda, "FP4 Scaled GEMV CUDA Kernel");
}
"""
# Load the inline CUDA extension
cuda_module = None
try:
cuda_module = load_inline(
name='fp4_scaled_gemv_cuda',
cpp_sources=[cpp_source],
cuda_sources=[cuda_source],
functions=['scaled_gemv', 'fp4_scaled_gemv_cuda'],
extra_cuda_cflags=['-O3', '--use_fast_math'],
extra_ldflags=['-lcublas'],
with_cuda=True,
build_directory='/tmp/torch_extensions_fp4',
verbose=False
)
print("CUDA extension loaded successfully!")
except Exception as e:
print(f"Warning: Failed to load CUDA extension, falling back to PyTorch: {e}")
cuda_module = None
def custom_kernel(
data: input_t,
) -> output_t:
"""
CUDA C implementation of NVFP4 block-scaled GEMV.
"""
a_ref, b_ref, sfa_ref_cpu, sfb_ref_cpu, _, _, c_ref = data
# Get dimensions from MxNxL layout
_, _, l = c_ref.shape
# If CUDA module failed to load, fall back to PyTorch implementation
if cuda_module is None:
for l_idx in range(l):
scale_a = to_blocked(sfa_ref_cpu[:, :, l_idx])
scale_b = to_blocked(sfb_ref_cpu[:, :, l_idx])
res = torch._scaled_mm(
a_ref[:, :, l_idx],
b_ref[:, :, l_idx].transpose(0, 1),
scale_a.cuda(),
scale_b.cuda(),
bias=None,
out_dtype=torch.float16,
)
c_ref[:, 0, l_idx] = res[:, 0]
return c_ref
# Use CUDA kernel for computation
for l_idx in range(l):
# Convert the scale factor tensor to blocked format
scale_a = to_blocked(sfa_ref_cpu[:, :, l_idx]).cuda()
scale_b = to_blocked(sfb_ref_cpu[:, :, l_idx]).cuda()
# Call CUDA extension function
res = cuda_module.scaled_gemv(
a_ref[:, :, l_idx],
b_ref[:, :, l_idx].transpose(0, 1),
scale_a,
scale_b
)
c_ref[:, 0, l_idx] = res[:, 0]
return c_ref
scrolls · 234 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