#include #include #include #include #include using BF = c10::BFloat16; // The positive RMS scale cancels in quantization except for quant_eps. // Keep it in the returned token norm; deliberately omit BF16 intermediates. __global__ void rmsquant_kernel(uint8_t* packed, float* norms, const BF* x, const BF* weight, const int32_t* permutation, const int8_t* signs, const float* boundaries, float rms_eps, float quant_eps) { constexpr int dim=2048; __shared__ float values[dim], raw_sum[256], weighted_sum[256], bounds[15]; const int t=threadIdx.x, row=blockIdx.x; float sx=0, sy=0; for(int j=t;j=32;stride>>=1){ if(t>=1){ raw+=__shfl_down_sync(0xffffffff,raw,stride); weighted+=__shfl_down_sync(0xffffffff,weighted,stride); } if(t==0){raw_sum[0]=raw;weighted_sum[0]=weighted;} } __syncthreads(); float scale=rsqrtf(raw_sum[0]/float(dim)+rms_eps); float norm=sqrtf(weighted_sum[0]); if(t==0)norms[row]=norm*scale; float inv=1.f/(norm+quant_eps/scale); float local[8]; #pragma unroll for(int i=0;i<8;i++)local[i]=values[t+256*i]*inv; // The first five Hadamard stages stay inside each warp. #pragma unroll for(int width=1;width<32;width<<=1){ #pragma unroll for(int i=0;i<8;i++){ float other=__shfl_xor_sync(0xffffffff,local[i],width); local[i]=(t&width)?other-local[i]:local[i]+other; } } #pragma unroll for(int i=0;i<8;i++)values[t+256*i]=local[i]; __syncthreads(); // Only three stages exchange values across warps. for(int width=32;width<=128;width<<=1){ for(int b=t;bbounds[7]?8:0; index+=v>bounds[index+3]?4:0; index+=v>bounds[index+1]?2:0; index+=v>bounds[index]?1:0; codes[k]=index; } packed[row*(dim/2)+j]=codes[0]|(codes[1]<<4); } } void rmsquant(torch::Tensor &packed, torch::Tensor &norms, torch::Tensor const &x, torch::Tensor const &weight, torch::Tensor const &permutation, torch::Tensor const &signs, torch::Tensor const &boundaries, double rms_eps, double quant_eps) { TORCH_CHECK(x.is_cuda() && x.is_contiguous() && x.scalar_type()==torch::kBFloat16 && x.dim()==2 && x.size(1)==2048,"requires contiguous CUDA BF16 [rows,2048]"); for(auto* t:{&weight,&permutation,&signs,&boundaries}) TORCH_CHECK(t->device()==x.device() && t->is_contiguous() && t->dim()==1,"invalid constant device/layout"); TORCH_CHECK(weight.scalar_type()==torch::kBFloat16 && weight.numel()==2048,"invalid RMS weight"); TORCH_CHECK(permutation.scalar_type()==torch::kInt && permutation.numel()==2048,"invalid permutation"); TORCH_CHECK(signs.scalar_type()==torch::kChar && signs.numel()==2048,"invalid signs"); TORCH_CHECK(boundaries.scalar_type()==torch::kFloat && boundaries.numel()==15,"invalid boundaries"); TORCH_CHECK(packed.device()==x.device() && packed.is_contiguous() && packed.scalar_type()==torch::kUInt8 && packed.dim()==2 && packed.size(0)==x.size(0) && packed.size(1)==1024,"invalid packed output"); TORCH_CHECK(norms.device()==x.device() && norms.is_contiguous() && norms.scalar_type()==torch::kFloat && norms.dim()==1 && norms.numel()==x.size(0),"invalid norm output"); TORCH_CHECK(std::isfinite(rms_eps) && rms_eps>0 && std::isfinite(quant_eps) && quant_eps>0,"epsilons must be finite and positive"); const at::cuda::OptionalCUDAGuard guard(device_of(x)); if(!x.size(0))return; rmsquant_kernel<<>>(packed.data_ptr(),norms.data_ptr(), x.data_ptr(),weight.data_ptr(),permutation.data_ptr(),signs.data_ptr(), boundaries.data_ptr(),rms_eps,quant_eps); C10_CUDA_KERNEL_LAUNCH_CHECK(); }