char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
059670428
char/aliceai-t5-moe
1#include "arg.h" 2#include "common.h" 3#include "fit.h" 4#include "log.h" 5#include "llama.h" 6 7#include <algorithm> 8#include <array> 9#include <atomic> 10#include <chrono> 11#include <clocale> 12#include <cmath> 13#include <cstdio> 14#include <cstring> 15#include <ctime> 16#include <fstream> 17#include <mutex> 18#include <random> 19#include <sstream> 20#include <thread> 21#include <vector> 22 23#if defined(_MSC_VER ) 24#pragma warning(disable: 4244 4267) // possible loss of data 25#endif 26 27struct results_perplexity { 28 std::vector < llama_token > tokens ; 29double ppl_value ; 30 std::vector < float > logits ; 31 std::vector < float > probs ; 32}; 33 34struct results_log_softmax { 35double log_softmax ; 36float logit ; 37float prob ; 38}; 39 40static std::vector < float > softmax (const std::vector < float >& logits ) { 41 std::vector < float > probs (logits .size ()); 42float max_logit = logits [0 ]; 43for (float v :logits ) { 44max_logit = std::max (max_logit ,v ); 45 } 46double sum_exp = 0.0 ; 47for (size_t i = 0 ;i < logits .size ();i ++ ) { 48// Subtract the maximum logit value from the current logit value for numerical stability 49const float logit = logits [i ]- max_logit ; 50const float exp_logit = expf (logit ); 51sum_exp += exp_logit ; 52probs [i ]= exp_logit ; 53 } 54for (size_t i = 0 ;i < probs .size ();i ++ ) { 55probs [i ] /=sum_exp ; 56 } 57return probs ; 58} 59 60static results_log_softmax log_softmax (int n_vocab ,const float * logits ,int tok ) { 61float max_logit = logits [0 ]; 62for (int i = 1 ;i < n_vocab ;++ i ) { 63max_logit = std::max (max_logit ,logits [i ]); 64 } 65double sum_exp = 0.0 ; 66for (int i = 0 ;i < n_vocab ;++ i ) { 67sum_exp += expf (logits [i ]- max_logit ); 68 } 69return {logits [tok ]- max_logit - log (sum_exp ),logits [tok ],expf (logits [tok ]- max_logit ) / (float )sum_exp }; 70} 71 72static inline int nearest_int (float fval ) { 73//assert(fval <= 4194303.f); 74float val = fval + 12582912.f ; 75int i ;memcpy (& i ,& val ,sizeof (int )); 76return (i & 0x007fffff )- 0x00400000 ; 77} 78 79static double log_softmax (int n_vocab ,const float * logits ,uint16_t * log_prob ,int tok ) { 80float max_logit = logits [0 ]; 81float min_logit = logits [0 ]; 82for (int i = 1 ;i < n_vocab ;++ i ) { 83max_logit = std::max (max_logit ,logits [i ]); 84min_logit = std::min (min_logit ,logits [i ]); 85 } 86min_logit = std::max (min_logit ,max_logit - 16 ); 87double sum_exp = 0.0 ; 88for (int i = 0 ;i < n_vocab ;++ i ) { 89sum_exp += expf (logits [i ]- max_logit ); 90 } 91const float log_sum_exp = log (sum_exp ); 92const float min_log_prob = min_logit - max_logit - log_sum_exp ; 93const float scale = (max_logit - min_logit )/65535.f ; 94float * d = (float * )log_prob ; 95d [0 ]= scale ; 96d [1 ]= min_log_prob ; 97log_prob += 4 ; 98if (scale ) { 99const float inv_scale = 1 /scale ; 100for (int i = 0 ;i < n_vocab ;++ i ) { 101log_prob [i ]= logits [i ]> min_logit ?nearest_int (inv_scale * (logits [i ]- min_logit )) :0 ; 102 } 103 }else { 104 std::memset (log_prob ,0 ,n_vocab * sizeof (uint16_t )); 105 } 106return max_logit + log_sum_exp - logits [tok ]; 107} 108 109static void process_logits ( 110int n_vocab ,const float * logits ,const int * tokens ,int n_token , std::vector < std::thread > & workers , 111double & nll ,double & nll2 ,float * logit_history ,float * prob_history 112) { 113 std::mutex mutex ; 114int counter = 0 ; 115auto compute = [& mutex ,& counter ,& nll ,& nll2 ,logit_history ,prob_history ,n_vocab ,logits ,tokens ,n_token ] () { 116double local_nll = 0 ; 117double local_nll2 = 0 ; 118while (true) { 119 std::unique_lock < std::mutex > lock (mutex ); 120int i = counter ++ ; 121if (i >=n_token ) { 122nll += local_nll ;nll2 += local_nll2 ; 123break ; 124 } 125lock .unlock (); 126const results_log_softmax results = log_softmax (n_vocab ,logits + size_t (i )* n_vocab ,tokens [i + 1 ]); 127const double v = - results .log_softmax ; 128local_nll += v ; 129local_nll2 += v * v ; 130 131logit_history [i ]= results .logit ; 132prob_history [i ]= results .prob ; 133 } 134 }; 135for (auto & w :workers ) { 136w = std::thread (compute ); 137 } 138compute (); 139for (auto & w :workers ) { 140w .join (); 141 } 142} 143 144static void process_logits (std::ostream & out ,int n_vocab ,const float * logits ,const int * tokens ,int n_token , 145 std::vector < std::thread > & workers , std::vector < uint16_t > & log_probs ,double & nll ,double & nll2 ) { 146 std::mutex mutex ; 147const int nv = 2 * ((n_vocab + 1 )/2 )+ 4 ; 148int counter = 0 ; 149auto compute = [& mutex ,& counter ,& log_probs ,& nll ,& nll2 ,n_vocab ,logits ,tokens ,n_token ,nv ] () { 150double local_nll = 0 ; 151double local_nll2 = 0 ; 152while (true) { 153 std::unique_lock < std::mutex > lock (mutex ); 154int i = counter ++ ; 155if (i >=n_token ) { 156nll += local_nll ;nll2 += local_nll2 ; 157break ; 158 } 159lock .unlock (); 160const double v = log_softmax (n_vocab ,logits + size_t (i )* n_vocab ,log_probs .data ()+ size_t (i )* nv ,tokens [i + 1 ]); 161local_nll += v ; 162local_nll2 += v * v ; 163 } 164 }; 165for (auto & w :workers ) { 166w = std::thread (compute ); 167 } 168compute (); 169for (auto & w :workers ) { 170w .join (); 171 } 172out .write ((const char * )log_probs .data (),size_t (n_token )* nv * sizeof (uint16_t )); 173} 174 175struct kl_divergence_result { 176double sum_nll = 0.0 ; 177double sum_nll2 = 0.0 ; 178double sum_nll_base = 0.0 ; 179double sum_nll_base2 = 0.0 ; 180double sum_nll_nll_base = 0.0 ; 181double sum_kld = 0.0 ; 182double sum_kld2 = 0.0 ; 183double sum_p_diff = 0.0 ; 184double sum_p_diff2 = 0.0 ; 185double sum_p_diff4 = 0.0 ; 186float max_p_diff = 0.0f ; 187size_t n_same_top = 0.0 ; 188size_t count = 0.0 ; 189}; 190 191static std::pair < double ,float > log_softmax (int n_vocab ,const float * logits ,const uint16_t * base_log_prob ,int tok ,kl_divergence_result & kld ) { 192float max_logit = logits [0 ]; 193int imax = 0 ; 194for (int i = 1 ;i < n_vocab ;++ i ) { 195if (logits [i ]> max_logit ) { 196max_logit = logits [i ]; 197imax = i ; 198 } 199 } 200double sum_exp = 0.0 ; 201for (int i = 0 ;i < n_vocab ;++ i ) { 202sum_exp += expf (logits [i ]- max_logit ); 203 } 204const float log_sum_exp = log (sum_exp ); 205const float * d = (const float * )base_log_prob ; 206const float scale = d [0 ]; 207const float min_log_prob = d [1 ]; 208base_log_prob += 4 ; 209 210const float nll = max_logit + log_sum_exp - logits [tok ]; 211kld .sum_nll += nll ; 212kld .sum_nll2 += nll * nll ; 213 214const float nll_base = - (scale * base_log_prob [tok ]+ min_log_prob ); 215kld .sum_nll_base += nll_base ; 216kld .sum_nll_base2 += nll_base * nll_base ; 217 218kld .sum_nll_nll_base += nll * nll_base ; 219 220max_logit += log_sum_exp ; 221double sum = 0 ; 222int imax_base = -1 ; 223float p_log_base_max = 0 ; 224for (int i = 0 ;i < n_vocab ;++ i ) { 225const float p_log_base = scale * base_log_prob [i ]+ min_log_prob ; 226if (i == 0 || p_log_base > p_log_base_max ) { 227p_log_base_max = p_log_base ; 228imax_base = i ; 229 } 230if (p_log_base > -16.f ) { 231const float p_base = expf (p_log_base ); 232sum += p_base * (p_log_base - logits [i ]+ max_logit ); 233 } 234 } 235kld .sum_kld += sum ; 236kld .sum_kld2 += sum * sum ; 237++ kld .count ; 238if (imax == imax_base ) { 239++ kld .n_same_top ; 240 } 241 242const float p_base = expf (- nll_base ); 243const float p = expf (- nll ); 244const float p_diff = p - p_base ; 245kld .sum_p_diff += p_diff ; 246const double p_diff2 = p_diff * p_diff ; 247kld .sum_p_diff2 += p_diff2 ; 248kld .sum_p_diff4 += p_diff2 * p_diff2 ; 249kld .max_p_diff = std::max (kld .max_p_diff , std::fabs (p_diff )); 250 251return std::make_pair (sum ,p_diff ); 252} 253 254static void process_logits (int n_vocab ,const float * logits ,const int * tokens ,int n_token , 255 std::vector < std::thread > & workers ,const std::vector < uint16_t > & base_log_probs ,kl_divergence_result & kld , 256float * kld_values ,float * p_diff_values ) { 257 std::mutex mutex ; 258const int nv = 2 * ((n_vocab + 1 )/2 )+ 4 ; 259int counter = 0 ; 260auto compute = [& mutex ,& counter ,& base_log_probs ,& kld ,n_vocab ,logits ,tokens ,n_token ,nv ,kld_values ,p_diff_values ] () { 261kl_divergence_result local_kld ; 262while (true) { 263 std::unique_lock < std::mutex > lock (mutex ); 264int i = counter ++ ; 265if (i >=n_token ) { 266kld .sum_nll += local_kld .sum_nll ; 267kld .sum_nll2 += local_kld .sum_nll2 ; 268kld .sum_nll_base += local_kld .sum_nll_base ; 269kld .sum_nll_base2 += local_kld .sum_nll_base2 ; 270kld .sum_nll_nll_base += local_kld .sum_nll_nll_base ; 271kld .sum_kld += local_kld .sum_kld ; 272kld .sum_kld2 += local_kld .sum_kld2 ; 273kld .sum_p_diff += local_kld .sum_p_diff ; 274kld .sum_p_diff2 += local_kld .sum_p_diff2 ; 275kld .sum_p_diff4 += local_kld .sum_p_diff4 ; 276kld .n_same_top += local_kld .n_same_top ; 277kld .max_p_diff = std::max (kld .max_p_diff ,local_kld .max_p_diff ); 278kld .count += local_kld .count ; 279break ; 280 } 281lock .unlock (); 282 std::pair < double ,float > v = log_softmax (n_vocab ,logits + size_t (i )* n_vocab ,base_log_probs .data ()+ size_t (i )* nv ,tokens [i + 1 ],local_kld ); 283kld_values [i ]= (float )v .first ; 284p_diff_values [i ]= v .second ; 285 } 286 }; 287for (auto & w :workers ) { 288w = std::thread (compute ); 289 } 290compute (); 291for (auto & w :workers ) { 292w .join (); 293 } 294} 295 296static results_perplexity perplexity_v2 (llama_context * ctx ,const common_params & params ) { 297// Download: https://huggingface.co/datasets/ggml-org/ci/resolve/main/wikitext-2-raw-v1.zip 298// Run `./perplexity -m models/7B/ggml-model-q4_0.bin -f wiki.test.raw` 299// Output: `perplexity: 13.5106 [114/114]` 300// BOS tokens will be added for each chunk before eval 301 302const llama_model * model = llama_get_model (ctx ); 303const llama_vocab * vocab = llama_model_get_vocab (model ); 304 305const bool add_bos = llama_vocab_get_add_bos (vocab ); 306GGML_ASSERT (!llama_vocab_get_add_eos (vocab )); 307 308LOG_INF ("%s: tokenizing the input ..\n" ,__func__ ); 309 310 std::vector < llama_token > tokens = common_tokenize (ctx ,params .prompt , true); 311 312const int n_ctx = llama_n_ctx (ctx ); 313 314if (int (tokens .size ())< 2 * n_ctx ) { 315LOG_ERR ("%s: you need at least %d tokens to evaluate perplexity with a context of %d\n" ,__func__ ,2 * n_ctx , 316n_ctx ); 317LOG_ERR ("%s: the data file you provided tokenizes to only %zu tokens\n" ,__func__ ,tokens .size ()); 318return {std::move (tokens ),0. , {}, {}}; 319 } 320 321 std::vector < float > logit_history ; 322 std::vector < float > prob_history ; 323 324logit_history .resize (tokens .size ()); 325prob_history .resize (tokens .size ()); 326 327if (params .ppl_stride <=0 ) { 328LOG_ERR ("%s: stride is %d but must be greater than zero!\n" ,__func__ ,params .ppl_stride ); 329return {tokens ,-1 ,logit_history ,prob_history }; 330 } 331 332const int calc_chunk = n_ctx ; 333 334LOG_INF ("%s: have %zu tokens. Calculation chunk = %d\n" ,__func__ ,tokens .size (),calc_chunk ); 335 336if (int (tokens .size ()) <=calc_chunk ) { 337LOG_ERR ("%s: there are only %zu tokens, this is not enough for a context size of %d and stride %d\n" ,__func__ , 338tokens .size (),n_ctx ,params .ppl_stride ); 339return {tokens ,-1 ,logit_history ,prob_history }; 340 } 341 342const int n_chunk_max = (tokens .size ()- calc_chunk + params .ppl_stride - 1 ) /params .ppl_stride ; 343 344const int n_chunk = params .n_chunks < 0 ?n_chunk_max : std::min (params .n_chunks ,n_chunk_max ); 345const int n_batch = params .n_batch ; 346 347const int n_vocab = llama_vocab_n_tokens (vocab ); 348 349int count = 0 ; 350double nll = 0.0 ; 351 352const int n_seq = std::max (1 ,n_batch /n_ctx ); 353LOG_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 ); 354 355for (int i = 0 ;i < n_chunk ;++ i ) { 356const int start = i * params .ppl_stride ; 357const int end = start + calc_chunk ; 358 359const int num_batches = (calc_chunk + n_batch - 1 ) /n_batch ; 360//LOG_DBG("%s: evaluating %d...%d using %d batches\n", __func__, start, end, num_batches); 361 362 std::vector < float > logits ; 363 364const auto t_start = std::chrono::high_resolution_clock::now (); 365 366// clear the KV cache 367llama_memory_clear (llama_get_memory (ctx ), true); 368 369llama_batch batch = llama_batch_init (n_batch ,0 ,1 ); 370 371for (int j = 0 ;j < num_batches ;++ j ) { 372const int batch_start = start + j * n_batch ; 373const int batch_size = std::min (end - batch_start ,n_batch ); 374 375common_batch_clear (batch ); 376for (int i = 0 ;i < batch_size ;i ++ ) { 377common_batch_add (batch ,tokens [batch_start + i ],j * n_batch + i , {0 }, true); 378 } 379 380//LOG_DBG(" Batch %d: starts at %d, size is %d, n_past is %d\n",j,batch_start,batch_size,j * n_batch); 381if (llama_decode (ctx ,batch )) { 382//LOG_ERR("%s : failed to eval\n", __func__); 383llama_batch_free (batch ); 384return {tokens ,-1 ,logit_history ,prob_history }; 385 } 386 387// save original token and restore it after eval 388const auto token_org = tokens [batch_start ]; 389 390// add BOS token for the first batch of each chunk 391if (add_bos && j == 0 ) { 392tokens [batch_start ]= llama_vocab_bos (vocab ); 393 } 394 395const auto * batch_logits = llama_get_logits (ctx ); 396logits .insert (logits .end (),batch_logits ,batch_logits + size_t (batch_size )* n_vocab ); 397 398if (j == 0 ) { 399tokens [batch_start ]= token_org ; 400 } 401 } 402 403llama_batch_free (batch ); 404 405const auto t_end = std::chrono::high_resolution_clock::now (); 406 407if (i == 0 ) { 408const float t_total = std::chrono::duration < float > (t_end - t_start ).count (); 409LOG_INF ("%s: %.2f seconds per pass - ETA " ,__func__ ,t_total ); 410int total_seconds = (int )(t_total * n_chunk ); 411if (total_seconds >=60 * 60 ) { 412LOG ("%d hours " ,total_seconds / (60 * 60 )); 413total_seconds = total_seconds % (60 * 60 ); 414 } 415LOG ("%.2f minutes\n" ,total_seconds /60.0 ); 416 } 417 418//LOG_DBG("%s: using tokens %d...%d\n",__func__,params.n_ctx - params.ppl_stride + start, params.n_ctx + start); 419for (int j = n_ctx - params .ppl_stride - 1 ;j < n_ctx - 1 ;++ j ) { 420// Calculate probability of next token, given the previous ones. 421const std::vector < float > tok_logits ( 422logits .begin ()+ size_t (j + 0 )* n_vocab , 423logits .begin ()+ size_t (j + 1 )* n_vocab ); 424 425const float prob = softmax (tok_logits )[tokens [start + j + 1 ]]; 426logit_history [start + j + 1 ]= tok_logits [tokens [start + j + 1 ]]; 427prob_history [start + j + 1 ]= prob ; 428 429nll += - std::log (prob ); 430++ count ; 431 } 432// perplexity is e^(average negative log-likelihood) 433if (params .ppl_output_type == 0 ) { 434LOG ("[%d]%.4lf," ,i + 1 , std::exp (nll /count )); 435 }else { 436LOG ("%8d %.4lf\n" ,i * params .ppl_stride , std::exp (nll /count )); 437 } 438 } 439LOG ("\n" ); 440 441return {tokens , std::exp (nll /count ),logit_history ,prob_history }; 442} 443 444static results_perplexity perplexity (llama_context * ctx ,const common_params & params ,const int32_t n_ctx ) { 445if (params .ppl_stride > 0 ) { 446return perplexity_v2 (ctx ,params ); 447 } 448 449// Download: https://huggingface.co/datasets/ggml-org/ci/resolve/main/wikitext-2-raw-v1.zip 450// Run `./llama-perplexity -m models/7B/ggml-model-q4_0.bin -f wiki.test.raw` 451// Output: `perplexity: 13.5106 [114/114]` 452// BOS tokens will be added for each chunk before eval 453 454const llama_model * model = llama_get_model (ctx ); 455const llama_vocab * vocab = llama_model_get_vocab (model ); 456 457const bool add_bos = llama_vocab_get_add_bos (vocab ); 458GGML_ASSERT (!llama_vocab_get_add_eos (vocab )); 459 460 std::ofstream logits_stream ; 461if (!params .logits_file .empty ()) { 462logits_stream .open (params .logits_file .c_str (), std::ios::binary ); 463if (!logits_stream .is_open ()) { 464LOG_ERR ("%s: failed to open %s for writing\n" ,__func__ ,params .logits_file .c_str ()); 465return {}; 466 } 467LOG_INF ("%s: saving all logits to %s\n" ,__func__ ,params .logits_file .c_str ()); 468logits_stream .write ("_logits_" ,8 ); 469logits_stream .write (reinterpret_cast < const char *> (& n_ctx ),sizeof (n_ctx )); 470 } 471 472auto tim1 = std::chrono::high_resolution_clock::now (); 473LOG_INF ("%s: tokenizing the input ..\n" ,__func__ ); 474 475 std::vector < llama_token > tokens = common_tokenize (ctx ,params .prompt , true); 476 477auto tim2 = std::chrono::high_resolution_clock::now (); 478LOG_INF ("%s: tokenization took %g ms\n" ,__func__ ,1e-3 * std::chrono::duration_cast < std::chrono::microseconds > (tim2 - tim1 ).count ()); 479 480if (int (tokens .size ())< 2 * n_ctx ) { 481LOG_ERR ("%s: you need at least %d tokens to evaluate perplexity with a context of %d\n" ,__func__ ,2 * n_ctx , 482n_ctx ); 483LOG_ERR ("%s: the data file you provided tokenizes to only %zu tokens\n" ,__func__ ,tokens .size ()); 484return {std::move (tokens ),0. , {}, {}}; 485 } 486 487 std::vector < float > logit_history ; 488logit_history .resize (tokens .size ()); 489 490 std::vector < float > prob_history ; 491prob_history .resize (tokens .size ()); 492 493const int n_chunk_max = tokens .size () /n_ctx ; 494 495const int n_chunk = params .n_chunks < 0 ?n_chunk_max : std::min (params .n_chunks ,n_chunk_max ); 496const int n_batch = params .n_batch ; 497 498const int n_vocab = llama_vocab_n_tokens (vocab ); 499 500int count = 0 ; 501double nll = 0.0 ; 502double nll2 = 0.0 ; 503 504const int num_batches = (n_ctx + n_batch - 1 ) /n_batch ; 505const int n_seq = std::max (1 ,n_batch /n_ctx ); 506 507GGML_ASSERT (n_batch < n_ctx || n_batch %n_ctx == 0 ); 508GGML_ASSERT (params .n_ctx == n_seq * n_ctx ); 509 510llama_batch batch = llama_batch_init (std::min (n_batch ,n_ctx * n_seq ),0 ,1 ); 511 512 std::vector < float > logits ; 513if (num_batches > 1 ) { 514logits .reserve (size_t (n_ctx )* n_vocab ); 515 } 516 517LOG_INF ("%s: calculating perplexity over %d chunks, n_ctx=%d, batch_size=%d, n_seq=%d\n" ,__func__ ,n_chunk ,n_ctx ,n_batch ,n_seq ); 518 519 std::vector < std::thread > workers (std::thread::hardware_concurrency ()- 1 ); 520 521 std::vector < uint16_t > log_probs ; 522if (!params .logits_file .empty ()) { 523logits_stream .write ((const char * )& n_vocab ,sizeof (n_vocab )); 524logits_stream .write ((const char * )& n_chunk ,sizeof (n_chunk )); 525logits_stream .write ((const char * )tokens .data (),n_chunk * n_ctx * sizeof (tokens [0 ])); 526const int nv = 2 * ((n_vocab + 1 )/2 )+ 4 ; 527log_probs .resize (size_t (n_ctx )* nv ); 528 } 529 530// We get the logits for all the tokens in the context window (params.n_ctx) 531// from llama_decode below. Now, based on https://huggingface.co/docs/transformers/perplexity, 532// calculate the perplexity over the last half of the window (so the model always has 533// some context to predict the token). 534// 535// We rely on the fact that attention in the forward pass only looks at previous 536// tokens here, so the logits returned for each token are an accurate representation 537// of what the model would have predicted at that point. 538// 539// Example, we have a context window of 512, we will compute perplexity for each of the 540// last 256 tokens. Then, we split the input up into context window size chunks to 541// process the entire prompt. 542const int first = n_ctx /2 ; 543 544for (int i = 0 ;i < n_chunk ;i += n_seq ) { 545const int start = i * n_ctx ; 546const int end = start + n_ctx ; 547 548const int n_seq_batch = std::min (n_seq ,n_chunk - i ); 549 550const auto t_start = std::chrono::high_resolution_clock::now (); 551 552// clear the KV cache 553llama_memory_clear (llama_get_memory (ctx ), true); 554 555for (int j = 0 ;j < num_batches ;++ j ) { 556const int batch_start = start + j * n_batch ; 557const int batch_size = std::min (end - batch_start ,n_batch ); 558 559int n_outputs = 0 ; 560 561batch .n_tokens = 0 ; 562for (int seq = 0 ;seq < n_seq_batch ;seq ++ ) { 563int seq_start = batch_start + seq * n_ctx ; 564 565// save original token and restore it after decode 566const auto token_org = tokens [seq_start ]; 567 568// add BOS token for the first batch of each chunk 569if (add_bos && j == 0 ) { 570tokens [seq_start ]= llama_vocab_bos (vocab ); 571 } 572 573for (int k = 0 ;k < batch_size ;++ k ) { 574const int idx = seq * n_ctx + k ; 575batch .token [idx ]= tokens [seq_start + k ]; 576batch .pos [idx ]= j * n_batch + k ; 577batch .n_seq_id [idx ]= 1 ; 578batch .seq_id [idx ][0 ]= seq ; 579batch .logits [idx ]= batch .pos [idx ] >=first ?1 :0 ; 580 581n_outputs += batch .logits [idx ]!= 0 ; 582 } 583batch .n_tokens += batch_size ; 584 585// restore the original token in case it was set to BOS 586tokens [seq_start ]= token_org ; 587 } 588 589if (llama_decode (ctx ,batch )) { 590LOG_INF ("%s : failed to decode\n" ,__func__ ); 591return {tokens ,-1 ,logit_history ,prob_history }; 592 } 593 594if (num_batches > 1 && n_outputs > 0 ) { 595const auto * batch_logits = llama_get_logits (ctx ); 596logits .insert (logits .end (),batch_logits ,batch_logits + size_t (n_outputs )* n_vocab ); 597 } 598 } 599 600 601if (i == 0 ) { 602llama_synchronize (ctx ); 603const auto t_end = std::chrono::high_resolution_clock::now (); 604const float t_total = std::chrono::duration < float > (t_end - t_start ).count (); 605LOG_INF ("%s: %.2f seconds per pass - ETA " ,__func__ ,t_total ); 606int total_seconds = (int )(t_total * n_chunk /n_seq ); 607if (total_seconds >=60 * 60 ) { 608LOG ("%d hours " ,total_seconds / (60 * 60 )); 609total_seconds = total_seconds % (60 * 60 ); 610 } 611LOG ("%.2f minutes\n" ,total_seconds /60.0 ); 612 } 613 614for (int seq = 0 ;seq < n_seq_batch ;seq ++ ) { 615const float * all_logits = num_batches > 1 ?logits .data () :llama_get_logits_ith (ctx ,seq * n_ctx + first ); 616 617llama_token * tokens_data = tokens .data ()+ start + seq * n_ctx + first ; 618if (!params .logits_file .empty ()) { 619process_logits (logits_stream ,n_vocab ,all_logits , 620tokens_data ,n_ctx - 1 - first , 621workers ,log_probs ,nll ,nll2 ); 622 }else { 623process_logits (n_vocab ,all_logits , 624tokens_data ,n_ctx - 1 - first , 625workers ,nll ,nll2 , 626logit_history .data ()+ start + seq * n_ctx + first , 627prob_history .data ()+ start + seq * n_ctx + first ); 628 } 629count += n_ctx - first - 1 ; 630 631// perplexity is e^(average negative log-likelihood) 632if (params .ppl_output_type == 0 ) { 633LOG ("[%d]%.4lf," ,i + seq + 1 , std::exp (nll /count )); 634 }else { 635double av = nll /count ; 636double av2 = nll2 /count - av * av ; 637if (av2 > 0 ) { 638av2 = sqrt (av2 /(count - 1 )); 639 } 640LOG ("%8d %.4lf %4lf %4lf\n" ,i * n_ctx , std::exp (nll /count ),av ,av2 ); 641 } 642 } 643 644logits .clear (); 645 } 646LOG ("\n" ); 647 648nll2 /=count ; 649nll /=count ; 650const double ppl = exp (nll ); 651nll2 -= nll * nll ; 652if (nll2 > 0 ) { 653nll2 = sqrt (nll2 /(count - 1 )); 654LOG_INF ("Final estimate: PPL = %.4lf +/- %.5lf\n" ,ppl ,nll2 * ppl ); 655 }else { 656LOG_ERR ("Unexpected negative standard deviation of log(prob)\n" ); 657 } 658 659llama_batch_free (batch ); 660 661return {tokens ,ppl ,logit_history ,prob_history }; 662} 663 664static bool decode_helper (llama_context * ctx ,llama_batch & batch , std::vector < float > & batch_logits ,int n_batch ,int n_vocab ) { 665int prev_outputs = 0 ; 666for (int i = 0 ;i < (int )batch .n_tokens ;i += n_batch ) { 667const int n_tokens = std::min < int > (n_batch ,batch .n_tokens - i ); 668 669llama_batch batch_view = { 670n_tokens , 671batch .token + i , 672nullptr , 673batch .pos + i , 674batch .n_seq_id + i , 675batch .seq_id + i , 676batch .logits + i , 677 }; 678 679const int ret = llama_decode (ctx ,batch_view ); 680if (ret != 0 ) { 681LOG_ERR ("failed to decode the batch, n_batch = %d, ret = %d\n" ,n_batch ,ret ); 682return false; 683 } 684 685int n_outputs = 0 ; 686for (int i = 0 ;i < n_tokens ;++ i ) { 687n_outputs += batch_view .logits [i ]!= 0 ; 688 } 689 690memcpy (batch_logits .data ()+ size_t (prev_outputs )* n_vocab ,llama_get_logits (ctx ),size_t (n_outputs )* n_vocab * sizeof (float )); 691 692prev_outputs += n_outputs ; 693 } 694 695return true; 696} 697 698#define K_TOKEN_CHUNK 4 699 700static void compute_logprobs (const float * batch_logits ,int n_vocab , std::vector < std::thread >& workers , 701const std::vector < std::pair < size_t ,llama_token >>& eval_pairs , std::vector < float >& eval_results ) { 702if (eval_results .size ()!= eval_pairs .size ()) { 703eval_results .resize (eval_pairs .size ()); 704 } 705if (eval_pairs .empty ()) { 706return ; 707 } 708 709size_t max_threads = std::min ((eval_pairs .size ()+ K_TOKEN_CHUNK - 1 )/K_TOKEN_CHUNK ,workers .size ()); 710 711 std::atomic < int > counter (0 ); 712auto compute = [& counter ,& eval_pairs ,& eval_results ,batch_logits ,n_vocab ] () { 713float local_logprobs [K_TOKEN_CHUNK ]; 714while (true) { 715const size_t first = counter .fetch_add (K_TOKEN_CHUNK , std::memory_order_relaxed ); 716if (first >=eval_results .size ()) { 717break ; 718 } 719const size_t last = std::min (first + K_TOKEN_CHUNK ,eval_results .size ()); 720for (size_t i = first ;i < last ;++ i ) { 721const auto * logits = batch_logits + eval_pairs [i ].first * n_vocab ; 722float max_logit = logits [0 ]; 723for (int j = 1 ;j < n_vocab ;++ j ) { 724max_logit = std::max (max_logit ,logits [j ]); 725 } 726float sum_p = 0.f ; 727for (int j = 0 ;j < n_vocab ;++ j ) { 728sum_p += expf (logits [j ]- max_logit ); 729 } 730local_logprobs [i - first ]= logits [eval_pairs [i ].second ]- max_logit - std::log (sum_p ); 731 } 732 std::memcpy (eval_results .data ()+ first ,local_logprobs , (last - first )* sizeof (float )); 733 } 734 }; 735 736for (size_t it = 0 ;it < max_threads ;++ it ) { 737workers [it ]= std::thread (compute ); 738 } 739for (size_t it = 0 ;it < max_threads ;++ it ) { 740workers [it ].join (); 741 } 742} 743 744static void hellaswag_score (llama_context * ctx ,const common_params & params ) { 745const llama_model * model = llama_get_model (ctx ); 746const llama_vocab * vocab = llama_model_get_vocab (model ); 747 748// Calculates hellaswag score (acc_norm) from prompt 749// 750// Data extracted from the HellaSwag validation dataset (MIT license) https://github.com/rowanz/hellaswag/blob/master/data/hellaswag_val.jsonl 751// All used data fields are preprocessed as in https://github.com/EleutherAI/lm-evaluation-harness/blob/df3da98c5405deafd519c2ddca52bb7c3fe36bef/lm_eval/tasks/hellaswag.py#L62-L68 752// 753// All 10042 tasks should be extracted to keep the results standardized like other implementations. 754// 755// Datafile layout: 756// ['??'] denotes json fields 757// 6 lines per task: 758// ['activity_label'] + ": " +['ctx'] - The first part of the query, the context 759// ['label'] - The index the best common sense ending aka gold ending 760// ['endings'][0] - Endings added to the first part of the query 761// ['endings'][1] 762// ['endings'][2] 763// ['endings'][3] 764 765 std::vector < std::string > prompt_lines ; 766 std::istringstream strstream (params .prompt ); 767 std::string line ; 768 769while (std::getline (strstream ,line ,'\n' )) { 770prompt_lines .push_back (line ); 771 } 772 773if (prompt_lines .size () %6 != 0 ) { 774LOG_ERR ("%s : number of lines in prompt not a multiple of 6.\n" ,__func__ ); 775return ; 776 } 777 778size_t hs_task_count = prompt_lines .size ()/6 ; 779LOG_INF ("%s : loaded %zu tasks from prompt.\n" ,__func__ ,hs_task_count ); 780 781const bool is_spm = llama_vocab_type (vocab )== LLAMA_VOCAB_TYPE_SPM ; 782LOG_INF ("================================= is_spm = %d\n" ,is_spm ); 783 784// The tasks should be randomized so the score stabilizes quickly. 785bool randomize_tasks = true; 786 787// Number of tasks to use when computing the score 788if (params .hellaswag_tasks < hs_task_count ) { 789hs_task_count = params .hellaswag_tasks ; 790 } 791 792// The random seed should not impact the final result if the computation is done over enough tasks, so kept hardcoded for now 793 std::mt19937 rng (1 ); 794 795// Dataholder for hellaswag tasks 796struct hs_data_t { 797 std::string context ; 798size_t gold_ending_idx ; 799 std::string ending [4 ]; 800size_t ending_logprob_count [4 ]; 801double ending_logprob [4 ]; 802 803size_t i_logits ;// starting index of logits in the llama_batch 804size_t common_prefix ;// max number of initial tokens that are the same in all sentences 805size_t required_tokens ;// needed number of tokens to evaluate all 4 endings 806 std::vector < llama_token > seq_tokens [4 ]; 807 }; 808 809LOG_INF ("%s : selecting %zu %s tasks.\n" ,__func__ ,hs_task_count , (randomize_tasks ?"randomized" :"the first" ) ); 810 811// Select and read data from prompt lines 812 std::vector < hs_data_t > hs_data (hs_task_count ); 813for (size_t i = 0 ;i < hs_task_count ;i ++ ) { 814size_t idx = i ; 815 816auto & hs_cur = hs_data [i ]; 817 818// Select a random example of those left in the prompt 819if (randomize_tasks ) { 820 std::uniform_int_distribution < size_t > dist (0 ,prompt_lines .size ()/6 - 1 ) ; 821idx = dist (rng ); 822 } 823 824hs_cur .context = prompt_lines [idx * 6 ]; 825hs_cur .gold_ending_idx = std::stoi (prompt_lines [idx * 6 + 1 ] ); 826for (size_t j = 0 ;j < 4 ;j ++ ) { 827hs_cur .ending [j ]= prompt_lines [idx * 6 + 2 + j ]; 828hs_cur .seq_tokens [j ]= common_tokenize (ctx ,hs_cur .context + " " + hs_cur .ending [j ], true); 829 } 830 831// determine the common prefix of the endings 832hs_cur .common_prefix = 0 ; 833for (size_t k = 0 ;k < hs_cur .seq_tokens [0 ].size ();k ++ ) { 834if (hs_cur .seq_tokens [0 ][k ]!= hs_cur .seq_tokens [1 ][k ]|| 835hs_cur .seq_tokens [0 ][k ]!= hs_cur .seq_tokens [2 ][k ]|| 836hs_cur .seq_tokens [0 ][k ]!= hs_cur .seq_tokens [3 ][k ]) { 837break ; 838 } 839hs_cur .common_prefix ++ ; 840 } 841hs_cur .required_tokens = hs_cur .common_prefix + 842hs_cur .seq_tokens [0 ].size ()- hs_cur .common_prefix + 843hs_cur .seq_tokens [1 ].size ()- hs_cur .common_prefix + 844hs_cur .seq_tokens [2 ].size ()- hs_cur .common_prefix + 845hs_cur .seq_tokens [3 ].size ()- hs_cur .common_prefix ; 846 847//GGML_ASSERT(hs_cur.common_prefix >= ::llama_tokenize(ctx, hs_cur.context, true).size()); 848 849// Delete the selected random example from the prompt 850if (randomize_tasks ) { 851prompt_lines .erase ( std::next (prompt_lines .begin (),idx * 6 ) , std::next (prompt_lines .begin (),idx * 6 + 6 ) ); 852 } 853 } 854 855LOG_INF ("%s : calculating hellaswag score over selected tasks.\n" ,__func__ ); 856 857LOG ("\ntask\tacc_norm\t95%% confidence interval\n" ); 858 859double acc = 0.0f ; 860 861const int n_ctx = llama_n_ctx (ctx ); 862const int n_batch = params .n_batch ; 863 864const int n_vocab = llama_vocab_n_tokens (vocab ); 865 866const int max_tasks_per_batch = 32 ; 867const int max_seq = std::min (4 * max_tasks_per_batch , (int )llama_n_seq_max (ctx )); 868 869llama_batch batch = llama_batch_init (n_ctx ,0 ,4 ); 870 871 std::vector < float > tok_logits (n_vocab ); 872// TODO: this could be made smaller; it's currently the worst-case size 873 std::vector < float > batch_logits (size_t (n_ctx )* n_vocab ); 874 875 std::vector < std::pair < size_t ,llama_token >> eval_pairs ; 876 std::vector < float > eval_results ; 877 std::vector < std::thread > workers (std::thread::hardware_concurrency ()); 878 879for (size_t i0 = 0 ;i0 < hs_task_count ;i0 ++ ) { 880int n_cur = 0 ; 881 882size_t i1 = i0 ; 883size_t i_logits = 0 ;// this tells us how many logits were needed before this point in the batch 884 885common_batch_clear (batch ); 886 887// batch as much tasks as possible into the available context 888// each task has 4 unique sequence ids - one for each ending 889// the common prefix is shared among the 4 sequences to save tokens 890// we extract logits only from the last common token and from all ending tokens of each sequence 891while (n_cur + (int )hs_data [i1 ].required_tokens <=n_ctx ) { 892auto & hs_cur = hs_data [i1 ]; 893int n_logits = 0 ; 894 895const int s0 = 4 * (i1 - i0 ); 896if (s0 + 4 > max_seq ) { 897break ; 898 } 899 900for (size_t i = 0 ;i < hs_cur .common_prefix ;++ i ) { 901common_batch_add (batch ,hs_cur .seq_tokens [0 ][i ],i , {s0 + 0 ,s0 + 1 ,s0 + 2 ,s0 + 3 }, false); 902 } 903batch .logits [batch .n_tokens - 1 ]= true;// we need logits for the last token of the common prefix 904n_logits += 1 ; 905 906for (int s = 0 ;s < 4 ;++ s ) { 907const size_t seq_tokens_size = hs_cur .seq_tokens [s ].size (); 908// TODO: don't evaluate the last token of each sequence 909for (size_t i = hs_cur .common_prefix ;i < seq_tokens_size ;++ i ) { 910const bool needs_logits = i < seq_tokens_size - 1 ; 911common_batch_add (batch ,hs_cur .seq_tokens [s ][i ],i , {s0 + s },needs_logits ); 912n_logits += needs_logits ; 913 } 914 } 915 916hs_cur .i_logits = i_logits ; 917i_logits += n_logits ; 918 919n_cur += hs_data [i1 ].required_tokens ; 920if (++ i1 == hs_task_count ) { 921break ; 922 } 923 } 924 925if (i0 == i1 ) { 926LOG_ERR ("%s : task %zu does not fit in the context window (requires %zu tokens)\n" ,__func__ ,i0 ,hs_data [i0 ].required_tokens ); 927return ; 928 } 929 930llama_memory_clear (llama_get_memory (ctx ), true); 931 932// decode all tasks [i0, i1) 933if (!decode_helper (ctx ,batch ,batch_logits ,n_batch ,n_vocab )) { 934LOG_ERR ("%s: llama_decode() failed\n" ,__func__ ); 935return ; 936 } 937 938// Compute log-probs in parallel 939// First we collect all tasks 940eval_pairs .clear (); 941for (size_t i = i0 ;i < i1 ;++ i ) { 942auto & hs_cur = hs_data [i ]; 943size_t li = 1 ;// skip the last logit of the common prefix (computed separately below) 944for (int s = 0 ;s < 4 ;++ s ) { 945for (size_t j = hs_cur .common_prefix ;j < hs_cur .seq_tokens [s ].size ()- 1 ;j ++ ) { 946eval_pairs .emplace_back (hs_cur .i_logits + li ++ ,hs_cur .seq_tokens [s ][j + 1 ]); 947 } 948 } 949 } 950// Then we do the actual calculation 951compute_logprobs (batch_logits .data (),n_vocab ,workers ,eval_pairs ,eval_results ); 952 953size_t ir = 0 ; 954 955// compute the logprobs for each ending of the decoded tasks 956for (size_t i = i0 ;i < i1 ;++ i ) { 957auto & hs_cur = hs_data [i ]; 958 959// get the logits of the last token of the common prefix 960 std::memcpy (tok_logits .data (),batch_logits .data ()+ hs_cur .i_logits * n_vocab ,n_vocab * sizeof (float )); 961 962const auto first_probs = softmax (tok_logits ); 963 964for (int s = 0 ;s < 4 ;++ s ) { 965hs_cur .ending_logprob_count [s ]= 1 ; 966hs_cur .ending_logprob [s ]= std::log (first_probs [hs_cur .seq_tokens [s ][hs_cur .common_prefix ]]); 967for (size_t j = hs_cur .common_prefix ;j < hs_cur .seq_tokens [s ].size ()- 1 ;j ++ ) { 968hs_cur .ending_logprob [s ]+= eval_results [ir ++ ]; 969hs_cur .ending_logprob_count [s ]++ ; 970 } 971hs_cur .ending_logprob [s ] /=hs_cur .ending_logprob_count [s ]; 972 } 973 974// Find the ending with maximum logprob 975size_t ending_logprob_max_idx = 0 ; 976double ending_logprob_max_val = hs_cur .ending_logprob [0 ]; 977for (size_t s = 1 ;s < 4 ;s ++ ) { 978if (hs_cur .ending_logprob [s ]> ending_logprob_max_val ) { 979ending_logprob_max_idx = s ; 980ending_logprob_max_val = hs_cur .ending_logprob [s ]; 981 } 982 } 983 984//LOG("max logprob ending idx %lu, gold ending idx %lu\n", ending_logprob_max_idx, hs_cur.gold_ending_idx); 985 986// If the gold ending got the maximum logprobe add one accuracy point 987if (ending_logprob_max_idx == hs_cur .gold_ending_idx ) { 988acc += 1.0 ; 989 } 990 991double freq = acc /double (i + 1 ); 992 993const double za = 1.95996398454 ; 994 995// // Wald normal approx 996// double conf =za*sqrt(freq*(1-freq)/double(i + 1)); 997// LOG("%zu\t%.8lf +/- %.8lf\n", i + 1, freq*100.0, conf*100.0); 998 999// Wilson score interval, more accurate 1000double z = za * za /double (i + 1 ); 1001double cnf = z * sqrt (double (i + 1 )* (4.0 * freq * (1 - freq )+ z )) / (za + za ); 1002double a = (freq + z * 0.5 - cnf ) / (1.0 + z ); 1003double b = (freq + z * 0.5 + cnf ) / (1.0 + z ); 1004 1005// Print the accumulated accuracy mean x 100 and confidence interval 1006LOG ("%zu\t%3.8lf%%\t[%3.4lf%%, %3.4lf%%]\n" ,i + 1 ,freq * 100.0 ,a * 100.0 ,b * 100.0 ); 1007 } 1008 1009i0 = i1 - 1 ; 1010 } 1011 1012llama_batch_free (batch ); 1013 1014LOG ("\n" ); 1015} 1016 1017struct winogrande_entry { 1018 std::string first ; 1019 std::string second ; 1020 std::array < std::string ,2 > choices ; 1021int answer ; 1022 1023size_t i_logits ; 1024size_t common_prefix ; 1025size_t required_tokens ; 1026size_t n_base1 ;// number of tokens for context + choice 1 1027size_t n_base2 ;// number of tokens for context + choice 2 1028 std::vector < llama_token > seq_tokens [2 ]; 1029}; 1030 1031static std::vector < winogrande_entry > load_winogrande_from_csv (const std::string & prompt ) { 1032 std::vector < winogrande_entry > result ; 1033 std::istringstream in (prompt ); 1034 std::string line ; 1035 std::array < int ,4 > comma_pos ; 1036while (true) { 1037 std::getline (in ,line ); 1038if (in .fail ()|| in .eof ())break ; 1039int ipos = 0 ; 1040bool quote_open = false; 1041for (int i = 0 ;i < int (line .size ());++ i ) { 1042if (!quote_open ) { 1043if (line [i ]== ',' ) { 1044comma_pos [ipos ++ ]= i ; 1045if (ipos == 4 )break ; 1046 } 1047else if (line [i ]== '"' ) { 1048quote_open = true; 1049 } 1050 } 1051else { 1052if (line [i ]== '"' ) { 1053quote_open = false; 1054 } 1055 } 1056 } 1057if (ipos != 4 ) { 1058LOG_ERR ("%s: failed to find comma separators in <%s>\n" ,__func__ ,line .c_str ()); 1059continue ; 1060 } 1061auto sentence = line [comma_pos [0 ]+ 1 ]== '"' ?line .substr (comma_pos [0 ]+ 2 ,comma_pos [1 ]- comma_pos [0 ]- 3 ) 1062 :line .substr (comma_pos [0 ]+ 1 ,comma_pos [1 ]- comma_pos [0 ]- 1 ); 1063auto choice1 = line .substr (comma_pos [1 ]+ 1 ,comma_pos [2 ]- comma_pos [1 ]- 1 ); 1064auto choice2 = line .substr (comma_pos [2 ]+ 1 ,comma_pos [3 ]- comma_pos [2 ]- 1 ); 1065auto answer = line .substr (comma_pos [3 ]+ 1 ,line .size ()- comma_pos [3 ]- 1 ); 1066auto index = line .substr (0 ,comma_pos [0 ]); 1067int where = 0 ; 1068for ( ;where < int (sentence .size ());++ where ) { 1069if (sentence [where ]== '_' )break ; 1070 } 1071if (where == int (sentence .size ())) { 1072LOG_ERR ("%s: no _ in <%s>\n" ,__func__ ,sentence .c_str ()); 1073continue ; 1074 } 1075 std::istringstream stream (answer .c_str ()); 1076int i_answer ;stream >>i_answer ; 1077if (stream .fail ()|| i_answer < 1 || i_answer > 2 ) { 1078LOG_ERR ("%s: failed to parse answer <%s>\n" ,__func__ ,answer .c_str ()); 1079continue ; 1080 } 1081result .emplace_back (); 1082auto & wg = result .back (); 1083wg .first = sentence .substr (0 ,where ); 1084wg .second = sentence .substr (where + 1 ,sentence .size ()- where - 1 ); 1085wg .choices [0 ]= std::move (choice1 ); 1086wg .choices [1 ]= std::move (choice2 ); 1087wg .answer = i_answer ; 1088 } 1089return result ; 1090} 1091 1092/* 1093* Evaluates the Winogrande score. 1094* Uses a CSV containing task index, dentence, choice 1, choice 2, answer (1 or 2) 1095* You can get one such dataset from e.g. https://huggingface.co/datasets/ikawrakow/winogrande-eval-for-llama.cpp 1096* As an example, the 1st row in the above dataset is 1097* 1098* 0,Sarah was a much better surgeon than Maria so _ always got the easier cases.,Sarah,Maria,2 1099* 1100*/ 1101static void winogrande_score (llama_context * ctx ,const common_params & params ) { 1102const llama_model * model = llama_get_model (ctx ); 1103const llama_vocab * vocab = llama_model_get_vocab (model ); 1104 1105constexpr int k_min_trailing_ctx = 3 ; 1106 1107auto data = load_winogrande_from_csv (params .prompt ); 1108if (data .empty ()) { 1109LOG_ERR ("%s: no tasks\n" ,__func__ ); 1110return ; 1111 } 1112 1113LOG_INF ("%s : loaded %zu tasks from prompt.\n" ,__func__ ,data .size ()); 1114 1115if (params .winogrande_tasks > 0 && params .winogrande_tasks < data .size ()) { 1116LOG_INF ("%s : selecting %zu random tasks\n" ,__func__ ,params .winogrande_tasks ); 1117 std::mt19937 rng (1 ); 1118 std::vector < int > aux (data .size ()); 1119for (int i = 0 ;i < int (data .size ());++ i ) { 1120aux [i ]= i ; 1121 } 1122float scale = 1 /(1.f + (float )rng .max ()); 1123 std::vector < winogrande_entry > selected ; 1124selected .resize (params .winogrande_tasks ); 1125for (int i = 0 ;i < int (params .winogrande_tasks );++ i ) { 1126int j = int (scale * rng ()* aux .size ()); 1127selected [i ]= std::move (data [aux [j ]]); 1128aux [j ]= aux .back (); 1129aux .pop_back (); 1130 } 1131data = std::move (selected ); 1132 } 1133 1134LOG_INF ("%s : tokenizing selected tasks\n" ,__func__ ); 1135 1136for (auto & task :data ) { 1137task .seq_tokens [0 ]= common_tokenize (ctx ,task .first + task .choices [0 ]+ task .second , true); 1138task .seq_tokens [1 ]= common_tokenize (ctx ,task .first + task .choices [1 ]+ task .second , true); 1139 1140task .common_prefix = 0 ; 1141for (size_t k = 0 ;k < task .seq_tokens [0 ].size ();k ++ ) { 1142if (task .seq_tokens [0 ][k ]!= task .seq_tokens [1 ][k ]) { 1143break ; 1144 } 1145task .common_prefix ++ ; 1146 } 1147 1148// TODO: the last token of each of the sequences don't need to be evaluated 1149task .required_tokens = task .common_prefix + 1150task .seq_tokens [0 ].size ()- task .common_prefix + 1151task .seq_tokens [1 ].size ()- task .common_prefix ; 1152 1153task .n_base1 = common_tokenize (ctx ,task .first + task .choices [0 ], true).size (); 1154task .n_base2 = common_tokenize (ctx ,task .first + task .choices [1 ], true).size (); 1155 } 1156 1157LOG_INF ("%s : calculating winogrande score over selected tasks.\n" ,__func__ ); 1158 1159const int n_ctx = llama_n_ctx (ctx ); 1160const int n_batch = params .n_batch ; 1161 1162const int n_vocab = llama_vocab_n_tokens (vocab ); 1163 1164const int max_tasks_per_batch = 128 ; 1165const int max_seq = std::min (2 * max_tasks_per_batch , (int )llama_n_seq_max (ctx )); 1166 1167llama_batch batch = llama_batch_init (n_ctx ,0 ,2 ); 1168 1169 std::vector < float > tok_logits (n_vocab ); 1170// TODO: this could be made smaller; it's currently the worst-case size 1171 std::vector < float > batch_logits (size_t (n_ctx )* n_vocab ); 1172 1173 std::vector < std::pair < size_t ,llama_token >> eval_pairs ; 1174 std::vector < float > eval_results ; 1175 std::vector < std::thread > workers (std::thread::hardware_concurrency ()); 1176 1177int n_correct = 0 ; 1178int n_done = 0 ; 1179 1180for (size_t i0 = 0 ;i0 < data .size ();i0 ++ ) { 1181int n_cur = 0 ; 1182 1183size_t i1 = i0 ; 1184size_t i_logits = 0 ; 1185 1186common_batch_clear (batch ); 1187 1188while (n_cur + (int )data [i1 ].required_tokens <=n_ctx ) { 1189int n_logits = 0 ; 1190const int s0 = 2 * (i1 - i0 ); 1191if (s0 + 2 > max_seq ) { 1192break ; 1193 } 1194 1195for (size_t i = 0 ;i < data [i1 ].common_prefix ;++ i ) { 1196common_batch_add (batch ,data [i1 ].seq_tokens [0 ][i ],i , {s0 + 0 ,s0 + 1 }, false); 1197 } 1198batch .logits [batch .n_tokens - 1 ]= true; 1199n_logits += 1 ; 1200 1201for (int s = 0 ;s < 2 ;++ s ) { 1202// TODO: end before the last token, no need to predict past the end of the sequences 1203for (size_t i = data [i1 ].common_prefix ;i < data [i1 ].seq_tokens [s ].size ();++ i ) { 1204common_batch_add (batch ,data [i1 ].seq_tokens [s ][i ],i , {s0 + s }, true); 1205n_logits += 1 ; 1206 } 1207 } 1208 1209data [i1 ].i_logits = i_logits ; 1210i_logits += n_logits ; 1211 1212n_cur += data [i1 ].required_tokens ; 1213if (++ i1 == data .size ()) { 1214break ; 1215 } 1216 } 1217 1218if (i0 == i1 ) { 1219LOG_ERR ("%s : task %zu does not fit in the context window (requires %zu tokens)\n" ,__func__ ,i0 ,data [i0 ].required_tokens ); 1220return ; 1221 } 1222 1223llama_memory_clear (llama_get_memory (ctx ), true); 1224 1225// decode all tasks [i0, i1) 1226if (!decode_helper (ctx ,batch ,batch_logits ,n_batch ,n_vocab )) { 1227LOG_ERR ("%s: llama_decode() failed\n" ,__func__ ); 1228return ; 1229 } 1230 1231eval_pairs .clear (); 1232for (size_t i = i0 ;i < i1 ;++ i ) { 1233auto & task = data [i ]; 1234 1235const bool skip_choice = 1236task .seq_tokens [0 ].size ()- task .common_prefix > k_min_trailing_ctx && 1237task .seq_tokens [1 ].size ()- task .common_prefix > k_min_trailing_ctx ; 1238 1239const auto & n_base1 = skip_choice ?task .n_base1 :task .common_prefix ; 1240const int last_1st = task .seq_tokens [0 ].size ()- n_base1 > 1 ?1 :0 ; 1241size_t li = n_base1 - task .common_prefix ; 1242for (size_t j = n_base1 - 1 ;j < task .seq_tokens [0 ].size ()- 1 - last_1st ;++ j ) { 1243eval_pairs .emplace_back (task .i_logits + li ++ ,task .seq_tokens [0 ][j + 1 ]); 1244 } 1245const auto & n_base2 = skip_choice ?task .n_base2 :task .common_prefix ; 1246const int last_2nd = task .seq_tokens [1 ].size ()- n_base2 > 1 ?1 :0 ; 1247// FIXME: this uses the wrong first logits when not skipping the choice word 1248li = task .seq_tokens [0 ].size ()- task .common_prefix + n_base2 - task .common_prefix ; 1249for (size_t j = n_base2 - 1 ;j < task .seq_tokens [1 ].size ()- 1 - last_2nd ;++ j ) { 1250eval_pairs .emplace_back (task .i_logits + li ++ ,task .seq_tokens [1 ][j + 1 ]); 1251 } 1252 } 1253compute_logprobs (batch_logits .data (),n_vocab ,workers ,eval_pairs ,eval_results ); 1254 1255size_t ir = 0 ; 1256for (size_t i = i0 ;i < i1 ;++ i ) { 1257auto & task = data [i ]; 1258 1259const bool skip_choice = 1260task .seq_tokens [0 ].size ()- task .common_prefix > k_min_trailing_ctx && 1261task .seq_tokens [1 ].size ()- task .common_prefix > k_min_trailing_ctx ; 1262 1263float score_1st = 0 ; 1264const auto & n_base1 = skip_choice ?task .n_base1 :task .common_prefix ; 1265const int last_1st = task .seq_tokens [0 ].size ()- n_base1 > 1 ?1 :0 ; 1266for (size_t j = n_base1 - 1 ;j < task .seq_tokens [0 ].size ()- 1 - last_1st ;++ j ) { 1267score_1st += eval_results [ir ++ ]; 1268 } 1269score_1st /= (task .seq_tokens [0 ].size ()- n_base1 - last_1st ); 1270 1271float score_2nd = 0 ; 1272const auto & n_base2 = skip_choice ?task .n_base2 :task .common_prefix ; 1273const int last_2nd = task .seq_tokens [1 ].size ()- n_base2 > 1 ?1 :0 ; 1274for (size_t j = n_base2 - 1 ;j < task .seq_tokens [1 ].size ()- 1 - last_2nd ;++ j ) { 1275score_2nd += eval_results [ir ++ ]; 1276 } 1277score_2nd /= (task .seq_tokens [1 ].size ()- n_base2 - last_2nd ); 1278 1279int result = score_1st > score_2nd ?1 :2 ; 1280 1281if (result == task .answer ) { 1282++ n_correct ; 1283 } 1284++ n_done ; 1285 1286// print the accumulated accuracy mean x 100 1287LOG ("%zu\t%.4lf\t%10.6f %10.6f %d %d\n" ,i + 1 ,100.0 * n_correct /n_done ,score_1st ,score_2nd ,result ,task .answer ); 1288 } 1289 1290i0 = i1 - 1 ; 1291 } 1292 1293LOG ("\n" ); 1294 1295if (n_done < 100 )return ; 1296 1297const float p = 1.f * n_correct /n_done ; 1298const float sigma = 100.f * sqrt (p * (1 - p )/(n_done - 1 )); 1299 1300LOG_INF ("Final Winogrande score(%d tasks): %.4lf +/- %.4lf\n" ,n_done ,100 * p ,sigma ); 1301} 1302 1303static bool deserialize_string (std::istream & in , std::string & str ) { 1304uint32_t size ; 1305if (!in .read ((char * )& size ,sizeof (size )).fail ()) { 1306str .resize (size ); 1307if (!in .read ((char * )& str [0 ],size ).fail ())return true; 1308 } 1309return false; 1310} 1311 1312struct multiple_choice_answers { 1313 std::vector < std::string > answers ; 1314 std::vector < int > labels ; 1315bool deserialize (std::istream & in ) { 1316uint32_t n ; 1317in .read ((char * )& n ,sizeof (n )); 1318if (in .fail ()|| n > 100 )return false;// 100 as max. number of answers should be good enough for any practical purpose 1319answers .resize (n ); 1320labels .resize (n ); 1321for (auto & a :answers ) { 1322if (!deserialize_string (in ,a ))return false; 1323 } 1324in .read ((char * )labels .data (),n * sizeof (int )); 1325return !in .fail (); 1326 } 1327}; 1328 1329struct multiple_choice_task { 1330 std::string question ;// the question (or context that needs to be continued) 1331multiple_choice_answers mc1 ;// possible answers (continuations) with a single correct answer 1332multiple_choice_answers mc2 ;// possible answers (continuations) with multiple correct answers - not handled yet 1333bool deserialize (std::istream & in ) { 1334if (!deserialize_string (in ,question ))return false; 1335return mc1 .deserialize (in )&& mc2 .deserialize (in ); 1336 } 1337 1338// For evaluation 1339size_t i_logits ;// starting index of logits in the llama_batch 1340size_t common_prefix ;// max number of initial tokens that are the same in all sentences 1341size_t required_tokens ;// needed number of tokens to evaluate all answers 1342 std::vector < std::vector < llama_token >> seq_tokens ; 1343 std::vector < float > log_probs ; 1344}; 1345 1346static bool multiple_choice_prepare_one_task (llama_context * ctx ,multiple_choice_task & task ,bool log_error ) { 1347if (task .question .empty ()|| task .mc1 .answers .empty ()) { 1348if (log_error ) { 1349LOG_ERR ("%s: found bad task with empty question and/or answers\n" ,__func__ ); 1350 } 1351return false; 1352 } 1353task .seq_tokens .reserve (task .mc1 .answers .size ()); 1354for (auto & answer :task .mc1 .answers ) { 1355if (answer .empty ()) { 1356if (log_error ) { 1357LOG_ERR ("%s: found empty answer\n" ,__func__ ); 1358 } 1359return false; 1360 } 1361task .seq_tokens .emplace_back (::common_tokenize (ctx ,task .question + " " + answer , true)); 1362 } 1363auto min_len = task .seq_tokens .front ().size (); 1364for (auto & seq :task .seq_tokens ) { 1365min_len = std::min (min_len ,seq .size ()); 1366 } 1367task .common_prefix = 0 ; 1368for (size_t k = 0 ;k < min_len ;++ k ) { 1369auto token = task .seq_tokens [0 ][k ]; 1370bool all_same = true; 1371for (size_t i = 1 ;i < task .seq_tokens .size ();++ i ) { 1372if (task .seq_tokens [i ][k ]!= token ) { 1373all_same = false; 1374break ; 1375 } 1376 } 1377if (!all_same ) { 1378break ; 1379 } 1380++ task .common_prefix ; 1381 } 1382task .required_tokens = task .common_prefix ; 1383for (auto & seq :task .seq_tokens ) { 1384task .required_tokens += seq .size ()- task .common_prefix ; 1385 } 1386return true; 1387} 1388 1389// 1390// Calculates score for multiple choice tasks with single correct answer from prompt. 1391// Commonly used LLM evaluation metrics of this type are 1392// * ARC 1393// * HellaSwag 1394// * MMLU 1395// * TruthfulQA 1396// 1397// Validation datasets for these 4 tests can be found at 1398// https://huggingface.co/datasets/ikawrakow/validation-datasets-for-llama.cpp 1399// The data for these datasets was extracted from 1400// git@hf.co:datasets/allenai/ai2_arc 1401// https://github.com/rowanz/hellaswag/blob/master/data/hellaswag_val.jsonl 1402// git@hf.co:datasets/Stevross/mmlu 1403// https://huggingface.co/datasets/truthful_qa 1404// 1405static void multiple_choice_score (llama_context * ctx ,const common_params & params ) { 1406const llama_model * model = llama_get_model (ctx ); 1407const llama_vocab * vocab = llama_model_get_vocab (model ); 1408 1409 std::istringstream strstream (params .prompt ); 1410uint32_t n_task ; 1411strstream .read ((char * )& n_task ,sizeof (n_task )); 1412if (strstream .fail ()|| n_task == 0 ) { 1413LOG_ERR ("%s: no tasks\n" ,__func__ ); 1414return ; 1415 } 1416LOG_INF ("%s: there are %u tasks in prompt\n" ,__func__ ,n_task ); 1417 std::vector < uint32_t > task_pos (n_task ); 1418strstream .read ((char * )task_pos .data (),task_pos .size ()* sizeof (uint32_t )); 1419if (strstream .fail ()) { 1420LOG_ERR ("%s: failed to read task positions from prompt\n" ,__func__ ); 1421return ; 1422 } 1423 1424 std::vector < multiple_choice_task > tasks ; 1425if (params .multiple_choice_tasks == 0 || params .multiple_choice_tasks >= (size_t )n_task ) { 1426// Use all tasks 1427tasks .resize (n_task ); 1428LOG_INF ("%s: reading tasks" ,__func__ ); 1429int n_dot = std::max ((int )n_task /100 ,1 ); 1430int i = 0 ; 1431for (auto & task :tasks ) { 1432++ i ; 1433if (!task .deserialize (strstream )) { 1434LOG_ERR ("%s: failed to read task %d of %u\n" ,__func__ ,i ,n_task ); 1435return ; 1436 } 1437if (i %n_dot == 0 )LOG ("." ); 1438 } 1439LOG ("done\n" ); 1440 } 1441else { 1442LOG_INF ("%s: selecting %zu random tasks from %u tasks available\n" ,__func__ ,params .multiple_choice_tasks ,n_task ); 1443 std::mt19937 rng (1 ); 1444 std::vector < int > aux (n_task ); 1445for (uint32_t i = 0 ;i < n_task ;++ i )aux [i ]= i ; 1446float scale = 1.f /(1.f + (float )std::mt19937::max ()); 1447tasks .resize (params .multiple_choice_tasks ); 1448for (auto & task :tasks ) { 1449int j = (int )(scale * rng ()* aux .size ()); 1450int idx = aux [j ]; 1451aux [j ]= aux .back (); 1452aux .pop_back (); 1453strstream .seekg (task_pos [idx ], std::ios::beg ); 1454if (!task .deserialize (strstream )) { 1455LOG_ERR ("%s: failed to read task %d at position %u\n" ,__func__ ,idx ,task_pos [idx ]); 1456return ; 1457 } 1458 } 1459n_task = params .multiple_choice_tasks ; 1460 } 1461 1462LOG_INF ("%s: preparing task data" ,__func__ ); 1463if (n_task > 500 ) { 1464LOG ("..." ); 1465 std::atomic < int > counter (0 ); 1466 std::atomic < int > n_bad (0 ); 1467auto prepare = [& counter ,& n_bad ,& tasks ,ctx ] () { 1468int num_tasks = tasks .size (); 1469int n_bad_local = 0 ; 1470while (true) { 1471int first = counter .fetch_add (K_TOKEN_CHUNK ); 1472if (first >=num_tasks ) { 1473if (n_bad_local > 0 )n_bad += n_bad_local ; 1474break ; 1475 } 1476int last = std::min (first + K_TOKEN_CHUNK ,num_tasks ); 1477for (int i = first ;i < last ;++ i ) { 1478if (!multiple_choice_prepare_one_task (ctx ,tasks [i ], false))++ n_bad_local ; 1479 } 1480 } 1481 }; 1482size_t max_thread = std::thread::hardware_concurrency (); 1483max_thread = std::min (max_thread , (tasks .size ()+ K_TOKEN_CHUNK - 1 )/K_TOKEN_CHUNK ); 1484 std::vector < std::thread > workers (max_thread - 1 ); 1485for (auto & w :workers )w = std::thread (prepare ); 1486prepare (); 1487for (auto & w :workers )w .join (); 1488LOG ("done\n" ); 1489int nbad = n_bad ; 1490if (nbad > 0 ) { 1491LOG_ERR ("%s: found %d malformed tasks\n" ,__func__ ,nbad ); 1492return ; 1493 } 1494 }else { 1495int n_dot = std::max ((int )n_task /100 ,1 ); 1496int i_task = 0 ; 1497for (auto & task :tasks ) { 1498++ i_task ; 1499if (!multiple_choice_prepare_one_task (ctx ,task , true)) { 1500return ; 1501 } 1502if (i_task %n_dot == 0 ) { 1503LOG ("." ); 1504 } 1505 } 1506LOG ("done\n" ); 1507 } 1508 1509LOG_INF ("%s : calculating TruthfulQA score over %zu tasks.\n" ,__func__ ,tasks .size ()); 1510 1511LOG ("\ntask\tacc_norm\n" ); 1512 1513const int n_ctx = llama_n_ctx (ctx ); 1514const int n_batch = params .n_batch ; 1515 1516const int n_vocab = llama_vocab_n_tokens (vocab ); 1517 1518const int max_tasks_per_batch = 32 ; 1519const int max_seq = std::min (4 * max_tasks_per_batch , (int )llama_n_seq_max (ctx )); 1520 1521llama_batch batch = llama_batch_init (n_ctx ,0 ,max_seq ); 1522 1523 std::vector < float > tok_logits (n_vocab ); 1524 std::vector < float > batch_logits (size_t (n_ctx )* n_vocab ); 1525 1526 std::vector < std::pair < size_t ,llama_token >> eval_pairs ; 1527 std::vector < float > eval_results ; 1528 std::vector < std::thread > workers (std::thread::hardware_concurrency ()); 1529 std::vector < int > batch_indeces ; 1530 1531int n_done = 0 ; 1532int n_correct = 0 ; 1533int n_tot_answers = 0 ; 1534 1535for (size_t i0 = 0 ;i0 < tasks .size ();i0 ++ ) { 1536int n_cur = 0 ; 1537 1538size_t i1 = i0 ; 1539size_t i_logits = 0 ;// this tells us how many logits were needed before this point in the batch 1540 1541common_batch_clear (batch ); 1542 1543// batch as much tasks as possible into the available context 1544// each task has 4 unique sequence ids - one for each ending 1545// the common prefix is shared among the 4 sequences to save tokens 1546// we extract logits only from the last common token and from all ending tokens of each sequence 1547int s0 = 0 ; 1548while (n_cur + (int )tasks [i1 ].required_tokens <=n_ctx ) { 1549auto & cur_task = tasks [i1 ]; 1550int n_logits = 0 ; 1551 1552int num_answers = cur_task .seq_tokens .size (); 1553if (s0 + num_answers > max_seq ) { 1554if (s0 == 0 ) { 1555LOG_ERR ("%s : task %zu requires a higher -np|--parallel value (at least %d)\n" ,__func__ ,i0 ,num_answers ); 1556return ; 1557 } 1558break ; 1559 } 1560 1561if (int (batch_indeces .size ())!= num_answers ) { 1562batch_indeces .resize (num_answers ); 1563 } 1564 1565for (int s = 0 ;s < num_answers ;++ s ) { 1566batch_indeces [s ]= s0 + s ; 1567 } 1568 1569for (size_t i = 0 ;i < cur_task .common_prefix ;++ i ) { 1570//llama_batch_add(batch, cur_task.seq_tokens[0][i], i, { s0 + 0, s0 + 1, s0 + 2, s0 + 3}, false); 1571common_batch_add (batch ,cur_task .seq_tokens [0 ][i ],i ,batch_indeces , false); 1572 } 1573batch .logits [batch .n_tokens - 1 ]= true;// we need logits for the last token of the common prefix 1574n_logits += 1 ; 1575 1576for (int s = 0 ;s < int (cur_task .seq_tokens .size ());++ s ) { 1577const size_t seq_tokens_size = cur_task .seq_tokens [s ].size (); 1578// TODO: don't evaluate the last token of each sequence 1579for (size_t i = cur_task .common_prefix ;i < seq_tokens_size ;++ i ) { 1580const bool needs_logits = i < seq_tokens_size - 1 ; 1581common_batch_add (batch ,cur_task .seq_tokens [s ][i ],i , {s0 + s },needs_logits ); 1582n_logits += needs_logits ; 1583 } 1584 } 1585 1586s0 += num_answers ; 1587 1588cur_task .i_logits = i_logits ; 1589i_logits += n_logits ; 1590 1591n_cur += cur_task .required_tokens ; 1592if (++ i1 == tasks .size ()) { 1593break ; 1594 } 1595 } 1596 1597if (i0 == i1 ) { 1598LOG_ERR ("%s : task %zu does not fit in the context window (requires %zu tokens)\n" ,__func__ ,i0 ,tasks [i0 ].required_tokens ); 1599return ; 1600 } 1601 1602llama_memory_clear (llama_get_memory (ctx ), true); 1603 1604// decode all tasks [i0, i1) 1605if (!decode_helper (ctx ,batch ,batch_logits ,n_batch ,n_vocab )) { 1606LOG_ERR ("%s: llama_decode() failed\n" ,__func__ ); 1607return ; 1608 } 1609 1610// Compute log-probs in parallel 1611// First we collect all tasks 1612eval_pairs .clear (); 1613for (size_t i = i0 ;i < i1 ;++ i ) { 1614auto & cur_task = tasks [i ]; 1615size_t li = 1 ;// skip the last logit of the common prefix (computed separately below) 1616for (int s = 0 ;s < int (cur_task .seq_tokens .size ());++ s ) { 1617for (size_t j = cur_task .common_prefix ;j < cur_task .seq_tokens [s ].size ()- 1 ;j ++ ) { 1618eval_pairs .emplace_back (cur_task .i_logits + li ++ ,cur_task .seq_tokens [s ][j + 1 ]); 1619 } 1620 } 1621 } 1622// Then we do the actual calculation 1623compute_logprobs (batch_logits .data (),n_vocab ,workers ,eval_pairs ,eval_results ); 1624 1625size_t ir = 0 ; 1626 1627// compute the logprobs for each ending of the decoded tasks 1628for (size_t i = i0 ;i < i1 ;++ i ) { 1629auto & cur_task = tasks [i ]; 1630//LOG("==== Evaluating <%s> with correct answer ", cur_task.question.c_str()); 1631//for (int j = 0; j < int(cur_task.mc1.labels.size()); ++j) { 1632// if (cur_task.mc1.labels[j] == 1) { 1633// LOG("%d", j+1); 1634// } 1635//} 1636//LOG("\n common_prefix: %zu\n", cur_task.common_prefix); 1637 1638// get the logits of the last token of the common prefix 1639 std::memcpy (tok_logits .data (),batch_logits .data ()+ cur_task .i_logits * n_vocab ,n_vocab * sizeof (float )); 1640 1641const auto first_probs = softmax (tok_logits ); 1642 1643cur_task .log_probs .resize (cur_task .seq_tokens .size ()); 1644for (int s = 0 ;s < int (cur_task .seq_tokens .size ());++ s ) { 1645size_t count = 1 ; 1646float log_prob = std::log (first_probs [cur_task .seq_tokens [s ][cur_task .common_prefix ]]); 1647for (size_t j = cur_task .common_prefix ;j < cur_task .seq_tokens [s ].size ()- 1 ;j ++ ) { 1648//LOG(" %zu %g\n", ir, eval_results[ir]); 1649++ count ; 1650log_prob += eval_results [ir ++ ]; 1651 } 1652cur_task .log_probs [s ]= log_prob /count ; 1653//LOG(" Final: %g\n", log_prob / count); 1654//LOG(" <%s> : %g\n", cur_task.mc1.answers[s].c_str(), log_prob/count); 1655 } 1656 1657// Find the ending with maximum logprob 1658size_t logprob_max_idx = 0 ; 1659float logprob_max_val = cur_task .log_probs [0 ]; 1660for (size_t s = 1 ;s < cur_task .log_probs .size ();s ++ ) { 1661if (cur_task .log_probs [s ]> logprob_max_val ) { 1662logprob_max_val = cur_task .log_probs [s ]; 1663logprob_max_idx = s ; 1664 } 1665 } 1666 1667n_tot_answers += cur_task .log_probs .size (); 1668if (cur_task .mc1 .labels [logprob_max_idx ]== 1 ) { 1669++ n_correct ; 1670 } 1671++ n_done ; 1672 1673// Print the accumulated accuracy mean x 100 1674LOG ("%d\t%.8lf\n" ,n_done ,100. * n_correct /n_done ); 1675 } 1676 1677i0 = i1 - 1 ; 1678 } 1679 1680llama_batch_free (batch ); 1681 1682if (n_done < 100 && (params .multiple_choice_tasks != 0 && params .multiple_choice_tasks < (size_t )n_task ))return ; 1683 1684float p = 1.f * n_correct /n_done ; 1685float sigma = sqrt (p * (1 - p )/(n_done - 1 )); 1686LOG ("\n" ); 1687LOG_INF ("Final result: %.4f +/- %.4f\n" ,100.f * p ,100.f * sigma ); 1688p = 1.f * n_done /n_tot_answers ; 1689sigma = sqrt (p * (1 - p )/(n_done - 1 )); 1690LOG_INF ("Random chance: %.4f +/- %.4f\n" ,100.f * p ,100.f * sigma ); 1691 1692LOG_INF ("\n" ); 1693} 1694 1695static void kl_divergence (llama_context * ctx ,const common_params & params ) { 1696const llama_model * model = llama_get_model (ctx ); 1697const llama_vocab * vocab = llama_model_get_vocab (model ); 1698 1699if (params .logits_file .empty ()) { 1700LOG_ERR ("%s: you must provide a name of a file containing the log probabilities of the base model\n" ,__func__ ); 1701return ; 1702 } 1703 std::ifstream in (params .logits_file .c_str (), std::ios::binary ); 1704if (!in ) { 1705LOG_ERR ("%s: failed to open %s\n" ,__func__ ,params .logits_file .c_str ()); 1706return ; 1707 } 1708 { 1709char check [9 ];check [8 ]= 0 ; 1710in .read (check ,8 ); 1711if (in .fail ()|| strncmp ("_logits_" ,check ,8 )!= 0 ) { 1712LOG_ERR ("%s: %s does not look like a file containing log-probabilities\n" ,__func__ ,params .logits_file .c_str ()); 1713return ; 1714 } 1715 } 1716 1717uint32_t n_ctx ; 1718in .read ((char * )& n_ctx ,sizeof (n_ctx )); 1719if (n_ctx > llama_n_ctx (ctx )) { 1720LOG_ERR ("%s: %s has been computed with %u, while the current context is %d. Increase it with -c and retry\n" , 1721__func__ ,params .logits_file .c_str (),n_ctx ,params .n_ctx ); 1722 } 1723 1724int n_vocab ; 1725int n_chunk ; 1726in .read ((char * )& n_vocab ,sizeof (n_vocab )); 1727in .read ((char * )& n_chunk ,sizeof (n_chunk )); 1728if (in .fail ()) { 1729LOG_ERR ("%s: failed reading n_vocab, n_chunk from %s\n" ,__func__ ,params .logits_file .c_str ()); 1730return ; 1731 } 1732if (n_vocab != llama_vocab_n_tokens (vocab )) { 1733LOG_ERR ("%s: inconsistent vocabulary (%d vs %d)\n" ,__func__ ,n_vocab ,llama_vocab_n_tokens (vocab )); 1734 } 1735 1736 std::vector < llama_token > tokens (size_t (n_ctx )* n_chunk ); 1737if (in .read ((char * )tokens .data (),tokens .size ()* sizeof (tokens [0 ])).fail ()) { 1738LOG_ERR ("%s: failed reading evaluation tokens from %s\n" ,__func__ ,params .logits_file .c_str ()); 1739return ; 1740 } 1741 1742const int n_batch = params .n_batch ; 1743const int num_batches = (static_cast < int > (n_ctx )+ n_batch - 1 ) /n_batch ; 1744// Calculate n_seq based on the logits file's n_ctx, but cap it at what the context supports 1745const int n_seq_max = llama_n_seq_max (ctx ); 1746int n_seq = std::max (1 ,n_batch /static_cast < int > (n_ctx )); 1747if (n_seq > n_seq_max ) { 1748LOG_WRN ("%s: calculated n_seq=%d exceeds context's n_seq_max=%d, capping at %d\n" , 1749__func__ ,n_seq ,n_seq_max ,n_seq_max ); 1750n_seq = n_seq_max ; 1751 } 1752const int nv = 2 * ((n_vocab + 1 )/2 )+ 4 ; 1753const bool add_bos = llama_vocab_get_add_bos (vocab ); 1754GGML_ASSERT (!llama_vocab_get_add_eos (vocab )); 1755 1756llama_batch batch = llama_batch_init (std::min (n_batch ,static_cast < int > (n_ctx )* n_seq ),0 ,1 ); 1757 1758 std::vector < uint16_t > log_probs_uint16 (size_t (n_ctx - 1 - n_ctx /2 )* nv ); 1759 std::vector < float > kld_values (size_t (n_ctx - 1 - n_ctx /2 )* n_chunk ); 1760 std::vector < float > p_diff_values (size_t (n_ctx - 1 - n_ctx /2 )* n_chunk ); 1761 std::vector < float > logits ; 1762if (num_batches > 1 ) { 1763logits .reserve (size_t (n_ctx )* n_vocab ); 1764 } 1765 1766LOG_INF ("%s: computing over %d chunks, n_ctx=%u, batch_size=%d, n_seq=%d\n" ,__func__ ,n_chunk ,n_ctx ,n_batch ,n_seq ); 1767 1768 std::vector < std::thread > workers (std::thread::hardware_concurrency ()- 1 ); 1769 1770auto mean_and_uncertainty = [] (double sum ,double sum2 ,size_t count ) { 1771if (count < 1 ) { 1772return std::make_pair (0. ,0. ); 1773 } 1774double f = sum /count ; 1775double df = sum2 /count - f * f ; 1776df = df > 0 && count > 10 ?sqrt (df /(count - 1 )) :0. ; 1777return std::make_pair (f ,df ); 1778 }; 1779auto covariance = [] (double suma ,double sumb ,double sumab ,size_t count ) { 1780if (count < 10 ) { 1781return 0.0 ; 1782 } 1783double var = sumab /count - (suma /count )* (sumb /count ); 1784var /=count - 1 ; 1785return var ; 1786 }; 1787 1788kl_divergence_result kld ; 1789auto kld_ptr = kld_values .data (); 1790auto p_diff_ptr = p_diff_values .data (); 1791 1792const int first = n_ctx /2 ; 1793 1794for (int i = 0 ;i < n_chunk ;i += n_seq ) { 1795const int start = i * n_ctx ; 1796const int end = start + n_ctx ; 1797 1798const int n_seq_batch = std::min (n_seq ,n_chunk - i ); 1799 1800const auto t_start = std::chrono::high_resolution_clock::now (); 1801 1802// clear the KV cache 1803llama_memory_clear (llama_get_memory (ctx ), true); 1804 1805for (int j = 0 ;j < num_batches ;++ j ) { 1806const int batch_start = start + j * n_batch ; 1807const int batch_size = std::min (end - batch_start ,n_batch ); 1808 1809int n_outputs = 0 ; 1810 1811common_batch_clear (batch ); 1812for (int seq = 0 ;seq < n_seq_batch ;seq ++ ) { 1813int seq_start = batch_start + seq * n_ctx ; 1814 1815// save original token and restore it after eval 1816const auto token_org = tokens [seq_start ]; 1817 1818// add BOS token for the first batch of each chunk 1819if (add_bos && j == 0 ) { 1820tokens [seq_start ]= llama_vocab_bos (vocab ); 1821 } 1822 1823for (int k = 0 ;k < batch_size ;++ k ) { 1824const int pos = j * n_batch + k ; 1825const bool need_logits = pos >=first ; 1826common_batch_add (batch ,tokens [seq_start + k ],pos , {seq },need_logits ); 1827n_outputs += need_logits ; 1828 } 1829 1830// restore the original token in case it was set to BOS 1831tokens [seq_start ]= token_org ; 1832 } 1833 1834if (llama_decode (ctx ,batch )) { 1835LOG_ERR ("%s : failed to decode\n" ,__func__ ); 1836llama_batch_free (batch ); 1837return ; 1838 } 1839 1840if (num_batches > 1 && n_outputs > 0 ) { 1841const auto * batch_logits = llama_get_logits (ctx ); 1842logits .insert (logits .end (),batch_logits ,batch_logits + size_t (n_outputs )* n_vocab ); 1843 } 1844 } 1845 1846if (i == 0 ) { 1847llama_synchronize (ctx ); 1848const auto t_end = std::chrono::high_resolution_clock::now (); 1849const float t_total = std::chrono::duration < float > (t_end - t_start ).count (); 1850LOG_INF ("%s: %.2f seconds per pass - ETA " ,__func__ ,t_total ); 1851int total_seconds = (int )(t_total * n_chunk /n_seq ); 1852if (total_seconds >=60 * 60 ) { 1853LOG ("%d hours " ,total_seconds / (60 * 60 )); 1854total_seconds = total_seconds % (60 * 60 ); 1855 } 1856LOG ("%.2f minutes\n" ,total_seconds /60.0 ); 1857LOG ("\n" ); 1858LOG ("chunk PPL ln(PPL(Q)/PPL(base)) KL Divergence Δp RMS Same top p\n" ); 1859 } 1860 1861// Read log probs for each sequence in the batch 1862for (int seq = 0 ;seq < n_seq_batch ;seq ++ ) { 1863if (in .read ((char * )log_probs_uint16 .data (),log_probs_uint16 .size ()* sizeof (uint16_t )).fail ()) { 1864LOG_ERR ("%s: failed reading log-probs for chunk %d\n" ,__func__ ,i + seq ); 1865llama_batch_free (batch ); 1866return ; 1867 } 1868 1869const float * all_logits = num_batches > 1 ?logits .data () :llama_get_logits_ith (ctx ,seq * n_ctx + first ); 1870 1871process_logits (n_vocab ,all_logits ,tokens .data ()+ start + seq * n_ctx + first ,n_ctx - 1 - first , 1872workers ,log_probs_uint16 ,kld ,kld_ptr ,p_diff_ptr ); 1873p_diff_ptr += n_ctx - 1 - first ; 1874kld_ptr += n_ctx - 1 - first ; 1875 1876LOG ("%4d" ,i + seq + 1 ); 1877 1878auto log_ppl = mean_and_uncertainty (kld .sum_nll ,kld .sum_nll2 ,kld .count ); 1879const double ppl_val = exp (log_ppl .first ); 1880const double ppl_unc = ppl_val * log_ppl .second ; 1881LOG (" %9.4lf ± %9.4lf" ,ppl_val ,ppl_unc ); 1882 1883auto log_ppl_base = mean_and_uncertainty (kld .sum_nll_base ,kld .sum_nll_base2 ,kld .count ); 1884const double log_ppl_cov = covariance (kld .sum_nll ,kld .sum_nll_base ,kld .sum_nll_nll_base ,kld .count ); 1885const double log_ppl_ratio_val = log_ppl .first - log_ppl_base .first ; 1886const double log_ppl_ratio_unc = sqrt (log_ppl .second * log_ppl .second + log_ppl_base .second * log_ppl_base .second - 2.0 * log_ppl_cov ); 1887LOG (" %10.5lf ± %10.5lf" ,log_ppl_ratio_val ,log_ppl_ratio_unc ); 1888 1889auto kl_div = mean_and_uncertainty (kld .sum_kld ,kld .sum_kld2 ,kld .count ); 1890LOG (" %10.5lf ± %10.5lf" ,kl_div .first ,kl_div .second ); 1891 1892auto p_diff_mse = mean_and_uncertainty (kld .sum_p_diff2 ,kld .sum_p_diff4 ,kld .count ); 1893const double p_diff_rms_val = sqrt (p_diff_mse .first ); 1894const double p_diff_rms_unc = 0.5 /p_diff_rms_val * p_diff_mse .second ; 1895LOG (" %6.3lf ± %6.3lf %%" ,100.0 * p_diff_rms_val ,100.0 * p_diff_rms_unc ); 1896 1897double p_top_val = 1. * kld .n_same_top /kld .count ; 1898double p_top_unc = sqrt (p_top_val * (1 - p_top_val )/(kld .count - 1 )); 1899LOG (" %6.3lf ± %6.3lf %%" ,100.0 * p_top_val ,100.0 * p_top_unc ); 1900 1901LOG ("\n" ); 1902 } 1903 1904logits .clear (); 1905 } 1906 1907llama_batch_free (batch ); 1908LOG ("\n" ); 1909 1910if (kld .count < 100 )return ;// we do not wish to do statistics on so few values 1911 1912 std::sort (kld_values .begin (),kld_values .end ()); 1913 std::sort (p_diff_values .begin (),p_diff_values .end ()); 1914 1915LOG ("====== Perplexity statistics ======\n" ); 1916 1917auto log_ppl = mean_and_uncertainty (kld .sum_nll ,kld .sum_nll2 ,kld .count ); 1918const double ppl_val = exp (log_ppl .first ); 1919const double ppl_unc = ppl_val * log_ppl .second ;// ppl_unc = sqrt( (dexp(x) / dx) ** 2 * log_ppl.second ** 2 ) 1920LOG ("Mean PPL(Q) : %10.6lf ± %10.6lf\n" ,ppl_val ,ppl_unc ); 1921 1922auto log_ppl_base = mean_and_uncertainty (kld .sum_nll_base ,kld .sum_nll_base2 ,kld .count ); 1923const double ppl_base_val = exp (log_ppl_base .first ); 1924const double ppl_base_unc = ppl_base_val * log_ppl_base .second ;// ppl_base_unc = sqrt( (dexp(x) / dx) ** 2 * log_ppl_base.second ** 2 ) 1925LOG ("Mean PPL(base) : %10.6lf ± %10.6lf\n" ,ppl_base_val ,ppl_base_unc ); 1926 1927const double log_ppl_cov = covariance (kld .sum_nll ,kld .sum_nll_base ,kld .sum_nll_nll_base ,kld .count ); 1928// LOG("Cov(ln(PPL(Q)), ln(PPL(base))): %10.6lf\n", log_ppl_cov); 1929const double log_ppl_cor = log_ppl_cov / (log_ppl .second * log_ppl_base .second ); 1930LOG ("Cor(ln(PPL(Q)), ln(PPL(base))): %6.2lf%%\n" ,100.0 * log_ppl_cor ); 1931 1932const double log_ppl_ratio_val = log_ppl .first - log_ppl_base .first ; 1933const double log_ppl_ratio_unc = sqrt (log_ppl .second * log_ppl .second + log_ppl_base .second * log_ppl_base .second - 2.0 * log_ppl_cov ); 1934LOG ("Mean ln(PPL(Q)/PPL(base)) : %10.6lf ± %10.6lf\n" ,log_ppl_ratio_val ,log_ppl_ratio_unc ); 1935 1936const double ppl_ratio_val = exp (log_ppl_ratio_val ); 1937const double ppl_ratio_unc = ppl_ratio_val * log_ppl_ratio_unc ;// ppl_ratio_unc = sqrt( (dexp(x) / dx) ** 2 * log_ppl_ratio.second ** 2 ) 1938LOG ("Mean PPL(Q)/PPL(base) : %10.6lf ± %10.6lf\n" ,ppl_ratio_val ,ppl_ratio_unc ); 1939 1940const double ppl_cov = ppl_val * ppl_base_val * log_ppl_cov ; 1941const double ppl_diff_val = ppl_val - ppl_base_val ; 1942const double ppl_diff_unc = sqrt (ppl_unc * ppl_unc + ppl_base_unc * ppl_base_unc - 2.0 * ppl_cov ); 1943LOG ("Mean PPL(Q)-PPL(base) : %10.6lf ± %10.6lf\n" ,ppl_diff_val ,ppl_diff_unc ); 1944 1945LOG ("\n" ); 1946 1947LOG ("====== KL divergence statistics ======\n" ); 1948auto kl_div = mean_and_uncertainty (kld .sum_kld ,kld .sum_kld2 ,kld .count ); 1949LOG ("Mean KLD: %10.6lf ± %10.6lf\n" ,kl_div .first ,kl_div .second ); 1950auto kld_median = kld_values .size ()%2 == 0 ?0.5f * (kld_values [kld_values .size ()/2 ]+ kld_values [kld_values .size ()/2 - 1 ]) 1951 :kld_values [kld_values .size ()/2 ]; 1952 1953auto percentile = [] (std::vector < float > values ,float fraction ) { 1954if (fraction <=0 )return values .front (); 1955if (fraction >=1 )return values .back (); 1956float p = fraction * (values .size ()- 1 ); 1957size_t ip = size_t (p );p -= ip ; 1958return (1 - p )* values [ip ]+ p * values [std::min (ip + 1 ,values .size ()- 1 )]; 1959 }; 1960 1961LOG ("Maximum KLD: %10.6f\n" ,kld_values .back ()); 1962LOG ("99.9%% KLD: %10.6f\n" ,percentile (kld_values ,0.999f )); 1963LOG ("99.0%% KLD: %10.6f\n" ,percentile (kld_values ,0.990f )); 1964LOG ("95.0%% KLD: %10.6f\n" ,percentile (kld_values ,0.950f )); 1965LOG ("90.0%% KLD: %10.6f\n" ,percentile (kld_values ,0.900f )); 1966LOG ("Median KLD: %10.6f\n" ,kld_median ); 1967LOG ("10.0%% KLD: %10.6f\n" ,percentile (kld_values ,0.100f )); 1968LOG (" 5.0%% KLD: %10.6f\n" ,percentile (kld_values ,0.050f )); 1969LOG (" 1.0%% KLD: %10.6f\n" ,percentile (kld_values ,0.010f )); 1970LOG (" 0.1%% KLD: %10.6f\n" ,percentile (kld_values ,0.001f )); 1971LOG ("Minimum KLD: %10.6f\n" ,kld_values .front ()); 1972 1973LOG ("\n" ); 1974 1975LOG ("====== Token probability statistics ======\n" ); 1976 1977auto p_diff = mean_and_uncertainty (kld .sum_p_diff ,kld .sum_p_diff2 ,kld .count ); 1978LOG ("Mean Δp: %6.3lf ± %5.3lf %%\n" ,100.0 * p_diff .first ,100.0 * p_diff .second ); 1979 1980auto p_diff_median = p_diff_values .size ()%2 == 0 ?0.5f * (p_diff_values [p_diff_values .size ()/2 ]+ p_diff_values [p_diff_values .size ()/2 - 1 ]) 1981 :p_diff_values [p_diff_values .size ()/2 ]; 1982 1983LOG ("Maximum Δp: %6.3lf%%\n" ,100.0 * p_diff_values .back ()); 1984LOG ("99.9%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.999f )); 1985LOG ("99.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.990f )); 1986LOG ("95.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.950f )); 1987LOG ("90.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.900f )); 1988LOG ("75.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.750f )); 1989LOG ("Median Δp: %6.3lf%%\n" ,100.0 * p_diff_median ); 1990LOG ("25.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.250f )); 1991LOG ("10.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.100f )); 1992LOG (" 5.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.050f )); 1993LOG (" 1.0%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.010f )); 1994LOG (" 0.1%% Δp: %6.3lf%%\n" ,100.0 * percentile (p_diff_values ,0.001f )); 1995LOG ("Minimum Δp: %6.3lf%%\n" ,100.0 * p_diff_values .front ()); 1996 1997auto p_diff_mse = mean_and_uncertainty (kld .sum_p_diff2 ,kld .sum_p_diff4 ,kld .count ); 1998// LOG("MSE Δp : %10.6lf ± %10.6lf\n", p_diff_mse.first, p_diff_mse.second); 1999 2000const double p_diff_rms_val = sqrt (p_diff_mse .first ); 2001const double p_diff_rms_unc = 0.5 /p_diff_rms_val * p_diff_mse .second ; 2002LOG ("RMS Δp : %6.3lf ± %5.3lf %%\n" ,100.0 * p_diff_rms_val ,100.0 * p_diff_rms_unc ); 2003 2004const double same_top_p = 1.0 * kld .n_same_top /kld .count ; 2005LOG ("Same top p: %6.3lf ± %5.3lf %%\n" ,100.0 * same_top_p ,100.0 * sqrt (same_top_p * (1.0 - same_top_p )/(kld .count - 1 ))); 2006} 2007 2008// satisfies -Wmissing-declarations 2009int llama_perplexity (int argc ,char ** argv ); 2010 2011int llama_perplexity (int argc ,char ** argv ) { 2012 std::setlocale (LC_NUMERIC ,"C" ); 2013 2014common_params params ; 2015 2016params .n_ctx = 512 ; 2017params .escape = false; 2018 2019common_init (); 2020 2021if (!common_params_parse (argc ,argv ,params ,LLAMA_EXAMPLE_PERPLEXITY )) { 2022return 1 ; 2023 } 2024 2025const int32_t n_ctx = params .n_ctx ; 2026if (n_ctx <=0 ) { 2027LOG_ERR ("%s: perplexity tool requires '--ctx-size' > 0\n" ,__func__ ); 2028return 1 ; 2029 } 2030 2031if (params .hellaswag || params .winogrande || params .multiple_choice ) { 2032params .n_parallel = std::max (4 ,params .n_parallel ); 2033params .kv_unified = true; 2034 }else {// Perplexity & KL divergence 2035params .n_parallel = std::max (1 ,params .n_batch /n_ctx ); 2036 } 2037params .n_ctx = params .n_parallel * n_ctx ; 2038params .n_batch = std::min (params .n_batch ,params .n_ctx ); 2039 2040if (params .ppl_stride > 0 ) { 2041LOG_INF ("Will perform strided perplexity calculation -> adjusting context size from %d to %d\n" , 2042params .n_ctx ,params .n_ctx + params .ppl_stride /2 ); 2043params .n_ctx += params .ppl_stride /2 ; 2044 } 2045 2046llama_backend_init (); 2047llama_numa_init (params .numa ); 2048 2049// load the model and apply lora adapter, if any 2050auto llama_init = common_init_from_params (params ); 2051 2052auto * model = llama_init -> model (); 2053auto * ctx = llama_init -> context (); 2054 2055if (model == nullptr ) { 2056LOG_ERR ("%s: unable to load model\n" ,__func__ ); 2057return 1 ; 2058 } 2059 2060if (ctx == nullptr ) { 2061LOG_ERR ("%s: failed to create context\n" ,__func__ ); 2062return 1 ; 2063 } 2064 2065const int n_ctx_train = llama_model_n_ctx_train (model ); 2066 2067if (params .n_ctx > n_ctx_train ) { 2068LOG_WRN ("%s: model was trained on only %d context tokens (%d specified)\n" , 2069__func__ ,n_ctx_train ,params .n_ctx ); 2070 } 2071 2072// print system information 2073 { 2074LOG_INF ("\n" ); 2075LOG_INF ("%s\n" ,common_params_get_system_info (params ).c_str ()); 2076 } 2077 2078struct results_perplexity results ; 2079if (params .hellaswag ) { 2080hellaswag_score (ctx ,params ); 2081 }else if (params .winogrande ) { 2082winogrande_score (ctx ,params ); 2083 }else if (params .multiple_choice ) { 2084multiple_choice_score (ctx ,params ); 2085 }else if (params .kl_divergence ) { 2086kl_divergence (ctx ,params ); 2087 }else { 2088results = perplexity (ctx ,params ,n_ctx ); 2089 } 2090 2091LOG ("\n" ); 2092llama_perf_context_print (ctx ); 2093common_memory_breakdown_print (ctx ); 2094 2095llama_backend_free (); 2096 2097return 0 ; 2098}