char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
dd1ea5243
char/aliceai-t5-moe
1#include "arg.h" 2#include "common.h" 3#include "sampling.h" 4#include "speculative.h" 5#include "log.h" 6#include "llama.h" 7 8#include <algorithm> 9#include <clocale> 10#include <cstdio> 11#include <cstring> 12#include <random> 13#include <set> 14#include <string> 15#include <vector> 16 17#define SPEC_VOCAB_MAX_SIZE_DIFFERENCE 128 18#define SPEC_VOCAB_CHECK_START_TOKEN_ID 5 19 20struct seq_draft { 21bool active = false; 22bool drafting = false; 23bool skip = false; 24 25int i_batch_dft = 0 ; 26 std::vector < int > i_batch_tgt ; 27 28 std::vector < llama_token > tokens ; 29 std::vector < std::vector < llama_token_data >> dists ; 30 31struct common_sampler * smpl = nullptr ; 32}; 33 34int main (int argc ,char ** argv ) { 35 std::setlocale (LC_NUMERIC ,"C" ); 36 37common_params params ; 38 39// needed to get candidate probs even for temp <= 0.0 40params .sampling .n_probs = 128 ; 41 42common_init (); 43 44if (!common_params_parse (argc ,argv ,params ,LLAMA_EXAMPLE_SPECULATIVE )) { 45return 1 ; 46 } 47 48if (params .n_predict < -1 ) { 49LOG_ERR ("%s: --n-predict must be >= -1\n" ,__func__ ); 50return 1 ; 51 } 52 53if (params .speculative .draft .mparams .path .empty ()) { 54LOG_ERR ("%s: --model-draft is required\n" ,__func__ ); 55return 1 ; 56 } 57 58// max number of parallel drafting sequences (i.e. tree branches) 59const int n_seq_dft = params .n_parallel ; 60 61const auto output_limits = common_speculative_get_output_limits ( 62params .n_batch ,params .n_parallel ,params .speculative .draft .n_max ); 63params .n_outputs_max = output_limits .total ; 64params .n_outputs_max_per_seq = output_limits .per_seq ; 65 66// probability threshold for splitting a draft branch (only for n_seq_dft > 1) 67const float p_draft_split = params .speculative .draft .p_split ; 68 69 std::default_random_engine rng (params .sampling .seed == LLAMA_DEFAULT_SEED ? std::random_device ()() :params .sampling .seed ); 70 std::uniform_real_distribution <> u_dist ; 71 72// init llama.cpp 73llama_backend_init (); 74llama_numa_init (params .numa ); 75 76llama_model * model_tgt = NULL ; 77llama_model * model_dft = NULL ; 78 79llama_context * ctx_tgt = NULL ; 80llama_context * ctx_dft = NULL ; 81 82// load the target model 83auto llama_init_tgt = common_init_from_params (params ); 84 85model_tgt = llama_init_tgt -> model (); 86ctx_tgt = llama_init_tgt -> context (); 87 88// load the draft model 89params .devices = params .speculative .draft .devices ; 90params .model = params .speculative .draft .mparams ; 91params .n_gpu_layers = params .speculative .draft .n_gpu_layers ; 92params .n_outputs_max = params .n_parallel ; 93params .n_outputs_max_per_seq = 1 ; 94if (params .speculative .draft .cpuparams .n_threads > 0 ) { 95params .cpuparams .n_threads = params .speculative .draft .cpuparams .n_threads ; 96 } 97 98params .cpuparams_batch .n_threads = params .speculative .draft .cpuparams_batch .n_threads ; 99params .tensor_buft_overrides = params .speculative .draft .tensor_buft_overrides ; 100 101auto llama_init_dft = common_init_from_params (params ); 102 103model_dft = llama_init_dft -> model (); 104ctx_dft = llama_init_dft -> context (); 105 106const llama_vocab * vocab_tgt = llama_model_get_vocab (model_tgt ); 107const llama_vocab * vocab_dft = llama_model_get_vocab (model_dft ); 108 109const bool vocab_type_tgt = llama_vocab_type (vocab_tgt ); 110LOG_DBG ("vocab_type tgt: %d\n" ,vocab_type_tgt ); 111 112const bool vocab_type_dft = llama_vocab_type (vocab_dft ); 113LOG_DBG ("vocab_type dft: %d\n" ,vocab_type_dft ); 114 115if (vocab_type_tgt != vocab_type_dft ) { 116LOG_ERR ("%s: draft model vocab type must match target model to use speculation but " ,__func__ ); 117LOG_ERR ("vocab_type_dft = %d while vocab_type_tgt = %d\n" ,vocab_type_dft ,vocab_type_tgt ); 118return 1 ; 119 } 120 121if (llama_vocab_get_add_bos (vocab_tgt )!= llama_vocab_get_add_bos (vocab_dft )|| 122 (llama_vocab_get_add_bos (vocab_tgt )&& llama_vocab_bos (vocab_tgt )!= llama_vocab_bos (vocab_dft ))) { 123LOG_ERR ("%s: draft model bos tokens must match target model to use speculation. add: %d - %d, id: %d - %d)\n" , 124__func__ , 125llama_vocab_get_add_bos (vocab_tgt ),llama_vocab_get_add_bos (vocab_dft ), 126llama_vocab_bos (vocab_tgt ),llama_vocab_bos (vocab_dft )); 127return 1 ; 128 } 129 130if (llama_vocab_get_add_eos (vocab_tgt )!= llama_vocab_get_add_eos (vocab_dft )|| 131 (llama_vocab_get_add_eos (vocab_tgt )&& llama_vocab_eos (vocab_tgt )!= llama_vocab_eos (vocab_dft ))) { 132LOG_ERR ("%s: draft model eos tokens must match target model to use speculation. add: %d - %d, id: %d - %d)\n" , 133__func__ , 134llama_vocab_get_add_eos (vocab_tgt ),llama_vocab_get_add_eos (vocab_dft ), 135llama_vocab_eos (vocab_tgt ),llama_vocab_eos (vocab_dft )); 136return 1 ; 137 } 138 139 { 140const int n_vocab_tgt = llama_vocab_n_tokens (vocab_tgt ); 141const int n_vocab_dft = llama_vocab_n_tokens (vocab_dft ); 142const int vocab_diff = n_vocab_tgt > n_vocab_dft 143 ?n_vocab_tgt - n_vocab_dft 144 :n_vocab_dft - n_vocab_tgt ; 145 146if (vocab_diff > SPEC_VOCAB_MAX_SIZE_DIFFERENCE ) { 147LOG_ERR ("%s: draft model vocab must closely match target model to use speculation but " ,__func__ ); 148LOG_ERR ("target vocab size %d does not match draft vocab size %d - difference %d, max allowed %d\n" , 149n_vocab_tgt ,llama_vocab_n_tokens (vocab_dft ),vocab_diff ,SPEC_VOCAB_MAX_SIZE_DIFFERENCE ); 150return 1 ; 151 } 152 153for (int i = SPEC_VOCAB_CHECK_START_TOKEN_ID ;i < std::min (n_vocab_tgt ,n_vocab_dft );++ i ) { 154const char * token_text_tgt = llama_vocab_get_text (vocab_tgt ,i ); 155const char * token_text_dft = llama_vocab_get_text (vocab_dft ,i ); 156 157if (std::strcmp (token_text_tgt ,token_text_dft )!= 0 ) { 158LOG_ERR ("%s: draft model vocab must match target model to use speculation but " ,__func__ ); 159LOG_ERR ("token %d content differs - target '%s', draft '%s'\n" ,i , 160common_token_to_piece (vocab_tgt ,i ).c_str (), 161common_token_to_piece (vocab_dft ,i ).c_str ()); 162return 1 ; 163 } 164 } 165 } 166 167auto * mem_tgt = llama_get_memory (ctx_tgt ); 168auto * mem_dft = llama_get_memory (ctx_dft ); 169 170// Tokenize the prompt 171 std::vector < llama_token > inp ; 172inp = common_tokenize (ctx_tgt ,params .prompt , true, true); 173 174const int max_context_size = llama_n_ctx (ctx_tgt ); 175const int max_tokens_list_size = max_context_size - 4 ; 176 177if ((int )inp .size ()> max_tokens_list_size ) { 178LOG_ERR ("%s: prompt too long (%d tokens, max %d)\n" ,__func__ , (int )inp .size (),max_tokens_list_size ); 179return 1 ; 180 } 181 182LOG ("\n\n" ); 183 184for (auto id :inp ) { 185LOG ("%s" ,common_token_to_piece (ctx_tgt ,id ).c_str ()); 186 } 187 188const int n_input = inp .size (); 189 190const auto t_enc_start = ggml_time_us (); 191 192// eval the prompt with both models 193llama_decode (ctx_tgt ,llama_batch_get_one (inp .data (),n_input - 1 )); 194llama_decode (ctx_tgt ,llama_batch_get_one (& inp .back (),1 )); 195llama_decode (ctx_dft ,llama_batch_get_one (inp .data (),n_input )); 196 197const auto t_enc_end = ggml_time_us (); 198 199// the 2 models should have the same vocab 200//GGML_ASSERT(n_vocab == llama_vocab_n_tokens(model_dft)); 201 202// how many tokens to draft each time 203int n_draft = params .speculative .draft .n_max ; 204 205int n_predict = 0 ; 206int n_drafted = 0 ; 207int n_accept = 0 ; 208 209int n_past_tgt = inp .size (); 210int n_past_dft = inp .size (); 211 212// used to determine end of generation 213bool has_eos = false; 214 215// target model sampling context (reuse the llama_context's sampling instance) 216struct common_sampler * smpl = common_sampler_init (model_tgt ,params .sampling ); 217 218// draft sequence data 219 std::vector < seq_draft > drafts (n_seq_dft ); 220 221for (int s = 0 ;s < n_seq_dft ;++ s ) { 222// allocate llama_sampler for each draft sequence 223drafts [s ].smpl = common_sampler_init (model_dft ,params .sampling ); 224 } 225 226llama_batch batch_dft = llama_batch_init (llama_n_batch (ctx_dft ),0 ,1 ); 227llama_batch batch_tgt = llama_batch_init (llama_n_batch (ctx_tgt ),0 ,n_seq_dft ); 228 229const auto t_dec_start = ggml_time_us (); 230 231// sample from the last token of the prompt 232drafts [0 ].i_batch_tgt .resize (1 ); 233drafts [0 ].i_batch_tgt [0 ]= 0 ; 234 235while (true) { 236 std::set < int > active_seqs = {}; 237 238// print current draft sequences 239for (int s = 0 ;s < n_seq_dft ;++ s ) { 240if (!drafts [s ].active ) { 241continue ; 242 } 243 244active_seqs .insert (s ); 245const auto & tokens = drafts [s ].tokens ; 246 247LOG_DBG ("draft %d: %s\n" ,s ,string_from (ctx_dft ,tokens ).c_str ()); 248 } 249 250int i_dft = 0 ; 251int s_keep = 0 ; 252 253llama_token token_id ; 254 std::string token_str ; 255 256// loop until we fail to accept a drafted token or we run out of drafted tokens 257while (true) { 258 259// check if the target token matches any of the drafts 260// for stochastic sampling, attempt to match the token with the drafted tokens 261 { 262bool accept = false; 263if (params .sampling .temp > 0 ) { 264// stochastic verification 265common_sampler_sample (smpl ,ctx_tgt ,drafts [s_keep ].i_batch_tgt [i_dft ], true); 266 267auto & dist_tgt = * common_sampler_get_candidates (smpl , true); 268 269float p_tgt = 0.0f ; 270float p_dft = 0.0f ; 271 272while (active_seqs .size ()> 0 ) { 273// randomly select a sequence to verify from active sequences 274 std::uniform_int_distribution < unsigned int > u_int_dist (0 ,active_seqs .size ()- 1 ); 275int s = * std::next (active_seqs .begin (),u_int_dist (rng )); 276if (i_dft >= (int )drafts [s ].tokens .size ()) { 277drafts [s ].active = false; 278active_seqs .erase (s ); 279continue ; 280 } 281if (accept ) { 282// if we already accepted a token, we can skip the rest 283if (drafts [s ].tokens [i_dft ]!= drafts [s_keep ].tokens [i_dft ]) { 284drafts [s ].active = false; 285active_seqs .erase (s ); 286 } 287continue ; 288 } 289 290LOG_DBG ("verifying sequence #%d at pos #%d from %d active sequence(s)\n" ,s ,i_dft , (int )active_seqs .size ()); 291float r = u_dist (rng ); 292llama_token_data_array dist_dft = {drafts [s ].dists [i_dft ].data () ,drafts [s ].dists [i_dft ].size (),LLAMA_TOKEN_NULL , true }; 293 294//GGML_ASSERT(dist_tgt.size <= dist_dft.size); 295 296// acquire the token probabilities assigned by the draft and target models 297for (size_t i = 0 ;i < dist_tgt .size ;i ++ ) { 298if (dist_tgt .data [i ].id == drafts [s ].tokens [i_dft ]) { 299p_tgt = dist_tgt .data [i ].p ; 300break ; 301 } 302 } 303for (size_t i = 0 ;i < dist_dft .size ;i ++ ) { 304if (dist_dft .data [i ].id == drafts [s ].tokens [i_dft ]) { 305p_dft = dist_dft .data [i ].p ; 306break ; 307 } 308 } 309LOG_DBG ("r = %f, p_dft = %f, p_tgt = %f\n" ,r ,p_dft ,p_tgt ); 310if (r <=p_tgt /p_dft ) { 311s_keep = s ; 312accept = true; 313token_id = drafts [s ].tokens [i_dft ]; 314token_str = common_token_to_piece (ctx_tgt ,token_id ); 315common_sampler_accept (smpl ,token_id , true); 316 317LOG_DBG ("draft token %d of sequence %d (%d, '%s') accepted\n" ,i_dft ,s ,token_id ,token_str .c_str ()); 318break ; 319 }else { 320LOG_DBG ("draft token %d of sequence %d (%d, '%s') rejected\n" ,i_dft ,s ,drafts [s ].tokens [i_dft ],common_token_to_piece (ctx_tgt ,drafts [s ].tokens [i_dft ]).c_str ()); 321drafts [s ].active = false; 322 323// calculate residual probability 324GGML_ASSERT (dist_tgt .sorted ); 325GGML_ASSERT (dist_dft .sorted ); 326 327// sort dist by id 328 std::sort (dist_tgt .data ,dist_tgt .data + dist_tgt .size , [](const llama_token_data & a ,const llama_token_data & b ) { 329return a .id < b .id ; 330 }); 331 std::sort (dist_dft .data ,dist_dft .data + dist_dft .size , [](const llama_token_data & a ,const llama_token_data & b ) { 332return a .id < b .id ; 333 }); 334 335float sum_probs = 0.0f ; 336 337for (size_t i = 0 ;i < dist_tgt .size ;i ++ ) { 338if (i < dist_dft .size ) { 339dist_tgt .data [i ].p = std::max (0.0f ,dist_tgt .data [i ].p - dist_dft .data [i ].p ); 340 }else { 341dist_tgt .data [i ].p = std::max (0.0f ,dist_tgt .data [i ].p ); 342 } 343 344sum_probs += dist_tgt .data [i ].p ; 345 } 346 347for (size_t i = 0 ;i < dist_tgt .size ;i ++ ) { 348dist_tgt .data [i ].p /=sum_probs ; 349 } 350 351// sort dist_tgt by p desc 352 std::sort (dist_tgt .data ,dist_tgt .data + dist_tgt .size , [](const llama_token_data & a ,const llama_token_data & b ) { 353return a .p > b .p ; 354 }); 355 } 356 357active_seqs .erase (s ); 358for (int i = 0 ;i < n_seq_dft ;i ++ ) { 359if (i == s ) { 360continue ; 361 } 362if (drafts [i ].active && drafts [i ].tokens [i_dft ]== drafts [s ].tokens [i_dft ]) { 363// synchronize active status for sequences with the same drafted token 364drafts [i ].active = drafts [i ].active && accept ; 365if (!drafts [i ].active ) { 366active_seqs .erase (s ); 367 } 368 } 369 } 370 } 371 372if (!accept ) { 373// all drafted tokens were rejected 374// sample from the target model 375LOG_DBG ("all drafted tokens were rejected, sampling from residual distribution\n" ); 376 std::vector < float > probs (dist_tgt .size ); 377for (size_t i = 0 ;i < dist_tgt .size ;++ i ) { 378probs [i ]= dist_tgt .data [i ].p ; 379 } 380 381 std::discrete_distribution <> dist (probs .begin (),probs .end ()); 382 383const int idx = dist (rng ); 384 385token_id = dist_tgt .data [idx ].id ; 386common_sampler_accept (smpl ,token_id , true); 387token_str = common_token_to_piece (ctx_tgt ,token_id ); 388 } 389 }else { 390// greedy verification 391 392// sample from the target model 393LOG_DBG ("sampling target: s_keep = %3d, i_dft = %3d, i_batch_tgt = %3d\n" ,s_keep ,i_dft ,drafts [s_keep ].i_batch_tgt [i_dft ]); 394token_id = common_sampler_sample (smpl ,ctx_tgt ,drafts [s_keep ].i_batch_tgt [i_dft ]); 395 396common_sampler_accept (smpl ,token_id , true); 397 398token_str = common_token_to_piece (ctx_tgt ,token_id ); 399 400for (int s = 0 ;s < n_seq_dft ;++ s ) { 401if (!drafts [s ].active ) { 402continue ; 403 } 404 405if (i_dft < (int )drafts [s ].tokens .size ()&& token_id == drafts [s ].tokens [i_dft ]) { 406LOG_DBG ("the sampled target token matches the %dth drafted token of sequence %d (%d, '%s') - accepted\n" ,i_dft ,s ,token_id ,token_str .c_str ()); 407 408s_keep = s ; 409accept = true; 410 }else { 411drafts [s ].active = false; 412 } 413 } 414 } 415 416if (llama_vocab_is_eog (vocab_tgt ,token_id )) { 417has_eos = true; 418 } 419++ n_predict ; 420 421if (accept ) { 422++ n_accept ; 423++ n_past_tgt ; 424++ n_past_dft ; 425++ i_dft ; 426if (params .use_color ) { 427// Color token according to its origin sequence 428LOG ("\u001b[%dm%s\u001b[37m" , (36 - s_keep %6 ),token_str .c_str ()); 429 }else { 430LOG ("%s" ,token_str .c_str ()); 431 } 432continue ; 433 }else { 434LOG ("%s" ,token_str .c_str ()); 435break ; 436 } 437 } 438 } 439 440 { 441LOG_DBG ("the sampled target token (%d, '%s') did not match, or we ran out of drafted tokens\n" ,token_id ,token_str .c_str ()); 442 443// TODO: simplify 444 { 445LOG_DBG ("keeping sequence %d, n_past_tgt = %d, n_past_dft = %d\n" ,s_keep ,n_past_tgt ,n_past_dft ); 446 447llama_memory_seq_keep (mem_dft ,s_keep ); 448llama_memory_seq_cp (mem_dft ,s_keep ,0 ,-1 ,-1 ); 449llama_memory_seq_keep (mem_dft ,0 ); 450 451llama_memory_seq_rm (mem_tgt ,s_keep ,n_past_tgt ,-1 ); 452llama_memory_seq_keep (mem_tgt ,s_keep ); 453llama_memory_seq_cp (mem_tgt ,s_keep ,0 ,-1 ,-1 ); 454llama_memory_seq_keep (mem_tgt ,0 ); 455 } 456 457for (int s = 0 ;s < n_seq_dft ;++ s ) { 458drafts [s ].active = false; 459drafts [s ].tokens .clear (); 460drafts [s ].i_batch_tgt .clear (); 461drafts [s ].dists .clear (); 462 } 463// note: will be erased after the speculation phase 464drafts [0 ].tokens .push_back (token_id ); 465drafts [0 ].dists .push_back (std::vector < llama_token_data > ()); 466drafts [0 ].i_batch_tgt .push_back (0 ); 467 468common_batch_clear (batch_dft ); 469common_batch_add (batch_dft ,token_id ,n_past_dft , {0 }, true); 470 471llama_memory_seq_rm (mem_dft ,0 ,n_past_dft ,-1 ); 472// LOG_DBG("dft batch: %s\n", LOG_BATCH_TOSTR_PRETTY(ctx_dft, batch_dft).c_str()); 473llama_decode (ctx_dft ,batch_dft ); 474 475++ n_past_dft ; 476 } 477 478if ((params .n_predict >=0 && n_predict > params .n_predict )|| has_eos ) { 479break ; 480 } 481 482if (drafts [0 ].smpl ) { 483common_sampler_free (drafts [0 ].smpl ); 484 } 485drafts [0 ].smpl = common_sampler_clone (smpl ); 486 487int n_seq_cur = 1 ; 488int n_past_cur = n_past_dft ; 489 490for (int s = 0 ;s < n_seq_dft ;++ s ) { 491drafts [s ].active = false; 492drafts [s ].drafting = false; 493 } 494drafts [0 ].active = true; 495drafts [0 ].drafting = true; 496drafts [0 ].i_batch_dft = 0 ; 497 498common_batch_clear (batch_tgt ); 499common_batch_add (batch_tgt ,drafts [0 ].tokens [0 ],n_past_tgt , {0 }, true); 500 501// sample n_draft tokens from the draft model using tree-based sampling 502for (int i = 0 ;i < n_draft ;++ i ) { 503batch_dft .n_tokens = 0 ; 504 505for (int s = 0 ;s < n_seq_dft ;++ s ) { 506drafts [s ].skip = false; 507 } 508 509for (int s = 0 ;s < n_seq_dft ;++ s ) { 510if (!drafts [s ].drafting || drafts [s ].skip ) { 511continue ; 512 } 513 514common_sampler_sample (drafts [s ].smpl ,ctx_dft ,drafts [s ].i_batch_dft , true); 515 516const auto * cur_p = common_sampler_get_candidates (drafts [s ].smpl , true); 517 518for (int k = 0 ;k < std::min (n_seq_dft + 3 , (int )cur_p -> size );++ k ) { 519LOG_DBG (" - draft candidate %3d for seq %3d, pos %3d: %6d (%8.3f) '%s'\n" , 520k ,s ,i ,cur_p -> data [k ].id ,cur_p -> data [k ].p ,common_token_to_piece (ctx_dft ,cur_p -> data [k ].id ).c_str ()); 521 } 522 523 std::vector < int > sa (1 ,s ); 524 525// attempt to split the branch if the probability is high enough 526for (int f = 1 ;f < 8 ;++ f ) { 527if (n_seq_cur < n_seq_dft && cur_p -> data [f ].p > p_draft_split ) { 528LOG_DBG ("splitting seq %3d into %3d\n" ,s ,n_seq_cur ); 529 530llama_memory_seq_rm (mem_dft ,n_seq_cur ,-1 ,-1 ); 531llama_memory_seq_cp (mem_dft ,s ,n_seq_cur ,-1 ,-1 ); 532 533// all previous tokens from this branch are now also part of the new branch 534for (int t = 0 ;t < batch_tgt .n_tokens ;++ t ) { 535for (int p = 0 ;p < batch_tgt .n_seq_id [t ];++ p ) { 536if (batch_tgt .seq_id [t ][p ]== s ) { 537batch_tgt .seq_id [t ][batch_tgt .n_seq_id [t ]]= n_seq_cur ; 538batch_tgt .n_seq_id [t ]++ ; 539break ; 540 } 541 } 542 } 543 544// copy the draft state 545drafts [n_seq_cur ].active = true; 546drafts [n_seq_cur ].drafting = true; 547drafts [n_seq_cur ].skip = true; 548 549drafts [n_seq_cur ].tokens = drafts [s ].tokens ; 550drafts [n_seq_cur ].dists = drafts [s ].dists ; 551drafts [n_seq_cur ].i_batch_dft = drafts [s ].i_batch_dft ; 552drafts [n_seq_cur ].i_batch_tgt = drafts [s ].i_batch_tgt ; 553 554if (drafts [n_seq_cur ].smpl ) { 555common_sampler_free (drafts [n_seq_cur ].smpl ); 556 } 557drafts [n_seq_cur ].smpl = common_sampler_clone (drafts [s ].smpl ); 558 559sa .push_back (n_seq_cur ); 560 561n_seq_cur ++ ; 562 }else { 563break ; 564 } 565 } 566 567// add drafted token for each sequence 568for (int is = 0 ;is < (int )sa .size ();++ is ) { 569const llama_token id = cur_p -> data [is ].id ; 570 571const int s = sa [is ]; 572 573common_sampler_accept (drafts [s ].smpl ,id , true); 574 575drafts [s ].tokens .push_back (id ); 576// save cur_p.data into drafts[s].dists 577drafts [s ].dists .push_back ({cur_p -> data ,cur_p -> data + cur_p -> size }); 578 579// add unique drafted tokens to the target batch 580drafts [s ].i_batch_tgt .push_back (batch_tgt .n_tokens ); 581 582common_batch_add (batch_tgt ,id ,n_past_tgt + i + 1 , {s }, true); 583 584// add the token to the batch for batched decoding with the draft model 585drafts [s ].i_batch_dft = batch_dft .n_tokens ; 586 587common_batch_add (batch_dft ,id ,n_past_cur , {s }, true); 588 589if (batch_tgt .n_tokens > n_draft ) { 590drafts [s ].drafting = false; 591 } 592 } 593 } 594 595// no sequence is drafting anymore 596if (batch_dft .n_tokens == 0 ) { 597break ; 598 } 599 600// evaluate the drafted tokens on the draft model 601llama_decode (ctx_dft ,batch_dft ); 602++ n_past_cur ; 603++ n_drafted ; 604 605if (batch_tgt .n_tokens > n_draft ) { 606break ; 607 } 608 } 609 610// evaluate the target model on the drafted tokens 611 { 612llama_memory_seq_keep (mem_tgt ,0 ); 613for (int s = 1 ;s < n_seq_dft ;++ s ) { 614llama_memory_seq_cp (mem_tgt ,0 ,s ,-1 ,-1 ); 615 } 616 617// LOG_DBG("target batch: %s\n", LOG_BATCH_TOSTR_PRETTY(ctx_tgt, batch_tgt).c_str()); 618llama_decode (ctx_tgt ,batch_tgt ); 619++ n_past_tgt ; 620 } 621 622// the first token is always proposed by the target model before the speculation loop so we erase it here 623for (int s = 0 ;s < n_seq_dft ;++ s ) { 624if (!drafts [s ].active ) { 625continue ; 626 } 627 628drafts [s ].tokens .erase (drafts [s ].tokens .begin ()); 629drafts [s ].dists .erase (drafts [s ].dists .begin ()); 630 } 631 } 632 633auto t_dec_end = ggml_time_us (); 634 635LOG ("\n\n" ); 636 637LOG_INF ("encoded %4d tokens in %8.3f seconds, speed: %8.3f t/s\n" ,n_input , (t_enc_end - t_enc_start ) /1e6f ,inp .size () / ((t_enc_end - t_enc_start ) /1e6f )); 638LOG_INF ("decoded %4d tokens in %8.3f seconds, speed: %8.3f t/s\n" ,n_predict , (t_dec_end - t_dec_start ) /1e6f ,n_predict / ((t_dec_end - t_dec_start ) /1e6f )); 639 640LOG_INF ("\n" ); 641LOG_INF ("n_draft = %d\n" ,n_draft ); 642LOG_INF ("n_predict = %d\n" ,n_predict ); 643LOG_INF ("n_drafted = %d\n" ,n_drafted ); 644LOG_INF ("n_accept = %d\n" ,n_accept ); 645LOG_INF ("accept = %.3f%%\n" ,100.0f * n_accept /n_drafted ); 646 647LOG_INF ("\n" ); 648LOG_INF ("draft:\n\n" ); 649// TODO: print sampling/grammar timings for all drafts 650llama_perf_context_print (ctx_dft ); 651 652LOG_INF ("\n" ); 653LOG_INF ("target:\n\n" ); 654common_perf_print (ctx_tgt ,smpl ); 655 656common_sampler_free (smpl ); 657for (int s = 0 ;s < n_seq_dft ;++ s ) { 658common_sampler_free (drafts [s ].smpl ); 659 } 660 661llama_batch_free (batch_dft ); 662 663llama_backend_free (); 664 665LOG ("\n\n" ); 666 667return 0 ; 668}