char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
680a9ae63
char/aliceai-t5-moe
1#include "llama.h" 2 3#include "build-info.h" 4#include "common.h" 5 6#include "ggml.h" 7#include "gguf.h" 8 9#include <algorithm> 10#include <cinttypes> 11#include <climits> 12#include <clocale> 13#include <cstdio> 14#include <cstdlib> 15#include <stdexcept> 16#include <cstring> 17#include <fstream> 18#include <string> 19#include <vector> 20 21#if defined(_WIN32 ) 22#include <windows.h> 23#ifndef PATH_MAX 24#define PATH_MAX MAX_PATH 25#endif 26#include <io.h> 27#endif 28 29enum split_operation :uint8_t { 30OP_NONE , 31OP_SPLIT , 32OP_MERGE , 33}; 34 35enum split_mode :uint8_t { 36MODE_NONE , 37MODE_TENSOR , 38MODE_SIZE , 39}; 40 41struct split_params { 42split_operation operation = OP_NONE ; 43split_mode mode = MODE_NONE ; 44size_t n_bytes_split = 0 ; 45int n_split_tensors = 128 ; 46 std::string input ; 47 std::string output ; 48bool no_tensor_first_split = false; 49bool dry_run = false; 50bool delete_splits = false; 51}; 52 53static void split_print_usage (const char * executable ) { 54const split_params default_params ; 55printf ("\n" ); 56printf ("usage: %s [options] GGUF_IN GGUF_OUT\n" ,executable ); 57printf ("\n" ); 58printf ("Apply a GGUF operation on IN to OUT." ); 59printf ("\n" ); 60printf ("options:\n" ); 61printf (" -h, --help show this help message and exit\n" ); 62printf (" --version show version and build info\n" ); 63printf (" --split split GGUF to multiple GGUF (enabled by default)\n" ); 64printf (" --merge merge multiple GGUF to a single GGUF\n" ); 65printf (" --split-max-tensors max tensors in each split (default: %d)\n" ,default_params .n_split_tensors ); 66printf (" --split-max-size N(M|G) max size per split\n" ); 67printf (" --no-tensor-first-split do not add tensors to the first split (disabled by default)\n" ); 68printf (" --dry-run only print out a split plan and exit, without writing any new files\n" ); 69printf (" --delete-splits delete the split files during merge to free up disk space WARNING: this option is unsafe and will leave you in an unrecoverable state if something fails during the merge\n" ); 70printf ("\n" ); 71} 72 73// return convert string, for example "128M" or "4G" to number of bytes 74static size_t split_str_to_n_bytes (std::string str ) { 75size_t n_bytes = 0 ; 76int n ; 77if (str .back ()== 'M' ) { 78sscanf (str .c_str (),"%d" ,& n ); 79n_bytes = (size_t )n * 1000 * 1000 ;// megabytes 80 }else if (str .back ()== 'G' ) { 81sscanf (str .c_str (),"%d" ,& n ); 82n_bytes = (size_t )n * 1000 * 1000 * 1000 ;// gigabytes 83 }else { 84throw std::invalid_argument ("error: supported units are M (megabytes) or G (gigabytes), but got: " + std::string (1 ,str .back ())); 85 } 86if (n <=0 ) { 87throw std::invalid_argument ("error: size must be a positive value" ); 88 } 89return n_bytes ; 90} 91 92static void split_params_parse_ex (int argc ,const char ** argv ,split_params & params ) { 93 std::string arg ; 94const std::string arg_prefix = "--" ; 95bool invalid_param = false; 96 97int arg_idx = 1 ; 98for (;arg_idx < argc && strncmp (argv [arg_idx ],"--" ,2 )== 0 ;arg_idx ++ ) { 99arg = argv [arg_idx ]; 100if (arg .compare (0 ,arg_prefix .size (),arg_prefix )== 0 ) { 101 std::replace (arg .begin (),arg .end (),'_' ,'-' ); 102 } 103 104bool arg_found = false; 105if (arg == "-h" || arg == "--help" ) { 106split_print_usage (argv [0 ]); 107exit (0 ); 108 }else if (arg == "--version" ) { 109fprintf (stderr ,"version: %s (build %d, commit %s)\n" ,llama_version (),llama_build_number (),llama_commit ()); 110fprintf (stderr ,"built with %s for %s\n" ,llama_compiler (),llama_build_target ()); 111exit (0 ); 112 }else if (arg == "--dry-run" ) { 113arg_found = true; 114params .dry_run = true; 115 }else if (arg == "--no-tensor-first-split" ) { 116arg_found = true; 117params .no_tensor_first_split = true; 118 }else if (arg == "--merge" ) { 119arg_found = true; 120if (params .operation != OP_NONE && params .operation != OP_MERGE ) { 121throw std::invalid_argument ("error: either --split or --merge can be specified, but not both" ); 122 } 123params .operation = OP_MERGE ; 124 }else if (arg == "--split" ) { 125arg_found = true; 126if (params .operation != OP_NONE && params .operation != OP_SPLIT ) { 127throw std::invalid_argument ("error: either --split or --merge can be specified, but not both" ); 128 } 129params .operation = OP_SPLIT ; 130 }else if (arg == "--split-max-tensors" ) { 131if (++ arg_idx >=argc ) { 132invalid_param = true; 133break ; 134 } 135arg_found = true; 136if (params .mode != MODE_NONE && params .mode != MODE_TENSOR ) { 137throw std::invalid_argument ("error: either --split-max-tensors or --split-max-size can be specified, but not both" ); 138 } 139params .mode = MODE_TENSOR ; 140params .n_split_tensors = atoi (argv [arg_idx ]); 141 }else if (arg == "--split-max-size" ) { 142if (++ arg_idx >=argc ) { 143invalid_param = true; 144break ; 145 } 146arg_found = true; 147if (params .mode != MODE_NONE && params .mode != MODE_SIZE ) { 148throw std::invalid_argument ("error: either --split-max-tensors or --split-max-size can be specified, but not both" ); 149 } 150params .mode = MODE_SIZE ; 151params .n_bytes_split = split_str_to_n_bytes (argv [arg_idx ]); 152 }else if (arg == "--delete-splits" ) { 153arg_found = true; 154params .delete_splits = true; 155 } 156 157if (!arg_found ) { 158throw std::invalid_argument ("error: unknown argument: " + arg ); 159 } 160 } 161 162// the operation is split if not specified 163if (params .operation == OP_NONE ) { 164params .operation = OP_SPLIT ; 165 } 166// the split mode is by tensor if not specified 167if (params .mode == MODE_NONE ) { 168params .mode = MODE_TENSOR ; 169 } 170 171if (invalid_param ) { 172throw std::invalid_argument ("error: invalid parameter for argument: " + arg ); 173 } 174 175if (argc - arg_idx != 2 ) { 176throw std::invalid_argument ("error: bad arguments" ); 177 } 178 179params .input = argv [arg_idx ++ ]; 180params .output = argv [arg_idx ++ ]; 181} 182 183static bool split_params_parse (int argc ,const char ** argv ,split_params & params ) { 184bool result = true; 185try { 186split_params_parse_ex (argc ,argv ,params ); 187 } 188catch (const std::invalid_argument & ex ) { 189fprintf (stderr ,"%s\n" ,ex .what ()); 190split_print_usage (argv [0 ]); 191exit (EXIT_FAILURE ); 192 } 193return result ; 194} 195 196static void zeros (std::ofstream & file ,size_t n ) { 197char zero = 0 ; 198for (size_t i = 0 ;i < n ;++ i ) { 199file .write (& zero ,1 ); 200 } 201} 202 203struct split_strategy { 204const split_params params ; 205 std::ifstream & f_input ; 206struct gguf_context * ctx_gguf ; 207struct ggml_context * ctx_meta = NULL ; 208const int n_tensors ; 209 210// one ctx_out per one output file 211 std::vector < struct gguf_context *> ctx_outs ; 212 213// temporary buffer for reading in tensor data 214 std::vector < uint8_t > read_buf ; 215 216split_strategy (const split_params & params , 217 std::ifstream & f_input , 218struct gguf_context * ctx_gguf , 219struct ggml_context * ctx_meta ) : 220params (params ), 221f_input (f_input ), 222ctx_gguf (ctx_gguf ), 223ctx_meta (ctx_meta ), 224n_tensors (gguf_get_n_tensors (ctx_gguf )) { 225 226// because we need to know list of tensors for each file in advance, we will build all the ctx_out for all output splits 227int i_split = -1 ; 228struct gguf_context * ctx_out = NULL ; 229auto new_ctx_out = [& ](bool allow_no_tensors ) { 230i_split ++ ; 231if (ctx_out != NULL ) { 232if (gguf_get_n_tensors (ctx_out )== 0 && !allow_no_tensors ) { 233fprintf (stderr ,"error: one of splits have 0 tensors. Maybe size or tensors limit is too small\n" ); 234exit (EXIT_FAILURE ); 235 } 236ctx_outs .push_back (ctx_out ); 237 } 238ctx_out = gguf_init_empty (); 239// Save all metadata in first split only 240if (i_split == 0 ) { 241gguf_set_kv (ctx_out ,ctx_gguf ); 242 } 243gguf_set_val_u16 (ctx_out ,LLM_KV_SPLIT_NO ,i_split ); 244gguf_set_val_u16 (ctx_out ,LLM_KV_SPLIT_COUNT ,0 );// placeholder 245gguf_set_val_i32 (ctx_out ,LLM_KV_SPLIT_TENSORS_COUNT ,n_tensors ); 246 }; 247 248// initialize ctx_out for the first split 249new_ctx_out (false); 250 251// skip first split if no_tensor_first_split is set 252if (params .no_tensor_first_split ) { 253new_ctx_out (true); 254 } 255 256// process tensors one by one 257size_t curr_tensors_size = 0 ;// current size by counting only tensors size (without metadata) 258for (int i = 0 ;i < n_tensors ;++ i ) { 259struct ggml_tensor * t = ggml_get_tensor (ctx_meta ,gguf_get_tensor_name (ctx_gguf ,i )); 260// calculate the "imaginary" size = the current size + next tensor size 261size_t n_bytes = GGML_PAD (ggml_nbytes (t ),GGUF_DEFAULT_ALIGNMENT ); 262size_t next_tensors_size = curr_tensors_size + n_bytes ; 263if (should_split (i ,next_tensors_size )) { 264new_ctx_out (false); 265curr_tensors_size = n_bytes ; 266 }else { 267curr_tensors_size = next_tensors_size ; 268 } 269gguf_add_tensor (ctx_out ,t ); 270 } 271 272// push the last ctx_out 273ctx_outs .push_back (ctx_out ); 274 275// set the correct n_split for all ctx_out 276for (auto & ctx :ctx_outs ) { 277gguf_set_val_u16 (ctx ,LLM_KV_SPLIT_COUNT ,ctx_outs .size ()); 278 } 279 } 280 281 ~split_strategy () { 282for (auto & ctx_out :ctx_outs ) { 283gguf_free (ctx_out ); 284 } 285 } 286 287bool should_split (int i_tensor ,size_t next_size ) { 288if (params .mode == MODE_SIZE ) { 289// split by max size per file 290return next_size > params .n_bytes_split ; 291 }else if (params .mode == MODE_TENSOR ) { 292// split by number of tensors per file 293return i_tensor > 0 && i_tensor < n_tensors && i_tensor %params .n_split_tensors == 0 ; 294 } 295// should never happen 296GGML_ABORT ("invalid mode" ); 297 } 298 299void print_info () { 300printf ("n_split: %zu\n" ,ctx_outs .size ()); 301int i_split = 0 ; 302for (auto & ctx_out :ctx_outs ) { 303// re-calculate the real gguf size for each split (= metadata size + total size of all tensors) 304size_t total_size = gguf_get_meta_size (ctx_out ); 305for (int i = 0 ;i < gguf_get_n_tensors (ctx_out );++ i ) { 306struct ggml_tensor * t = ggml_get_tensor (ctx_meta ,gguf_get_tensor_name (ctx_out ,i )); 307total_size += ggml_nbytes (t ); 308 } 309total_size = total_size /1000 /1000 ;// convert to megabytes 310printf ("split %05d: n_tensors = %" PRIi64 ", total_size = %zuM\n" ,i_split + 1 ,gguf_get_n_tensors (ctx_out ),total_size ); 311i_split ++ ; 312 } 313 } 314 315void write () { 316int i_split = 0 ; 317int n_split = ctx_outs .size (); 318for (auto & ctx_out :ctx_outs ) { 319// construct file path 320char split_path [PATH_MAX ]= {0 }; 321llama_split_path (split_path ,sizeof (split_path ),params .output .c_str (),i_split ,n_split ); 322 323// open the output file 324printf ("Writing file %s ... " ,split_path ); 325fflush (stdout ); 326 std::ofstream fout = std::ofstream (split_path , std::ios::binary ); 327fout .exceptions (std::ofstream::failbit );// fail fast on write errors 328 329// write metadata 330 std::vector < uint8_t > data (gguf_get_meta_size (ctx_out )); 331gguf_get_meta_data (ctx_out ,data .data ()); 332fout .write ((const char * )data .data (),data .size ()); 333 334// write tensors 335for (int i = 0 ;i < gguf_get_n_tensors (ctx_out );++ i ) { 336// read tensor meta and prepare buffer 337const char * t_name = gguf_get_tensor_name (ctx_out ,i ); 338struct ggml_tensor * t = ggml_get_tensor (ctx_meta ,t_name ); 339auto n_bytes = ggml_nbytes (t ); 340read_buf .resize (n_bytes ); 341 342// calculate offset 343auto i_tensor_in = gguf_find_tensor (ctx_gguf ,t_name );// idx of tensor in the input file 344auto offset = gguf_get_data_offset (ctx_gguf )+ gguf_get_tensor_offset (ctx_gguf ,i_tensor_in ); 345 346// copy tensor from input to output file 347copy_file_to_file (f_input ,fout ,offset ,n_bytes ); 348zeros (fout ,GGML_PAD (n_bytes ,GGUF_DEFAULT_ALIGNMENT )- n_bytes ); 349 } 350 351printf ("done\n" ); 352// close the file 353fout .close (); 354i_split ++ ; 355 } 356 } 357 358void copy_file_to_file (std::ifstream & f_in , std::ofstream & f_out ,const size_t in_offset ,const size_t len ) { 359// TODO: detect OS and use copy_file_range() here for better performance 360if (read_buf .size ()< len ) { 361read_buf .resize (len ); 362 } 363f_in .seekg (in_offset ); 364f_in .read ((char * )read_buf .data (),len ); 365f_out .write ((const char * )read_buf .data (),len ); 366 } 367}; 368 369static void gguf_split (const split_params & split_params ) { 370struct ggml_context * ctx_meta = NULL ; 371 372struct gguf_init_params params = { 373/*.no_alloc = */ true, 374/*.ctx = */ & ctx_meta , 375 }; 376 377 std::ifstream f_input (split_params .input .c_str (), std::ios::binary ); 378if (!f_input .is_open ()) { 379fprintf (stderr ,"%s: failed to open input GGUF from %s\n" ,__func__ ,split_params .input .c_str ()); 380exit (EXIT_FAILURE ); 381 } 382 383auto * ctx_gguf = gguf_init_from_file (split_params .input .c_str (),params ); 384if (!ctx_gguf ) { 385fprintf (stderr ,"%s: failed to load input GGUF from %s\n" ,__func__ ,split_params .input .c_str ()); 386exit (EXIT_FAILURE ); 387 } 388 389// prepare the strategy 390split_strategy strategy (split_params ,f_input ,ctx_gguf ,ctx_meta ); 391int n_split = strategy .ctx_outs .size (); 392strategy .print_info (); 393 394if (!split_params .dry_run ) { 395// write all output splits 396strategy .write (); 397 } 398 399// done, clean up 400gguf_free (ctx_gguf ); 401f_input .close (); 402 403fprintf (stderr ,"%s: %d gguf split written with a total of %d tensors.\n" , 404__func__ ,n_split ,strategy .n_tensors ); 405} 406 407static void gguf_merge (const split_params & split_params ) { 408fprintf (stderr ,"%s: %s -> %s\n" , 409__func__ ,split_params .input .c_str (), 410split_params .output .c_str ()); 411int n_split = 1 ; 412int total_tensors = 0 ; 413 414// avoid overwriting existing output file 415if (std::ifstream (split_params .output .c_str ())) { 416fprintf (stderr ,"%s: output file %s already exists\n" ,__func__ ,split_params .output .c_str ()); 417exit (EXIT_FAILURE ); 418 } 419 420 421auto * ctx_out = gguf_init_empty (); 422 423 std::vector < uint8_t > read_data ; 424 std::vector < ggml_context *> ctx_metas ; 425 std::vector < gguf_context *> ctx_ggufs ; 426 427char split_path [PATH_MAX ]= {0 }; 428strncpy (split_path ,split_params .input .c_str (),sizeof (split_path )- 1 ); 429char split_prefix [PATH_MAX ]= {0 }; 430 431// First pass to find KV and tensors metadata 432for (int i_split = 0 ;i_split < n_split ;i_split ++ ) { 433struct ggml_context * ctx_meta = NULL ; 434 435struct gguf_init_params params = { 436/*.no_alloc = */ true, 437/*.ctx = */ & ctx_meta , 438 }; 439 440if (i_split > 0 ) { 441llama_split_path (split_path ,sizeof (split_path ),split_prefix ,i_split ,n_split ); 442 } 443fprintf (stderr ,"%s: reading metadata %s ..." ,__func__ ,split_path ); 444 445auto * ctx_gguf = gguf_init_from_file (split_path ,params ); 446if (!ctx_gguf ) { 447fprintf (stderr ,"\n%s: failed to load input GGUF from %s\n" ,__func__ ,split_params .input .c_str ()); 448exit (EXIT_FAILURE ); 449 } 450ctx_ggufs .push_back (ctx_gguf ); 451ctx_metas .push_back (ctx_meta ); 452 453if (i_split == 0 ) { 454auto key_n_split = gguf_find_key (ctx_gguf ,LLM_KV_SPLIT_COUNT ); 455if (key_n_split < 0 ) { 456fprintf (stderr , 457"\n%s: input file does not contain %s metadata\n" , 458__func__ , 459LLM_KV_SPLIT_COUNT ); 460gguf_free (ctx_gguf ); 461ggml_free (ctx_meta ); 462gguf_free (ctx_out ); 463exit (EXIT_FAILURE ); 464 } 465 466n_split = gguf_get_val_u16 (ctx_gguf ,key_n_split ); 467if (n_split < 1 ) { 468fprintf (stderr , 469"\n%s: input file does not contain a valid split count %d\n" , 470__func__ , 471n_split ); 472gguf_free (ctx_gguf ); 473ggml_free (ctx_meta ); 474gguf_free (ctx_out ); 475exit (EXIT_FAILURE ); 476 } 477 478// Verify the file naming and extract split_prefix 479if (!llama_split_prefix (split_prefix ,sizeof (split_prefix ),split_path ,i_split ,n_split )) { 480fprintf (stderr ,"\n%s: unexpected input file name: %s" 481" i_split=%d" 482" n_split=%d\n" ,__func__ , 483split_path ,i_split ,n_split ); 484gguf_free (ctx_gguf ); 485ggml_free (ctx_meta ); 486gguf_free (ctx_out ); 487exit (EXIT_FAILURE ); 488 } 489 490// Do not trigger merge if we try to merge again the output 491gguf_set_val_u16 (ctx_gguf ,LLM_KV_SPLIT_COUNT ,0 ); 492 493// Set metadata from the first split 494gguf_set_kv (ctx_out ,ctx_gguf ); 495 } 496 497auto n_tensors = gguf_get_n_tensors (ctx_gguf ); 498for (int i_tensor = 0 ;i_tensor < n_tensors ;i_tensor ++ ) { 499const char * t_name = gguf_get_tensor_name (ctx_gguf ,i_tensor ); 500struct ggml_tensor * t = ggml_get_tensor (ctx_meta ,t_name ); 501gguf_add_tensor (ctx_out ,t ); 502 } 503total_tensors += n_tensors ; 504 505fprintf (stderr ,"\033[3Ddone\n" ); 506 } 507 std::ofstream fout ; 508if (!split_params .dry_run ) { 509fout .open (split_params .output .c_str (), std::ios::binary ); 510fout .exceptions (std::ofstream::failbit );// fail fast on write errors 511// placeholder for the meta data 512auto meta_size = gguf_get_meta_size (ctx_out ); 513 ::zeros (fout ,meta_size ); 514 } 515 516// Write tensors data 517bool merge_error = false; 518for (int i_split = 0 ;i_split < n_split ;i_split ++ ) { 519llama_split_path (split_path ,sizeof (split_path ),split_prefix ,i_split ,n_split ); 520 std::ifstream f_input (split_path , std::ios::binary ); 521if (!f_input .is_open ()) { 522fprintf (stderr ,"%s: failed to open input GGUF from %s\n" ,__func__ ,split_path ); 523for (uint32_t i = 0 ;i < ctx_ggufs .size ();i ++ ) { 524gguf_free (ctx_ggufs [i ]); 525ggml_free (ctx_metas [i ]); 526 } 527gguf_free (ctx_out ); 528if (!split_params .dry_run ) { 529fout .close (); 530 } 531exit (EXIT_FAILURE ); 532 } 533fprintf (stderr ,"%s: writing tensors %s ..." ,__func__ ,split_path ); 534 535auto * ctx_gguf = ctx_ggufs [i_split ]; 536auto * ctx_meta = ctx_metas [i_split ]; 537 538auto n_tensors = gguf_get_n_tensors (ctx_gguf ); 539for (int i_tensor = 0 ;i_tensor < n_tensors ;i_tensor ++ ) { 540const char * t_name = gguf_get_tensor_name (ctx_gguf ,i_tensor ); 541struct ggml_tensor * t = ggml_get_tensor (ctx_meta ,t_name ); 542 543auto n_bytes = ggml_nbytes (t ); 544 545if (read_data .size ()< n_bytes ) { 546read_data .resize (n_bytes ); 547 } 548 549auto offset = gguf_get_data_offset (ctx_gguf )+ gguf_get_tensor_offset (ctx_gguf ,i_tensor ); 550f_input .seekg (offset ); 551f_input .read ((char * )read_data .data (),n_bytes ); 552if (!split_params .dry_run ) { 553// write tensor data + padding 554fout .write ((const char * )read_data .data (),n_bytes ); 555zeros (fout ,GGML_PAD (n_bytes ,GGUF_DEFAULT_ALIGNMENT )- n_bytes ); 556 } 557 } 558 559gguf_free (ctx_gguf ); 560ggml_free (ctx_meta ); 561f_input .close (); 562fprintf (stderr ,"\033[3Ddone\n" ); 563 564if (!split_params .dry_run && split_params .delete_splits ) { 565int delete_result = std::remove (split_path ); 566if (delete_result != 0 ) { 567merge_error = true; 568fprintf (stderr ,"error: failed to delete %s\n" ,split_path ); 569 }else { 570fprintf (stderr ,"%s: deleted file %s\n" ,__func__ ,split_path ); 571 } 572 } 573 } 574 575if (!split_params .dry_run ) { 576// go back to beginning of file and write the updated metadata 577fout .seekp (0 ); 578 std::vector < uint8_t > data (gguf_get_meta_size (ctx_out )); 579gguf_get_meta_data (ctx_out ,data .data ()); 580fout .write ((const char * )data .data (),data .size ()); 581fout .close (); 582 } 583gguf_free (ctx_out ); 584 585fprintf (stderr ,"%s: %s merged from %d split with %d tensors.\n" , 586__func__ ,split_params .output .c_str (),n_split ,total_tensors ); 587 588if (merge_error ) { 589exit (EXIT_FAILURE ); 590 } 591} 592 593int main (int argc ,const char ** argv ) { 594 std::setlocale (LC_NUMERIC ,"C" ); 595 596split_params params ; 597split_params_parse (argc ,argv ,params ); 598 599switch (params .operation ) { 600case OP_SPLIT :gguf_split (params ); 601break ; 602case OP_MERGE :gguf_merge (params ); 603break ; 604default :split_print_usage (argv [0 ]); 605exit (EXIT_FAILURE ); 606 } 607 608return 0 ; 609}