char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
38406d597
char/aliceai-t5-moe
1#include "arg.h" 2#include "common.h" 3#include "imatrix-loader.h" 4#include "log.h" 5#include "llama.h" 6#include "gguf.h" 7 8#include <algorithm> 9#include <chrono> 10#include <clocale> 11#include <cmath> 12#include <cstdio> 13#include <cstring> 14#include <ctime> 15#include <thread> 16#include <mutex> 17#include <vector> 18#include <fstream> 19#include <unordered_map> 20#include <map> 21#include <regex> 22#include <numeric> 23 24#if defined(_MSC_VER ) 25#pragma warning(disable: 4244 4267) // possible loss of data 26#endif 27 28static void print_usage (int ,char ** argv ) { 29LOG ("\nexample usage:\n" ); 30LOG ("\n %s \\\n" 31" -m model.gguf -f some-text.txt [-o imatrix.gguf] [--output-format {gguf,dat}] [--no-ppl] \\\n" 32" [--process-output] [--chunk 123] [--save-frequency 0] [--output-frequency 10] \\\n" 33" [--in-file imatrix-prev-0.gguf --in-file imatrix-prev-1.gguf ...] [--parse-special] \\\n" 34" [--show-statistics] [...]\n" ,argv [0 ]); 35LOG ("\n" ); 36} 37 38struct Stats { 39 std::vector < float > values ; 40 std::vector < int64_t > counts ; 41}; 42 43struct tensor_statistics { 44 std::string tensor ; 45Stats stats ; 46float total_sqract = 0.0f ; 47float mean_sqract = 0.0f ; 48float max_sqract = 0.0f ; 49float min_sqract = 0.0f ; 50int elements = 0 ; 51float stddev = 0.0f ; 52float active = 0.0f ; 53float entropy = 0.0f ; 54float zd = 0.0f ; 55float cossim = 0.0f ; 56}; 57 58class IMatrixCollector { 59public : 60IMatrixCollector ()= default ; 61void set_params (common_params params ) {m_params = std::move (params ); } 62bool collect_imatrix (struct ggml_tensor * t ,bool ask ,void * user_data ); 63void save_imatrix_legacy (int32_t ncall = -1 )const ; 64void save_imatrix (int32_t n_chunk = -1 )const ; 65bool load_imatrix (const char * file_name ); 66const std::unordered_map < std::string ,Stats > & get_mstats ()const {return m_stats ; } 67private : 68 std::unordered_map < std::string ,Stats > m_stats ; 69common_params m_params ; 70 std::mutex m_mutex ; 71 std::vector < std::string > m_datasets ; 72int32_t m_last_chunk = 0 ; 73 std::vector < char > m_src1_data ; 74 std::vector < char > m_ids ;// the expert ids from ggml_mul_mat_id 75}; 76 77// remove any prefix and suffixes from the name 78// CUDA0#blk.0.attn_k.weight#0 => blk.0.attn_k.weight 79static std::string filter_tensor_name (const char * name ) { 80 std::string wname ; 81const char * p = strchr (name ,'#' ); 82if (p != NULL ) { 83p = p + 1 ; 84const char * q = strchr (p ,'#' ); 85if (q != NULL ) { 86wname = std::string (p ,q - p ); 87 }else { 88wname = p ; 89 } 90 }else { 91wname = name ; 92 } 93return wname ; 94} 95 96static void process_tensor_name (const std::string & input , std::string & layer , std::string & tensor ) { 97 std::vector < std::string > name ; 98 std::istringstream stream (input ); 99 std::string item ; 100 101while (std::getline (stream ,item ,'.' )) { 102name .push_back (item ); 103 } 104for (size_t i = 0 ;i < name .size ();++ i ) { 105if (name [i ]== "blk" && i + 1 < name .size ()) { 106layer = name [i + 1 ]; 107break ; 108 } 109 } 110for (size_t i = 0 ;i < name .size ();++ i ) { 111if (name [i ]== "weight" && i > 0 ) { 112tensor = name [i - 1 ]; 113break ; 114 } 115 } 116 117if (tensor .empty ()) { 118tensor = input ; 119 } 120if (layer .empty ()) { 121layer = "-" ; 122 } 123} 124 125static void compute_statistics (std::vector < tensor_statistics > & tstats ,const std::string & name ,const Stats & e ) { 126if (e .values .size () %e .counts .size ()!= 0 ) { 127LOG_ERR ("%s: activation size mismatch for tensor %s (%zu vs %zu)\n" ,__func__ ,name .c_str (),e .counts .size (),e .values .size ()); 128return ; 129 } 130if (e .counts .empty ()) { 131LOG_ERR ("%s: there are no activations for tensor %s. The imatrix may be suboptimal\n" ,__func__ ,name .c_str ()); 132return ; 133 } 134 135const int n_mat = e .counts .size (); 136const int row_size = e .values .size () /n_mat ; 137 138 std::vector < float > activations ; 139activations .reserve (e .values .size ()); 140 141for (int i = 0 ;i < n_mat ;++ i ) { 142if (e .counts [i ]== 0 ) { 143LOG_DBG ("%s: skipping tensor %s due to zero count at index %d\n" ,__func__ ,name .c_str (),i ); 144continue ; 145 } 146for (int j = 0 ;j < row_size ;++ j ) { 147activations .push_back (e .values [i * row_size + j ] /e .counts [i ]); 148 } 149 } 150 151if (activations .empty ()) { 152LOG_ERR ("%s: all counts are zero for tensor %s, skipping statistics computation\n" ,__func__ ,name .c_str ()); 153return ; 154 } 155 156const float act_total = std::accumulate (activations .begin (),activations .end (),0.0f ); 157const float act_max = * std::max_element (activations .begin (),activations .end ()); 158const float act_min = * std::min_element (activations .begin (),activations .end ()); 159const float act_mean = act_total /activations .size (); 160const float act_sqr_total = std::inner_product (activations .begin (),activations .end (),activations .begin (),0.0f ); 161const float act_var = (act_sqr_total /activations .size ())- (act_mean * act_mean ); 162const float act_dev = std::sqrt (std::max (0.0f ,act_var )); 163float threshold = 1e-5f ; 164const int inactive_count = std::count_if (activations .begin (),activations .end (), 165 [threshold ](const float v ) {return fabsf (v ) <=threshold ; }); 166const float active_ratio = 1 - static_cast < float > (inactive_count ) /activations .size (); 167 168float entropy = 0 ; 169if (act_total > 0 ) { 170for (const auto act :activations ) { 171if (const float p = act /act_total ;p > 0 ) { 172entropy -= p * std::log2 (p ); 173 } 174 } 175 } 176 177int z_score = 0 ; 178if (act_dev > 0.0f ) { 179for (const auto act :activations ) { 180if (const float p = (act - act_mean ) /act_dev ;p > 1 ) { 181z_score ++ ; 182 } 183 } 184 } 185 186auto & ts = tstats .emplace_back (); 187ts .tensor = name ; 188ts .stats = e ; 189ts .total_sqract = act_total ; 190ts .mean_sqract = act_mean ; 191ts .max_sqract = act_max ; 192ts .min_sqract = act_min ; 193ts .elements = static_cast < int > (activations .size ()); 194ts .stddev = act_dev ; 195ts .active = active_ratio ; 196ts .entropy = entropy ; 197ts .zd = static_cast < float > (z_score ) /ts .elements ; 198} 199 200static void compute_cossim (std::vector < tensor_statistics > & tstats ) { 201static const std::regex pattern (R"(blk\.(\d+)\.)" ); 202for (auto & ts :tstats ) { 203if (std::smatch match ; std::regex_search (ts .tensor ,match ,pattern )) { 204const int blk = std::stoi (match [1 ]); 205 std::string tname (ts .tensor ); 206tname .replace (match .position (1 ),match .length (1 ), std::to_string (blk - 1 )); 207auto prev = std::find_if (tstats .begin (),tstats .end (), 208 [tname ](const tensor_statistics & t ) {return t .tensor == tname ; }); 209if (prev != tstats .end ()) { 210const float dp = std::inner_product (ts .stats .values .begin (),ts .stats .values .end (), 211prev -> stats .values .begin (),0.0f ); 212const float curr_mag = std::sqrt (std::inner_product (ts .stats .values .begin (),ts .stats .values .end (), 213ts .stats .values .begin (),0.0f )); 214const float prev_mag = std::sqrt (std::inner_product (prev -> stats .values .begin (),prev -> stats .values .end (), 215prev -> stats .values .begin (),0.0f )); 216const float cs = dp / (curr_mag * prev_mag ); 217ts .cossim = cs ; 218 } 219 }else { 220ts .cossim = 0 ; 221 } 222 } 223} 224 225static bool all_finite (const float * v ,size_t n ) { 226for (size_t i = 0 ;i < n ;++ i ) { 227if (!std::isfinite (v [i ])) { 228return false; 229 } 230 } 231return true; 232} 233 234bool IMatrixCollector ::collect_imatrix (struct ggml_tensor * t ,bool ask ,void * user_data ) { 235GGML_UNUSED (user_data ); 236 237const struct ggml_tensor * src0 = t -> src [0 ]; 238const struct ggml_tensor * src1 = t -> src [1 ]; 239 std::string wname = filter_tensor_name (src0 -> name ); 240 241const int32_t chunk_size = m_params .n_ctx /m_params .n_parallel ; 242 243// when ask is true, the scheduler wants to know if we are interested in data from this tensor 244// if we return true, a follow-up call will be made with ask=false in which we can do the actual collection 245if (ask ) { 246if (t -> op == GGML_OP_MUL_MAT_ID )return true;// collect all indirect matrix multiplications 247if (t -> op != GGML_OP_MUL_MAT )return false; 248// why are small batches ignored (<16 tokens)? 249if (src1 -> ne [1 ]< 16 || src1 -> type != GGML_TYPE_F32 )return false; 250if (!(wname .substr (0 ,4 )== "blk." || (m_params .process_output && wname == "output.weight" )))return false; 251return true; 252 } 253 254 std::lock_guard < std::mutex > lock (m_mutex ); 255 256// copy the data from the GPU memory if needed 257const bool is_host = ggml_backend_buffer_is_host (src1 -> buffer ); 258 259if (!is_host ) { 260const size_t src1_nbytes = ggml_nbytes (src1 ); 261m_src1_data .resize (src1_nbytes ); 262ggml_backend_tensor_get (src1 ,m_src1_data .data (),0 ,src1_nbytes ); 263 } 264 265const char * data = is_host ? (const char * )src1 -> data :m_src1_data .data (); 266GGML_ASSERT (src1 -> nb [0 ]== ggml_element_size (src1 )); 267 268// this has been adapted to the new format of storing merged experts in a single 3d tensor 269// ref: https://github.com/ggml-org/llama.cpp/pull/6387 270if (t -> op == GGML_OP_MUL_MAT_ID ) { 271// ids -> [n_experts_used, n_tokens] 272// src1 -> [cols, n_expert_used, n_tokens] 273const ggml_tensor * ids = t -> src [2 ]; 274const int64_t n_as = src0 -> ne [2 ]; 275const int64_t n_ids = ids -> ne [0 ]; 276 277// the top-k selected expert ids are stored in the ids tensor 278// for simplicity, always copy ids to host, because it is small 279// take into account that ids is not contiguous! 280 281GGML_ASSERT (ids -> ne [1 ]== src1 -> ne [2 ]); 282 283// the extra dimension would need to be stored somewhere to be reflected in the imatrix file 284if (ggml_nrows (src1 )!= src1 -> ne [1 ]* src1 -> ne [2 ]) { 285LOG_ERR ("%s: tensor has more than 3 dimensions: %s" ,__func__ ,wname .c_str ()); 286GGML_ASSERT (false); 287 } 288 289m_ids .resize (ggml_nbytes (ids )); 290ggml_backend_tensor_get (ids ,m_ids .data (),0 ,ggml_nbytes (ids )); 291 292auto & e = m_stats [wname ]; 293 294if (e .counts .size ()== 1 && n_as > 1 ) { 295// broadcast, when loading an old imatrix 296e .counts .resize (n_as ,e .counts [0 ]); 297 } 298if (e .values .empty ()) { 299e .values .resize (src1 -> ne [0 ]* n_as ,0 ); 300e .counts .resize (n_as ,0 ); 301 } 302else if (e .values .size ()!= (size_t )src1 -> ne [0 ]* n_as ) { 303LOG_ERR ("%s: inconsistent size for %s (%d vs %d)\n" ,__func__ ,wname .c_str (), (int )e .values .size (), (int )(src1 -> ne [0 ]* n_as )); 304exit (1 );//GGML_ABORT("fatal error"); 305 } 306else if (e .counts .size ()!= (size_t )n_as ) { 307LOG_ERR ("%s: inconsistent expert count for %s (%d vs %d)\n" ,__func__ ,wname .c_str (), (int )e .counts .size (), (int )n_as ); 308exit (1 );//GGML_ABORT("fatal error"); 309 } 310LOG_DBGV (2 ,"%s[%d]: %32s, %s, %5d x %5d, %d\n" ,__func__ ,m_last_chunk ,wname .c_str (),ggml_op_name (t -> op ), (int )src1 -> ne [0 ], (int )src1 -> ne [2 ], (int )src1 -> type ); 311 312const int64_t ne0 = src1 -> ne [0 ]; 313const int64_t n_tokens = src1 -> ne [2 ]; 314 315// single pass over the routing ids 316 std::vector < uint8_t > touched (n_as ,0 ); 317for (int64_t idx = 0 ;idx < n_ids ;++ idx ) { 318for (int64_t row = 0 ;row < n_tokens ;++ row ) { 319const int32_t ex = * (const int32_t * ) (m_ids .data ()+ row * ids -> nb [1 ]+ idx * ids -> nb [0 ]); 320 321GGML_ASSERT (ex >=0 && ex < n_as );// sanity check 322 323const int64_t i11 = idx %src1 -> ne [1 ]; 324const float * x = (const float * ) (data + i11 * src1 -> nb [1 ]+ row * src1 -> nb [2 ]); 325float * acc = e .values .data ()+ ex * ne0 ; 326 327e .counts [ex ]++ ; 328touched [ex ]= 1 ; 329for (int64_t j = 0 ;j < ne0 ;++ j ) { 330acc [j ]+= x [j ]* x [j ]; 331 } 332 } 333 } 334 335// check for non-finite values, only checking experts that were routed to and touched 336for (int64_t ex = 0 ;ex < n_as ;++ ex ) { 337if (touched [ex ]&& !all_finite (e .values .data ()+ ex * ne0 ,ne0 )) { 338LOG_ERR ("%s: non-finite values detected in %s\n" ,__func__ ,wname .c_str ()); 339exit (1 ); 340 } 341 } 342 343for (int64_t ex = 0 ;ex < n_as ;++ ex ) { 344const int32_t n_chunk = e .counts [ex ] /chunk_size ; 345if (n_chunk > m_last_chunk ) { 346const int32_t chunk_step = n_chunk - m_last_chunk ; 347m_last_chunk = n_chunk ; 348if ((m_last_chunk %m_params .n_out_freq ) /chunk_step == 0 ) { 349save_imatrix (); 350 } 351if (m_params .n_save_freq > 0 && (m_last_chunk %m_params .n_save_freq ) /chunk_step == 0 ) { 352save_imatrix (m_last_chunk ); 353 } 354 } 355 } 356 }else { 357auto & e = m_stats [wname ]; 358const int64_t n_mat = src0 -> ne [2 ]* src0 -> ne [3 ]; 359 360// use a single count per dense tensor 361// (necessary when merging older GGUF-imatrix files with 3d tensors) 362if (e .counts .size ()> 1 ) { 363bool all_equal = true; 364for (size_t i = 1 ;i < e .counts .size ();++ i ) { 365if (e .counts [0 ]!= e .counts [i ]) { 366all_equal = false; 367break ; 368 } 369 } 370if (all_equal ) { 371e .counts .resize (1 ); 372 } 373 } 374if (e .values .empty ()) { 375e .values .resize (src1 -> ne [0 ]* n_mat ,0 ); 376e .counts .resize (1 ,0 ); 377 } 378else if (e .values .size ()!= (size_t )(src1 -> ne [0 ]* n_mat )) { 379LOG_ERR ("%s: inconsistent size for %s (%d vs %d)\n" ,__func__ ,wname .c_str (), (int )e .values .size (), (int )(src1 -> ne [0 ]* n_mat )); 380exit (1 );//GGML_ABORT("fatal error"); 381 } 382LOG_DBGV (2 ,"%s[%d]: %32s, %s, %5d x %5d x %5d, %d\n" ,__func__ ,m_last_chunk ,wname .c_str (),ggml_op_name (t -> op ), (int )src1 -> ne [0 ], (int )src1 -> ne [1 ], (int )src1 -> ne [2 ], (int )src1 -> type ); 383 384const int64_t ne0 = src1 -> ne [0 ]; 385 386for (int64_t i3 = 0 ;i3 < src1 -> ne [3 ];++ i3 ) { 387for (int64_t i2 = 0 ;i2 < src1 -> ne [2 ];++ i2 ) { 388// handle 3D+ tensors, but flatten 3D+ activations when model tensor is 2D 389const int64_t mat_id = (i3 %src0 -> ne [3 ])* src0 -> ne [2 ]+ (i2 %src0 -> ne [2 ]); 390float * acc = e .values .data ()+ mat_id * ne0 ; 391 392for (int64_t row = 0 ;row < src1 -> ne [1 ];++ row ) { 393const float * x = (const float * ) (data + row * src1 -> nb [1 ]+ i2 * src1 -> nb [2 ]+ i3 * src1 -> nb [3 ]); 394for (int64_t j = 0 ;j < ne0 ;++ j ) { 395acc [j ]+= x [j ]* x [j ]; 396 } 397 } 398 } 399 } 400 401// check for non-finite values 402if (!all_finite (e .values .data (),e .values .size ())) { 403LOG_ERR ("%s: non-finite values detected in %s\n" ,__func__ ,wname .c_str ()); 404exit (1 ); 405 } 406// only 1 count in practice, except when a tensor is used for both MUL_MAT_ID and MUL_MAT 407for (size_t i = 0 ;i < e .counts .size ();++ i ) { 408e .counts [i ]+= ggml_nrows (src1 ) /n_mat ; 409const int32_t n_chunk = e .counts [i ] /chunk_size ; 410if (n_chunk > m_last_chunk ) { 411const int32_t chunk_step = n_chunk - m_last_chunk ; 412m_last_chunk = n_chunk ; 413if ((m_last_chunk %m_params .n_out_freq ) /chunk_step == 0 ) { 414save_imatrix (); 415 } 416if (m_params .n_save_freq > 0 && (m_last_chunk %m_params .n_save_freq ) /chunk_step == 0 ) { 417save_imatrix (m_last_chunk ); 418 } 419 } 420 } 421 } 422 423return true; 424} 425 426void IMatrixCollector ::save_imatrix_legacy (int32_t ncall )const { 427auto fname = m_params .out_file ; 428 429if (ncall > 0 ) { 430fname += ".at_" ; 431fname += std::to_string (ncall ); 432 } 433 434// warn when writing imatrix entries that do not have full data 435// this can happen with MoE models where some of the experts end up not being exercised by the provided training data 436 437int n_entries = 0 ; 438 std::vector < std::string > to_store ; 439 440bool is_first = true;// for printing 441for (const auto & kv :m_stats ) { 442const int n_all = kv .second .counts .size (); 443 444if (n_all == 0 ) { 445continue ; 446 } 447 448int n_zeros = 0 ; 449for (const int c :kv .second .counts ) { 450if (c == 0 ) { 451n_zeros ++ ; 452 } 453 } 454 455if (n_zeros != 0 && is_first ) { 456LOG_INF ("\n" ); 457is_first = false; 458 } 459 460if (n_zeros == n_all ) { 461LOG_WRN ("%s: entry '%40s' has no data - skipping\n" ,__func__ ,kv .first .c_str ()); 462continue ; 463 } 464 465if (n_zeros > 0 ) { 466LOG_WRN ("%s: entry '%40s' has partial data (%.2f%%)\n" ,__func__ ,kv .first .c_str (),100.0f * (n_all - n_zeros ) /n_all ); 467 } 468 469n_entries ++ ; 470to_store .push_back (kv .first ); 471 } 472 473if (to_store .size ()< m_stats .size ()) { 474LOG_WRN ("%s: storing only %zu out of %zu entries\n" ,__func__ ,to_store .size (),m_stats .size ()); 475 } 476 477// deterministic tensor name order 478 std::sort (to_store .begin (),to_store .end ()); 479 480const int32_t chunk_size = m_params .n_ctx /m_params .n_parallel ; 481 482 std::ofstream out (fname , std::ios::binary ); 483out .write ((const char * )& n_entries ,sizeof (n_entries )); 484for (const auto & name :to_store ) { 485const auto & stat = m_stats .at (name ); 486const int32_t len = name .size (); 487out .write ((const char * )& len ,sizeof (len )); 488out .write (name .c_str (),len ); 489// ceiling division to avoid accidental zeros 490const int32_t ncall = (* std::max_element (stat .counts .begin (),stat .counts .end ())+ (chunk_size - 1 )) /chunk_size ; 491out .write ((const char * )& ncall ,sizeof (ncall )); 492const int32_t nval = stat .values .size (); 493const int32_t nmat = stat .counts .size (); 494out .write ((const char * )& nval ,sizeof (nval )); 495if (nval > 0 && nmat > 0 ) { 496 std::vector < float > tmp (nval ); 497for (int32_t i = 0 ;i < nval ;i ++ ) { 498float count = static_cast < float > (stat .counts [i / (nval /nmat )]); 499float value = stat .values [i ]; 500if (count == 0.0f ) { 501// store 1 for partial data 502value = 1.0f ; 503count = 1.0f ; 504 } 505tmp [i ]= (value /count )* static_cast < float > (ncall ); 506 } 507out .write ((const char * )tmp .data (),nval * sizeof (float )); 508 } 509 } 510 511// Write the number of call the matrix was computed with 512out .write ((const char * )& m_last_chunk ,sizeof (m_last_chunk )); 513 514// Write the input filename at the end of the file to later on specify it in quantize 515 { 516const char * dataset_file = m_params .prompt_file .c_str (); 517int32_t len = m_params .prompt_file .size (); 518// When there is no prompt but there were other imatrix files loaded, use the last dataset 519if (m_params .prompt_file .empty ()&& !m_datasets .empty ()) { 520const std::string & dataset_str = m_datasets [m_datasets .size ()- 1 ]; 521dataset_file = dataset_str .c_str (); 522len = dataset_str .size (); 523 } 524out .write ((const char * )& len ,sizeof (len )); 525out .write (dataset_file ,len ); 526 } 527 528LOGV (1 ,"\n" ); 529LOG_DBGV (1 ,"%s: stored collected data after %d chunks in %s\n" ,__func__ ,m_last_chunk ,fname .c_str ()); 530} 531 532void IMatrixCollector ::save_imatrix (int32_t n_chunk )const { 533auto fname = m_params .out_file ; 534int8_t use_legacy_format = m_params .imat_dat ; 535 536if (use_legacy_format > 0 ) { 537this -> save_imatrix_legacy (n_chunk ); 538return ; 539 } 540// only warn when `--output-format gguf` is not specified 541if (use_legacy_format == 0 && !string_ends_with (fname ,".gguf" )) { 542LOG_WRN ("\n%s: saving imatrix using GGUF format with a different suffix than .gguf\n" ,__func__ ); 543LOG_WRN ("%s: if you want the previous imatrix format, use --output-format dat\n" ,__func__ ); 544 } 545 546if (n_chunk > 0 ) { 547fname += ".at_" ; 548fname += std::to_string (n_chunk ); 549 } 550 551// write imatrix entries even if they don't have full data. (can be corrected when reading) 552// this can happen with MoE models where some of the experts end up not being exercised by the provided training data 553 554 std::vector < std::string > to_store ; 555size_t data_size = 0 ; 556 557bool is_first = true;// for printing 558for (const auto & kv :m_stats ) { 559const int n_all = kv .second .counts .size (); 560 561int n_zeros = 0 ; 562for (const auto c :kv .second .counts ) { 563if (c == 0 ) { 564n_zeros ++ ; 565 } 566 } 567 568if (n_zeros != 0 && is_first ) { 569LOG_INF ("\n" ); 570is_first = false; 571 } 572 573if (n_zeros > 0 ) { 574LOG_WRN ("%s: entry '%40s' has partial data (%.2f%%)\n" ,__func__ ,kv .first .c_str (),100.0f * (n_all - n_zeros ) /n_all ); 575 } 576 577to_store .push_back (kv .first ); 578data_size += GGML_PAD (ggml_tensor_overhead ()+ sizeof (float )* kv .second .values .size (),GGML_MEM_ALIGN ); 579data_size += GGML_PAD (ggml_tensor_overhead ()+ sizeof (float )* kv .second .counts .size (),GGML_MEM_ALIGN ); 580 } 581 582// deterministic tensor name order 583 std::sort (to_store .begin (),to_store .end ()); 584 585struct ggml_init_params params = { 586/* .mem_size = */ data_size , 587/* .mem_buffer = */ NULL , 588/* .no_alloc = */ false, 589 }; 590struct ggml_context * ctx = ggml_init (params ); 591struct gguf_context * ctx_gguf = gguf_init_empty (); 592 593 { 594 std::vector < const char *> datasets ; 595datasets .reserve (m_datasets .size ()+ 1 ); 596for (size_t i = 0 ;i < m_datasets .size ();++ i ) { 597datasets .push_back (m_datasets [i ].c_str ()); 598 } 599if (!m_params .prompt_file .empty ()) { 600datasets .push_back (m_params .prompt_file .c_str ()); 601 } 602 603gguf_set_val_str (ctx_gguf ,"general.type" ,"imatrix" ); 604// Write the dataset paths 605gguf_set_arr_str (ctx_gguf ,LLM_KV_IMATRIX_DATASETS ,datasets .data (),datasets .size ()); 606// Write the number of chunks the matrix was computed with 607gguf_set_val_u32 (ctx_gguf ,LLM_KV_IMATRIX_CHUNK_COUNT ,m_last_chunk ); 608gguf_set_val_u32 (ctx_gguf ,LLM_KV_IMATRIX_CHUNK_SIZE ,m_params .n_ctx /m_params .n_parallel ); 609 } 610 611for (const auto & name :to_store ) { 612const auto & stat = m_stats .at (name ); 613const int32_t nval = (int32_t )stat .values .size (); 614const int32_t nmat = (int32_t )stat .counts .size (); 615if (nval > 0 && nmat > 0 ) { 616struct ggml_tensor * in_sum2 = ggml_new_tensor_2d (ctx ,GGML_TYPE_F32 ,nval /nmat ,nmat ); 617struct ggml_tensor * counts = ggml_new_tensor_2d (ctx ,GGML_TYPE_F32 ,1 ,nmat ); 618ggml_format_name (in_sum2 ,"%s.in_sum2" ,name .c_str ()); 619ggml_format_name (counts ,"%s.counts" ,name .c_str ()); 620 621for (int32_t j = 0 ;j < nval ;++ j ) { 622 ((float * )in_sum2 -> data )[j ]= (float )stat .values [j ]; 623 } 624for (int32_t j = 0 ;j < nmat ;++ j ) { 625 ((float * )counts -> data )[j ]= (float )stat .counts [j ]; 626 } 627 628gguf_add_tensor (ctx_gguf ,in_sum2 ); 629gguf_add_tensor (ctx_gguf ,counts ); 630 } 631 } 632 633gguf_write_to_file (ctx_gguf ,fname .c_str (), false); 634 635LOGV (1 ,"\n" ); 636LOG_DBGV (1 ,"%s: stored collected data after %d chunks in %s\n" ,__func__ ,m_last_chunk ,fname .c_str ()); 637 638gguf_free (ctx_gguf ); 639ggml_free (ctx ); 640} 641 642bool IMatrixCollector ::load_imatrix (const char * file_name ) { 643common_imatrix loaded ; 644if (!common_imatrix_load (file_name ,loaded )) { 645return false; 646 } 647 648const int32_t chunk_size = m_params .n_ctx /m_params .n_parallel ; 649const bool is_legacy = loaded .is_legacy ; 650 651for (auto & [name ,entry ] :loaded .entries ) { 652auto & e = m_stats [name ]; 653 654if (is_legacy ) { 655// Legacy format: sums contain (raw_sum/raw_count)*ncall, counts contain {ncall} 656// Reconstruct raw form by multiplying by chunk_size 657if (e .values .empty ()) { 658e .values .resize (entry .sums .size (),0.0f ); 659e .counts .resize (1 ,0 ); 660 } 661for (size_t j = 0 ;j < entry .sums .size ();++ j ) { 662e .values [j ]+= entry .sums [j ]* chunk_size ; 663 } 664for (size_t j = 0 ;j < e .counts .size ();++ j ) { 665e .counts [j ]+= entry .counts [0 ]* chunk_size ; 666 } 667 }else { 668// GGUF format: raw sums and counts, accumulate directly 669const int64_t nval = entry .sums .size (); 670const int64_t ncounts = entry .counts .size (); 671 672if (e .values .empty ()) { 673e .values .resize (nval ,0.0f ); 674 }else if ((size_t )nval != e .values .size ()) { 675LOG_ERR ("%s: mismatched sums size for %s: %zu != %zu\n" ,__func__ ,name .c_str (), (size_t )nval ,e .values .size ()); 676return false; 677 } 678 679if (e .counts .empty ()) { 680e .counts .resize (ncounts ,0 ); 681 }else if (e .counts .size ()== 1 && ncounts > 1 ) { 682e .counts .resize (ncounts ,e .counts [0 ]); 683 }else if ((size_t )ncounts != e .counts .size ()) { 684LOG_ERR ("%s: mismatched counts size for %s: %zu != %zu\n" ,__func__ ,name .c_str (), (size_t )ncounts ,e .counts .size ()); 685return false; 686 } 687 688for (int64_t j = 0 ;j < nval ;++ j ) { 689e .values [j ]+= entry .sums [j ]; 690 } 691for (int64_t j = 0 ;j < ncounts ;++ j ) { 692e .counts [j ]+= entry .counts [j ]; 693 } 694 } 695 } 696 697m_datasets .insert (m_datasets .end (),loaded .datasets .begin (),loaded .datasets .end ()); 698 699// Calculate the last chunk count 700int64_t max_count = 0 ; 701for (const auto & stats :m_stats ) { 702for (int64_t count :stats .second .counts ) { 703if (count > max_count ) { 704max_count = count ; 705 } 706 } 707 } 708m_last_chunk = max_count /chunk_size ; 709 710return true; 711} 712 713static IMatrixCollector g_collector ; 714 715static bool ik_collect_imatrix (struct ggml_tensor * t ,bool ask ,void * user_data ) { 716return g_collector .collect_imatrix (t ,ask ,user_data ); 717} 718 719struct results_log_softmax { 720double log_softmax ; 721float logit ; 722float prob ; 723}; 724 725static std::vector < float > softmax (const std::vector < float > & logits ) { 726 std::vector < float > probs (logits .size ()); 727float max_logit = logits [0 ]; 728for (float v :logits ) { 729max_logit = std::max (max_logit ,v ); 730 } 731double sum_exp = 0.0 ; 732for (size_t i = 0 ;i < logits .size ();i ++ ) { 733// Subtract the maximum logit value from the current logit value for numerical stability 734const float logit = logits [i ]- max_logit ; 735const float exp_logit = expf (logit ); 736sum_exp += exp_logit ; 737probs [i ]= exp_logit ; 738 } 739for (size_t i = 0 ;i < probs .size ();i ++ ) { 740probs [i ] /=sum_exp ; 741 } 742return probs ; 743} 744 745static results_log_softmax log_softmax (int n_vocab ,const float * logits ,int tok ) { 746float max_logit = logits [0 ]; 747for (int i = 1 ;i < n_vocab ;++ i ) { 748max_logit = std::max (max_logit ,logits [i ]); 749 } 750double sum_exp = 0.0 ; 751for (int i = 0 ;i < n_vocab ;++ i ) { 752sum_exp += expf (logits [i ]- max_logit ); 753 } 754return {logits [tok ]- max_logit - log (sum_exp ),logits [tok ],expf (logits [tok ]- max_logit ) / (float )sum_exp }; 755} 756 757static void process_logits ( 758int n_vocab ,const float * logits ,const int * tokens ,int n_token , std::vector < std::thread > & workers , 759double & nll ,double & nll2 ,float * logit_history ,float * prob_history ) { 760 std::mutex mutex ; 761int counter = 0 ; 762auto compute = [& mutex ,& counter ,& nll ,& nll2 ,logit_history ,prob_history ,n_vocab ,logits ,tokens ,n_token ] () { 763double local_nll = 0 ; 764double local_nll2 = 0 ; 765while (true) { 766 std::unique_lock < std::mutex > lock (mutex ); 767int i = counter ++ ; 768if (i >=n_token ) { 769nll += local_nll ;nll2 += local_nll2 ; 770break ; 771 } 772lock .unlock (); 773const results_log_softmax results = log_softmax (n_vocab ,logits + i * n_vocab ,tokens [i + 1 ]); 774const double v = - results .log_softmax ; 775local_nll += v ; 776local_nll2 += v * v ; 777 778logit_history [i ]= results .logit ; 779prob_history [i ]= results .prob ; 780 } 781 }; 782for (auto & w :workers ) { 783w = std::thread (compute ); 784 } 785compute (); 786for (auto & w :workers ) { 787w .join (); 788 } 789} 790 791static bool compute_imatrix (llama_context * ctx ,const common_params & params ,const int32_t n_ctx ) { 792const llama_model * model = llama_get_model (ctx ); 793const llama_vocab * vocab = llama_model_get_vocab (model ); 794 795const bool add_bos = llama_vocab_get_add_bos (vocab ); 796 797if (llama_pooling_type (ctx )!= LLAMA_POOLING_TYPE_LAST ) { 798GGML_ASSERT (!llama_vocab_get_add_eos (vocab )); 799 } 800 801auto tim1 = std::chrono::high_resolution_clock::now (); 802LOG_INF ("%s: tokenizing the input ..\n" ,__func__ ); 803 804 std::vector < llama_token > tokens = common_tokenize (ctx ,params .prompt , true,params .parse_special ); 805 806auto tim2 = std::chrono::high_resolution_clock::now (); 807LOG_INF ("%s: tokenization took %g ms\n" ,__func__ ,1e-3 * std::chrono::duration_cast < std::chrono::microseconds > (tim2 - tim1 ).count ()); 808 809if (params .i_chunk > 0 ) { 810if (size_t ((params .i_chunk + 2 )* n_ctx ) >=tokens .size ()) { 811LOG_ERR ("%s: there will be not enough tokens left after removing %d chunks\n" ,__func__ ,params .i_chunk ); 812return false; 813 } 814LOG_INF ("%s: removing initial %d chunks (%d tokens)\n" ,__func__ ,params .i_chunk ,params .i_chunk * n_ctx ); 815tokens .erase (tokens .begin (),tokens .begin ()+ params .i_chunk * n_ctx ); 816 } 817 818if (int (tokens .size ())< 2 * n_ctx ) { 819LOG_ERR ("%s: you need at least %d tokens for a context of %d tokens\n" ,__func__ ,2 * n_ctx ,n_ctx ); 820LOG_ERR ("%s: the data file you provided tokenizes to only %zu tokens\n" ,__func__ ,tokens .size ()); 821return false; 822 } 823 824 std::vector < float > logit_history ; 825 std::vector < float > prob_history ; 826 827if (params .compute_ppl ) { 828logit_history .resize (tokens .size ()); 829prob_history .resize (tokens .size ()); 830 } 831 832const int n_chunk_max = tokens .size () /n_ctx ; 833 834const int n_chunk = params .n_chunks < 0 ?n_chunk_max : std::min (params .n_chunks ,n_chunk_max ); 835const int n_vocab = llama_vocab_n_tokens (vocab ); 836const int n_batch = params .n_batch ; 837 838int count = 0 ; 839double nll = 0.0 ; 840double nll2 = 0.0 ; 841 842const int num_batches = (n_ctx + n_batch - 1 ) /n_batch ; 843const int n_seq = std::max (1 ,n_batch /n_ctx ); 844 845GGML_ASSERT (n_batch < n_ctx || n_batch %n_ctx == 0 ); 846GGML_ASSERT (params .n_ctx == n_seq * n_ctx ); 847 848llama_batch batch = llama_batch_init (std::min (n_batch ,n_ctx * n_seq ),0 ,1 ); 849 850 std::vector < float > logits ; 851if (params .compute_ppl && num_batches > 1 ) { 852logits .reserve ((size_t )n_ctx * n_vocab ); 853 } 854 855LOG_INF ("%s: computing over %d chunks, n_ctx=%d, batch_size=%d, n_seq=%d\n" ,__func__ ,n_chunk ,n_ctx ,n_batch ,n_seq ); 856 857 std::vector < std::thread > workers (std::thread::hardware_concurrency ()- 1 ); 858 859for (int i = 0 ;i < n_chunk ;i += n_seq ) { 860const int start = i * n_ctx ; 861const int end = start + n_ctx ; 862 863const int n_seq_batch = std::min (n_seq ,n_chunk - i ); 864 865const auto t_start = std::chrono::high_resolution_clock::now (); 866 867// clear the KV cache 868llama_memory_clear (llama_get_memory (ctx ), true); 869 870for (int j = 0 ;j < num_batches ;++ j ) { 871const int batch_start = start + j * n_batch ; 872const int batch_size = std::min (end - batch_start ,n_batch ); 873 874// clear the batch 875common_batch_clear (batch ); 876 877for (int seq = 0 ;seq < n_seq_batch ;seq ++ ) { 878int seq_start = batch_start + seq * n_ctx ; 879 880// save original token and restore it after eval 881const auto token_org = tokens [seq_start ]; 882 883// add BOS token for the first batch of each chunk 884if (add_bos && j == 0 ) { 885tokens [seq_start ]= llama_vocab_bos (vocab ); 886 } 887for (int k = 0 ;k < batch_size ;++ k ) { 888// NOTE: specifying all logits to get activations for the output.weight tensor 889// and also for the perplexity calculation. 890// TODO: only get outputs when (params.process_output || params.compute_ppl) 891// (not possible when this skips FFN computation of the last layer) 892common_batch_add (batch ,tokens [seq_start + k ],j * n_batch + k , {seq }, true); 893 } 894 895// restore the original token in case it was set to BOS 896tokens [seq_start ]= token_org ; 897 } 898 899if (llama_decode (ctx ,batch )) { 900LOG_ERR ("%s : failed to eval\n" ,__func__ ); 901llama_batch_free (batch ); 902return false; 903 } 904 905if (params .compute_ppl && num_batches > 1 ) { 906const auto * batch_logits = llama_get_logits (ctx ); 907logits .insert (logits .end (),batch_logits ,batch_logits + batch_size * n_vocab ); 908 } 909 } 910 911 912if (i == 0 ) { 913llama_synchronize (ctx ); 914const auto t_end = std::chrono::high_resolution_clock::now (); 915const float t_total = std::chrono::duration < float > (t_end - t_start ).count (); 916LOG_INF ("%s: %.2f seconds per pass - ETA " ,__func__ ,t_total ); 917int total_seconds = (int )(t_total * n_chunk /n_seq ); 918if (total_seconds >=60 * 60 ) { 919LOG ("%d hours " ,total_seconds / (60 * 60 )); 920total_seconds = total_seconds % (60 * 60 ); 921 } 922LOG ("%.2f minutes\n" ,total_seconds /60.0 ); 923 } 924 925if (params .compute_ppl ) { 926const int first = n_ctx /2 ; 927for (int seq = 0 ;seq < n_seq_batch ;seq ++ ) { 928const float * all_logits = num_batches > 1 ?logits .data () :llama_get_logits_ith (ctx ,seq * n_ctx ); 929 930llama_token * tokens_data = tokens .data ()+ start + seq * n_ctx + first ; 931 932process_logits (n_vocab ,all_logits + first * n_vocab , 933tokens_data ,n_ctx - 1 - first , 934workers ,nll ,nll2 , 935logit_history .data ()+ start + seq * n_ctx + first , 936prob_history .data ()+ start + seq * n_ctx + first ); 937 938count += n_ctx - first - 1 ; 939 940LOG ("[%d]%.4lf," ,i + seq + 1 , std::exp (nll /count )); 941 } 942fflush (stdout ); 943 944logits .clear (); 945 } 946 } 947 948LOG ("\n" ); 949 950if (params .compute_ppl ) { 951nll2 /=count ; 952nll /=count ; 953const double ppl = exp (nll ); 954nll2 -= nll * nll ; 955if (nll2 > 0 ) { 956nll2 = sqrt (nll2 /(count - 1 )); 957LOG ("Final estimate: PPL = %.4lf +/- %.5lf\n" ,ppl ,nll2 * ppl ); 958 }else { 959LOG ("Unexpected negative standard deviation of log(prob)\n" ); 960 } 961 } 962 963llama_batch_free (batch ); 964 965return true; 966} 967 968static bool show_statistics (const common_params & params ) { 969 std::vector < tensor_statistics > ts ; 970if (params .in_files .empty ()|| params .in_files .size ()> 1 ) { 971LOG_ERR ("\nError: a single imatrix file is required to compute tensor statistics\n\n" ); 972return false; 973 } 974if (g_collector .load_imatrix (params .in_files [0 ].c_str ())) { 975for (const auto & [name ,stats ] :g_collector .get_mstats ()) { 976compute_statistics (ts ,name ,stats ); 977 } 978 }else { 979LOG_ERR ("\nError: %s is not a valid imatrix file\n\n" ,params .in_files [0 ].c_str ()); 980return false; 981 } 982if (!ts .empty ()) { 983compute_cossim (ts ); 984 }else { 985LOG_ERR ("Error: cannot compute statistics for %s\n\n" ,params .in_files [0 ].c_str ()); 986return false; 987 } 988 989struct tensor_comparer { 990bool operator()(const tensor_statistics & a ,const tensor_statistics & b )const { 991 std::string layer ,name_a ,name_b ; 992 ; 993process_tensor_name (a .tensor ,layer ,name_a ); 994process_tensor_name (b .tensor ,layer ,name_b ); 995return name_a < name_b || (name_a == name_b && a .total_sqract > b .total_sqract ); 996 } 997 }; 998 std::sort (ts .begin (),ts .end (),tensor_comparer ()); 999 1000struct weighted_stats { 1001float weighted_bias = 0.0f ; 1002float weighted_zd = 0.0f ; 1003float weighted_cossim = 0.0f ; 1004int total_elements = 0 ; 1005 }; 1006 std::map < int ,weighted_stats > ws ; 1007 1008LOG_INF ("\nComputing statistics for %s (%d tensors)\n" ,params .in_files [0 ].c_str (),static_cast < int > (ts .size ())); 1009LOG_INF ("\n%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" ," Layer" ," Tensor" ," Σ(Act²)" , 1010" Min" ," Max" ," μ" ," σ" ," % Active" ,"N" ," Entropy" ,"E (norm)" ,"ZD" , 1011" CosSim" ); 1012LOG_INF ( 1013"==============================================================================================================" 1014"===========================================================\n" ); 1015for (const auto & tstat :ts ) { 1016 std::string layer ,name ; 1017process_tensor_name (tstat .tensor ,layer ,name ); 1018 1019int blk ; 1020try { 1021blk = std::stoi (layer ); 1022 }catch (const std::exception & e ) { 1023blk = -1 ;// not a block layer 1024 } 1025 1026const float entropy_norm = (tstat .elements > 0 ) ?100.0f * (tstat .entropy / std::log2 (tstat .elements )) :0.0f ; 1027 1028LOG_INF ("%5s\t%-20s\t%10.2f\t%8.4f\t%11.4f\t%6.2f\t%6.2f\t%8.2f%%\t%6d\t%10.4f\t%6.2f%%\t%10.2f%%\t%8.4f\n" , 1029layer .c_str (),name .c_str (),tstat .total_sqract ,tstat .min_sqract ,tstat .max_sqract ,tstat .mean_sqract , 1030tstat .stddev ,tstat .active * 100.0f ,tstat .elements ,tstat .entropy , 1031entropy_norm ,100.0f * tstat .zd ,tstat .cossim ); 1032 1033const float weighted_bias = tstat .elements * tstat .total_sqract ; 1034const float weighted_zd = tstat .elements * tstat .zd ; 1035const float weighted_cossim = tstat .elements * tstat .cossim ; 1036 1037if (ws .find (blk )!= ws .end ()) { 1038ws [blk ].weighted_bias += weighted_bias ; 1039ws [blk ].weighted_zd += weighted_zd ; 1040ws [blk ].weighted_cossim += weighted_cossim ; 1041ws [blk ].total_elements += tstat .elements ; 1042 }else { 1043weighted_stats temp_ws ; 1044temp_ws .weighted_bias = weighted_bias ; 1045temp_ws .weighted_zd = weighted_zd ; 1046temp_ws .weighted_cossim = weighted_cossim ; 1047temp_ws .total_elements = tstat .elements ; 1048ws [blk ]= temp_ws ; 1049 } 1050 } 1051 1052const int layers = std::count_if (ws .begin (),ws .end (), [](const auto & kv ) {return kv .first >=0 ; }); 1053LOG_INF ("\nComputing weighted average statistics per layer (%d layers)\n" ,layers ); 1054LOG_INF ("\n%s\t%s\t%s\t%s\n" ," Layer" ," μΣ(Act²)" ," μZD" ,"μCosSim" ); 1055LOG_INF ("================================================\n" ); 1056for (const auto & [first ,second ] :ws ) { 1057const auto & layer = first ; 1058const auto & stats = second ; 1059 1060if (stats .total_elements == 0 ) { 1061continue ; 1062 } 1063 1064if (layer >=0 ) { 1065const float bias = stats .weighted_bias /stats .total_elements ; 1066const float zd = stats .weighted_zd /stats .total_elements ; 1067const float cossim = stats .weighted_cossim /stats .total_elements ; 1068 1069LOG_INF ("%5d\t%14.2f\t%10.4f%%\t%6.4f\n" ,layer ,bias ,100.0f * zd ,cossim ); 1070 } 1071 } 1072LOG_INF ("\n" ); 1073 1074return true; 1075} 1076 1077int main (int argc ,char ** argv ) { 1078 std::setlocale (LC_NUMERIC ,"C" ); 1079 1080common_params params ; 1081 1082params .out_file = "imatrix.gguf" ; 1083 1084params .n_ctx = 512 ; 1085params .escape = false; 1086 1087common_init (); 1088 1089if (!common_params_parse (argc ,argv ,params ,LLAMA_EXAMPLE_IMATRIX ,print_usage )) { 1090return 1 ; 1091 } 1092 1093// set_params before show_statistics so load_imatrix has valid n_ctx/n_parallel 1094g_collector .set_params (params ); 1095 1096if (params .show_statistics ) { 1097if (!show_statistics (params )) { 1098return 1 ; 1099 } 1100return 0 ; 1101 } 1102 1103const int32_t n_ctx = params .n_ctx ; 1104 1105if (n_ctx <=0 ) { 1106LOG_ERR ("%s: imatrix tool requires '--ctx-size' > 0\n" ,__func__ ); 1107return 1 ; 1108 } 1109 1110 { 1111const int32_t n_seq = std::max (1 ,params .n_batch /n_ctx ); 1112const int32_t n_kv = n_seq * n_ctx ; 1113 1114params .n_parallel = n_seq ; 1115params .n_ctx = n_kv ; 1116 1117params .n_batch = std::min (params .n_batch ,n_kv ); 1118 } 1119 1120g_collector .set_params (params ); 1121 1122for (const auto & in_file :params .in_files ) { 1123LOG_INF ("%s : loading imatrix from '%s'\n" ,__func__ ,in_file .c_str ()); 1124if (!g_collector .load_imatrix (in_file .c_str ())) { 1125LOG_ERR ("%s : failed to load %s\n" ,__func__ ,in_file .c_str ()); 1126return 1 ; 1127 } 1128 } 1129 1130if (params .prompt .empty ()) { 1131LOG_INF ("No prompt provided; combining precomputed matrices only.\n" ); 1132 1133if (params .in_files .empty ()) { 1134LOG_ERR ("Error: No prompt provided and no precomputed matrices (--in-file) to combine.\n" ); 1135return 1 ; 1136 } 1137 1138if (params .in_files .size ()== 1 ) { 1139LOG_INF ("%s : saving imatrix to '%s'\n" ,__func__ ,params .out_file .c_str ()); 1140 }else if (params .in_files .size ()> 1 ) { 1141LOG_INF ("%s : saving combined imatrix to '%s'\n" ,__func__ ,params .out_file .c_str ()); 1142 } 1143 1144g_collector .save_imatrix (); 1145 1146return 0 ; 1147 } 1148 1149llama_backend_init (); 1150llama_numa_init (params .numa ); 1151 1152// pass the callback to the backend scheduler 1153// it will be executed for each node during the graph computation 1154params .cb_eval = ik_collect_imatrix ; 1155params .cb_eval_user_data = NULL ; 1156params .warmup = false; 1157 1158// init 1159auto llama_init = common_init_from_params (params ); 1160 1161auto * model = llama_init -> model (); 1162auto * ctx = llama_init -> context (); 1163 1164if (model == nullptr || ctx == nullptr ) { 1165LOG_ERR ("%s : failed to init\n" ,__func__ ); 1166return 1 ; 1167 } 1168 1169const int n_ctx_train = llama_model_n_ctx_train (model ); 1170if (params .n_ctx > n_ctx_train ) { 1171LOG_WRN ("%s: model was trained on only %d context tokens (%d specified)\n" , 1172__func__ ,n_ctx_train ,params .n_ctx ); 1173 } 1174 1175// print system information 1176 { 1177LOG_INF ("\n" ); 1178LOG_INF ("%s\n" ,common_params_get_system_info (params ).c_str ()); 1179 } 1180 1181if (!compute_imatrix (ctx ,params ,n_ctx )) { 1182return 1 ; 1183 } 1184 1185g_collector .save_imatrix (); 1186 1187LOG ("\n" ); 1188llama_perf_context_print (ctx ); 1189 1190llama_backend_free (); 1191 1192return 0 ; 1193}