Kernels
relu / README.md
superexpai's picture
v3: fix pre-Hopper (32MiB, L2] launch cliff (independently reported); retract position-biased 4090 claims; buffer-fair dtype benchmarks (MK, powered by Claude)
f30427a verified
|
Raw
History Blame Contribute Delete
7.71 kB
---
library_name: kernels
license: apache-2.0
---
This is the repository card of `SuperexponentialAI/relu`. It was built to
be used with the [`kernels` library](https://github.com/huggingface/kernels).
## How to use
```python
# make sure `kernels` is installed: `pip install -U kernels`
from kernels import get_kernel
kernel_module = get_kernel("SuperexponentialAI/relu", version=3)
relu = kernel_module.relu
relu(x)
```
## Available functions
- `relu`
## Scope
This build covers **cpu, cuda, and xpu only**. `metal` and `rocm` are
declared in `kernels-community/relu` upstream but are intentionally
**not** included here β€” no Apple or AMD hardware was available to build
or validate them, and this repo only ships backends that were actually
optimized and benchmarked.
Each included backend supports **fp32, fp16, bf16, and int8** (upstream
`kernels-community/relu` is fp32-only). Semantics match upstream exactly,
including `NaN β†’ 0` (not PyTorch's `NaN β†’ NaN`) β€” this is a pre-existing
upstream behavior, intentionally preserved. All backends verified
bit-identical to `torch.nn.functional.relu` on non-NaN inputs.
## Optimizations
### Results at a glance
GPU rows: nsys GPU-kernel duration or the official harness with matched
buffer handling, 3+ passes, correctness-gated (bit-identical to
`F.relu`). Upstream (`kernels-community/relu`) is fp32-only, so other
dtypes have no Hub baseline. **v3 corrects earlier 4090 claims** (fp16/
bf16 "1.85x/1.81x", fp32 "1.20x DRAM") that came from a position-biased
shared-buffer interleave, and fixes a real (32 MiB, L2] launch-config
cliff β€” full story in `L2_BAND_CLIFF.md`; methodology in
`PERFORMANCE.md`.
| target | dtype | vs torch | vs upstream Hub |
|---|---|---|---|
| RTX 4090 (sm_89) | fp32 | ~parity (0.95–1.09x) | 0.96–1.22x L2, parity DRAM |
| RTX 4090 | fp16 / bf16 | 1.17–1.27x base, ~parity large | β€” |
| RTX 4090 | int8 | **1.14–1.37x** | β€” |
| H100 (sm_90) | fp32 | **1.52x** L2, ~parity DRAM | **1.24–1.44x** DRAM |
| H100 | fp16 / bf16 | **1.38x** L2, ~1.0–1.20x DRAM | β€” |
| H100 | int8 | **1.23–1.61x** | β€” |
| CPU (i9-13900K) | fp32/fp16/bf16/int8 | at DRAM bandwidth ceiling | β€” |
| XPU (UHD 770) | fp32/fp16/bf16/int8 | 1.01x / 0.96x / 1.16x / 1.06x | β€” |
### CUDA (sm_70–sm_90, benchmarked on RTX 4090 / Ada and H100 / Hopper)
float4-vectorized, flat grid-stride, scalar tail, arch-adaptive launch:
128-thread blocks below 32 MiB working sets, 512 above; streaming
`__ldcs`/`__stcs` **except** in the pre-Hopper (32 MiB, L2] band, which
uses default loads + streaming stores (v3 fix β€” evict-first loads there
ran 0.34–0.65x vs torch by discarding L2 input residency; see
`L2_BAND_CLIFF.md`), and Hopper+ below 16 MB, which uses unroll-2 /
stream-store-only / 256-thread blocks (+4.6–9.3%, symmetric pairwise
A/B). int8 additionally uses `__vmaxs4` SIMD byte-max. Tuned via
per-arch empirical sweeps, a 5-agent design fan-out, and roofline
analysis (`OPTIMIZATION.md` for sm_89, `H100_BENCHMARK.md` for sm_90 β€”
including which standalone-sweep "wins" failed in-harness verification
and were not shipped).
- **4090 vs `torch.relu`** (v3, fair buffer handling β€” see
`L2_BAND_CLIFF.md` for why v2's shared-buffer interleave numbers were
retracted): fp32 ~parity at every size (0.95–1.09x, both at the ~944
GB/s DRAM wall when DRAM-bound); fp16/bf16 1.17–1.27x at 1024Β²,
~parity at 4096Β²; int8 1.14–1.37x. In the band the v2 kernel lost
2–3x, v3 measures 0.99–1.06x.
- **4090 vs upstream `kernels-community/relu`** (fp32, bit-identical
output): 0.96–1.22x at L2-resident sizes (run-sensitive), parity at
the DRAM wall β€” both kernels saturate GDDR6X there. Upstream's real
gaps are dtype coverage (fp32-only) and the 1-D launch collapse
below.
- fp16/bf16/fp8/int8 element throughput scales with the memory-bound
1/sizeof(dtype) rule: bf16/fp16 β‰ˆ 2x fp32, int8/fp8 β‰ˆ 4x fp32
intrinsically (`DTYPE_THROUGHPUT.md`).
**H100 80GB HBM3 (sm_90)** β€” same method (nsys GPU-kernel duration,
interleaved 1:1, 3 independent passes, `H100_BENCHMARK.md`):
- DRAM-bound, this kernel runs at the HBM3 wall (~3.0 TB/s, ~90% of
peak). The upstream Hub kernel never reaches it (2.2–2.4 TB/s), so
the DRAM-bound margin is real and position-insensitive: **1.24–1.44x
vs upstream** (fp32 4096Β²/8192Β²).
- vs `torch` (separate-buffer symmetric pairs): fp32 **1.52x** at
L2-resident 1024Β², ~parity DRAM-bound (both at the wall); fp16/bf16
**1.38x** at 1024Β², 1.0–1.20x at 4096Β²; int8 **1.23x** at 1024Β²,
**1.61x** at L2-resident 4096Β². The pre-Hopper L2-band cliff does not
occur on Hopper (measured 1.43–1.55x over torch at band sizes with
the streaming config; `L2_BAND_CLIFF.md`).
- Robustness: this kernel's launch is shape-agnostic. The upstream Hub
kernel launches `grid = numel/size(-1)` blocks, which collapses to a
single block on flat 1-D tensors β€” measured **140x slower** than this
kernel at 4096Β² elements on H100 (`relu(x.view(-1))`-shaped calls).
### CPU (benchmarked on i9-13900K)
Rewritten with AVX2, OpenMP, and non-temporal stores; extended to
fp16/bf16/int8. A thread/ILP sweep confirmed the implementation sits at
the memory-bandwidth ceiling rather than being compute- or
thread-count-limited.
### XPU (SYCL, validated on Intel UHD 770 iGPU)
Vectorized to 16 bytes/work-item for coalesced access, extended to
fp16/bf16/int8. Hits the DDR5 bandwidth wall on all dtypes tested;
int8 measured 2.6x the naive (non-vectorized) SYCL implementation.
**Live comparison vs `torch.relu`** (torch 2.12.0+xpu, Intel UHD 770 β€”
a consumer iGPU, not an officially-supported PyTorch XPU tier; both
implementations are bound by the same shared-DDR5 wall, so gains are
modest compared to CUDA/CPU):
| dtype | torch (GB/s) | ours (GB/s) | ratio (ours vs torch) |
|-------|:---:|:---:|:---:|
| fp32 | 40.6 | 40.8 | 1.01x (tied) |
| fp16 | 43.8 | 42.1 | 0.96x (torch ~4% faster) |
| bf16 | 36.6 | 42.5 | 1.16x faster |
| int8 | 78.0 | 82.9 | 1.06x faster |
All four dtypes verified bit-identical to `F.relu`. See `AITESTING.md`
for the environment setup and hardware-driver caveats needed to run
this (a separate `torch==2.12.0+xpu` venv, Level Zero runtime install,
device ACLs, and a CPU-generate-then-copy workaround for an on-device
fp16/bf16 creation bug on this GPU).
## Benchmarks
Official-harness scripts live in `benchmarks/`: `ReluBenchmark` mirrors
upstream's fp32 base/large workloads (directly comparable), and
`ReluDtypeBenchmark` adds the fp16/bf16/int8 workloads upstream lacks.
- Local checkout: `kernels benchmark ./relu-build` (all workloads verify
against `F.relu`).
- Remote (`kernels benchmark SuperexponentialAI/relu --version 3`)
requires this repo to be hosted as a `kernel`-type repo; it is
currently `model`-type (kernel-repo creation is restricted for this
account), so use the local form until it migrates. The same caveat
applies to the `get_kernel` snippet above β€” load via
`snapshot_download` + `sys.path` in the meantime.
`ReluDtypeBenchmark` uses the kernel's preallocated `out=` form and times
the reference the same way β€” the allocating form alternates two live
output blocks and pushes L2-boundary workloads off the L2 cliff for
whichever side allocates (details in `L2_BAND_CLIFF.md`). For pure GPU
kernel time, the nsys numbers above remain the ground truth
(`INVESTIGATION_L2.md`).
Full methodology and results: see `OPTIMIZATION.md`, `DTYPE_THROUGHPUT.md`,
and `INVESTIGATION_L2.md` in this repository.
## Upstream
The original source code for this kernel comes from
[kernels-community/relu](https://huggingface.co/kernels-community/relu).