submission 67773
aikitoria · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 110 lines, June 9 Researcher Reciprocity License v1.0.
greyscale_v2_fma.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-grayscale-v2-67773?include=source"interfacepython
Compatibility
measured onNVIDIA B200
declared hardwareNVIDIA B200
architecturessm_100
dtypesfp32
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:e276bb63fe6a4981ad4d365dac32e9cca937d9461dec805acc862150d487895a
license declaredunknown
license concludedunknown
authorsaikitoria
imported2026-08-15
Techniques
Extracted from the mirrored source by pattern, never inferred. Each row cites its line.
vector-width = float4
float4 vec0 = *reinterpret_cast<const float4*>(&rgb[rgb_base]);Kernel source
greyscale_v2_fma.py110 lines
import torch
from torch.utils.cpp_extension import load_inline
from task import input_t, output_t
grayscale_cuda_source = """
#include <cuda_fp16.h>
__global__ void rgb_to_grayscale_kernel(
const float* __restrict__ rgb,
float* __restrict__ gray,
const int total_pixels)
{
const float w_r = 0.2989f;
const float w_g = 0.5870f;
const float w_b = 0.1140f;
// Each thread processes 1 iteration of 4 pixels = 4 pixels total
constexpr int iterations = 1;
constexpr int pixels_per_iter = 4;
int base_idx = (blockIdx.x * blockDim.x + threadIdx.x) * pixels_per_iter * iterations;
#pragma unroll
for (int iter = 0; iter < iterations; iter++) {
int idx = base_idx + iter * pixels_per_iter;
if (idx + 3 < total_pixels) {
int rgb_base = idx * 3;
float4 vec0 = *reinterpret_cast<const float4*>(&rgb[rgb_base]);
float4 vec1 = *reinterpret_cast<const float4*>(&rgb[rgb_base + 4]);
float4 vec2 = *reinterpret_cast<const float4*>(&rgb[rgb_base + 8]);
float r0 = vec0.x, g0 = vec0.y, b0 = vec0.z;
float r1 = vec0.w, g1 = vec1.x, b1 = vec1.y;
float r2 = vec1.z, g2 = vec1.w, b2 = vec2.x;
float r3 = vec2.y, g3 = vec2.z, b3 = vec2.w;
float y0 = fmaf(w_r, r0, fmaf(w_g, g0, w_b * b0));
float y1 = fmaf(w_r, r1, fmaf(w_g, g1, w_b * b1));
float y2 = fmaf(w_r, r2, fmaf(w_g, g2, w_b * b2));
float y3 = fmaf(w_r, r3, fmaf(w_g, g3, w_b * b3));
float4 result = {y0, y1, y2, y3};
*reinterpret_cast<float4*>(&gray[idx]) = result;
}
}
}
torch::Tensor rgb_to_grayscale_cuda(torch::Tensor rgb, torch::Tensor gray) {
TORCH_CHECK(rgb.device().is_cuda(), "RGB tensor must be a CUDA tensor");
TORCH_CHECK(gray.device().is_cuda(), "Gray tensor must be a CUDA tensor");
TORCH_CHECK(rgb.dim() == 3, "RGB tensor must be 3D (H, W, 3)");
TORCH_CHECK(rgb.size(2) == 3, "RGB tensor must have 3 channels");
const int H = rgb.size(0);
const int W = rgb.size(1);
const int total_pixels = H * W;
const int threads = 1024;
const int pixels_per_thread = 4; // 1 iteration × 4 pixels per iteration
const int blocks = (total_pixels + threads * pixels_per_thread - 1) / (threads * pixels_per_thread);
rgb = rgb.contiguous();
gray = gray.contiguous();
rgb_to_grayscale_kernel<<<blocks, threads>>>(
rgb.data_ptr<float>(),
gray.data_ptr<float>(),
total_pixels
);
cudaError_t err = cudaGetLastError();
if (err != cudaSuccess) {
throw std::runtime_error(cudaGetErrorString(err));
}
return gray;
}
"""
grayscale_cpp_source = """
#include <torch/extension.h>
torch::Tensor rgb_to_grayscale_cuda(torch::Tensor rgb, torch::Tensor gray);
"""
import sys
import os
if sys.stdout is None:
sys.stdout = open(os.devnull, 'w')
if sys.stderr is None:
sys.stderr = open(os.devnull, 'w')
grayscale_module = load_inline(
name='rgb_to_grayscale_cuda',
cpp_sources=grayscale_cpp_source,
cuda_sources=grayscale_cuda_source,
functions=['rgb_to_grayscale_cuda'],
extra_cuda_cflags=['-O3', '--use_fast_math', '-lineinfo', '--generate-code=arch=compute_100,code=sm_100a'],
verbose=False,
)
def custom_kernel(data: input_t) -> output_t:
rgb, output = data
assert rgb.is_cuda and output.is_cuda, "Tensors must be on GPU"
assert rgb.dim() == 3 and rgb.size(2) == 3, "RGB must be (H, W, 3)"
assert rgb.dtype == torch.float32, "RGB must be float32"
return grayscale_module.rgb_to_grayscale_cuda(rgb, output)
scrolls · 110 lines total
Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0
Changes from previous submission
Against this author's previous submission submission 66514.
- # submission.py- import os- from task import input_t, output_timport torchfrom torch.utils.cpp_extension import load_inline+ from task import input_t, output_t- _cuda = r"""- #include <torch/extension.h>- #include <ATen/cuda/CUDAContext.h>- #include <cuda.h>+ grayscale_cuda_source = """+ #include <cuda_fp16.h>- #ifndef UNROLL- #define UNROLL 8- #endif+ __global__ void rgb_to_grayscale_kernel(+ const float* __restrict__ rgb,+ float* __restrict__ gray,+ const int total_pixels)+ {+ const float w_r = 0.2989f;+ const float w_g = 0.5870f;+ const float w_b = 0.1140f;- __launch_bounds__(512, 2)- __global__ void rgb2gray_f32_kernel(const float* __restrict__ in,- float* __restrict__ out,- size_t n_pix,- const float w0,- const float w1,- const float w2) {- const size_t tid = blockIdx.x * blockDim.x + threadIdx.x;- const size_t stride = blockDim.x * gridDim.x;+ // Each thread processes 1 iteration of 4 pixels = 4 pixels total+ constexpr int iterations = 1;+ constexpr int pixels_per_iter = 4;- for (size_t base = tid; base < n_pix; base += stride * UNROLL) {- #pragma unroll- for (int u = 0; u < UNROLL; ++u) {- const size_t i = base + (size_t)u * stride;- if (i >= n_pix) break;+ int base_idx = (blockIdx.x * blockDim.x + threadIdx.x) * pixels_per_iter * iterations;- const size_t o = 3 * i; // RGB interleaved- #if __CUDA_ARCH__ >= 800- float r = __ldg(in + o + 0);- float g = __ldg(in + o + 1);- float b = __ldg(in + o + 2);- #else- float r = in[o + 0];- float g = in[o + 1];- float b = in[o + 2];- #endif- float y = fmaf(w2, b, fmaf(w1, g, w0 * r));- out[i] = y;+ #pragma unroll+ for (int iter = 0; iter < iterations; iter++) {+ int idx = base_idx + iter * pixels_per_iter;++ if (idx + 3 < total_pixels) {+ int rgb_base = idx * 3;++ float4 vec0 = *reinterpret_cast<const float4*>(&rgb[rgb_base]);+ float4 vec1 = *reinterpret_cast<const float4*>(&rgb[rgb_base + 4]);+ float4 vec2 = *reinterpret_cast<const float4*>(&rgb[rgb_base + 8]);++ float r0 = vec0.x, g0 = vec0.y, b0 = vec0.z;+ float r1 = vec0.w, g1 = vec1.x, b1 = vec1.y;+ float r2 = vec1.z, g2 = vec1.w, b2 = vec2.x;+ float r3 = vec2.y, g3 = vec2.z, b3 = vec2.w;++ float y0 = fmaf(w_r, r0, fmaf(w_g, g0, w_b * b0));+ float y1 = fmaf(w_r, r1, fmaf(w_g, g1, w_b * b1));+ float y2 = fmaf(w_r, r2, fmaf(w_g, g2, w_b * b2));+ float y3 = fmaf(w_r, r3, fmaf(w_g, g3, w_b * b3));++ float4 result = {y0, y1, y2, y3};+ *reinterpret_cast<float4*>(&gray[idx]) = result;}}}- torch::Tensor grayscale_forward(torch::Tensor input,- torch::Tensor output,- double w0,- double w1,- double w2) {- TORCH_CHECK(input.is_cuda() && output.is_cuda(), "CUDA only");- TORCH_CHECK(input.scalar_type() == at::kFloat && output.scalar_type() == at::kFloat, "fp32 only");- TORCH_CHECK(input.is_contiguous() && output.is_contiguous(), "contiguous required");- TORCH_CHECK(input.size(-1) == 3, "last dim must be 3");+ torch::Tensor rgb_to_grayscale_cuda(torch::Tensor rgb, torch::Tensor gray) {+ TORCH_CHECK(rgb.device().is_cuda(), "RGB tensor must be a CUDA tensor");+ TORCH_CHECK(gray.device().is_cuda(), "Gray tensor must be a CUDA tensor");+ TORCH_CHECK(rgb.dim() == 3, "RGB tensor must be 3D (H, W, 3)");+ TORCH_CHECK(rgb.size(2) == 3, "RGB tensor must have 3 channels");- const size_t n_pix = static_cast<size_t>(input.numel() / 3);- TORCH_CHECK(static_cast<size_t>(output.numel()) == n_pix, "output numel mismatch");+ const int H = rgb.size(0);+ const int W = rgb.size(1);+ const int total_pixels = H * W;- auto* props = at::cuda::getCurrentDeviceProperties();- const int sm = props->multiProcessorCount;+ const int threads = 1024;+ const int pixels_per_thread = 4; // 1 iteration × 4 pixels per iteration+ const int blocks = (total_pixels + threads * pixels_per_thread - 1) / (threads * pixels_per_thread);- const int block = 512;- int grid = (int)((n_pix + block - 1) / block);- grid = max(grid, sm * 8);- grid = min(grid, 65535);+ rgb = rgb.contiguous();+ gray = gray.contiguous();- auto stream = at::cuda::getCurrentCUDAStream();- rgb2gray_f32_kernel<<<grid, block, 0, stream>>>(- input.data_ptr<float>(),- output.data_ptr<float>(),- n_pix,- static_cast<float>(w0),- static_cast<float>(w1),- static_cast<float>(w2));- C10_CUDA_KERNEL_LAUNCH_CHECK();- return output;+ rgb_to_grayscale_kernel<<<blocks, threads>>>(+ rgb.data_ptr<float>(),+ gray.data_ptr<float>(),+ total_pixels+ );++ cudaError_t err = cudaGetLastError();+ if (err != cudaSuccess) {+ throw std::runtime_error(cudaGetErrorString(err));+ }++ return gray;}"""- _cpp_decl = r"""+ grayscale_cpp_source = """#include <torch/extension.h>- torch::Tensor grayscale_forward(torch::Tensor, torch::Tensor, double, double, double);++ torch::Tensor rgb_to_grayscale_cuda(torch::Tensor rgb, torch::Tensor gray);"""- mod = load_inline(- name="rgb2gray_inline_fp32_p2",- cpp_sources=_cpp_decl,- cuda_sources=_cuda,- functions=["grayscale_forward"],- extra_cuda_cflags=[- "-O3",- "-lineinfo",- "--use_fast_math",- "-Xptxas","-O3",- "-Xptxas","-dlcm=ca"- ],+ import sys+ import os+ if sys.stdout is None:+ sys.stdout = open(os.devnull, 'w')+ if sys.stderr is None:+ sys.stderr = open(os.devnull, 'w')++ grayscale_module = load_inline(+ name='rgb_to_grayscale_cuda',+ cpp_sources=grayscale_cpp_source,+ cuda_sources=grayscale_cuda_source,+ functions=['rgb_to_grayscale_cuda'],+ extra_cuda_cflags=['-O3', '--use_fast_math', '-lineinfo', '--generate-code=arch=compute_100,code=sm_100a'],verbose=False,)- _WEIGHTS = (0.2989, 0.5870, 0.1140)-- def _contig(x: torch.Tensor) -> torch.Tensor:- return x if x.is_contiguous() else x.contiguous()-- @torch.inference_mode()def custom_kernel(data: input_t) -> output_t:- x, out = data- assert x.is_cuda and out.is_cuda- assert x.dtype == torch.float32 and out.dtype == torch.float32- assert x.size(-1) == 3- x = _contig(x); out = _contig(out)- xv = x.view(-1, 3); ov = out.view(-1)- mod.grayscale_forward(xv, ov, *_WEIGHTS)- return out+ rgb, output = data+ assert rgb.is_cuda and output.is_cuda, "Tensors must be on GPU"+ assert rgb.dim() == 3 and rgb.size(2) == 3, "RGB must be (H, W, 3)"+ assert rgb.dtype == torch.float32, "RGB must be float32"+ return grayscale_module.rgb_to_grayscale_cuda(rgb, output)
scrolls · 200 diff lines total
Best evidence level for this revision: reported
JSON