/* Grouped-int4 (fmt=4) CUDA kernel oracle (#334). * * Feeds random offset-binary nibble weights + [O, ng] group scales through * grouped_hidden_g4_dual / grouped_down_g4 and checks against a CPU reference * that replicates matmul_i4_grouped's semantics (value = nibble - 8, per-group * partial dot x scale). Covers gs=64, a non-divisible tail group, and a * per-row (gs=0) member riding in the same launch — the fmt=2-compat case. * * The device buffers get the same XOR 0x88 offset->signed conversion the * upload path applies, so the kernels are exercised exactly as deployed. * * Build: nvcc -O2 -std=c++17 -arch=native tests/test_grouped_g4_cuda.cu -o tests/test_grouped_g4 */ #include #include #include #include #include #include "../backend_cuda.cu" static void cpu_gemv_g4(const uint8_t *q,const float *sc,int K,int O,int gs, const float *x,float *y){ int rb=(K+1)/2, ng=gs>0?(K+gs-1)/gs:1, egs=gs>0?gs:K; for(int o=0;oK) glen=K-base; double p=0; for(int i=base;i>1]; int n=(i&1)?(v>>4):(v&15); p+=(double)x[i]*(n-8); } a+=p*scl[g]; } y[o]=(float)a; } } int main(void){ srand(7); const int D=200, I=96, gs=64; /* tail group: 200 % 64 = 8 */ const int COUNT=3; /* expert 0,1: fmt4 gs=64; expert 2: per-row (gs=0) */ const int rbD=(D+1)/2, rbI=(I+1)/2; const int ngD=(D+gs-1)/gs, ngI=(I+gs-1)/gs; int trials=50, bad=0; for(int t=0;t>>(qg[c],(size_t)I*rbD); offset_to_signed_s4<<<64,256>>>(qu[c],(size_t)I*rbD); offset_to_signed_s4<<<64,256>>>(qd[c],(size_t)D*rbI); cudaMemcpy(sg[c],hgs[c],(size_t)I*cngD*4,cudaMemcpyHostToDevice); cudaMemcpy(su[c],hus[c],(size_t)I*cngD*4,cudaMemcpyHostToDevice); cudaMemcpy(sd[c],hds[c],(size_t)D*cngI*4,cudaMemcpyHostToDevice); host[c]={qg[c],qu[c],qd[c],sg[c],su[c],sd[c],4,4,4,1,c,cgs,cgs,cgs}; } for(size_t i=0;i<(size_t)COUNT*D;i++) xs[i]=(rand()/(float)RAND_MAX-.5f)*2.f; GroupDesc *ddesc; cudaMalloc(&ddesc,sizeof(host)); cudaMemcpy(ddesc,host,sizeof(host),cudaMemcpyHostToDevice); dim3 hgd((unsigned)I,1,(unsigned)COUNT),ogd((unsigned)D,1,(unsigned)COUNT); grouped_hidden_g4_dual<<>>(gate,up,xs,ddesc,I,D); grouped_down_g4<<>>(y,gate,ddesc,D,I); if(cudaDeviceSynchronize()!=cudaSuccess){ printf("FAIL cuda\n"); return 1; } for(int c=0;c1e-3f*(fabsf(rg[o])+1e-3f)|| fabsf(up[(size_t)c*I+o]-ru[o])>1e-3f*(fabsf(ru[o])+1e-3f)) bad++; } cpu_gemv_g4(hd[c],hds[c],I,D,cgs,(float*)gate+(size_t)c*I,ry); for(int o=0;o1e-3f*(fabsf(ry[o])+1e-3f)) bad++; } for(int c=0;c