Instructions to use SuperexponentialAI/relu with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Kernels
How to use SuperexponentialAI/relu with Kernels:
# !pip install kernels from kernels import get_kernel kernel = get_kernel("SuperexponentialAI/relu") - Notebooks
- Google Colab
- Kaggle
Optimized relu: cpu/cuda/xpu, 1.2-1.85x faster on RTX 4090, benchmarked vs upstream and torch.relu
e873e70 verified | # ReLU throughput vs dtype on RTX 4090 (sm_89) | |
| ReLU is **memory-bound** (read N + write N, trivial compute). So at the GPU's | |
| byte-bandwidth wall, **element throughput scales as 1/sizeof(dtype)** β precision | |
| choice trades only bytes moved, not compute. Measured two ways (custom CUDA | |
| kernel + `torch.relu`), all correctness-verified. | |
| Harness: `bench/relu_dtype.cu` (custom, covers fp8/int8 that PyTorch has no | |
| ReLU for) and a `torch.relu` cross-check. 128-bit (int4) vectorized loads so every | |
| dtype gets an identical memory access pattern. | |
| ## Result 1 β intrinsic precision effect (DRAM-bound, N=64M, all > L2) | |
| Byte-bandwidth is **dtype-invariant** (~943 GB/s = the wall); element rate = 1/sizeof. | |
| | dtype | bytes | GB/s | Gelem/s | vs fp32 | | |
| |-------|:---:|:---:|:---:|:---:| | |
| | fp64 / int64 | 8 | ~943 | 59 | **0.5Γ** | | |
| | fp32 / int32 | 4 | ~944 | 118 | 1.0Γ | | |
| | **fp16 / bf16** / int16 | 2 | ~944 | 236 | **2.0Γ** | | |
| | **fp8 e4m3 / e5m2** / int8 / uint8 | 1 | ~941 | 471 | **4.0Γ** | | |
| Cross-checked in `torch.relu` @ 64M: fp64 0.50Γ, bf16 2.01Γ, fp16 2.01Γ, int8 4.02Γ | |
| β identical to the custom kernel. fp16 and bf16 are exactly equal (both 2 bytes); | |
| the format (5e10m vs 8e7m) is irrelevant to a memory-bound op. fp8 only measurable | |
| via the custom kernel (`torch.relu` raises NotImplementedError for float8). | |
| ## Result 2 β L2-residency bonus (fixed element count near the 72 MB L2) | |
| At a *fixed element count* where the low-precision working set fits in the 72 MB L2 | |
| but fp32 spills to DRAM, low precision gets an EXTRA super-linear win. `torch.relu` | |
| @ N=16.7M (4096Β²): | |
| | dtype | working set | GB/s | Gelem/s | vs fp32 | regime | | |
| |-------|:---:|:---:|:---:|:---:|:---| | |
| | fp32 | 134 MB | 935 | 117 | 1.0Γ | DRAM (spills) | | |
| | bf16 | 67 MB | 3753 | 938 | **8.0Γ** | **L2-resident** | | |
| | fp16 | 67 MB | 3598 | 900 | 7.7Γ | L2-resident | | |
| | int8 | 34 MB | 3631 | 1816 | **15.5Γ** | L2-resident | | |
| This is two effects stacked: 2Γ (bf16 bytes) Γ ~4Γ (L2 vs DRAM BW). Real activation | |
| tensors that hover around L2 size see exactly this β a strong reason to keep | |
| activations in bf16/fp16. | |
| ## L2-resident pure (custom kernel, N=2M, all fit in L2) | |
| Absolute L2 bandwidth is higher and rises with larger dtypes (more in-flight bytes | |
| per int4 chunk): fp64 ~3.4 TB/s β fp8 ~1.6 TB/s. Element rate still favors small | |
| dtypes (fp8 ~808 vs fp32 ~395 Gelem/s) but sub-linearly, because tiny byte working | |
| sets underutilize the memory system. | |
| ## Takeaways | |
| 1. **bf16/fp16 ReLU = 2Γ fp32 throughput** intrinsically (memory-bound, fewer | |
| bytes), and up to ~8Γ at L2-boundary sizes. fp16 == bf16 for this op. | |
| 2. **fp8/int8 = 4Γ fp32** intrinsically, up to ~15Γ at L2-boundary sizes. | |
| 3. **fp64/int64 = 0.5Γ fp32** β avoid 64-bit for elementwise. | |
| 4. The byte-bandwidth wall (~943 GB/s) is the same for every dtype; you cannot beat | |
| it within one dtype β only move fewer bytes (lower precision) or skip the | |
| round-trip (fusion). | |
| 5. The shipped `kernels-community/relu` kernel is **fp32-only** (`TORCH_CHECK`). | |
| Adding bf16/fp16 (and int8/fp8) would unlock the 2β4Γ shown here for the dtypes | |
| real models actually use; the vectorized + streaming kernel design generalizes | |
| directly (template on T, 16-byte loads, per-element relu). | |
| ## Reproduce | |
| ``` | |
| cd bench && nvcc -arch=sm_89 -O3 -o relu_dtype relu_dtype.cu && ./relu_dtype | |
| ``` | |