char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
35a74c8fb
char/aliceai-t5-moe
1// GGUF binary parser adapted from the huggingface/gguf package. 2// Reference: https://github.com/huggingface/huggingface.js 3 4#include "gguf-model-data.h" 5 6#include "common.h" 7#include "ggml-cpp.h" 8#include "gguf.h" 9 10#include <algorithm> 11#include <cstdio> 12#include <cstring> 13#include <filesystem> 14#include <fstream> 15 16#include "http.h" 17#define JSON_ASSERT GGML_ASSERT 18#include <nlohmann/json.hpp> 19 20// Equivalent of RangeView 21struct gguf_buf_reader { 22const char * data ; 23size_t size ; 24size_t pos ; 25 26gguf_buf_reader (const std::vector < char > & buf ) :data (buf .data ()),size (buf .size ()),pos (0 ) {} 27 28bool has_n_bytes (size_t n )const { 29return pos + n <=size ; 30 } 31 32template < typename T > 33bool read_val (T & out ) { 34if (!has_n_bytes (sizeof (T ))) { 35return false; 36 } 37memcpy (& out ,data + pos ,sizeof (T )); 38pos += sizeof (T ); 39return true; 40 } 41 42bool read_str (std::string & out ) { 43uint64_t len ; 44if (!read_val (len )) { 45return false; 46 } 47if (!has_n_bytes ((size_t )len )) { 48return false; 49 } 50out .assign (data + pos , (size_t )len ); 51pos += (size_t )len ; 52return true; 53 } 54 55bool skip (size_t n ) { 56if (!has_n_bytes (n )) { 57return false; 58 } 59pos += n ; 60return true; 61 } 62}; 63 64static size_t gguf_val_type_size (int32_t vtype ) { 65switch (vtype ) { 66case GGUF_TYPE_UINT8 :return 1 ; 67case GGUF_TYPE_INT8 :return 1 ; 68case GGUF_TYPE_UINT16 :return 2 ; 69case GGUF_TYPE_INT16 :return 2 ; 70case GGUF_TYPE_UINT32 :return 4 ; 71case GGUF_TYPE_INT32 :return 4 ; 72case GGUF_TYPE_FLOAT32 :return 4 ; 73case GGUF_TYPE_BOOL :return 1 ; 74case GGUF_TYPE_UINT64 :return 8 ; 75case GGUF_TYPE_INT64 :return 8 ; 76case GGUF_TYPE_FLOAT64 :return 8 ; 77default :return 0 ;// string/array handled separately 78 } 79} 80 81// Equivalent of readMetadataValue(), skips unused values rather than storing 82static bool gguf_skip_value (gguf_buf_reader & r ,int32_t vtype ) { 83if (vtype == GGUF_TYPE_STRING ) { 84 std::string tmp ; 85return r .read_str (tmp ); 86 } 87if (vtype == GGUF_TYPE_ARRAY ) { 88int32_t elem_type ; 89uint64_t count ; 90if (!r .read_val (elem_type )) { 91return false; 92 } 93if (!r .read_val (count )) { 94return false; 95 } 96if (elem_type == GGUF_TYPE_STRING ) { 97for (uint64_t i = 0 ;i < count ;i ++ ) { 98 std::string tmp ; 99if (!r .read_str (tmp )) { 100return false; 101 } 102 } 103return true; 104 } 105if (elem_type == GGUF_TYPE_ARRAY ) { 106// nested arrays - recurse 107for (uint64_t i = 0 ;i < count ;i ++ ) { 108if (!gguf_skip_value (r ,GGUF_TYPE_ARRAY )) { 109return false; 110 } 111 } 112return true; 113 } 114size_t elem_sz = gguf_val_type_size (elem_type ); 115if (elem_sz == 0 ) { 116return false; 117 } 118return r .skip ((size_t )count * elem_sz ); 119 } 120size_t sz = gguf_val_type_size (vtype ); 121if (sz == 0 ) { 122return false; 123 } 124return r .skip (sz ); 125} 126 127static bool gguf_read_uint32_val (gguf_buf_reader & r ,int32_t vtype ,uint32_t & out ) { 128// Handle array-valued fields (e.g. per-layer head counts in hybrid models) 129// by reading the first element as a representative value. 130if (vtype == GGUF_TYPE_ARRAY ) { 131int32_t elem_type ; 132uint64_t count ; 133if (!r .read_val (elem_type )) { 134return false; 135 } 136if (!r .read_val (count )) { 137return false; 138 } 139if (count == 0 ) { 140return false; 141 } 142// Read first element, skip the rest 143if (!gguf_read_uint32_val (r ,elem_type ,out )) { 144return false; 145 } 146for (uint64_t i = 1 ;i < count ;i ++ ) { 147size_t sz = gguf_val_type_size (elem_type ); 148if (sz == 0 ) { 149return false; 150 } 151if (!r .skip (sz )) { 152return false; 153 } 154 } 155return true; 156 } 157if (vtype == GGUF_TYPE_UINT8 ) { 158uint8_t v ; 159if (!r .read_val (v )) { 160return false; 161 } 162out = v ; 163return true; 164 } 165if (vtype == GGUF_TYPE_INT8 ) { 166int8_t v ; 167if (!r .read_val (v )) { 168return false; 169 } 170out = (uint32_t )v ; 171return true; 172 } 173if (vtype == GGUF_TYPE_UINT16 ) { 174uint16_t v ; 175if (!r .read_val (v )) { 176return false; 177 } 178out = v ; 179return true; 180 } 181if (vtype == GGUF_TYPE_INT16 ) { 182int16_t v ; 183if (!r .read_val (v )) { 184return false; 185 } 186out = (uint32_t )v ; 187return true; 188 } 189if (vtype == GGUF_TYPE_UINT32 ) { 190uint32_t v ; 191if (!r .read_val (v )) { 192return false; 193 } 194out = v ; 195return true; 196 } 197if (vtype == GGUF_TYPE_INT32 ) { 198int32_t v ; 199if (!r .read_val (v )) { 200return false; 201 } 202out = (uint32_t )v ; 203return true; 204 } 205if (vtype == GGUF_TYPE_UINT64 ) { 206uint64_t v ; 207if (!r .read_val (v )) { 208return false; 209 } 210out = (uint32_t )v ; 211return true; 212 } 213if (vtype == GGUF_TYPE_INT64 ) { 214int64_t v ; 215if (!r .read_val (v )) { 216return false; 217 } 218out = (uint32_t )v ; 219return true; 220 } 221return false; 222} 223 224// Follows the same header -> KV -> tensor parsing sequence as gguf() huggingface/gguf 225static std::optional < gguf_remote_model > gguf_parse_meta (const std::vector < char > & buf ) { 226gguf_buf_reader r (buf ); 227 228// Header: magic(4) + version(4) + tensor_count(8) + kv_count(8) = 24 bytes minimum 229uint32_t magic_raw ; 230if (!r .read_val (magic_raw )) { 231return std::nullopt ; 232 } 233if (memcmp (& magic_raw ,"GGUF" ,4 )!= 0 ) { 234fprintf (stderr ,"gguf_parse_meta: invalid magic\n" ); 235return std::nullopt ; 236 } 237 238uint32_t version ; 239if (!r .read_val (version )) { 240return std::nullopt ; 241 } 242if (version < 2 || version > 3 ) { 243fprintf (stderr ,"gguf_parse_meta: unsupported version %u\n" ,version ); 244return std::nullopt ; 245 } 246 247int64_t tensor_count_raw ; 248int64_t kv_count_raw ; 249if (!r .read_val (tensor_count_raw )) { 250return std::nullopt ; 251 } 252if (!r .read_val (kv_count_raw )) { 253return std::nullopt ; 254 } 255 256uint64_t tensor_count = (uint64_t )tensor_count_raw ; 257uint64_t kv_count = (uint64_t )kv_count_raw ; 258 259gguf_remote_model model ; 260 261 std::string arch_prefix ; 262 263// Parse KV pairs 264for (uint64_t i = 0 ;i < kv_count ;i ++ ) { 265 std::string key ; 266if (!r .read_str (key )) { 267return std::nullopt ; 268 } 269 270int32_t vtype ; 271if (!r .read_val (vtype )) { 272return std::nullopt ; 273 } 274 275if (key == "general.architecture" && vtype == GGUF_TYPE_STRING ) { 276if (!r .read_str (model .architecture )) { 277return std::nullopt ; 278 } 279arch_prefix = model .architecture + "." ; 280continue ; 281 } 282 283// Extract split.count for proper handling of split files 284if (key == "split.count" ) { 285uint32_t v ; 286if (!gguf_read_uint32_val (r ,vtype ,v )) { 287return std::nullopt ; 288 } 289model .n_split = (uint16_t )v ; 290continue ; 291 } 292 293// Extract split.tensors.count so we can verify we have all tensors 294if (key == "split.tensors.count" ) { 295uint32_t v ; 296if (!gguf_read_uint32_val (r ,vtype ,v )) { 297return std::nullopt ; 298 } 299model .n_split_tensors = v ; 300continue ; 301 } 302 303if (!arch_prefix .empty ()) { 304uint32_t * target = nullptr ; 305 306if (key == arch_prefix + "embedding_length" ) {target = & model .n_embd ; } 307else if (key == arch_prefix + "feed_forward_length" ) {target = & model .n_ff ; } 308else if (key == arch_prefix + "block_count" ) {target = & model .n_layer ; } 309else if (key == arch_prefix + "attention.head_count" ) {target = & model .n_head ; } 310else if (key == arch_prefix + "attention.head_count_kv" ) {target = & model .n_head_kv ; } 311else if (key == arch_prefix + "expert_count" ) {target = & model .n_expert ; } 312else if (key == arch_prefix + "attention.key_length" ) {target = & model .n_embd_head_k ; } 313else if (key == arch_prefix + "attention.value_length" ) {target = & model .n_embd_head_v ; } 314 315if (target ) { 316if (!gguf_read_uint32_val (r ,vtype ,* target )) { 317return std::nullopt ; 318 } 319continue ; 320 } 321 } 322 323if (!gguf_skip_value (r ,vtype )) { 324return std::nullopt ; 325 } 326 } 327 328// Parse tensor info entries 329model .tensors .reserve ((size_t )tensor_count ); 330for (uint64_t i = 0 ;i < tensor_count ;i ++ ) { 331gguf_remote_tensor t ; 332 333if (!r .read_str (t .name )) { 334return std::nullopt ; 335 } 336if (!r .read_val (t .n_dims )) { 337return std::nullopt ; 338 } 339 340if (t .n_dims > 4 ) { 341fprintf (stderr ,"gguf_parse_meta: tensor '%s' has %u dims (max 4)\n" ,t .name .c_str (),t .n_dims ); 342return std::nullopt ; 343 } 344 345for (uint32_t d = 0 ;d < t .n_dims ;d ++ ) { 346if (!r .read_val (t .ne [d ])) { 347return std::nullopt ; 348 } 349 } 350 351int32_t type_raw ; 352if (!r .read_val (type_raw )) { 353return std::nullopt ; 354 } 355t .type = (ggml_type )type_raw ; 356 357uint64_t offset ; 358if (!r .read_val (offset )) { 359return std::nullopt ; 360 } 361 362// Infer n_vocab from token_embd.weight 363if (t .name == "token_embd.weight" ) { 364model .n_vocab = (uint32_t )t .ne [1 ]; 365 } 366 367model .tensors .push_back (std::move (t )); 368 } 369 370return model ; 371} 372 373// cache handling for local download 374static std::string get_default_cache_dir () { 375return fs_get_cache_directory ()+ "gguf-headers/" ; 376} 377 378static std::string sanitize_for_path (const std::string & s ) { 379 std::string out = s ; 380for (char & c :out ) { 381if (c == '/' || c == '\\' || c == ':' ) { 382c = '_' ; 383 } 384 } 385return out ; 386} 387 388static bool read_file (const std::string & path , std::vector < char > & out ) { 389 std::ifstream f (path , std::ios::binary | std::ios::ate ); 390if (!f .good ()) { 391return false; 392 } 393auto sz = f .tellg (); 394if (sz <=0 ) { 395return false; 396 } 397out .resize ((size_t )sz ); 398f .seekg (0 ); 399f .read (out .data (),sz ); 400return f .good (); 401} 402 403static bool write_file (const std::string & path ,const std::vector < char > & data ) { 404 std::ofstream f (path , std::ios::binary | std::ios::trunc ); 405if (!f .good ()) { 406return false; 407 } 408f .write (data .data (), (std::streamsize )data .size ()); 409return f .good (); 410} 411 412// HuggingFace file auto-detection and HTTP download 413static std::pair < long , std::vector < char >> gguf_http_get ( 414const std::string & url , 415const httplib::Headers & headers = {}, 416int timeout_sec = 60 ) { 417try { 418auto [ cli , parts ] = common_http_client ( url ); 419 420if ( timeout_sec > 0 ) { 421cli . set_read_timeout ( timeout_sec , 0 ); 422cli . set_write_timeout ( timeout_sec , 0 ); 423} 424cli . set_connection_timeout ( 30 , 0 ); 425 426std::vector < char > body ; 427auto res = cli . Get ( parts . path , headers , 428[ & ]( const char * data , size_t len ) { 429body . insert ( body . end (), data , data + len ); 430return true; 431}, nullptr ); 432 433if (! res ) { 434fprintf ( stderr , "gguf_fetch: HTTP request failed for %s (error %d)\n" , 435url . c_str (), (int) res . error ()); 436return { -1 , {}}; 437} 438return { res -> status , std:: move ( body )}; 439} catch ( const std::exception & e ) { 440fprintf ( stderr , "gguf_fetch: HTTP error: %s\n" , e . what ()); 441return { -1 , {}}; 442} 443} 444 445// Find the filename for given repo/quant. 446// For split models, returns the first shard (the one containing "00001-of-") 447// split_prefix is set to the portion before "-00001-of-XXXXX.gguf" when a split file is found 448static std::string detect_gguf_filename ( const std::string & repo , const std::string & quant , 449std::string & split_prefix ) { 450split_prefix . clear (); 451std::string api_url = "https://huggingface.co/api/models/" + repo ; 452 453auto [ code , body ] = gguf_http_get ( api_url , {}, 30 ); 454if ( code != 200 || body . empty ()) { 455fprintf ( stderr , "gguf_fetch: failed to query HF API for %s (HTTP %ld)\n" , repo . c_str (), code ); 456return "" ; 457} 458 459nlohmann::json j ; 460try { 461j = nlohmann::json:: parse ( body . begin (), body . end ()); 462} catch (...) { 463fprintf ( stderr , "gguf_fetch: failed to parse HF API response\n" ); 464return "" ; 465} 466 467if (! j . contains ( "siblings" ) || ! j [ "siblings" ]. is_array ()) { 468fprintf ( stderr , "gguf_fetch: unexpected HF API response format\n" ); 469return "" ; 470} 471 472std::vector < std::string > matches ; 473std::string quant_upper = quant ; 474for (char & c : quant_upper ) { c = (char) toupper ( c ); } 475 476for ( const auto & sibling : j [ "siblings" ]) { 477if (! sibling . contains ( "rfilename" )) { continue ; } 478std::string fname = sibling [ "rfilename" ]. get < std::string > (); 479if ( fname . size () < 5 || fname . substr ( fname . size () - 5 ) != ".gguf" ) { 480continue ; 481} 482 483std::string fname_upper = fname ; 484for (char & c : fname_upper ) { c = (char) toupper ( c ); } 485if ( fname_upper . find ( quant_upper ) != std::string:: npos ) { 486matches . push_back ( fname ); 487} 488} 489 490if ( matches . empty ()) { 491fprintf ( stderr , "gguf_fetch: no .gguf files matching '%s' in %s\n" , quant . c_str (), repo . c_str ()); 492return "" ; 493} 494 495std:: sort ( matches . begin (), matches . end ()); 496 497// Prefer non-split, non-supplementary file 498for ( const auto & m : matches ) { 499if ( m . find ( "-of-" ) == std::string:: npos && m . find ( "mmproj" ) == std::string:: npos ) { 500return m ; 501} 502} 503 504// Return the first shard (00001-of-) and extract the prefix 505for ( const auto & m : matches ) { 506auto pos = m . find ( "-00001-of-" ); 507if ( pos != std::string:: npos ) { 508split_prefix = m . substr ( 0 , pos ); 509return m ; 510} 511} 512 513return matches [ 0 ]; 514} 515 516static std::optional < gguf_remote_model > fetch_and_parse ( 517const std::string & repo , 518const std::string & filename , 519const std::string & cache_path , 520bool verbose ) { 521std::string url = "https://huggingface.co/" + repo + "/resolve/main/" + filename ; 522 523// Progressive download inspired by RangeView.fetchChunk() 524// Start at 2MB, double each time, cap at 64MB 525size_t chunk_size = 2 * 1024 * 1024 ; 526const size_t max_chunk = 64 * 1024 * 1024 ; 527 528while ( chunk_size <= max_chunk ) { 529if ( verbose ) { 530fprintf ( stderr , "gguf_fetch: downloading %zu bytes from %s\n" , chunk_size , filename . c_str ()); 531} 532 533char range_buf [ 64 ]; 534snprintf ( range_buf , sizeof ( range_buf ), "bytes=0-%zu" , chunk_size - 1 ); 535httplib::Headers headers = {{ "Range" , range_buf }}; 536 537auto [ code , body ] = gguf_http_get ( url , headers , 120 ); 538if ( code != 200 && code != 206 ) { 539fprintf ( stderr , "gguf_fetch: HTTP %ld fetching %s\n" , code , url . c_str ()); 540return std:: nullopt ; 541} 542 543if ( body . empty ()) { 544fprintf ( stderr , "gguf_fetch: empty response\n" ); 545return std:: nullopt ; 546} 547 548auto result = gguf_parse_meta ( body ); 549if ( result . has_value ()) { 550write_file ( cache_path , body ); 551return result ; 552} 553 554if ( code == 200 ) { 555fprintf ( stderr , "gguf_fetch: server returned full response but metadata parse failed\n" ); 556return std:: nullopt ; 557} 558 559// Parse failed, try larger chunk 560chunk_size *= 2 ; 561} 562 563fprintf ( stderr , "gguf_fetch: metadata exceeds 64MB, giving up\n" ); 564return std:: nullopt ; 565} 566 567static std::string get_cache_file_path ( const std::string & cdir , const std::string & repo_part , const std::string & filename ) { 568std::string fname_part = sanitize_for_path ( filename ); 569return cdir + "/" + repo_part + "--" + fname_part + ".partial" ; 570} 571 572// Try cache first, then fetch and parse a single GGUF shard. 573static std::optional < gguf_remote_model > fetch_or_cached ( 574const std::string & repo , 575const std::string & filename , 576const std::string & cdir , 577const std::string & repo_part , 578bool verbose ) { 579std::string cache_path = get_cache_file_path ( cdir , repo_part , filename ); 580 581{ 582std::vector < char > cached ; 583if (std::filesystem:: exists ( cache_path ) && read_file ( cache_path , cached )) { 584auto result = gguf_parse_meta ( cached ); 585if ( result . has_value ()) { 586if ( verbose ) { 587fprintf ( stderr , "gguf_fetch: loaded from cache: %s\n" , cache_path . c_str ()); 588} 589return result ; 590} 591} 592} 593 594fs_create_directory_with_parents ( cdir ); 595return fetch_and_parse ( repo , filename , cache_path , verbose ); 596} 597 598std::optional < gguf_remote_model > gguf_fetch_model_meta ( 599const std::string & repo , 600const std::string & quant , 601const std::string & cache_dir , 602bool verbose ) { 603std::string cdir = cache_dir . empty () ? get_default_cache_dir () : cache_dir ; 604std::string repo_part = sanitize_for_path ( repo ); 605 606std::string split_prefix ; 607std::string filename = detect_gguf_filename ( repo , quant , split_prefix ); 608if ( filename . empty ()) { 609return std:: nullopt ; 610} 611 612auto model_opt = fetch_or_cached ( repo , filename , cdir , repo_part , verbose ); 613if (! model_opt . has_value ()) { 614fprintf ( stderr , "gguf_fetch: failed to fetch %s\n" , filename . c_str ()); 615return std:: nullopt ; 616} 617 618auto & model = model_opt . value (); 619 620// If the model is split across multiple files we need to fetch the remaining shards metadata 621if ( model . n_split > 1 ) { 622if ( split_prefix . empty ()) { 623fprintf ( stderr , "gguf_fetch: model reports %u splits but filename has no split pattern\n" , model . n_split ); 624return std:: nullopt ; 625} 626 627if ( verbose ) { 628fprintf ( stderr , "gguf_fetch: split model with %u shards, fetching remaining %u...\n" , 629model . n_split , model . n_split - 1 ); 630} 631 632for (int i = 2 ; i <= model . n_split ; i ++ ) { 633char buf_num [ 32 ]; 634char buf_tot [ 32 ]; 635snprintf ( buf_num , sizeof ( buf_num ), "%05d" , i ); 636snprintf ( buf_tot , sizeof ( buf_tot ), "%05d" , (int) model . n_split ); 637std::string shard_name = split_prefix + "-" + buf_num + "-of-" + buf_tot + ".gguf" ; 638 639auto shard = fetch_or_cached ( repo , shard_name , cdir , repo_part , verbose ); 640if (! shard . has_value ()) { 641fprintf ( stderr , "gguf_fetch: failed to fetch shard %d: %s\n" , i , shard_name . c_str ()); 642return std:: nullopt ; 643} 644 645model . tensors . insert ( model . tensors . end (), 646std:: make_move_iterator ( shard -> tensors . begin ()), 647std:: make_move_iterator ( shard -> tensors . end ())); 648} 649 650if ( model . n_split_tensors > 0 && model . tensors . size () != model . n_split_tensors ) { 651fprintf ( stderr , "gguf_fetch: WARNING: expected %u tensors from split.tensors.count, got %zu\n" , 652model . n_split_tensors , model . tensors . size ()); 653} 654} 655 656return model_opt ; 657} 658 659gguf_context_ptr gguf_fetch_gguf_ctx ( 660const std::string & repo , 661const std::string & quant , 662const std::string & cache_dir , 663bool verbose ) { 664std::string cdir = cache_dir . empty () ? get_default_cache_dir () : cache_dir ; 665std::string repo_part = sanitize_for_path ( repo ); 666 667std::string split_prefix ; 668std::string filename = detect_gguf_filename ( repo , quant , split_prefix ); 669 670if ( filename . empty ()) { 671return nullptr ; 672} 673 674auto model_opt = fetch_or_cached ( repo , filename , cdir , repo_part , verbose ); 675if (! model_opt . has_value ()) { 676fprintf ( stderr , "gguf_fetch: failed to fetch %s\n" , filename . c_str ()); 677return nullptr ; 678} 679 680auto & model = model_opt . value (); 681 682const std::string cache_path = get_cache_file_path ( cdir , repo_part , filename ); 683 684ggml_context_ptr ggml_ctx_ptr ; 685ggml_context * ggml_ctx {}; 686gguf_init_params params {true, & ggml_ctx }; 687gguf_context_ptr ctx { gguf_init_from_file ( cache_path . c_str (), params )}; 688ggml_ctx_ptr . reset ( ggml_ctx ); 689 690if ( ctx == nullptr ) { 691fprintf ( stderr , "gguf_fetch: gguf_init_from_file failed\n" ); 692return nullptr ; 693} 694 695// If the model is split across multiple files we need to fetch the remaining shards metadata 696if ( model . n_split > 1 ) { 697if ( split_prefix . empty ()) { 698fprintf ( stderr , "gguf_fetch: model reports %u splits but filename has no split pattern\n" , model . n_split ); 699return nullptr ; 700} 701 702if ( verbose ) { 703fprintf ( stderr , "gguf_fetch: split model with %u shards, fetching remaining %u...\n" , 704model . n_split , model . n_split - 1 ); 705} 706 707for (int i = 2 ; i <= model . n_split ; i ++ ) { 708char buf_num [ 32 ]; 709char buf_tot [ 32 ]; 710snprintf ( buf_num , sizeof ( buf_num ), "%05d" , i ); 711snprintf ( buf_tot , sizeof ( buf_tot ), "%05d" , (int) model . n_split ); 712std::string shard_name = split_prefix + "-" + buf_num + "-of-" + buf_tot + ".gguf" ; 713 714auto shard = fetch_or_cached ( repo , shard_name , cdir , repo_part , verbose ); 715if (! shard . has_value ()) { 716fprintf ( stderr , "gguf_fetch: failed to fetch shard %d: %s\n" , i , shard_name . c_str ()); 717return nullptr ; 718} 719 720// Load tensors from shard and add to main gguf_context 721const std::string shard_path = get_cache_file_path ( cdir , repo_part , shard_name ); 722ggml_context_ptr shard_ggml_ctx_ptr ; 723ggml_context * shard_ggml_ctx {}; 724gguf_init_params shard_params {true, & shard_ggml_ctx }; 725gguf_context_ptr shard_ctx { gguf_init_from_file ( shard_path . c_str (), shard_params )}; 726shard_ggml_ctx_ptr . reset ( shard_ggml_ctx ); 727 728if ( shard_ctx == nullptr ) { 729fprintf ( stderr , "gguf_fetch: shard gguf_init_from_file failed\n" ); 730return nullptr ; 731} 732 733for (ggml_tensor * t = ggml_get_first_tensor ( shard_ggml_ctx ); t ; t = ggml_get_next_tensor ( shard_ggml_ctx , t )) { 734gguf_add_tensor ( ctx . get (), t ); 735} 736} 737 738gguf_set_val_u16 ( ctx . get (), "split.count" , 1 ); 739} 740 741return ctx ; 742}