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 | // RTX 4090 (sm_89) float32 ReLU design-space sweep. | |
| // Sweeps vector width x unroll x store-policy x load-policy x block size across | |
| // tensor sizes, verifies correctness, reports best effective bandwidth per size. | |
| __device__ __forceinline__ float relu1(float x){ return x > 0.0f ? x : 0.0f; } | |
| template<int STORE> __device__ __forceinline__ void st4(float4* p, float4 v){ | |
| if (STORE) __stcs(p, v); else *p = v; | |
| } | |
| template<int LOAD> __device__ __forceinline__ float4 ld4(const float4* p){ | |
| return LOAD ? __ldcs(p) : *p; | |
| } | |
| template<int STORE> __device__ __forceinline__ void st2(float2* p, float2 v){ | |
| if (STORE) __stcs(p, v); else *p = v; | |
| } | |
| template<int LOAD> __device__ __forceinline__ float2 ld2(const float2* p){ | |
| return LOAD ? __ldcs(p) : *p; | |
| } | |
| // ---- float4 kernel, templated unroll/store/load ---- | |
| template<int U,int S,int L> | |
| __global__ void kv4(float4* __restrict__ out, const float4* __restrict__ in, long long n4){ | |
| long long stride=(long long)gridDim.x*blockDim.x; | |
| for(long long b=(long long)blockIdx.x*blockDim.x+threadIdx.x; b<n4; b+=stride*U){ | |
| float4 r[U]; | |
| for(int u=0;u<U;u++){ long long i=b+(long long)u*stride; if(i<n4) r[u]=ld4<L>(in+i); } | |
| for(int u=0;u<U;u++){ r[u].x=relu1(r[u].x); r[u].y=relu1(r[u].y); r[u].z=relu1(r[u].z); r[u].w=relu1(r[u].w); } | |
| for(int u=0;u<U;u++){ long long i=b+(long long)u*stride; if(i<n4) st4<S>(out+i, r[u]); } | |
| } | |
| } | |
| // ---- float2 kernel ---- | |
| template<int U,int S,int L> | |
| __global__ void kv2(float2* __restrict__ out, const float2* __restrict__ in, long long n2){ | |
| long long stride=(long long)gridDim.x*blockDim.x; | |
| for(long long b=(long long)blockIdx.x*blockDim.x+threadIdx.x; b<n2; b+=stride*U){ | |
| float2 r[U]; | |
| for(int u=0;u<U;u++){ long long i=b+(long long)u*stride; if(i<n2) r[u]=ld2<L>(in+i); } | |
| for(int u=0;u<U;u++){ r[u].x=relu1(r[u].x); r[u].y=relu1(r[u].y); } | |
| for(int u=0;u<U;u++){ long long i=b+(long long)u*stride; if(i<n2) st2<S>(out+i, r[u]); } | |
| } | |
| } | |
| // ---- scalar grid-stride reference ---- | |
| __global__ void kscalar(float* __restrict__ out, const float* __restrict__ in, long long n){ | |
| long long stride=(long long)gridDim.x*blockDim.x; | |
| for(long long i=(long long)blockIdx.x*blockDim.x+threadIdx.x; i<n; i+=stride) out[i]=relu1(in[i]); | |
| } | |
| __global__ void ktail(float* out,const float* in,long long start,long long n){ | |
| long long i=start+(long long)blockIdx.x*blockDim.x+threadIdx.x; if(i<n) out[i]=relu1(in[i]); | |
| } | |
| static long long ceil_div(long long a,long long b){ return (a+b-1)/b; } | |
| template<int U,int S,int L> | |
| void launch_v4(float* out,const float* in,long long n,int threads){ | |
| long long n4=n/4, tail=n4*4; | |
| if(n4>0){ long long blk=ceil_div(n4,(long long)threads*U); | |
| kv4<U,S,L><<<(unsigned)std::min<long long>(blk, 1u<<31 - 1), threads>>>((float4*)out,(const float4*)in,n4); } | |
| if(tail<n){ long long b=ceil_div(n-tail,threads); ktail<<<(unsigned)b,threads>>>(out,in,tail,n); } | |
| } | |
| template<int U,int S,int L> | |
| void launch_v2(float* out,const float* in,long long n,int threads){ | |
| long long n2=n/2, tail=n2*2; | |
| if(n2>0){ long long blk=ceil_div(n2,(long long)threads*U); | |
| kv2<U,S,L><<<(unsigned)std::min<long long>(blk, 1u<<31 - 1), threads>>>((float2*)out,(const float2*)in,n2); } | |
| if(tail<n){ long long b=ceil_div(n-tail,threads); ktail<<<(unsigned)b,threads>>>(out,in,tail,n); } | |
| } | |
| void launch_scalar(float* out,const float* in,long long n,int threads){ | |
| // full-ish grid stride: cap blocks to a large number; one pass covers it | |
| long long blk=std::min<long long>(ceil_div(n,threads), 262144); | |
| kscalar<<<(unsigned)blk,threads>>>(out,in,n); | |
| } | |
| struct Cfg { std::string name; int threads; std::function<void(float*,const float*,long long,int)> fn; }; | |
| int main(){ | |
| cudaDeviceProp p; CK(cudaGetDeviceProperties(&p,0)); | |
| printf("GPU %s SMs=%d peakMemClk=%d kHz busWidth=%d-bit\n", p.name, p.multiProcessorCount, p.memoryClockRate, p.memoryBusWidth); | |
| double peak_gbps = 2.0 * p.memoryClockRate * 1e3 * (p.memoryBusWidth/8) / 1e9; // 2x for DDR | |
| printf("theoretical DRAM peak ~%.0f GB/s\n\n", peak_gbps); | |
| std::vector<Cfg> cfgs; | |
| for(int t : {128,256,512}){ | |
| char b[64]; | |
| ADD4(1,0,0,"def") ADD4(2,0,0,"def") ADD4(4,0,0,"def") | |
| ADD4(1,1,0,"st.cs") ADD4(2,1,0,"st.cs") ADD4(4,1,0,"st.cs") | |
| ADD4(1,0,1,"ld.cs") ADD4(1,1,1,"ld+st.cs") ADD4(2,1,1,"ld+st.cs") | |
| } | |
| // a couple of reference points | |
| for(int t : {256,512}){ char b[64]; snprintf(b,64,"v2 u1 def blk%d",t); cfgs.push_back({b,t,launch_v2<1,0,0>}); } | |
| for(int t : {256}){ char b[64]; snprintf(b,64,"v2 u2 st.cs blk%d",t); cfgs.push_back({b,t,launch_v2<2,1,0>}); } | |
| cfgs.push_back({"scalar blk256",256,launch_scalar}); | |
| // sizes (in elements): include 1024^2 and 4096^2 plus a sweep | |
| std::vector<long long> sizes = { 1<<16, 1<<18, 1024LL*1024, 1<<22, 4096LL*4096, 1<<26, 1<<27 }; | |
| const int WARM=50, ITER=200; | |
| for(long long n : sizes){ | |
| size_t bytes=n*sizeof(float); | |
| float *din,*dout; CK(cudaMalloc(&din,bytes)); CK(cudaMalloc(&dout,bytes)); | |
| // init host with mix of + and - (and a few exact patterns) | |
| std::vector<float> h(n); | |
| for(long long i=0;i<n;i++) h[i]= ((i*1103515245u+12345u)&1) ? -float((i%97)-48) : float((i%97)-48); | |
| CK(cudaMemcpy(din,h.data(),bytes,cudaMemcpyHostToDevice)); | |
| double gb = 2.0*bytes/1e9; | |
| printf("=== N=%lld (%.1f MB/array, rw %.1f MB) ===\n", n, bytes/1e6, gb*1e3); | |
| std::string best; double bestbw=0; | |
| for(auto& c : cfgs){ | |
| CK(cudaMemset(dout,0xff,bytes)); | |
| c.fn(dout,din,n,c.threads); CK(cudaGetLastError()); CK(cudaDeviceSynchronize()); | |
| // correctness | |
| std::vector<float> ho(n); CK(cudaMemcpy(ho.data(),dout,bytes,cudaMemcpyDeviceToHost)); | |
| bool ok=true; for(long long i=0;i<n && ok;i++){ float e=h[i]>0?h[i]:0; if(ho[i]!=e) ok=false; } | |
| // timing | |
| for(int w=0;w<WARM;w++) c.fn(dout,din,n,c.threads); | |
| CK(cudaDeviceSynchronize()); | |
| cudaEvent_t a,bb; cudaEventCreate(&a); cudaEventCreate(&bb); | |
| cudaEventRecord(a); | |
| for(int it=0;it<ITER;it++) c.fn(dout,din,n,c.threads); | |
| cudaEventRecord(bb); CK(cudaEventSynchronize(bb)); | |
| float ms=0; cudaEventElapsedTime(&ms,a,bb); ms/=ITER; | |
| double bw=gb/(ms/1e3); | |
| cudaEventDestroy(a); cudaEventDestroy(bb); | |
| printf(" %-22s %7.4f ms %6.0f GB/s %s\n", c.name.c_str(), ms, bw, ok?"ok":"FAIL"); | |
| if(ok && bw>bestbw){ bestbw=bw; best=c.name; } | |
| } | |
| printf(" >> BEST: %s %.0f GB/s (%.1f%% of peak)\n\n", best.c_str(), bestbw, 100*bestbw/peak_gbps); | |
| cudaFree(din); cudaFree(dout); | |
| } | |
| return 0; | |
| } | |