char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
5a6caa05f
char/aliceai-t5-moe
1#include "clip.h" 2#include "clip-impl.h" 3#include "clip-model.h" 4#include "clip-graph.h" 5#include "models/models.h" 6 7#include "ggml.h" 8#include "ggml-cpp.h" 9#include "ggml-alloc.h" 10#include "ggml-backend.h" 11#include "gguf.h" 12 13#include <algorithm> 14#include <cassert> 15#include <cmath> 16#include <cstdlib> 17#include <cstring> 18#include <fstream> 19#include <map> 20#include <random> 21#include <stdexcept> 22#include <unordered_set> 23#include <vector> 24#include <cinttypes> 25#include <limits> 26#include <array> 27#include <functional> 28#include <float.h> 29 30struct clip_logger_state g_logger_state = {clip_log_callback_default ,NULL }; 31 32//#define CLIP_DEBUG_FUNCTIONS 33 34#ifdef CLIP_DEBUG_FUNCTIONS 35static void clip_image_write_image_to_ppm (const clip_image_u8 & img ,const std::string & filename ) { 36 std::ofstream file (filename , std::ios::binary ); 37if (!file .is_open ()) { 38LOG_ERR ("Failed to open file for writing: %s\n" ,filename .c_str ()); 39return ; 40 } 41 42// PPM header: P6 format, width, height, and max color value 43const auto ppm_size = img .get_size (); 44file <<"P6\n" <<ppm_size .width <<" " <<ppm_size .height <<"\n255\n" ; 45 46// Write pixel data 47const auto & ppm_buf = img .get_ro_buf (); 48for (size_t i = 0 ;i < ppm_buf .size ();i += 3 ) { 49// PPM expects binary data in RGB format, which matches our image buffer 50file .write (reinterpret_cast < const char *> (& ppm_buf [i ]),3 ); 51 } 52 53file .close (); 54} 55 56static void clip_image_save_to_bmp (const clip_image_u8 & img ,const std::string & filename ) { 57 std::ofstream file (filename , std::ios::binary ); 58if (!file .is_open ()) { 59LOG_ERR ("Failed to open file for writing: %s\n" ,filename .c_str ()); 60return ; 61 } 62 63const auto bmp_size = img .get_size (); 64int fileSize = 54 + 3 * bmp_size .width * bmp_size .height ;// File header + info header + pixel data 65int bytesPerPixel = 3 ; 66int widthInBytes = bmp_size .width * bytesPerPixel ; 67int paddingAmount = (4 - (widthInBytes %4 )) %4 ; 68int stride = widthInBytes + paddingAmount ; 69 70// Bitmap file header 71unsigned char fileHeader [14 ]= { 72'B' ,'M' ,// Signature 730 ,0 ,0 ,0 ,// Image file size in bytes 740 ,0 ,0 ,0 ,// Reserved 7554 ,0 ,0 ,0 // Start of pixel array 76 }; 77 78// Total file size 79fileSize = 54 + (stride * bmp_size .height ); 80fileHeader [2 ]= (unsigned char )(fileSize ); 81fileHeader [3 ]= (unsigned char )(fileSize >>8 ); 82fileHeader [4 ]= (unsigned char )(fileSize >>16 ); 83fileHeader [5 ]= (unsigned char )(fileSize >>24 ); 84 85// Bitmap information header (BITMAPINFOHEADER) 86unsigned char infoHeader [40 ]= { 8740 ,0 ,0 ,0 ,// Size of this header (40 bytes) 880 ,0 ,0 ,0 ,// Image width 890 ,0 ,0 ,0 ,// Image height 901 ,0 ,// Number of color planes 9124 ,0 ,// Bits per pixel 920 ,0 ,0 ,0 ,// No compression 930 ,0 ,0 ,0 ,// Image size (can be 0 for no compression) 940 ,0 ,0 ,0 ,// X pixels per meter (not specified) 950 ,0 ,0 ,0 ,// Y pixels per meter (not specified) 960 ,0 ,0 ,0 ,// Total colors (color table not used) 970 ,0 ,0 ,0 // Important colors (all are important) 98 }; 99 100// Width and height in the information header 101infoHeader [4 ]= (unsigned char )(bmp_size .width ); 102infoHeader [5 ]= (unsigned char )(bmp_size .width >>8 ); 103infoHeader [6 ]= (unsigned char )(bmp_size .width >>16 ); 104infoHeader [7 ]= (unsigned char )(bmp_size .width >>24 ); 105infoHeader [8 ]= (unsigned char )(bmp_size .height ); 106infoHeader [9 ]= (unsigned char )(bmp_size .height >>8 ); 107infoHeader [10 ]= (unsigned char )(bmp_size .height >>16 ); 108infoHeader [11 ]= (unsigned char )(bmp_size .height >>24 ); 109 110// Write file headers 111file .write (reinterpret_cast < char *> (fileHeader ),sizeof (fileHeader )); 112file .write (reinterpret_cast < char *> (infoHeader ),sizeof (infoHeader )); 113 114// Pixel data 115 std::vector < unsigned char > padding (3 ,0 );// Max padding size to be added to each row 116for (int y = bmp_size .height - 1 ;y >=0 ;-- y ) {// BMP files are stored bottom-to-top 117for (int x = 0 ;x < bmp_size .width ;++ x ) { 118// Each pixel 119const auto px = img .get_pixel (x ,y ); 120unsigned char pixel [3 ]= { 121px [2 ],// BMP stores pixels in BGR format 122px [1 ], 123px [0 ] 124 }; 125file .write (reinterpret_cast < char *> (pixel ),3 ); 126 } 127// Write padding for the row 128file .write (reinterpret_cast < char *> (padding .data ()),paddingAmount ); 129 } 130 131file .close (); 132} 133 134// debug function to convert f32 to u8 135static void clip_image_convert_f32_to_u8 (const clip_image_f32 & src ,clip_image_u8 & dst ) { 136dst .set_size (src .get_size (), false); 137const auto & src_buf = src .get_ro_buf (); 138 std::vector < uint8_t > dst_buf (src .n_elements ()); 139for (size_t i = 0 ;i < src .n_elements ();++ i ) { 140dst_buf [i ]= static_cast < uint8_t > (std::min (std::max (int (src_buf [i ]* 255.0f ),0 ),255 )); 141 } 142dst .cpy_buf (dst_buf ); 143} 144#endif 145 146 147struct clip_ctx { 148clip_model model ; 149 150gguf_context_ptr ctx_gguf ; 151ggml_context_ptr ctx_data ; 152 153 std::vector < uint8_t > buf_compute_meta ; 154 155 std::vector < ggml_backend_t > backend_ptrs ; 156 std::vector < ggml_backend_buffer_type_t > backend_buft ; 157 158ggml_backend_t backend = nullptr ; 159ggml_backend_t backend_cpu = nullptr ; 160ggml_backend_buffer_ptr buf ; 161 162 163int max_nodes = 8192 ; 164ggml_backend_sched_ptr sched ; 165clip_flash_attn_type flash_attn_type = CLIP_FLASH_ATTN_TYPE_AUTO ; 166bool is_allocated = false; 167 168bool debug_output_embeddings = false; 169 170// for measuring memory usage 171bool no_alloc = false; 172 std::map < ggml_backend_dev_t ,size_t > mem_usage ; 173 std::map < ggml_backend_dev_t ,size_t > mem_compute ; 174 175bool support_batch = false; 176 177// for audio gen, reseeded only when the caller asks for another seed 178 std::mt19937 rng {std::random_device {}()}; 179uint32_t rng_seed = UINT32_MAX ; 180 181clip_ctx (clip_context_params & ctx_params ) { 182flash_attn_type = ctx_params .flash_attn_type ; 183no_alloc = ctx_params .no_alloc ; 184backend_cpu = ggml_backend_init_by_type (GGML_BACKEND_DEVICE_TYPE_CPU ,nullptr ); 185if (!backend_cpu ) { 186throw std::runtime_error ("failed to initialize CPU backend" ); 187 } 188if (ctx_params .use_gpu ) { 189if (ctx_params .device != nullptr ) { 190backend = ggml_backend_dev_init (ctx_params .device ,nullptr ); 191if (!backend ) { 192throw std::runtime_error (string_format ("%s: failed to initialize \"%s\" backend\n" , 193__func__ ,ggml_backend_dev_name (ctx_params .device ))); 194 } 195 }else { 196backend = ggml_backend_init_by_type (GGML_BACKEND_DEVICE_TYPE_GPU ,nullptr ); 197backend = backend ?backend :ggml_backend_init_by_type (GGML_BACKEND_DEVICE_TYPE_IGPU ,nullptr ); 198 } 199 } 200 201if (backend ) { 202LOG_INF ("%s: CLIP using %s backend\n" ,__func__ ,ggml_backend_name (backend )); 203backend_ptrs .push_back (backend ); 204backend_buft .push_back (ggml_backend_get_default_buffer_type (backend )); 205 }else { 206backend = backend_cpu ; 207LOG_INF ("%s: CLIP using CPU backend\n" ,__func__ ); 208 } 209 210if (ctx_params .image_min_tokens > 0 ) { 211model .hparams .custom_image_min_tokens = ctx_params .image_min_tokens ; 212 } 213if (ctx_params .image_max_tokens > 0 ) { 214model .hparams .custom_image_max_tokens = ctx_params .image_max_tokens ; 215 } 216 217backend_ptrs .push_back (backend_cpu ); 218backend_buft .push_back (ggml_backend_get_default_buffer_type (backend_cpu )); 219 220sched .reset ( 221ggml_backend_sched_new (backend_ptrs .data (),backend_buft .data (),backend_ptrs .size (),8192 , false, true) 222 ); 223 224if (ctx_params .cb_eval != nullptr ) { 225ggml_backend_sched_set_eval_callback (sched .get (),ctx_params .cb_eval ,ctx_params .cb_eval_user_data ); 226 } 227 228debug_output_embeddings = std::getenv ("MTMD_DEBUG_EMBEDDINGS" )!= nullptr ; 229 } 230 231 ~clip_ctx () { 232ggml_backend_free (backend ); 233if (backend != backend_cpu ) { 234ggml_backend_free (backend_cpu ); 235 } 236 } 237 238// this function is added so that we don't change too much of the existing code 239projector_type proj_type ()const { 240return model .proj_type ; 241 } 242}; 243 244// 245// clip_graph 246// 247 248clip_graph::clip_graph (clip_ctx * ctx ,const clip_image_f32 & img ) : 249model (ctx -> model ), 250hparams (model .hparams ), 251proj_type (ctx -> proj_type ()), 252img (img ), 253patch_size (hparams .patch_size ), 254n_patches_x (img .nx () /patch_size ), 255n_patches_y (img .ny () /patch_size ), 256n_patches (n_patches_x * n_patches_y ), 257n_embd (hparams .n_embd ), 258n_head (hparams .n_head ), 259n_head_kv (hparams .n_head_kv ), 260d_head (hparams .n_embd_head > 0 ?hparams .n_embd_head : (n_head > 0 ?n_embd /n_head :0 )), 261n_layer (hparams .n_layer ), 262n_mmproj_embd (clip_n_mmproj_embd (ctx )), 263eps (hparams .eps ), 264kq_scale (d_head > 0 ?1.0f /sqrtf ((float )d_head ) :0.0f ), 265flash_attn_type (ctx -> flash_attn_type ) { 266struct ggml_init_params params = { 267/*.mem_size =*/ ctx -> buf_compute_meta .size (), 268/*.mem_buffer =*/ ctx -> buf_compute_meta .data (), 269/*.no_alloc =*/ true, 270 }; 271ctx0_ptr .reset (ggml_init (params )); 272ctx0 = ctx0_ptr .get (); 273gf = ggml_new_graph_custom (ctx0 ,ctx -> max_nodes , false); 274} 275 276clip_graph::clip_graph (const clip_graph & parent ) : 277model (parent .model ), 278hparams (parent .hparams ), 279proj_type (parent .proj_type ), 280img (parent .img ), 281patch_size (parent .patch_size ), 282n_patches_x (parent .n_patches_x ), 283n_patches_y (parent .n_patches_y ), 284n_patches (parent .n_patches ), 285n_embd (parent .n_embd ), 286n_head (parent .n_head ), 287n_head_kv (parent .n_head_kv ), 288d_head (parent .d_head ), 289n_layer (parent .n_layer ), 290n_mmproj_embd (parent .n_mmproj_embd ), 291eps (parent .eps ), 292kq_scale (parent .kq_scale ), 293flash_attn_type (parent .flash_attn_type ) { 294// reuse from parent 295ctx0 = parent .ctx0 ; 296gf = parent .gf ; 297} 298 299ggml_tensor * clip_graph::build_mm (ggml_tensor * w ,ggml_tensor * x )const { 300return ggml_mul_mat (ctx0 ,w ,x ); 301} 302 303void clip_graph::cb (ggml_tensor * cur ,const char * name ,int il )const { 304if (il >=0 ) { 305ggml_format_name (cur ,"%s-%d" ,name ,il ); 306 }else { 307ggml_set_name (cur ,name ); 308 } 309} 310 311// siglip2 naflex 312ggml_tensor * clip_graph::resize_position_embeddings (uint32_t interpolation_mode ) { 313ggml_tensor * pos_embd = model .position_embeddings ; 314const int height = img .ny () /patch_size ; 315const int width = img .nx () /patch_size ; 316const uint32_t mode = interpolation_mode ; 317const int n_per_side = (int )std::sqrt (pos_embd -> ne [1 ]); 318 319GGML_ASSERT (pos_embd ); 320 321if (height == n_per_side && width == n_per_side ) { 322return pos_embd ; 323 } 324 325pos_embd = ggml_reshape_3d (ctx0 ,pos_embd ,n_embd ,n_per_side ,n_per_side );// -> (n_embd, n_per_side, n_per_side) 326pos_embd = ggml_permute (ctx0 ,pos_embd ,2 ,0 ,1 ,3 );// -> (n_per_side, n_per_side, n_embd) 327pos_embd = ggml_interpolate (ctx0 ,pos_embd ,width ,height ,n_embd ,1 ,mode );// -> (width, height, n_embd) 328pos_embd = ggml_permute (ctx0 ,pos_embd ,1 ,2 ,0 ,3 );// -> (n_embd, width, height) 329pos_embd = ggml_cont_2d (ctx0 ,pos_embd ,n_embd ,width * height );// -> (n_embd, width * height) 330 331return pos_embd ; 332} 333 334// build vision transformer (ViT) cgraph 335// this function should cover most of the models 336// if your model has specific features, you should probably duplicate this function 337ggml_tensor * clip_graph::build_vit ( 338ggml_tensor * inp , 339int64_t n_pos , 340norm_type norm_t , 341ffn_op_type ffn_t , 342ggml_tensor * learned_pos_embd , 343 std::function < ggml_tensor * (ggml_tensor * ,const clip_layer & )> add_pos , 344const build_vit_opts & opts 345 ) { 346// batch dim: inp is [n_embd, n_pos, B] 347const int64_t B = inp -> ne [2 ]; 348 349if (learned_pos_embd ) { 350inp = ggml_add (ctx0 ,inp ,learned_pos_embd ); 351cb (inp ,"pos_embed" ,-1 ); 352 } 353 354// flatten batch; unflatten again in attention 355inp = ggml_reshape_2d (ctx0 ,inp ,n_embd ,n_pos * B ); 356 357ggml_tensor * inpL = inp ; 358 359// pre-layernorm 360if (model .pre_ln_w ) { 361inpL = build_norm (inpL ,model .pre_ln_w ,model .pre_ln_b ,norm_t ,eps ,-1 ); 362cb (inpL ,"pre_ln" ,-1 ); 363 } 364 365// loop over layers 366for (int il = 0 ;il < n_layer ;il ++ ) { 367auto & layer = model .layers [il ]; 368ggml_tensor * cur = inpL ;// inpL = residual, cur = hidden_states 369 370ggml_tensor * attn_mask = opts .attn_mask ; 371if (opts .attn_mask_layers .size ()> (size_t )il ) { 372attn_mask = opts .attn_mask_layers [il ]; 373 } 374 375// layernorm1 376cur = build_norm (cur ,layer .ln_1_w ,layer .ln_1_b ,norm_t ,eps ,il ); 377cb (cur ,"layer_inp_normed" ,il ); 378 379// self-attention 380 { 381ggml_tensor * Qcur = nullptr ; 382ggml_tensor * Kcur = nullptr ; 383ggml_tensor * Vcur = nullptr ; 384if (layer .qkv_w != nullptr ) { 385// fused qkv 386cur = build_mm (layer .qkv_w ,cur ); 387if (layer .qkv_b != nullptr ) { 388cur = ggml_add (ctx0 ,cur ,layer .qkv_b ); 389 } 390 391// Q/K/V as [d_head, n_head, n_pos, B], the batch stride is cur->nb[1]*n_pos. 392Qcur = ggml_view_4d (ctx0 ,cur ,d_head ,n_head ,n_pos ,B , 393/* nb1 */ ggml_row_size (cur -> type ,d_head ), 394/* nb2 */ cur -> nb [1 ], 395/* nb3 */ cur -> nb [1 ]* n_pos , 396/* offset */ 0 ); 397 398Kcur = ggml_view_4d (ctx0 ,cur ,d_head ,n_head ,n_pos ,B , 399/* nb1 */ ggml_row_size (cur -> type ,d_head ), 400/* nb2 */ cur -> nb [1 ], 401/* nb3 */ cur -> nb [1 ]* n_pos , 402/* offset */ ggml_row_size (cur -> type ,n_head * d_head )); 403 404Vcur = ggml_view_4d (ctx0 ,cur ,d_head ,n_head ,n_pos ,B , 405/* nb1 */ ggml_row_size (cur -> type ,d_head ), 406/* nb2 */ cur -> nb [1 ], 407/* nb3 */ cur -> nb [1 ]* n_pos , 408/* offset */ ggml_row_size (cur -> type ,2 * n_head * d_head )); 409 410if (layer .q_norm ) { 411GGML_ASSERT (layer .q_norm -> ne [0 ]== Qcur -> ne [0 ]); 412Qcur = build_norm (Qcur ,layer .q_norm ,NULL ,norm_t ,eps ,il ); 413cb (Qcur ,"Qcur_norm" ,il ); 414 } 415 416if (layer .k_norm ) { 417GGML_ASSERT (layer .k_norm -> ne [0 ]== Kcur -> ne [0 ]); 418Kcur = build_norm (Kcur ,layer .k_norm ,NULL ,norm_t ,eps ,il ); 419cb (Kcur ,"Kcur_norm" ,il ); 420 } 421 422 }else { 423// separate q, k, v 424Qcur = build_mm (layer .q_w ,cur ); 425if (layer .q_b ) { 426Qcur = ggml_add (ctx0 ,Qcur ,layer .q_b ); 427 } 428 429Kcur = build_mm (layer .k_w ,cur ); 430if (layer .k_b ) { 431Kcur = ggml_add (ctx0 ,Kcur ,layer .k_b ); 432 } 433 434Vcur = build_mm (layer .v_w ,cur ); 435if (layer .v_b ) { 436Vcur = ggml_add (ctx0 ,Vcur ,layer .v_b ); 437 } 438 439// if true, norm must be applied after reshaping to (d_head, n_head, n_pos) 440bool norm_per_head = layer .q_norm && layer .q_norm -> ne [0 ]== d_head ; 441 442if (!norm_per_head ) { 443if (layer .q_norm ) { 444Qcur = build_norm (Qcur ,layer .q_norm ,NULL ,norm_t ,eps ,il ); 445cb (Qcur ,"Qcur_norm" ,il ); 446 } 447if (layer .k_norm ) { 448Kcur = build_norm (Kcur ,layer .k_norm ,NULL ,norm_t ,eps ,il ); 449cb (Kcur ,"Kcur_norm" ,il ); 450 } 451 } 452 453Qcur = ggml_reshape_4d (ctx0 ,Qcur ,d_head ,n_head ,n_pos ,B ); 454Kcur = ggml_reshape_4d (ctx0 ,Kcur ,d_head ,n_head_kv ,n_pos ,B ); 455Vcur = ggml_reshape_4d (ctx0 ,Vcur ,d_head ,n_head_kv ,n_pos ,B ); 456 457if (norm_per_head ) { 458if (layer .q_norm ) { 459Qcur = build_norm (Qcur ,layer .q_norm ,NULL ,norm_t ,eps ,il ); 460cb (Qcur ,"Qcur_norm_per_head" ,il ); 461 } 462if (layer .k_norm ) { 463Kcur = build_norm (Kcur ,layer .k_norm ,NULL ,norm_t ,eps ,il ); 464cb (Kcur ,"Kcur_norm_per_head" ,il ); 465 } 466 } 467 } 468 469cb (Qcur ,"Qcur" ,il ); 470cb (Kcur ,"Kcur" ,il ); 471cb (Vcur ,"Vcur" ,il ); 472 473if (add_pos ) { 474Qcur = add_pos (Qcur ,layer ); 475Kcur = add_pos (Kcur ,layer ); 476cb (Qcur ,"Qcur_pos" ,il ); 477cb (Kcur ,"Kcur_pos" ,il ); 478 } 479 480if (proj_type == PROJECTOR_TYPE_GEMMA4V ) { 481Vcur = ggml_rms_norm (ctx0 ,Vcur ,eps ); 482cb (Vcur ,"Vcur_normed" ,il ); 483 } 484 485// build_attn returns a flat 2D [n_embd, n_pos*B] 486cur = build_attn (layer .o_w ,layer .o_b , 487Qcur ,Kcur ,Vcur ,attn_mask ,kq_scale ,il ); 488cb (cur ,"attn_out" ,il ); 489 } 490 491if (layer .ls_1_w ) { 492cur = ggml_mul (ctx0 ,cur ,layer .ls_1_w ); 493cb (cur ,"attn_out_scaled" ,il ); 494 } 495 496if (layer .attn_post_norm_w ) { 497cur = build_norm (cur ,layer .attn_post_norm_w ,nullptr ,norm_t ,eps ,il ); 498cb (cur ,"attn_post_normed" ,il ); 499 } 500 501// re-add the layer input, e.g., residual 502cur = ggml_add (ctx0 ,cur ,inpL ); 503 504inpL = cur ;// inpL = residual, cur = hidden_states 505 506if (opts .callback_layer_out ) { 507opts .callback_layer_out (cur ,il ); 508 } 509 510cb (cur ,"ffn_inp" ,il ); 511 512// layernorm2 (pre-ffn norm) 513cur = build_norm (cur ,layer .ln_2_w ,layer .ln_2_b ,norm_t ,eps ,il ); 514cb (cur ,"ffn_inp_normed" ,il ); 515 516// ffn 517cur = layer .ff_gate_exps_w 518 ?build_moe_ffn (cur ,layer ,ffn_t ,il ) 519 :build_ffn (cur , 520layer .ff_up_w ,layer .ff_up_b , 521layer .ff_gate_w ,layer .ff_gate_b , 522layer .ff_down_w ,layer .ff_down_b , 523ffn_t ,il ); 524 525cb (cur ,"ffn_out" ,il ); 526 527if (layer .ff_post_norm_w ) { 528cur = build_norm (cur ,layer .ff_post_norm_w ,nullptr ,norm_t ,eps ,il ); 529cb (cur ,"ffn_post_normed" ,il ); 530 } 531 532if (layer .ls_2_w ) { 533cur = ggml_mul (ctx0 ,cur ,layer .ls_2_w ); 534cb (cur ,"ffn_out_scaled" ,il ); 535 } 536 537// residual 2 538cur = ggml_add (ctx0 ,inpL ,cur ); 539cb (cur ,"layer_out" ,il ); 540 541if (layer .ls_out_w ) { 542cur = ggml_mul (ctx0 ,cur ,layer .ls_out_w ); 543cb (cur ,"layer_out_scaled" ,il ); 544 } 545 546inpL = cur ; 547 } 548 549if (model .audio_has_avgpool ()) { 550ggml_tensor * cur = inpL ; 551cur = ggml_transpose (ctx0 ,cur ); 552cur = ggml_cont (ctx0 ,cur ); 553cur = ggml_pool_1d (ctx0 ,cur ,GGML_OP_POOL_AVG ,2 ,2 ,0 ); 554cur = ggml_transpose (ctx0 ,cur ); 555cur = ggml_cont (ctx0 ,cur ); 556inpL = cur ; 557 } 558 559// post-layernorm 560if (model .post_ln_w && !opts .skip_post_ln ) { 561inpL = build_norm (inpL ,model .post_ln_w ,model .post_ln_b ,norm_t ,eps ,-1 ); 562 } 563 564// restore the batch dim 565GGML_ASSERT (inpL -> ne [1 ] %B == 0 ); 566inpL = ggml_reshape_3d (ctx0 ,inpL ,n_embd ,inpL -> ne [1 ] /B ,B ); 567return inpL ; 568} 569 570// build the input after conv2d (inp_raw --> patches) 571// returns tensor with shape [n_embd, n_patches] 572ggml_tensor * clip_graph::build_inp () { 573ggml_tensor * inp_raw = build_inp_raw (); 574ggml_tensor * inp = ggml_conv_2d (ctx0 ,model .patch_embeddings_0 ,inp_raw ,patch_size ,patch_size ,0 ,0 ,1 ,1 ); 575inp = ggml_reshape_3d (ctx0 ,inp ,n_patches ,n_embd ,n_batch ); 576inp = ggml_cont (ctx0 ,ggml_transpose (ctx0 ,inp )); 577if (model .patch_bias ) { 578inp = ggml_add (ctx0 ,inp ,model .patch_bias ); 579cb (inp ,"patch_bias" ,-1 ); 580 } 581return inp ; 582} 583 584ggml_tensor * clip_graph::build_inp_raw (int channels ) { 585ggml_tensor * inp_raw = ggml_new_tensor_4d (ctx0 ,GGML_TYPE_F32 ,img .nx (),img .ny (),channels ,n_batch ); 586ggml_set_name (inp_raw ,"inp_raw" ); 587ggml_set_input (inp_raw ); 588return inp_raw ; 589} 590 591ggml_tensor * clip_graph::build_norm ( 592ggml_tensor * cur , 593ggml_tensor * mw , 594ggml_tensor * mb , 595norm_type type , 596float norm_eps , 597int il )const { 598 599cur = type == NORM_TYPE_RMS 600 ?ggml_rms_norm (ctx0 ,cur ,norm_eps ) 601 :ggml_norm (ctx0 ,cur ,norm_eps ); 602 603if (mw ) { 604cur = ggml_mul (ctx0 ,cur ,mw ); 605cb (cur ,"norm_w" ,il ); 606 } 607 608if (mb ) { 609cur = ggml_add (ctx0 ,cur ,mb ); 610cb (cur ,"norm_b" ,il ); 611 } 612 613return cur ; 614} 615 616ggml_tensor * clip_graph::build_ffn ( 617ggml_tensor * cur , 618ggml_tensor * up , 619ggml_tensor * up_b , 620ggml_tensor * gate , 621ggml_tensor * gate_b , 622ggml_tensor * down , 623ggml_tensor * down_b , 624ffn_op_type type_op , 625int il )const { 626 627ggml_tensor * tmp = up ?build_mm (up ,cur ) :cur ; 628cb (tmp ,"ffn_up" ,il ); 629 630if (up_b ) { 631tmp = ggml_add (ctx0 ,tmp ,up_b ); 632cb (tmp ,"ffn_up_b" ,il ); 633 } 634 635if (gate ) { 636cur = build_mm (gate ,cur ); 637cb (cur ,"ffn_gate" ,il ); 638 639if (gate_b ) { 640cur = ggml_add (ctx0 ,cur ,gate_b ); 641cb (cur ,"ffn_gate_b" ,il ); 642 } 643 }else { 644cur = tmp ; 645 } 646 647// we only support parallel ffn for now 648switch (type_op ) { 649case FFN_SILU : 650if (gate ) { 651cur = ggml_swiglu_split (ctx0 ,cur ,tmp ); 652cb (cur ,"ffn_swiglu" ,il ); 653 }else { 654cur = ggml_silu (ctx0 ,cur ); 655cb (cur ,"ffn_silu" ,il ); 656 }break ; 657case FFN_GELU : 658if (gate ) { 659cur = ggml_geglu_split (ctx0 ,cur ,tmp ); 660cb (cur ,"ffn_geglu" ,il ); 661 }else { 662cur = ggml_gelu (ctx0 ,cur ); 663cb (cur ,"ffn_gelu" ,il ); 664 }break ; 665case FFN_GELU_ERF : 666if (gate ) { 667cur = ggml_geglu_erf_split (ctx0 ,cur ,tmp ); 668cb (cur ,"ffn_geglu_erf" ,il ); 669 }else { 670cur = ggml_gelu_erf (ctx0 ,cur ); 671cb (cur ,"ffn_gelu_erf" ,il ); 672 }break ; 673case FFN_GELU_QUICK : 674if (gate ) { 675cur = ggml_geglu_quick_split (ctx0 ,cur ,tmp ); 676cb (cur ,"ffn_geglu_quick" ,il ); 677 }else { 678cur = ggml_gelu_quick (ctx0 ,cur ); 679cb (cur ,"ffn_gelu_quick" ,il ); 680 }break ; 681case FFN_RELU_SQR : 682 { 683cur = ggml_relu (ctx0 ,cur ); 684cur = ggml_sqr (ctx0 ,cur ); 685cb (cur ,"ffn_relu_sqr" ,il ); 686 }break ; 687 } 688 689if (down ) { 690cur = build_mm (down ,cur ); 691 } 692 693if (down_b ) { 694cb (cur ,"ffn_down" ,il ); 695 } 696 697if (down_b ) { 698cur = ggml_add (ctx0 ,cur ,down_b ); 699 } 700 701return cur ; 702} 703 704// MoE FFN with sigmoid router and normalized top-k weights (dots3note vision) 705// the router runs in fp32; exp_probs_b only affects expert selection, not the weights 706ggml_tensor * clip_graph::build_moe_ffn (ggml_tensor * cur ,const clip_layer & layer ,ffn_op_type type_op ,int il )const { 707const int64_t n_tokens = cur -> ne [1 ]; 708const int64_t n_expert = layer .ff_gate_exps_w -> ne [2 ]; 709const int64_t n_expert_used = std::min ((int64_t )hparams .n_expert_used ,n_expert ); 710GGML_ASSERT (n_expert_used > 0 ); 711GGML_ASSERT (type_op == FFN_SILU ); 712 713ggml_tensor * probs = ggml_sigmoid (ctx0 ,build_mm (layer .ff_gate_inp_w ,cur ));// [n_expert, n_tokens] 714cb (probs ,"ffn_moe_probs" ,il ); 715 716ggml_tensor * sel = layer .ff_exp_probs_b 717 ?ggml_add (ctx0 ,probs ,layer .ff_exp_probs_b ) 718 :probs ; 719ggml_tensor * selected = ggml_top_k (ctx0 ,sel ,n_expert_used );// [n_expert_used, n_tokens] 720 721ggml_tensor * weights = ggml_get_rows (ctx0 , 722ggml_reshape_3d (ctx0 ,probs ,1 ,n_expert ,n_tokens ),selected ); 723weights = ggml_reshape_2d (ctx0 ,weights ,n_expert_used ,n_tokens ); 724weights = ggml_div (ctx0 ,weights ,ggml_sum_rows (ctx0 ,weights )); 725weights = ggml_reshape_3d (ctx0 ,weights ,1 ,n_expert_used ,n_tokens ); 726cb (weights ,"ffn_moe_weights" ,il ); 727 728cur = ggml_reshape_3d (ctx0 ,cur ,cur -> ne [0 ],1 ,n_tokens ); 729ggml_tensor * gate = ggml_mul_mat_id (ctx0 ,layer .ff_gate_exps_w ,cur ,selected );// [n_ff, n_expert_used, n_tokens] 730ggml_tensor * up = ggml_mul_mat_id (ctx0 ,layer .ff_up_exps_w ,cur ,selected ); 731cur = ggml_mul (ctx0 ,ggml_silu (ctx0 ,gate ),up ); 732cur = ggml_mul_mat_id (ctx0 ,layer .ff_down_exps_w ,cur ,selected );// [n_embd, n_expert_used, n_tokens] 733cur = ggml_mul (ctx0 ,cur ,weights ); 734 735// sum over the selected experts 736ggml_tensor * out = nullptr ; 737for (int64_t i = 0 ;i < n_expert_used ;i ++ ) { 738ggml_tensor * v = ggml_view_2d (ctx0 ,cur ,cur -> ne [0 ],n_tokens ,cur -> nb [2 ],i * cur -> nb [1 ]); 739out = out ?ggml_add (ctx0 ,out ,v ) :v ; 740 } 741if (n_expert_used == 1 ) { 742out = ggml_cont (ctx0 ,out ); 743 } 744cb (out ,"ffn_moe_out" ,il ); 745return out ; 746} 747 748ggml_tensor * clip_graph::build_attn ( 749ggml_tensor * wo , 750ggml_tensor * wo_b , 751ggml_tensor * q_cur , 752ggml_tensor * k_cur , 753ggml_tensor * v_cur , 754ggml_tensor * kq_mask , 755float kq_scale , 756int il , 757ggml_tensor * sinks )const { 758// these nodes are added to the graph together so that they are not reordered 759// by doing so, the number of splits in the graph is reduced 760// the order is fixed without the compute flag, so an unselected branch stays out of the compute set 761ggml_build_forward_order (gf ,q_cur ); 762ggml_build_forward_order (gf ,k_cur ); 763ggml_build_forward_order (gf ,v_cur ); 764 765ggml_tensor * q = ggml_permute (ctx0 ,q_cur ,0 ,2 ,1 ,3 ); 766//cb(q, "q", il); 767 768ggml_tensor * k = ggml_permute (ctx0 ,k_cur ,0 ,2 ,1 ,3 ); 769//cb(k, "k", il); 770 771ggml_tensor * cur ; 772 773if (flash_attn_type == CLIP_FLASH_ATTN_TYPE_ENABLED ) { 774ggml_tensor * v = ggml_permute (ctx0 ,v_cur ,0 ,2 ,1 ,3 ); 775 776k = ggml_cast (ctx0 ,k ,GGML_TYPE_F16 ); 777v = ggml_cast (ctx0 ,v ,GGML_TYPE_F16 ); 778if (kq_mask ) { 779kq_mask = ggml_cast (ctx0 ,kq_mask ,GGML_TYPE_F16 ); 780 } 781 782cur = ggml_flash_attn_ext (ctx0 ,q ,k ,v ,kq_mask ,kq_scale ,0.0f ,0.0f ); 783ggml_prec_set_acc (cur ,GGML_PREC_F32 ); 784if (sinks != nullptr ) { 785ggml_flash_attn_ext_add_sinks (cur ,sinks ); 786 } 787 788cur = ggml_reshape_2d (ctx0 ,cur ,cur -> ne [0 ]* cur -> ne [1 ],cur -> ne [2 ]* cur -> ne [3 ]); 789 790 }else { 791ggml_tensor * v = ggml_permute (ctx0 ,v_cur ,1 ,2 ,0 ,3 ); 792v = ggml_cont (ctx0 ,v ); 793 794ggml_tensor * kq = ggml_mul_mat (ctx0 ,k ,q ); 795// F32 may not needed for vision encoders? 796// ggml_prec_set_acc(kq, GGML_PREC_F32); 797 798kq = ggml_soft_max_ext (ctx0 ,kq ,kq_mask ,kq_scale ,0.0f ); 799if (sinks != nullptr ) { 800ggml_soft_max_add_sinks (kq ,sinks ); 801 } 802 803ggml_tensor * kqv = ggml_mul_mat (ctx0 ,v ,kq ); 804cur = ggml_permute (ctx0 ,kqv ,0 ,2 ,1 ,3 ); 805cur = ggml_cont_2d (ctx0 ,cur ,cur -> ne [0 ]* cur -> ne [1 ],cur -> ne [2 ]* cur -> ne [3 ]); 806 } 807 808cb (cur ,"kqv_out" ,il ); 809 810if (wo ) { 811cur = build_mm (wo ,cur ); 812 } 813 814if (wo_b ) { 815cur = ggml_add (ctx0 ,cur ,wo_b ); 816 } 817 818return cur ; 819} 820 821// implementation of the 2D RoPE without adding a new op in ggml 822ggml_tensor * clip_graph::build_rope_2d ( 823ggml_context * ctx0 , 824ggml_tensor * cur , 825ggml_tensor * pos_a ,// first half 826ggml_tensor * pos_b ,// second half 827const float freq_base , 828const bool interleave_freq 829) { 830const int64_t n_dim = cur -> ne [0 ]; 831 832// for example, if we have cur tensor of shape (n_dim=8, n_head, n_pos) 833// we will have a list of 4 inv_freq: 1e-0, 1e-1, 1e-2, 1e-3 834// first half of cur will use 1e-0, 1e-2 (even) 835// second half of cur will use 1e-1, 1e-3 (odd) 836// the trick here is to rotate just half of n_dim, so inv_freq will automatically be even 837// ^ don't ask me why, it's math! -2(2i) / n_dim == -2i / (n_dim/2) 838// then for the second half, we use freq_scale to shift the inv_freq 839// ^ why? replace (2i) with (2i+1) in the above equation 840const float freq_scale_odd = interleave_freq 841 ? std::pow (freq_base , (float )-2 /n_dim ) 842 :1.0 ; 843 844// first half, dims [0, n_dim/2) 845cur = ggml_rope_ext ( 846ctx0 , 847cur , 848pos_a ,// positions 849nullptr ,// freq factors 850n_dim /2 ,// n_dims 8510 ,0 ,freq_base , 8521.0f ,0.0f ,1.0f ,0.0f ,0.0f 853 ); 854 855// second half, dims [n_dim/2, n_dim) 856cur = ggml_rope_ext ( 857ctx0 , 858cur , 859pos_b ,// positions 860nullptr ,// freq factors 861n_dim /2 ,// n_dims 8620 ,0 ,freq_base , 863freq_scale_odd , 8640.0f ,1.0f ,0.0f ,0.0f 865 ); 866cur = ggml_rope_set_offset (cur ,n_dim /2 ); 867 868return cur ; 869} 870 871// Generic function to stack frames for audio processing 872// Abstracts out the StackAudioFrames logic used by ultravox 873ggml_tensor * clip_graph::build_stack (ggml_tensor * cur ,int32_t stack_factor ,int32_t n_embed ) { 874if (stack_factor <=1 ) { 875return cur ; 876 } 877 878int64_t total_elements = ggml_nelements (cur ); 879int64_t stride = n_embed * stack_factor ; 880 881// Calculate padded length 882int64_t padded_len = GGML_PAD (total_elements ,stride ); 883int64_t pad = padded_len - total_elements ; 884 885if (pad > 0 ) { 886// Pad the tensor to make it divisible by stride 887cur = ggml_view_1d (ctx0 ,cur ,total_elements ,0 ); 888cur = ggml_pad (ctx0 ,cur ,pad ,0 ,0 ,0 ); 889 } 890 891// Reshape to [stride, padded_len / stride] 892cur = ggml_view_2d (ctx0 ,cur ,stride ,padded_len /stride , 893ggml_row_size (cur -> type ,stride ),0 ); 894return cur ; 895} 896 897// aka pixel_shuffle / pixel_unshuffle / patch_merger (Kimi-VL) 898// support dynamic resolution 899ggml_tensor * clip_graph::build_patch_merge_permute (ggml_tensor * cur ,int scale_factor ) { 900GGML_ASSERT (scale_factor > 1 ); 901 902const int n_embd = cur -> ne [0 ]; 903int width = img .nx () /patch_size ; 904int height = img .ny () /patch_size ; 905 906// pad width and height to factor 907const int64_t pad_width = CLIP_ALIGN (width ,scale_factor )- width ; 908const int64_t pad_height = CLIP_ALIGN (height ,scale_factor )- height ; 909cur = ggml_reshape_3d (ctx0 ,cur ,n_embd ,width ,height ); 910if (pad_width || pad_height ) { 911cur = ggml_pad (ctx0 ,cur ,0 ,pad_width ,pad_height ,0 ); 912width += pad_width ; 913height += pad_height ; 914 } 915 916// unshuffle h 917cur = ggml_reshape_3d (ctx0 ,cur ,n_embd * scale_factor ,width /scale_factor ,height ); 918cur = ggml_permute (ctx0 ,cur ,0 ,2 ,1 ,3 ); 919 920// unshuffle w 921cur = ggml_cont_3d (ctx0 ,cur ,n_embd * scale_factor * scale_factor ,height /scale_factor ,width /scale_factor ); 922cur = ggml_permute (ctx0 ,cur ,0 ,2 ,1 ,3 ); 923 924cur = ggml_cont_2d (ctx0 ,cur ,cur -> ne [0 ],cur -> ne [1 ]* cur -> ne [2 ]); 925cb (cur ,"pixel_shuffle" ,-1 ); 926 927return cur ; 928} 929 930static std::unique_ptr < clip_graph > clip_get_graph_builder (clip_ctx * ctx ,const clip_image_f32_batch & imgs , 931const clip_encode_params * params = nullptr ) { 932const clip_image_f32 & img = imgs .entries [0 ]; 933 std::unique_ptr < clip_graph > builder ; 934 935switch (ctx -> proj_type ()) { 936case PROJECTOR_TYPE_GEMMA3 : 937case PROJECTOR_TYPE_IDEFICS3 : 938case PROJECTOR_TYPE_LFM2 : 939case PROJECTOR_TYPE_JANUS_PRO : 940case PROJECTOR_TYPE_PHI4 : 941 { 942builder = std::make_unique < clip_graph_siglip > (ctx ,img ); 943 }break ; 944case PROJECTOR_TYPE_GEMMA3NV : 945 { 946builder = std::make_unique < clip_graph_mobilenetv5 > (ctx ,img ); 947 }break ; 948case PROJECTOR_TYPE_GEMMA4V : 949 { 950builder = std::make_unique < clip_graph_gemma4v > (ctx ,img ); 951 }break ; 952case PROJECTOR_TYPE_GEMMA4UV : 953 { 954builder = std::make_unique < clip_graph_gemma4uv > (ctx ,img ); 955 }break ; 956case PROJECTOR_TYPE_PIXTRAL : 957case PROJECTOR_TYPE_LIGHTONOCR : 958 { 959builder = std::make_unique < clip_graph_pixtral > (ctx ,img ); 960 }break ; 961case PROJECTOR_TYPE_DOTS_OCR : 962case PROJECTOR_TYPE_DOTS3NOTE_V :// same ViT + merger; pyramid MoE is handled by build_vit 963 { 964builder = std::make_unique < clip_graph_dotsocr > (ctx ,img ); 965 }break ; 966case PROJECTOR_TYPE_DOTS3NOTE_A : 967 { 968builder = std::make_unique < clip_graph_dots3note_a > (ctx ,img ); 969 }break ; 970case PROJECTOR_TYPE_QWEN2VL : 971case PROJECTOR_TYPE_QWEN25VL : 972 { 973builder = std::make_unique < clip_graph_qwen2vl > (ctx ,img ); 974 }break ; 975case PROJECTOR_TYPE_QWEN3VL : 976 { 977builder = std::make_unique < clip_graph_qwen3vl > (ctx ,img ); 978 }break ; 979case PROJECTOR_TYPE_EXAONE4_5 : 980 { 981builder = std::make_unique < clip_graph_exaone4_5 > (ctx ,img ); 982 }break ; 983case PROJECTOR_TYPE_MIMOVL : 984 { 985builder = std::make_unique < clip_graph_mimovl > (ctx ,img ); 986 }break ; 987case PROJECTOR_TYPE_MINIMAX_M3 : 988 { 989builder = std::make_unique < clip_graph_minimax_m3 > (ctx ,img ); 990 }break ; 991case PROJECTOR_TYPE_MUSE_GLIMMER : 992 { 993builder = std::make_unique < clip_graph_muse_glimmer > (ctx ,img ); 994 }break ; 995case PROJECTOR_TYPE_STEP3VL : 996 { 997builder = std::make_unique < clip_graph_step3vl > (ctx ,img ); 998 }break ; 999case PROJECTOR_TYPE_MINICPMV : 1000 { 1001builder = std::make_unique < clip_graph_minicpmv > (ctx ,img ); 1002 }break ; 1003case PROJECTOR_TYPE_MINICPMV4_6 : 1004 { 1005builder = std::make_unique < clip_graph_minicpmv4_6 > (ctx ,img ); 1006 }break ; 1007case PROJECTOR_TYPE_INTERNVL : 1008 { 1009builder = std::make_unique < clip_graph_internvl > (ctx ,img ); 1010 }break ; 1011case PROJECTOR_TYPE_NEMOTRON_V2_VL : 1012 { 1013builder = std::make_unique < clip_graph_nemotron_v2_vl > (ctx ,img ); 1014 }break ; 1015case PROJECTOR_TYPE_LLAMA4 : 1016 { 1017builder = std::make_unique < clip_graph_llama4 > (ctx ,img ); 1018 }break ; 1019case PROJECTOR_TYPE_ULTRAVOX : 1020case PROJECTOR_TYPE_VOXTRAL : 1021case PROJECTOR_TYPE_QWEN2A : 1022case PROJECTOR_TYPE_GLMA : 1023case PROJECTOR_TYPE_MERALION : 1024case PROJECTOR_TYPE_MUSIC_FLAMINGO : 1025 { 1026builder = std::make_unique < clip_graph_whisper_enc > (ctx ,img ); 1027 }break ; 1028case PROJECTOR_TYPE_KIMIVL : 1029 { 1030builder = std::make_unique < clip_graph_kimivl > (ctx ,img ); 1031 }break ; 1032case PROJECTOR_TYPE_PADDLEOCR : 1033 { 1034builder = std::make_unique < clip_graph_paddleocr > (ctx ,img ); 1035 }break ; 1036case PROJECTOR_TYPE_KIMIK25 : 1037 { 1038builder = std::make_unique < clip_graph_kimik25 > (ctx ,img ); 1039 }break ; 1040case PROJECTOR_TYPE_DEEPSEEK4V : 1041 { 1042builder = std::make_unique < clip_graph_deepseek4v > (ctx ,img ); 1043 }break ; 1044case PROJECTOR_TYPE_COGVLM : 1045 { 1046builder = std::make_unique < clip_graph_cogvlm > (ctx ,img ); 1047 }break ; 1048case PROJECTOR_TYPE_HUNYUANVL : 1049 { 1050builder = std::make_unique < clip_graph_hunyuanvl > (ctx ,img ); 1051 }break ; 1052case PROJECTOR_TYPE_MLP : 1053case PROJECTOR_TYPE_MLP_NORM : 1054case PROJECTOR_TYPE_LDP : 1055case PROJECTOR_TYPE_LDPV2 : 1056case PROJECTOR_TYPE_GLM_EDGE : 1057 { 1058builder = std::make_unique < clip_graph_llava > (ctx ,img ); 1059 }break ; 1060case PROJECTOR_TYPE_DEEPSEEKOCR : 1061 { 1062builder = std::make_unique < clip_graph_deepseekocr > (ctx ,img ); 1063 }break ; 1064case PROJECTOR_TYPE_DEEPSEEKOCR2 : 1065 { 1066builder = std::make_unique < clip_graph_deepseekocr2 > (ctx ,img ); 1067 }break ; 1068case PROJECTOR_TYPE_LFM2A : 1069 { 1070builder = std::make_unique < clip_graph_conformer > (ctx ,img ); 1071 }break ; 1072case PROJECTOR_TYPE_GEMMA4A : 1073 { 1074builder = std::make_unique < clip_graph_gemma4a > (ctx ,img ); 1075 }break ; 1076case PROJECTOR_TYPE_GEMMA4UA : 1077 { 1078builder = std::make_unique < clip_graph_gemma4ua > (ctx ,img ); 1079 }break ; 1080case PROJECTOR_TYPE_GRANITE_SPEECH : 1081 { 1082builder = std::make_unique < clip_graph_granite_speech > (ctx ,img ); 1083 }break ; 1084case PROJECTOR_TYPE_GLM4V : 1085 { 1086builder = std::make_unique < clip_graph_glm4v > (ctx ,img ); 1087 }break ; 1088case PROJECTOR_TYPE_QWEN3A : 1089 { 1090builder = std::make_unique < clip_graph_qwen3a > (ctx ,img ); 1091 }break ; 1092case PROJECTOR_TYPE_MIMO_AUDIO : 1093 { 1094builder = std::make_unique < clip_graph_mimo_audio > (ctx ,img ); 1095 }break ; 1096case PROJECTOR_TYPE_QWEN3TTS_SPKENC : 1097 { 1098builder = std::make_unique < clip_graph_qwen3tts_spkenc > (ctx ,img ); 1099 }break ; 1100case PROJECTOR_TYPE_POCKETTTS_SPKENC : 1101 { 1102builder = std::make_unique < clip_graph_pockettts_spkenc > (ctx ,img ); 1103 }break ; 1104case PROJECTOR_TYPE_POCKETTTS_GEN : 1105 { 1106const auto gen_process = params ?params -> gen_process :CLIP_GEN_PROCESS_GEN_CODE ; 1107const int n_step = ctx -> model .hparams .flow_n_step ; 1108const int64_t n_latent = ctx -> model .gen_input_lin_w -> ne [0 ]; 1109GGML_ASSERT (n_step > 0 ); 1110GGML_ASSERT (n_latent > 0 ); 1111// "inp_feats" takes the caller's buffer as-is, the graph must consume all of it 1112if (params && params -> feats ) { 1113GGML_ASSERT (params -> feats -> size () % (size_t )n_latent == 0 ); 1114GGML_ASSERT (params -> feats -> size () >= (size_t )n_latent ); 1115 } 1116const int n_frames = params && params -> feats ? (int ) (params -> feats -> size () /n_latent ) :1 ; 1117builder = std::make_unique < clip_graph_pockettts_gen > (ctx ,img ,gen_process ,n_step ,n_frames ); 1118 }break ; 1119case PROJECTOR_TYPE_QWEN3TTS_GEN : 1120 { 1121const auto gen_process = params ?params -> gen_process :CLIP_GEN_PROCESS_GEN_CODE ; 1122const int top_k = params ?params -> top_k :50 ; 1123const float top_p = params ?params -> top_p :1.0f ; 1124builder = std::make_unique < clip_graph_qwen3tts_gen > (ctx ,img ,gen_process ,top_k ,top_p ); 1125 }break ; 1126case PROJECTOR_TYPE_YOUTUVL : 1127 { 1128builder = std::make_unique < clip_graph_youtuvl > (ctx ,img ); 1129 }break ; 1130case PROJECTOR_TYPE_YASA2 : 1131 { 1132builder = std::make_unique < clip_graph_yasa2 > (ctx ,img ); 1133 }break ; 1134case PROJECTOR_TYPE_PARAKEET : 1135 { 1136builder = std::make_unique < clip_graph_parakeet > (ctx ,img ); 1137 }break ; 1138case PROJECTOR_TYPE_GRANITE4_VISION : 1139 { 1140builder = std::make_unique < clip_graph_granite4_vision > (ctx ,img ); 1141 }break ; 1142default : 1143GGML_ABORT ("missing cgraph builder" ); 1144 } 1145 1146builder -> img_batch = & imgs ; 1147 1148// TODO [QWEN_VIDEO]: improve this in the future 1149builder -> n_batch = imgs .entries .size (); 1150 1151return builder ; 1152} 1153 1154// 1155// clip_model_loader 1156// 1157 1158struct clip_model_loader { 1159ggml_context_ptr ctx_meta ; 1160gguf_context_ptr ctx_gguf ; 1161 1162 std::string fname ; 1163 1164size_t model_size = 0 ;// in bytes 1165 1166bool has_vision = false; 1167bool has_audio = false; 1168bool has_gen_audio = false; 1169 1170mtmd_progress_callback progress_callback = nullptr ; 1171void * progress_callback_user_data = nullptr ; 1172 1173// TODO @ngxson : we should not pass clip_ctx here, it should be clip_model 1174clip_model_loader (const char * fname , 1175bool skip_tensors = false, 1176mtmd_progress_callback progress_cb = nullptr , 1177void * progress_user_data = nullptr ) 1178 :fname (fname ), 1179progress_callback (progress_cb ), 1180progress_callback_user_data (progress_user_data ) { 1181struct ggml_context * meta = nullptr ; 1182 1183struct gguf_init_params params = { 1184/*.no_alloc = */ true, 1185/*.ctx = */ & meta , 1186 }; 1187 1188ctx_gguf = gguf_context_ptr (gguf_init_from_file (fname ,params )); 1189if (!ctx_gguf .get ()) { 1190throw std::runtime_error (string_format ("%s: failed to load CLIP model from %s. Does this file exist?\n" ,__func__ ,fname )); 1191 } 1192 1193ctx_meta .reset (meta ); 1194 1195const int n_tensors = gguf_get_n_tensors (ctx_gguf .get ()); 1196 1197// print gguf info 1198 { 1199 std::string name ; 1200get_string (KEY_NAME ,name , false); 1201 std::string description ; 1202get_string (KEY_DESCRIPTION ,description , false); 1203LOG_INF ("%s: model name: %s\n" ,__func__ ,name .c_str ()); 1204LOG_INF ("%s: description: %s\n" ,__func__ ,description .c_str ()); 1205LOG_INF ("%s: GGUF version: %d\n" ,__func__ ,gguf_get_version (ctx_gguf .get ())); 1206LOG_INF ("%s: alignment: %zu\n" ,__func__ ,gguf_get_alignment (ctx_gguf .get ())); 1207LOG_INF ("%s: n_tensors: %d\n" ,__func__ ,n_tensors ); 1208LOG_INF ("%s: n_kv: %d\n" ,__func__ , (int )gguf_get_n_kv (ctx_gguf .get ())); 1209LOG_INF ("\n" ); 1210 } 1211 1212// modalities 1213 { 1214get_bool (KEY_HAS_VISION_ENC ,has_vision , false); 1215get_bool (KEY_HAS_AUDIO_ENC ,has_audio , false); 1216get_bool (KEY_HAS_GEN_AUDIO_ENC ,has_gen_audio , false); 1217 1218if (has_vision ) { 1219LOG_INF ("%s: has vision encoder\n" ,__func__ ); 1220 } 1221if (has_audio ) { 1222LOG_INF ("%s: has audio encoder\n" ,__func__ ); 1223 } 1224if (has_gen_audio ) { 1225LOG_INF ("%s: has audio generation (gen) encoder\n" ,__func__ ); 1226 } 1227 } 1228 1229// tensors 1230if (!skip_tensors ) { 1231for (int i = 0 ;i < n_tensors ;++ i ) { 1232const char * name = gguf_get_tensor_name (ctx_gguf .get (),i ); 1233const size_t offset = gguf_get_tensor_offset (ctx_gguf .get (),i ); 1234enum ggml_type type = gguf_get_tensor_type (ctx_gguf .get (),i ); 1235ggml_tensor * cur = ggml_get_tensor (meta ,name ); 1236size_t tensor_size = ggml_nbytes (cur ); 1237model_size += tensor_size ; 1238LOG_DBG ("%s: tensor[%d]: n_dims = %d, name = %s, tensor_size=%zu, offset=%zu, shape:[%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "], type = %s\n" , 1239__func__ ,i ,ggml_n_dims (cur ),cur -> name ,tensor_size ,offset ,cur -> ne [0 ],cur -> ne [1 ],cur -> ne [2 ],cur -> ne [3 ],ggml_type_name (type )); 1240 } 1241 } 1242 } 1243 1244void load_hparams (clip_model & model ,clip_modality modality ) { 1245auto & hparams = model .hparams ; 1246 std::string log_ffn_op ;// for logging 1247 1248// sanity check 1249if (modality == CLIP_MODALITY_VISION ) { 1250GGML_ASSERT (has_vision ); 1251 }else if (modality == CLIP_MODALITY_AUDIO ) { 1252GGML_ASSERT (has_audio ); 1253 }else if (modality == CLIP_MODALITY_GEN_AUDIO ) { 1254GGML_ASSERT (has_gen_audio ); 1255 } 1256model .modality = modality ; 1257 1258 1259// projector type 1260 std::string proj_type ; 1261 { 1262// default key 1263get_string (KEY_PROJ_TYPE ,proj_type , false); 1264 1265// for models with mixed modalities 1266if (proj_type .empty ()) { 1267if (modality == CLIP_MODALITY_VISION ) { 1268get_string (KEY_VISION_PROJ_TYPE ,proj_type , false); 1269 }else if (modality == CLIP_MODALITY_AUDIO ) { 1270get_string (KEY_AUDIO_PROJ_TYPE ,proj_type , false); 1271 }else if (modality == CLIP_MODALITY_GEN_AUDIO ) { 1272get_string (KEY_GEN_AUDIO_PROJ_TYPE ,proj_type , false); 1273 }else { 1274GGML_ABORT ("unknown modality" ); 1275 } 1276 } 1277 1278model .proj_type = clip_projector_type_from_string (proj_type ); 1279 1280if (model .proj_type == PROJECTOR_TYPE_UNKNOWN ) { 1281throw std::runtime_error (string_format ("%s: unknown projector type: %s\n" ,__func__ ,proj_type .c_str ())); 1282 } 1283 1284// correct arch for multimodal models (legacy method) 1285if (model .proj_type == PROJECTOR_TYPE_QWEN25O ) { 1286model .proj_type = modality == CLIP_MODALITY_VISION 1287 ?PROJECTOR_TYPE_QWEN25VL 1288 :PROJECTOR_TYPE_QWEN2A ; 1289 } 1290 } 1291 1292const bool is_vision = model .modality == CLIP_MODALITY_VISION ; 1293const bool is_audio = model .modality == CLIP_MODALITY_AUDIO ; 1294const bool is_gen_audio = model .modality == CLIP_MODALITY_GEN_AUDIO ; 1295 1296// other hparams 1297 { 1298const char * prefix = is_vision ?"vision" : (is_audio ?"audio" :"gen.audio" ); 1299get_u32 (string_format (KEY_N_EMBD ,prefix ),hparams .n_embd ); 1300get_u32 (string_format (KEY_N_HEAD ,prefix ),hparams .n_head ); 1301get_u32 (string_format (KEY_N_EMBD_HEAD ,prefix ),hparams .n_embd_head , false); 1302get_u32 (string_format (KEY_N_FF ,prefix ),hparams .n_ff ); 1303get_u32 (string_format (KEY_N_BLOCK ,prefix ),hparams .n_layer ); 1304get_u32 (string_format (KEY_PROJ_DIM ,prefix ),hparams .projection_dim ); 1305get_f32 (string_format (KEY_LAYER_NORM_EPS ,prefix ),hparams .eps ); 1306 1307// n_head_kv is optional (for GQA), default to n_head 1308hparams .n_head_kv = hparams .n_head ; 1309get_u32 (string_format (KEY_N_HEAD_KV ,prefix ),hparams .n_head_kv , false); 1310 1311if (is_vision ) { 1312get_u32 (KEY_IMAGE_SIZE ,hparams .image_size ); 1313get_u32 (KEY_PATCH_SIZE ,hparams .patch_size ); 1314get_i32 (KEY_MINICPMV_VERSION ,hparams .minicpmv_version , false);// legacy 1315get_u32 (KEY_MINICPMV_QUERY_NUM ,hparams .minicpmv_query_num , false); 1316if (hparams .minicpmv_query_num == 0 ) { 1317// Fallback to hardcoded values for legacy models 1318if (hparams .minicpmv_version == 3 ) { 1319hparams .minicpmv_query_num = 64 ; 1320 }else if (hparams .minicpmv_version == 4 ) { 1321hparams .minicpmv_query_num = 64 ; 1322 }else if (hparams .minicpmv_version == 5 ) { 1323hparams .minicpmv_query_num = 64 ; 1324 }else if (hparams .minicpmv_version == 6 ) { 1325hparams .minicpmv_query_num = 64 ; 1326 }else if (hparams .minicpmv_version == 100045 ) { 1327hparams .minicpmv_query_num = 64 ; 1328 }else { 1329hparams .minicpmv_query_num = 96 ; 1330 } 1331 } 1332 }else if (is_audio ) { 1333get_u32 (KEY_A_NUM_MEL_BINS ,hparams .n_mel_bins ); 1334// some hparams are unused, but still need to set to avoid issues 1335hparams .image_size = 0 ; 1336hparams .patch_size = 1 ; 1337 1338 }else if (is_gen_audio ) { 1339// these are unused, but still need to be set to avoid issues 1340hparams .image_size = 0 ; 1341hparams .patch_size = 1 ; 1342get_string (KEY_GEN_AUDIO_VARIANT ,hparams .gen_model_variant , false); 1343 1344 }else { 1345GGML_ASSERT (false&& "unknown modality" ); 1346 } 1347 1348// for pinpoints, we need to convert it into a list of resolution candidates 1349 { 1350 std::vector < int > pinpoints ; 1351get_arr_int (KEY_IMAGE_GRID_PINPOINTS ,pinpoints , false); 1352if (pinpoints .size () %2 != 0 ) { 1353throw std::runtime_error (string_format ("%s: image_grid_pinpoints must have an even number of elements, got %zu\n" ,__func__ ,pinpoints .size ())); 1354 } 1355if (!pinpoints .empty ()) { 1356for (size_t i = 0 ;i < pinpoints .size ();i += 2 ) { 1357hparams .image_res_candidates .push_back ({ 1358pinpoints [i ], 1359pinpoints [i + 1 ], 1360 }); 1361 } 1362 } 1363 } 1364 1365// default warmup value 1366hparams .warmup_image_size = hparams .image_size ; 1367 1368 { 1369bool use_gelu = false; 1370bool use_silu = false; 1371get_bool (KEY_USE_GELU ,use_gelu , false); 1372get_bool (KEY_USE_SILU ,use_silu , false); 1373if (use_gelu && use_silu ) { 1374throw std::runtime_error (string_format ("%s: both use_gelu and use_silu are set to true\n" ,__func__ )); 1375 } 1376if (use_gelu ) { 1377hparams .ffn_op = FFN_GELU ; 1378log_ffn_op = "gelu" ; 1379 }else if (use_silu ) { 1380hparams .ffn_op = FFN_SILU ; 1381log_ffn_op = "silu" ; 1382 }else { 1383hparams .ffn_op = FFN_GELU_QUICK ; 1384log_ffn_op = "gelu_quick" ; 1385 } 1386 } 1387 1388 { 1389 std::string mm_patch_merge_type ; 1390get_string (KEY_MM_PATCH_MERGE_TYPE ,mm_patch_merge_type , false); 1391if (mm_patch_merge_type == "spatial_unpad" ) { 1392hparams .mm_patch_merge_type = PATCH_MERGE_SPATIAL_UNPAD ; 1393 } 1394 } 1395 1396if (is_vision ) { 1397 std::vector < float > image_mean ; 1398 std::vector < float > image_std ; 1399get_arr_f32 (KEY_IMAGE_MEAN ,image_mean , false); 1400get_arr_f32 (KEY_IMAGE_STD ,image_std , false); 1401if (image_mean .size ()< 3 || image_std .size ()< 3 ) { 1402throw std::runtime_error (string_format ("%s: image_mean/image_std arrays must have at least 3 elements, got %zu and %zu\n" ,__func__ ,image_mean .size (),image_std .size ())); 1403 } 1404for (int i = 0 ;i < 3 ;++ i ) { 1405hparams .image_mean [i ]= image_mean [i ]; 1406hparams .image_std [i ]= image_std [i ]; 1407 } 1408 } 1409 1410// Load the vision/audio feature layer indices if they are explicitly provided 1411// NOTE: gguf conversions should standardize the values of the vision feature layer to 1412// be non-negative, since we use -1 to mark values as unset here. 1413get_arr_int (string_format (KEY_FEATURE_LAYERS ,prefix ),hparams .feature_layers , false); 1414 1415// model-specific params 1416switch (model .proj_type ) { 1417case PROJECTOR_TYPE_MLP : 1418case PROJECTOR_TYPE_MLP_NORM : 1419case PROJECTOR_TYPE_LDP : 1420case PROJECTOR_TYPE_LDPV2 : 1421case PROJECTOR_TYPE_COGVLM : 1422 { 1423hparams .has_llava_projector = model .proj_type != PROJECTOR_TYPE_COGVLM ; 1424hparams .image_pad_color = {122 ,116 ,104 }; 1425if (!hparams .image_res_candidates .empty ()) { 1426hparams .image_resize_pad = PAD_CEIL ; 1427hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1428 }else { 1429// llava-1.6 default params 1430hparams .image_pad_ov = PAD_NONE ; 1431hparams .image_pad_rf = PAD_CEIL ; 1432hparams .image_pad_color_rf = {122 ,116 ,104 }; 1433 } 1434 }break ; 1435case PROJECTOR_TYPE_GLM_EDGE : 1436 { 1437hparams .image_resize_pad = PAD_CEIL ; 1438hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1439 }break ; 1440case PROJECTOR_TYPE_MINICPMV : 1441 { 1442// use default llava-uhd preprocessing params 1443if (hparams .minicpmv_version == 0 ) { 1444hparams .minicpmv_version = 2 ;// default to 2 if not set 1445 } 1446 }break ; 1447case PROJECTOR_TYPE_MINICPMV4_6 : 1448 { 1449// MiniCPM-V 4.6 unified merger projector 1450// ViT merger 2x2 + final merger 2x2 = 4x spatial merge per dimension 1451hparams .n_merge = 4 ; 1452get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1453GGML_ASSERT (hparams .n_merge == 2 || hparams .n_merge == 4 ); 1454 1455// borrow wa_layer_indexes for vit_merger insertion point 1456 std::vector < int > wa_layer_indexes_vec ; 1457get_arr_int (KEY_WIN_ATTN_LAYER_INDEXES ,wa_layer_indexes_vec , false); 1458if (!wa_layer_indexes_vec .empty ()) { 1459hparams .insert_layer_id = wa_layer_indexes_vec [0 ]; 1460 } 1461 }break ; 1462case PROJECTOR_TYPE_INTERNVL : 1463 { 1464// use default llava-uhd preprocessing params 1465// older version of internvl doesn't have min/max tiles, we need to provide default values for them to avoid issues 1466hparams .preproc_min_tiles = 1 ; 1467hparams .preproc_max_tiles = 12 ; 1468get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1469get_u32 (KEY_PREPROC_MIN_TILES ,hparams .preproc_min_tiles , false); 1470get_u32 (KEY_PREPROC_MAX_TILES ,hparams .preproc_max_tiles , false); 1471GGML_ASSERT (hparams .preproc_min_tiles <=hparams .preproc_max_tiles && hparams .preproc_max_tiles < INT32_MAX ); 1472set_internvl_dhr_res_candidates (model ); 1473 }break ; 1474case PROJECTOR_TYPE_NEMOTRON_V2_VL : 1475 { 1476get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1477 }break ; 1478case PROJECTOR_TYPE_PARAKEET : 1479 { 1480get_u32 (KEY_AUDIO_SUBSMPL_FACTOR ,hparams .subsampling_factor ); 1481GGML_ASSERT (hparams .subsampling_factor == 8 && 1482"subsampling_factor must match the conv strides in clip_graph_parakeet::build()" ); 1483get_u32 (KEY_A_CONV_KERNEL_SIZE ,hparams .audio_conv_kernel_size ); 1484GGML_ASSERT (hparams .audio_conv_kernel_size > 0 && hparams .audio_conv_kernel_size %2 == 1 && 1485"audio_conv_kernel_size must be a positive odd integer" ); 1486hparams .audio_chunk_len = 0 ; 1487hparams .audio_sample_rate = 16000 ; 1488hparams .audio_n_fft = 512 ; 1489hparams .audio_window_len = 400 ; 1490hparams .audio_hop_len = 160 ; 1491 }break ; 1492case PROJECTOR_TYPE_IDEFICS3 : 1493 { 1494// use default llava-uhd preprocessing params 1495hparams .image_resize_algo = RESIZE_ALGO_LANCZOS ; 1496get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1497get_u32 (KEY_PREPROC_IMAGE_SIZE ,hparams .image_longest_edge , false); 1498hparams .set_limit_image_tokens (); 1499 }break ; 1500case PROJECTOR_TYPE_LFM2 : 1501 { 1502hparams .image_resize_algo = RESIZE_ALGO_BILINEAR ; 1503hparams .image_resize_algo_rf = RESIZE_ALGO_BILINEAR ; 1504hparams .image_resize_algo_ov = RESIZE_ALGO_BILINEAR ; 1505get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1506// ref: https://huggingface.co/LiquidAI/LFM2.5-VL-1.6B/blob/main/processor_config.json 1507hparams .set_limit_image_tokens (64 ,256 ); 1508 }break ; 1509case PROJECTOR_TYPE_PHI4 : 1510 { 1511hparams .n_merge = 1 ; 1512hparams .image_resize_algo = RESIZE_ALGO_BILINEAR ; 1513get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels ); 1514get_u32 (KEY_IMAGE_MAX_PIXELS ,hparams .image_max_pixels ); 1515hparams .set_warmup_n_tokens (16 * 16 ); 1516 }break ; 1517case PROJECTOR_TYPE_PIXTRAL : 1518 { 1519// ref: https://huggingface.co/mistral-community/pixtral-12b/blob/main/preprocessor_config.json 1520// TODO: verify the image_min_tokens 1521hparams .n_merge = 1 ;// the original pixtral does not use patch merging 1522hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1523hparams .rope_theta = 10000.0f ; 1524get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1525hparams .set_limit_image_tokens (8 ,1024 ); 1526hparams .set_warmup_n_tokens (256 );// avoid OOM on warmup 1527 }break ; 1528case PROJECTOR_TYPE_LIGHTONOCR : 1529 { 1530hparams .n_merge = 1 ; 1531hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1532hparams .rope_theta = 10000.0f ; 1533get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1534hparams .image_longest_edge = hparams .image_size ; 1535get_u32 (KEY_PREPROC_IMAGE_SIZE ,hparams .image_longest_edge , false); 1536hparams .set_limit_image_tokens (); 1537hparams .set_warmup_n_tokens (256 );// avoid OOM on warmup 1538 }break ; 1539case PROJECTOR_TYPE_DOTS_OCR : 1540 { 1541hparams .rope_theta = 10000.0f ; 1542get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge ); 1543get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels ); 1544get_u32 (KEY_IMAGE_MAX_PIXELS ,hparams .image_max_pixels ); 1545hparams .set_warmup_n_tokens (46 * 46 );// avoid OOM on warmup 1546 }break ; 1547case PROJECTOR_TYPE_DOTS3NOTE_V : 1548 { 1549hparams .rope_theta = 10000.0f ; 1550hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1551get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge ); 1552get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels ); 1553get_u32 (KEY_IMAGE_MAX_PIXELS ,hparams .image_max_pixels ); 1554get_u32 (KEY_VISION_N_EXPERT_USED ,hparams .n_expert_used ); 1555hparams .set_warmup_n_tokens (46 * 46 );// avoid OOM on warmup 1556 }break ; 1557case PROJECTOR_TYPE_DOTS3NOTE_A : 1558 { 1559hparams .rope_theta = 10000.0f ; 1560hparams .audio_chunk_len = 60 ;// in seconds 1561hparams .audio_sample_rate = 16000 ; 1562hparams .audio_n_fft = 400 ; 1563hparams .audio_window_len = 400 ; 1564hparams .audio_hop_len = 160 ; 1565 }break ; 1566case PROJECTOR_TYPE_KIMIVL : 1567 { 1568hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1569hparams .rope_theta = 10000.0f ; 1570get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1571// TODO: check kimivl preprocessor for exact values 1572hparams .set_limit_image_tokens (8 ,1024 ); 1573hparams .set_warmup_n_tokens (256 );// avoid OOM on warmup 1574 }break ; 1575case PROJECTOR_TYPE_KIMIK25 : 1576 { 1577hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1578hparams .rope_theta = 10000.0f ; 1579get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1580 1581int min_pixels = 0 ,max_pixels = 0 ; 1582get_u32 (KEY_IMAGE_MIN_PIXELS ,min_pixels , false); 1583get_u32 (KEY_IMAGE_MAX_PIXELS ,max_pixels , false); 1584if (min_pixels > 0 && max_pixels > 0 ) { 1585hparams .image_min_pixels = min_pixels ; 1586hparams .image_max_pixels = max_pixels ; 1587hparams .warmup_image_size = static_cast < int > (std::sqrt (max_pixels )); 1588 }else { 1589hparams .set_limit_image_tokens (2 ,4096 ); 1590 } 1591 }break ; 1592case PROJECTOR_TYPE_DEEPSEEK4V : 1593 { 1594hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1595hparams .image_pad_color = {127 ,127 ,127 }; 1596hparams .rope_theta = 10000.0f ; 1597get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge ); 1598get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels ); 1599hparams .dsv4_max_n_token = 384 ; 1600hparams .dsv4_max_wh_ratio = 8 ; 1601const int patch_area = hparams .patch_size * hparams .patch_size * hparams .n_merge * hparams .n_merge ; 1602// handle min/max token counts from CLI 1603if (hparams .custom_image_min_tokens > 0 ) { 1604hparams .image_min_pixels = hparams .custom_image_min_tokens * patch_area ; 1605 } 1606if (hparams .custom_image_max_tokens > 0 ) { 1607// the cap is on the whole token block, keep some room for the resize solver 1608hparams .dsv4_max_n_token = std::max (hparams .custom_image_max_tokens ,16 ); 1609 } 1610hparams .image_max_pixels = hparams .dsv4_max_n_token * patch_area ; 1611// a small custom max token count also lowers the min-pixel upscale threshold 1612hparams .image_min_pixels = std::min (hparams .image_min_pixels ,hparams .image_max_pixels ); 1613// avoid OOM on warmup 1614const int warmup_side = (int ) std::sqrt ((double ) std::min (256 ,hparams .dsv4_max_n_token )); 1615hparams .set_warmup_n_tokens (warmup_side * warmup_side ); 1616 }break ; 1617case PROJECTOR_TYPE_GEMMA3 : 1618 { 1619// default value (used by all model sizes in gemma 3 family) 1620// number of patches for each **side** is reduced by a factor of 4 1621hparams .n_merge = 4 ; 1622hparams .image_resize_algo = RESIZE_ALGO_BILINEAR ; 1623// test model (tinygemma3) has a different value, we optionally read it 1624get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1625 }break ; 1626 1627case PROJECTOR_TYPE_GEMMA4V : 1628case PROJECTOR_TYPE_GEMMA4UV : 1629 { 1630hparams .rope_theta = 100.0f ; 1631hparams .n_merge = 3 ;// pooling_kernel_size 1632hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1633get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1634if (model .proj_type == PROJECTOR_TYPE_GEMMA4UV ) { 1635// for "unified" variant, we directly use a bigger patch size, because the "token merging" is done directly on conv layer 1636hparams .patch_size = hparams .patch_size * hparams .n_merge ; 1637hparams .n_merge = 1 ; 1638 } 1639hparams .set_limit_image_tokens (70 ,1120 ); 1640hparams .set_warmup_n_tokens (256 );// avoid OOM on warmup 1641 }break ; 1642 1643case PROJECTOR_TYPE_GEMMA3NV : 1644 { 1645// Gemma3n uses MobileNetV5 which produces 256 tokens (16x16) 1646// Similar configuration to Gemma3 1647hparams .n_merge = 1 ;// MobileNetV5 handles resizing internally 1648hparams .image_resize_algo = RESIZE_ALGO_BILINEAR ; 1649get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1650 }break ; 1651case PROJECTOR_TYPE_QWEN2VL : 1652case PROJECTOR_TYPE_QWEN25VL : 1653case PROJECTOR_TYPE_QWEN3VL : 1654 { 1655hparams .n_merge = 2 ;// default value for Qwen 2 and 2.5 1656hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1657get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1658get_u32 (KEY_WIN_ATTN_PATTERN ,hparams .n_wa_pattern ,model .proj_type == PROJECTOR_TYPE_QWEN25VL );// only 2.5 requires it 1659// ref: https://huggingface.co/Qwen/Qwen2.5-VL-7B-Instruct/blob/main/preprocessor_config.json 1660hparams .set_limit_image_tokens (8 ,4096 ); 1661hparams .set_warmup_n_tokens (46 * 46 );// avoid OOM on warmup 1662const int warn_min_pixels = 1024 * hparams .n_merge * hparams .n_merge * hparams .patch_size * hparams .patch_size ; 1663if (hparams .image_min_pixels < warn_min_pixels ) { 1664LOG_WRN ("%s: Qwen-VL models require at minimum 1024 image tokens to function correctly on grounding tasks\n" ,__func__ ); 1665LOG_WRN ("%s: if you encounter problems with accuracy, try adding --image-min-tokens 1024\n" ,__func__ ); 1666LOG_WRN ("%s: more info: https://github.com/ggml-org/llama.cpp/issues/16842\n\n" ,__func__ ); 1667 } 1668 }break ; 1669case PROJECTOR_TYPE_MINIMAX_M3 : 1670 { 1671hparams .n_merge = 2 ;// spatial_merge_size 1672hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1673hparams .image_resize_pad = PAD_NONE ; 1674get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1675// n_merge is used as a divisor in clip_image_batch_encode 1676// (gh / n_merge); reject 0 to avoid int div-by-zero (DoS). 1677GGML_ASSERT (hparams .n_merge > 0 ); 1678hparams .rope_theta = 10000.0f ;// vision_config.rope_theta 1679// MiniMax-M3: max_pixels 451584 (=672^2) -> 576 merged tokens (image_seq_length) 1680hparams .set_limit_image_tokens (8 ,576 ); 1681hparams .set_warmup_n_tokens (16 * 16 ); 1682 }break ; 1683case PROJECTOR_TYPE_MUSE_GLIMMER : 1684 { 1685hparams .n_merge = 2 ;// pixel-shuffle downsample after the ViT 1686hparams .image_resize_algo = RESIZE_ALGO_LANCZOS ; 1687hparams .rope_theta = 10000.0f ; 1688hparams .muse_glimmer_patch_temporal = 2 ; 1689hparams .muse_glimmer_sparse_factor = 4 ;// 3 sparse layers + 1 global, repeating 1690get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1691hparams .set_limit_image_tokens (1 ,4096 ); 1692hparams .set_warmup_n_tokens (32 * 32 ); 1693 }break ; 1694case PROJECTOR_TYPE_MIMOVL : 1695 { 1696hparams .n_merge = 2 ;// spatial_merge_size 1697hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1698get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1699get_u32 (string_format (KEY_N_HEAD_KV ,"vision" ),hparams .n_head_kv ); 1700// 1D banded sliding-window radius (visual_token_window_size); required 1701get_u32 (KEY_ATTN_WINDOW_SIZE ,hparams .attn_window_size ); 1702 std::vector < int > pat ; 1703get_arr_int (KEY_WA_PATTERN_MODE ,pat , true); 1704GGML_ASSERT ((int )pat .size ()== hparams .n_layer && "mimovl wa_pattern_mode length must equal n_layer" ); 1705hparams .wa_pattern_mode .assign (pat .begin (),pat .end ()); 1706get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels ); 1707get_u32 (KEY_IMAGE_MAX_PIXELS ,hparams .image_max_pixels ); 1708hparams .set_warmup_n_tokens (46 * 46 );// avoid OOM on warmup 1709 }break ; 1710case PROJECTOR_TYPE_STEP3VL : 1711 { 1712hparams .n_merge = 4 ;// two stride-2 downsamplers after patching 1713get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1714hparams .rope_theta = 10000.0f ; 1715get_u32 (KEY_PREPROC_IMAGE_SIZE ,hparams .image_longest_edge , false); 1716if (hparams .image_longest_edge == 0 ) { 1717hparams .image_longest_edge = 3024 ; 1718 } 1719// note: the step3vl preprocessor slices based on a fixed window grid, so it does not support custom min/max image tokens 1720hparams .warmup_image_size = hparams .image_size ; 1721 }break ; 1722case PROJECTOR_TYPE_YOUTUVL : 1723 { 1724hparams .n_merge = 2 ; 1725hparams .image_resize_algo = RESIZE_ALGO_BILINEAR ; 1726hparams .image_resize_pad = PAD_NONE ; 1727get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1728get_u32 (KEY_ATTN_WINDOW_SIZE ,hparams .attn_window_size , true); 1729 std::vector < int > wa_layer_indexes_vec ; 1730get_arr_int (KEY_WIN_ATTN_LAYER_INDEXES ,wa_layer_indexes_vec , true); 1731for (auto & layer :wa_layer_indexes_vec ) { 1732hparams .wa_layer_indexes .insert (layer ); 1733 } 1734// support max_height * max_width = 8000 * 8000. 8000/16/2 = 250 image tokens 1735hparams .set_limit_image_tokens (1 ,62500 ); 1736hparams .set_warmup_n_tokens (16 * 16 );// avoid OOM on warmup 1737 }break ; 1738case PROJECTOR_TYPE_YASA2 : 1739 { 1740hparams .ffn_op = FFN_GELU_ERF ; 1741log_ffn_op = "gelu_erf" ; 1742hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1743 1744// reka model performs better when the image is stretched to fit 1745// fixed square size (no padding) 1746hparams .image_resize_pad = PAD_NONE ; 1747 }break ; 1748case PROJECTOR_TYPE_GLM4V : 1749 { 1750hparams .rope_theta = 10000.0f ; 1751hparams .n_merge = 2 ;// default value for GLM4-V 1752hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1753get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1754hparams .set_limit_image_tokens (8 ,4096 ); 1755hparams .set_warmup_n_tokens (46 * 46 );// avoid OOM on warmup 1756 }break ; 1757case PROJECTOR_TYPE_LLAMA4 : 1758 { 1759hparams .rope_theta = 10000.0f ; 1760hparams .image_resize_algo = RESIZE_ALGO_BILINEAR ; 1761get_u32 (KEY_PROJ_SCALE_FACTOR ,hparams .n_merge , false); 1762set_llava_uhd_res_candidates (model ,3 ); 1763 }break ; 1764case PROJECTOR_TYPE_ULTRAVOX : 1765case PROJECTOR_TYPE_QWEN2A : 1766case PROJECTOR_TYPE_QWEN3A : 1767case PROJECTOR_TYPE_GLMA : 1768case PROJECTOR_TYPE_VOXTRAL : 1769case PROJECTOR_TYPE_MERALION : 1770case PROJECTOR_TYPE_MUSIC_FLAMINGO : 1771 { 1772bool require_stack = model .proj_type == PROJECTOR_TYPE_ULTRAVOX || 1773model .proj_type == PROJECTOR_TYPE_VOXTRAL || 1774model .proj_type == PROJECTOR_TYPE_MERALION || 1775model .proj_type == PROJECTOR_TYPE_GLMA ; 1776get_u32 (KEY_A_PROJ_STACK_FACTOR ,hparams .proj_stack_factor ,require_stack ); 1777hparams .ffn_op = FFN_GELU_ERF ; 1778log_ffn_op = "gelu_erf" ;// temporary solution for logging 1779 1780// audio preprocessing params 1781hparams .audio_chunk_len = 30 ;// in seconds 1782hparams .audio_sample_rate = 16000 ; 1783hparams .audio_n_fft = 400 ; 1784hparams .audio_window_len = 400 ; 1785hparams .audio_hop_len = 160 ; 1786 }break ; 1787case PROJECTOR_TYPE_MIMO_AUDIO : 1788 { 1789get_u32 (KEY_A_RVQ_NUM_QUANTIZERS ,hparams .rvq_num_quantizers , false); 1790get_arr_int (KEY_A_RVQ_CODEBOOK_SIZE ,hparams .rvq_codebook_size , false); 1791if (hparams .rvq_num_quantizers <=0 ) { 1792throw std::runtime_error (string_format ("%s: mimo_audio: missing %s\n" ,__func__ ,KEY_A_RVQ_NUM_QUANTIZERS )); 1793 } 1794if ((int )hparams .rvq_codebook_size .size ()!= hparams .rvq_num_quantizers ) { 1795throw std::runtime_error (string_format ( 1796"%s: mimo_audio: %s length (%zu) must equal %s (%d)\n" ,__func__ , 1797KEY_A_RVQ_CODEBOOK_SIZE ,hparams .rvq_codebook_size .size (), 1798KEY_A_RVQ_NUM_QUANTIZERS ,hparams .rvq_num_quantizers )); 1799 } 1800hparams .ffn_op = FFN_GELU_ERF ;// PyTorch F.gelu default (approximate="none") 1801hparams .rope_theta = 10000.0f ; 1802 1803// audio preprocessing params (mel spectrogram) 1804hparams .audio_sample_rate = 24000 ; 1805hparams .audio_n_fft = 960 ; 1806hparams .audio_window_len = 960 ; 1807hparams .audio_hop_len = 240 ; 1808 1809get_u32 (KEY_A_ATTN_WINDOW_SIZE ,hparams .attn_window_size ); 1810 std::vector < int > wa_pattern ; 1811get_arr_int (KEY_A_WA_PATTERN_MODE ,wa_pattern , true); 1812if ((int )wa_pattern .size ()!= hparams .n_layer ) { 1813throw std::runtime_error (string_format ( 1814"%s: mimo_audio: %s length (%zu) must equal n_layer (%d)\n" ,__func__ , 1815KEY_A_WA_PATTERN_MODE ,wa_pattern .size (),hparams .n_layer )); 1816 } 1817hparams .wa_pattern_mode .assign (wa_pattern .begin (),wa_pattern .end ()); 1818 1819get_u32 (KEY_A_LOCAL_BLOCK_COUNT ,hparams .audio_local_n_layer ); 1820get_u32 (KEY_A_LOCAL_GROUP_SIZE ,hparams .audio_local_group_size ); 1821if (hparams .audio_local_group_size <=0 ) { 1822throw std::runtime_error (string_format ( 1823"%s: mimo_audio: %s must be > 0\n" ,__func__ ,KEY_A_LOCAL_GROUP_SIZE )); 1824 } 1825 }break ; 1826case PROJECTOR_TYPE_QWEN3TTS_SPKENC : 1827 { 1828// ECAPA-TDNN speaker encoder, mel front-end uses the Slaney default (fmin=0, fmax=sr/2) 1829hparams .audio_sample_rate = 24000 ; 1830hparams .audio_n_fft = 1024 ; 1831hparams .audio_window_len = 1024 ; 1832hparams .audio_hop_len = 256 ; 1833 }break ; 1834case PROJECTOR_TYPE_QWEN3TTS_GEN : 1835 { 1836// TODO: hardcoded for now, read from code_predictor_config instead 1837hparams .rope_theta = 1000000.0f ; 1838 1839// code2wav params 1840hparams .wav_tfm_n_layer = 8 ; 1841hparams .wav_tfm_n_embd = 512 ; 1842hparams .wav_tfm_n_ff = 1024 ; 1843hparams .wav_tfm_n_head = 16 ; 1844hparams .wav_tfm_n_head_kv = 16 ; 1845hparams .wav_tfm_eps = 1e-5f ; 1846hparams .wav_tfm_rope_theta = 10000.0f ; 1847hparams .wav_upsample_n_block = 2 ; 1848hparams .wav_dac_n_block = 4 ; 1849hparams .wav_dac_n_res = 3 ; 1850// matches the reference decoder's sliding_window (speech_tokenizer/config.json) 1851hparams .wav_tfm_swa = 72 ; 1852 }break ; 1853case PROJECTOR_TYPE_POCKETTTS_SPKENC : 1854case PROJECTOR_TYPE_POCKETTTS_GEN : 1855 { 1856// mimi front-end takes the raw waveform, no mel 1857hparams .audio_sample_rate = 24000 ; 1858// seanet ratios are [6,5,4] in the config, the encoder reverses them 1859hparams .seanet_ratios = {4 ,5 ,6 }; 1860hparams .seanet_n_stage = (int32_t )hparams .seanet_ratios .size (); 1861hparams .mimi_downsample = 16 ; 1862// matches the reference transformer's "context" 1863hparams .mimi_tfm_context = 250 ; 1864hparams .rope_theta = 10000.0f ; 1865// flow_lm defaults, see pocket_tts/default_parameters.py 1866hparams .flow_n_step = 1 ; 1867hparams .gen_eos_threshold = -4.0f ; 1868 }break ; 1869case PROJECTOR_TYPE_PADDLEOCR : 1870 { 1871hparams .n_merge = 2 ; 1872hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1873get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels ); 1874get_u32 (KEY_IMAGE_MAX_PIXELS ,hparams .image_max_pixels ); 1875 1876hparams .set_warmup_n_tokens (28 * 28 );// avoid OOM on warmup 1877 }break ; 1878case PROJECTOR_TYPE_DEEPSEEKOCR : 1879case PROJECTOR_TYPE_DEEPSEEKOCR2 : 1880 { 1881hparams .patch_size = 16 ; 1882hparams .image_size = 1024 ; 1883hparams .warmup_image_size = 1024 ; 1884hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1885hparams .image_pad_color = {127 ,127 ,127 }; 1886 1887get_u32 (KEY_SAM_N_BLOCK ,hparams .sam_n_layer , true); 1888get_u32 (KEY_SAM_N_HEAD ,hparams .sam_n_head , true); 1889get_u32 (KEY_SAM_N_EMBD ,hparams .sam_n_embd , true); 1890get_u32 (KEY_ATTN_WINDOW_SIZE ,hparams .attn_window_size , true); 1891hparams .preproc_min_tiles = 2 ; 1892if (model .proj_type == PROJECTOR_TYPE_DEEPSEEKOCR ) { 1893hparams .preproc_max_tiles = 9 ; 1894hparams .preproc_tile_size = 640 ; 1895// the CLIP/ViT body runs its layernorms at 1e-5 (the SAM stage uses 1e-6) 1896hparams .eps = 1e-5f ; 1897 } 1898if (model .proj_type == PROJECTOR_TYPE_DEEPSEEKOCR2 ) { 1899hparams .preproc_max_tiles = 6 ; 1900hparams .preproc_tile_size = 768 ; 1901// qwen2 encoder is GQA, requires KEY_N_HEAD_KV 1902get_u32 (string_format (KEY_N_HEAD_KV ,"vision" ),hparams .n_head_kv ); 1903 } 1904// unlimited-ocr shares the v1 projector but tiles up to 32 1905get_u32 (KEY_PREPROC_MIN_TILES ,hparams .preproc_min_tiles , false); 1906get_u32 (KEY_PREPROC_MAX_TILES ,hparams .preproc_max_tiles , false); 1907GGML_ASSERT (hparams .preproc_min_tiles >=0 1908&& hparams .preproc_min_tiles <=hparams .preproc_max_tiles 1909&& hparams .preproc_max_tiles <=256 ); 1910 }break ; 1911case PROJECTOR_TYPE_HUNYUANVL : 1912 { 1913hparams .n_merge = 2 ; 1914hparams .image_resize_algo = RESIZE_ALGO_LANCZOS ; 1915hparams .image_resize_pad = PAD_NONE ; 1916hparams .ffn_op = FFN_GELU ; 1917hparams .set_limit_image_tokens (256 ,16384 ); 1918get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1919get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels , false); 1920get_u32 (KEY_IMAGE_MAX_PIXELS ,hparams .image_max_pixels , false); 1921hparams .set_warmup_n_tokens (32 * 32 ); 1922 }break ; 1923case PROJECTOR_TYPE_LFM2A : 1924 { 1925// audio preprocessing params 1926hparams .audio_chunk_len = 1 ;// in seconds 1927hparams .audio_sample_rate = 16000 ; 1928hparams .audio_n_fft = 512 ; 1929hparams .audio_window_len = 400 ; 1930hparams .audio_hop_len = 160 ; 1931 }break ; 1932case PROJECTOR_TYPE_EXAONE4_5 : 1933 { 1934hparams .n_merge = 2 ; 1935get_u32 (KEY_SPATIAL_MERGE_SIZE ,hparams .n_merge , false); 1936get_u32 (KEY_WIN_ATTN_PATTERN ,hparams .n_wa_pattern , false); 1937get_u32 (KEY_IMAGE_MIN_PIXELS ,hparams .image_min_pixels ); 1938get_u32 (KEY_IMAGE_MAX_PIXELS ,hparams .image_max_pixels ); 1939hparams .set_warmup_n_tokens (46 * 46 ); 1940if (hparams .rope_theta <=0.0f ) { 1941hparams .rope_theta = 10000.0f ; 1942 } 1943get_u32 (string_format (KEY_N_HEAD_KV ,"vision" ),hparams .n_head_kv ); 1944 }break ; 1945case PROJECTOR_TYPE_GEMMA4A : 1946 { 1947// Gemma4 feature_extraction_gemma4.py: 1948// frame_length_ms=20 -> 320 samples, n_fft=512, hop=10ms -> 160 1949hparams .audio_chunk_len = 0 ;// no fixed-length padding 1950hparams .audio_sample_rate = 16000 ; 1951hparams .audio_n_fft = 512 ; 1952hparams .audio_window_len = 320 ;// 20ms frame (NOT 25ms/400) 1953hparams .audio_hop_len = 160 ; 1954// due to a mistake in the original conversion code, rms_norm_eps is set to a wrong value 1955// since all gemma4a models use 1e-6, we just hardcode it here to avoid re-conversion 1956hparams .eps = 1e-6f ; 1957 }break ; 1958case PROJECTOR_TYPE_GEMMA4UA : 1959 { 1960// Encoder-free: raw 16 kHz waveform chunked into 640-sample frames. 1961hparams .audio_chunk_len = 0 ; 1962hparams .audio_sample_rate = 16000 ; 1963hparams .eps = 1e-6f ; 1964hparams .n_mel_bins = 640 ; 1965 }break ; 1966case PROJECTOR_TYPE_GRANITE_SPEECH : 1967 { 1968hparams .audio_chunk_len = 0 ; 1969hparams .audio_sample_rate = 16000 ; 1970hparams .audio_n_fft = 512 ; 1971hparams .audio_window_len = 400 ; 1972hparams .audio_hop_len = 160 ; 1973get_u32 (KEY_A_CHUNK_SIZE ,hparams .audio_chunk_size ); 1974// context_size is squared for the attn_dists/mask buffers; cap to prevent int32 overflow 1975// (legitimate values are small, e.g. 12-200; 8192^2 = 67M still fits int32) 1976GGML_ASSERT (hparams .audio_chunk_size > 0 && hparams .audio_chunk_size <=8192 ); 1977get_u32 (KEY_A_CONV_KERNEL_SIZE ,hparams .audio_conv_kernel_size ); 1978get_u32 (KEY_A_MAX_POS_EMB ,hparams .audio_max_pos_emb ); 1979get_u32 (KEY_A_PROJ_WINDOW_SIZE ,hparams .audio_proj_window_size ); 1980get_u32 (KEY_A_PROJ_DOWNSAMPLE_RATE ,hparams .audio_proj_downsample_rate ); 1981get_u32 (KEY_A_PROJ_HEAD_COUNT ,hparams .audio_proj_head_count ); 1982// NOTE: feature layers loaded above in common path 1983 }break ; 1984case PROJECTOR_TYPE_JANUS_PRO : 1985 { 1986hparams .image_pad_color = {127 ,127 ,127 }; 1987hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1988 }break ; 1989case PROJECTOR_TYPE_GRANITE4_VISION : 1990 { 1991// SigLIP tower. 1992hparams .image_resize_algo = RESIZE_ALGO_BICUBIC ; 1993hparams .image_resize_pad = PAD_CEIL ; 1994 1995// NOTE: feature_layers loaded in common path as optional 1996get_arr_int (KEY_PROJ_SPATIAL_OFFSETS ,hparams .proj_spatial_offsets ); 1997if (hparams .feature_layers .size ()!= hparams .proj_spatial_offsets .size ()) { 1998throw std::runtime_error (string_format ("%s: feature_layers.size() %d != proj_spatial_offsets.size() %d" , 1999hparams .feature_layers .size (),hparams .proj_spatial_offsets .size ())); 2000 } 2001 2002get_u32 (KEY_PROJ_SAMPLE_QUERY_SIDE ,hparams .downsample_query_side ); 2003get_u32 (KEY_PROJ_SAMPLE_WINDOW_SIDE ,hparams .downsample_window_side ); 2004hparams .warmup_image_size = hparams .image_size ; 2005 }break ; 2006default : 2007throw std::runtime_error (string_format ("%s: unknown vision projector type %s\n" ,__func__ ,proj_type .c_str ())); 2008 } 2009 2010// sanity check 2011 { 2012if (hparams .image_size < 0 ) { 2013// note: some models having hparams.image_size == 0, which means the image size is dynamic 2014throw std::runtime_error (string_format ("%s: image_size (%d) cannot be negative\n" ,__func__ ,hparams .image_size )); 2015 } 2016if (hparams .image_size > 8192 ) { 2017// cap prevents int32 overflow in n_patches = (image_size/patch_size)^2 2018throw std::runtime_error (string_format ("%s: image_size (%d) is too large (max 8192)\n" ,__func__ ,hparams .image_size )); 2019 } 2020if (hparams .patch_size <=0 || hparams .patch_size >=65536 ) { 2021throw std::runtime_error (string_format ("%s: patch_size (%d) must be positive and less than 65536\n" ,__func__ ,hparams .patch_size )); 2022 } 2023if (hparams .n_embd <=0 ) { 2024throw std::runtime_error (string_format ("%s: n_embd (%d) must be greater than 0\n" ,__func__ ,hparams .n_embd )); 2025 } 2026if (hparams .image_max_pixels < hparams .image_min_pixels ) { 2027throw std::runtime_error (string_format ("%s: image_max_pixels (%d) is less than image_min_pixels (%d)\n" ,__func__ ,hparams .image_max_pixels ,hparams .image_min_pixels )); 2028 } 2029if (hparams .n_merge <=0 || hparams .n_merge >=65536 ) { 2030throw std::runtime_error (string_format ("%s: n_merge (%d) must be greater than 0 and less than 65536\n" ,__func__ ,hparams .n_merge )); 2031 } 2032if (hparams .attn_window_size > 4096 ) { 2033throw std::runtime_error (string_format ("%s: attn_window_size (%d) is too large (max 4096)\n" ,__func__ ,hparams .attn_window_size )); 2034 } 2035 } 2036 2037LOG_INF ("%s: projector: %s\n" ,__func__ ,proj_type .c_str ()); 2038LOG_INF ("%s: n_embd: %d\n" ,__func__ ,hparams .n_embd ); 2039LOG_INF ("%s: n_head: %d\n" ,__func__ ,hparams .n_head ); 2040LOG_INF ("%s: n_ff: %d\n" ,__func__ ,hparams .n_ff ); 2041LOG_INF ("%s: n_layer: %d\n" ,__func__ ,hparams .n_layer ); 2042LOG_INF ("%s: ffn_op: %s\n" ,__func__ ,log_ffn_op .c_str ()); 2043LOG_INF ("%s: projection_dim: %d\n" ,__func__ ,hparams .projection_dim ); 2044if (is_vision ) { 2045LOG_INF ("\n--- vision hparams ---\n" ); 2046LOG_INF ("%s: image_size: %d\n" ,__func__ ,hparams .image_size ); 2047LOG_INF ("%s: patch_size: %d\n" ,__func__ ,hparams .patch_size ); 2048LOG_INF ("%s: has_llava_proj: %d\n" ,__func__ ,hparams .has_llava_projector ); 2049LOG_INF ("%s: minicpmv_version: %d\n" ,__func__ ,hparams .minicpmv_version ); 2050LOG_INF ("%s: n_merge: %d\n" ,__func__ ,hparams .n_merge ); 2051LOG_INF ("%s: n_wa_pattern: %d\n" ,__func__ ,hparams .n_wa_pattern ); 2052if (!hparams .wa_layer_indexes .empty ()) { 2053LOG_INF ("%s: wa_layer_indexes: " ,__func__ ); 2054for (auto & layer :hparams .wa_layer_indexes ) { 2055LOG_INF ("%d " ,layer ); 2056 } 2057LOG_INF ("\n" ); 2058 } 2059if (hparams .image_min_pixels > 0 ) { 2060LOG_INF ("%s: image_min_pixels: %d%s\n" ,__func__ ,hparams .image_min_pixels ,hparams .custom_image_min_tokens > 0 ?" (custom value)" :"" ); 2061 } 2062if (hparams .image_max_pixels > 0 ) { 2063LOG_INF ("%s: image_max_pixels: %d%s\n" ,__func__ ,hparams .image_max_pixels ,hparams .custom_image_max_tokens > 0 ?" (custom value)" :"" ); 2064 } 2065if (hparams .preproc_max_tiles > 0 ) { 2066LOG_INF ("%s: preproc_tiles: %d - %d\n" ,__func__ ,hparams .preproc_min_tiles ,hparams .preproc_max_tiles ); 2067 } 2068 }else if (is_audio ) { 2069LOG_INF ("\n--- audio hparams ---\n" ); 2070LOG_INF ("%s: n_mel_bins: %d\n" ,__func__ ,hparams .n_mel_bins ); 2071LOG_INF ("%s: proj_stack_factor: %d\n" ,__func__ ,hparams .proj_stack_factor ); 2072LOG_INF ("%s: audio_chunk_len: %d\n" ,__func__ ,hparams .audio_chunk_len ); 2073LOG_INF ("%s: audio_sample_rate: %d\n" ,__func__ ,hparams .audio_sample_rate ); 2074LOG_INF ("%s: audio_n_fft: %d\n" ,__func__ ,hparams .audio_n_fft ); 2075LOG_INF ("%s: audio_window_len: %d\n" ,__func__ ,hparams .audio_window_len ); 2076LOG_INF ("%s: audio_hop_len: %d\n" ,__func__ ,hparams .audio_hop_len ); 2077 2078// GEMMA4UA is encoder-free: it uses n_mel_bins as a raw-waveform frame size (640) and has no FFT/filterbank, so the mel-range and FFT 2079// checks below do not apply to it. 2080// pocket-tts is encoder-free in the same sense: mimi convolves the raw waveform 2081const bool fft_based = model .proj_type != PROJECTOR_TYPE_GEMMA4UA && 2082model .proj_type != PROJECTOR_TYPE_POCKETTTS_SPKENC ; 2083 2084// Validate audio hparams loaded from GGUF metadata 2085if (hparams .n_mel_bins <=0 || (fft_based && hparams .n_mel_bins > 256 )) { 2086throw std::runtime_error (string_format ("%s: n_mel_bins (%d) must be in range [1, 256]\n" ,__func__ ,hparams .n_mel_bins )); 2087 } 2088if (fft_based && (hparams .audio_sample_rate <=0 || hparams .audio_n_fft <=0 || hparams .audio_hop_len <=0 || hparams .audio_window_len <=0 )) { 2089throw std::runtime_error (string_format ("%s: audio hparams invalid: sample_rate=%d n_fft=%d window_len=%d hop_len=%d\n" , 2090__func__ ,hparams .audio_sample_rate ,hparams .audio_n_fft ,hparams .audio_window_len ,hparams .audio_hop_len )); 2091 } 2092 } 2093LOG_INF ("\n" ); 2094LOG_INF ("%s: model size: %.2f MiB\n" ,__func__ ,model_size /1024.0 /1024.0 ); 2095LOG_INF ("%s: metadata size: %.2f MiB\n" ,__func__ ,ggml_get_mem_size (ctx_meta .get ()) /1024.0 /1024.0 ); 2096 } 2097 } 2098 2099void load_tensors (clip_ctx & ctx_clip ) { 2100auto & model = ctx_clip .model ; 2101auto & hparams = model .hparams ; 2102 std::map < std::string ,size_t > tensor_offset ; 2103 std::vector < ggml_tensor *> tensors_to_load ; 2104 2105auto fin = open_ifstream_binary (fname ); 2106if (!fin ) { 2107throw std::runtime_error (string_format ("%s: failed to open %s\n" ,__func__ ,fname .c_str ())); 2108 } 2109 2110// TODO @ngxson : support both audio and video in the future 2111const char * prefix = model .modality == CLIP_MODALITY_AUDIO ?"a" 2112 :model .modality == CLIP_MODALITY_GEN_AUDIO ?"a.gen.code" 2113 :"v" ; 2114 2115// get offsets 2116for (int64_t i = 0 ;i < gguf_get_n_tensors (ctx_gguf .get ());++ i ) { 2117const char * name = gguf_get_tensor_name (ctx_gguf .get (),i ); 2118tensor_offset [name ]= gguf_get_data_offset (ctx_gguf .get ())+ gguf_get_tensor_offset (ctx_gguf .get (),i ); 2119 } 2120 2121// create data context 2122struct ggml_init_params params = { 2123/*.mem_size =*/ static_cast < size_t > (gguf_get_n_tensors (ctx_gguf .get ())+ 1 )* ggml_tensor_overhead (), 2124/*.mem_buffer =*/ NULL , 2125/*.no_alloc =*/ true, 2126 }; 2127ctx_clip .ctx_data .reset (ggml_init (params )); 2128if (!ctx_clip .ctx_data ) { 2129throw std::runtime_error (string_format ("%s: failed to init ggml context\n" ,__func__ )); 2130 } 2131 2132// helper function 2133 std::unordered_set < std::string > loaded_tensor_names ; 2134auto get_tensor = [& ](const std::string & name ,bool required = true) { 2135// Each tensor should only be loaded once; duplicates indicate a bug 2136if (loaded_tensor_names .count (name )) { 2137throw std::runtime_error (string_format ("%s: tensor already loaded: %s\n" ,__func__ ,name .c_str ())); 2138 } 2139ggml_tensor * cur = ggml_get_tensor (ctx_meta .get (),name .c_str ()); 2140if (!cur && required ) { 2141throw std::runtime_error (string_format ("%s: unable to find tensor %s\n" ,__func__ ,name .c_str ())); 2142 } 2143if (cur ) { 2144tensors_to_load .push_back (cur ); 2145ggml_tensor * data_tensor = ggml_dup_tensor (ctx_clip .ctx_data .get (),cur ); 2146ggml_set_name (data_tensor ,cur -> name ); 2147loaded_tensor_names .insert (name ); 2148cur = data_tensor ; 2149// add to weight memory counter 2150ctx_clip .mem_usage [ggml_backend_get_device (ctx_clip .backend )]+= ggml_nbytes (cur ); 2151 } 2152return cur ; 2153 }; 2154 2155// pocket-tts: the encoder and the decoder share the same layout, only the prefix differs 2156auto load_seanet = [& ](clip_seanet & seanet ,bool is_decoder ) { 2157const char * conv_in = is_decoder ?TN_A_GEN_WAV_SEANET_CONV_IN :TN_A_SEANET_CONV_IN ; 2158const char * conv_out = is_decoder ?TN_A_GEN_WAV_SEANET_CONV_OUT :TN_A_SEANET_CONV_OUT ; 2159const char * res1 = is_decoder ?TN_A_GEN_WAV_SEANET_RES_CONV1 :TN_A_SEANET_RES_CONV1 ; 2160const char * res2 = is_decoder ?TN_A_GEN_WAV_SEANET_RES_CONV2 :TN_A_SEANET_RES_CONV2 ; 2161const char * scale = is_decoder ?TN_A_GEN_WAV_SEANET_SCALE_CONV :TN_A_SEANET_SCALE_CONV ; 2162 2163seanet .conv_in_w = get_tensor (string_format (conv_in ,"weight" )); 2164seanet .conv_in_b = get_tensor (string_format (conv_in ,"bias" )); 2165seanet .conv_out_w = get_tensor (string_format (conv_out ,"weight" )); 2166seanet .conv_out_b = get_tensor (string_format (conv_out ,"bias" )); 2167 2168seanet .stages .resize (hparams .seanet_n_stage ); 2169for (int i = 0 ;i < hparams .seanet_n_stage ;i ++ ) { 2170auto & stage = seanet .stages [i ]; 2171stage .res_conv1_w = get_tensor (string_format (res1 ,i ,"weight" )); 2172stage .res_conv1_b = get_tensor (string_format (res1 ,i ,"bias" )); 2173stage .res_conv2_w = get_tensor (string_format (res2 ,i ,"weight" )); 2174stage .res_conv2_b = get_tensor (string_format (res2 ,i ,"bias" )); 2175stage .scale_conv_w = get_tensor (string_format (scale ,i ,"weight" )); 2176stage .scale_conv_b = get_tensor (string_format (scale ,i ,"bias" )); 2177 } 2178 }; 2179 2180auto get_vector = [& ](const std::string & name ) { 2181 std::vector < float > result ; 2182auto it = tensor_offset .find (name ); 2183if (it == tensor_offset .end ()) { 2184return result ; 2185 } 2186 2187const int64_t idx = gguf_find_tensor (ctx_gguf .get (),name .c_str ()); 2188if (idx < 0 ) { 2189throw std::runtime_error (string_format ("%s: failed to find tensor %s\n" ,__func__ ,name .c_str ())); 2190 } 2191 2192if (const auto type = gguf_get_tensor_type (ctx_gguf .get (),idx );type != GGML_TYPE_F32 ) { 2193throw std::runtime_error (string_format ("%s: %s must be %s, was %s\n" ,__func__ , 2194name .c_str (),ggml_type_name (GGML_TYPE_F32 ),ggml_type_name (type ))); 2195 } 2196 2197const size_t n_bytes = gguf_get_tensor_size (ctx_gguf .get (),idx ); 2198if (n_bytes == 0 ) { 2199throw std::runtime_error (string_format ("%s: tensor %s is empty\n" ,__func__ ,name .c_str ())); 2200 } 2201 2202const size_t n_elems = n_bytes /sizeof (float ); 2203result .resize (n_elems ); 2204fin .seekg (it -> second , std::ios::beg ); 2205fin .read (reinterpret_cast < char *> (result .data ()),n_bytes ); 2206return result ; 2207 }; 2208 2209auto get_scalar = [& ](const std::string & name ,float default_val ) { 2210auto v = get_vector (name ); 2211if (v .empty ()) { 2212return default_val ; 2213 } 2214if (v .size ()!= 1 ) { 2215throw std::runtime_error (string_format ("%s: expected scalar tensor '%s' but got %d elements\n" , 2216__func__ ,name .c_str (), (int )v .size ())); 2217 } 2218 2219return v [0 ]; 2220 }; 2221 2222model .class_embedding = get_tensor (TN_CLASS_EMBD , false); 2223 2224model .pre_ln_w = get_tensor (string_format (TN_LN_PRE ,prefix ,"weight" ), false); 2225model .pre_ln_b = get_tensor (string_format (TN_LN_PRE ,prefix ,"bias" ), false); 2226 2227model .post_ln_w = get_tensor (string_format (TN_LN_POST ,prefix ,"weight" ), false); 2228model .post_ln_b = get_tensor (string_format (TN_LN_POST ,prefix ,"bias" ), false); 2229 2230model .patch_bias = get_tensor (TN_PATCH_BIAS , false); 2231model .patch_embeddings_0 = get_tensor (TN_PATCH_EMBD , false); 2232model .patch_embeddings_1 = get_tensor (TN_PATCH_EMBD_1 , false); 2233 2234model .norm_embd_w = get_tensor (string_format (TN_NORM_EMBD ,"weight" ), false); 2235model .norm_embd_b = get_tensor (string_format (TN_NORM_EMBD ,"bias" ), false); 2236 2237model .position_embeddings = get_tensor (string_format (TN_POS_EMBD ,prefix ), false); 2238 2239const bool has_standard_layers = ( 2240model .proj_type != PROJECTOR_TYPE_GEMMA3NV && 2241model .proj_type != PROJECTOR_TYPE_QWEN3TTS_SPKENC && 2242model .proj_type != PROJECTOR_TYPE_POCKETTTS_GEN ); 2243 2244// layers 2245const int n_layers_to_load = has_standard_layers ?hparams .n_layer :0 ; 2246model .layers .resize (n_layers_to_load ); 2247for (int il = 0 ;il < n_layers_to_load ;++ il ) { 2248auto & layer = model .layers [il ]; 2249layer .k_w = get_tensor (string_format (TN_ATTN_K ,prefix ,il ,"weight" ), false); 2250layer .q_w = get_tensor (string_format (TN_ATTN_Q ,prefix ,il ,"weight" ), false); 2251layer .v_w = get_tensor (string_format (TN_ATTN_V ,prefix ,il ,"weight" ), false); 2252layer .o_w = get_tensor (string_format (TN_ATTN_OUTPUT ,prefix ,il ,"weight" )); 2253layer .qkv_w = get_tensor (string_format (TN_ATTN_QKV ,prefix ,il ,"weight" ), false); 2254layer .k_norm = get_tensor (string_format (TN_ATTN_K_NORM ,prefix ,il ,"weight" ), false); 2255layer .q_norm = get_tensor (string_format (TN_ATTN_Q_NORM ,prefix ,il ,"weight" ), false); 2256layer .ln_1_w = get_tensor (string_format (TN_LN_1 ,prefix ,il ,"weight" ), false); 2257layer .ln_2_w = get_tensor (string_format (TN_LN_2 ,prefix ,il ,"weight" ), false); 2258layer .ls_1_w = get_tensor (string_format (TN_LS_1 ,prefix ,il ,"weight" ), false);// no bias 2259layer .ls_2_w = get_tensor (string_format (TN_LS_2 ,prefix ,il ,"weight" ), false);// no bias 2260layer .ls_out_w = get_tensor (string_format (TN_LS_OUT ,prefix ,il ,"weight" ), false);// no bias 2261layer .attn_post_norm_w = get_tensor (string_format (TN_ATTN_POST_NORM ,prefix ,il ,"weight" ), false);// no bias 2262layer .ff_post_norm_w = get_tensor (string_format (TN_FFN_POST_NORM ,prefix ,il ,"weight" ), false);// no bias 2263 2264layer .k_b = get_tensor (string_format (TN_ATTN_K ,prefix ,il ,"bias" ), false); 2265layer .q_b = get_tensor (string_format (TN_ATTN_Q ,prefix ,il ,"bias" ), false); 2266layer .v_b = get_tensor (string_format (TN_ATTN_V ,prefix ,il ,"bias" ), false); 2267layer .o_b = get_tensor (string_format (TN_ATTN_OUTPUT ,prefix ,il ,"bias" ), false); 2268layer .qkv_b = get_tensor (string_format (TN_ATTN_QKV ,prefix ,il ,"bias" ), false); 2269layer .ln_1_b = get_tensor (string_format (TN_LN_1 ,prefix ,il ,"bias" ), false); 2270layer .ln_2_b = get_tensor (string_format (TN_LN_2 ,prefix ,il ,"bias" ), false); 2271 2272// MoE ffn (dots3note vision pyramid blocks); replaces the dense ffn when present 2273layer .ff_gate_inp_w = get_tensor (string_format (TN_FFN_GATE_INP ,prefix ,il ,"weight" ), false); 2274layer .ff_gate_exps_w = get_tensor (string_format (TN_FFN_GATE_EXPS ,prefix ,il ,"weight" ), false); 2275layer .ff_up_exps_w = get_tensor (string_format (TN_FFN_UP_EXPS ,prefix ,il ,"weight" ), false); 2276layer .ff_down_exps_w = get_tensor (string_format (TN_FFN_DOWN_EXPS ,prefix ,il ,"weight" ), false); 2277layer .ff_exp_probs_b = get_tensor (string_format (TN_FFN_EXP_PROBS_B ,prefix ,il ,"weight" ), false); 2278const bool is_moe = layer .ff_gate_exps_w != nullptr ; 2279 2280// ffn 2281layer .ff_up_w = get_tensor (string_format (TN_FFN_UP ,prefix ,il ,"weight" ), !is_moe ); 2282layer .ff_up_b = get_tensor (string_format (TN_FFN_UP ,prefix ,il ,"bias" ), false); 2283layer .ff_gate_w = get_tensor (string_format (TN_FFN_GATE ,prefix ,il ,"weight" ), false); 2284layer .ff_gate_b = get_tensor (string_format (TN_FFN_GATE ,prefix ,il ,"bias" ), false); 2285layer .ff_down_w = get_tensor (string_format (TN_FFN_DOWN ,prefix ,il ,"weight" ), !is_moe ); 2286layer .ff_down_b = get_tensor (string_format (TN_FFN_DOWN ,prefix ,il ,"bias" ), false); 2287 2288// mimovl per-head attention sink bias 2289layer .attn_sinks = get_tensor (string_format (TN_ATTN_SINKS ,prefix ,il ), false); 2290 2291// qwen3vl deepstack layer 2292layer .deepstack_norm_w = get_tensor (string_format (TN_DEEPSTACK_NORM ,il ,"weight" ), false); 2293layer .deepstack_norm_b = get_tensor (string_format (TN_DEEPSTACK_NORM ,il ,"bias" ), false); 2294layer .deepstack_fc1_w = get_tensor (string_format (TN_DEEPSTACK_FC1 ,il ,"weight" ), false); 2295layer .deepstack_fc1_b = get_tensor (string_format (TN_DEEPSTACK_FC1 ,il ,"bias" ), false); 2296layer .deepstack_fc2_w = get_tensor (string_format (TN_DEEPSTACK_FC2 ,il ,"weight" ), false); 2297layer .deepstack_fc2_b = get_tensor (string_format (TN_DEEPSTACK_FC2 ,il ,"bias" ), false); 2298if (layer .has_deepstack ()) { 2299model .n_deepstack_layers ++ ; 2300 } 2301 2302// some models already exported with legacy (incorrect) naming which is quite messy, let's fix it here 2303// note: Qwen model converted from the old surgery script has n_ff = 0, so we cannot use n_ff to check! 2304bool is_ffn_swapped = ( 2305// only old models need this fix 2306model .proj_type == PROJECTOR_TYPE_MLP 2307|| model .proj_type == PROJECTOR_TYPE_MLP_NORM 2308|| model .proj_type == PROJECTOR_TYPE_LDP 2309|| model .proj_type == PROJECTOR_TYPE_LDPV2 2310|| model .proj_type == PROJECTOR_TYPE_QWEN2VL 2311|| model .proj_type == PROJECTOR_TYPE_QWEN25VL 2312|| model .proj_type == PROJECTOR_TYPE_EXAONE4_5 2313|| model .proj_type == PROJECTOR_TYPE_GLM_EDGE 2314|| model .proj_type == PROJECTOR_TYPE_GEMMA3 2315|| model .proj_type == PROJECTOR_TYPE_IDEFICS3 2316|| model .proj_type == PROJECTOR_TYPE_MINICPMV 2317|| model .proj_type == PROJECTOR_TYPE_MINICPMV4_6 2318 )&& layer .ff_up_w && layer .ff_down_w && layer .ff_down_w -> ne [0 ]== hparams .n_embd ; 2319if (is_ffn_swapped ) { 2320// swap up and down weights 2321ggml_tensor * tmp = layer .ff_up_w ; 2322layer .ff_up_w = layer .ff_down_w ; 2323layer .ff_down_w = tmp ; 2324// swap up and down biases 2325tmp = layer .ff_up_b ; 2326layer .ff_up_b = layer .ff_down_b ; 2327layer .ff_down_b = tmp ; 2328if (il == 0 ) { 2329LOG_WRN ("%s: ffn up/down are swapped\n" ,__func__ ); 2330 } 2331 } 2332 } 2333 2334 2335switch (model .proj_type ) { 2336case PROJECTOR_TYPE_MLP : 2337case PROJECTOR_TYPE_MLP_NORM : 2338 { 2339// LLaVA projection 2340model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" ), false); 2341model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" ), false); 2342// Yi-type llava 2343model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" ), false); 2344model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" ), false); 2345// missing in Yi-type llava 2346model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" ), false); 2347model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" ), false); 2348// Yi-type llava 2349model .mm_3_w = get_tensor (string_format (TN_LLAVA_PROJ ,3 ,"weight" ), false); 2350model .mm_3_b = get_tensor (string_format (TN_LLAVA_PROJ ,3 ,"bias" ), false); 2351model .mm_4_w = get_tensor (string_format (TN_LLAVA_PROJ ,4 ,"weight" ), false); 2352model .mm_4_b = get_tensor (string_format (TN_LLAVA_PROJ ,4 ,"bias" ), false); 2353if (model .mm_3_w ) { 2354// TODO: this is a hack to support Yi-type llava 2355model .proj_type = PROJECTOR_TYPE_MLP_NORM ; 2356 } 2357model .image_newline = get_tensor (TN_IMAGE_NEWLINE , false); 2358 }break ; 2359case PROJECTOR_TYPE_LDP : 2360 { 2361// MobileVLM projection 2362model .mm_model_mlp_1_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,1 ,"weight" )); 2363model .mm_model_mlp_1_b = get_tensor (string_format (TN_MVLM_PROJ_MLP ,1 ,"bias" )); 2364model .mm_model_mlp_3_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,3 ,"weight" )); 2365model .mm_model_mlp_3_b = get_tensor (string_format (TN_MVLM_PROJ_MLP ,3 ,"bias" )); 2366model .mm_model_block_1_block_0_0_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,0 ,"0.weight" )); 2367model .mm_model_block_1_block_0_1_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,0 ,"1.weight" )); 2368model .mm_model_block_1_block_0_1_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,0 ,"1.bias" )); 2369model .mm_model_block_1_block_1_fc1_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,1 ,"fc1.weight" )); 2370model .mm_model_block_1_block_1_fc1_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,1 ,"fc1.bias" )); 2371model .mm_model_block_1_block_1_fc2_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,1 ,"fc2.weight" )); 2372model .mm_model_block_1_block_1_fc2_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,1 ,"fc2.bias" )); 2373model .mm_model_block_1_block_2_0_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,2 ,"0.weight" )); 2374model .mm_model_block_1_block_2_1_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,2 ,"1.weight" )); 2375model .mm_model_block_1_block_2_1_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,1 ,2 ,"1.bias" )); 2376model .mm_model_block_2_block_0_0_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,0 ,"0.weight" )); 2377model .mm_model_block_2_block_0_1_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,0 ,"1.weight" )); 2378model .mm_model_block_2_block_0_1_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,0 ,"1.bias" )); 2379model .mm_model_block_2_block_1_fc1_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,1 ,"fc1.weight" )); 2380model .mm_model_block_2_block_1_fc1_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,1 ,"fc1.bias" )); 2381model .mm_model_block_2_block_1_fc2_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,1 ,"fc2.weight" )); 2382model .mm_model_block_2_block_1_fc2_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,1 ,"fc2.bias" )); 2383model .mm_model_block_2_block_2_0_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,2 ,"0.weight" )); 2384model .mm_model_block_2_block_2_1_w = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,2 ,"1.weight" )); 2385model .mm_model_block_2_block_2_1_b = get_tensor (string_format (TN_MVLM_PROJ_BLOCK ,2 ,2 ,"1.bias" )); 2386 }break ; 2387case PROJECTOR_TYPE_LDPV2 : 2388 { 2389// MobilVLM_V2 projection 2390model .mm_model_mlp_0_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,0 ,"weight" )); 2391model .mm_model_mlp_0_b = get_tensor (string_format (TN_MVLM_PROJ_MLP ,0 ,"bias" )); 2392model .mm_model_mlp_2_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,2 ,"weight" )); 2393model .mm_model_mlp_2_b = get_tensor (string_format (TN_MVLM_PROJ_MLP ,2 ,"bias" )); 2394model .mm_model_peg_0_w = get_tensor (string_format (TN_MVLM_PROJ_PEG ,0 ,"weight" )); 2395model .mm_model_peg_0_b = get_tensor (string_format (TN_MVLM_PROJ_PEG ,0 ,"bias" )); 2396 }break ; 2397case PROJECTOR_TYPE_MINICPMV : 2398 { 2399// model.mm_model_pos_embed = get_tensor(new_clip->ctx_data, TN_MINICPMV_POS_EMBD); 2400model .mm_model_pos_embed_k = get_tensor (TN_MINICPMV_POS_EMBD_K ); 2401model .mm_model_query = get_tensor (TN_MINICPMV_QUERY ); 2402model .mm_model_proj = get_tensor (TN_MINICPMV_PROJ ); 2403model .mm_model_kv_proj = get_tensor (TN_MINICPMV_KV_PROJ ); 2404model .mm_model_attn_q_w = get_tensor (string_format (TN_MINICPMV_ATTN ,"q" ,"weight" )); 2405model .mm_model_attn_k_w = get_tensor (string_format (TN_MINICPMV_ATTN ,"k" ,"weight" )); 2406model .mm_model_attn_v_w = get_tensor (string_format (TN_MINICPMV_ATTN ,"v" ,"weight" )); 2407model .mm_model_attn_q_b = get_tensor (string_format (TN_MINICPMV_ATTN ,"q" ,"bias" )); 2408model .mm_model_attn_k_b = get_tensor (string_format (TN_MINICPMV_ATTN ,"k" ,"bias" )); 2409model .mm_model_attn_v_b = get_tensor (string_format (TN_MINICPMV_ATTN ,"v" ,"bias" )); 2410model .mm_model_attn_o_w = get_tensor (string_format (TN_MINICPMV_ATTN ,"out" ,"weight" )); 2411model .mm_model_attn_o_b = get_tensor (string_format (TN_MINICPMV_ATTN ,"out" ,"bias" )); 2412model .mm_model_ln_q_w = get_tensor (string_format (TN_MINICPMV_LN ,"q" ,"weight" )); 2413model .mm_model_ln_q_b = get_tensor (string_format (TN_MINICPMV_LN ,"q" ,"bias" )); 2414model .mm_model_ln_kv_w = get_tensor (string_format (TN_MINICPMV_LN ,"kv" ,"weight" )); 2415model .mm_model_ln_kv_b = get_tensor (string_format (TN_MINICPMV_LN ,"kv" ,"bias" )); 2416model .mm_model_ln_post_w = get_tensor (string_format (TN_MINICPMV_LN ,"post" ,"weight" )); 2417model .mm_model_ln_post_b = get_tensor (string_format (TN_MINICPMV_LN ,"post" ,"bias" )); 2418 }break ; 2419case PROJECTOR_TYPE_MINICPMV4_6 : 2420 { 2421const bool merger_required = hparams .n_merge == 4 ; 2422auto get_merger_tensor = [& ](const std::string & name ,bool required = true) { 2423return get_tensor (name ,merger_required && required ); 2424 }; 2425 2426// ViT merger: window self-attention 2427model .vit_merger_ln1_w = get_merger_tensor (string_format (TN_VIT_MERGER_LN1 ,"weight" )); 2428model .vit_merger_ln1_b = get_merger_tensor (string_format (TN_VIT_MERGER_LN1 ,"bias" )); 2429model .vit_merger_attn_q_w = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_Q ,"weight" )); 2430model .vit_merger_attn_q_b = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_Q ,"bias" ), false); 2431model .vit_merger_attn_k_w = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_K ,"weight" )); 2432model .vit_merger_attn_k_b = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_K ,"bias" ), false); 2433model .vit_merger_attn_v_w = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_V ,"weight" )); 2434model .vit_merger_attn_v_b = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_V ,"bias" ), false); 2435model .vit_merger_attn_o_w = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_O ,"weight" )); 2436model .vit_merger_attn_o_b = get_merger_tensor (string_format (TN_VIT_MERGER_ATTN_O ,"bias" ), false); 2437// ViT merger: MLP downsample 2438model .vit_merger_ds_ln_w = get_merger_tensor (string_format (TN_VIT_MERGER_DS_LN ,"weight" )); 2439model .vit_merger_ds_ln_b = get_merger_tensor (string_format (TN_VIT_MERGER_DS_LN ,"bias" )); 2440model .vit_merger_ds_up_w = get_merger_tensor (string_format (TN_VIT_MERGER_DS_UP ,"weight" )); 2441model .vit_merger_ds_up_b = get_merger_tensor (string_format (TN_VIT_MERGER_DS_UP ,"bias" ), false); 2442model .vit_merger_ds_down_w = get_merger_tensor (string_format (TN_VIT_MERGER_DS_DOWN ,"weight" )); 2443model .vit_merger_ds_down_b = get_merger_tensor (string_format (TN_VIT_MERGER_DS_DOWN ,"bias" ), false); 2444// Final Merger (DownsampleMLP) 2445model .mm_input_norm_w = get_tensor (TN_MM_INP_NORM ); 2446model .mm_input_norm_b = get_tensor (TN_MM_INP_NORM_B , false); 2447model .mm_ffn_up_w = get_tensor (string_format (TN_MM_UP ,"weight" )); 2448model .mm_ffn_up_b = get_tensor (string_format (TN_MM_UP ,"bias" ), false); 2449model .mm_ffn_down_w = get_tensor (string_format (TN_MM_DOWN ,"weight" )); 2450model .mm_ffn_down_b = get_tensor (string_format (TN_MM_DOWN ,"bias" ), false); 2451 }break ; 2452case PROJECTOR_TYPE_GLM_EDGE : 2453 { 2454model .mm_model_adapter_conv_w = get_tensor (string_format (TN_GLM_ADAPER_CONV ,"weight" )); 2455model .mm_model_adapter_conv_b = get_tensor (string_format (TN_GLM_ADAPER_CONV ,"bias" )); 2456model .mm_model_mlp_0_w = get_tensor (string_format (TN_GLM_ADAPTER_LINEAR ,"weight" )); 2457model .mm_model_ln_q_w = get_tensor (string_format (TN_GLM_ADAPTER_NORM_1 ,"weight" )); 2458model .mm_model_ln_q_b = get_tensor (string_format (TN_GLM_ADAPTER_NORM_1 ,"bias" )); 2459model .mm_model_mlp_1_w = get_tensor (string_format (TN_GLM_ADAPTER_D_H_2_4H ,"weight" )); 2460model .mm_model_mlp_2_w = get_tensor (string_format (TN_GLM_ADAPTER_GATE ,"weight" )); 2461model .mm_model_mlp_3_w = get_tensor (string_format (TN_GLM_ADAPTER_D_4H_2_H ,"weight" )); 2462model .mm_boi = get_tensor (string_format (TN_TOK_GLM_BOI )); 2463model .mm_eoi = get_tensor (string_format (TN_TOK_GLM_EOI )); 2464 }break ; 2465case PROJECTOR_TYPE_QWEN2VL : 2466case PROJECTOR_TYPE_QWEN25VL : 2467case PROJECTOR_TYPE_EXAONE4_5 : 2468 { 2469model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 2470model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" )); 2471model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2472model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2473 }break ; 2474case PROJECTOR_TYPE_QWEN3VL : 2475 { 2476model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 2477model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" )); 2478model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2479model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2480 }break ; 2481case PROJECTOR_TYPE_MIMOVL : 2482 { 2483model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 2484model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" ), false); 2485model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2486model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" ), false); 2487 }break ; 2488case PROJECTOR_TYPE_MINIMAX_M3 : 2489 { 2490// per-patch MLP: mm.1 -> gelu -> mm.2 2491model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2492model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" )); 2493model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2494model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2495// 2x2 merge MLP: mm.merge.fc1 -> gelu -> mm.merge.fc2 2496model .mm_merger_fc1_w = get_tensor (string_format (TN_MM_MERGER_FC1 ,"weight" )); 2497model .mm_merger_fc1_b = get_tensor (string_format (TN_MM_MERGER_FC1 ,"bias" )); 2498model .mm_merger_fc2_w = get_tensor (string_format (TN_MM_MERGER_FC2 ,"weight" )); 2499model .mm_merger_fc2_b = get_tensor (string_format (TN_MM_MERGER_FC2 ,"bias" )); 2500 }break ; 2501case PROJECTOR_TYPE_MUSE_GLIMMER : 2502 { 2503// 3-linear MLP: fc -> erf-GELU -> proj -> erf-GELU -> vision_proj (into LLM residual dim) 2504model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 2505model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2506model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2507 }break ; 2508case PROJECTOR_TYPE_STEP3VL : 2509 { 2510model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 2511model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" ), false); 2512model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2513model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" ), false); 2514model .mm_model_proj = get_tensor (string_format (TN_MM_PROJECTOR ,"weight" )); 2515 }break ; 2516case PROJECTOR_TYPE_YOUTUVL : 2517 { 2518model .mm_input_norm_w = get_tensor (TN_MM_INP_NORM );// merger.ln_q (RMS norm) 2519model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" ));// merger.mlp.0 2520model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" )); 2521model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" ));// merger.mlp.2 2522model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2523 }break ; 2524case PROJECTOR_TYPE_YASA2 : 2525 { 2526// reuse tensors already loaded by the common section 2527// (TN_PATCH_EMBD and TN_PATCH_BIAS have the same tensor names) 2528GGML_ASSERT (model .patch_embeddings_0 && "yasa2 requires v.patch_embd.weight" ); 2529model .yasa_patch_w = model .patch_embeddings_0 ; 2530model .yasa_patch_b = model .patch_bias ; 2531model .yasa_patch_ln_w = get_tensor (TN_YASA_PATCH_LN_W , false); 2532model .yasa_patch_ln_b = get_tensor (TN_YASA_PATCH_LN_B , false); 2533model .yasa_backbone_ln_w = get_tensor (TN_YASA_BACKBONE_LN_W , false); 2534model .yasa_backbone_ln_b = get_tensor (TN_YASA_BACKBONE_LN_B , false); 2535model .yasa_vision_pos_embed = get_tensor (TN_YASA_POS_EMBD , false); 2536model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 2537model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" ), false); 2538model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2539model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" ), false); 2540 2541model .yasa_stages .clear (); 2542for (int s = 0 ; ;++ s ) { 2543yasa2_stage stage ; 2544stage .down_ln_w = get_tensor (string_format (TN_YASA_STAGE_DOWN_LN ,s ,"weight" ), false); 2545stage .down_ln_b = get_tensor (string_format (TN_YASA_STAGE_DOWN_LN ,s ,"bias" ), false); 2546stage .down_conv_w = get_tensor (string_format (TN_YASA_STAGE_DOWN_CONV ,s ,"weight" ), false); 2547stage .down_conv_b = get_tensor (string_format (TN_YASA_STAGE_DOWN_CONV ,s ,"bias" ), false); 2548 2549for (int bi = 0 ; ;++ bi ) { 2550yasa2_block blk ; 2551blk .dw_w = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"dw" ,"weight" ), false); 2552if (!blk .dw_w ) { 2553break ; 2554 } 2555blk .dw_b = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"dw" ,"bias" ), false); 2556blk .ln_w = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"ln" ,"weight" ), false); 2557blk .ln_b = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"ln" ,"bias" ), false); 2558blk .pw1_w = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"pw1" ,"weight" ), false); 2559blk .pw1_b = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"pw1" ,"bias" ), false); 2560blk .grn_w = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"grn" ,"weight" ), false); 2561blk .grn_b = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"grn" ,"bias" ), false); 2562blk .pw2_w = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"pw2" ,"weight" ), false); 2563blk .pw2_b = get_tensor (string_format (TN_YASA_STAGE_BLK ,s ,bi ,"pw2" ,"bias" ), false); 2564stage .blocks .push_back (blk ); 2565 } 2566 2567if (!stage .down_conv_w && stage .blocks .empty ()) { 2568break ; 2569 } 2570model .yasa_stages .push_back (std::move (stage )); 2571 } 2572 }break ; 2573case PROJECTOR_TYPE_GLM4V : 2574 { 2575model .mm_fc_w = get_tensor (string_format (TN_MM_PROJECTOR ,"weight" )); 2576model .mm_ffn_up_w = get_tensor (string_format (TN_MM_UP ,"weight" )); 2577model .mm_ffn_up_b = get_tensor (string_format (TN_MM_UP ,"bias" ), false); 2578model .mm_ffn_gate_w = get_tensor (string_format (TN_MM_GATE ,"weight" )); 2579model .mm_ffn_gate_b = get_tensor (string_format (TN_MM_GATE ,"bias" ), false); 2580model .mm_ffn_down_w = get_tensor (string_format (TN_MM_DOWN ,"weight" )); 2581model .mm_ffn_down_b = get_tensor (string_format (TN_MM_DOWN ,"bias" ), false); 2582model .mm_post_norm_w = get_tensor (string_format (TN_MM_POST_NORM ,"weight" )); 2583model .mm_post_norm_b = get_tensor (string_format (TN_MM_POST_NORM ,"bias" ), false); 2584model .mm_patch_merger_w = get_tensor (string_format (TN_MM_PATCH_MERGER ,"weight" )); 2585model .mm_patch_merger_b = get_tensor (string_format (TN_MM_PATCH_MERGER ,"bias" )); 2586 }break ; 2587case PROJECTOR_TYPE_GEMMA3 : 2588 { 2589model .mm_input_proj_w = get_tensor (TN_MM_INP_PROJ ); 2590model .mm_soft_emb_norm_w = get_tensor (TN_MM_SOFT_EMB_N ); 2591 }break ; 2592case PROJECTOR_TYPE_GEMMA4V : 2593 { 2594model .mm_input_proj_w = get_tensor (TN_MM_INP_PROJ ); 2595model .std_bias = get_tensor (TN_STD_BIAS , false); 2596model .std_scale = get_tensor (TN_STD_SCALE , false); 2597// load scalar for Gemma4ClippableLinear 2598for (auto * tensor :tensors_to_load ) { 2599 std::string name = tensor -> name ; 2600if (string_ends_with (name ,".weight" )) { 2601 std::string name_inp_max = name ; 2602 std::string name_inp_min = name ; 2603 std::string name_out_max = name ; 2604 std::string name_out_min = name ; 2605string_replace_all (name_inp_max ,".weight" ,".input_max" ); 2606string_replace_all (name_inp_min ,".weight" ,".input_min" ); 2607string_replace_all (name_out_max ,".weight" ,".output_max" ); 2608string_replace_all (name_out_min ,".weight" ,".output_min" ); 2609model .clamp_info_map [name ]= { 2610get_scalar (name_inp_max ,FLT_MAX ), 2611get_scalar (name_inp_min ,- FLT_MAX ), 2612get_scalar (name_out_max ,FLT_MAX ), 2613get_scalar (name_out_min ,- FLT_MAX ) 2614 }; 2615 } 2616 } 2617 }break ; 2618case PROJECTOR_TYPE_GEMMA4UV : 2619 { 2620model .mm_input_proj_w = get_tensor (TN_MM_INP_PROJ ); 2621model .patch_norm_1_w = get_tensor (string_format (TN_PATCH_NORM ,1 ,"weight" )); 2622model .patch_norm_1_b = get_tensor (string_format (TN_PATCH_NORM ,1 ,"bias" )); 2623model .patch_norm_2_w = get_tensor (string_format (TN_PATCH_NORM ,2 ,"weight" )); 2624model .patch_norm_2_b = get_tensor (string_format (TN_PATCH_NORM ,2 ,"bias" )); 2625model .patch_norm_3_w = get_tensor (string_format (TN_PATCH_NORM ,3 ,"weight" ));// pos_norm 2626model .patch_norm_3_b = get_tensor (string_format (TN_PATCH_NORM ,3 ,"bias" ));// pos_norm 2627 }break ; 2628case PROJECTOR_TYPE_GEMMA3NV : 2629 { 2630model .mobilenet_stem_conv_w = get_tensor (TN_MNV5_STEM_CONV , false); 2631model .mobilenet_stem_conv_b = get_tensor (TN_MNV5_STEM_BIAS , false); 2632model .mobilenet_stem_norm_w = get_tensor (TN_MNV5_STEM_BN , false); 2633 2634model .msfa_ffn_expand_w = get_tensor (TN_MNV5_MSFA_FFN_EXP_W , false); 2635model .msfa_ffn_expand_bn = get_tensor (TN_MNV5_MSFA_FFN_EXP_BN , false);// Consume BN if present but likely folded 2636model .msfa_ffn_project_w = get_tensor (TN_MNV5_MSFA_FFN_PROJ_W , false); 2637model .msfa_ffn_project_bn = get_tensor (TN_MNV5_MSFA_FFN_PROJ_BN , false); 2638 2639model .msfa_concat_norm_w = get_tensor (TN_MNV5_MSFA_NORM , false); 2640 2641// Dynamically load blocks stage by stage 2642for (int stage = 0 ;stage < 4 ;++ stage ) { 2643int blocks_found_in_stage = 0 ; 2644 2645for (int blk_idx = 0 ; ;++ blk_idx ) { 2646bool found_block = false; 2647mobilenetv5_block block ; 2648 2649// 1. Check for Edge Residual (S0) 2650block .s0_conv_exp_w = get_tensor (string_format (TN_MNV5_BLK_S0_EXP_W ,stage ,blk_idx ), false); 2651if (block .s0_conv_exp_w ) { 2652found_block = true; 2653block .s0_bn1_w = get_tensor (string_format (TN_MNV5_BLK_S0_BN1_W ,stage ,blk_idx ), false); 2654block .s0_conv_pwl_w = get_tensor (string_format (TN_MNV5_BLK_S0_PWL_W ,stage ,blk_idx ), false); 2655block .s0_bn2_w = get_tensor (string_format (TN_MNV5_BLK_S0_BN2_W ,stage ,blk_idx ), false); 2656 } 2657// 2. Check for UIR (Universal Inverted Residual) 2658else { 2659// Check for dw_start OR pw_exp (some UIR blocks skip dw_start) 2660block .dw_start_w = get_tensor (string_format (TN_MNV5_BLK_DW_START_W ,stage ,blk_idx ), false); 2661block .pw_exp_w = get_tensor (string_format (TN_MNV5_BLK_PW_EXP_W ,stage ,blk_idx ), false); 2662 2663if (block .dw_start_w || block .pw_exp_w ) { 2664found_block = true; 2665if (block .dw_start_w ) { 2666block .dw_start_bn_w = get_tensor (string_format (TN_MNV5_BLK_DW_START_BN ,stage ,blk_idx ), false); 2667 } 2668if (block .pw_exp_w ) { 2669block .pw_exp_bn_w = get_tensor (string_format (TN_MNV5_BLK_PW_EXP_BN ,stage ,blk_idx ), false); 2670 } 2671block .dw_mid_w = get_tensor (string_format (TN_MNV5_BLK_DW_MID_W ,stage ,blk_idx ), false); 2672if (block .dw_mid_w ) { 2673block .dw_mid_bn_w = get_tensor (string_format (TN_MNV5_BLK_DW_MID_BN ,stage ,blk_idx ), false); 2674 } 2675block .pw_proj_w = get_tensor (string_format (TN_MNV5_BLK_PW_PROJ_W ,stage ,blk_idx ), false); 2676if (block .pw_proj_w ) { 2677block .pw_proj_bn_w = get_tensor (string_format (TN_MNV5_BLK_PW_PROJ_BN ,stage ,blk_idx ), false); 2678 } 2679block .layer_scale_w = get_tensor (string_format (TN_MNV5_BLK_LAYER_SCALE ,stage ,blk_idx ), false); 2680 } 2681 } 2682 2683// 3. Check for Attention (MQA) 2684// Even if UIR/Edge check failed, this might be a pure attention block 2685ggml_tensor * attn_q_check = get_tensor (string_format (TN_MNV5_ATTN_Q_W ,stage ,blk_idx ), false); 2686if (attn_q_check ) { 2687found_block = true; 2688block .attn_q_w = attn_q_check ; 2689block .attn_k_w = get_tensor (string_format (TN_MNV5_ATTN_K_W ,stage ,blk_idx ), false); 2690block .attn_v_w = get_tensor (string_format (TN_MNV5_ATTN_V_W ,stage ,blk_idx ), false); 2691block .attn_o_w = get_tensor (string_format (TN_MNV5_ATTN_O_W ,stage ,blk_idx ), false); 2692block .attn_k_dw_w = get_tensor (string_format (TN_MNV5_ATTN_K_DW ,stage ,blk_idx ), false); 2693block .attn_k_norm_w = get_tensor (string_format (TN_MNV5_ATTN_K_NORM ,stage ,blk_idx ), false); 2694block .attn_v_dw_w = get_tensor (string_format (TN_MNV5_ATTN_V_DW ,stage ,blk_idx ), false); 2695block .attn_v_norm_w = get_tensor (string_format (TN_MNV5_ATTN_V_NORM ,stage ,blk_idx ), false); 2696block .attn_norm_w = get_tensor (string_format (TN_MNV5_ATTN_NORM ,stage ,blk_idx ), false); 2697// Note: Attention blocks also have layer_scale, load it if not already loaded by UIR check 2698if (!block .layer_scale_w ) { 2699block .layer_scale_w = get_tensor (string_format (TN_MNV5_BLK_LAYER_SCALE ,stage ,blk_idx ), false); 2700 } 2701 } 2702 2703if (found_block ) { 2704model .mobilenet_blocks .push_back (block ); 2705blocks_found_in_stage ++ ; 2706 }else { 2707// End of blocks for this stage 2708break ; 2709 } 2710 } 2711 2712// Track where this stage ends in the flat vector 2713if (blocks_found_in_stage > 0 ) { 2714model .mobilenet_stage_ends .push_back (model .mobilenet_blocks .size ()- 1 ); 2715LOG_INF ("%s: Stage %d ended at global block index %zu\n" ,__func__ ,stage ,model .mobilenet_blocks .size ()- 1 ); 2716 } 2717 } 2718model .mm_input_proj_w = get_tensor (TN_MM_INP_PROJ ); 2719model .mm_soft_emb_norm_w = get_tensor (TN_MM_SOFT_EMB_N ); 2720 }break ; 2721case PROJECTOR_TYPE_IDEFICS3 : 2722 { 2723model .mm_fc_w = get_tensor (string_format (TN_MM_PROJECTOR ,"weight" )); 2724 }break ; 2725case PROJECTOR_TYPE_LFM2 : 2726 { 2727model .mm_input_norm_w = get_tensor (TN_MM_INP_NORM , false); 2728model .mm_input_norm_b = get_tensor (TN_MM_INP_NORM_B , false); 2729model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2730model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" )); 2731model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2732model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2733 }break ; 2734case PROJECTOR_TYPE_KIMIVL : 2735case PROJECTOR_TYPE_PADDLEOCR : 2736case PROJECTOR_TYPE_KIMIK25 : 2737 { 2738model .mm_input_norm_w = get_tensor (TN_MM_INP_NORM ); 2739model .mm_input_norm_b = get_tensor (TN_MM_INP_NORM_B ); 2740model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2741model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" )); 2742model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2743model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2744 }break ; 2745case PROJECTOR_TYPE_DEEPSEEK4V : 2746 { 2747model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2748model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" )); 2749model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2750model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2751// sentinel token embeddings written into the output block 2752model .image_newline = get_tensor (TN_IMAGE_NEWLINE ); 2753model .token_embd_img_start = get_tensor (TN_TOK_IMG_START ); 2754model .token_embd_img_end = get_tensor (TN_TOK_IMG_END ); 2755model .token_embd_img_pad = get_tensor (TN_TOK_IMG_PAD ); 2756 }break ; 2757case PROJECTOR_TYPE_PIXTRAL : 2758 { 2759model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2760model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" ), false); 2761model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2762model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" ), false); 2763// [IMG_BREAK] token embedding 2764model .token_embd_img_break = get_tensor (TN_TOK_IMG_BREAK ); 2765// for mistral small 3.1 2766model .mm_input_norm_w = get_tensor (TN_MM_INP_NORM , false); 2767model .mm_patch_merger_w = get_tensor (string_format (TN_MM_PATCH_MERGER ,"weight" ), false); 2768 }break ; 2769case PROJECTOR_TYPE_LIGHTONOCR : 2770 { 2771model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 2772model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" ), false); 2773model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2774model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" ), false); 2775model .mm_input_norm_w = get_tensor (TN_MM_INP_NORM , false); 2776model .mm_patch_merger_w = get_tensor (string_format (TN_MM_PATCH_MERGER ,"weight" ), false); 2777 }break ; 2778case PROJECTOR_TYPE_DOTS_OCR : 2779case PROJECTOR_TYPE_DOTS3NOTE_V : 2780 { 2781model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 2782model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" )); 2783model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 2784model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 2785model .mm_input_norm_w = get_tensor (TN_MM_INP_NORM ); 2786model .mm_input_norm_b = get_tensor (TN_MM_INP_NORM_B ); 2787// post_trunk_norm: applied after all ViT blocks, before the merger 2788model .post_ln_w = get_tensor (string_format (TN_MM_POST_NORM ,"weight" )); 2789 }break ; 2790case PROJECTOR_TYPE_DOTS3NOTE_A : 2791 { 2792model .conv2d_1_w = get_tensor (string_format (TN_CONV2D ,1 ,"weight" )); 2793model .conv2d_1_b = get_tensor (string_format (TN_CONV2D ,1 ,"bias" )); 2794model .conv2d_2_w = get_tensor (string_format (TN_CONV2D ,2 ,"weight" )); 2795model .conv2d_2_b = get_tensor (string_format (TN_CONV2D ,2 ,"bias" )); 2796model .conv2d_3_w = get_tensor (string_format (TN_CONV2D ,3 ,"weight" )); 2797model .conv2d_3_b = get_tensor (string_format (TN_CONV2D ,3 ,"bias" )); 2798model .conv_out_w = get_tensor (string_format (TN_CONV_OUT ,"weight" ));// no bias 2799// adapter: LayerNorm -> Linear -> GELU -> Linear 2800model .mm_norm_pre_w = get_tensor (string_format (TN_MM_NORM_PRE ,"weight" )); 2801model .mm_norm_pre_b = get_tensor (string_format (TN_MM_NORM_PRE ,"bias" )); 2802model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 2803model .mm_1_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"bias" )); 2804model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,3 ,"weight" )); 2805model .mm_2_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,3 ,"bias" )); 2806 }break ; 2807case PROJECTOR_TYPE_ULTRAVOX : 2808 { 2809model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,1 ,"weight" )); 2810model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,1 ,"bias" )); 2811model .conv1d_2_w = get_tensor (string_format (TN_CONV1D ,2 ,"weight" )); 2812model .conv1d_2_b = get_tensor (string_format (TN_CONV1D ,2 ,"bias" )); 2813model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 2814model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" )); 2815model .mm_norm_pre_w = get_tensor (string_format (TN_MM_NORM_PRE ,"weight" )); 2816model .mm_norm_mid_w = get_tensor (string_format (TN_MM_NORM_MID ,"weight" )); 2817 }break ; 2818case PROJECTOR_TYPE_MERALION : 2819 { 2820// Whisper encoder conv layers 2821model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,1 ,"weight" )); 2822model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,1 ,"bias" )); 2823model .conv1d_2_w = get_tensor (string_format (TN_CONV1D ,2 ,"weight" )); 2824model .conv1d_2_b = get_tensor (string_format (TN_CONV1D ,2 ,"bias" )); 2825// MERaLiON adaptor: 4 linear layers + ln_pre 2826// linear_0 = frame compression (19200->6400) + SiLU 2827// linear_1 = gate_proj (6400->6400) for GLU 2828// linear_2 = pool_proj (6400->6400) for GLU 2829// linear_3 = out_proj (6400->3584) 2830model .mm_0_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,0 ,"weight" )); 2831model .mm_0_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,0 ,"bias" )); 2832model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 2833model .mm_1_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"bias" )); 2834model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" )); 2835model .mm_2_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"bias" )); 2836model .mm_3_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,3 ,"weight" )); 2837model .mm_3_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,3 ,"bias" )); 2838// ln_speech (LayerNorm before adaptor) 2839model .mm_norm_pre_w = get_tensor (string_format (TN_MM_NORM_PRE ,"weight" )); 2840model .mm_norm_pre_b = get_tensor (string_format (TN_MM_NORM_PRE ,"bias" )); 2841 }break ; 2842case PROJECTOR_TYPE_QWEN2A : 2843 { 2844model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,1 ,"weight" )); 2845model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,1 ,"bias" )); 2846model .conv1d_2_w = get_tensor (string_format (TN_CONV1D ,2 ,"weight" )); 2847model .conv1d_2_b = get_tensor (string_format (TN_CONV1D ,2 ,"bias" )); 2848model .mm_fc_w = get_tensor (string_format (TN_MM_AUDIO_FC ,"weight" )); 2849model .mm_fc_b = get_tensor (string_format (TN_MM_AUDIO_FC ,"bias" )); 2850 }break ; 2851case PROJECTOR_TYPE_QWEN3A : 2852 { 2853model .conv2d_1_w = get_tensor (string_format (TN_CONV2D ,1 ,"weight" )); 2854model .conv2d_1_b = get_tensor (string_format (TN_CONV2D ,1 ,"bias" )); 2855model .conv2d_2_w = get_tensor (string_format (TN_CONV2D ,2 ,"weight" )); 2856model .conv2d_2_b = get_tensor (string_format (TN_CONV2D ,2 ,"bias" )); 2857model .conv2d_3_w = get_tensor (string_format (TN_CONV2D ,3 ,"weight" )); 2858model .conv2d_3_b = get_tensor (string_format (TN_CONV2D ,3 ,"bias" )); 2859model .conv_out_w = get_tensor (string_format (TN_CONV_OUT ,"weight" ));// no bias 2860model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 2861model .mm_1_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"bias" )); 2862model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" )); 2863model .mm_2_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"bias" )); 2864 }break ; 2865case PROJECTOR_TYPE_MIMO_AUDIO : 2866 { 2867model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,1 ,"weight" )); 2868model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,1 ,"bias" )); 2869model .conv1d_2_w = get_tensor (string_format (TN_CONV1D ,2 ,"weight" )); 2870model .conv1d_2_b = get_tensor (string_format (TN_CONV1D ,2 ,"bias" )); 2871model .downsample_conv_w = get_tensor (string_format (TN_A_DOWNSAMPLE_CONV ,"weight" )); 2872model .downsample_norm_w = get_tensor (string_format (TN_A_DOWNSAMPLE_NORM ,"weight" )); 2873model .downsample_norm_b = get_tensor (string_format (TN_A_DOWNSAMPLE_NORM ,"bias" )); 2874model .rvq_codebook = get_tensor (string_format (TN_A_RVQ_CODEBOOK ,"weight" ), false); 2875model .mm_a_code_embd = get_tensor (string_format (TN_MM_A_CODE_EMBD ,"weight" ), false); 2876if (!model .rvq_codebook || !model .mm_a_code_embd ) { 2877throw std::runtime_error (string_format ("%s: mimo_audio: missing %s or %s\n" ,__func__ , 2878TN_A_RVQ_CODEBOOK ,TN_MM_A_CODE_EMBD )); 2879 } 2880// hparams.rvq_codebook_size comes from GGUF metadata and is independent of the 2881// tensors' actual shapes - bound it so codebook/code_embd views built from it 2882// (mimo-audio.cpp) can never read past either tensor's allocated bins/vocab. 2883for (int32_t bins :hparams .rvq_codebook_size ) { 2884if (bins <=0 || bins > model .rvq_codebook -> ne [1 ]|| bins > model .mm_a_code_embd -> ne [1 ]) { 2885throw std::runtime_error (string_format ( 2886"%s: mimo_audio: %s entry (%d) out of range for codebook/code_embd tensors\n" , 2887__func__ ,KEY_A_RVQ_CODEBOOK_SIZE ,bins )); 2888 } 2889 } 2890 2891// LLM-side connector: input_local_transformer + projection 2892model .mm_a_local_layers .resize (hparams .audio_local_n_layer ); 2893for (int il = 0 ;il < hparams .audio_local_n_layer ;il ++ ) { 2894auto & layer = model .mm_a_local_layers [il ]; 2895layer .q_w = get_tensor (string_format (TN_MM_A_LOCAL_ATTN_Q ,il ,"weight" )); 2896layer .q_b = get_tensor (string_format (TN_MM_A_LOCAL_ATTN_Q ,il ,"bias" )); 2897layer .k_w = get_tensor (string_format (TN_MM_A_LOCAL_ATTN_K ,il ,"weight" )); 2898layer .k_b = get_tensor (string_format (TN_MM_A_LOCAL_ATTN_K ,il ,"bias" )); 2899layer .v_w = get_tensor (string_format (TN_MM_A_LOCAL_ATTN_V ,il ,"weight" )); 2900layer .v_b = get_tensor (string_format (TN_MM_A_LOCAL_ATTN_V ,il ,"bias" )); 2901layer .o_w = get_tensor (string_format (TN_MM_A_LOCAL_ATTN_OUT ,il ,"weight" )); 2902layer .ff_gate_w = get_tensor (string_format (TN_MM_A_LOCAL_FFN_GATE ,il ,"weight" )); 2903layer .ff_up_w = get_tensor (string_format (TN_MM_A_LOCAL_FFN_UP ,il ,"weight" )); 2904layer .ff_down_w = get_tensor (string_format (TN_MM_A_LOCAL_FFN_DOWN ,il ,"weight" )); 2905layer .ln_1_w = get_tensor (string_format (TN_MM_A_LOCAL_LN1 ,il ,"weight" )); 2906layer .ln_2_w = get_tensor (string_format (TN_MM_A_LOCAL_LN2 ,il ,"weight" )); 2907 } 2908model .mm_a_local_norm_w = get_tensor (string_format (TN_MM_A_LOCAL_NORM ,"weight" )); 2909 2910model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 2911model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" )); 2912 }break ; 2913case PROJECTOR_TYPE_QWEN3TTS_SPKENC : 2914 { 2915// stem TDNN (block 0) 2916model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,0 ,"weight" )); 2917model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,0 ,"bias" )); 2918 2919// SE-Res2Net blocks (GGUF bid 1..3, one per hparams.n_layer) 2920model .layers .resize (hparams .n_layer ); 2921for (int il = 0 ;il < hparams .n_layer ;il ++ ) { 2922auto & layer = model .layers [il ]; 2923int bid = il + 1 ; 2924layer .conv_pw1_w = get_tensor (string_format (TN_CONV_PW1 ,prefix ,bid ,"weight" )); 2925layer .conv_pw1_b = get_tensor (string_format (TN_CONV_PW1 ,prefix ,bid ,"bias" )); 2926layer .conv_pw2_w = get_tensor (string_format (TN_CONV_PW2 ,prefix ,bid ,"weight" )); 2927layer .conv_pw2_b = get_tensor (string_format (TN_CONV_PW2 ,prefix ,bid ,"bias" )); 2928layer .se_conv1_w = get_tensor (string_format (TN_A_SE_CONV1 ,bid ,"weight" )); 2929layer .se_conv1_b = get_tensor (string_format (TN_A_SE_CONV1 ,bid ,"bias" )); 2930layer .se_conv2_w = get_tensor (string_format (TN_A_SE_CONV2 ,bid ,"weight" )); 2931layer .se_conv2_b = get_tensor (string_format (TN_A_SE_CONV2 ,bid ,"bias" )); 2932layer .res2_conv_w .resize (7 ); 2933layer .res2_conv_b .resize (7 ); 2934for (int xid = 0 ;xid < 7 ;xid ++ ) { 2935layer .res2_conv_w [xid ]= get_tensor (string_format (TN_A_CONV_RES2 ,bid ,xid ,"weight" )); 2936layer .res2_conv_b [xid ]= get_tensor (string_format (TN_A_CONV_RES2 ,bid ,xid ,"bias" )); 2937 } 2938 } 2939 2940// multi-layer feature aggregation 2941model .conv_out_w = get_tensor (string_format (TN_CONV_OUT ,"weight" )); 2942model .conv_out_b = get_tensor (string_format (TN_CONV_OUT ,"bias" )); 2943 2944// attentive statistics pooling 2945model .spk_asp_attn_w = get_tensor (string_format (TN_A_ASP_ATTN ,"weight" )); 2946model .spk_asp_attn_b = get_tensor (string_format (TN_A_ASP_ATTN ,"bias" )); 2947model .spk_asp_tdnn_w = get_tensor (string_format (TN_A_ASP_TDNN ,"weight" )); 2948model .spk_asp_tdnn_b = get_tensor (string_format (TN_A_ASP_TDNN ,"bias" )); 2949 2950// final speaker embedding projection 2951model .mm_fc_w = get_tensor (string_format (TN_MM_AUDIO_FC ,"weight" )); 2952model .mm_fc_b = get_tensor (string_format (TN_MM_AUDIO_FC ,"bias" )); 2953 }break ; 2954case PROJECTOR_TYPE_POCKETTTS_SPKENC : 2955 { 2956load_seanet (model .seanet , false); 2957model .downsample_w = get_tensor (string_format (TN_A_DOWNSAMPLE_CONV ,"weight" )); 2958model .spk_proj_w = get_tensor (string_format (TN_A_SPEAKER_PROJ ,"weight" )); 2959 }break ; 2960case PROJECTOR_TYPE_POCKETTTS_GEN : 2961 { 2962auto & flow = model .flow ; 2963flow .input_proj_w = get_tensor (string_format (TN_A_GEN_FLOW_INPUT_PROJ ,"weight" )); 2964flow .input_proj_b = get_tensor (string_format (TN_A_GEN_FLOW_INPUT_PROJ ,"bias" )); 2965flow .cond_embd_w = get_tensor (string_format (TN_A_GEN_FLOW_COND_EMBD ,"weight" )); 2966flow .cond_embd_b = get_tensor (string_format (TN_A_GEN_FLOW_COND_EMBD ,"bias" )); 2967flow .final_ada_w = get_tensor (string_format (TN_A_GEN_FLOW_FINAL_ADA ,"weight" )); 2968flow .final_ada_b = get_tensor (string_format (TN_A_GEN_FLOW_FINAL_ADA ,"bias" )); 2969flow .final_proj_w = get_tensor (string_format (TN_A_GEN_FLOW_FINAL_PROJ ,"weight" )); 2970flow .final_proj_b = get_tensor (string_format (TN_A_GEN_FLOW_FINAL_PROJ ,"bias" )); 2971 2972flow .time .resize (2 ); 2973for (size_t i = 0 ;i < flow .time .size ();i ++ ) { 2974auto & t = flow .time [i ]; 2975t .freqs = get_tensor (string_format (TN_A_GEN_FLOW_TIME_FREQS , (int )i )); 2976t .up_w = get_tensor (string_format (TN_A_GEN_FLOW_TIME_UP , (int )i ,"weight" )); 2977t .up_b = get_tensor (string_format (TN_A_GEN_FLOW_TIME_UP , (int )i ,"bias" )); 2978t .down_w = get_tensor (string_format (TN_A_GEN_FLOW_TIME_DOWN , (int )i ,"weight" )); 2979t .down_b = get_tensor (string_format (TN_A_GEN_FLOW_TIME_DOWN , (int )i ,"bias" )); 2980t .norm = get_tensor (string_format (TN_A_GEN_FLOW_TIME_NORM , (int )i )); 2981 } 2982 2983// one AdaLN block per flow depth, the count is only known from the tensors 2984for (int il = 0 ; ;il ++ ) { 2985ggml_tensor * probe = get_tensor (string_format (TN_A_GEN_FLOW_BLK_NORM ,il ,"weight" ), false); 2986if (probe == nullptr ) { 2987break ; 2988 } 2989 clip_flow_net::block blk ; 2990blk .norm_w = probe ; 2991blk .norm_b = get_tensor (string_format (TN_A_GEN_FLOW_BLK_NORM ,il ,"bias" )); 2992blk .up_w = get_tensor (string_format (TN_A_GEN_FLOW_BLK_UP ,il ,"weight" )); 2993blk .up_b = get_tensor (string_format (TN_A_GEN_FLOW_BLK_UP ,il ,"bias" )); 2994blk .down_w = get_tensor (string_format (TN_A_GEN_FLOW_BLK_DOWN ,il ,"weight" )); 2995blk .down_b = get_tensor (string_format (TN_A_GEN_FLOW_BLK_DOWN ,il ,"bias" )); 2996blk .ada_w = get_tensor (string_format (TN_A_GEN_FLOW_BLK_ADA ,il ,"weight" )); 2997blk .ada_b = get_tensor (string_format (TN_A_GEN_FLOW_BLK_ADA ,il ,"bias" )); 2998flow .blocks .push_back (blk ); 2999 } 3000 3001model .gen_out_eos_w = get_tensor (string_format (TN_A_GEN_OUT_EOS ,"weight" )); 3002model .gen_out_eos_b = get_tensor (string_format (TN_A_GEN_OUT_EOS ,"bias" )); 3003model .gen_input_lin_w = get_tensor (string_format (TN_A_GEN_INPUT_LINEAR ,"weight" )); 3004model .gen_emb_mean = get_tensor (TN_A_GEN_EMB_MEAN ); 3005model .gen_emb_std = get_tensor (TN_A_GEN_EMB_STD ); 3006 3007// mimi decoder 3008model .gen_quant_out_w = get_tensor (string_format (TN_A_GEN_WAV_QUANT_OUT ,"weight" )); 3009model .gen_upsample_w = get_tensor (string_format (TN_A_GEN_WAV_UPSAMPLE ,"weight" )); 3010load_seanet (model .seanet , true); 3011model .gen_tfm_layers .resize (hparams .n_layer ); 3012for (int il = 0 ;il < hparams .n_layer ;il ++ ) { 3013auto & layer = model .gen_tfm_layers [il ]; 3014const char * p = "a.gen.wav.tfm" ; 3015layer .ln_1_w = get_tensor (string_format (TN_LN_1 ,p ,il ,"weight" )); 3016layer .ln_1_b = get_tensor (string_format (TN_LN_1 ,p ,il ,"bias" )); 3017layer .q_w = get_tensor (string_format (TN_ATTN_Q ,p ,il ,"weight" )); 3018layer .k_w = get_tensor (string_format (TN_ATTN_K ,p ,il ,"weight" )); 3019layer .v_w = get_tensor (string_format (TN_ATTN_V ,p ,il ,"weight" )); 3020layer .o_w = get_tensor (string_format (TN_ATTN_OUTPUT ,p ,il ,"weight" )); 3021layer .ls_1_w = get_tensor (string_format (TN_LS_1 ,p ,il ,"weight" )); 3022layer .ln_2_w = get_tensor (string_format (TN_LN_2 ,p ,il ,"weight" )); 3023layer .ln_2_b = get_tensor (string_format (TN_LN_2 ,p ,il ,"bias" )); 3024layer .ff_up_w = get_tensor (string_format (TN_FFN_UP ,p ,il ,"weight" )); 3025layer .ff_down_w = get_tensor (string_format (TN_FFN_DOWN ,p ,il ,"weight" )); 3026layer .ls_2_w = get_tensor (string_format (TN_LS_2 ,p ,il ,"weight" )); 3027 } 3028 }break ; 3029case PROJECTOR_TYPE_QWEN3TTS_GEN : 3030 { 3031// code_predictor, proj_in is absent when the talker and the predictor share the hidden size 3032model .gen_code_proj_in_w = get_tensor (string_format (TN_A_GEN_CODE_PROJ_IN ,"weight" ), false); 3033model .gen_code_proj_in_b = get_tensor (string_format (TN_A_GEN_CODE_PROJ_IN ,"bias" ), false); 3034model .gen_code_embd_w = get_tensor (string_format (TN_A_GEN_CODE_EMBD ,"weight" )); 3035model .gen_code_head_w = get_tensor (string_format (TN_A_GEN_CODE_HEAD ,"weight" )); 3036model .gen_code_out_embd_w = get_tensor (string_format (TN_A_GEN_CODE_OUT_EMBD ,"weight" )); 3037model .gen_code_norm_w = get_tensor (string_format (TN_A_GEN_CODE_NORM ,"weight" )); 3038 3039// code2wav: RVQ codes -> raw PCM, lives in the same ctx as code_predictor 3040 { 3041auto & c2w = model .c2w ; 3042 3043c2w .quant_first_in_w = get_tensor (string_format (TN_A_GEN_WAV_QUANT_FIRST_IN ,"weight" )); 3044c2w .quant_first_out_w = get_tensor (string_format (TN_A_GEN_WAV_QUANT_FIRST_OUT ,"weight" )); 3045c2w .quant_first_cb_w = get_tensor (string_format (TN_A_GEN_WAV_QUANT_FIRST_CB ,"weight" )); 3046c2w .quant_rest_in_w = get_tensor (string_format (TN_A_GEN_WAV_QUANT_REST_IN ,"weight" )); 3047c2w .quant_rest_out_w = get_tensor (string_format (TN_A_GEN_WAV_QUANT_REST_OUT ,"weight" )); 3048c2w .quant_rest_cb_w = get_tensor (string_format (TN_A_GEN_WAV_QUANT_REST_CB ,"weight" )); 3049 3050c2w .pre_conv_w = get_tensor (string_format (TN_A_GEN_WAV_PRE_CONV ,"weight" )); 3051c2w .pre_conv_b = get_tensor (string_format (TN_A_GEN_WAV_PRE_CONV ,"bias" )); 3052 3053c2w .tfm_in_proj_w = get_tensor (string_format (TN_A_GEN_WAV_TFM_IN_PROJ ,"weight" )); 3054c2w .tfm_in_proj_b = get_tensor (string_format (TN_A_GEN_WAV_TFM_IN_PROJ ,"bias" )); 3055c2w .tfm_out_proj_w = get_tensor (string_format (TN_A_GEN_WAV_TFM_OUT_PROJ ,"weight" )); 3056c2w .tfm_out_proj_b = get_tensor (string_format (TN_A_GEN_WAV_TFM_OUT_PROJ ,"bias" )); 3057c2w .tfm_output_norm_w = get_tensor (string_format (TN_A_GEN_WAV_TFM_OUT_NORM ,"weight" )); 3058 3059// loaded manually, the generic model.layers loop is taken by code_predictor 3060c2w .tfm_layers .resize (hparams .wav_tfm_n_layer ); 3061for (int il = 0 ;il < hparams .wav_tfm_n_layer ;il ++ ) { 3062auto & layer = c2w .tfm_layers [il ]; 3063const char * p = "a.gen.wav.tfm" ; 3064layer .q_w = get_tensor (string_format (TN_ATTN_Q ,p ,il ,"weight" )); 3065layer .k_w = get_tensor (string_format (TN_ATTN_K ,p ,il ,"weight" )); 3066layer .v_w = get_tensor (string_format (TN_ATTN_V ,p ,il ,"weight" )); 3067layer .o_w = get_tensor (string_format (TN_ATTN_OUTPUT ,p ,il ,"weight" )); 3068layer .ln_1_w = get_tensor (string_format (TN_LN_1 ,p ,il ,"weight" )); 3069layer .ln_2_w = get_tensor (string_format (TN_LN_2 ,p ,il ,"weight" )); 3070layer .ls_1_w = get_tensor (string_format (TN_LS_1 ,p ,il ,"weight" )); 3071layer .ls_2_w = get_tensor (string_format (TN_LS_2 ,p ,il ,"weight" )); 3072layer .ff_gate_w = get_tensor (string_format (TN_FFN_GATE ,p ,il ,"weight" )); 3073layer .ff_up_w = get_tensor (string_format (TN_FFN_UP ,p ,il ,"weight" )); 3074layer .ff_down_w = get_tensor (string_format (TN_FFN_DOWN ,p ,il ,"weight" )); 3075 } 3076 3077// upsample: 2x (causal ConvTranspose1d + ConvNeXt block) 3078c2w .upsample .resize (hparams .wav_upsample_n_block ); 3079for (int il = 0 ;il < hparams .wav_upsample_n_block ;il ++ ) { 3080auto & up = c2w .upsample [il ]; 3081up .conv_w = get_tensor (string_format (TN_A_GEN_WAV_UP_CONV ,il ,"weight" )); 3082up .conv_b = get_tensor (string_format (TN_A_GEN_WAV_UP_CONV ,il ,"bias" )); 3083up .dwconv_w = get_tensor (string_format (TN_A_GEN_WAV_UP_DWCONV ,il ,"weight" )); 3084up .dwconv_b = get_tensor (string_format (TN_A_GEN_WAV_UP_DWCONV ,il ,"bias" )); 3085up .norm_w = get_tensor (string_format (TN_A_GEN_WAV_UP_NORM ,il ,"weight" )); 3086up .norm_b = get_tensor (string_format (TN_A_GEN_WAV_UP_NORM ,il ,"bias" )); 3087up .pw1_w = get_tensor (string_format (TN_A_GEN_WAV_UP_PW1 ,il ,"weight" )); 3088up .pw1_b = get_tensor (string_format (TN_A_GEN_WAV_UP_PW1 ,il ,"bias" )); 3089up .pw2_w = get_tensor (string_format (TN_A_GEN_WAV_UP_PW2 ,il ,"weight" )); 3090up .pw2_b = get_tensor (string_format (TN_A_GEN_WAV_UP_PW2 ,il ,"bias" )); 3091up .gamma = get_tensor (string_format (TN_A_GEN_WAV_UP_GAMMA ,il )); 3092 } 3093 3094// DAC decoder: conv_pre + n upsample blocks (each with n_res residual units) + conv_post 3095c2w .dac_entry_w = get_tensor (string_format (TN_A_GEN_WAV_DAC_ENTRY ,"weight" )); 3096c2w .dac_entry_b = get_tensor (string_format (TN_A_GEN_WAV_DAC_ENTRY ,"bias" )); 3097 3098c2w .dac .resize (hparams .wav_dac_n_block ); 3099for (int il = 0 ;il < hparams .wav_dac_n_block ;il ++ ) { 3100auto & blk = c2w .dac [il ]; 3101blk .snake_alpha = get_tensor (string_format (TN_A_GEN_WAV_DAC_SNAKE ,il ,"alpha" )); 3102blk .snake_beta = get_tensor (string_format (TN_A_GEN_WAV_DAC_SNAKE ,il ,"beta" )); 3103blk .conv_w = get_tensor (string_format (TN_A_GEN_WAV_DAC_CONV ,il ,"weight" )); 3104blk .conv_b = get_tensor (string_format (TN_A_GEN_WAV_DAC_CONV ,il ,"bias" )); 3105 3106blk .res .resize (hparams .wav_dac_n_res ); 3107for (int ir = 0 ;ir < hparams .wav_dac_n_res ;ir ++ ) { 3108auto & res = blk .res [ir ]; 3109res .act1_alpha = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_ACT1 ,il ,ir ,"alpha" )); 3110res .act1_beta = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_ACT1 ,il ,ir ,"beta" )); 3111res .conv1_w = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_CONV1 ,il ,ir ,"weight" )); 3112res .conv1_b = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_CONV1 ,il ,ir ,"bias" )); 3113res .act2_alpha = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_ACT2 ,il ,ir ,"alpha" )); 3114res .act2_beta = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_ACT2 ,il ,ir ,"beta" )); 3115res .conv2_w = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_CONV2 ,il ,ir ,"weight" )); 3116res .conv2_b = get_tensor (string_format (TN_A_GEN_WAV_DAC_RES_CONV2 ,il ,ir ,"bias" )); 3117 } 3118 } 3119 3120c2w .dac_post_snake_alpha = get_tensor (string_format (TN_A_GEN_WAV_DAC_POST_SNAKE ,"alpha" )); 3121c2w .dac_post_snake_beta = get_tensor (string_format (TN_A_GEN_WAV_DAC_POST_SNAKE ,"beta" )); 3122c2w .dac_post_conv_w = get_tensor (string_format (TN_A_GEN_WAV_DAC_POST_CONV ,"weight" )); 3123c2w .dac_post_conv_b = get_tensor (string_format (TN_A_GEN_WAV_DAC_POST_CONV ,"bias" )); 3124 } 3125 }break ; 3126case PROJECTOR_TYPE_VOXTRAL : 3127 { 3128model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,1 ,"weight" )); 3129model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,1 ,"bias" )); 3130model .conv1d_2_w = get_tensor (string_format (TN_CONV1D ,2 ,"weight" )); 3131model .conv1d_2_b = get_tensor (string_format (TN_CONV1D ,2 ,"bias" )); 3132model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 3133model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" )); 3134 }break ; 3135case PROJECTOR_TYPE_MUSIC_FLAMINGO : 3136 { 3137model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,1 ,"weight" )); 3138model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,1 ,"bias" )); 3139model .conv1d_2_w = get_tensor (string_format (TN_CONV1D ,2 ,"weight" )); 3140model .conv1d_2_b = get_tensor (string_format (TN_CONV1D ,2 ,"bias" )); 3141model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 3142model .mm_1_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"bias" )); 3143model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" )); 3144model .mm_2_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"bias" )); 3145 }break ; 3146case PROJECTOR_TYPE_INTERNVL : 3147 { 3148model .mm_0_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,0 ,"weight" )); 3149model .mm_0_b = get_tensor (string_format (TN_MVLM_PROJ_MLP ,0 ,"bias" )); 3150model .mm_1_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,1 ,"weight" )); 3151model .mm_1_b = get_tensor (string_format (TN_MVLM_PROJ_MLP ,1 ,"bias" )); 3152model .mm_3_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,3 ,"weight" )); 3153model .mm_3_b = get_tensor (string_format (TN_MVLM_PROJ_MLP ,3 ,"bias" )); 3154 }break ; 3155case PROJECTOR_TYPE_NEMOTRON_V2_VL : 3156 { 3157model .mm_0_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,0 ,"weight" )); 3158model .mm_1_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,1 ,"weight" )); 3159model .mm_3_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,3 ,"weight" )); 3160 }break ; 3161case PROJECTOR_TYPE_GLMA : 3162 { 3163model .conv1d_1_w = get_tensor (string_format (TN_CONV1D ,1 ,"weight" )); 3164model .conv1d_1_b = get_tensor (string_format (TN_CONV1D ,1 ,"bias" )); 3165model .conv1d_2_w = get_tensor (string_format (TN_CONV1D ,2 ,"weight" )); 3166model .conv1d_2_b = get_tensor (string_format (TN_CONV1D ,2 ,"bias" )); 3167model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 3168model .mm_1_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"bias" )); 3169model .mm_2_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" )); 3170model .mm_2_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"bias" )); 3171model .mm_norm_pre_w = get_tensor (string_format (TN_MM_NORM_PRE ,"weight" )); 3172model .mm_norm_pre_b = get_tensor (string_format (TN_MM_NORM_PRE ,"bias" )); 3173model .mm_boi = get_tensor (string_format (TN_TOK_BOI )); 3174model .mm_eoi = get_tensor (string_format (TN_TOK_EOI )); 3175 }break ; 3176case PROJECTOR_TYPE_LLAMA4 : 3177 { 3178model .mm_model_proj = get_tensor (string_format (TN_MM_PROJECTOR ,"weight" )); 3179model .mm_model_mlp_1_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,1 ,"weight" )); 3180model .mm_model_mlp_2_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,2 ,"weight" )); 3181 }break ; 3182case PROJECTOR_TYPE_COGVLM : 3183 { 3184model .mm_model_proj = get_tensor (string_format (TN_MM_PROJECTOR ,"weight" )); 3185model .mm_post_fc_norm_w = get_tensor (string_format (TN_MM_POST_FC_NORM ,"weight" )); 3186model .mm_post_fc_norm_b = get_tensor (string_format (TN_MM_POST_FC_NORM ,"bias" )); 3187model .mm_h_to_4h_w = get_tensor (string_format (TN_MM_H_TO_4H ,"weight" )); 3188model .mm_gate_w = get_tensor (string_format (TN_MM_GATE ,"weight" )); 3189model .mm_4h_to_h_w = get_tensor (string_format (TN_MM_4H_TO_H ,"weight" )); 3190model .mm_boi = get_tensor (TN_TOK_BOI ); 3191model .mm_eoi = get_tensor (TN_TOK_EOI ); 3192 }break ; 3193case PROJECTOR_TYPE_HUNYUANVL : 3194 { 3195// proj.0 -> mm.0 (conv1), proj.2 -> mm.2 (conv2), mlp -> mm.model.fc (linear) 3196model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 3197model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" )); 3198model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 3199model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 3200model .mm_model_proj = get_tensor (string_format (TN_MM_PROJECTOR ,"weight" )); 3201model .mm_model_proj_b = get_tensor (string_format (TN_MM_PROJECTOR ,"bias" )); 3202model .mm_pre_norm_w = get_tensor (string_format (TN_MM_PRE_NORM ,"weight" )); 3203model .mm_post_norm_w = get_tensor (string_format (TN_MM_POST_NORM ,"weight" )); 3204model .mm_img_begin = get_tensor (TN_MM_IMG_BEGIN ); 3205model .mm_img_end = get_tensor (TN_MM_IMG_END ); 3206model .image_newline = get_tensor (TN_IMAGE_NEWLINE ); 3207model .view_seperator = get_tensor (TN_IMAGE_SEPERATOR , false); 3208 }break ; 3209case PROJECTOR_TYPE_JANUS_PRO : 3210 { 3211model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 3212model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" )); 3213model .mm_1_w = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"weight" )); 3214model .mm_1_b = get_tensor (string_format (TN_LLAVA_PROJ ,1 ,"bias" )); 3215 }break ; 3216case PROJECTOR_TYPE_PHI4 : 3217 { 3218model .mm_0_w = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"weight" )); 3219model .mm_0_b = get_tensor (string_format (TN_LLAVA_PROJ ,0 ,"bias" )); 3220model .mm_2_w = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"weight" )); 3221model .mm_2_b = get_tensor (string_format (TN_LLAVA_PROJ ,2 ,"bias" )); 3222 }break ; 3223case PROJECTOR_TYPE_DEEPSEEKOCR : 3224case PROJECTOR_TYPE_DEEPSEEKOCR2 : 3225 { 3226model .pos_embed = get_tensor (string_format (TN_SAM_POS_EMBD ,"weight" )); 3227model .patch_embed_proj_w = get_tensor (string_format (TN_SAM_PATCH_EMBD ,"weight" )); 3228model .patch_embed_proj_b = get_tensor (string_format (TN_SAM_PATCH_EMBD ,"bias" )); 3229model .sam_layers .resize (model .n_sam_layers ); 3230for (int il = 0 ;il < model .n_sam_layers ;++ il ) { 3231auto & layer = model .sam_layers [il ]; 3232layer .qkv_w = get_tensor (string_format (TN_SAM_ATTN_QKV ,il ,"weight" )); 3233layer .qkv_b = get_tensor (string_format (TN_SAM_ATTN_QKV ,il ,"bias" )); 3234layer .o_w = get_tensor (string_format (TN_SAM_ATTN_OUT ,il ,"weight" )); 3235layer .o_b = get_tensor (string_format (TN_SAM_ATTN_OUT ,il ,"bias" )); 3236layer .ln_1_w = get_tensor (string_format (TN_SAM_PRE_NORM ,il ,"weight" )); 3237layer .ln_1_b = get_tensor (string_format (TN_SAM_PRE_NORM ,il ,"bias" )); 3238layer .ln_2_w = get_tensor (string_format (TN_SAM_POST_NORM ,il ,"weight" )); 3239layer .ln_2_b = get_tensor (string_format (TN_SAM_POST_NORM ,il ,"bias" )); 3240layer .rel_pos_h = get_tensor (string_format (TN_SAM_ATTN_POS_H ,il ,"weight" )); 3241layer .rel_pos_w = get_tensor (string_format (TN_SAM_ATTN_POS_W ,il ,"weight" )); 3242layer .ff_up_w = get_tensor (string_format (TN_SAM_FFN_UP ,il ,"weight" )); 3243layer .ff_up_b = get_tensor (string_format (TN_SAM_FFN_UP ,il ,"bias" )); 3244layer .ff_down_w = get_tensor (string_format (TN_SAM_FFN_DOWN ,il ,"weight" )); 3245layer .ff_down_b = get_tensor (string_format (TN_SAM_FFN_DOWN ,il ,"bias" )); 3246 } 3247model .neck_0_w = get_tensor (string_format (TN_SAM_NECK ,0 ,"weight" )); 3248model .neck_1_b = get_tensor (string_format (TN_SAM_NECK ,1 ,"bias" )); 3249model .neck_1_w = get_tensor (string_format (TN_SAM_NECK ,1 ,"weight" )); 3250model .neck_2_w = get_tensor (string_format (TN_SAM_NECK ,2 ,"weight" )); 3251model .neck_3_b = get_tensor (string_format (TN_SAM_NECK ,3 ,"bias" )); 3252model .neck_3_w = get_tensor (string_format (TN_SAM_NECK ,3 ,"weight" )); 3253model .net_2 = get_tensor (string_format (TN_SAM_NET ,2 ,"weight" )); 3254model .net_3 = get_tensor (string_format (TN_SAM_NET ,3 ,"weight" )); 3255model .image_newline = get_tensor (TN_IMAGE_NEWLINE , false); 3256model .view_seperator = get_tensor (TN_IMAGE_SEPERATOR ); 3257model .mm_fc_w = get_tensor (string_format (TN_MM_PROJECTOR ,"weight" )); 3258model .mm_fc_b = get_tensor (string_format (TN_MM_PROJECTOR ,"bias" )); 3259model .resample_query_768 = get_tensor (string_format (TN_RESMPL_QUERY ,768 ,"weight" ), false); 3260model .resample_query_1024 = get_tensor (string_format (TN_RESMPL_QUERY ,1024 ,"weight" ), false); 3261 }break ; 3262case PROJECTOR_TYPE_GEMMA4A : 3263 { 3264for (int i = 0 ;i < 2 ;i ++ ) { 3265model .sscp_conv_w [i ]= get_tensor (string_format (TN_A_CONV1D ,i ,"weight" )); 3266model .sscp_conv_b [i ]= get_tensor (string_format (TN_A_CONV1D ,i ,"bias" ), false); 3267model .sscp_norm_w [i ]= get_tensor (string_format (TN_A_CONV1D_NORM ,i ,"weight" ), false); 3268 } 3269model .sscp_inp_proj_w = get_tensor (string_format (TN_A_INP_PROJ ,"weight" )); 3270model .sscp_inp_proj_b = get_tensor (string_format (TN_A_INP_PROJ ,"bias" ), false); 3271model .audio_out_proj_w = get_tensor (string_format (TN_A_OUT_PROJ ,"weight" ), false); 3272model .audio_out_proj_b = get_tensor (string_format (TN_A_OUT_PROJ ,"bias" ), false); 3273// audio multimodal embedder (mm.a.* namespace, not mm.*) 3274model .mm_soft_emb_norm_w = get_tensor (string_format (TN_A_MM_SOFT_EMB_N ,"weight" ), false); 3275model .mm_input_proj_w = get_tensor (string_format (TN_A_MM_INP_PROJ ,"weight" ), false); 3276 3277// Per-layer tensors NOT loaded by the generic loop above 3278for (int il = 0 ;il < hparams .n_layer ;++ il ) { 3279auto & layer = model .layers [il ]; 3280 3281// Gemma4 audio conformer-specific tensors 3282layer .ff_norm_w = get_tensor (string_format (TN_FFN_NORM ,prefix ,il ,"weight" )); 3283layer .attn_pre_norm_w = get_tensor (string_format (TN_A_ATTN_PRE_NORM ,prefix ,il ,"weight" ), false); 3284layer .per_dim_scale_w = get_tensor (string_format (TN_A_PER_DIM_SCALE ,prefix ,il ,"weight" ), false); 3285layer .per_dim_k_scale_w = get_tensor (string_format (TN_A_PER_DIM_K_SCALE ,prefix ,il ,"weight" ), false); 3286layer .attn_k_rel_w = get_tensor (string_format (TN_A_ATTN_K_REL ,prefix ,il ,"weight" ), false); 3287 3288// Convolution module 3289// Note: conv_norm / norm_conv are swapped in GGUF due to 3290// upstream tensor_mapping.py, so we load them in reverse order 3291layer .norm_conv_w = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"weight" ), false); 3292layer .norm_conv_b = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"bias" ), false); 3293layer .conv_pw1_w = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"weight" )); 3294layer .conv_pw1_b = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"bias" ), false); 3295layer .conv_dw_w = get_tensor (string_format (TN_CONV_DW ,prefix ,il ,"weight" )); 3296layer .conv_dw_b = get_tensor (string_format (TN_CONV_DW ,prefix ,il ,"bias" ), false); 3297layer .conv_norm_w = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"weight" ), false); 3298layer .conv_norm_b = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"bias" ), false); 3299layer .conv_pw2_w = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"weight" )); 3300layer .conv_pw2_b = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"bias" ), false); 3301 3302// FFN2 (second half-step) 3303layer .ff_norm_1_w = get_tensor (string_format (TN_FFN_NORM_1 ,prefix ,il ,"weight" )); 3304layer .ff_up_1_w = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"weight" )); 3305layer .ff_up_1_b = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"bias" ), false); 3306layer .ff_down_1_w = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"weight" )); 3307layer .ff_down_1_b = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"bias" ), false); 3308layer .ff_post_norm_1_w = get_tensor (string_format (TN_A_FFN_POST_NORM_1 ,prefix ,il ,"weight" ), false); 3309 } 3310 3311// Load clamp info for ClippableLinear AFTER all tensors are loaded 3312for (auto * tensor :tensors_to_load ) { 3313 std::string name = tensor -> name ; 3314if (string_ends_with (name ,".weight" )) { 3315 std::string name_inp_max = name ; 3316 std::string name_inp_min = name ; 3317 std::string name_out_max = name ; 3318 std::string name_out_min = name ; 3319string_replace_all (name_inp_max ,".weight" ,".input_max" ); 3320string_replace_all (name_inp_min ,".weight" ,".input_min" ); 3321string_replace_all (name_out_max ,".weight" ,".output_max" ); 3322string_replace_all (name_out_min ,".weight" ,".output_min" ); 3323model .clamp_info_map [name ]= { 3324get_scalar (name_inp_max ,FLT_MAX ), 3325get_scalar (name_inp_min ,- FLT_MAX ), 3326get_scalar (name_out_max ,FLT_MAX ), 3327get_scalar (name_out_min ,- FLT_MAX ) 3328 }; 3329 } 3330 } 3331 }break ; 3332case PROJECTOR_TYPE_GEMMA4UA : 3333 { 3334model .mm_input_proj_w = get_tensor (string_format (TN_A_MM_INP_PROJ ,"weight" )); 3335 }break ; 3336case PROJECTOR_TYPE_LFM2A : 3337 { 3338for (int i : {0 ,2 ,3 ,5 ,6 }) { 3339model .pre_encode_conv_X_w [i ]= get_tensor (string_format (TN_CONV1D ,i ,"weight" )); 3340model .pre_encode_conv_X_b [i ]= get_tensor (string_format (TN_CONV1D ,i ,"bias" )); 3341 } 3342model .pre_encode_out_w = get_tensor (string_format (TN_PRE_ENCODE_OUT ,"weight" )); 3343model .pre_encode_out_b = get_tensor (string_format (TN_PRE_ENCODE_OUT ,"bias" )); 3344 3345model .mm_0_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,0 ,"weight" )); 3346model .mm_0_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,0 ,"bias" )); 3347model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" )); 3348model .mm_1_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"bias" )); 3349model .mm_3_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,3 ,"weight" )); 3350model .mm_3_b = get_tensor (string_format (TN_MM_AUDIO_MLP ,3 ,"bias" )); 3351 3352for (int il = 0 ;il < hparams .n_layer ;++ il ) { 3353auto & layer = model .layers [il ]; 3354 3355layer .ff_norm_w = get_tensor (string_format (TN_FFN_NORM ,prefix ,il ,"weight" )); 3356layer .ff_norm_b = get_tensor (string_format (TN_FFN_NORM ,prefix ,il ,"bias" )); 3357layer .ff_norm_1_w = get_tensor (string_format (TN_FFN_NORM_1 ,prefix ,il ,"weight" )); 3358layer .ff_norm_1_b = get_tensor (string_format (TN_FFN_NORM_1 ,prefix ,il ,"bias" )); 3359layer .ff_up_1_w = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"weight" )); 3360layer .ff_up_1_b = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"bias" )); 3361layer .ff_down_1_w = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"weight" )); 3362layer .ff_down_1_b = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"bias" )); 3363 3364layer .pos_bias_u = get_tensor (string_format (TN_POS_BIAS_U ,prefix ,il )); 3365layer .pos_bias_v = get_tensor (string_format (TN_POS_BIAS_V ,prefix ,il )); 3366 3367layer .norm_conv_w = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"weight" )); 3368layer .norm_conv_b = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"bias" )); 3369 3370layer .linear_pos_w = get_tensor (string_format (TN_LINEAR_POS ,prefix ,il ,"weight" )); 3371 3372layer .conv_norm_w = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"weight" )); 3373layer .conv_norm_b = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"bias" )); 3374layer .conv_dw_w = get_tensor (string_format (TN_CONV_DW ,prefix ,il ,"weight" )); 3375layer .conv_dw_b = get_tensor (string_format (TN_CONV_DW ,prefix ,il ,"bias" )); 3376layer .conv_pw1_w = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"weight" )); 3377layer .conv_pw1_b = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"bias" )); 3378layer .conv_pw2_w = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"weight" )); 3379layer .conv_pw2_b = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"bias" )); 3380 } 3381 }break ; 3382case PROJECTOR_TYPE_PARAKEET : 3383 { 3384 3385hparams .mel_filters = get_vector (TN_MEL_FILTERS ); 3386hparams .window = get_vector (TN_WINDOW ); 3387 3388// Subsampling layers (conv1d) 3389for (int i : {0 ,2 ,3 ,5 ,6 }) { 3390model .pre_encode_conv_X_w [i ]= get_tensor (string_format (TN_CONV1D ,i ,"weight" )); 3391model .pre_encode_conv_X_b [i ]= get_tensor (string_format (TN_CONV1D ,i ,"bias" )); 3392 } 3393model .pre_encode_out_w = get_tensor (string_format (TN_PRE_ENCODE_OUT ,"weight" )); 3394model .pre_encode_out_b = get_tensor (string_format (TN_PRE_ENCODE_OUT ,"bias" )); 3395 3396// Projection layers 3397model .mm_norm_pre_w = get_tensor (string_format (TN_MM_NORM_PRE ,"weight" ), false); 3398model .mm_0_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,1 ,"weight" ), false); 3399model .mm_1_w = get_tensor (string_format (TN_MM_AUDIO_MLP ,2 ,"weight" ), false); 3400 3401// Encoder layers 3402for (int il = 0 ;il < hparams .n_layer ;++ il ) { 3403auto & layer = model .layers [il ]; 3404 3405// Attention (from shared above) 3406 3407// Relative position encoding 3408layer .linear_pos_w = get_tensor (string_format (TN_LINEAR_POS ,prefix ,il ,"weight" )); 3409layer .pos_bias_u = get_tensor (string_format (TN_POS_BIAS_U ,prefix ,il )); 3410layer .pos_bias_v = get_tensor (string_format (TN_POS_BIAS_V ,prefix ,il )); 3411 3412// Convolution module 3413layer .conv_pw1_w = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"weight" )); 3414layer .conv_pw1_b = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"bias" ), false); 3415layer .conv_dw_w = get_tensor (string_format (TN_CONV_DW ,prefix ,il ,"weight" )); 3416layer .conv_dw_b = get_tensor (string_format (TN_CONV_DW ,prefix ,il ,"bias" ), false); 3417layer .conv_norm_w = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"weight" )); 3418layer .conv_norm_b = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"bias" )); 3419layer .conv_norm_mean = get_tensor (string_format (TN_CONV_NORM_MEAN ,prefix ,il )); 3420layer .conv_norm_var = get_tensor (string_format (TN_CONV_NORM_VAR ,prefix ,il )); 3421layer .conv_pw2_w = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"weight" )); 3422layer .conv_pw2_b = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"bias" ), false); 3423 3424// Feed-forward networks 3425layer .ff_norm_w = get_tensor (string_format (TN_FFN_NORM ,prefix ,il ,"weight" )); 3426layer .ff_norm_b = get_tensor (string_format (TN_FFN_NORM ,prefix ,il ,"bias" )); 3427 3428layer .ff_norm_1_w = get_tensor (string_format (TN_FFN_NORM_1 ,prefix ,il ,"weight" )); 3429layer .ff_norm_1_b = get_tensor (string_format (TN_FFN_NORM_1 ,prefix ,il ,"bias" )); 3430layer .ff_up_1_w = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"weight" )); 3431layer .ff_up_1_b = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"bias" ), false); 3432layer .ff_down_1_w = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"weight" )); 3433layer .ff_down_1_b = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"bias" ), false); 3434 3435// Layer norms 3436layer .norm_conv_w = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"weight" )); 3437layer .norm_conv_b = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"bias" )); 3438 } 3439 3440model .mm_model_mlp_1_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,0 ,"weight" )); 3441model .mm_model_mlp_2_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,1 ,"weight" )); 3442model .mm_model_mlp_3_w = get_tensor (string_format (TN_MVLM_PROJ_MLP ,3 ,"weight" )); 3443 }break ; 3444case PROJECTOR_TYPE_GRANITE_SPEECH : 3445 { 3446model .inp_proj_w = get_tensor (string_format (TN_INP_PROJ ,"weight" )); 3447model .inp_proj_b = get_tensor (string_format (TN_INP_PROJ ,"bias" )); 3448model .ctc_out_w = get_tensor (string_format (TN_CTC_OUT ,"weight" )); 3449model .ctc_out_b = get_tensor (string_format (TN_CTC_OUT ,"bias" )); 3450model .ctc_out_mid_w = get_tensor (string_format (TN_CTC_OUT_MID ,"weight" )); 3451model .ctc_out_mid_b = get_tensor (string_format (TN_CTC_OUT_MID ,"bias" )); 3452 3453// per-layer tensors not loaded by the generic loop above 3454for (int il = 0 ;il < hparams .n_layer ;++ il ) { 3455auto & layer = model .layers [il ]; 3456 3457layer .attn_rel_pos_emb = get_tensor (string_format (TN_ATTN_REL_POS_EMB ,prefix ,il )); 3458 3459layer .ff_norm_w = get_tensor (string_format (TN_FFN_NORM ,prefix ,il ,"weight" )); 3460layer .ff_norm_b = get_tensor (string_format (TN_FFN_NORM ,prefix ,il ,"bias" )); 3461 3462layer .ff_norm_1_w = get_tensor (string_format (TN_FFN_NORM_1 ,prefix ,il ,"weight" )); 3463layer .ff_norm_1_b = get_tensor (string_format (TN_FFN_NORM_1 ,prefix ,il ,"bias" )); 3464layer .ff_up_1_w = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"weight" )); 3465layer .ff_up_1_b = get_tensor (string_format (TN_FFN_UP_1 ,prefix ,il ,"bias" )); 3466layer .ff_down_1_w = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"weight" )); 3467layer .ff_down_1_b = get_tensor (string_format (TN_FFN_DOWN_1 ,prefix ,il ,"bias" )); 3468 3469layer .norm_conv_w = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"weight" )); 3470layer .norm_conv_b = get_tensor (string_format (TN_NORM_CONV ,prefix ,il ,"bias" )); 3471layer .conv_norm_w = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"weight" )); 3472layer .conv_norm_b = get_tensor (string_format (TN_CONV_NORM ,prefix ,il ,"bias" )); 3473layer .conv_dw_w = get_tensor (string_format (TN_CONV_DW ,prefix ,il ,"weight" )); 3474layer .conv_pw1_w = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"weight" )); 3475layer .conv_pw1_b = get_tensor (string_format (TN_CONV_PW1 ,prefix ,il ,"bias" )); 3476layer .conv_pw2_w = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"weight" )); 3477layer .conv_pw2_b = get_tensor (string_format (TN_CONV_PW2 ,prefix ,il ,"bias" )); 3478 } 3479 3480model .qf_proj_blocks .resize (1 ); 3481auto & qf = model .qf_proj_blocks [0 ]; 3482qf .qf_proj_query = get_tensor (string_format (TN_QF_PROJ_QUERY ,prefix )); 3483qf .qf_proj_norm_w = get_tensor (string_format (TN_QF_PROJ_NORM ,prefix ,"weight" )); 3484qf .qf_proj_norm_b = get_tensor (string_format (TN_QF_PROJ_NORM ,prefix ,"bias" )); 3485qf .qf_proj_linear_w = get_tensor (string_format (TN_QF_PROJ_LINEAR ,prefix ,"weight" )); 3486qf .qf_proj_linear_b = get_tensor (string_format (TN_QF_PROJ_LINEAR ,prefix ,"bias" )); 3487 3488const int n_proj_layers = 2 ; 3489qf .qf_proj_layers .resize (n_proj_layers ); 3490for (int il = 0 ;il < n_proj_layers ;++ il ) { 3491auto & pl = qf .qf_proj_layers [il ]; 3492 3493pl .q_w = get_tensor (string_format (TN_QF_SELF_ATTN_Q ,prefix ,il ,"weight" )); 3494pl .q_b = get_tensor (string_format (TN_QF_SELF_ATTN_Q ,prefix ,il ,"bias" )); 3495pl .k_w = get_tensor (string_format (TN_QF_SELF_ATTN_K ,prefix ,il ,"weight" )); 3496pl .k_b = get_tensor (string_format (TN_QF_SELF_ATTN_K ,prefix ,il ,"bias" )); 3497pl .v_w = get_tensor (string_format (TN_QF_SELF_ATTN_V ,prefix ,il ,"weight" )); 3498pl .v_b = get_tensor (string_format (TN_QF_SELF_ATTN_V ,prefix ,il ,"bias" )); 3499pl .o_w = get_tensor (string_format (TN_QF_SELF_ATTN_O ,prefix ,il ,"weight" )); 3500pl .o_b = get_tensor (string_format (TN_QF_SELF_ATTN_O ,prefix ,il ,"bias" )); 3501pl .ln_1_w = get_tensor (string_format (TN_QF_SELF_ATTN_N ,prefix ,il ,"weight" )); 3502pl .ln_1_b = get_tensor (string_format (TN_QF_SELF_ATTN_N ,prefix ,il ,"bias" )); 3503 3504pl .cross_attn_q_w = get_tensor (string_format (TN_QF_CROSS_ATTN_Q ,prefix ,il ,"weight" )); 3505pl .cross_attn_q_b = get_tensor (string_format (TN_QF_CROSS_ATTN_Q ,prefix ,il ,"bias" )); 3506pl .cross_attn_k_w = get_tensor (string_format (TN_QF_CROSS_ATTN_K ,prefix ,il ,"weight" )); 3507pl .cross_attn_k_b = get_tensor (string_format (TN_QF_CROSS_ATTN_K ,prefix ,il ,"bias" )); 3508pl .cross_attn_v_w = get_tensor (string_format (TN_QF_CROSS_ATTN_V ,prefix ,il ,"weight" )); 3509pl .cross_attn_v_b = get_tensor (string_format (TN_QF_CROSS_ATTN_V ,prefix ,il ,"bias" )); 3510pl .cross_attn_o_w = get_tensor (string_format (TN_QF_CROSS_ATTN_O ,prefix ,il ,"weight" )); 3511pl .cross_attn_o_b = get_tensor (string_format (TN_QF_CROSS_ATTN_O ,prefix ,il ,"bias" )); 3512pl .cross_attn_norm_w = get_tensor (string_format (TN_QF_CROSS_ATTN_N ,prefix ,il ,"weight" )); 3513pl .cross_attn_norm_b = get_tensor (string_format (TN_QF_CROSS_ATTN_N ,prefix ,il ,"bias" )); 3514 3515pl .ff_up_w = get_tensor (string_format (TN_QF_FFN_UP ,prefix ,il ,"weight" )); 3516pl .ff_up_b = get_tensor (string_format (TN_QF_FFN_UP ,prefix ,il ,"bias" )); 3517pl .ff_down_w = get_tensor (string_format (TN_QF_FFN_DOWN ,prefix ,il ,"weight" )); 3518pl .ff_down_b = get_tensor (string_format (TN_QF_FFN_DOWN ,prefix ,il ,"bias" )); 3519pl .ln_2_w = get_tensor (string_format (TN_QF_FFN_NORM ,prefix ,il ,"weight" )); 3520pl .ln_2_b = get_tensor (string_format (TN_QF_FFN_NORM ,prefix ,il ,"bias" )); 3521 } 3522 }break ; 3523case PROJECTOR_TYPE_GRANITE4_VISION : 3524 { 3525// image_newline lives at the top-level. 3526model .image_newline = get_tensor (TN_IMAGE_NEWLINE ); 3527 3528// Load separate layerwise and spatial projector tensors 3529const auto projector_count = hparams .feature_layers .size (); 3530model .qf_proj_blocks .resize (projector_count ); 3531for (size_t bid = 0 ;bid < projector_count ;++ bid ) { 3532auto & b = model .qf_proj_blocks [bid ]; 3533 3534// non-layerwise tensors 3535b .qf_proj_img_pos = get_tensor (string_format (TN_MULTI_PROJ_IMG_POS ,bid )); 3536b .qf_proj_query = get_tensor (string_format (TN_MULTI_PROJ_QUERY ,prefix ,bid )); 3537b .qf_proj_linear_w = get_tensor (string_format (TN_MULTI_PROJ_LINEAR ,prefix ,bid ,"weight" )); 3538b .qf_proj_linear_b = get_tensor (string_format (TN_MULTI_PROJ_LINEAR ,prefix ,bid ,"bias" )); 3539b .qf_proj_norm_w = get_tensor (string_format (TN_MULTI_PROJ_NORM ,prefix ,bid ,"weight" )); 3540b .qf_proj_norm_b = get_tensor (string_format (TN_MULTI_PROJ_NORM ,prefix ,bid ,"bias" )); 3541b .qf_proj_post_norm_w = get_tensor (string_format (TN_MULTI_PROJ_POST_NORM ,prefix ,bid ,"weight" )); 3542b .qf_proj_post_norm_b = get_tensor (string_format (TN_MULTI_PROJ_POST_NORM ,prefix ,bid ,"bias" )); 3543 3544// laywerwise tensors 3545// NOTE: If any model uses multi-layer qformers, this will need to change 3546b .qf_proj_layers .resize (1 ); 3547auto & pl = b .qf_proj_layers [0 ]; 3548 3549pl .q_w = get_tensor (string_format (TN_QF_SELF_ATTN_Q ,prefix ,bid ,"weight" )); 3550pl .q_b = get_tensor (string_format (TN_QF_SELF_ATTN_Q ,prefix ,bid ,"bias" )); 3551pl .k_w = get_tensor (string_format (TN_QF_SELF_ATTN_K ,prefix ,bid ,"weight" )); 3552pl .k_b = get_tensor (string_format (TN_QF_SELF_ATTN_K ,prefix ,bid ,"bias" )); 3553pl .v_w = get_tensor (string_format (TN_QF_SELF_ATTN_V ,prefix ,bid ,"weight" )); 3554pl .v_b = get_tensor (string_format (TN_QF_SELF_ATTN_V ,prefix ,bid ,"bias" )); 3555pl .o_w = get_tensor (string_format (TN_QF_SELF_ATTN_O ,prefix ,bid ,"weight" )); 3556pl .o_b = get_tensor (string_format (TN_QF_SELF_ATTN_O ,prefix ,bid ,"bias" )); 3557pl .ln_1_w = get_tensor (string_format (TN_QF_SELF_ATTN_N ,prefix ,bid ,"weight" )); 3558pl .ln_1_b = get_tensor (string_format (TN_QF_SELF_ATTN_N ,prefix ,bid ,"bias" )); 3559 3560pl .cross_attn_q_w = get_tensor (string_format (TN_QF_CROSS_ATTN_Q ,prefix ,bid ,"weight" )); 3561pl .cross_attn_q_b = get_tensor (string_format (TN_QF_CROSS_ATTN_Q ,prefix ,bid ,"bias" )); 3562pl .cross_attn_k_w = get_tensor (string_format (TN_QF_CROSS_ATTN_K ,prefix ,bid ,"weight" )); 3563pl .cross_attn_k_b = get_tensor (string_format (TN_QF_CROSS_ATTN_K ,prefix ,bid ,"bias" )); 3564pl .cross_attn_v_w = get_tensor (string_format (TN_QF_CROSS_ATTN_V ,prefix ,bid ,"weight" )); 3565pl .cross_attn_v_b = get_tensor (string_format (TN_QF_CROSS_ATTN_V ,prefix ,bid ,"bias" )); 3566pl .cross_attn_o_w = get_tensor (string_format (TN_QF_CROSS_ATTN_O ,prefix ,bid ,"weight" )); 3567pl .cross_attn_o_b = get_tensor (string_format (TN_QF_CROSS_ATTN_O ,prefix ,bid ,"bias" )); 3568pl .cross_attn_norm_w = get_tensor (string_format (TN_QF_CROSS_ATTN_N ,prefix ,bid ,"weight" )); 3569pl .cross_attn_norm_b = get_tensor (string_format (TN_QF_CROSS_ATTN_N ,prefix ,bid ,"bias" )); 3570 3571pl .ff_up_w = get_tensor (string_format (TN_QF_FFN_UP ,prefix ,bid ,"weight" )); 3572pl .ff_up_b = get_tensor (string_format (TN_QF_FFN_UP ,prefix ,bid ,"bias" )); 3573pl .ff_down_w = get_tensor (string_format (TN_QF_FFN_DOWN ,prefix ,bid ,"weight" )); 3574pl .ff_down_b = get_tensor (string_format (TN_QF_FFN_DOWN ,prefix ,bid ,"bias" )); 3575pl .ln_2_w = get_tensor (string_format (TN_QF_FFN_NORM ,prefix ,bid ,"weight" )); 3576pl .ln_2_b = get_tensor (string_format (TN_QF_FFN_NORM ,prefix ,bid ,"bias" )); 3577 } 3578 3579 }break ; 3580default : 3581GGML_ASSERT (false&& "unknown projector type" ); 3582 } 3583 3584// load data 3585 { 3586 std::vector < uint8_t > read_buf ; 3587 3588// start loading event 3589if (progress_callback ){ 3590progress_callback (0.0 ,progress_callback_user_data ); 3591 } 3592 3593// compute total tensor data size for progress reporting 3594size_t total_data_size = 0 ; 3595for (auto & t :tensors_to_load ) { 3596total_data_size += ggml_nbytes (t ); 3597 } 3598 3599// alloc memory and offload data 3600ggml_backend_buffer_type_t buft = ggml_backend_get_default_buffer_type (ctx_clip .backend ); 3601ctx_clip .buf .reset (ggml_backend_alloc_ctx_tensors_from_buft (ctx_clip .ctx_data .get (),buft )); 3602ggml_backend_buffer_set_usage (ctx_clip .buf .get (),GGML_BACKEND_BUFFER_USAGE_WEIGHTS ); 3603// read the weight from file 3604if (!ctx_clip .no_alloc ) { 3605size_t data_loaded = 0 ; 3606for (auto & t :tensors_to_load ) { 3607ggml_tensor * cur = ggml_get_tensor (ctx_clip .ctx_data .get (),t -> name ); 3608GGML_ASSERT (cur && "tensor not found in ctx_data" ); 3609auto it_off = tensor_offset .find (t -> name ); 3610GGML_ASSERT (it_off != tensor_offset .end ()&& "no offset for tensor" ); 3611const size_t offset = it_off -> second ; 3612fin .seekg (offset , std::ios::beg ); 3613if (!fin ) { 3614throw std::runtime_error (string_format ("%s: failed to seek for tensor %s\n" ,__func__ ,t -> name )); 3615 } 3616size_t num_bytes = ggml_nbytes (cur ); 3617if (ggml_backend_buft_is_host (buft )) { 3618// for the CPU and Metal backend, we can read directly into the tensor 3619fin .read (reinterpret_cast < char *> (cur -> data ),num_bytes ); 3620 }else { 3621// read into a temporary buffer first, then copy to device memory 3622read_buf .resize (num_bytes ); 3623fin .read (reinterpret_cast < char *> (read_buf .data ()),num_bytes ); 3624ggml_backend_tensor_set (cur ,read_buf .data (),0 ,num_bytes ); 3625 } 3626data_loaded += num_bytes ; 3627if (progress_callback && total_data_size > 0 ) { 3628const float progress = (float )data_loaded / (float )total_data_size ; 3629if (!progress_callback (progress ,progress_callback_user_data )) { 3630throw std::runtime_error (string_format ("%s: model loading cancelled by progress_callback\n" ,__func__ )); 3631 } 3632 } 3633 } 3634LOG_DBG ("%s: loaded %zu tensors from %s\n" ,__func__ ,tensors_to_load .size (),fname .c_str ()); 3635 }else { 3636LOG_DBG ("%s: no_alloc is set, skipping tensor data loading (%zu tensors)\n" ,__func__ ,tensors_to_load .size ()); 3637 } 3638fin .close (); 3639 } 3640 3641 } 3642 3643struct support_info_op { 3644ggml_tensor * op ; 3645 3646// true if the op runs on the accelerated ctx_clip.backend 3647bool is_accel = true; 3648 }; 3649 3650struct support_info_graph { 3651// whether the clip_ctx.backend supports flash attention 3652bool fattn = true; 3653ggml_tensor * fattn_op = nullptr ;// for debugging 3654 3655 std::vector < support_info_op > ops ; 3656 }; 3657 3658static clip_image_f32_batch get_dummy_batch (clip_ctx & ctx_clip ) { 3659// create a fake batch 3660const auto & hparams = ctx_clip .model .hparams ; 3661clip_image_f32_batch batch ; 3662clip_image_f32 img ; 3663if (ctx_clip .model .modality == CLIP_MODALITY_VISION ) { 3664const int sz = hparams .warmup_image_size ; 3665img .set_size ({sz ,sz }, false, false); 3666LOG_INF ("%s: warmup with image size = %d x %d\n" ,__func__ ,sz ,sz ); 3667 }else { 3668// GEMMA4UA uses n_mel_bins as a raw-waveform frame size (640), not a mel-bin count, 3669// so the [1, 256] bound only applies to FFT-based models. 3670const bool fft_based = ctx_clip .model .proj_type != PROJECTOR_TYPE_GEMMA4UA ; 3671if (hparams .n_mel_bins <=0 || (fft_based && hparams .n_mel_bins > 256 )) { 3672throw std::runtime_error (string_format ("%s: invalid n_mel_bins (%d), must be in [1, 256]\n" ,__func__ ,hparams .n_mel_bins )); 3673 } 3674img .set_size ({hparams .warmup_audio_size ,hparams .n_mel_bins }, false, false); 3675LOG_INF ("%s: warmup with audio size = %d\n" ,__func__ ,hparams .warmup_audio_size ); 3676 } 3677batch .entries .push_back (img ); 3678return batch ; 3679 } 3680 3681static void init_ctx (clip_ctx & ctx_clip ) { 3682ctx_clip .buf_compute_meta .resize (ctx_clip .max_nodes * ggml_tensor_overhead ()+ ggml_graph_overhead ()); 3683 3684// check batching support 3685auto batch = get_dummy_batch (ctx_clip ); 3686auto builder = clip_get_graph_builder (& ctx_clip ,batch ); 3687ctx_clip .support_batch = builder -> support_batch (); 3688 } 3689 3690static void warmup (clip_ctx & ctx_clip ) { 3691auto batch = get_dummy_batch (ctx_clip ); 3692warmup (ctx_clip ,batch ); 3693 } 3694 3695static void warmup (clip_ctx & ctx_clip ,const clip_image_f32_batch & batch ) { 3696support_info_graph info ; 3697 3698if (ctx_clip .flash_attn_type == CLIP_FLASH_ATTN_TYPE_AUTO ) { 3699// try to enable flash attention to see if it's supported 3700ctx_clip .flash_attn_type = CLIP_FLASH_ATTN_TYPE_ENABLED ; 3701info = reserve_compute_meta (ctx_clip ,batch ); 3702if (!info .fattn && info .fattn_op ) { 3703auto op = info .fattn_op ; 3704LOG_WRN ("%s: *****************************************************************\n" ,__func__ ); 3705LOG_WRN ("%s: WARNING: flash attention not supported by %s, memory usage will increase\n" ,__func__ ,ggml_backend_name (ctx_clip .backend )); 3706LOG_WRN ("%s: op params: \n" ,__func__ ); 3707static auto print_shape = [](const char * fn ,const char * name ,ggml_tensor * t ) { 3708LOG_WRN ("%s: %s: type = %s, ne = [%d %d %d %d], nb = [%d %d %d %d]\n" ,fn , 3709name ,ggml_type_name (t -> type ), 3710t -> ne [0 ],t -> ne [1 ],t -> ne [2 ],t -> ne [3 ], 3711t -> nb [0 ],t -> nb [1 ],t -> nb [2 ],t -> nb [3 ]); 3712 }; 3713print_shape (__func__ ," dst" ,op ); 3714print_shape (__func__ ,"src0" ,op -> src [0 ]); 3715print_shape (__func__ ,"src1" ,op -> src [1 ]); 3716print_shape (__func__ ,"src2" ,op -> src [2 ]); 3717LOG_WRN ("%s: please report this on github as an issue\n" ,__func__ ); 3718LOG_WRN ("%s: *****************************************************************\n" ,__func__ ); 3719ctx_clip .flash_attn_type = CLIP_FLASH_ATTN_TYPE_DISABLED ; 3720reserve_compute_meta (ctx_clip ,batch ); 3721 } 3722 }else { 3723info = reserve_compute_meta (ctx_clip ,batch ); 3724if (!info .fattn && ctx_clip .flash_attn_type == CLIP_FLASH_ATTN_TYPE_ENABLED ) { 3725LOG_WRN ("%s: flash attention is not supported by the current backend; falling back to CPU (performance will be degraded)\n" ,__func__ ); 3726 } 3727 } 3728 3729ctx_clip .is_allocated = true;// mark buffers as allocated 3730 3731LOG_INF ("%s: flash attention is %s\n" ,__func__ , 3732 (ctx_clip .flash_attn_type == CLIP_FLASH_ATTN_TYPE_ENABLED ) ?"enabled" :"disabled" ); 3733 3734// print ops that are not supported by the GPU backend (if there is one) 3735if (ctx_clip .backend && ctx_clip .backend != ctx_clip .backend_cpu ) { 3736 std::vector < support_info_op > unsupported_ops ; 3737for (const auto & op :info .ops ) { 3738if (!op .is_accel ) { 3739unsupported_ops .push_back (op ); 3740 } 3741 } 3742if (!unsupported_ops .empty ()) { 3743LOG_WRN ("%s: *****************************************************************\n" ,__func__ ); 3744LOG_WRN ("%s: WARNING: the CLIP graph uses unsupported operators by the backend\n" ,__func__ ); 3745LOG_WRN ("%s: the performance will be suboptimal \n" ,__func__ ); 3746LOG_WRN ("%s: list of unsupported ops (backend=%s):\n" ,__func__ ,ggml_backend_name (ctx_clip .backend )); 3747for (const auto & op :unsupported_ops ) { 3748LOG_WRN ("%s: %16s: type = %s, ne = [%d %d %d %d]\n" ,__func__ , 3749ggml_op_name (op .op -> op ), 3750ggml_type_name (op .op -> type ), 3751op .op -> ne [0 ],op .op -> ne [1 ],op .op -> ne [2 ],op .op -> ne [3 ]); 3752 } 3753LOG_WRN ("%s: flash attention is %s\n" ,__func__ , 3754 (ctx_clip .flash_attn_type == CLIP_FLASH_ATTN_TYPE_ENABLED ) ?"enabled" :"disabled" ); 3755LOG_WRN ("%s: please report this on github as an issue\n" ,__func__ ); 3756LOG_WRN ("%s: ref: https://github.com/ggml-org/llama.cpp/pull/16837#issuecomment-3461676118\n" ,__func__ ); 3757LOG_WRN ("%s: *****************************************************************\n" ,__func__ ); 3758 } 3759 } 3760 } 3761 3762// only initialize backend buffers, but do not allocate them yet 3763static support_info_graph reserve_compute_meta (clip_ctx & ctx_clip ,const clip_image_f32_batch & batch ) { 3764ggml_cgraph * gf = clip_get_graph_builder (& ctx_clip ,batch )-> build (); 3765ggml_backend_sched_reserve (ctx_clip .sched .get (),gf ); 3766 3767ctx_clip .mem_compute .clear (); 3768for (size_t i = 0 ;i < ctx_clip .backend_ptrs .size ();++ i ) { 3769ggml_backend_t backend = ctx_clip .backend_ptrs [i ]; 3770ggml_backend_buffer_type_t buft = ctx_clip .backend_buft [i ]; 3771size_t size = ggml_backend_sched_get_buffer_size (ctx_clip .sched .get (),backend ); 3772if (size > 1 ) { 3773LOG_INF ("%s: %10s compute buffer size = %8.2f MiB\n" ,__func__ , 3774ggml_backend_buft_name (buft ), 3775size /1024.0 /1024.0 ); 3776 } 3777ctx_clip .mem_compute [ggml_backend_get_device (backend )]+= size ; 3778 } 3779 3780const int n_splits = ggml_backend_sched_get_n_splits (ctx_clip .sched .get ()); 3781const int n_nodes = ggml_graph_n_nodes (gf ); 3782 3783LOG_INF ("%s: graph splits = %d, nodes = %d\n" ,__func__ ,n_splits ,n_nodes ); 3784 3785support_info_graph res { 3786/*.fattn = */ true, 3787/*.fattn_op = */ nullptr , 3788/*.ops = */ {}, 3789 }; 3790 3791// check op support 3792for (int i = 0 ;i < ggml_graph_n_nodes (gf );i ++ ) { 3793ggml_tensor * node = ggml_graph_node (gf ,i ); 3794res .ops .push_back ({node , true}); 3795if (!ggml_backend_supports_op (ctx_clip .backend ,node )) { 3796res .ops .back ().is_accel = false; 3797if (node -> op == GGML_OP_FLASH_ATTN_EXT ) { 3798res .fattn = false; 3799res .fattn_op = node ; 3800 } 3801 } 3802 } 3803 3804return res ; 3805 } 3806 3807void get_bool (const std::string & key ,bool & output ,bool required = true)const { 3808const int i = gguf_find_key (ctx_gguf .get (),key .c_str ()); 3809if (i < 0 ) { 3810if (required ) { 3811throw std::runtime_error ("Key not found: " + key ); 3812 } 3813return ; 3814 } 3815output = gguf_get_val_bool (ctx_gguf .get (),i ); 3816 } 3817 3818void get_i32 (const std::string & key ,int & output ,bool required = true)const { 3819const int i = gguf_find_key (ctx_gguf .get (),key .c_str ()); 3820if (i < 0 ) { 3821if (required ) { 3822throw std::runtime_error ("Key not found: " + key ); 3823 } 3824return ; 3825 } 3826output = gguf_get_val_i32 (ctx_gguf .get (),i ); 3827 } 3828 3829void get_u32 (const std::string & key ,int & output ,bool required = true)const { 3830const int i = gguf_find_key (ctx_gguf .get (),key .c_str ()); 3831if (i < 0 ) { 3832if (required ) { 3833throw std::runtime_error ("Key not found: " + key ); 3834 } 3835return ; 3836 } 3837const uint32_t val = gguf_get_val_u32 (ctx_gguf .get (),i ); 3838// sanity check 3839if (val > (uint32_t )INT32_MAX ) { 3840throw std::runtime_error (string_format ("%s: value %u for key '%s' exceeds INT32_MAX\n" , 3841__func__ ,val ,key .c_str ())); 3842 } 3843output = (int )val ; 3844 } 3845 3846void get_f32 (const std::string & key ,float & output ,bool required = true)const { 3847const int i = gguf_find_key (ctx_gguf .get (),key .c_str ()); 3848if (i < 0 ) { 3849if (required ) { 3850throw std::runtime_error ("Key not found: " + key ); 3851 } 3852return ; 3853 } 3854output = gguf_get_val_f32 (ctx_gguf .get (),i ); 3855 } 3856 3857void get_arr_f32 (const std::string & key , std::vector < float > & output ,bool required = true)const { 3858const int i = gguf_find_key (ctx_gguf .get (),key .c_str ()); 3859if (i < 0 ) { 3860if (required ) { 3861throw std::runtime_error ("Key not found: " + key ); 3862 } 3863return ; 3864 } 3865if (gguf_get_kv_type (ctx_gguf .get (),i )!= GGUF_TYPE_ARRAY ) { 3866throw std::runtime_error (string_format ("%s: key '%s' is not an array\n" ,__func__ ,key .c_str ())); 3867 } 3868const auto type = gguf_get_arr_type (ctx_gguf .get (),i ); 3869if (type != GGUF_TYPE_FLOAT32 ) { 3870throw std::runtime_error (string_format ("%s: array '%s' has type %d, expected %d (GGUF_TYPE_FLOAT32)\n" ,__func__ ,key .c_str (),type ,GGUF_TYPE_FLOAT32 )); 3871 } 3872const size_t n = gguf_get_arr_n (ctx_gguf .get (),i ); 3873if (n > (size_t ) std::numeric_limits < int > ::max ()) { 3874throw std::runtime_error (string_format ("%s: array '%s' is too large (%zu elements)\n" ,__func__ ,key .c_str (),n )); 3875 } 3876output .resize (n ); 3877const float * values = (const float * )gguf_get_arr_data (ctx_gguf .get (),i ); 3878for (size_t j = 0 ;j < n ;++ j ) { 3879output [j ]= values [j ]; 3880 } 3881 } 3882 3883void get_string (const std::string & key , std::string & output ,bool required = true)const { 3884const int i = gguf_find_key (ctx_gguf .get (),key .c_str ()); 3885if (i < 0 ) { 3886if (required ) { 3887throw std::runtime_error ("Key not found: " + key ); 3888 } 3889return ; 3890 } 3891output = std::string (gguf_get_val_str (ctx_gguf .get (),i )); 3892 } 3893 3894void get_arr_int (const std::string & key , std::vector < int > & output ,bool required = true)const { 3895const int i = gguf_find_key (ctx_gguf .get (),key .c_str ()); 3896if (i < 0 ) { 3897if (required ) { 3898throw std::runtime_error ("Key not found: " + key ); 3899 } 3900return ; 3901 } 3902if (gguf_get_kv_type (ctx_gguf .get (),i )!= GGUF_TYPE_ARRAY ) { 3903throw std::runtime_error (string_format ("%s: key '%s' is not an array\n" ,__func__ ,key .c_str ())); 3904 } 3905const auto type = gguf_get_arr_type (ctx_gguf .get (),i ); 3906if (type != GGUF_TYPE_INT32 ) { 3907throw std::runtime_error (string_format ("%s: array '%s' has type %d, expected %d (GGUF_TYPE_INT32)\n" ,__func__ ,key .c_str (),type ,GGUF_TYPE_INT32 )); 3908 } 3909const size_t n = gguf_get_arr_n (ctx_gguf .get (),i ); 3910if (n > (size_t ) std::numeric_limits < int > ::max ()) { 3911throw std::runtime_error (string_format ("%s: array '%s' is too large (%zu elements)\n" ,__func__ ,key .c_str (),n )); 3912 } 3913output .resize (n ); 3914const int32_t * values = (const int32_t * )gguf_get_arr_data (ctx_gguf .get (),i ); 3915for (size_t j = 0 ;j < n ;++ j ) { 3916output [j ]= values [j ]; 3917 } 3918 } 3919 3920static void set_llava_uhd_res_candidates (clip_model & model ,const int max_patches_per_side ) { 3921auto & hparams = model .hparams ; 3922for (int x = 1 ;x <=max_patches_per_side ;x ++ ) { 3923for (int y = 1 ;y <=max_patches_per_side ;y ++ ) { 3924if (x == 1 && y == 1 ) { 3925continue ;// skip the first point 3926 } 3927hparams .image_res_candidates .push_back (clip_image_size { 3928x * hparams .image_size , 3929y * hparams .image_size , 3930 }); 3931 } 3932 } 3933 } 3934 3935static void set_internvl_dhr_res_candidates (clip_model & model ) { 3936auto & hparams = model .hparams ; 3937int min_num = hparams .preproc_min_tiles ; 3938int max_num = hparams .preproc_max_tiles ; 3939if (min_num < 1 ) { 3940return ;// avoid divide by 0 3941 } 3942for (int a = min_num ;a <=max_num ;++ a ) { 3943int b_lo = (min_num + a - 1 ) /a ; 3944int b_hi = max_num /a ; 3945b_lo = std::max (b_lo ,min_num ); 3946b_hi = std::min (b_hi ,max_num ); 3947for (int b = b_lo ;b <=b_hi ;++ b ) { 3948hparams .image_res_candidates .push_back (clip_image_size { 3949a * hparams .image_size , 3950b * hparams .image_size , 3951 }); 3952 } 3953 } 3954 } 3955}; 3956 3957struct clip_init_result clip_init (const char * fname ,struct clip_context_params ctx_params ) { 3958clip_ctx * ctx_vision = nullptr ; 3959clip_ctx * ctx_audio = nullptr ; 3960clip_ctx * ctx_gen_audio = nullptr ; 3961 3962try { 3963clip_model_loader loader (fname , 3964/* skip_tensors */ false, 3965ctx_params .progress_callback , 3966ctx_params .progress_callback_user_data ); 3967bool skip_audio = false; 3968 3969if (loader .has_vision ) { 3970ctx_vision = new clip_ctx (ctx_params ); 3971loader .load_hparams (ctx_vision -> model ,CLIP_MODALITY_VISION ); 3972loader .load_tensors (* ctx_vision ); 3973loader .init_ctx (* ctx_vision ); 3974if (ctx_params .warmup ) { 3975loader .warmup (* ctx_vision ); 3976 } 3977 3978// TODO: we don't support audio for Gemma 3N, but GGUF contains audio tensors 3979// we can remove this check when we implement audio support for Gemma 3N 3980skip_audio = ctx_vision -> model .proj_type == PROJECTOR_TYPE_GEMMA3NV ; 3981 } 3982 3983if (loader .has_audio && !skip_audio ) { 3984ctx_audio = new clip_ctx (ctx_params ); 3985loader .load_hparams (ctx_audio -> model ,CLIP_MODALITY_AUDIO ); 3986loader .load_tensors (* ctx_audio ); 3987loader .init_ctx (* ctx_audio ); 3988if (ctx_params .warmup ) { 3989loader .warmup (* ctx_audio ); 3990 } 3991 } 3992 3993if (loader .has_gen_audio ) { 3994ctx_gen_audio = new clip_ctx (ctx_params ); 3995loader .load_hparams (ctx_gen_audio -> model ,CLIP_MODALITY_GEN_AUDIO ); 3996loader .load_tensors (* ctx_gen_audio ); 3997// TODO: fix warmup 3998ctx_gen_audio -> buf_compute_meta .resize (ctx_gen_audio -> max_nodes * ggml_tensor_overhead ()+ ggml_graph_overhead ()); 3999 } 4000 4001 }catch (const std::exception & e ) { 4002LOG_ERR ("%s: failed to load model '%s': %s\n" ,__func__ ,fname ,e .what ()); 4003 4004delete ctx_vision ; 4005delete ctx_audio ; 4006delete ctx_gen_audio ; 4007 4008return {nullptr ,nullptr ,nullptr }; 4009 } 4010 4011return {ctx_vision ,ctx_audio ,ctx_gen_audio }; 4012} 4013 4014struct clip_cap clip_get_cap (const char * fname ) { 4015clip_cap res ; 4016clip_model_loader loader (fname ,/* skip_tensors= */ true ); 4017res .has_vision = loader .has_vision ; 4018res .has_audio = loader .has_audio ; 4019return res ; 4020} 4021 4022void clip_free (clip_ctx * ctx ) { 4023if (ctx == nullptr ) { 4024return ; 4025 } 4026delete ctx ; 4027} 4028 4029const char * clip_patch_merge_type (const struct clip_ctx * ctx ) { 4030return ctx -> model .hparams .mm_patch_merge_type == PATCH_MERGE_SPATIAL_UNPAD ?"spatial_unpad" :"flat" ; 4031} 4032 4033int clip_n_output_tokens_x (const clip_ctx * ctx ,const clip_image_f32 * img ) { 4034const auto & params = ctx -> model .hparams ; 4035const int n_total = clip_n_output_tokens (ctx ,img ); 4036const auto & proj = ctx -> proj_type (); 4037switch (proj ) { 4038case PROJECTOR_TYPE_QWEN2VL : 4039case PROJECTOR_TYPE_QWEN25VL : 4040case PROJECTOR_TYPE_QWEN3VL : 4041case PROJECTOR_TYPE_EXAONE4_5 : 4042case PROJECTOR_TYPE_MIMOVL : 4043case PROJECTOR_TYPE_GLM4V : 4044case PROJECTOR_TYPE_PADDLEOCR : 4045case PROJECTOR_TYPE_HUNYUANVL : 4046case PROJECTOR_TYPE_YOUTUVL : 4047case PROJECTOR_TYPE_MUSE_GLIMMER : 4048return (img -> nx () /params .patch_size ) /2 ; 4049case PROJECTOR_TYPE_STEP3VL : 4050return img -> nx () / (params .patch_size * params .n_merge ); 4051case PROJECTOR_TYPE_DEEPSEEKOCR : 4052case PROJECTOR_TYPE_DEEPSEEKOCR2 : 4053return (img -> nx () /params .patch_size ) /4 ; 4054default : 4055break ; 4056 } 4057return n_total ; 4058} 4059 4060int clip_n_output_tokens_y (const clip_ctx * ctx ,const clip_image_f32 * img ) { 4061const auto & params = ctx -> model .hparams ; 4062const auto & proj = ctx -> proj_type (); 4063switch (proj ) { 4064case PROJECTOR_TYPE_QWEN2VL : 4065case PROJECTOR_TYPE_QWEN25VL : 4066case PROJECTOR_TYPE_QWEN3VL : 4067case PROJECTOR_TYPE_EXAONE4_5 : 4068case PROJECTOR_TYPE_MIMOVL : 4069case PROJECTOR_TYPE_GLM4V : 4070case PROJECTOR_TYPE_PADDLEOCR : 4071case PROJECTOR_TYPE_HUNYUANVL : 4072case PROJECTOR_TYPE_YOUTUVL : 4073case PROJECTOR_TYPE_MUSE_GLIMMER : 4074return (img -> ny () /params .patch_size ) /2 ; 4075case PROJECTOR_TYPE_STEP3VL : 4076return img -> ny () / (params .patch_size * params .n_merge ); 4077default : 4078break ; 4079 } 4080return 1 ; 4081} 4082 4083int clip_n_output_tokens (const clip_ctx * ctx ,const clip_image_f32 * img ) { 4084const auto & params = ctx -> model .hparams ; 4085 4086// for models with fixed size image, the input image is already pre-processed and resized to square 4087int patch_size = params .patch_size ; 4088int n_patches = (img -> nx () /patch_size )* (img -> ny () /patch_size ); 4089 4090projector_type proj = ctx -> proj_type (); 4091 4092switch (proj ) { 4093case PROJECTOR_TYPE_MLP : 4094case PROJECTOR_TYPE_MLP_NORM : 4095case PROJECTOR_TYPE_JANUS_PRO : 4096case PROJECTOR_TYPE_PHI4 : 4097 { 4098// do nothing 4099 }break ; 4100case PROJECTOR_TYPE_YASA2 : 4101 { 4102n_patches = 64 ;// adaptive average pooling to 8x8 tokens 4103 }break ; 4104case PROJECTOR_TYPE_LDP : 4105case PROJECTOR_TYPE_LDPV2 : 4106case PROJECTOR_TYPE_GLM_EDGE : 4107 { 4108n_patches /=4 ; 4109if (ctx -> model .mm_boi ) { 4110n_patches += 2 ;// for BOI and EOI token embeddings 4111 } 4112 }break ; 4113case PROJECTOR_TYPE_MINICPMV : 4114 { 4115// Use actual config value if available, otherwise fall back to hardcoded values 4116if (params .minicpmv_query_num > 0 ) { 4117n_patches = params .minicpmv_query_num ; 4118 }else { 4119// Fallback to hardcoded values for legacy models 4120if (params .minicpmv_version == 2 ) { 4121n_patches = 96 ; 4122 }else if (params .minicpmv_version == 3 ) { 4123n_patches = 64 ; 4124 }else if (params .minicpmv_version == 4 ) { 4125n_patches = 64 ; 4126 }else if (params .minicpmv_version == 5 ) { 4127// MiniCPM-V 4.0 4128n_patches = 64 ; 4129 }else if (params .minicpmv_version == 6 ) { 4130// MiniCPM-V 4.5 4131n_patches = 64 ; 4132 }else if (params .minicpmv_version == 100045 ) { 4133// MiniCPM-o 4.5 4134n_patches = 64 ; 4135 }else { 4136GGML_ABORT ("Unknown minicpmv version" ); 4137 } 4138 } 4139 }break ; 4140case PROJECTOR_TYPE_MINICPMV4_6 : 4141 { 4142n_patches /=params .n_merge * params .n_merge ; 4143 }break ; 4144case PROJECTOR_TYPE_QWEN2VL : 4145case PROJECTOR_TYPE_QWEN25VL : 4146case PROJECTOR_TYPE_QWEN3VL : 4147case PROJECTOR_TYPE_EXAONE4_5 : 4148case PROJECTOR_TYPE_MIMOVL : 4149case PROJECTOR_TYPE_MINIMAX_M3 : 4150case PROJECTOR_TYPE_GLM4V : 4151case PROJECTOR_TYPE_YOUTUVL : 4152case PROJECTOR_TYPE_MUSE_GLIMMER : 4153 { 4154// dynamic size (2 conv, so double patch size) 4155int x_patch = img -> nx () / (params .patch_size * 2 ); 4156int y_patch = img -> ny () / (params .patch_size * 2 ); 4157n_patches = x_patch * y_patch ; 4158 }break ; 4159case PROJECTOR_TYPE_STEP3VL : 4160 { 4161int x_patch = img -> nx () / (params .patch_size * params .n_merge ); 4162int y_patch = img -> ny () / (params .patch_size * params .n_merge ); 4163n_patches = x_patch * y_patch ; 4164 }break ; 4165case PROJECTOR_TYPE_GEMMA3 : 4166case PROJECTOR_TYPE_GEMMA4V : 4167case PROJECTOR_TYPE_GEMMA4UV : 4168case PROJECTOR_TYPE_IDEFICS3 : 4169case PROJECTOR_TYPE_INTERNVL : 4170case PROJECTOR_TYPE_NEMOTRON_V2_VL : 4171case PROJECTOR_TYPE_LLAMA4 : 4172 { 4173// both X and Y are downscaled by the scale factor 4174int scale_factor = ctx -> model .hparams .n_merge ; 4175n_patches /= (scale_factor * scale_factor ); 4176 }break ; 4177case PROJECTOR_TYPE_GEMMA3NV : 4178 { 4179// MobileNetV5 MSFA adapter always outputs fixed 16x16 resolution 4180// regardless of input size (see architecture description) 4181n_patches = ctx -> model .hparams .image_size /ctx -> model .hparams .patch_size ; 4182 }break ; 4183case PROJECTOR_TYPE_LFM2 : 4184case PROJECTOR_TYPE_KIMIVL : 4185case PROJECTOR_TYPE_KIMIK25 : 4186 { 4187// dynamic size 4188int out_patch_size = params .patch_size * ctx -> model .hparams .n_merge ; 4189int x_patch = CLIP_ALIGN (img -> nx (),out_patch_size ) /out_patch_size ; 4190int y_patch = CLIP_ALIGN (img -> ny (),out_patch_size ) /out_patch_size ; 4191n_patches = x_patch * y_patch ; 4192 }break ; 4193case PROJECTOR_TYPE_DEEPSEEK4V : 4194 { 4195const int out_patch_size = params .patch_size * params .n_merge ; 4196const int n_llm_w = CLIP_ALIGN (img -> nx (),out_patch_size ) /out_patch_size ; 4197const int n_llm_h = CLIP_ALIGN (img -> ny (),out_patch_size ) /out_patch_size ; 4198n_patches = dsv4_get_block_layout (n_llm_w ,n_llm_h ,img -> lead_pad ).n_out ; 4199 }break ; 4200case PROJECTOR_TYPE_PADDLEOCR : 4201case PROJECTOR_TYPE_DOTS_OCR : 4202case PROJECTOR_TYPE_DOTS3NOTE_V : 4203 { 4204// dynamic size 4205int n_merge = ctx -> model .hparams .n_merge ; 4206int stride = n_merge * n_merge ; 4207n_patches = CLIP_ALIGN (n_patches ,stride ) /stride ; 4208 }break ; 4209case PROJECTOR_TYPE_DOTS3NOTE_A : 4210 { 4211// 3x stride-2 conv2d over mel frames 4212n_patches = (img -> nx ()+ 7 ) /8 ; 4213 }break ; 4214case PROJECTOR_TYPE_PIXTRAL : 4215case PROJECTOR_TYPE_LIGHTONOCR : 4216 { 4217// dynamic size 4218int n_merge = ctx -> model .hparams .n_merge ; 4219int n_patches_x = img -> nx () /patch_size /n_merge ; 4220int n_patches_y = img -> ny () /patch_size /n_merge ; 4221if (ctx -> model .token_embd_img_break ) { 4222n_patches = n_patches_y * n_patches_x + n_patches_y - 1 ;// + one [IMG_BREAK] per row, except the last row 4223 }else { 4224n_patches = n_patches_y * n_patches_x ; 4225 } 4226 }break ; 4227case PROJECTOR_TYPE_VOXTRAL : 4228case PROJECTOR_TYPE_ULTRAVOX : 4229case PROJECTOR_TYPE_QWEN2A : 4230case PROJECTOR_TYPE_MERALION : 4231case PROJECTOR_TYPE_MUSIC_FLAMINGO : 4232 { 4233n_patches = img -> nx (); 4234 4235const int proj_stack_factor = ctx -> model .hparams .proj_stack_factor ; 4236if (ctx -> model .audio_has_stack_frames ()) { 4237GGML_ASSERT (proj_stack_factor > 0 ); 4238const int n_len = CLIP_ALIGN (n_patches ,proj_stack_factor ); 4239n_patches = n_len /proj_stack_factor ; 4240 } 4241 4242// whisper downscales input token by half after conv1d 4243n_patches /=2 ; 4244 4245if (ctx -> model .audio_has_avgpool ()) { 4246// divide by 2 because of nn.AvgPool1d(2, stride=2) 4247n_patches /=2 ; 4248 } 4249 }break ; 4250case PROJECTOR_TYPE_QWEN3A : 4251 { 4252// chunk_size=100 frames --> 3x stride-2 conv2d --> 13 tokens per chunk 4253const int chunk_size = 100 ; 4254const int tokens_per_chunk = 13 ; 4255n_patches = (img -> nx () /chunk_size )* tokens_per_chunk ; 4256 }break ; 4257case PROJECTOR_TYPE_GLMA : 4258 { 4259n_patches = img -> nx (); 4260// whisper downscales input token by half after conv1d 4261n_patches /=2 ; 4262// reshape by merge_factor 4263n_patches /=ctx -> model .hparams .proj_stack_factor ; 4264// for BOI and EOI token embeddings 4265n_patches += 2 ; 4266 }break ; 4267case PROJECTOR_TYPE_COGVLM : 4268 { 4269n_patches += 2 ;// for BOI and EOI token embeddings 4270 }break ; 4271case PROJECTOR_TYPE_DEEPSEEKOCR : 4272 { 4273// SAM encoder applies two stride-2 convolutions (net_2 and net_3) 4274// that reduce spatial dimensions by 4x in each direction (16x total) 4275// E.g., 64x64 -> 16x16 patches 4276n_patches /=16 ; 4277 4278if (img -> add_viewsep ) { 4279// global view: one image-newline per token-row + trailing view separator 4280const int h = static_cast < int > (std::sqrt (static_cast < float > (n_patches ))); 4281n_patches = h * (h + 1 )+ 1 ; 4282 }else if (img -> ny () >=img -> nx ()&& img -> ny () %img -> nx ()== 0 ) { 4283// tile row: one image-newline per token-row 4284const int grid_w = img -> ny () /img -> nx (); 4285const int tile_patches = img -> nx () / (patch_size * 4 );// patches per tile side (SAM divides by 4) 4286const int h = tile_patches ; 4287n_patches = (tile_patches * grid_w + 1 )* h ; 4288 } 4289 }break ; 4290case PROJECTOR_TYPE_HUNYUANVL : 4291 { 4292int merge = ctx -> model .hparams .n_merge ; 4293int ow = (img -> nx () /patch_size ) /merge ; 4294int oh = (img -> ny () /patch_size ) /merge ; 4295n_patches = (ow + 1 )* oh + 2 ; 4296 }break ; 4297case PROJECTOR_TYPE_DEEPSEEKOCR2 : 4298 { 4299// 1024 global view -> 256 query tokens + 1 view separator = 257; 4300// 768 local tile -> 144 query tokens, no separator. 4301n_patches /=16 ; 4302if (img -> add_viewsep ) { 4303n_patches += 1 ;// view separator, appended only after the global view 4304 } 4305 }break ; 4306case PROJECTOR_TYPE_LFM2A : 4307 { 4308n_patches = ((((img -> nx ()+ 1 ) /2 )+ 1 ) /2 + 1 ) /2 ; 4309 }break ; 4310case PROJECTOR_TYPE_GEMMA4A : 4311 { 4312// Two Conv2D stride-2: O = floor((I + 2p - k) / s) + 1, p=1, k=3, s=2 4313// O = floor((I - 1) / 2) + 1 4314int n = img -> nx (); 4315for (int i = 0 ;i < 2 ;i ++ ) { 4316n = (n - 1 ) /2 + 1 ; 4317 } 4318n_patches = n ; 4319 }break ; 4320case PROJECTOR_TYPE_PARAKEET : 4321 { 4322n_patches = (img -> nx ()+ (params .subsampling_factor - 1 )) /params .subsampling_factor ; 4323 }break ; 4324case PROJECTOR_TYPE_GEMMA4UA : 4325 { 4326n_patches = img -> nx ();// no downsampling: one token per raw waveform frame 4327 }break ; 4328case PROJECTOR_TYPE_MIMO_AUDIO : 4329 { 4330// conv1(s=1) + conv2(s=2) -> RVQ-encoder downsample conv(k=2,s=2) 4331int n = img -> nx (); 4332n = (n - 1 ) /2 + 1 ;// conv1 + conv2 4333n = (n - 2 ) /2 + 1 ;// downsample conv 4334const int group_size = params .audio_local_group_size ; 4335n_patches = (n + group_size - 1 ) /group_size ; 4336 }break ; 4337case PROJECTOR_TYPE_GRANITE_SPEECH : 4338 { 4339const int ws = ctx -> model .hparams .audio_proj_window_size ; 4340const int ds = ctx -> model .hparams .audio_proj_downsample_rate ; 4341n_patches = ((img -> nx ()+ ws - 1 ) /ws )* (ws /ds ); 4342 }break ; 4343case PROJECTOR_TYPE_QWEN3TTS_SPKENC : 4344 { 4345// pooling gives one speaker embedding, whatever the clip length is 4346n_patches = 1 ; 4347 }break ; 4348case PROJECTOR_TYPE_QWEN3TTS_GEN : 4349 { 4350// one hidden-state vector fed back to the talker per call 4351n_patches = 1 ; 4352 }break ; 4353case PROJECTOR_TYPE_POCKETTTS_SPKENC : 4354 { 4355// one conditioning row per 12.5Hz frame 4356const int hop = ctx -> model .hparams .mimi_downsample * 120 ; 4357n_patches = img -> nx () /hop ; 4358 }break ; 4359case PROJECTOR_TYPE_POCKETTTS_GEN : 4360 { 4361// one latent per call for GEN_CODE, GEN_WAV sizes its input from the caller 4362n_patches = 1 ; 4363 }break ; 4364case PROJECTOR_TYPE_GRANITE4_VISION : 4365 { 4366// Per-tile output token count: each projector block outputs 4367// query_side^2 tokens per window x n^2 windows. 4368// For 384x384 input: n = 24/8 = 3, query_side = 4 -> 144. 4369const int window_side = ctx -> model .hparams .downsample_window_side ; 4370const int query_side = ctx -> model .hparams .downsample_query_side ; 4371const int side = img -> nx () /params .patch_size ; 4372const int n = side /window_side ; 4373const int out_side = query_side * n ; 4374n_patches = out_side * out_side ; 4375if (img -> anyres .is_tiled ()) { 4376// overview tile, then the unpadded tile grid with one newline per row 4377int off_x ,off_y ,w ,h ; 4378clip_anyres_unpad (img -> anyres .grid_x * out_side ,img -> anyres .grid_y * out_side , 4379img -> anyres .orig_nx ,img -> anyres .orig_ny ,off_x ,off_y ,w ,h ); 4380n_patches += h * (w + 1 ); 4381 } 4382 }break ; 4383default : 4384GGML_ABORT ("unsupported projector type" ); 4385 } 4386 4387return n_patches ; 4388} 4389 4390bool clip_image_encode (struct clip_ctx * ctx ,int n_threads ,const clip_image_f32 * img , std::vector < float > & out_vec ) { 4391clip_image_f32_batch imgs ; 4392clip_image_f32 img_copy = * img ; 4393imgs .entries .push_back (std::move (img_copy )); 4394 4395return clip_image_batch_encode (ctx ,n_threads ,& imgs ,out_vec ); 4396} 4397 4398bool clip_image_batch_encode (clip_ctx * ctx ,int n_threads ,const clip_image_f32_batch * imgs_c_ptr , std::vector < float > & out_batch_embd ) { 4399clip_encode_params params ; 4400params .imgs = imgs_c_ptr ; 4401params .n_threads = n_threads ; 4402params .out_embd = & out_batch_embd ; 4403 4404return clip_encode (ctx ,& params ); 4405} 4406 4407// persisted state slots of the gen-audio decoder, per pipeline 4408static std::vector < c2w_state_slot > list_gen_state_slots (const clip_hparams & hparams ,const clip_model & model ) { 4409switch (model .proj_type ) { 4410case PROJECTOR_TYPE_QWEN3TTS_GEN :return list_c2w_state_slots (hparams ,model ); 4411case PROJECTOR_TYPE_POCKETTTS_GEN :return list_pockettts_state_slots (hparams ,model ); 4412default :return {}; 4413 } 4414} 4415 4416bool clip_encode (struct clip_ctx * ctx ,struct clip_encode_params * params ) { 4417const clip_image_f32_batch & imgs = * params -> imgs ; 4418int n_batch_cur = imgs .entries .size (); 4419 4420// [QWEN_VIDEO] for video models, the batch dimension is used as temporal dimension for merged frames 4421if (!ctx -> support_batch && n_batch_cur > clip_model_n_temporal_merge (ctx )) { 4422LOG_ERR ("%s: batch size %d exceeds maximum supported batch/temporal-merge size %d\n" ,__func__ ,n_batch_cur ,clip_model_n_temporal_merge (ctx )); 4423return false; 4424 } 4425 4426// if buffers are not allocated, we need to do a warmup run to allocate them 4427if (!ctx -> is_allocated ) { 4428 clip_model_loader::warmup (* ctx ,* params -> imgs ); 4429 } 4430 4431if (params -> seed != ctx -> rng_seed ) { 4432ctx -> rng_seed = params -> seed ; 4433ctx -> rng .seed (params -> seed == UINT32_MAX ? std::random_device {}() :params -> seed ); 4434 } 4435 4436// build the inference graph 4437ggml_backend_sched_reset (ctx -> sched .get ()); 4438ggml_cgraph * gf = clip_get_graph_builder (ctx ,imgs ,params )-> build (); 4439ggml_backend_sched_alloc_graph (ctx -> sched .get (),gf ); 4440 4441// set inputs 4442const auto & model = ctx -> model ; 4443const auto & hparams = model .hparams ; 4444 4445const int image_size_width = imgs .entries [0 ].nx (); 4446const int image_size_height = imgs .entries [0 ].ny (); 4447 4448const int patch_size = hparams .patch_size ; 4449const int num_patches = ((image_size_width /patch_size )* (image_size_height /patch_size )); 4450const int n_pos = num_patches + (model .class_embedding ?1 :0 ); 4451const int pos_w = image_size_width /patch_size ; 4452const int pos_h = image_size_height /patch_size ; 4453 4454 4455auto get_inp_tensor = [& gf ](const char * name ) { 4456ggml_tensor * inp = ggml_graph_get_tensor (gf ,name ); 4457if (inp == nullptr ) { 4458GGML_ABORT ("Failed to get tensor %s" ,name ); 4459 } 4460if (!(inp -> flags & GGML_TENSOR_FLAG_INPUT )) { 4461GGML_ABORT ("Tensor %s is not an input tensor" ,name ); 4462 } 4463return inp ; 4464 }; 4465 4466auto set_input_f32 = [& get_inp_tensor ](const char * name ,const std::vector < float > & values ) { 4467ggml_tensor * cur = get_inp_tensor (name ); 4468GGML_ASSERT (cur -> type == GGML_TYPE_F32 ); 4469GGML_ASSERT (ggml_nelements (cur )== (int64_t )values .size ()); 4470ggml_backend_tensor_set (cur ,values .data (),0 ,ggml_nbytes (cur )); 4471 }; 4472 4473auto set_input_i32 = [& get_inp_tensor ](const char * name , std::vector < int32_t > & values ) { 4474ggml_tensor * cur = get_inp_tensor (name ); 4475GGML_ASSERT (cur -> type == GGML_TYPE_I32 ); 4476GGML_ASSERT (ggml_nelements (cur )== (int64_t )values .size ()); 4477ggml_backend_tensor_set (cur ,values .data (),0 ,ggml_nbytes (cur )); 4478 }; 4479 4480// upload the decoder state from the previous call, or zero-fill on a cold start 4481auto set_gen_state_in = [& ]() { 4482size_t offset = 0 ; 4483for (const auto & slot :list_gen_state_slots (hparams ,model )) { 4484ggml_tensor * t = get_inp_tensor (("state_in_" + slot .name ).c_str ()); 4485const size_t nb = ggml_nbytes (t ); 4486if (params -> state_in && params -> state_in -> size () >=offset + nb ) { 4487ggml_backend_tensor_set (t ,params -> state_in -> data ()+ offset ,0 ,nb ); 4488 }else { 4489 std::vector < uint8_t > zeros (nb ,0 ); 4490ggml_backend_tensor_set (t ,zeros .data (),0 ,nb ); 4491 } 4492offset += nb ; 4493 } 4494 }; 4495 4496// rope positions and attention mask of the mimi transformers (pocket-tts). 4497// the mask is causal with a sliding window, see _build_attention_mask() in the reference 4498auto set_pockettts_tfm_inputs = [& ]() { 4499const int64_t n_pos = ggml_nelements (get_inp_tensor ("inp_pos" )); 4500GGML_ASSERT (n_pos > 0 ); 4501 std::vector < int32_t > positions ((size_t )n_pos ); 4502for (int64_t i = 0 ;i < n_pos ;i ++ ) { 4503positions [(size_t )i ]= (int32_t )i ; 4504 } 4505set_input_i32 ("inp_pos" ,positions ); 4506 4507// the preprocessor truncates the waveform to keep this mask bounded 4508const int64_t max_pos = (int64_t ) clip_hparams::pockettts_max_spk_seconds * hparams .audio_sample_rate /120 ; 4509GGML_ASSERT (n_pos <=max_pos && "pocket-tts speaker reference too long for a dense mask" ); 4510 4511const int64_t context = hparams .mimi_tfm_context ; 4512 std::vector < float > mask ((size_t )n_pos * n_pos ,- INFINITY ); 4513for (int64_t q = 0 ;q < n_pos ;q ++ ) { 4514for (int64_t k = 0 ;k < n_pos ;k ++ ) { 4515const int64_t delta = q - k ; 4516if (delta >=0 && delta < context ) { 4517mask [(size_t )q * n_pos + k ]= 0.0f ; 4518 } 4519 } 4520 } 4521set_input_f32 ("kq_mask" ,mask ); 4522 }; 4523 4524// set input pixel values 4525if (!imgs .is_audio ) { 4526size_t nelem = 0 ; 4527for (const auto & img :imgs .entries ) { 4528nelem += img .nx ()* img .ny ()* 3 ; 4529 } 4530 std::vector < float > inp_raw (nelem ); 4531 4532// layout of data (note: the channel dim is unrolled to better visualize the layout): 4533// 4534// ┌──W──┐ 4535// │ H │ channel = R 4536// ├─────┤ │ 4537// │ H │ channel = G 4538// ├─────┤ │ 4539// │ H │ channel = B 4540// └─────┘ │ 4541// ──────┘ x B 4542 4543// IMPORTANT: [QWEN_VIDEO] the batch dim is currently used for temporal dim in Qwen-VL models 4544// All entries must have the same spatial size (enforced by can_batch_with() during merging) 4545 { 4546const int nx = imgs .entries [0 ].nx (); 4547const int ny = imgs .entries [0 ].ny (); 4548const int n = nx * ny ; 4549 4550for (int b = 0 ;b < n_batch_cur ;b ++ ) { 4551LOG_DBG ("%s: copying image %d/%d to input buffer (nx=%d, ny=%d)\n" ,__func__ ,b + 1 ,n_batch_cur ,nx ,ny ); 4552const auto & buf = imgs .entries [b ].get_ro_buf (); 4553float * batch_entry = inp_raw .data ()+ b * (3 * n ); 4554for (int y = 0 ;y < ny ;y ++ ) { 4555for (int x = 0 ;x < nx ;x ++ ) { 4556size_t base_src = 3 * (y * nx + x ); 4557size_t base_dst = y * nx + x ; 4558batch_entry [base_dst ]= buf [base_src ]; 4559batch_entry [1 * n + base_dst ]= buf [base_src + 1 ]; 4560batch_entry [2 * n + base_dst ]= buf [base_src + 2 ]; 4561 } 4562 } 4563 } 4564 } 4565set_input_f32 ("inp_raw" ,inp_raw ); 4566 4567 }else if (params -> gen_process != CLIP_GEN_PROCESS_GEN_WAV ) { 4568// audio input. GEN_WAV is not here: it takes codes or feats, set in the switch below 4569GGML_ASSERT (imgs .entries .size ()== 1 ); 4570 4571const auto & mel_inp = imgs .entries [0 ]; 4572const auto & buf = mel_inp .get_ro_buf (); 4573const int n_step = mel_inp .nx (); 4574const int n_mel = mel_inp .ny (); 4575GGML_ASSERT ((size_t )n_step * n_mel == buf .size ()); 4576 4577set_input_f32 ("inp_raw" ,buf ); 4578 } 4579 4580// set input per projector 4581switch (ctx -> model .proj_type ) { 4582case PROJECTOR_TYPE_MUSE_GLIMMER : 4583 { 4584const int grid_w = pos_w ;// image_size_width / patch_size 4585const int grid_h = pos_h ;// image_size_height / patch_size 4586const int n_tok = grid_w * grid_h ; 4587const int pgrid = (int ) std::sqrt ((double )ctx -> model .position_embeddings -> ne [1 ]);// 32 4588const int f = hparams .n_merge ;// downsample 2 4589 4590// pixel patchify runs inside the graph via build_inp() (ggml_conv_2d); 4591// pos-emb bilinear interp via resize_position_embeddings(). 4592 4593// --- sparse window grouping (pgrid x pgrid windows) --- 4594const int win = pgrid ; 4595const int nwin_h = (grid_h + win - 1 ) /win ; 4596const int nwin_w = (grid_w + win - 1 ) /win ; 4597 std::vector < int32_t > sp_perm ;sp_perm .reserve (n_tok ); 4598 std::vector < int > sp_slens ; 4599for (int wy = 0 ;wy < nwin_h ;wy ++ ) { 4600for (int wx = 0 ;wx < nwin_w ;wx ++ ) { 4601int cnt = 0 ; 4602for (int hh = 0 ;hh < win ;hh ++ ) { 4603for (int ww = 0 ;ww < win ;ww ++ ) { 4604const int gy = wy * win + hh ; 4605const int gx = wx * win + ww ; 4606if (gy < grid_h && gx < grid_w ) {sp_perm .push_back (gy * grid_w + gx );cnt ++ ; } 4607 } 4608 } 4609if (cnt > 0 )sp_slens .push_back (cnt ); 4610 } 4611 } 4612 std::vector < int32_t > rpos_w (n_tok ),rpos_h (n_tok ),inv_perm (n_tok ); 4613for (int i = 0 ;i < n_tok ;i ++ ) { 4614const int orig = sp_perm [i ]; 4615rpos_w [i ]= (orig %grid_w )+ 1 ;// 1-indexed 4616rpos_h [i ]= (orig /grid_w )+ 1 ; 4617inv_perm [orig ]= i ; 4618 } 4619set_input_i32 ("muse_glimmer_sp_perm" ,sp_perm ); 4620set_input_i32 ("muse_glimmer_inv_perm" ,inv_perm ); 4621set_input_i32 ("muse_glimmer_pos_w" ,rpos_w ); 4622set_input_i32 ("muse_glimmer_pos_h" ,rpos_h ); 4623 4624// block-diagonal window mask (permuted order) 4625 std::vector < float > sp_mask ((size_t )n_tok * n_tok ,- INFINITY ); 4626 { 4627int off = 0 ; 4628for (int s :sp_slens ) { 4629for (int a = 0 ;a < s ;a ++ ) 4630for (int b = 0 ;b < s ;b ++ ) 4631sp_mask [(size_t ) (off + a )* n_tok + (off + b )]= 0.0f ; 4632off += s ; 4633 } 4634 } 4635set_input_f32 ("muse_glimmer_sp_mask" ,sp_mask ); 4636 4637// pixel-shuffle gather (original order): f*f spatial neighbours grouped 4638 std::vector < int32_t > dsp ;dsp .reserve (n_tok ); 4639for (int oy = 0 ;oy < grid_h /f ;oy ++ ) 4640for (int ox = 0 ;ox < grid_w /f ;ox ++ ) 4641for (int ry = 0 ;ry < f ;ry ++ ) 4642for (int rx = 0 ;rx < f ;rx ++ ) 4643dsp .push_back ((oy * f + ry )* grid_w + (ox * f + rx )); 4644set_input_i32 ("muse_glimmer_ds_perm" ,dsp ); 4645 }break ; 4646case PROJECTOR_TYPE_MINICPMV : 4647 { 4648// inspired from siglip: 4649// -> https://huggingface.co/HuggingFaceM4/siglip-so400m-14-980-flash-attn2-navit 4650// -> https://huggingface.co/HuggingFaceM4/siglip-so400m-14-980-flash-attn2-navit/blob/d66538faeba44480d0bfaa42145eef26f9423199/modeling_siglip.py#L316 4651 std::vector < int32_t > positions (pos_h * pos_w ); 4652int bucket_coords_h [1024 ]; 4653int bucket_coords_w [1024 ]; 4654for (int i = 0 ;i < pos_h ;i ++ ){ 4655bucket_coords_h [i ]= std::floor (70.0 * i /pos_h ); 4656 } 4657for (int i = 0 ;i < pos_w ;i ++ ){ 4658bucket_coords_w [i ]= std::floor (70.0 * i /pos_w ); 4659 } 4660for (int i = 0 ,id = 0 ;i < pos_h ;i ++ ){ 4661for (int j = 0 ;j < pos_w ;j ++ ){ 4662positions [id ++ ]= bucket_coords_h [i ]* 70 + bucket_coords_w [j ]; 4663 } 4664 } 4665set_input_i32 ("positions" ,positions ); 4666 4667// inputs for resampler projector 4668// set the 2D positions (using float for sinusoidal embedding) 4669int n_patches_per_col = image_size_width /patch_size ; 4670 std::vector < float > pos_data (n_pos ); 4671// dimension H 4672for (int i = 0 ;i < n_pos ;i ++ ) { 4673pos_data [i ]= static_cast < float > (i /n_patches_per_col ); 4674 } 4675set_input_f32 ("pos_h" ,pos_data ); 4676// dimension W 4677for (int i = 0 ;i < n_pos ;i ++ ) { 4678pos_data [i ]= static_cast < float > (i %n_patches_per_col ); 4679 } 4680set_input_f32 ("pos_w" ,pos_data ); 4681// base frequency omega 4682const float base_freq = 10000.0f ; 4683const int n_embd_proj = clip_n_mmproj_embd (ctx ); 4684 std::vector < float > omega (n_embd_proj /4 ); 4685for (int i = 0 ;i < n_embd_proj /4 ;++ i ) { 4686omega [i ]= 1.0f / std::pow (base_freq ,static_cast < float > (i ) / (n_embd_proj /4 )); 4687 } 4688set_input_f32 ("omega" ,omega ); 4689 }break ; 4690case PROJECTOR_TYPE_MINICPMV4_6 : 4691 { 4692const bool is_4x = hparams .n_merge == 2 ; 4693 4694// SigLIP position buckets (same as resampler path) 4695 std::vector < int32_t > positions (pos_h * pos_w ); 4696int bucket_coords_h [1024 ]; 4697int bucket_coords_w [1024 ]; 4698for (int i = 0 ;i < pos_h ;i ++ ){ 4699bucket_coords_h [i ]= std::floor (70.0 * i /pos_h ); 4700 } 4701for (int i = 0 ;i < pos_w ;i ++ ){ 4702bucket_coords_w [i ]= std::floor (70.0 * i /pos_w ); 4703 } 4704for (int i = 0 ,id = 0 ;i < pos_h ;i ++ ){ 4705for (int j = 0 ;j < pos_w ;j ++ ){ 4706positions [id ++ ]= bucket_coords_h [i ]* 70 + bucket_coords_w [j ]; 4707 } 4708 } 4709set_input_i32 ("positions" ,positions ); 4710 4711const int half_h = pos_h /2 ; 4712const int half_w = pos_w /2 ; 4713 4714auto make_ds_idx = [](int off_r ,int off_c ,int ds_h ,int ds_w ,int stride_w ) { 4715 std::vector < int32_t > idx (ds_h * ds_w ); 4716for (int i = 0 ;i < ds_h ;i ++ ) { 4717for (int j = 0 ;j < ds_w ;j ++ ) { 4718idx [i * ds_w + j ]= (2 * i + off_r )* stride_w + (2 * j + off_c ); 4719 } 4720 } 4721return idx ; 4722 }; 4723 4724if (!is_4x ) { 4725// window reorder indices for 2x2 windows 4726 std::vector < int32_t > window_idx (n_pos ); 4727 std::vector < int32_t > inv_window_idx (n_pos ); 4728 { 4729int k = 0 ; 4730for (int wi = 0 ;wi < half_h ;wi ++ ) { 4731for (int wj = 0 ;wj < half_w ;wj ++ ) { 4732window_idx [k ++ ]= (2 * wi )* pos_w + (2 * wj ); 4733window_idx [k ++ ]= (2 * wi )* pos_w + (2 * wj + 1 ); 4734window_idx [k ++ ]= (2 * wi + 1 )* pos_w + (2 * wj ); 4735window_idx [k ++ ]= (2 * wi + 1 )* pos_w + (2 * wj + 1 ); 4736 } 4737 } 4738for (int i = 0 ;i < n_pos ;i ++ ) { 4739inv_window_idx [window_idx [i ]]= i ; 4740 } 4741 } 4742set_input_i32 ("vit_merger_window_idx" ,window_idx ); 4743set_input_i32 ("vit_merger_inv_window_idx" ,inv_window_idx ); 4744 4745// block-diagonal attention mask: tokens in the same 4-token 4746// window attend to each other (mask = 0), all other positions 4747// are masked out (-inf). matches the window-major reorder above. 4748 std::vector < float > window_mask_data (n_pos * n_pos , std::numeric_limits < float > ::lowest ()); 4749for (int wi = 0 ;wi < n_pos /4 ;wi ++ ) { 4750for (int i = 0 ;i < 4 ;i ++ ) { 4751for (int j = 0 ;j < 4 ;j ++ ) { 4752window_mask_data [(wi * 4 + i )* n_pos + (wi * 4 + j )]= 0.0f ; 4753 } 4754 } 4755 } 4756set_input_f32 ("vit_merger_window_mask" ,window_mask_data ); 4757 4758// ViT merger 2x2 downsample indices 4759auto vit_merger_ds_0 = make_ds_idx (0 ,0 ,half_h ,half_w ,pos_w ); 4760auto vit_merger_ds_1 = make_ds_idx (0 ,1 ,half_h ,half_w ,pos_w ); 4761auto vit_merger_ds_2 = make_ds_idx (1 ,0 ,half_h ,half_w ,pos_w ); 4762auto vit_merger_ds_3 = make_ds_idx (1 ,1 ,half_h ,half_w ,pos_w ); 4763set_input_i32 ("vit_merger_ds_idx_0" ,vit_merger_ds_0 ); 4764set_input_i32 ("vit_merger_ds_idx_1" ,vit_merger_ds_1 ); 4765set_input_i32 ("vit_merger_ds_idx_2" ,vit_merger_ds_2 ); 4766set_input_i32 ("vit_merger_ds_idx_3" ,vit_merger_ds_3 ); 4767 } 4768 4769const int merger_h = is_4x ?pos_h :half_h ; 4770const int merger_w = is_4x ?pos_w :half_w ; 4771auto m_ds_0 = make_ds_idx (0 ,0 ,merger_h /2 ,merger_w /2 ,merger_w ); 4772auto m_ds_1 = make_ds_idx (0 ,1 ,merger_h /2 ,merger_w /2 ,merger_w ); 4773auto m_ds_2 = make_ds_idx (1 ,0 ,merger_h /2 ,merger_w /2 ,merger_w ); 4774auto m_ds_3 = make_ds_idx (1 ,1 ,merger_h /2 ,merger_w /2 ,merger_w ); 4775set_input_i32 ("merger_ds_idx_0" ,m_ds_0 ); 4776set_input_i32 ("merger_ds_idx_1" ,m_ds_1 ); 4777set_input_i32 ("merger_ds_idx_2" ,m_ds_2 ); 4778set_input_i32 ("merger_ds_idx_3" ,m_ds_3 ); 4779 }break ; 4780case PROJECTOR_TYPE_QWEN2VL : 4781case PROJECTOR_TYPE_QWEN3VL : 4782case PROJECTOR_TYPE_GLM4V : 4783 { 4784const int merge_ratio = hparams .n_merge ; 4785const int pw = image_size_width /patch_size ; 4786const int ph = image_size_height /patch_size ; 4787 std::vector < int > positions (n_pos * 4 ); 4788int ptr = 0 ; 4789for (int y = 0 ;y < ph ;y += merge_ratio ) { 4790for (int x = 0 ;x < pw ;x += merge_ratio ) { 4791for (int dy = 0 ;dy < 2 ;dy ++ ) { 4792for (int dx = 0 ;dx < 2 ;dx ++ ) { 4793positions [ptr ]= y + dy ; 4794positions [num_patches + ptr ]= x + dx ; 4795positions [2 * num_patches + ptr ]= y + dy ; 4796positions [3 * num_patches + ptr ]= x + dx ; 4797ptr ++ ; 4798 } 4799 } 4800 } 4801 } 4802 4803set_input_i32 ("positions" ,positions ); 4804 }break ; 4805case PROJECTOR_TYPE_STEP3VL : 4806 { 4807 std::vector < int32_t > pos_data (n_pos ); 4808for (int i = 0 ;i < n_pos ;i ++ ) { 4809pos_data [i ]= i /pos_w ; 4810 } 4811set_input_i32 ("pos_h" ,pos_data ); 4812for (int i = 0 ;i < n_pos ;i ++ ) { 4813pos_data [i ]= i %pos_w ; 4814 } 4815set_input_i32 ("pos_w" ,pos_data ); 4816 }break ; 4817case PROJECTOR_TYPE_PADDLEOCR : 4818 { 4819const int merge_ratio = hparams .n_merge ; 4820const int pw = image_size_width /patch_size ; 4821const int ph = image_size_height /patch_size ; 4822 std::vector < int > positions (n_pos * 4 ); 4823int ptr = 0 ; 4824// NOTE: same as Qwen-VL, but x and y are swapped 4825for (int y = 0 ;y < ph ;y += merge_ratio ) { 4826for (int dy = 0 ;dy < 2 ;dy ++ ) { 4827for (int x = 0 ;x < pw ;x += merge_ratio ) { 4828for (int dx = 0 ;dx < 2 ;dx ++ ) { 4829positions [ptr ]= y + dy ; 4830positions [num_patches + ptr ]= x + dx ; 4831positions [2 * num_patches + ptr ]= y + dy ; 4832positions [3 * num_patches + ptr ]= x + dx ; 4833ptr ++ ; 4834 } 4835 } 4836 } 4837 } 4838 4839set_input_i32 ("positions" ,positions ); 4840 }break ; 4841case PROJECTOR_TYPE_MINIMAX_M3 : 4842 { 4843const int n_merge = hparams .n_merge ; 4844const int gh = image_size_height /patch_size ; 4845const int gw = image_size_width /patch_size ; 4846 std::vector < int32_t > pos_h ,pos_w ; 4847pos_h .reserve (gh * gw ); 4848pos_w .reserve (gh * gw ); 4849for (int bh = 0 ;bh < gh /n_merge ;bh ++ ) 4850for (int bw = 0 ;bw < gw /n_merge ;bw ++ ) 4851for (int mh = 0 ;mh < n_merge ;mh ++ ) 4852for (int mw = 0 ;mw < n_merge ;mw ++ ) { 4853pos_h .push_back (bh * n_merge + mh ); 4854pos_w .push_back (bw * n_merge + mw ); 4855 } 4856set_input_i32 ("minimax_pos_h" ,pos_h ); 4857set_input_i32 ("minimax_pos_w" ,pos_w ); 4858 }break ; 4859case PROJECTOR_TYPE_DOTS_OCR : 4860case PROJECTOR_TYPE_DOTS3NOTE_V : 4861 { 4862const int pw = image_size_width /patch_size ; 4863const int ph = image_size_height /patch_size ; 4864const int n_pos = ph * pw ; 4865 std::vector < int > positions (n_pos * 4 ); 4866int ptr = 0 ; 4867 4868// flat layout: [h, w, h, w] for each patch 4869// patches are in raster order (matching conv2d output) 4870for (int y = 0 ;y < ph ;y ++ ) { 4871for (int x = 0 ;x < pw ;x ++ ) { 4872positions [ptr ]= y ; 4873positions [n_pos + ptr ]= x ; 4874positions [2 * n_pos + ptr ]= y ; 4875positions [3 * n_pos + ptr ]= x ; 4876ptr ++ ; 4877 } 4878 } 4879 4880set_input_i32 ("positions" ,positions ); 4881 }break ; 4882case PROJECTOR_TYPE_QWEN25VL : 4883case PROJECTOR_TYPE_EXAONE4_5 : 4884case PROJECTOR_TYPE_YOUTUVL : 4885 { 4886// pw * ph = number of tokens output by ViT after apply patch merger 4887// ipw * ipw = number of vision token been processed inside ViT 4888const bool use_window_attn = 4889 (ctx -> model .proj_type == PROJECTOR_TYPE_QWEN25VL || ctx -> model .proj_type == PROJECTOR_TYPE_EXAONE4_5 ) 4890 ?hparams .n_wa_pattern > 0 4891 : !hparams .wa_layer_indexes .empty (); 4892const int merge_ratio = 2 ; 4893const int pw = image_size_width /patch_size /merge_ratio ; 4894const int ph = image_size_height /patch_size /merge_ratio ; 4895const int ipw = image_size_width /patch_size ; 4896const int iph = image_size_height /patch_size ; 4897 4898 std::vector < int > idx (ph * pw ); 4899 std::vector < int > inv_idx (ph * pw ); 4900 4901if (use_window_attn ) { 4902const int attn_window_size = hparams .attn_window_size > 0 ?hparams .attn_window_size :112 ; 4903const int grid_window = attn_window_size /patch_size /merge_ratio ; 4904int dst = 0 ; 4905// [num_vision_tokens, num_vision_tokens] attention mask tensor 4906 std::vector < float > mask (pow (ipw * iph ,2 ), std::numeric_limits < float > ::lowest ()); 4907int mask_row = 0 ; 4908 4909for (int y = 0 ;y < ph ;y += grid_window ) { 4910for (int x = 0 ;x < pw ;x += grid_window ) { 4911const int win_h = std::min (grid_window ,ph - y ); 4912const int win_w = std::min (grid_window ,pw - x ); 4913const int dst_0 = dst ; 4914// group all tokens belong to the same window togather (to a continue range) 4915for (int dy = 0 ;dy < win_h ;dy ++ ) { 4916for (int dx = 0 ;dx < win_w ;dx ++ ) { 4917const int src = (y + dy )* pw + (x + dx ); 4918GGML_ASSERT (src < (int )idx .size ()); 4919GGML_ASSERT (dst < (int )inv_idx .size ()); 4920idx [src ]= dst ; 4921inv_idx [dst ]= src ; 4922dst ++ ; 4923 } 4924 } 4925 4926for (int r = 0 ;r < win_h * win_w * merge_ratio * merge_ratio ;r ++ ) { 4927int row_offset = mask_row * (ipw * iph ); 4928 std::fill ( 4929mask .begin ()+ row_offset + (dst_0 * merge_ratio * merge_ratio ), 4930mask .begin ()+ row_offset + (dst * merge_ratio * merge_ratio ), 49310.0 ); 4932mask_row ++ ; 4933 } 4934 } 4935 } 4936 4937set_input_i32 ("window_idx" ,idx ); 4938set_input_i32 ("inv_window_idx" ,inv_idx ); 4939set_input_f32 ("window_mask" ,mask ); 4940 }else { 4941for (int i = 0 ;i < ph * pw ;i ++ ) { 4942idx [i ]= i ; 4943 } 4944 } 4945 4946const int mpow = merge_ratio * merge_ratio ; 4947 std::vector < int > positions (n_pos * 4 ); 4948 4949int ptr = 0 ; 4950for (int y = 0 ;y < iph ;y += merge_ratio ) { 4951for (int x = 0 ;x < ipw ;x += merge_ratio ) { 4952for (int dy = 0 ;dy < 2 ;dy ++ ) { 4953for (int dx = 0 ;dx < 2 ;dx ++ ) { 4954auto remap = idx [ptr /mpow ]; 4955remap = (remap * mpow )+ (ptr %mpow ); 4956 4957positions [remap ]= y + dy ; 4958positions [num_patches + remap ]= x + dx ; 4959positions [2 * num_patches + remap ]= y + dy ; 4960positions [3 * num_patches + remap ]= x + dx ; 4961ptr ++ ; 4962 } 4963 } 4964 } 4965 } 4966 4967set_input_i32 ("positions" ,positions ); 4968 }break ; 4969case PROJECTOR_TYPE_MIMOVL : 4970 { 4971const int merge = hparams .n_merge ;// 2 4972const int merge_unit = merge * merge ;// 4 4973const int patch = hparams .patch_size ;// 16 4974const int H = image_size_height /patch ; 4975const int W = image_size_width /patch ; 4976const int n_pos_full = H * W ; 4977const int llm_h = H /merge ; 4978const int llm_w = W /merge ; 4979const int n_units = llm_h * llm_w ;// n_pos / merge_unit 4980 4981// Row-major merge-tile-ordered (h, w) positions 4982 std::vector < int32_t > pos_h_row (n_pos_full ); 4983 std::vector < int32_t > pos_w_row (n_pos_full ); 4984 { 4985int idx = 0 ; 4986for (int ty = 0 ;ty < llm_h ;ty ++ ) { 4987for (int tx = 0 ;tx < llm_w ;tx ++ ) { 4988for (int dy = 0 ;dy < merge ;dy ++ ) { 4989for (int dx = 0 ;dx < merge ;dx ++ ) { 4990pos_h_row [idx ]= ty * merge + dy ; 4991pos_w_row [idx ]= tx * merge + dx ; 4992idx ++ ; 4993 } 4994 } 4995 } 4996 } 4997 } 4998 4999// Col-major merge-unit permutation 5000 std::vector < float > idx_col (n_units ); 5001for (int r = 0 ;r < llm_h ;r ++ ) { 5002for (int c = 0 ;c < llm_w ;c ++ ) { 5003int u_row = r * llm_w + c ; 5004int u_col = c * llm_h + r ; 5005idx_col [u_col ]= (float )u_row ; 5006 } 5007 } 5008 5009// Col-mode positions: permute pos_*_row by idx_col 5010 std::vector < int32_t > pos_h_col (n_pos_full ); 5011 std::vector < int32_t > pos_w_col (n_pos_full ); 5012for (int u = 0 ;u < n_units ;u ++ ) { 5013int src = (int )idx_col [u ]; 5014for (int k = 0 ;k < merge_unit ;k ++ ) { 5015pos_h_col [u * merge_unit + k ]= pos_h_row [src * merge_unit + k ]; 5016pos_w_col [u * merge_unit + k ]= pos_w_row [src * merge_unit + k ]; 5017 } 5018 } 5019 5020// Pack into ggml_rope_multi VISION-mode layout. The non-CPU kernels 5021// only read slots 0 and 1, so pack h in slot 0, w in slot 1: 5022// positions[0..n_pos) = h 5023// positions[n_pos..2*n_pos) = w 5024// positions[2*n_pos..3*n_pos) = 0 5025// positions[3*n_pos..4*n_pos) = 0 5026 std::vector < int32_t > positions_row (static_cast < size_t > (n_pos_full )* 4 ,0 ); 5027 std::vector < int32_t > positions_col (static_cast < size_t > (n_pos_full )* 4 ,0 ); 5028for (int i = 0 ;i < n_pos_full ;i ++ ) { 5029positions_row [0 * n_pos_full + i ]= pos_h_row [i ]; 5030positions_row [1 * n_pos_full + i ]= pos_w_row [i ]; 5031positions_col [0 * n_pos_full + i ]= pos_h_col [i ]; 5032positions_col [1 * n_pos_full + i ]= pos_w_col [i ]; 5033 } 5034 5035// Banded 1D sliding-window mask 5036const int window = hparams .attn_window_size ; 5037GGML_ASSERT (window > 0 ); 5038 std::vector < float > mask (static_cast < size_t > (n_pos_full )* n_pos_full , std::numeric_limits < float > ::lowest ()); 5039for (int q = 0 ;q < n_pos_full ;q ++ ) { 5040int lo = std::max (0 ,q - window ); 5041int hi = std::min (n_pos_full - 1 ,q + window ); 5042for (int k = lo ;k <=hi ;k ++ ) { 5043mask [static_cast < size_t > (q )* n_pos_full + k ]= 0.0f ; 5044 } 5045 } 5046 5047set_input_i32 ("mimovl_positions_row" ,positions_row ); 5048set_input_i32 ("mimovl_positions_col" ,positions_col ); 5049set_input_f32 ("mimovl_idx_col" ,idx_col ); 5050set_input_f32 ("mimovl_window_mask" ,mask ); 5051 }break ; 5052case PROJECTOR_TYPE_PIXTRAL : 5053case PROJECTOR_TYPE_KIMIVL : 5054case PROJECTOR_TYPE_KIMIK25 : 5055case PROJECTOR_TYPE_LIGHTONOCR : 5056 { 5057// set the 2D positions 5058int n_patches_per_col = image_size_width /patch_size ; 5059 std::vector < int > pos_data (n_pos ); 5060// dimension H 5061for (int i = 0 ;i < n_pos ;i ++ ) { 5062pos_data [i ]= i /n_patches_per_col ; 5063 } 5064set_input_i32 ("pos_h" ,pos_data ); 5065// dimension W 5066for (int i = 0 ;i < n_pos ;i ++ ) { 5067pos_data [i ]= i %n_patches_per_col ; 5068 } 5069set_input_i32 ("pos_w" ,pos_data ); 5070 }break ; 5071case PROJECTOR_TYPE_DEEPSEEK4V : 5072 { 5073// set the 2D positions (mrope layout, only the first 2 channels are used) 5074int n_patches_per_row = image_size_width /patch_size ; 5075 std::vector < int32_t > positions (n_pos * 4 ,0 ); 5076for (int i = 0 ;i < n_pos ;i ++ ) { 5077positions [i ]= i /n_patches_per_row ;// row 5078positions [n_pos + i ]= i %n_patches_per_row ;// col 5079 } 5080set_input_i32 ("positions" ,positions ); 5081 5082// token block layout index (see clip_graph_deepseek4v::build) 5083// rows [0, n_grid) are the aligner output, the sentinels follow 5084const int n_merge = hparams .n_merge ; 5085const int n_llm_w = CLIP_ALIGN (pos_w ,n_merge ) /n_merge ; 5086const int n_llm_h = CLIP_ALIGN (pos_h ,n_merge ) /n_merge ; 5087const int n_grid = n_llm_w * n_llm_h ; 5088const int idx_start = n_grid ; 5089const int idx_end = n_grid + 1 ; 5090const int idx_newline = n_grid + 2 ; 5091const int idx_pad = n_grid + 3 ; 5092 5093const int lead_pad = imgs .entries [0 ].lead_pad ; 5094const auto bl = dsv4_get_block_layout (n_llm_w ,n_llm_h ,lead_pad ); 5095 5096 std::vector < int32_t > idx ; 5097idx .reserve (bl .n_out ); 5098for (int i = 0 ;i < lead_pad ;i ++ ) { 5099idx .push_back (idx_pad ); 5100 } 5101idx .push_back (idx_start ); 5102// pairs of adjacent rows are interleaved column-wise ("N-layout") 5103// ref: build_image_block in inference/image_processor.py 5104for (int t = 0 ;t < bl .rows * bl .row_len ;t ++ ) { 5105const int g = t / (2 * bl .row_len ); 5106const int rem = t % (2 * bl .row_len ); 5107const int c = rem /2 ;// column 5108const int r = 2 * g + rem %2 ;// row 5109if (r >=n_llm_h ) { 5110idx .push_back (idx_pad ); 5111 }else if (c == n_llm_w ) { 5112idx .push_back (idx_newline ); 5113 }else { 5114idx .push_back (r * n_llm_w + c ); 5115 } 5116 } 5117for (int i = 0 ;i < bl .pad_last ;i ++ ) { 5118idx .push_back (idx_pad ); 5119 } 5120idx .push_back (idx_end ); 5121set_input_i32 ("layout_idx" ,idx ); 5122 }break ; 5123case PROJECTOR_TYPE_GLM_EDGE : 5124 { 5125// llava and other models 5126 std::vector < int32_t > positions (n_pos ); 5127for (int i = 0 ;i < n_pos ;i ++ ) { 5128positions [i ]= i ; 5129 } 5130set_input_i32 ("positions" ,positions ); 5131 }break ; 5132case PROJECTOR_TYPE_MLP : 5133case PROJECTOR_TYPE_MLP_NORM : 5134case PROJECTOR_TYPE_LDP : 5135case PROJECTOR_TYPE_LDPV2 : 5136 { 5137// llava and other models 5138 std::vector < int32_t > positions (n_pos ); 5139for (int i = 0 ;i < n_pos ;i ++ ) { 5140positions [i ]= i ; 5141 } 5142set_input_i32 ("positions" ,positions ); 5143 5144// The patches vector is used to get rows to index into the embeds with; 5145// we should skip dim 0 only if we have CLS to avoid going out of bounds 5146// when retrieving the rows. 5147int patch_offset = model .class_embedding ?1 :0 ; 5148 std::vector < int32_t > patches (num_patches ); 5149for (int i = 0 ;i < num_patches ;i ++ ) { 5150patches [i ]= i + patch_offset ; 5151 } 5152set_input_i32 ("patches" ,patches ); 5153 }break ; 5154case PROJECTOR_TYPE_POCKETTTS_SPKENC : 5155 { 5156set_pockettts_tfm_inputs (); 5157 }break ; 5158case PROJECTOR_TYPE_POCKETTTS_GEN : 5159 { 5160if (params -> gen_process == CLIP_GEN_PROCESS_GEN_WAV ) { 5161GGML_ASSERT (params -> feats != nullptr ); 5162set_input_f32 ("inp_feats" ,* params -> feats ); 5163// positions and mask are derived in-graph from the persisted counter 5164set_gen_state_in (); 5165 }else { 5166// flow matching starts from gaussian noise, std = sqrt(temp) 5167ggml_tensor * t = get_inp_tensor ("inp_noise" ); 5168// Config.default_temperature, for a caller that does not set one 5169const float temp = params -> temp > 0.0f ?params -> temp :0.7f ; 5170 std::normal_distribution < float > dist (0.0f , std::sqrt (temp )); 5171 std::vector < float > noise (ggml_nelements (t )); 5172for (auto & v :noise ) { 5173v = dist (ctx -> rng ); 5174 } 5175set_input_f32 ("inp_noise" ,noise ); 5176 } 5177 }break ; 5178case PROJECTOR_TYPE_GEMMA4V : 5179case PROJECTOR_TYPE_GEMMA4UV : 5180 { 5181// set (col, row) patch positions for learned positional embedding 5182const int n_cols = image_size_width /patch_size ; 5183 std::vector < int > pos_x (num_patches ),pos_y (num_patches ); 5184for (int i = 0 ;i < num_patches ;i ++ ) { 5185pos_x [i ]= i %n_cols ; 5186pos_y [i ]= i /n_cols ; 5187 } 5188set_input_i32 ("pos_x" ,pos_x ); 5189set_input_i32 ("pos_y" ,pos_y ); 5190 }break ; 5191case PROJECTOR_TYPE_DEEPSEEKOCR : 5192case PROJECTOR_TYPE_DEEPSEEKOCR2 : 5193 { 5194GGML_ASSERT ( 5195 (pos_w == pos_h )// overview image 5196|| (pos_h >=pos_w && pos_h %pos_w == 0 )// tile images 5197 ); 5198 5199const int window = hparams .attn_window_size ; 5200const int pos = pos_w ; 5201 std::vector < int32_t > rel_pos_indices_local (window * window ); 5202 std::vector < int32_t > rel_pos_indices_global (pos * pos ); 5203 5204for (int q = 0 ;q < window ;q ++ ) { 5205for (int k = 0 ;k < window ;k ++ ) { 5206rel_pos_indices_local [q * window + k ]= q - k + window - 1 ; 5207 } 5208 } 5209 5210for (int q = 0 ;q < pos ;q ++ ) { 5211for (int k = 0 ;k < pos ;k ++ ) { 5212rel_pos_indices_global [q * pos + k ]= q - k + pos - 1 ; 5213 } 5214 } 5215 5216set_input_i32 ("rel_pos_indices_local" ,rel_pos_indices_local ); 5217set_input_i32 ("rel_pos_indices_global" ,rel_pos_indices_global ); 5218 5219if (ctx -> proj_type ()== PROJECTOR_TYPE_DEEPSEEKOCR2 ) { 5220 5221// qwen2 encoder attention mask 5222 5223// num_image_tokens = num_patches / 16 5224// 256 for 1024 global view 5225// 144 for 768 tile views 5226const int num_image_tokens = num_patches /16 ; 5227const int seq_len = num_image_tokens * 2 ; 5228 std::vector qwen2_mask (static_cast < size_t > (seq_len )* seq_len ,0.0f ); 5229 5230// attention mask layout 5231// +--------------+---------------+ 5232// | all 0 | all -inf | 5233// +--------------+---------------+ 5234// | all 0 | lower tri 0 | 5235// +--------------+---------------+ 5236for (int i = 0 ;i < seq_len ;i ++ ) { 5237for (int j = 0 ;j < seq_len ;j ++ ) { 5238const bool zero = i < num_image_tokens ? 5239j < num_image_tokens : 5240j < num_image_tokens || j <=i ; 5241qwen2_mask [static_cast < size_t > (i )* seq_len + j ]= zero ?0.0f :-1e9f ; 5242 } 5243 } 5244set_input_f32 ("qwen2_attn_mask" ,qwen2_mask ); 5245 } 5246 }break ; 5247case PROJECTOR_TYPE_GEMMA3 : 5248case PROJECTOR_TYPE_GEMMA3NV : 5249case PROJECTOR_TYPE_IDEFICS3 : 5250case PROJECTOR_TYPE_INTERNVL : 5251case PROJECTOR_TYPE_NEMOTRON_V2_VL : 5252case PROJECTOR_TYPE_QWEN2A : 5253case PROJECTOR_TYPE_QWEN3A : 5254case PROJECTOR_TYPE_GLMA : 5255case PROJECTOR_TYPE_ULTRAVOX : 5256case PROJECTOR_TYPE_LFM2 : 5257case PROJECTOR_TYPE_VOXTRAL : 5258case PROJECTOR_TYPE_MERALION : 5259case PROJECTOR_TYPE_MUSIC_FLAMINGO : 5260case PROJECTOR_TYPE_JANUS_PRO : 5261case PROJECTOR_TYPE_PHI4 : 5262case PROJECTOR_TYPE_COGVLM : 5263case PROJECTOR_TYPE_YASA2 : 5264case PROJECTOR_TYPE_GEMMA4UA : 5265case PROJECTOR_TYPE_QWEN3TTS_SPKENC : 5266 { 5267// do nothing 5268 }break ; 5269case PROJECTOR_TYPE_QWEN3TTS_GEN : 5270 { 5271if (params -> gen_process == CLIP_GEN_PROCESS_GEN_WAV ) { 5272GGML_ASSERT (params -> codes != nullptr ); 5273 5274// frame-major input to group-major, rear-padded with code 0 up to one window 5275const int64_t n_codes = model .gen_code_head_w -> ne [2 ]+ 1 ; 5276const int64_t n_frames_w = hparams .wav_tfm_swa ; 5277const int64_t n_frames = (int64_t )params -> codes -> size () /n_codes ; 5278GGML_ASSERT (n_frames > 0 && n_frames <=n_frames_w ); 5279 5280// codes are used as ggml_get_rows indices, so check them against the codebook vocab 5281const int64_t vocab_first = model .c2w .quant_first_cb_w -> ne [1 ]; 5282const int64_t vocab_rest = model .c2w .quant_rest_cb_w -> ne [1 ]; 5283for (int64_t f = 0 ;f < n_frames ;f ++ ) { 5284for (int64_t g = 0 ;g < n_codes ;g ++ ) { 5285const int32_t c = (* params -> codes )[f * n_codes + g ]; 5286const int64_t vocab = (g == 0 ) ?vocab_first :vocab_rest ; 5287if (c < 0 || (int64_t )c >=vocab ) { 5288LOG_ERR ("%s: code out of range (frame %lld, group %lld, code %d, vocab %lld)\n" , 5289__func__ , (long long )f , (long long )g ,c , (long long )vocab ); 5290return false; 5291 } 5292 } 5293 } 5294 5295 std::vector < int32_t > codes (n_frames_w * n_codes ,0 ); 5296for (int64_t f = 0 ;f < n_frames ;f ++ ) { 5297for (int64_t g = 0 ;g < n_codes ;g ++ ) { 5298codes [g * n_frames_w + f ]= (* params -> codes )[f * n_codes + g ]; 5299 } 5300 } 5301set_input_i32 ("inp_codes" ,codes ); 5302set_gen_state_in (); 5303 }else { 5304// code0 indexes gen_code_out_embd_w via ggml_get_rows; bound it 5305const int64_t vocab0 = model .gen_code_out_embd_w -> ne [1 ]; 5306if (params -> code0 < 0 || (int64_t )params -> code0 >=vocab0 ) { 5307LOG_ERR ("%s: code0 out of range (%d, vocab %lld)\n" ,__func__ ,params -> code0 , (long long )vocab0 ); 5308return false; 5309 } 5310 std::vector < int32_t > code0 = {params -> code0 }; 5311set_input_i32 ("inp_code0" ,code0 ); 5312 5313// one uniform(0,1) draw per codebook, used by do_sampling() 5314 std::uniform_real_distribution < float > dist (0.0f ,1.0f ); 5315const int64_t n_acoustic = model .gen_code_head_w -> ne [2 ]; 5316for (int64_t g = 0 ;g < n_acoustic ;g ++ ) { 5317 std::vector < float > r = {dist (ctx -> rng ) }; 5318set_input_f32 (("inp_rand_" + std::to_string (g )).c_str (),r ); 5319 } 5320 } 5321 }break ; 5322case PROJECTOR_TYPE_HUNYUANVL : 5323 { 5324// Compute the HunyuanVL 2D position embedding on CPU (with the 5325// custom sf=(target+0.1)/n_grid bilinear sampling that the 5326// reference implementation uses) and upload it to the graph 5327// input declared in clip_graph_hunyuanvl::build(). 5328GGML_ASSERT (model .position_embeddings != nullptr ); 5329ggml_tensor * src_t = model .position_embeddings ; 5330const int64_t n_embd = src_t -> ne [0 ]; 5331const int64_t n_pos = src_t -> ne [1 ];// = n_grid * n_grid 5332const int n_grid = (int )std::lround (std::sqrt ((double )n_pos )); 5333GGML_ASSERT ((int64_t )n_grid * n_grid == n_pos ); 5334const int out_w = pos_w ;// pw 5335const int out_h = pos_h ;// ph 5336 5337// Pull weight to host. 5338 std::vector < float > src (n_embd * n_pos ); 5339ggml_backend_tensor_get (src_t ,src .data (),0 ,ggml_nbytes (src_t )); 5340 5341// Output layout matches ggml_new_tensor_2d(F32, n_embd, out_h*out_w): 5342// ne[0] = n_embd (fastest), ne[1] = out_h*out_w 5343// dst[(y*out_w + x) * n_embd + c] 5344 std::vector < float > dst ((size_t )n_embd * out_h * out_w ); 5345 5346const float sx = (float )(out_w + 0.1f ) / (float )n_grid ; 5347const float sy = (float )(out_h + 0.1f ) / (float )n_grid ; 5348 5349for (int y = 0 ;y < out_h ;++ y ) { 5350// Match ggml_compute_forward_upscale_f32 pixel-center 5351// convention (align_corners=False): src_y = (y+0.5)/sy - 0.5. 5352const float fy = ((float )y + 0.5f ) /sy - 0.5f ; 5353int y0 = (int )std::floor (fy ); 5354int y1 = y0 + 1 ; 5355y0 = std::clamp (y0 ,0 ,n_grid - 1 ); 5356y1 = std::clamp (y1 ,0 ,n_grid - 1 ); 5357float wy1 = std::clamp (fy - (float )y0 ,0.0f ,1.0f ); 5358const float wy0 = 1.0f - wy1 ; 5359for (int x = 0 ;x < out_w ;++ x ) { 5360const float fx = ((float )x + 0.5f ) /sx - 0.5f ; 5361int x0 = (int )std::floor (fx ); 5362int x1 = x0 + 1 ; 5363x0 = std::clamp (x0 ,0 ,n_grid - 1 ); 5364x1 = std::clamp (x1 ,0 ,n_grid - 1 ); 5365float wx1 = std::clamp (fx - (float )x0 ,0.0f ,1.0f ); 5366const float wx0 = 1.0f - wx1 ; 5367 5368const float w00 = wy0 * wx0 ; 5369const float w01 = wy0 * wx1 ; 5370const float w10 = wy1 * wx0 ; 5371const float w11 = wy1 * wx1 ; 5372 5373const float * s00 = & src [((size_t )y0 * n_grid + x0 )* n_embd ]; 5374const float * s01 = & src [((size_t )y0 * n_grid + x1 )* n_embd ]; 5375const float * s10 = & src [((size_t )y1 * n_grid + x0 )* n_embd ]; 5376const float * s11 = & src [((size_t )y1 * n_grid + x1 )* n_embd ]; 5377float * d = & dst [((size_t )y * out_w + x )* n_embd ]; 5378for (int c = 0 ;c < n_embd ;++ c ) { 5379d [c ]= w00 * s00 [c ]+ w01 * s01 [c ]+ w10 * s10 [c ]+ w11 * s11 [c ]; 5380 } 5381 } 5382 } 5383 5384set_input_f32 ("hunyuanvl_pos_embd" ,dst ); 5385 }break ; 5386case PROJECTOR_TYPE_LLAMA4 : 5387 { 5388// set the 2D positions 5389int n_patches_per_col = image_size_width /patch_size ; 5390 std::vector < int > pos_data (num_patches + 1 ,0 );// +1 for the [CLS] token 5391// last pos is always kept 0, it's for CLS 5392// dimension H 5393for (int i = 0 ;i < num_patches ;i ++ ) { 5394pos_data [i ]= (i /n_patches_per_col )+ 1 ; 5395 } 5396set_input_i32 ("pos_h" ,pos_data ); 5397// dimension W 5398for (int i = 0 ;i < num_patches ;i ++ ) { 5399pos_data [i ]= (i %n_patches_per_col )+ 1 ; 5400 } 5401set_input_i32 ("pos_w" ,pos_data ); 5402 }break ; 5403case PROJECTOR_TYPE_DOTS3NOTE_A : 5404 { 5405GGML_ASSERT (imgs .entries .size ()== 1 ); 5406const int n_pos = (imgs .entries .front ().nx ()+ 7 ) /8 ;// 3x stride-2 conv2d 5407 std::vector < int32_t > positions (n_pos ); 5408for (int i = 0 ;i < n_pos ;i ++ ) { 5409positions [i ]= i ; 5410 } 5411set_input_i32 ("positions" ,positions ); 5412 }break ; 5413case PROJECTOR_TYPE_GEMMA4A : 5414 { 5415GGML_ASSERT (imgs .entries .size ()== 1 ); 5416const auto & img0 = imgs .entries .front (); 5417// Compute n_pos matching SSCP output: two stride-2 convs 5418int n_pos = img0 .nx (); 5419for (int i = 0 ;i < 2 ;i ++ ) {n_pos = (n_pos - 1 ) /2 + 1 ; } 5420 5421// Chunked local attention: blocked causal mask and RPE 5422const int chunk_size = 12 ; 5423const int max_past = 12 ; 5424const int context_size = chunk_size + max_past ; 5425const int num_blocks = (n_pos + chunk_size - 1 ) /chunk_size ; 5426 5427// Blocked causal attention mask: [context_size, chunk_size, num_blocks] 5428 { 5429 std::vector < float > mask (context_size * chunk_size * num_blocks ,-1e9f ); 5430for (int b = 0 ;b < num_blocks ;b ++ ) { 5431for (int q = 0 ;q < chunk_size ;q ++ ) { 5432int gq = b * chunk_size + q ; 5433for (int k = 0 ;k < context_size ;k ++ ) { 5434int gk = b * chunk_size - max_past + k ; 5435if (gq < n_pos && gk >=0 && gk < n_pos && gk <=gq && (gq - gk )< max_past ) { 5436mask [k + q * context_size + b * context_size * chunk_size ]= 0.0f ; 5437 } 5438 } 5439 } 5440 } 5441set_input_f32 ("kq_mask" ,mask ); 5442 } 5443 5444// Sinusoidal RPE: 13 positions [12, 11, ..., 0] 5445 { 5446const int n_embd = ctx -> model .hparams .n_embd ; 5447const int num_timescales = n_embd /2 ; 5448const float log_timescale_increment = logf (10000.0f ) / std::max (num_timescales - 1 ,1 ); 5449const int rpe_len = max_past + 1 ; 5450 std::vector < float > pos_emb (n_embd * rpe_len ,0.0f ); 5451for (int p = 0 ;p < rpe_len ;p ++ ) { 5452float position = (float )(max_past - p ); 5453for (int i = 0 ;i < num_timescales ;i ++ ) { 5454float inv_ts = expf (- (float )i * log_timescale_increment ); 5455float scaled = position * inv_ts ; 5456pos_emb [p * n_embd + i ]= sinf (scaled ); 5457pos_emb [p * n_embd + i + num_timescales ]= cosf (scaled ); 5458 } 5459 } 5460set_input_f32 ("pos_emb" ,pos_emb ); 5461 } 5462 }break ; 5463case PROJECTOR_TYPE_MIMO_AUDIO : 5464 { 5465GGML_ASSERT (imgs .entries .size ()== 1 ); 5466const int n_frames = imgs .entries .front ().nx (); 5467const int n_pos = (n_frames - 1 ) /2 + 1 ;// matches conv1(s=1)+conv2(s=2) output length 5468 5469 std::vector < int32_t > positions (n_pos ); 5470for (int i = 0 ;i < n_pos ;i ++ ) { 5471positions [i ]= i ; 5472 } 5473set_input_i32 ("mimo_audio_positions" ,positions ); 5474 5475const int window = hparams .attn_window_size ; 5476GGML_ASSERT (window > 0 ); 5477 5478const float neg_inf = std::numeric_limits < float > ::lowest (); 5479 std::vector < float > full_mask ((size_t )n_pos * n_pos ); 5480 std::vector < float > window_mask ((size_t )n_pos * n_pos ); 5481for (int q = 0 ;q < n_pos ;q ++ ) { 5482for (int k = 0 ;k < n_pos ;k ++ ) { 5483const bool causal_ok = k <=q ; 5484full_mask [(size_t )q * n_pos + k ]= causal_ok ?0.0f :neg_inf ; 5485window_mask [(size_t )q * n_pos + k ]= (causal_ok && (q - k ) <=window ) ?0.0f :neg_inf ; 5486 } 5487 } 5488set_input_f32 ("mimo_audio_full_mask" ,full_mask ); 5489set_input_f32 ("mimo_audio_window_mask" ,window_mask ); 5490 5491// input_local_transformer: block-diagonal mask + in-group positions 5492 { 5493const int n_pos_ds = (n_pos - 2 ) /2 + 1 ;// matches downsample conv (k=2,s=2,p=0) 5494const int group_size = hparams .audio_local_group_size ; 5495GGML_ASSERT (group_size > 0 ); 5496const int n_groups = (n_pos_ds + group_size - 1 ) /group_size ; 5497const int n_padded = n_groups * group_size ; 5498 5499 std::vector < int32_t > local_positions (n_padded ); 5500for (int i = 0 ;i < n_padded ;i ++ ) { 5501local_positions [i ]= i %group_size ; 5502 } 5503set_input_i32 ("mimo_audio_local_positions" ,local_positions ); 5504 5505 std::vector < float > local_mask ((size_t )n_padded * n_padded ); 5506for (int q = 0 ;q < n_padded ;q ++ ) { 5507for (int k = 0 ;k < n_padded ;k ++ ) { 5508const bool same_group = (q /group_size )== (k /group_size ); 5509local_mask [(size_t )q * n_padded + k ]= same_group ?0.0f :neg_inf ; 5510 } 5511 } 5512set_input_f32 ("mimo_audio_local_mask" ,local_mask ); 5513 } 5514 }break ; 5515case PROJECTOR_TYPE_LFM2A : 5516 { 5517GGML_ASSERT (imgs .entries .size ()== 1 ); 5518const auto n_frames = clip_n_output_tokens (ctx ,& imgs .entries .front ()); 5519 5520auto d_model = 512 ; 5521auto seq_len = n_frames * 2 - 1 ; 5522 std::vector < float > pos_emb (d_model * seq_len ); 5523 std::vector < double > inv_freq (d_model /2 ); 5524for (size_t i = 0 ;i < inv_freq .size ();++ i ) { 5525inv_freq [i ]= std::exp (- (std::log (10000.0 ) / (float )d_model )* (2.0f * (float )(i ))); 5526 } 5527for (int64_t pos = 0 ;pos < seq_len ;++ pos ) { 5528for (size_t i = 0 ;i < inv_freq .size ();++ i ) { 5529const float ang = (n_frames - pos - 1 )* inv_freq [i ]; 5530pos_emb [pos * d_model + 2 * i + 0 ]= sinf (ang );// even 5531pos_emb [pos * d_model + 2 * i + 1 ]= cosf (ang );// odd 5532 } 5533 } 5534set_input_f32 ("pos_emb" ,pos_emb ); 5535 }break ; 5536case PROJECTOR_TYPE_PARAKEET : 5537 { 5538GGML_ASSERT (imgs .entries .size ()== 1 ); 5539struct ggml_tensor * attn_mask = ggml_graph_get_tensor (gf ,"attn_mask" ); 5540const int n_q = attn_mask -> ne [1 ]; 5541const int n_k = attn_mask -> ne [0 ]; 5542const int n_frames = imgs .entries .front ().nx (); 5543const int n_tokens_real = (n_frames + hparams .subsampling_factor - 1 ) /hparams .subsampling_factor ; 5544const float mask_value = -1e30f ; 5545 5546 std::vector < float > mask_data (n_q * n_k ); 5547if (n_k == n_q ) { 5548// full attention: mask keys that are padding 5549for (int q = 0 ;q < n_q ;++ q ) { 5550for (int k = 0 ;k < n_k ;++ k ) { 5551mask_data [q * n_k + k ]= (k >=n_tokens_real ) ?mask_value :0.0f ; 5552 } 5553 } 5554 }else { 5555// local attention: mask keys outside the valid window 5556const int att_left = n_k /2 ; 5557for (int q = 0 ;q < n_q ;++ q ) { 5558for (int k = 0 ;k < n_k ;++ k ) { 5559const int key = q - att_left + k ; 5560mask_data [q * n_k + k ]= (key >=0 && key < n_tokens_real ) ?0.0f :mask_value ; 5561 } 5562 } 5563 } 5564set_input_f32 (attn_mask -> name ,mask_data ); 5565 5566// local attention skew mask: zeroes out the probs that were 5567// computed for keys outside the valid sliding window. 5568if (struct ggml_tensor * local_mask = ggml_graph_get_tensor (gf ,"local_mask" )) { 5569const int lm_k = local_mask -> ne [0 ]; 5570const int lm_q = local_mask -> ne [1 ]; 5571const int window_size = lm_k - lm_q + 1 ; 5572 std::vector < float > lm_data (lm_q * lm_k ); 5573for (int q = 0 ;q < lm_q ;++ q ) { 5574for (int k = 0 ;k < lm_k ;++ k ) { 5575const int rel = k - q ; 5576lm_data [q * lm_k + k ]= (rel >=0 && rel < window_size ) ?1.0f :0.0f ; 5577 } 5578 } 5579set_input_f32 (local_mask -> name ,lm_data ); 5580 } 5581 5582// Generate rotation frequencies for relative positional encoding. 5583 { 5584const int n_state = hparams .n_embd ; 5585const int d_half = n_state /2 ; 5586const float log_10000 = logf (10000.0f ); 5587 std::vector < float > freqs (d_half ); 5588for (int k = 0 ;k < d_half ;++ k ) { 5589freqs [k ]= expf (- (float (k * 2 )* log_10000 /float (n_state ))); 5590 } 5591set_input_f32 ("pos_freqs" ,freqs ); 5592 } 5593 5594// Generate relative positional distance values which scaled by 5595// the frequency to produce the angles for sin/cos. 5596 { 5597// window_size is only known after graph construction since it depends on 5598// n_time from the conv output, so we read it back from the graph tensor. 5599struct ggml_tensor * rel_pos = ggml_graph_get_tensor (gf ,"rel_positions" ); 5600const int window_size = rel_pos -> ne [1 ]; 5601 std::vector < float > pos (window_size ); 5602// local attention: window is fixed at [att_left, att_right] 5603// full attention: window covers the full sequence, centered 5604if (ggml_graph_get_tensor (gf ,"local_mask" )) { 5605const int att_left = window_size /2 ; 5606for (int t = 0 ;t < window_size ;++ t ) { 5607pos [t ]= float (att_left - t ); 5608 } 5609 }else { 5610const int n_time = (window_size + 1 ) /2 ; 5611for (int t = 0 ;t < window_size ;++ t ) { 5612pos [t ]= float (n_time - 1 - t ); 5613 } 5614 } 5615set_input_f32 (rel_pos -> name ,pos ); 5616 } 5617 }break ; 5618case PROJECTOR_TYPE_GRANITE_SPEECH : 5619 { 5620const int context_size = ctx -> model .hparams .audio_chunk_size ; 5621const int max_pos_emb = ctx -> model .hparams .audio_max_pos_emb ; 5622 5623 std::vector < int32_t > dists ((size_t )context_size * (size_t )context_size ); 5624for (int i = 0 ;i < context_size ;i ++ ) { 5625for (int j = 0 ;j < context_size ;j ++ ) { 5626int d = i - j ; 5627if (d < - context_size )d = - context_size ; 5628if (d > context_size )d = context_size ; 5629dists [(size_t )i * (size_t )context_size + (size_t )j ]= d + max_pos_emb ; 5630 } 5631 } 5632set_input_i32 ("attn_dists" ,dists ); 5633 5634const int n_frames = image_size_width ; 5635const int remainder = n_frames %context_size ; 5636if (remainder > 0 ) { 5637const int num_blocks = (n_frames + context_size - 1 ) /context_size ; 5638 std::vector < float > mask ((size_t )context_size * (size_t )context_size * (size_t )num_blocks ,0.0f ); 5639const float neg_inf = - INFINITY ; 5640const size_t last_block_offset = (size_t ) (num_blocks - 1 )* (size_t )context_size * (size_t )context_size ; 5641for (int q = 0 ;q < context_size ;q ++ ) { 5642for (int k = 0 ;k < context_size ;k ++ ) { 5643if (q >=remainder || k >=remainder ) { 5644mask [last_block_offset + (size_t )q * (size_t )context_size + (size_t )k ]= neg_inf ; 5645 } 5646 } 5647 } 5648set_input_f32 ("attn_mask" ,mask ); 5649 } 5650 }break ; 5651case PROJECTOR_TYPE_GRANITE4_VISION : 5652 { 5653// Granite Vision 4.1 uses precomputed permutation index 5654// tensors to express the _win / _unwin / spatial sampling 5655// reshapes as ggml_get_rows gathers. The names are set 5656// by g4v_gather() in models/granite4-vision.cpp. 5657const int patch_size = model .hparams .patch_size ; 5658const int image_side = imgs .entries .front ().nx () /patch_size ; 5659const int window_side = hparams .downsample_window_side ; 5660const int query_side = hparams .downsample_query_side ; 5661const int n = image_side /window_side ; 5662const int new_side = n * query_side ; 5663 5664// Builds the raster→window permutation indices for a 5665// (side, side) grid split into (n × n) windows of (win × win) 5666// tokens each. dst[w * win*win + p] = source raster index. 5667auto make_win_idx = [](int side ,int win ) { 5668const int nn = side /win ; 5669 std::vector < int32_t > idx (static_cast < size_t > (side )* side ); 5670for (int wy = 0 ;wy < nn ;++ wy ) { 5671for (int wx = 0 ;wx < nn ;++ wx ) { 5672for (int iy = 0 ;iy < win ;++ iy ) { 5673for (int ix = 0 ;ix < win ;++ ix ) { 5674const int w = wy * nn + wx ; 5675const int p = iy * win + ix ; 5676const int y = wy * win + iy ; 5677const int x = wx * win + ix ; 5678idx [static_cast < size_t > (w )* (win * win )+ p ]= y * side + x ; 5679 } 5680 } 5681 } 5682 } 5683return idx ; 5684 }; 5685 5686auto make_unwin_idx = [& ](int side ,int win ) { 5687const std::vector < int32_t > fwd = make_win_idx (side ,win ); 5688 std::vector < int32_t > inv (fwd .size ()); 5689for (size_t i = 0 ;i < fwd .size ();++ i ) { 5690inv [fwd [i ]]= static_cast < int32_t > (i ); 5691 } 5692return inv ; 5693 }; 5694 5695auto make_spatial_idx = [](int side ,int offset ) { 5696const int off_y = (offset >>1 )& 1 ; 5697const int off_x = offset & 1 ; 5698const int new_s = side /2 ; 5699 std::vector < int32_t > idx (static_cast < size_t > (new_s )* new_s ); 5700for (int y = 0 ;y < new_s ;++ y ) { 5701for (int x = 0 ;x < new_s ;++ x ) { 5702idx [y * new_s + x ]= (y * 2 + off_y )* side + (x * 2 + off_x ); 5703 } 5704 } 5705return idx ; 5706 }; 5707 5708// the same permutation is applied to every tile of the stacked image 5709auto upload = [& ](const std::string & name ,const std::vector < int32_t > & idx ) { 5710ggml_tensor * t = ggml_graph_get_tensor (gf ,name .c_str ()); 5711GGML_ASSERT (t ); 5712GGML_ASSERT (ggml_nelements (t ) % (int64_t )idx .size ()== 0 ); 5713const int n_rep = ggml_nelements (t ) /idx .size (); 5714 std::vector < int32_t > buf ; 5715buf .reserve (idx .size ()* n_rep ); 5716for (int i = 0 ;i < n_rep ;++ i ) { 5717buf .insert (buf .end (),idx .begin (),idx .end ()); 5718 } 5719ggml_backend_tensor_set (t ,buf .data (),0 ,ggml_nbytes (t )); 5720 }; 5721 5722// Stage 1b only uses block 0's permutations; future stages 5723// will upload all blocks. 5724for (size_t bid = 0 ;bid < hparams .feature_layers .size ();++ bid ) { 5725const std::string prefix = "g4v_blk" + std::to_string (bid )+ "_" ; 5726upload (prefix + "win_idx" ,make_win_idx (image_side ,window_side )); 5727upload (prefix + "qwin_idx" ,make_win_idx (new_side ,query_side )); 5728upload (prefix + "unwin_idx" ,make_unwin_idx (new_side ,query_side )); 5729const auto spatial_offset = hparams .proj_spatial_offsets [bid ]; 5730if (spatial_offset >=0 ) { 5731upload (prefix + "spatial_idx" ,make_spatial_idx (image_side ,spatial_offset )); 5732 } 5733 } 5734 }break ; 5735default : 5736GGML_ABORT ("Unknown projector type" ); 5737 } 5738 5739// ggml_backend_cpu_set_n_threads(ctx->backend_cpu, n_threads); 5740ggml_backend_dev_t dev = ggml_backend_get_device (ctx -> backend_cpu ); 5741ggml_backend_reg_t reg = dev ?ggml_backend_dev_backend_reg (dev ) :nullptr ; 5742if (reg ) { 5743auto ggml_backend_set_n_threads_fn = (ggml_backend_set_n_threads_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_set_n_threads" ); 5744if (ggml_backend_set_n_threads_fn ) { 5745ggml_backend_set_n_threads_fn (ctx -> backend_cpu ,params -> n_threads ); 5746 } 5747 } 5748 5749auto status = ggml_backend_sched_graph_compute (ctx -> sched .get (),gf ); 5750if (status != GGML_STATUS_SUCCESS ) { 5751LOG_ERR ("%s: ggml_backend_sched_graph_compute failed with error %d\n" ,__func__ ,status ); 5752return false; 5753 } 5754 5755// the last node is the embedding tensor, code2wav has no out_embd 5756ggml_tensor * embeddings = params -> out_embd ?ggml_graph_node (gf ,-1 ) :nullptr ; 5757 5758if (embeddings != nullptr ) { 5759// sanity check (assuming that all images in batch have the same number of tokens, so we only check the first one) 5760const int n_tokens_out = embeddings -> ne [1 ]; 5761const int expected_n_tokens_out = clip_n_output_tokens (ctx ,& imgs .entries [0 ]); 5762if (n_tokens_out != expected_n_tokens_out ) { 5763LOG_ERR ("%s: expected output %d tokens, got %d\n" ,__func__ ,expected_n_tokens_out ,n_tokens_out ); 5764GGML_ABORT ("Invalid number of output tokens" ); 5765 } 5766 5767LOG_DBG ("%s: output embedding shape [%d, %d, %d]\n" ,__func__ , 5768 (int )embeddings -> ne [0 ], (int )embeddings -> ne [1 ], (int )embeddings -> ne [2 ]); 5769 5770// copy output to user buffer if provided 5771// if output is empty, skip the copy 5772auto & out_batch_embd = * params -> out_embd ; 5773if (!out_batch_embd .empty ()) { 5774if (out_batch_embd .size ()!= (size_t )ggml_nelements (embeddings )) { 5775LOG_ERR ("%s: output buffer has %zu elements but expected %zu\n" ,__func__ ,out_batch_embd .size (), (size_t )ggml_nelements (embeddings )); 5776GGML_ABORT ("Output buffer size mismatch" ); 5777 } 5778ggml_backend_tensor_get (embeddings ,out_batch_embd .data (),0 ,ggml_nbytes (embeddings )); 5779 }else { 5780LOG_WRN ("%s: output buffer is empty, skipping copy\n" ,__func__ ); 5781 } 5782 } 5783 5784// 5785// for audio gen models 5786// 5787 5788// optional outputs: a pipeline yields codes or feats, and not all have an eos head 5789if (params -> out_codes != nullptr ) { 5790ggml_tensor * codes = ggml_graph_get_tensor (gf ,"out_codes" ); 5791if (codes != nullptr ) { 5792auto & out_codes = * params -> out_codes ; 5793out_codes .resize (ggml_nelements (codes )); 5794ggml_backend_tensor_get (codes ,out_codes .data (),0 ,ggml_nbytes (codes )); 5795 } 5796 } 5797if (params -> out_feats != nullptr ) { 5798ggml_tensor * feats = ggml_graph_get_tensor (gf ,"out_feats" ); 5799if (feats != nullptr ) { 5800auto & out_feats = * params -> out_feats ; 5801out_feats .resize (ggml_nelements (feats )); 5802ggml_backend_tensor_get (feats ,out_feats .data (),0 ,ggml_nbytes (feats )); 5803 } 5804 } 5805if (params -> out_is_eos != nullptr ) { 5806ggml_tensor * eos = ggml_graph_get_tensor (gf ,"out_eos_score" ); 5807if (eos != nullptr ) { 5808GGML_ASSERT (ggml_nelements (eos )== 1 ); 5809float score = 0.0f ; 5810ggml_backend_tensor_get (eos ,& score ,0 ,sizeof (float )); 5811* params -> out_is_eos = score > hparams .gen_eos_threshold ; 5812 } 5813 } 5814if (params -> out_audio != nullptr ) { 5815ggml_tensor * audio = ggml_graph_get_tensor (gf ,"out_audio" ); 5816if (audio == nullptr ) { 5817GGML_ABORT ("out_audio requested but graph has no \"out_audio\" tensor" ); 5818 } 5819auto & out_audio = * params -> out_audio ; 5820out_audio .resize (ggml_nelements (audio )); 5821ggml_backend_tensor_get (audio ,out_audio .data (),0 ,ggml_nbytes (audio )); 5822 5823// drop the tail audio that comes from the code-0 rear padding 5824const int64_t n_codes = params -> codes ?model .gen_code_head_w -> ne [2 ]+ 1 :0 ; 5825const int64_t n_frames_w = hparams .wav_tfm_swa ; 5826const int64_t n_frames = params -> codes ? (int64_t )params -> codes -> size () /n_codes :n_frames_w ; 5827if (n_frames < n_frames_w ) { 5828const size_t hop = out_audio .size () /n_frames_w ; 5829out_audio .resize ((size_t )n_frames * hop ); 5830 } 5831 } 5832if (params -> state_out != nullptr ) { 5833auto & state_out = * params -> state_out ; 5834size_t total = 0 ; 5835for (const auto & slot :list_gen_state_slots (hparams ,model )) { 5836total += (size_t ) (slot .ne0 * slot .ne1 )* sizeof (float ); 5837 } 5838state_out .resize (total ); 5839size_t offset = 0 ; 5840for (const auto & slot :list_gen_state_slots (hparams ,model )) { 5841ggml_tensor * t = ggml_graph_get_tensor (gf , ("state_out_" + slot .name ).c_str ()); 5842if (t == nullptr ) { 5843GGML_ABORT ("state_out requested but graph has no \"state_out_%s\" tensor" ,slot .name .c_str ()); 5844 } 5845const size_t nb = ggml_nbytes (t ); 5846ggml_backend_tensor_get (t ,state_out .data ()+ offset ,0 ,nb ); 5847offset += nb ; 5848 } 5849 } 5850 5851// 5852// Debug: dump final embeddings if MTMD_DEBUG_EMBEDDINGS is set 5853// 5854 5855if (ctx -> debug_output_embeddings && embeddings != nullptr ) { 5856const int64_t n_embd = embeddings -> ne [0 ]; 5857const int64_t n_tokens = embeddings -> ne [1 ]; 5858 std::vector < float > emb_data (ggml_nelements (embeddings )); 5859ggml_backend_tensor_get (embeddings ,emb_data .data (),0 ,ggml_nbytes (embeddings )); 5860 5861LOG_INF ("\n=== MTMD_DEBUG_EMBEDDINGS ===\n" ); 5862LOG_INF ("Shape: [%lld, %lld]\n" , (long long )n_embd , (long long )n_tokens ); 5863 5864// TEMP debugging (parity validation), will be removed before merge 5865// when the env var holds a path, dump the raw data: [int32 n_tokens][int32 n_embd][f32 data] 5866const char * dump_path = std::getenv ("MTMD_DEBUG_EMBEDDINGS" ); 5867if (dump_path && strcmp (dump_path ,"1" )!= 0 ) { 5868FILE * f = fopen (dump_path ,"wb" ); 5869if (f ) { 5870const int32_t hdr [2 ]= { (int32_t )n_tokens , (int32_t )n_embd }; 5871fwrite (hdr ,sizeof (hdr ),1 ,f ); 5872fwrite (emb_data .data (),sizeof (float ),emb_data .size (),f ); 5873fclose (f ); 5874 } 5875 } 5876 5877// Print first few values of first token 5878LOG_INF ("Token 0 (first 16 values): " ); 5879for (int i = 0 ;i < std::min ((int64_t )16 ,n_embd );i ++ ) { 5880LOG_INF ("%.6f " ,emb_data [i ]); 5881 } 5882LOG_INF ("\n" ); 5883 5884// Print last few values of first token 5885if (n_embd > 16 ) { 5886LOG_INF ("Token 0 (last 16 values): " ); 5887for (int64_t i = n_embd - 16 ;i < n_embd ;i ++ ) { 5888LOG_INF ("%.6f " ,emb_data [i ]); 5889 } 5890LOG_INF ("\n" ); 5891 } 5892 5893// Compute and print statistics 5894float sum = 0.0f ,sum_sq = 0.0f ,min_val = emb_data [0 ],max_val = emb_data [0 ]; 5895for (size_t i = 0 ;i < emb_data .size ();i ++ ) { 5896sum += emb_data [i ]; 5897sum_sq += emb_data [i ]* emb_data [i ]; 5898min_val = std::min (min_val ,emb_data [i ]); 5899max_val = std::max (max_val ,emb_data [i ]); 5900 } 5901float mean = sum /emb_data .size (); 5902float variance = (sum_sq /emb_data .size ())- (mean * mean ); 5903LOG_INF ("Stats: mean=%.6f, std=%.6f, min=%.6f, max=%.6f, sum=%.6f\n" , 5904mean ,sqrtf (variance ),min_val ,max_val ,sum ); 5905LOG_INF ("=== END MTMD_DEBUG_EMBEDDINGS ===\n\n" ); 5906 } 5907 5908return true; 5909} 5910 5911int clip_n_mmproj_embd (const struct clip_ctx * ctx ) { 5912switch (ctx -> model .proj_type ) { 5913case PROJECTOR_TYPE_LDP : 5914return ctx -> model .mm_model_block_1_block_2_1_b -> ne [0 ]; 5915case PROJECTOR_TYPE_LDPV2 : 5916return ctx -> model .mm_model_peg_0_b -> ne [0 ]; 5917case PROJECTOR_TYPE_MLP : 5918case PROJECTOR_TYPE_PHI4 : 5919case PROJECTOR_TYPE_PIXTRAL : 5920case PROJECTOR_TYPE_LIGHTONOCR : 5921case PROJECTOR_TYPE_DOTS_OCR : 5922case PROJECTOR_TYPE_DOTS3NOTE_V : 5923case PROJECTOR_TYPE_DOTS3NOTE_A : 5924return ctx -> model .mm_2_w -> ne [1 ]; 5925case PROJECTOR_TYPE_MLP_NORM : 5926return ctx -> model .mm_3_b -> ne [0 ]; 5927case PROJECTOR_TYPE_MINICPMV : 5928return ctx -> model .mm_model_proj -> ne [0 ]; 5929case PROJECTOR_TYPE_MINICPMV4_6 : 5930return ctx -> model .mm_ffn_down_w -> ne [1 ]; 5931case PROJECTOR_TYPE_GLM_EDGE : 5932return ctx -> model .mm_model_mlp_3_w -> ne [1 ]; 5933case PROJECTOR_TYPE_MINIMAX_M3 : 5934return ctx -> model .mm_merger_fc2_b -> ne [0 ]; 5935case PROJECTOR_TYPE_MUSE_GLIMMER : 5936return ctx -> model .mm_2_w -> ne [1 ]; 5937case PROJECTOR_TYPE_QWEN2VL : 5938case PROJECTOR_TYPE_QWEN25VL : 5939case PROJECTOR_TYPE_EXAONE4_5 : 5940case PROJECTOR_TYPE_JANUS_PRO : 5941case PROJECTOR_TYPE_YOUTUVL : 5942return ctx -> model .mm_1_b -> ne [0 ]; 5943case PROJECTOR_TYPE_QWEN3VL : 5944// main path + deepstack paths 5945return ctx -> model .mm_1_b -> ne [0 ]* (1 + ctx -> model .n_deepstack_layers ); 5946case PROJECTOR_TYPE_MIMOVL : 5947return ctx -> model .mm_1_w -> ne [1 ]; 5948case PROJECTOR_TYPE_STEP3VL : 5949return ctx -> model .mm_model_proj -> ne [1 ]; 5950case PROJECTOR_TYPE_GEMMA3 : 5951case PROJECTOR_TYPE_GEMMA3NV : 5952return ctx -> model .mm_input_proj_w -> ne [0 ]; 5953case PROJECTOR_TYPE_GEMMA4V : 5954case PROJECTOR_TYPE_GEMMA4UV : 5955case PROJECTOR_TYPE_GEMMA4A : 5956case PROJECTOR_TYPE_GEMMA4UA : 5957return ctx -> model .mm_input_proj_w -> ne [1 ]; 5958case PROJECTOR_TYPE_IDEFICS3 : 5959return ctx -> model .mm_fc_w -> ne [1 ]; 5960case PROJECTOR_TYPE_ULTRAVOX : 5961case PROJECTOR_TYPE_VOXTRAL : 5962case PROJECTOR_TYPE_MUSIC_FLAMINGO : 5963return ctx -> model .mm_2_w -> ne [1 ]; 5964case PROJECTOR_TYPE_MERALION : 5965return ctx -> model .mm_3_w -> ne [1 ];// out_proj output dim 5966case PROJECTOR_TYPE_INTERNVL : 5967case PROJECTOR_TYPE_NEMOTRON_V2_VL : 5968return ctx -> model .mm_3_w -> ne [1 ]; 5969case PROJECTOR_TYPE_LLAMA4 : 5970return ctx -> model .mm_model_proj -> ne [1 ]; 5971case PROJECTOR_TYPE_QWEN2A : 5972return ctx -> model .mm_fc_w -> ne [1 ]; 5973case PROJECTOR_TYPE_QWEN3A : 5974return ctx -> model .mm_2_w -> ne [1 ]; 5975case PROJECTOR_TYPE_GLMA : 5976case PROJECTOR_TYPE_LFM2 : 5977case PROJECTOR_TYPE_KIMIVL : 5978case PROJECTOR_TYPE_PADDLEOCR : 5979case PROJECTOR_TYPE_KIMIK25 : 5980case PROJECTOR_TYPE_YASA2 : 5981case PROJECTOR_TYPE_DEEPSEEK4V : 5982return ctx -> model .mm_2_w -> ne [1 ]; 5983case PROJECTOR_TYPE_HUNYUANVL : 5984return ctx -> model .mm_model_proj -> ne [1 ]; 5985case PROJECTOR_TYPE_COGVLM : 5986return ctx -> model .mm_4h_to_h_w -> ne [1 ]; 5987case PROJECTOR_TYPE_DEEPSEEKOCR : 5988case PROJECTOR_TYPE_DEEPSEEKOCR2 : 5989return ctx -> model .mm_fc_w -> ne [1 ]; 5990case PROJECTOR_TYPE_LFM2A : 5991return ctx -> model .position_embeddings -> ne [0 ]; 5992case PROJECTOR_TYPE_GRANITE_SPEECH : 5993return ctx -> model .qf_proj_blocks [0 ].qf_proj_linear_w -> ne [1 ]; 5994case PROJECTOR_TYPE_GRANITE4_VISION : 5995return ctx -> model .qf_proj_blocks .size ()* ctx -> model .hparams .projection_dim ; 5996case PROJECTOR_TYPE_GLM4V : 5997return ctx -> model .mm_ffn_down_w -> ne [1 ]; 5998case PROJECTOR_TYPE_MIMO_AUDIO : 5999return ctx -> model .mm_2_w -> ne [1 ]; 6000case PROJECTOR_TYPE_QWEN3TTS_SPKENC : 6001return ctx -> model .mm_fc_w -> ne [2 ]; 6002case PROJECTOR_TYPE_QWEN3TTS_GEN : 6003return ctx -> model .gen_code_out_embd_w -> ne [0 ]; 6004case PROJECTOR_TYPE_POCKETTTS_SPKENC : 6005return ctx -> model .spk_proj_w -> ne [1 ]; 6006case PROJECTOR_TYPE_POCKETTTS_GEN : 6007return ctx -> model .gen_input_lin_w -> ne [1 ]; 6008case PROJECTOR_TYPE_PARAKEET : 6009return ctx -> model .mm_1_w -> ne [1 ]; 6010default : 6011GGML_ABORT ("Unknown projector type" ); 6012 } 6013} 6014 6015bool clip_is_llava (const struct clip_ctx * ctx ) { 6016return ctx -> model .hparams .has_llava_projector ; 6017} 6018 6019bool clip_has_vision_encoder (const struct clip_ctx * ctx ) { 6020return ctx -> model .modality == CLIP_MODALITY_VISION ; 6021} 6022 6023bool clip_has_audio_encoder (const struct clip_ctx * ctx ) { 6024return ctx -> model .modality == CLIP_MODALITY_AUDIO ; 6025} 6026 6027bool clip_support_batch (const struct clip_ctx * ctx ) { 6028return ctx -> support_batch ; 6029} 6030 6031// TODO @ngxson : this is no longer correct with mtmd_batch API 6032// this was only meant to be used by qwen-vl-based models, to fuse 2 input images into one (qwen-vl video support) 6033// this logic should be refactored in near future to distinctly handle "merge frames" and "batching" 6034int clip_model_n_temporal_merge (const struct clip_ctx * ctx ) { 6035switch (ctx -> proj_type ()) { 6036case PROJECTOR_TYPE_QWEN2VL : 6037case PROJECTOR_TYPE_QWEN25VL : 6038case PROJECTOR_TYPE_QWEN3VL : 6039return 2 ; 6040default : 6041return 1 ; 6042 } 6043} 6044 6045// 6046// API used internally with mtmd 6047// 6048 6049projector_type clip_get_projector_type (const struct clip_ctx * ctx ) { 6050return ctx -> proj_type (); 6051} 6052 6053const clip_hparams * clip_get_hparams (const struct clip_ctx * ctx ) { 6054return & ctx -> model .hparams ; 6055} 6056 6057std::map < ggml_backend_dev_t ,size_t > clip_get_mem_usage (const struct clip_ctx * ctx ) { 6058 std::map < ggml_backend_dev_t ,size_t > result = ctx -> mem_usage ; 6059for (auto & [dev ,size ] :ctx -> mem_compute ) { 6060result [dev ]+= size ; 6061 } 6062return result ; 6063} 6064 6065// 6066// API for debugging 6067// 6068 6069void clip_set_debug_output_embeddings (clip_ctx * ctx ,bool enable ) { 6070ctx -> debug_output_embeddings = enable ; 6071}