char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
26021699b
char/aliceai-t5-moe
1// test-col2im-1d.cpp: validate GGML_OP_COL2IM_1D against ggml_conv_transpose_1d. 2// 3// A ConvTranspose1d factorizes as a GEMM followed by an overlap-add: 4// conv_transpose_1d(w, x) equals col2im_1d(mul_mat(w_perm, x_t), s0, OC, p0) 5// with w_perm the [IC, K*OC] permutation of the [K, OC, IC] kernel and x_t the 6// [IC, T_in] transpose of the [T_in, IC] input. The test derives both alternative 7// layouts from one logical weight and one logical input with graph ops only 8// (permute + cont + reshape), runs the two paths on the CPU backend, and compares 9// them in F32. The F16 and BF16 kernels are exercised by casting the column 10// matrix before the scatter. Cropping (p0 > 0) is checked against the shifted 11// slice of the uncropped reference, which conv_transpose_1d cannot express. 12 13#include "ggml.h" 14#include "ggml-cpu.h" 15 16#include <cmath> 17#include <cstdint> 18#include <cstdio> 19#include <cstring> 20#include <vector> 21 22// One geometry: kernel size, output channels, input length, stride, crop 23struct col2im_case { 24int64_t K ; 25int64_t OC ; 26int64_t T_in ; 27int s0 ; 28int p0 ; 29}; 30 31// Mirrors the eval grid of test-backend-ops 32static const col2im_case CASES []= { 33 {16 ,32 ,197 ,8 ,0 },// kernel = 2*stride, DAC upsampling shape 34 {4 ,3 ,7 ,2 ,0 }, 35 {1 ,5 ,13 ,1 ,0 },// stride 1, no overlap 36 {6 ,4 ,11 ,3 ,1 },// with cropping 37 {2 ,3 ,9 ,3 ,0 },// kernel < stride, gap positions are zeroed 38 {5 ,4 ,11 ,2 ,0 },// kernel not a multiple of stride, alternating overlap 39 {8 ,4 ,13 ,4 ,2 },// padding = stride/2, DAC causal cropping 40 {4 ,3 ,1 ,2 ,0 },// single column, pure kernel unfold 41 {16 ,1 ,197 ,8 ,0 },// OC = 1, mono output stage 42 {1 ,5 ,13 ,3 ,0 },// K = 1 with stride > 1, sparse scatter 43 {8 ,2 ,3 ,2 ,5 },// cropping eats most of the signal, T_out = 2 44}; 45 46// Input channels of the GEMM, shared by every case 47static const int64_t IC = 7 ; 48 49// Deterministic LCG mapped to [-1, 1] 50static uint64_t g_rng = 0x12345678ULL ; 51static float frand (void ) { 52g_rng = g_rng * 6364136223846793005ULL + 1442695040888963407ULL ; 53return (float )((g_rng >>33 )& 0xffffff ) / (float )0x800000 - 1.0f ; 54} 55 56// Read a F32/F16/BF16 tensor back as a flat F32 vector 57static std::vector < float > tensor_to_f32 (const struct ggml_tensor * t ) { 58const int64_t n = ggml_nelements (t ); 59 std::vector < float > out (n ); 60if (t -> type == GGML_TYPE_F32 ) { 61memcpy (out .data (),t -> data ,n * sizeof (float )); 62 }else if (t -> type == GGML_TYPE_F16 ) { 63for (int64_t i = 0 ;i < n ;i ++ ) { 64out [i ]= ggml_fp16_to_fp32 (((const ggml_fp16_t * )t -> data )[i ]); 65 } 66 }else { 67for (int64_t i = 0 ;i < n ;i ++ ) { 68out [i ]= ggml_bf16_to_fp32 (((const ggml_bf16_t * )t -> data )[i ]); 69 } 70 } 71return out ; 72} 73 74// NMSE of the cropped output against the p0 shifted slice of the full reference 75static double nmse_cropped (const float * y ,const float * ref ,int64_t T_out ,int64_t T_ref ,int64_t OC ,int p0 ) { 76double num = 0.0 ; 77double den = 0.0 ; 78for (int64_t oc = 0 ;oc < OC ;oc ++ ) { 79for (int64_t t = 0 ;t < T_out ;t ++ ) { 80const double a = y [t + oc * T_out ]; 81const double b = ref [t + p0 + oc * T_ref ]; 82num += (a - b )* (a - b ); 83den += b * b ; 84 } 85 } 86return num / (den + 1e-30 ); 87} 88 89int main (void ) { 90int fails = 0 ; 91 92for (const col2im_case & c :CASES ) { 93const int64_t T_ref = (c .T_in - 1 )* c .s0 + c .K ; 94const int64_t T_out = T_ref - 2 * c .p0 ; 95 96struct ggml_init_params params = { 97/* .mem_size = */ (size_t )64 <<20 , 98/* .mem_base = */ NULL , 99/* .no_alloc = */ false, 100 }; 101struct ggml_context * ctx = ggml_init (params ); 102 103// One logical weight and one logical input feed both paths 104struct ggml_tensor * w = ggml_new_tensor_3d (ctx ,GGML_TYPE_F32 ,c .K ,c .OC ,IC ); 105struct ggml_tensor * x = ggml_new_tensor_2d (ctx ,GGML_TYPE_F32 ,c .T_in ,IC ); 106for (int64_t i = 0 ;i < ggml_nelements (w );i ++ ) { 107 ((float * )w -> data )[i ]= frand (); 108 } 109for (int64_t i = 0 ;i < ggml_nelements (x );i ++ ) { 110 ((float * )x -> data )[i ]= frand (); 111 } 112 113// Reference path: the native op, uncropped 114struct ggml_tensor * y_ref = ggml_conv_transpose_1d (ctx ,w ,x ,c .s0 ,0 ,1 ); 115 116// Decomposed path: [K, OC, IC] -> [IC, K, OC] -> [IC, K*OC], k fastest inside each oc block 117struct ggml_tensor * w_perm = ggml_cont (ctx ,ggml_permute (ctx ,w ,1 ,2 ,0 ,3 )); 118w_perm = ggml_reshape_2d (ctx ,w_perm ,IC ,c .K * c .OC ); 119struct ggml_tensor * x_t = ggml_cont (ctx ,ggml_transpose (ctx ,x )); 120struct ggml_tensor * col = ggml_mul_mat (ctx ,w_perm ,x_t ); 121struct ggml_tensor * y32 = ggml_col2im_1d (ctx ,col ,c .s0 , (int )c .OC ,c .p0 ); 122 123// Half precision kernels: the same columns cast before the scatter 124struct ggml_tensor * y16 = ggml_col2im_1d (ctx ,ggml_cast (ctx ,col ,GGML_TYPE_F16 ),c .s0 , (int )c .OC ,c .p0 ); 125struct ggml_tensor * ybf = ggml_col2im_1d (ctx ,ggml_cast (ctx ,col ,GGML_TYPE_BF16 ),c .s0 , (int )c .OC ,c .p0 ); 126 127GGML_ASSERT (y_ref -> ne [0 ]== T_ref && y_ref -> ne [1 ]== c .OC ); 128GGML_ASSERT (y32 -> ne [0 ]== T_out && y32 -> ne [1 ]== c .OC ); 129 130struct ggml_cgraph * gf = ggml_new_graph (ctx ); 131ggml_build_forward_expand (gf ,y_ref ); 132ggml_build_forward_expand (gf ,y32 ); 133ggml_build_forward_expand (gf ,y16 ); 134ggml_build_forward_expand (gf ,ybf ); 135ggml_graph_compute_with_ctx (ctx ,gf ,4 ); 136 137const std::vector < float > f32 = tensor_to_f32 (y32 ); 138const std::vector < float > f16 = tensor_to_f32 (y16 ); 139const std::vector < float > fbf = tensor_to_f32 (ybf ); 140const float * ref = (const float * )y_ref -> data ; 141 142const double e32 = nmse_cropped (f32 .data (),ref ,T_out ,T_ref ,c .OC ,c .p0 ); 143const double e16 = nmse_cropped (f16 .data (),ref ,T_out ,T_ref ,c .OC ,c .p0 ); 144const double ebf = nmse_cropped (fbf .data (),ref ,T_out ,T_ref ,c .OC ,c .p0 ); 145 146// Same thresholds as test-backend-ops: 1e-7 full precision, 5e-4 half 147const bool ok = e32 <=1e-7 && e16 <=5e-4 && ebf <=5e-4 ; 148if (!ok ) { 149fails ++ ; 150 } 151printf ("col2im_1d K=%2d OC=%2d T_in=%3d s0=%d p0=%d: nmse f32=%.2e f16=%.2e bf16=%.2e %s\n" , 152 (int )c .K , (int )c .OC , (int )c .T_in ,c .s0 ,c .p0 ,e32 ,e16 ,ebf ,ok ?"OK" :"FAIL" ); 153 154ggml_free (ctx ); 155 } 156 157printf (fails == 0 ?"all col2im_1d checks passed\n" :"%d col2im_1d checks FAILED\n" ,fails ); 158return fails == 0 ?0 :1 ; 159}