char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
98d2d2884
char/aliceai-t5-moe
1// ABOUTME: Yasa2 vision encoder graph builder for ConvNeXt-based architecture. 2// ABOUTME: Implements patch embedding, ConvNeXt stages with GRN, and adaptive pooling. 3 4#include "models.h" 5 6static ggml_tensor * add_channel_bias ( 7ggml_context * ctx0 , 8ggml_tensor * x_whcb , 9ggml_tensor * b_c ) { 10if (!b_c ) { 11return x_whcb ; 12 } 13ggml_tensor * b4 = ggml_reshape_4d (ctx0 ,b_c ,1 ,1 ,b_c -> ne [0 ],1 ); 14return ggml_add (ctx0 ,x_whcb ,b4 ); 15} 16 17static ggml_tensor * mul_channel_weight ( 18ggml_context * ctx0 , 19ggml_tensor * x_whcb , 20ggml_tensor * w_c ) { 21if (!w_c ) { 22return x_whcb ; 23 } 24ggml_tensor * w4 = ggml_reshape_4d (ctx0 ,w_c ,1 ,1 ,w_c -> ne [0 ],1 ); 25return ggml_mul (ctx0 ,x_whcb ,w4 ); 26} 27 28ggml_tensor * clip_graph_yasa2::layer_norm_channels (ggml_tensor * inp ,ggml_tensor * w ,ggml_tensor * b ,float eps ) { 29// Match HF ConvNextLayerNorm(channels_first): 30// u = mean_c(x), s = mean_c((x-u)^2), x = (x-u)/sqrt(s+eps) 31// cast back to input dtype before affine. 32ggml_tensor * cur = ggml_permute (ctx0 ,inp ,2 ,1 ,0 ,3 );// [W,H,C,B] -> [C,H,W,B] 33cur = ggml_cont (ctx0 ,cur ); 34 35ggml_tensor * u = ggml_mean (ctx0 ,cur );// [1,H,W,B] 36ggml_tensor * xm = ggml_sub (ctx0 ,cur ,u );// [C,H,W,B] 37 38ggml_tensor * s = ggml_mul (ctx0 ,xm ,xm );// [C,H,W,B] 39s = ggml_mean (ctx0 ,s );// [1,H,W,B] 40s = ggml_clamp (ctx0 ,s ,eps ,1e30f );// avoid div-by-zero in no-alloc warmup 41s = ggml_sqrt (ctx0 ,s );// [1,H,W,B] 42 43ggml_tensor * xhat = ggml_div (ctx0 ,xm ,s );// [C,H,W,B] 44xhat = ggml_permute (ctx0 ,xhat ,2 ,1 ,0 ,3 );// [W,H,C,B] 45xhat = ggml_cont (ctx0 ,xhat ); 46xhat = mul_channel_weight (ctx0 ,xhat ,w ); 47xhat = add_channel_bias (ctx0 ,xhat ,b ); 48return xhat ; 49} 50 51ggml_tensor * clip_graph_yasa2::convnext_grn (ggml_tensor * inp ,ggml_tensor * w ,ggml_tensor * b ) { 52// Exact ConvNeXtV2 GRN: 53// Gx = ||x||_2 over spatial dims (W,H), Nx = Gx / (mean_c(Gx) + eps) 54// y = w * (x * Nx) + b + x 55const int64_t wdim = inp -> ne [0 ]; 56const int64_t hdim = inp -> ne [1 ]; 57const int64_t cdim = inp -> ne [2 ]; 58const int64_t bdim = inp -> ne [3 ]; 59 60// Keep GRN math in fp32 for stability; fp16/bf16 accumulation can drift. 61ggml_tensor * sq = ggml_mul (ctx0 ,inp ,inp ); 62ggml_tensor * sq_flat = ggml_reshape_4d (ctx0 ,sq ,wdim * hdim ,cdim ,1 ,bdim );// [WH,C,1,B] 63ggml_tensor * gx = ggml_sum_rows (ctx0 ,sq_flat );// [1,C,1,B] 64gx = ggml_sqrt (ctx0 ,gx );// [1,C,1,B] 65 66ggml_tensor * gx_ch_first = ggml_permute (ctx0 ,gx ,1 ,0 ,2 ,3 );// [C,1,1,B] 67gx_ch_first = ggml_cont (ctx0 ,gx_ch_first ); 68ggml_tensor * gx_mean = ggml_mean (ctx0 ,gx_ch_first );// [1,1,1,B] 69 70gx_mean = ggml_clamp (ctx0 ,gx_mean ,1e-6f ,1e30f );// approx +eps, warmup-safe 71ggml_tensor * nx = ggml_div (ctx0 ,gx ,gx_mean );// [1,C,1,B] 72nx = ggml_permute (ctx0 ,nx ,0 ,2 ,1 ,3 );// [1,1,C,B] 73nx = ggml_cont (ctx0 ,nx ); 74 75ggml_tensor * xnx = ggml_mul (ctx0 ,inp ,nx ); 76xnx = mul_channel_weight (ctx0 ,xnx ,w ); 77xnx = add_channel_bias (ctx0 ,xnx ,b ); 78return ggml_add (ctx0 ,inp ,xnx ); 79} 80 81ggml_cgraph * clip_graph_yasa2::build () { 82ggml_tensor * cur = build_inp_raw (); 83 84// Patch embedding Conv2d(kernel=4, stride=4) 85cur = ggml_conv_2d (ctx0 ,model .yasa_patch_w ,cur ,patch_size ,patch_size ,0 ,0 ,1 ,1 ); 86cur = add_channel_bias (ctx0 ,cur ,model .yasa_patch_b ); 87ggml_set_name (cur ,"yasa2_patch_conv_out" ); 88cb (cur ,"yasa2_patch_conv_out" ,-1 ); 89cur = layer_norm_channels (cur ,model .yasa_patch_ln_w ,model .yasa_patch_ln_b ,eps ); 90ggml_set_name (cur ,"yasa2_patch_ln_out" ); 91cb (cur ,"yasa2_patch_ln_out" ,-1 ); 92 93// ConvNeXt stages 94for (size_t s = 0 ;s < model .yasa_stages .size ();++ s ) { 95const auto & stage = model .yasa_stages [s ]; 96 97if (stage .down_conv_w ) { 98cur = layer_norm_channels (cur ,stage .down_ln_w ,stage .down_ln_b ,eps ); 99cur = ggml_conv_2d (ctx0 ,stage .down_conv_w ,cur ,2 ,2 ,0 ,0 ,1 ,1 ); 100cur = add_channel_bias (ctx0 ,cur ,stage .down_conv_b ); 101ggml_format_name (cur ,"yasa2_stage%zu_down_out" ,s ); 102 } 103 104for (size_t bi = 0 ;bi < stage .blocks .size ();++ bi ) { 105const auto & blk = stage .blocks [bi ]; 106ggml_tensor * res = cur ; 107 108ggml_tensor * x = ggml_conv_2d_dw (ctx0 ,blk .dw_w ,cur ,1 ,1 ,3 ,3 ,1 ,1 ); 109x = add_channel_bias (ctx0 ,x ,blk .dw_b ); 110x = layer_norm_channels (x ,blk .ln_w ,blk .ln_b ,eps ); 111 112// pwconv1/pwconv2 are HF Linear layers over channels; implement via matmul on tokens. 113const int64_t w = x -> ne [0 ]; 114const int64_t h = x -> ne [1 ]; 115const int64_t b = x -> ne [3 ]; 116 117ggml_tensor * tok = ggml_reshape_3d (ctx0 ,x ,w * h ,x -> ne [2 ],b );// [T,C,B] 118tok = ggml_permute (ctx0 ,tok ,1 ,0 ,2 ,3 );// [C,T,B] 119tok = ggml_cont (ctx0 ,tok ); 120 121tok = ggml_mul_mat (ctx0 ,blk .pw1_w ,tok );// [4C,T,B] 122if (blk .pw1_b ) { 123ggml_tensor * b1 = ggml_reshape_3d (ctx0 ,blk .pw1_b ,blk .pw1_b -> ne [0 ],1 ,1 );// [4C,1,1] 124tok = ggml_add (ctx0 ,tok ,b1 ); 125 } 126x = ggml_permute (ctx0 ,tok ,1 ,0 ,2 ,3 );// [T,4C,B] 127x = ggml_cont (ctx0 ,x ); 128x = ggml_reshape_4d (ctx0 ,x ,w ,h ,tok -> ne [0 ],b );// [W,H,4C,B] 129x = ggml_gelu_erf (ctx0 ,x ); 130x = convnext_grn (x ,blk .grn_w ,blk .grn_b ); 131 132tok = ggml_reshape_3d (ctx0 ,x ,w * h ,x -> ne [2 ],b );// [T,4C,B] 133tok = ggml_permute (ctx0 ,tok ,1 ,0 ,2 ,3 );// [4C,T,B] 134tok = ggml_cont (ctx0 ,tok ); 135 136tok = ggml_mul_mat (ctx0 ,blk .pw2_w ,tok );// [C,T,B] 137if (blk .pw2_b ) { 138ggml_tensor * b2 = ggml_reshape_3d (ctx0 ,blk .pw2_b ,blk .pw2_b -> ne [0 ],1 ,1 );// [C,1,1] 139tok = ggml_add (ctx0 ,tok ,b2 ); 140 } 141x = ggml_permute (ctx0 ,tok ,1 ,0 ,2 ,3 );// [T,C,B] 142x = ggml_cont (ctx0 ,x ); 143x = ggml_reshape_4d (ctx0 ,x ,w ,h ,tok -> ne [0 ],b );// [W,H,C,B] 144 145cur = ggml_add (ctx0 ,res ,x ); 146ggml_format_name (cur ,"yasa2_stage%zu_blk%zu_out" ,s ,bi ); 147 } 148 } 149 150// HF path adds vision position embeddings BEFORE adaptive pooling. 151const int64_t pre_w = cur -> ne [0 ]; 152const int64_t pre_h = cur -> ne [1 ]; 153ggml_tensor * tokens_pre = ggml_reshape_3d (ctx0 ,cur ,pre_w * pre_h ,cur -> ne [2 ],cur -> ne [3 ]);// [T,C,B] 154tokens_pre = ggml_permute (ctx0 ,tokens_pre ,1 ,0 ,2 ,3 );// [C,T,B] 155tokens_pre = ggml_cont (ctx0 ,tokens_pre ); 156if (model .yasa_vision_pos_embed && tokens_pre -> ne [1 ]== model .yasa_vision_pos_embed -> ne [1 ]) { 157const int64_t n_ch = model .yasa_vision_pos_embed -> ne [0 ]; 158const int64_t n_tokens = model .yasa_vision_pos_embed -> ne [1 ]; 159ggml_tensor * pos = ggml_reshape_3d (ctx0 ,model .yasa_vision_pos_embed , (int )n_ch , (int )n_tokens ,1 ); 160tokens_pre = ggml_add (ctx0 ,tokens_pre ,pos ); 161 } 162cur = ggml_permute (ctx0 ,tokens_pre ,1 ,0 ,2 ,3 );// [T,C,B] 163cur = ggml_cont (ctx0 ,cur ); 164cur = ggml_reshape_4d (ctx0 ,cur ,pre_w ,pre_h ,cur -> ne [1 ],cur -> ne [2 ]);// [W,H,C,B] 165 166// AdaptiveAvgPool2d target is 8x8 for real inputs, but warmup can use tiny images. 167const int pooled_w = std::min (8 , (int )cur -> ne [0 ]); 168const int pooled_h = std::min (8 , (int )cur -> ne [1 ]); 169const int kw = std::max (1 , (int )cur -> ne [0 ] /pooled_w ); 170const int kh = std::max (1 , (int )cur -> ne [1 ] /pooled_h ); 171cur = ggml_pool_2d (ctx0 ,cur ,GGML_OP_POOL_AVG ,kw ,kh ,kw ,kh ,0 ,0 ); 172 173// [W,H,C,B] -> [C,T,B] 174ggml_tensor * tokens = ggml_reshape_3d (ctx0 ,cur ,cur -> ne [0 ]* cur -> ne [1 ],cur -> ne [2 ],cur -> ne [3 ]); 175tokens = ggml_permute (ctx0 ,tokens ,1 ,0 ,2 ,3 ); 176tokens = ggml_cont (ctx0 ,tokens ); 177cb (tokens ,"yasa2_tokens" ,-1 ); 178 179GGML_ASSERT (model .mm_0_w && model .mm_2_w ); 180ggml_tensor * embeddings = build_ffn ( 181tokens , 182model .mm_0_w ,model .mm_0_b , 183nullptr ,nullptr , 184model .mm_2_w ,model .mm_2_b , 185FFN_GELU_ERF , 186-1 ); 187cb (embeddings ,"yasa2_emb" ,-1 ); 188 189ggml_build_forward_expand (gf ,embeddings ); 190return gf ; 191}