char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
1dfe94e04
char/aliceai-t5-moe
1#include "speculative.h" 2 3#include "common.h" 4#include "ggml.h" 5#include "ggml-cpp.h" 6#include "llama.h" 7#include "log.h" 8#include "ngram-cache.h" 9#include "ngram-map.h" 10#include "ngram-mod.h" 11#include "sampling.h" 12 13#include "../src/llama-ext.h" // staging API: llama_set_embeddings_nextn / llama_get_embeddings_nextn_ith (used by MTP) 14 15#include <algorithm> 16#include <cassert> 17#include <cmath> 18#include <cstring> 19#include <iomanip> 20#include <map> 21#include <cinttypes> 22 23#define SPC_DBG (fmt , ...) LOG_DBG("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__) 24#define SPC_TRC (fmt , ...) LOG_TRC("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__) 25#define SPC_INF (fmt , ...) LOG_INF("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__) 26#define SPC_WRN (fmt , ...) LOG_WRN("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__) 27#define SPC_ERR (fmt , ...) LOG_ERR("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__) 28#define SPC_CNT (fmt , ...) LOG_CNT("" fmt, __VA_ARGS__) 29 30#define SPEC_VOCAB_MAX_SIZE_DIFFERENCE 128 31#define SPEC_VOCAB_CHECK_START_TOKEN_ID 5 32 33const std::map < std::string ,common_speculative_type > common_speculative_type_from_name_map = { 34 {"none" ,COMMON_SPECULATIVE_TYPE_NONE }, 35 {"draft-simple" ,COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE }, 36 {"draft-eagle3" ,COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 }, 37 {"draft-mtp" ,COMMON_SPECULATIVE_TYPE_DRAFT_MTP }, 38 {"draft-dflash" ,COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH }, 39 {"draft-dspark" ,COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK }, 40 {"ngram-simple" ,COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE }, 41 {"ngram-map-k" ,COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K }, 42 {"ngram-map-k4v" ,COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V }, 43 {"ngram-mod" ,COMMON_SPECULATIVE_TYPE_NGRAM_MOD }, 44 {"ngram-cache" ,COMMON_SPECULATIVE_TYPE_NGRAM_CACHE } 45}; 46 47static std::string common_speculative_get_devices_str (const std::vector < ggml_backend_dev_t > & devices ) { 48 std::string result ; 49for (size_t i = 0 ;i < devices .size ();i ++ ) { 50if (devices [i ]== nullptr ) { 51continue ; 52 } 53if (!result .empty ())result += ", " ; 54result += ggml_backend_dev_name (devices [i ]); 55 } 56return result .empty () ?"default" :result ; 57} 58 59struct common_speculative_config { 60common_speculative_type type ; 61common_params_speculative params ; 62 63common_speculative_config (common_speculative_type t , 64const common_params_speculative & p = common_params_speculative {}) :type (t ),params (p ) {} 65}; 66 67static bool common_speculative_are_compatible ( 68const llama_model * model_tgt , 69const llama_model * model_dft ) { 70const llama_vocab * vocab_tgt = llama_model_get_vocab (model_tgt ); 71const llama_vocab * vocab_dft = llama_model_get_vocab (model_dft ); 72 73const auto vocab_type_tgt = llama_vocab_type (vocab_tgt ); 74SPC_DBG ("vocab_type tgt: %d\n" ,vocab_type_tgt ); 75 76const auto vocab_type_dft = llama_vocab_type (vocab_dft ); 77SPC_DBG ("vocab_type dft: %d\n" ,vocab_type_dft ); 78 79if (vocab_type_tgt != vocab_type_dft ) { 80SPC_WRN ("draft model vocab type must match target model to use speculation but " 81"vocab_type_dft = %d while vocab_type_tgt = %d\n" ,vocab_type_dft ,vocab_type_tgt ); 82return false; 83 } 84 85if (llama_vocab_get_add_bos (vocab_tgt )!= llama_vocab_get_add_bos (vocab_dft )|| 86 (llama_vocab_get_add_bos (vocab_tgt )&& llama_vocab_bos (vocab_tgt )!= llama_vocab_bos (vocab_dft ))) { 87SPC_WRN ("draft model bos tokens must match target model to use speculation. add: %d - %d, id: %d - %d)\n" , 88llama_vocab_get_add_bos (vocab_tgt ),llama_vocab_get_add_bos (vocab_dft ), 89llama_vocab_bos (vocab_tgt ),llama_vocab_bos (vocab_dft )); 90return false; 91 } 92 93if (llama_vocab_get_add_eos (vocab_tgt )!= llama_vocab_get_add_eos (vocab_dft )|| 94 (llama_vocab_get_add_eos (vocab_tgt )&& llama_vocab_eos (vocab_tgt )!= llama_vocab_eos (vocab_dft ))) { 95SPC_WRN ("draft model eos tokens must match target model to use speculation. add: %d - %d, id: %d - %d)\n" , 96llama_vocab_get_add_eos (vocab_tgt ),llama_vocab_get_add_eos (vocab_dft ), 97llama_vocab_eos (vocab_tgt ),llama_vocab_eos (vocab_dft )); 98return false; 99 } 100 101 { 102const int n_vocab_tgt = llama_vocab_n_tokens (vocab_tgt ); 103const int n_vocab_dft = llama_vocab_n_tokens (vocab_dft ); 104const int vocab_diff = n_vocab_tgt > n_vocab_dft 105 ?n_vocab_tgt - n_vocab_dft 106 :n_vocab_dft - n_vocab_tgt ; 107 108if (vocab_diff > SPEC_VOCAB_MAX_SIZE_DIFFERENCE ) { 109SPC_DBG ("draft model vocab must closely match target model to use speculation but " 110"target vocab size %d does not match draft vocab size %d - difference %d, max allowed %d\n" , 111n_vocab_tgt ,llama_vocab_n_tokens (vocab_dft ),vocab_diff ,SPEC_VOCAB_MAX_SIZE_DIFFERENCE ); 112return false; 113 } 114 115for (int i = SPEC_VOCAB_CHECK_START_TOKEN_ID ;i < std::min (n_vocab_tgt ,n_vocab_dft );++ i ) { 116const char * token_text_tgt = llama_vocab_get_text (vocab_tgt ,i ); 117const char * token_text_dft = llama_vocab_get_text (vocab_dft ,i ); 118 119if (std::strcmp (token_text_tgt ,token_text_dft )!= 0 ) { 120SPC_DBG ("draft model vocab must match target model to use speculation but " 121"token %d content differs - target '%s', draft '%s'\n" ,i , 122common_token_to_piece (vocab_tgt ,i ).c_str (), 123common_token_to_piece (vocab_dft ,i ).c_str ()); 124return false; 125 } 126 } 127 } 128 129return true; 130} 131 132using common_speculative_draft_params_vec = std::vector < common_speculative_draft_params > ; 133 134// state of an implementation of speculative decoding 135// 136// each implementation has a unique type and a state that is implementation-specific 137// in a subclass of common_speculative_impl 138struct common_speculative_impl { 139const common_speculative_type type ; 140 141uint32_t n_seq ; 142int32_t n_max ;// maximum draft length after implementation-specific limits 143 144size_t n_call_begin = 0 ;// number of times this implementation was called for refresh. 145size_t n_call_draft = 0 ;// number of times this implementation was called for generation. 146size_t n_call_accept = 0 ;// number of times this implementation was called for accumulation. 147 148size_t n_gen_drafts = 0 ;// number of times a draft or part was generated by this implementation. 149size_t n_acc_drafts = 0 ;// number of times a draft or part was accepted by the target model. 150size_t n_gen_tokens = 0 ;// number of tokens generated by this implementation. 151size_t n_acc_tokens = 0 ;// number of tokens accepted by the target model. 152 153 std::vector < size_t > n_acc_tokens_per_pos ;// number of tokens accepted per draft position. 154 155// TODO: track performance of most recent calls 156const bool gen_perf = true;// whether to generate performance stats. 157 158int64_t t_begin_us = 0 ;// total time spent in refresh of this implementation in microseconds. 159int64_t t_draft_us = 0 ;// total time spent in generating drafts in this implementation in microseconds. 160int64_t t_accept_us = 0 ;// total time spent in accumulation of this implementation in microseconds. 161 162common_speculative_impl (common_speculative_type type ,uint32_t n_seq ,int32_t n_max ) :type (type ),n_seq (n_seq ),n_max (n_max ) {} 163 164virtual ~common_speculative_impl ()= default ; 165 166virtual void begin (llama_seq_id seq_id ,const llama_tokens & prompt )= 0 ; 167 168virtual bool process (const llama_batch & batch )= 0 ; 169 170virtual void draft (common_speculative_draft_params_vec & dparams )= 0 ; 171 172virtual void accept (llama_seq_id seq_id ,uint16_t n_accepted ,bool is_other )= 0 ; 173 174// (optional) serialize/restore per-seq internal state (e.g. eagle3's deferred boundary). 175virtual bool get_state (llama_seq_id /*seq_id*/ , std::vector < uint8_t > & /*data*/ )const {return false; } 176virtual void set_state (llama_seq_id /*seq_id*/ ,const std::vector < uint8_t > & /*data*/ ) {} 177}; 178 179struct common_speculative_impl_draft_simple :public common_speculative_impl { 180common_params_speculative_draft params ; 181 182llama_batch batch ; 183 184 std::vector < common_sampler_ptr > smpls ; 185 186common_speculative_impl_draft_simple (const common_params_speculative & params ,uint32_t n_seq ) 187 :common_speculative_impl (COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE ,n_seq ,params .draft .n_max ) 188 ,params (params .draft ) 189 { 190auto * ctx_dft = this -> params .ctx_dft ; 191auto * ctx_tgt = this -> params .ctx_tgt ; 192 193if (!ctx_dft ) { 194throw std::runtime_error ("draft-simple requires a draft context" ); 195 } 196 197SPC_TRC ("%s" ,"adding speculative implementation 'draft-simple'\n" ); 198SPC_TRC ("- n_max=%d, n_min=%d, p_min=%f\n" ,this -> params .n_max ,this -> params .n_min ,this -> params .p_min ); 199SPC_TRC ("- gpu_layers=%d, cache_k=%s, cache_v=%s, ctx_tgt=%s, ctx_dft=%s, devices=[%s]\n" , 200this -> params .n_gpu_layers , 201ggml_type_name (this -> params .cache_type_k ), 202ggml_type_name (this -> params .cache_type_v ), 203ctx_tgt ?"yes" :"no" , 204ctx_dft ?"yes" :"no" , 205common_speculative_get_devices_str (this -> params .devices ).c_str ()); 206 207batch = llama_batch_init (llama_n_batch (ctx_dft ),0 ,1 ); 208 209// TODO: optimize or pass from outside? 210// { 211// common_params_sampling params; 212// params.no_perf = false; 213// 214// params.top_k = 40; 215// params.top_p = 0.9; 216// 217// params.samplers = { 218// COMMON_SAMPLER_TYPE_TOP_K, 219// COMMON_SAMPLER_TYPE_TOP_P, 220// COMMON_SAMPLER_TYPE_INFILL, 221// }; 222// 223// result->smpl = common_sampler_init(llama_get_model(ctx_dft), params); 224// } 225 226smpls .resize (n_seq ); 227for (auto & smpl :smpls ) { 228common_params_sampling params ; 229params .no_perf = false; 230params .top_k = 10 ; 231params .samplers = { 232COMMON_SAMPLER_TYPE_TOP_K , 233 }; 234 235smpl .reset (common_sampler_init (llama_get_model (ctx_dft ),params )); 236 } 237 238const bool vocab_cmpt = common_speculative_are_compatible (llama_get_model (ctx_tgt ),llama_get_model (ctx_dft )); 239SPC_DBG ("vocab_cmpt = %d\n" ,vocab_cmpt ); 240 241if (!vocab_cmpt ) { 242SPC_ERR ("%s" ,"the target and draft vocabs are not compatible\n" ); 243 244throw std::runtime_error ("draft model vocab type must match target model to use speculation" ); 245 } 246 247if (n_seq != llama_n_seq_max (ctx_dft )) { 248SPC_ERR ("n_seq mismatch: %d != %d\n" ,n_seq ,llama_n_seq_max (ctx_dft )); 249 250throw std::runtime_error ("the draft model number of sequences is incompatible with the speculative n_seq" ); 251 } 252 } 253 254 ~common_speculative_impl_draft_simple ()override { 255llama_batch_free (batch ); 256 } 257 258void begin (llama_seq_id /*seq_id*/ ,const llama_tokens & /*prompt*/ )override { 259// noop 260 } 261 262bool process (const llama_batch & batch )override { 263auto * ctx_dft = params .ctx_dft ; 264 265llama_batch batch_dft = batch ; 266batch_dft .logits = nullptr ; 267 268const int ret = llama_decode (ctx_dft ,batch_dft ); 269 270if (ret != 0 ) { 271SPC_ERR ("failed to decode draft batch, ret = %d\n" ,ret ); 272 273return false; 274 } 275 276return true; 277 } 278 279void draft (common_speculative_draft_params_vec & dparams )override { 280auto & ctx_dft = params .ctx_dft ; 281 282common_batch_clear (batch ); 283 284// keep track of which sequences are still drafting 285int n_drafting = 0 ; 286 std::vector < bool > drafting (n_seq ); 287 288for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 289auto & dp = dparams [seq_id ]; 290 291if (!dp .drafting ) { 292continue ; 293 } 294 295n_drafting ++ ; 296drafting [seq_id ]= true; 297common_sampler_reset (smpls [seq_id ].get ()); 298 299common_batch_add (batch ,dp .id_last ,dp .pos0 , {seq_id }, true); 300 } 301 302int ret = llama_decode (ctx_dft ,batch ); 303if (ret != 0 ) { 304SPC_ERR ("llama_decode returned %d\n" ,ret ); 305return ; 306 } 307 308int i = 0 ; 309 310while (n_drafting > 0 ) { 311int i_batch = 0 ; 312 313common_batch_clear (batch ); 314 315for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 316if (!drafting [seq_id ]) { 317continue ; 318 } 319 320auto * smpl = smpls [seq_id ].get (); 321 322common_sampler_sample (smpl ,ctx_dft ,i_batch , true); 323++ i_batch ; 324 325const auto * cur_p = common_sampler_get_candidates (smpl , true); 326 327for (int k = 0 ;k < std::min (3 , (int )cur_p -> size );++ k ) { 328SPC_DBG (" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n" , 329seq_id ,k ,i ,cur_p -> data [k ].id ,cur_p -> data [k ].p , 330common_token_to_piece (ctx_dft ,cur_p -> data [k ].id ).c_str ()); 331 } 332 333// add drafted token for each sequence 334const llama_token id = cur_p -> data [0 ].id ; 335 336// only collect very high-confidence draft tokens 337if (cur_p -> data [0 ].p < params .p_min ) { 338drafting [seq_id ]= false; 339n_drafting -- ; 340 341continue ; 342 } 343 344common_sampler_accept (smpl ,id , true); 345 346auto & dp = dparams .at (seq_id ); 347auto & result = * dp .result ; 348 349result .push_back (id ); 350 351if ((params .n_max <= (int )result .size ())|| 352 (dp .n_max > 0 && dp .n_max <= (int )result .size ())) { 353drafting [seq_id ]= false; 354n_drafting -- ; 355continue ; 356 } 357 358common_batch_add (batch ,id ,dp .pos0 + i + 1 , {seq_id }, true); 359 } 360 361if (batch .n_tokens == 0 ) { 362break ; 363 } 364 365// evaluate the drafted tokens on the draft model 366ret = llama_decode (ctx_dft ,batch ); 367if (ret != 0 ) { 368SPC_ERR ("llama_decode[%d] returned %d\n" ,i ,ret ); 369break ; 370 } 371 372++ i ; 373 } 374 375for (auto & dp :dparams ) { 376if (!dp .drafting ) { 377continue ; 378 } 379 380if (dp .result -> size ()< (size_t )params .n_min ) { 381dp .result -> clear (); 382 } 383 } 384 } 385 386void accept (llama_seq_id /*seq_id*/ ,uint16_t /*n_accepted*/ ,bool /*is_other*/ )override { 387// noop 388 } 389}; 390 391 392// EAGLE3 speculative decoding state 393// 394// Input of draft decoder: (This is different compared to MTP) 395// At "pos P", the decoder takes input pair (t_{P+1}, g_P), with RoPE at P. 396// - t_{P+1} = token at sequence pos P+1 (the *next* token after P) 397// - g_P = encoder output = projection of target's extracted hidden states at P 398// 399// Deferred boundary (MTP doesn't have this issue): 400// Within a single process() call with n_tokens, we can only write decoder KV for 401// training pos 0..n_tokens-2. The last training pos (n_tokens-1) needs t_{n_tokens} 402// which lies *outside* this batch — it is the token target will sample next or the first token from next ubatch. 403// So the last training pos of each process() call is *deferred* to whichever next call has 404// the missing token in hand: 405// - multi-ubatch prefill: the next process()'s first token completes the pair 406// (handled by the per-seq "cross-ubatch bridge") 407// - single-ubatch prefill / after verify: draft()'s seed step uses "dp.id_last" 408// (target's freshest sample) to complete the pair 409// 410// Per-seq carry-over state: 411// pending_g_last [n_embd_dec] ┐ the deferred boundary's (g, pos). Set by 412// pending_pos_last llama_pos ┘ process() at end of ubatch (= last row); 413// rebased by accept() to first-non-accepted pos. 414// verify_g [N × n_embd_dec] snapshot of process()'s encoder output; 415// verify_pos_first llama_pos consumed by accept() to recover the right 416// verify_g_rows int32_t pending_g_last row for any n_accepted value. 417// 418// Performance is overall good but there is waste in verify cycle: 419// process() runs encoder + decoder on the *full* verify batch including rows for 420// rejected drafts. The KV at those positions is then dropped. 421// 422// TODO: Not sure if we need optimization for this waste? 423// If so we may need hybrid stash: 424// in verify mode, have process() only stash features and let draft() seed run 425// encoder+decoder on n_accepted+1 rows). 426struct common_speculative_impl_draft_eagle3 :public common_speculative_impl { 427common_params_speculative_draft params ; 428llama_batch batch ; 429 430 std::vector < common_sampler_ptr > smpls ; 431 432// backend sampler chain per seq, attached to ctx_dft 433 std::vector < llama_sampler *> backend_chains ; 434 435int32_t n_embd_dec = 0 ;// draft hidden size 436int32_t n_embd_enc = 0 ;// target_layer_ids_n * target_hidden_size 437int32_t n_embd_tgt = 0 ;// target model hidden size 438int32_t n_layer_tgt = 0 ;// target model layer count 439 440const int32_t * target_layer_ids = nullptr ;// model_dft's extract layer indices 441uint32_t target_layer_ids_n = 0 ; 442 443// [per-seq] deferred boundary state 444 std::vector < std::vector < float >> pending_g_last ; 445 std::vector < llama_pos > pending_pos_last ; 446 447// [per-seq] snapshot of the most recent process()'s encoder output 448 std::vector < std::vector < float >> verify_g ;// [n_seq][n_rows * n_embd_dec] 449 std::vector < llama_pos > verify_pos_first ;// [n_seq] — pos of verify_g[seq][0] 450 std::vector < int32_t > verify_g_rows ;// [n_seq] — number of rows 451 452// scratch buffer for concatenated target features [n_tokens, n_embd_enc] 453 std::vector < float > features_buf ; 454 std::vector < float > g_embd_buf ; 455 456common_speculative_impl_draft_eagle3 (const common_params_speculative & params ,uint32_t n_seq ) 457 :common_speculative_impl (COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 ,n_seq ,params .draft .n_max ) 458 ,params (params .draft ) 459 { 460SPC_TRC ("%s" ,"adding speculative implementation 'draft-eagle3'\n" ); 461SPC_TRC ("- n_max=%d, n_min=%d, p_min=%f, backend_sampling=%d\n" ,params .draft .n_max ,params .draft .n_min ,params .draft .p_min , (int )params .draft .backend_sampling ); 462 463auto * ctx_tgt = this -> params .ctx_tgt ; 464auto * ctx_dft = this -> params .ctx_dft ; 465GGML_ASSERT (ctx_tgt && ctx_dft && "EAGLE3 requires ctx_tgt and ctx_dft to be set" ); 466 467const llama_model * model_dft = llama_get_model (ctx_dft ); 468const llama_model * model_tgt = llama_get_model (ctx_tgt ); 469 470target_layer_ids = llama_model_target_layer_ids (model_dft ); 471target_layer_ids_n = llama_model_target_layer_ids_n (model_dft ); 472if (target_layer_ids_n != 3 ) { 473throw std::runtime_error ("draft model is not eagle3 (expected 3 extract layers, got " + 474 std::to_string (target_layer_ids_n )+ ")" ); 475 } 476 477n_embd_tgt = llama_model_n_embd (model_tgt ); 478n_embd_dec = llama_model_n_embd (model_dft ); 479n_embd_enc = (int32_t )target_layer_ids_n * n_embd_tgt ; 480n_layer_tgt = llama_model_n_layer (model_tgt ); 481 482const int32_t n_b = (int32_t )llama_n_batch (ctx_dft ); 483batch = llama_batch_init (/*n_tokens=*/ n_b ,/*embd=*/ n_embd_dec ,/*n_seq_max=*/ 1 ); 484// llama_batch_init allocates only one of token/embd; eagle3 decoder needs both. 485// TODO: fix, how to call without malloc 486batch .token = (llama_token * )malloc (sizeof (llama_token )* n_b ); 487 488smpls .resize (n_seq ); 489for (auto & s :smpls ) { 490common_params_sampling sparams ; 491sparams .no_perf = false; 492sparams .top_k = 10 ; 493sparams .samplers = {COMMON_SAMPLER_TYPE_TOP_K }; 494s .reset (common_sampler_init (llama_get_model (ctx_dft ),sparams )); 495 } 496 497// offload draft sampling to the backend 498backend_chains .assign (n_seq ,nullptr ); 499if (this -> params .backend_sampling ) { 500for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 501llama_sampler * chain = llama_sampler_chain_init (llama_sampler_chain_default_params ()); 502llama_sampler_chain_add (chain ,llama_sampler_init_top_k (10 )); 503 504if (!llama_set_sampler (ctx_dft ,seq_id ,chain )) { 505SPC_WRN ("backend offload failed for seq_id=%d; using CPU sampler\n" , (int )seq_id ); 506llama_sampler_free (chain ); 507chain = nullptr ; 508 } 509backend_chains [seq_id ]= chain ; 510 } 511 } 512 513// turn on extraction of the target layers' hidden states 514for (uint32_t k = 0 ;k < target_layer_ids_n ;++ k ) { 515if (target_layer_ids [k ]< n_layer_tgt ) { 516llama_set_embeddings_layer_inp (ctx_tgt , (uint32_t )target_layer_ids [k ], true); 517 }else if (target_layer_ids [k ]== n_layer_tgt ) { 518llama_set_embeddings_nextn (ctx_tgt , true,/*masked*/ false); 519 }else { 520GGML_ABORT ("EAGLE3: target layer id %d exceeds target n_layer %d" ,target_layer_ids [k ],n_layer_tgt ); 521 } 522 } 523 524// turn on extraction of the draft model's pre-norm hidden state 525// (used both for the encoder output g_embd and the decoder pre-norm output). 526llama_set_embeddings_nextn (ctx_dft , true,/*masked*/ true); 527 528pending_g_last .assign (n_seq , std::vector < float > (n_embd_dec ,0.0f )); 529pending_pos_last .assign (n_seq ,-1 ); 530 531verify_g .assign (n_seq , std::vector < float > ()); 532verify_pos_first .assign (n_seq ,-1 ); 533verify_g_rows .assign (n_seq ,0 ); 534 } 535 536 ~common_speculative_impl_draft_eagle3 ()override { 537auto * ctx_dft = this -> params .ctx_dft ; 538for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )backend_chains .size ();++ seq_id ) { 539if (backend_chains [seq_id ]== nullptr ) { 540continue ; 541 } 542if (ctx_dft ) { 543llama_set_sampler (ctx_dft ,seq_id ,nullptr ); 544 } 545llama_sampler_free (backend_chains [seq_id ]); 546 } 547backend_chains .clear (); 548 549if (batch .token != nullptr ) { 550free (batch .token ); 551batch .token = nullptr ; 552 } 553llama_batch_free (batch ); 554 } 555 556void begin (llama_seq_id seq_id ,const llama_tokens & prompt )override { 557const int32_t N = (int32_t )prompt .size (); 558if (N <=0 ) { 559return ; 560 } 561// expected state after prefill: ctx_dft has pos 0..N-2 (last position is deferred to 562// draft()'s seed step). Warn only if more than one position is missing. 563auto * ctx_dft = this -> params .ctx_dft ; 564const llama_pos pos_max = llama_memory_seq_pos_max (llama_get_memory (ctx_dft ),seq_id ); 565if (pos_max < N - 2 ) { 566SPC_WRN ("ctx_dft pos_max=%d < N-2=%d — process() did not run on every prefill ubatch. " 567"Drafts may degrade.\n" , 568 (int )pos_max ,N - 2 ); 569 } 570 } 571 572bool process (const llama_batch & batch_in )override { 573if (batch_in .n_tokens <=0 ) { 574return true; 575 } 576 577if (batch_in .token == nullptr || batch_in .embd != nullptr ) { 578return true; 579 } 580 581const int32_t n_tokens = batch_in .n_tokens ; 582 583// i_batch_beg[seq] / i_batch_end[seq]: inclusive batch indices of this seq's 584// first/last token in batch_in. Assumes per-seq tokens are contiguous within 585// the ubatch (server's default ordering). 586 std::vector < int32_t > i_batch_beg (n_seq ,-1 ); 587 std::vector < int32_t > i_batch_end (n_seq ,-1 ); 588for (int k = 0 ;k < n_tokens ;++ k ) { 589GGML_ASSERT (batch_in .n_seq_id [k ]== 1 ); 590const llama_seq_id seq_id = batch_in .seq_id [k ][0 ]; 591if (seq_id < 0 || seq_id >= (llama_seq_id )n_seq ) { 592continue ; 593 } 594i_batch_end [seq_id ]= k ; 595if (i_batch_beg [seq_id ]< 0 ) { 596i_batch_beg [seq_id ]= k ; 597 } 598 } 599 600auto * ctx_tgt = this -> params .ctx_tgt ; 601auto * ctx_dft = this -> params .ctx_dft ; 602 603// Interleave each extract_layer's hidden state into a contiguous buffer of 604// shape [n_tokens, target_layer_ids_n * n_embd_tgt]. Then run EAGLE3 encoder 605// to get one g_embd row per token. 606features_buf .resize ((size_t )n_tokens * n_embd_enc ,0.0f ); 607 608for (uint32_t k = 0 ;k < target_layer_ids_n ;++ k ) { 609const float * layer = target_layer_ids [k ]< n_layer_tgt 610 ?llama_get_embeddings_layer_inp (ctx_tgt , (uint32_t )target_layer_ids [k ]) 611 :llama_get_embeddings_nextn (ctx_tgt ); 612if (!layer ) { 613GGML_ABORT ("EAGLE3: target layer %d input not extracted." ,target_layer_ids [k ]); 614 } 615for (int32_t i = 0 ;i < n_tokens ;++ i ) { 616float * dst = features_buf .data ()+ (size_t )i * n_embd_enc + k * (size_t )n_embd_tgt ; 617const float * src = layer + (size_t )i * n_embd_tgt ; 618 std::memcpy (dst ,src , (size_t )n_embd_tgt * sizeof (float )); 619 } 620 } 621 622g_embd_buf .resize ((size_t )n_tokens * n_embd_dec ); 623 624// llama_encode() requires the full encoder batch to fit in n_ubatch. 625// Allow batch > ubatch: eagle3's per-token encoder can be chunked safely. 626const int32_t n_ubatch_dft = (int32_t )llama_n_ubatch (ctx_dft ); 627for (int32_t i = 0 ;i < n_tokens ;i += n_ubatch_dft ) { 628const int32_t n_chunk = std::min (n_ubatch_dft ,n_tokens - i ); 629 630llama_batch enc_batch = { 631/*.n_tokens =*/ n_chunk , 632/*.token =*/ nullptr , 633/*.embd =*/ features_buf .data ()+ (size_t )i * n_embd_enc , 634/*.pos =*/ nullptr , 635/*.n_seq_id =*/ nullptr , 636/*.seq_id =*/ nullptr , 637/*.logits =*/ nullptr , 638 }; 639const int32_t rc = llama_encode (ctx_dft ,enc_batch ); 640if (rc != 0 ) { 641SPC_ERR ("llama_encode(ctx_dft) failed rc=%d (n_tokens=%d, offset=%d)\n" , 642rc , (int )n_chunk , (int )i ); 643return false; 644 } 645 646// g_embd has shape [n_chunk, n_embd_dec] in ctx_dft's pre-norm embeddings buffer. 647const float * g_embd_chunk = llama_get_embeddings_nextn (ctx_dft ); 648GGML_ASSERT (g_embd_chunk && "EAGLE3 encoder produced no output." ); 649 std::memcpy (g_embd_buf .data ()+ (size_t )i * n_embd_dec , 650g_embd_chunk , 651 (size_t )n_chunk * n_embd_dec * sizeof (float )); 652 } 653 654const float * g_embd = g_embd_buf .data (); 655 656const size_t row_bytes = (size_t )n_embd_dec * sizeof (float ); 657 658// EAGLE3 decoder input convention: at memory pos P the input pair is 659// (token[P+1], g_embd[P]). This shifts the token index "left by one" relative to g_embd. 660// 661// Per seq, in order: 662// (a) cross-ubatch bridge — when applicable, write the previously-deferred 663// pos using this ubatch's first token + pending_g_last. 664// (b) main write loop — for k in [beg, end-1], write (token[k+1], g_embd[k]) 665// at pos[k]. The last training pos (k=end) is left unwritten = new 666// deferred boundary, completed by the next process() or draft() call. 667// (c) refresh deferred state — stash this ubatch's full g_embd into verify_g, 668// update pending_g_last / pending_pos_last to the last row. 669common_batch_clear (batch ); 670 671for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 672const int32_t beg = i_batch_beg [seq_id ]; 673const int32_t end = i_batch_end [seq_id ]; 674if (beg < 0 || end < 0 ) { 675continue ; 676 } 677 678// cross-ubatch bridge — complete the prior ubatch's deferred boundary. 679// Fires iff all three preconditions hold: 680// 1) pending_pos_last >= 0 681// 2) pending_pos_last + 1 == pos[beg] 682// 3) pending_pos_last > dft_pos_max // TODO: is this check needed? 683const llama_pos pending_pos = pending_pos_last [seq_id ]; 684if (pending_pos >=0 && pending_pos + 1 == batch_in .pos [beg ]) { 685const llama_pos dft_pos_max = llama_memory_seq_pos_max (llama_get_memory (ctx_dft ),seq_id ); 686if (pending_pos > dft_pos_max ) { 687common_batch_add (batch ,batch_in .token [beg ],pending_pos , {seq_id },/*logits=*/ false); 688 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd_dec , 689pending_g_last [seq_id ].data (),row_bytes ); 690 } 691 } 692 693for (int32_t k = beg ;k < end ;++ k ) { 694common_batch_add (batch ,batch_in .token [k + 1 ],batch_in .pos [k ], {seq_id },/*logits=*/ false); 695 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd_dec , 696g_embd + (size_t )k * n_embd_dec ,row_bytes ); 697 } 698 699// refresh deferred state 700const int32_t n_rows = end - beg + 1 ; 701verify_pos_first [seq_id ]= batch_in .pos [beg ]; 702pending_pos_last [seq_id ]= batch_in .pos [end ]; 703verify_g_rows [seq_id ]= n_rows ; 704verify_g [seq_id ].resize ((size_t )n_rows * n_embd_dec ,0.0f ); 705 std::memcpy (verify_g [seq_id ].data (),g_embd + (size_t )beg * n_embd_dec ,row_bytes * n_rows ); 706 std::memcpy (pending_g_last [seq_id ].data (),g_embd + (size_t )end * n_embd_dec ,row_bytes ); 707 } 708 709if (batch .n_tokens > 0 ) { 710const int32_t rc = llama_decode (ctx_dft ,batch ); 711if (rc != 0 ) { 712SPC_ERR ("llama_decode(ctx_dft) failed rc=%d (n_tokens=%d, ubatch_pos[0]=%d)\n" , 713rc , (int )batch .n_tokens , (int )batch_in .pos [0 ]); 714return false; 715 } 716 } 717 718return true; 719 } 720 721void draft (common_speculative_draft_params_vec & dparams )override { 722auto & ctx_dft = params .ctx_dft ; 723 724common_batch_clear (batch ); 725 726// keep track of which sequences are still drafting 727int n_drafting = 0 ; 728 std::vector < bool > drafting (n_seq ); 729 730const size_t row_bytes = (size_t )n_embd_dec * sizeof (float ); 731 732// Complete the deferred boundary pair (dp.id_last, pending_g_last) at memory 733// pos pending_pos_last. dp.id_last is target's freshest sample (= corrected 734// token after verify, or first generated token after prefill), matching the 735// EAGLE3 input convention (token[P+1], g_embd[P]) at pos P. 736for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 737auto & dp = dparams [seq_id ]; 738 739if (!dp .drafting ) { 740continue ; 741 } 742if (pending_pos_last [seq_id ]< 0 ) { 743continue ; 744 } 745 746n_drafting ++ ; 747drafting [seq_id ]= true; 748common_sampler_reset (smpls [seq_id ].get ()); 749 750llama_memory_seq_rm (llama_get_memory (ctx_dft ),seq_id ,pending_pos_last [seq_id ],-1 ); 751 752common_batch_add (batch ,dp .id_last ,pending_pos_last [seq_id ], {seq_id }, true); 753 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd_dec , 754pending_g_last [seq_id ].data (), 755row_bytes ); 756 } 757 758if (batch .n_tokens == 0 ) { 759return ; 760 } 761 762int ret = llama_decode (ctx_dft ,batch ); 763if (ret != 0 ) { 764SPC_ERR ("llama_decode returned %d\n" ,ret ); 765return ; 766 } 767 768int i = 0 ; 769 770while (n_drafting > 0 ) { 771int i_batch = 0 ; 772 773common_batch_clear (batch ); 774 775for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 776if (!drafting [seq_id ]) { 777continue ; 778 } 779 780auto * smpl = smpls [seq_id ].get (); 781 782common_sampler_sample (smpl ,ctx_dft ,i_batch , true); 783// pre-norm hidden state of this position becomes g_embd for the next step 784const float * prenorm = llama_get_embeddings_nextn_ith (ctx_dft ,i_batch ); 785++ i_batch ; 786 787const auto * cur_p = common_sampler_get_candidates (smpl , true); 788 789for (int k = 0 ;k < std::min (3 , (int )cur_p -> size );++ k ) { 790SPC_DBG (" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n" , 791seq_id ,k ,i ,cur_p -> data [k ].id ,cur_p -> data [k ].p , 792common_token_to_piece (ctx_dft ,cur_p -> data [k ].id ).c_str ()); 793 } 794 795const llama_token id = cur_p -> data [0 ].id ; 796 797// only collect very high-confidence draft tokens 798// (configurable via --spec-draft-p-min, set to 0.0 to disable early-stop) 799if (cur_p -> data [0 ].p < params .p_min ) { 800drafting [seq_id ]= false; 801n_drafting -- ; 802 803continue ; 804 } 805 806common_sampler_accept (smpl ,id , true); 807 808auto & dp = dparams .at (seq_id ); 809auto & result = * dp .result ; 810 811result .push_back (id ); 812 813if (params .n_max <= (int )result .size ()) { 814drafting [seq_id ]= false; 815n_drafting -- ; 816continue ; 817 } 818 819common_batch_add (batch ,id ,pending_pos_last [seq_id ]+ (i + 1 ), {seq_id }, true); 820 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd_dec ,prenorm ,row_bytes ); 821 } 822 823if (batch .n_tokens == 0 ) { 824break ; 825 } 826 827ret = llama_decode (ctx_dft ,batch ); 828if (ret != 0 ) { 829SPC_ERR ("llama_decode[%d] returned %d\n" ,i ,ret ); 830break ; 831 } 832 833++ i ; 834 } 835 836for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 837auto & dp = dparams [seq_id ]; 838if (!dp .drafting ) { 839continue ; 840 } 841 842if (dp .result -> size ()< (size_t )params .n_min ) { 843dp .result -> clear (); 844 } 845 } 846 } 847 848void accept (llama_seq_id seq_id ,uint16_t n_accepted ,bool /*is_other*/ )override { 849if (seq_id < 0 || seq_id >= (llama_seq_id )n_seq ) { 850return ; 851 } 852 853const int32_t n_rows = verify_g_rows [seq_id ]; 854if (n_rows <=0 ) { 855return ; 856 } 857 858const int32_t i_g = std::min < int32_t > (n_accepted ,n_rows - 1 ); 859pending_pos_last [seq_id ]= verify_pos_first [seq_id ]+ i_g ; 860 std::memcpy (pending_g_last [seq_id ].data (), 861verify_g [seq_id ].data ()+ (size_t )i_g * n_embd_dec , 862 (size_t )n_embd_dec * sizeof (float )); 863 } 864 865// we only need to stash the deferred boundary's g_embd row for recurrent/hybrid targets: 866// their single-position checkpoints drop it on restore 867bool need_boundary_stash ()const { 868const llama_model * model_tgt = llama_get_model (params .ctx_tgt ); 869return llama_model_is_recurrent (model_tgt )|| llama_model_is_hybrid (model_tgt ); 870 } 871 872bool get_state (llama_seq_id seq_id , std::vector < uint8_t > & data )const override { 873if (!need_boundary_stash ()) { 874return false; 875 } 876if (seq_id < 0 || seq_id >= (llama_seq_id )n_seq || pending_pos_last [seq_id ]< 0 ) { 877return false; 878 } 879 880const llama_pos pos = pending_pos_last [seq_id ]; 881const std::vector < float > & g = pending_g_last [seq_id ]; 882 883data .resize (sizeof (llama_pos )+ g .size ()* sizeof (float )); 884 std::memcpy (data .data (),& pos ,sizeof (llama_pos )); 885 std::memcpy (data .data ()+ sizeof (llama_pos ),g .data (),g .size ()* sizeof (float )); 886return true; 887 } 888 889void set_state (llama_seq_id seq_id ,const std::vector < uint8_t > & data )override { 890if (!need_boundary_stash ()) { 891return ; 892 } 893if (seq_id < 0 || seq_id >= (llama_seq_id )n_seq ) { 894return ; 895 } 896if (data .size ()!= sizeof (llama_pos )+ (size_t )n_embd_dec * sizeof (float )) { 897return ; 898 } 899 900llama_pos pos = -1 ; 901 std::memcpy (& pos ,data .data (),sizeof (llama_pos )); 902 903pending_pos_last [seq_id ]= pos ; 904pending_g_last [seq_id ].resize (n_embd_dec ); 905 std::memcpy (pending_g_last [seq_id ].data (),data .data ()+ sizeof (llama_pos ), (size_t )n_embd_dec * sizeof (float )); 906 } 907}; 908 909// DFlash: block-diffusion drafting with a draft-side KV cache injection 910struct common_speculative_impl_draft_dflash :public common_speculative_impl { 911common_params_speculative_draft params ; 912 913llama_batch batch ;// noise tokens 914llama_batch batch_inject ;// target features for KV cache injection 915 916 std::vector < common_sampler_ptr > smpls ; 917 918// backend sampler chain per seq, attached to ctx_dft 919 std::vector < llama_sampler *> backend_chains ; 920 921int32_t n_embd_dec = 0 ;// draft hidden size 922int32_t n_embd_enc = 0 ;// target_layer_ids_n * target_hidden_size 923int32_t n_embd_tgt = 0 ;// target model hidden size 924 925int32_t block_size = 0 ; 926llama_token mask_token_id = 0 ; 927 928bool is_dflash2 = false; 929bool is_mrope = false; 930int32_t selector_top_k = 0 ; 931 932// draft-dspark: the draft carries a Markov head and uses an anchor-first block layout 933const bool is_dspark ; 934 935// dspark speculators 936bool sample_from_anchor = true; 937 938// block-internal attention 939bool causal_attn = false; 940 941const int32_t * target_layer_ids = nullptr ;// model_dft's extract layer indices 942uint32_t target_layer_ids_n = 0 ; 943 944common_speculative_impl_draft_dflash (const common_params_speculative & params ,uint32_t n_seq , 945common_speculative_type type = COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH ) 946 :common_speculative_impl (type ,n_seq ,params .draft .n_max ) 947 ,params (params .draft ) 948 ,is_dspark (type == COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK ) 949 { 950auto * ctx_tgt = this -> params .ctx_tgt ; 951auto * ctx_dft = this -> params .ctx_dft ; 952GGML_ASSERT (ctx_tgt && ctx_dft && "DFlash requires ctx_tgt and ctx_dft to be set" ); 953 954const llama_model * model_dft = llama_get_model (ctx_dft ); 955const llama_model * model_tgt = llama_get_model (ctx_tgt ); 956 957target_layer_ids = llama_model_target_layer_ids (model_dft ); 958target_layer_ids_n = llama_model_target_layer_ids_n (model_dft ); 959GGML_ASSERT (target_layer_ids_n > 0 && "DFlash model has no target_layer_ids" ); 960 961n_embd_tgt = llama_model_n_embd (model_tgt ); 962n_embd_dec = llama_model_n_embd (model_dft ); 963n_embd_enc = (int32_t )target_layer_ids_n * n_embd_tgt ; 964 965// read the trained block size from the dflash.block_size metadata key 966block_size = 16 ; 967 { 968char buf [32 ]= {}; 969if (llama_model_meta_val_str (model_dft ,"dflash.block_size" ,buf ,sizeof (buf )) >=0 ) { 970block_size = std::atoi (buf ); 971 } 972if (llama_model_meta_val_str (model_dft ,"dflash.sample_from_anchor" ,buf ,sizeof (buf )) >=0 ) { 973sample_from_anchor = std::strcmp (buf ,"true" )== 0 ; 974 } 975if (llama_model_meta_val_str (model_dft ,"dflash.attention.causal" ,buf ,sizeof (buf )) >=0 ) { 976causal_attn = std::strcmp (buf ,"true" )== 0 ; 977 } 978 } 979 980selector_top_k = llama_model_dflash_selector_top_k (model_dft ); 981is_dflash2 = selector_top_k > 0 ; 982mask_token_id = llama_vocab_mask (llama_model_get_vocab (model_dft )); 983 984if (is_dspark && this -> params .p_min > 0.0f ) { 985char buf [16 ]= {}; 986const bool has_conf = 987llama_model_meta_val_str (model_dft ,"dflash.has_confidence_head" ,buf ,sizeof (buf ))< 0 || 988 std::strcmp (buf ,"true" )== 0 ; 989if (!has_conf ) { 990throw std::runtime_error ("DSpark draft has no confidence head: please set --spec-draft-p-min 0" ); 991 } 992 } 993 994LOG_INF ("%s: adding speculative implementation '%s'\n" ,__func__ ,common_speculative_type_to_str (type ).c_str ()); 995LOG_INF ("%s: - n_max=%d, n_min=%d, p_min=%.2f\n" ,__func__ ,this -> params .n_max ,this -> params .n_min ,this -> params .p_min ); 996LOG_INF ("%s: - block_size=%d, mask_token_id=%d, n_extract=%u, sample_from_anchor=%s\n" ,__func__ , 997block_size ,mask_token_id ,target_layer_ids_n ,sample_from_anchor ?"true" :"false" ); 998 999// DFlash input is [id_last, <mask> * (block_size-1)]: in-place denoising yields at most 1000// block_size-1 draft tokens, anchor-first DSpark yields a full block_size draft tokens 1001const int32_t n_draft_max = is_dspark && sample_from_anchor ?block_size :block_size - 1 ; 1002if (this -> params .n_max > n_draft_max || this -> params .n_min > n_draft_max ) { 1003LOG_WRN ("%s: requested draft size (n_max=%d, n_min=%d) exceeds the trained block size %d -- clamping to %d\n" , 1004__func__ ,this -> params .n_max ,this -> params .n_min ,block_size ,n_draft_max ); 1005this -> params .n_max = std::min (this -> params .n_max ,n_draft_max ); 1006this -> params .n_min = std::min (this -> params .n_min ,n_draft_max ); 1007 } 1008this -> n_max = this -> params .n_max ; 1009 1010batch = llama_batch_init (llama_n_batch (ctx_dft ),0 ,n_seq ); 1011batch_inject = llama_batch_init (llama_n_ubatch (ctx_dft ),n_embd_enc ,n_seq ); 1012 1013// embd batches on an M-RoPE draft need 4 position rows per token 1014is_mrope = llama_model_rope_type (model_dft )== LLAMA_ROPE_TYPE_MROPE ; 1015if (is_mrope ) { 1016free (batch_inject .pos ); 1017batch_inject .pos = (llama_pos * )malloc (sizeof (llama_pos )* 4 * llama_n_batch (ctx_dft )); 1018 } 1019 1020smpls .resize (n_seq ); 1021for (auto & s :smpls ) { 1022common_params_sampling sparams ; 1023sparams .no_perf = false; 1024sparams .top_k = 10 ; 1025sparams .samplers = {COMMON_SAMPLER_TYPE_TOP_K }; 1026s .reset (common_sampler_init (model_dft ,sparams )); 1027 } 1028 1029// offload draft sampling to the backend 1030backend_chains .assign (n_seq ,nullptr ); 1031if (this -> params .backend_sampling && !is_dflash2 ) { 1032for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1033llama_sampler * chain = llama_sampler_chain_init (llama_sampler_chain_default_params ()); 1034llama_sampler_chain_add (chain ,llama_sampler_init_top_k (10 )); 1035 1036if (!llama_set_sampler (ctx_dft ,seq_id ,chain )) { 1037SPC_WRN ("backend offload failed for seq_id=%d; using CPU sampler\n" , (int )seq_id ); 1038llama_sampler_free (chain ); 1039chain = nullptr ; 1040 } 1041backend_chains [seq_id ]= chain ; 1042 } 1043 } 1044 1045// turn on extraction of the target layers' input embeddings 1046for (uint32_t k = 0 ;k < target_layer_ids_n ;++ k ) { 1047llama_set_embeddings_layer_inp (ctx_tgt , (uint32_t )target_layer_ids [k ], true); 1048 } 1049 1050// DFlash2 reads its selector lattice from h_nextn and never consumes raw logits. 1051llama_set_embeddings_nextn (ctx_dft , true,/*masked*/ !is_dflash2 ); 1052llama_set_causal_attn (ctx_dft ,causal_attn );// DFlash needs non-causal attention unless the model says otherwise 1053 } 1054 1055 ~common_speculative_impl_draft_dflash ()override { 1056auto * ctx_dft = this -> params .ctx_dft ; 1057for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )backend_chains .size ();++ seq_id ) { 1058if (backend_chains [seq_id ]== nullptr ) { 1059continue ; 1060 } 1061if (ctx_dft ) { 1062llama_set_sampler (ctx_dft ,seq_id ,nullptr ); 1063 } 1064llama_sampler_free (backend_chains [seq_id ]); 1065 } 1066backend_chains .clear (); 1067 1068llama_batch_free (batch ); 1069llama_batch_free (batch_inject ); 1070 } 1071 1072void begin (llama_seq_id seq_id ,const llama_tokens & prompt )override { 1073if (seq_id < 0 || seq_id >= (llama_seq_id )n_seq ) { 1074return ; 1075 } 1076 1077const int32_t N = (int32_t )prompt .size (); 1078if (N <=0 ) { 1079return ; 1080 } 1081 1082const llama_pos pos_max = llama_memory_seq_pos_max (llama_get_memory (params .ctx_dft ),seq_id ); 1083if (pos_max < N - 1 ) { 1084LOG_WRN ("%s: ctx_dft pos_max=%d < N-1=%d - process() did not run on every prefill ubatch. " 1085"Drafts may degrade.\n" , 1086__func__ , (int )pos_max ,N - 1 ); 1087 } 1088 } 1089 1090bool process (const llama_batch & batch_in )override { 1091if (batch_in .n_tokens <=0 ) { 1092return true; 1093 } 1094 1095// Target prefill may contain token IDs or multimodal embeddings. Both 1096// produce the target-layer features used to seed the draft KV cache, so 1097// embeddings are injected too, except the pinned ones skipped below. 1098// TODO: revisit after https://github.com/ggml-org/llama.cpp/pull/24669 is merged 1099const bool has_tokens = batch_in .token != nullptr ; 1100const bool has_embeddings = batch_in .embd != nullptr ; 1101if (has_tokens == has_embeddings ) { 1102return true; 1103 } 1104 1105const int32_t n_tokens = batch_in .n_tokens ; 1106 1107// per-seq inclusive batch range (assumes each seq's tokens are contiguous in the batch) 1108 std::vector < int32_t > i_batch_beg (n_seq ,-1 ); 1109 std::vector < int32_t > i_batch_end (n_seq ,-1 ); 1110for (int32_t k = 0 ;k < n_tokens ;++ k ) { 1111GGML_ASSERT (batch_in .n_seq_id [k ]== 1 ); 1112const llama_seq_id seq_id = batch_in .seq_id [k ][0 ]; 1113if (seq_id < 0 || seq_id >= (llama_seq_id )n_seq ) { 1114continue ; 1115 } 1116i_batch_end [seq_id ]= k ; 1117if (i_batch_beg [seq_id ]< 0 ) { 1118i_batch_beg [seq_id ]= k ; 1119 } 1120 } 1121 1122auto * ctx_tgt = this -> params .ctx_tgt ; 1123auto * ctx_dft = this -> params .ctx_dft ; 1124 1125const int32_t n_ubatch = (int32_t )llama_n_ubatch (ctx_dft ); 1126 1127for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1128if (i_batch_beg [seq_id ]< 0 ) { 1129continue ; 1130 } 1131const int32_t n_rows = i_batch_end [seq_id ]- i_batch_beg [seq_id ]+ 1 ; 1132 1133// an M-RoPE image pins all its rows to one position, so a windowed draft 1134// cache cannot free cells for it - skip it, the draft can jump over the gap 1135const bool pos_pinned = batch_in .pos [i_batch_beg [seq_id ]]== batch_in .pos [i_batch_end [seq_id ]]; 1136if (has_embeddings && n_rows > 1 && pos_pinned ) { 1137continue ; 1138 } 1139 1140for (int32_t offset = 0 ;offset < n_rows ;offset += n_ubatch ) { 1141const int32_t n_chunk = std::min (n_ubatch ,n_rows - offset ); 1142 1143// gather target features per extract layer; the fused decode encodes and 1144// injects them into the K/V cache at the target positions 1145batch_inject .n_tokens = n_chunk ; 1146for (uint32_t k = 0 ;k < target_layer_ids_n ;++ k ) { 1147const float * layer = llama_get_embeddings_layer_inp (ctx_tgt , (uint32_t )target_layer_ids [k ]); 1148if (!layer ) { 1149GGML_ABORT ("DFlash: target layer %d input not extracted." ,target_layer_ids [k ]); 1150 } 1151for (int32_t i = 0 ;i < n_chunk ;++ i ) { 1152float * dst = batch_inject .embd + (size_t )i * n_embd_enc + k * (size_t )n_embd_tgt ; 1153const float * src = layer + (size_t ) (i_batch_beg [seq_id ]+ offset + i )* n_embd_tgt ; 1154 std::memcpy (dst ,src , (size_t )n_embd_tgt * sizeof (float )); 1155 } 1156 } 1157 1158for (int32_t i = 0 ;i < n_chunk ;++ i ) { 1159const llama_pos p = batch_in .pos [i_batch_beg [seq_id ]+ offset + i ]; 1160batch_inject .pos [i ]= p ; 1161if (is_mrope ) { 1162batch_inject .pos [1 * n_chunk + i ]= p ; 1163batch_inject .pos [2 * n_chunk + i ]= p ; 1164batch_inject .pos [3 * n_chunk + i ]= 0 ; 1165 } 1166batch_inject .n_seq_id [i ]= 1 ; 1167batch_inject .seq_id [i ][0 ]= seq_id ; 1168batch_inject .logits [i ]= false; 1169 } 1170const int32_t rc = llama_decode (ctx_dft ,batch_inject ); 1171if (rc != 0 ) { 1172LOG_ERR ("%s: llama_decode(ctx_dft) failed rc=%d (n_tokens=%d, offset=%d)\n" , 1173__func__ ,rc , (int )n_chunk , (int )offset ); 1174return false; 1175 } 1176 } 1177 } 1178 1179return true; 1180 } 1181 1182void draft (common_speculative_draft_params_vec & dparams )override { 1183auto & ctx_dft = params .ctx_dft ; 1184 1185common_batch_clear (batch ); 1186 1187// build one batch holding every drafting sequence's noise block into a single decode) 1188// record where each block starts and its size 1189 std::vector < int32_t > i_block_beg (n_seq ,-1 ); 1190 std::vector < int32_t > n_block (n_seq ,0 ); 1191 1192for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1193auto & dp = dparams [seq_id ]; 1194if (!dp .drafting ) { 1195continue ; 1196 } 1197 1198common_sampler_reset (smpls [seq_id ].get ()); 1199 1200const int32_t n = (int32_t )dp .pos0 ; 1201 1202const int32_t n_draft = params .n_max ; 1203 1204const int32_t n_block_tokens = n_draft + (is_dspark && sample_from_anchor ?0 :1 ); 1205i_block_beg [seq_id ]= batch .n_tokens ; 1206n_block [seq_id ]= n_block_tokens ; 1207for (int32_t i = 0 ;i < n_block_tokens ;++ i ) { 1208common_batch_add (batch ,i == 0 ?dp .id_last :mask_token_id ,n + i , {seq_id }, !is_dflash2 ); 1209 } 1210 } 1211 1212if (batch .n_tokens == 0 ) { 1213return ; 1214 } 1215 1216// decode all sequence's noise block in a single batch 1217int ret = llama_decode (ctx_dft ,batch ); 1218if (ret != 0 ) { 1219LOG_WRN ("%s: llama_decode returned %d\n" ,__func__ ,ret ); 1220return ; 1221 } 1222 1223for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1224if (i_block_beg [seq_id ]< 0 ) { 1225continue ; 1226 } 1227auto & dp = dparams [seq_id ]; 1228 1229const int32_t beg = i_block_beg [seq_id ]; 1230const int32_t n_block_tokens = n_block [seq_id ]; 1231 1232auto * smpl = smpls [seq_id ].get (); 1233 1234auto & result = * dp .result ; 1235 1236if (is_dflash2 ) { 1237const float * lattice = llama_get_embeddings_nextn (ctx_dft ); 1238GGML_ASSERT (lattice && "DFlash2 selector produced no lattice" ); 1239 1240int32_t predecessor = 0 ; 1241for (int32_t i = 1 ;i < n_block_tokens ;++ i ) { 1242const float * row = lattice + (size_t ) (beg + i )* n_embd_dec ; 1243const float * scores = row + selector_top_k + (size_t )predecessor * selector_top_k ; 1244 1245predecessor = (int32_t ) std::distance (scores , 1246 std::max_element (scores ,scores + selector_top_k )); 1247if (params .p_min > 0.0f ) { 1248// softmax(scores) at the argmax, i.e. 1 / sum(exp(s_k - s_max)) 1249float sum = 0.0f ; 1250for (int32_t k = 0 ;k < selector_top_k ;++ k ) { 1251sum += std::exp (scores [k ]- scores [predecessor ]); 1252 } 1253if (1.0f /sum < params .p_min ) { 1254break ; 1255 } 1256 } 1257result .push_back ((llama_token )row [predecessor ]); 1258 } 1259 1260if (result .size ()< (size_t )params .n_min ) { 1261result .clear (); 1262 } 1263continue ; 1264 } 1265 1266if (is_dspark ) { 1267// DSpark: read from the first draft slot, truncate below the confidence threshold 1268const float * conf = params .p_min > 0.0f ?llama_get_embeddings_nextn (ctx_dft ) :nullptr ; 1269// bonus-anchor drafts read the mask positions only, like DFlash 1270const int32_t i_draft_beg = sample_from_anchor ?0 :1 ; 1271for (int32_t i = i_draft_beg ;i < n_block_tokens ;++ i ) { 1272const int32_t idx = beg + i ; 1273 1274if (conf && conf [(size_t )idx * n_embd_dec ]< params .p_min ) { 1275break ; 1276 } 1277 1278common_sampler_sample (smpl ,ctx_dft ,idx , true); 1279 1280const auto * cur_p = common_sampler_get_candidates (smpl , true); 1281 1282for (int k = 0 ;k < std::min (3 , (int )cur_p -> size );++ k ) { 1283LOG_DBG (" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n" , 1284seq_id ,k ,i ,cur_p -> data [k ].id ,cur_p -> data [k ].p , 1285common_token_to_piece (ctx_dft ,cur_p -> data [k ].id ).c_str ()); 1286 } 1287 1288const llama_token id = cur_p -> data [0 ].id ; 1289 1290common_sampler_accept (smpl ,id , true); 1291 1292result .push_back (id ); 1293 } 1294 }else { 1295// greedily read the predicted block at this sequence's noise positions 1..n_block_tokens-1 1296for (int32_t i = 1 ;i < n_block_tokens ;++ i ) { 1297common_sampler_sample (smpl ,ctx_dft ,beg + i , true); 1298 1299const auto * cur_p = common_sampler_get_candidates (smpl , true); 1300 1301for (int k = 0 ;k < std::min (3 , (int )cur_p -> size );++ k ) { 1302LOG_DBG (" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n" , 1303seq_id ,k ,i - 1 ,cur_p -> data [k ].id ,cur_p -> data [k ].p , 1304common_token_to_piece (ctx_dft ,cur_p -> data [k ].id ).c_str ()); 1305 } 1306 1307const llama_token id = cur_p -> data [0 ].id ; 1308 1309if (cur_p -> data [0 ].p < params .p_min ) { 1310break ; 1311 } 1312 1313common_sampler_accept (smpl ,id , true); 1314 1315result .push_back (id ); 1316 } 1317 } 1318 1319if (result .size ()< (size_t )params .n_min ) { 1320result .clear (); 1321 } 1322 } 1323 } 1324 1325void accept (llama_seq_id /*seq_id*/ ,uint16_t /*n_accepted*/ ,bool /*is_other*/ )override { 1326// noop 1327 } 1328}; 1329 1330struct common_speculative_impl_draft_mtp :public common_speculative_impl { 1331common_params_speculative_draft params ;// reuses the draft-model params slot (ctx_tgt/ctx_dft) 1332 1333llama_batch batch ; 1334 1335 std::vector < common_sampler_ptr > smpls ; 1336 1337// backend sampler chain per seq, attached to ctx_dft 1338 std::vector < llama_sampler *> backend_chains ; 1339 1340int32_t n_embd = 0 ; 1341 1342// One MTP draft driver, three modes (set once in the ctor): 1343// is_mem_shared (gemma4): shares the target KV, runs all heads in one graph. 1344// chain_heads (step35): n_mtp_layers trained heads, one per draft step. 1345// neither (qwen35 / qwen35moe): a single trained MTP head. 1346int32_t n_mtp_layers = 1 ; 1347bool is_mem_shared = false;// gemma4 1348bool chain_heads = false;// derived in the ctor: n_mtp_layers > 1 && !is_mem_shared 1349 1350// Per-sequence cross-batch carryover: pair (h_p, x_{p+1}) at MTP pos p+1. 1351// The last h-row of one process() call needs the first token of the NEXT 1352// call to pair with, so it's stashed here until that next call fires. 1353 std::vector < std::vector < float >> pending_h ;// [n_seq][n_embd] 1354 1355 std::vector < int32_t > i_batch_beg ; 1356 std::vector < int32_t > i_batch_end ; 1357 1358// Hidden rows from the most recent target verification batch, grouped by seq. 1359// Row 0 corresponds to the sampled token, row N to the Nth accepted draft token. 1360 std::vector < std::vector < float >> verify_h ; 1361 std::vector < int32_t > verify_h_rows ; 1362 1363 std::vector < int > i_last ; 1364 std::vector < std::vector < float >> chain_h ; 1365 1366common_speculative_impl_draft_mtp (const common_params_speculative & params ,uint32_t n_seq ) 1367 :common_speculative_impl (COMMON_SPECULATIVE_TYPE_DRAFT_MTP ,n_seq ,params .draft .n_max ) 1368 ,params (params .draft ) 1369 { 1370auto * ctx_tgt = this -> params .ctx_tgt ; 1371auto * ctx_dft = this -> params .ctx_dft ; 1372GGML_ASSERT (ctx_tgt && ctx_dft && "MTP requires ctx_tgt and ctx_dft to be set" ); 1373 1374n_embd = llama_model_n_embd_out (llama_get_model (ctx_dft )); 1375GGML_ASSERT (n_embd == llama_model_n_embd_out (llama_get_model (ctx_tgt ))&& 1376"MTP input row width must match the target h_nextn width" ); 1377n_mtp_layers = std::max (1 , (int )llama_model_n_layer_nextn (llama_get_model (ctx_dft ))); 1378 1379SPC_TRC ("%s" ,"adding speculative implementation 'draft-mtp'\n" ); 1380SPC_TRC ("- n_max=%d, n_min=%d, p_min=%.2f, n_embd=%d, backend_sampling=%d\n" ,this -> params .n_max ,this -> params .n_min ,this -> params .p_min ,n_embd , (int )this -> params .backend_sampling ); 1381SPC_TRC ("- gpu_layers=%d, cache_k=%s, cache_v=%s, ctx_tgt=%s, ctx_dft=%s, devices=[%s]\n" , 1382this -> params .n_gpu_layers , 1383ggml_type_name (this -> params .cache_type_k ), 1384ggml_type_name (this -> params .cache_type_v ), 1385ctx_tgt ?"yes" :"no" , 1386ctx_dft ?"yes" :"no" , 1387common_speculative_get_devices_str (this -> params .devices ).c_str ()); 1388 1389const int32_t n_b = (int32_t )llama_n_batch (ctx_dft ); 1390batch = llama_batch_init (/*n_tokens=*/ n_b ,/*embd=*/ n_embd ,/*n_seq_max=*/ 1 ); 1391// llama_batch_init allocates only one of token/embd; MTP needs both. 1392// TODO: fix, how to call without malloc 1393batch .token = (llama_token * )malloc (sizeof (llama_token )* n_b ); 1394 1395smpls .resize (n_seq ); 1396for (auto & s :smpls ) { 1397common_params_sampling sparams ; 1398sparams .no_perf = false; 1399sparams .top_k = 10 ; 1400sparams .samplers = {COMMON_SAMPLER_TYPE_TOP_K }; 1401s .reset (common_sampler_init (llama_get_model (ctx_dft ),sparams )); 1402 } 1403 1404// offload draft sampling to the backend 1405backend_chains .assign (n_seq ,nullptr ); 1406if (this -> params .backend_sampling ) { 1407for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1408llama_sampler * chain = llama_sampler_chain_init (llama_sampler_chain_default_params ()); 1409llama_sampler_chain_add (chain ,llama_sampler_init_top_k (10 )); 1410 1411if (!llama_set_sampler (ctx_dft ,seq_id ,chain )) { 1412SPC_WRN ("backend offload failed for seq_id=%d; using CPU sampler\n" , (int )seq_id ); 1413llama_sampler_free (chain ); 1414chain = nullptr ; 1415 } 1416backend_chains [seq_id ]= chain ; 1417 } 1418 } 1419 1420llama_set_embeddings_nextn (ctx_tgt , true,/*masked*/ false); 1421llama_set_embeddings_nextn (ctx_dft , true,/*masked*/ true); 1422 1423is_mem_shared = llama_get_ctx_other (ctx_dft )== ctx_tgt ; 1424chain_heads = n_mtp_layers > 1 && !is_mem_shared ; 1425 1426if (chain_heads ) { 1427this -> params .n_max = std::min (this -> params .n_max ,n_mtp_layers ); 1428 1429chain_h .assign (n_seq , {}); 1430for (auto & c :chain_h ) { 1431c .reserve ((size_t ) (this -> params .n_max + 1 )* n_embd ); 1432 } 1433 } 1434this -> n_max = this -> params .n_max ; 1435 1436pending_h .assign (n_seq , std::vector < float > (n_embd ,0.0f )); 1437 1438i_last .assign (n_seq ,-1 ); 1439i_batch_beg .assign (n_seq ,-1 ); 1440i_batch_end .assign (n_seq ,-1 ); 1441 1442verify_h .assign (n_seq , {}); 1443verify_h_rows .assign (n_seq ,0 ); 1444 } 1445 1446 ~common_speculative_impl_draft_mtp ()override { 1447auto * ctx_dft = this -> params .ctx_dft ; 1448for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )backend_chains .size ();++ seq_id ) { 1449if (backend_chains [seq_id ]== nullptr ) { 1450continue ; 1451 } 1452if (ctx_dft ) { 1453llama_set_sampler (ctx_dft ,seq_id ,nullptr ); 1454 } 1455llama_sampler_free (backend_chains [seq_id ]); 1456 } 1457backend_chains .clear (); 1458 1459if (batch .token != nullptr ) { 1460free (batch .token ); 1461batch .token = nullptr ; 1462 } 1463llama_batch_free (batch ); 1464 } 1465 1466void begin (llama_seq_id seq_id ,const llama_tokens & prompt )override { 1467const int32_t N = (int32_t )prompt .size (); 1468if (N <=0 ) { 1469return ; 1470 } 1471 1472auto * ctx_dft = this -> params .ctx_dft ; 1473const llama_pos pos_max = llama_memory_seq_pos_max (llama_get_memory (ctx_dft ),seq_id ); 1474 1475if (pos_max < N - 1 && !is_mem_shared ) { 1476SPC_WRN ("ctx_dft pos_max=%d < N-1=%d - " 1477"process() hook may not have run on every prefill ubatch " 1478"(need_embd / logits=1 on every prompt position?). " 1479"Drafts may degrade.\n" , 1480 (int )pos_max ,N - 1 ); 1481 } 1482 } 1483 1484bool process (const llama_batch & batch_in )override { 1485if (batch_in .n_tokens <=0 ) { 1486return true; 1487 } 1488 1489// TODO: how to make it work with vision tokens? 1490if (batch_in .token == nullptr || batch_in .embd != nullptr ) { 1491return true; 1492 } 1493 1494const int32_t n_tokens = batch_in .n_tokens ; 1495 1496// remember the first and last batch index for each sequence 1497 std::fill (i_batch_beg .begin (),i_batch_beg .end (),-1 ); 1498 std::fill (i_batch_end .begin (),i_batch_end .end (),-1 ); 1499 1500for (int k = 0 ;k < n_tokens ;++ k ) { 1501for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1502GGML_ASSERT (batch_in .n_seq_id [k ]== 1 ); 1503 1504if (batch_in .seq_id [k ][0 ]== seq_id ) { 1505i_batch_end [seq_id ]= k ; 1506if (i_batch_beg [seq_id ]< 0 ) { 1507i_batch_beg [seq_id ]= k ; 1508 } 1509 } 1510 } 1511 } 1512 1513auto * ctx_tgt = this -> params .ctx_tgt ; 1514auto * ctx_dft = this -> params .ctx_dft ; 1515 1516const size_t row_bytes = (size_t )n_embd * sizeof (float ); 1517 1518// if kv is shared with target (e.g Gemma4), then we can skip this catch-up decode 1519if (!is_mem_shared ) { 1520common_batch_clear (batch ); 1521 1522for (int k = 0 ;k < n_tokens ;++ k ) { 1523common_batch_add (batch ,batch_in .token [k ],batch_in .pos [k ], {batch_in .seq_id [k ][0 ] },0 ); 1524 } 1525 1526// shift the tgt embeddings to the right by one position 1527// assumes that the tokens in the batch are sequential for each sequence 1528// i.e. we cannot have seq_id like this: [0, 0, 0, 1, 1, 0, 1, 1] 1529// ^--- this is a problem 1530// TODO:this is generally true, but would be nice to assert it 1531 { 1532const float * h_tgt = llama_get_embeddings_nextn (ctx_tgt ); 1533 std::memcpy (batch .embd + (size_t )1 * n_embd ,h_tgt ,row_bytes * (n_tokens - 1 )); 1534 } 1535 1536// fill the pending embeddings from a previous run 1537auto set_h = [& ](int idx ,const float * h_row ) { 1538 std::memcpy (batch .embd + (size_t )idx * n_embd ,h_row ,row_bytes ); 1539 }; 1540 1541for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1542if (i_batch_beg [seq_id ]< 0 ) { 1543continue ; 1544 } 1545 1546set_h (i_batch_beg [seq_id ],pending_h [seq_id ].data ()); 1547 } 1548 1549auto * mem_dft = llama_get_memory (ctx_dft ); 1550 1551bool ok = true; 1552for (int head = 0 ;head < n_mtp_layers ;++ head ) { 1553if (chain_heads ) { 1554// ref: https://github.com/ggml-org/llama.cpp/pull/24340/changes#r3413498544 1555for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1556if (i_batch_beg [seq_id ]< 0 ) { 1557continue ; 1558 } 1559llama_memory_seq_rm (mem_dft ,seq_id ,batch_in .pos [i_batch_beg [seq_id ]],-1 ); 1560 } 1561llama_set_nextn_layer_offset (ctx_dft ,head ); 1562 } 1563 1564const int32_t rc = llama_decode (ctx_dft ,batch ); 1565if (rc != 0 ) { 1566SPC_ERR ("llama_decode(ctx_dft) head=%d failed rc=%d (pos=%d)\n" , 1567head , (int )rc , (int )batch_in .pos [0 ]); 1568ok = false; 1569break ; 1570 } 1571 } 1572 1573if (chain_heads ) { 1574llama_set_nextn_layer_offset (ctx_dft ,0 );// restore default for non-draft decodes 1575 } 1576if (!ok ) { 1577return false; 1578 } 1579 } 1580 1581for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1582if (i_batch_end [seq_id ]< 0 ) { 1583continue ; 1584 } 1585 1586const int32_t n_rows = i_batch_end [seq_id ]- i_batch_beg [seq_id ]+ 1 ; 1587verify_h_rows [seq_id ]= n_rows ; 1588verify_h [seq_id ].resize ((size_t )n_rows * n_embd ); 1589 1590for (int32_t i = 0 ;i < n_rows ;++ i ) { 1591const float * h = llama_get_embeddings_nextn_ith (ctx_tgt ,i_batch_beg [seq_id ]+ i ); 1592 std::memcpy (verify_h [seq_id ].data ()+ (size_t )i * n_embd ,h ,row_bytes ); 1593 } 1594 1595 std::memcpy (pending_h [seq_id ].data (), 1596verify_h [seq_id ].data ()+ (size_t ) (n_rows - 1 )* n_embd ,row_bytes ); 1597 } 1598 1599return true; 1600 } 1601 1602void draft (common_speculative_draft_params_vec & dparams )override { 1603auto & ctx_dft = params .ctx_dft ; 1604 1605common_batch_clear (batch ); 1606 1607// keep track of which sequences are still drafting 1608int n_drafting = 0 ; 1609 std::vector < bool > drafting (n_seq ); 1610 1611const size_t row_bytes = (size_t )n_embd * sizeof (float ); 1612 1613for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1614auto & dp = dparams [seq_id ]; 1615 1616if (!dp .drafting ) { 1617continue ; 1618 } 1619 1620n_drafting ++ ; 1621drafting [seq_id ]= true; 1622common_sampler_reset (smpls [seq_id ].get ()); 1623 1624common_batch_add (batch ,dp .id_last ,dp .pos0 , {seq_id }, true); 1625 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd ,pending_h [seq_id ].data (),row_bytes ); 1626 1627i_last [seq_id ]= batch .n_tokens - 1 ; 1628 1629if (chain_heads ) { 1630chain_h [seq_id ].assign (pending_h [seq_id ].begin (),pending_h [seq_id ].end ()); 1631 } 1632 } 1633 1634int i = 0 ; 1635 1636while (n_drafting > 0 ) { 1637// each step decodes under a different head, i.e. a different decoder layer, and 1638// KV is per layer. process() filled this layer's KV only for positions < pos0 1639// (prompt + accepted prefix) — nothing in the draft region yet. so reset the 1640// draft region (the seq_rm lower bound is pos0, leaving the prompt KV intact) 1641// and select head i so it rebuilds its own layer's KV there; decoding just the 1642// latest token would leave its attention reading cells only another head wrote. 1643if (chain_heads ) { 1644auto * mem_dft = llama_get_memory (ctx_dft ); 1645for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1646if (drafting [seq_id ]) { 1647llama_memory_seq_rm (mem_dft ,seq_id ,dparams [seq_id ].pos0 ,-1 ); 1648 } 1649 } 1650llama_set_nextn_layer_offset (ctx_dft ,i ); 1651 } 1652 1653int ret = llama_decode (ctx_dft ,batch ); 1654if (ret != 0 ) { 1655SPC_ERR ("llama_decode[%d] returned %d\n" ,i ,ret ); 1656break ; 1657 } 1658 1659// rebuild the batch for the next step: the growing-KV paths re-add only the 1660// new token (the KV already holds the prefix), while chained heads re-add the 1661// whole prefix at the next head. dropped sequences are simply not re-added. 1662common_batch_clear (batch ); 1663 1664for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1665if (!drafting [seq_id ]) { 1666continue ; 1667 } 1668 1669auto * smpl = smpls [seq_id ].get (); 1670 1671common_sampler_sample (smpl ,ctx_dft ,i_last [seq_id ], true); 1672const float * h_row = llama_get_embeddings_nextn_ith (ctx_dft ,i_last [seq_id ]); 1673 1674const auto * cur_p = common_sampler_get_candidates (smpl , true); 1675 1676for (int k = 0 ;k < std::min (3 , (int )cur_p -> size );++ k ) { 1677SPC_DBG (" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n" , 1678seq_id ,k ,i ,cur_p -> data [k ].id ,cur_p -> data [k ].p , 1679common_token_to_piece (ctx_dft ,cur_p -> data [k ].id ).c_str ()); 1680 } 1681 1682// add drafted token for each sequence 1683const llama_token id = cur_p -> data [0 ].id ; 1684 1685// only collect very high-confidence draft tokens 1686if (cur_p -> data [0 ].p < params .p_min ) { 1687drafting [seq_id ]= false; 1688n_drafting -- ; 1689 1690continue ; 1691 } 1692 1693common_sampler_accept (smpl ,id , true); 1694 1695auto & dp = dparams .at (seq_id ); 1696auto & result = * dp .result ; 1697 1698result .push_back (id ); 1699 1700if (params .n_max <= (int )result .size ()) { 1701drafting [seq_id ]= false; 1702n_drafting -- ; 1703continue ; 1704 } 1705 1706if (chain_heads ) { 1707// ref: https://github.com/ggml-org/llama.cpp/pull/24340#discussion_r3448031546 1708chain_h [seq_id ].insert (chain_h [seq_id ].end (),h_row ,h_row + n_embd ); 1709 1710const int n_rows = (int )result .size ()+ 1 ;// id_last + tokens drafted so far 1711for (int t = 0 ;t < n_rows ;++ t ) { 1712const llama_token tok = (t == 0 ) ?dp .id_last :result [t - 1 ]; 1713common_batch_add (batch ,tok ,dp .pos0 + t , {seq_id },t == n_rows - 1 ); 1714 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd , 1715chain_h [seq_id ].data ()+ (size_t )t * n_embd ,row_bytes ); 1716 } 1717 }else if (is_mem_shared ) { 1718// note: with shared memory (e.g. Gemma4 assistants) we use the same position for all draft tokens 1719// ref: https://github.com/huggingface/transformers/blob/effde20942e3f82a1b97449f60b3a48c5ff96145/docs/source/en/model_doc/gemma4_assistant.md?plain=1#L36-L37 1720common_batch_add (batch ,id ,dp .pos0 , {seq_id }, true); 1721 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd ,h_row ,row_bytes ); 1722 }else { 1723common_batch_add (batch ,id ,dp .pos0 + i + 1 , {seq_id }, true); 1724 std::memcpy (batch .embd + (size_t ) (batch .n_tokens - 1 )* n_embd ,h_row ,row_bytes ); 1725 } 1726 1727i_last [seq_id ]= batch .n_tokens - 1 ; 1728 } 1729 1730if (batch .n_tokens == 0 ) { 1731break ; 1732 } 1733 1734++ i ; 1735 } 1736 1737if (chain_heads ) { 1738llama_set_nextn_layer_offset (ctx_dft ,0 );// restore default for non-draft decodes 1739 } 1740 1741for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1742auto & dp = dparams [seq_id ]; 1743if (!dp .drafting ) { 1744continue ; 1745 } 1746 1747if (dp .result -> size ()< (size_t )params .n_min ) { 1748dp .result -> clear (); 1749 } 1750 } 1751 } 1752 1753void accept (llama_seq_id seq_id ,uint16_t n_accepted ,bool /*is_other*/ )override { 1754if (seq_id < 0 || seq_id >= (llama_seq_id )n_seq ) { 1755return ; 1756 } 1757 1758const int32_t n_rows = verify_h_rows [seq_id ]; 1759if (n_rows <=0 ) { 1760return ; 1761 } 1762 1763const int32_t i_h = std::min < int32_t > (n_accepted ,n_rows - 1 ); 1764const size_t row_bytes = (size_t )n_embd * sizeof (float ); 1765 std::memcpy (pending_h [seq_id ].data (),verify_h [seq_id ].data ()+ (size_t )i_h * n_embd ,row_bytes ); 1766 } 1767}; 1768 1769// state of self-speculation (simple implementation, not ngram-map) 1770struct common_speculative_impl_ngram_simple :public common_speculative_impl { 1771common_params_speculative_ngram_map params ; 1772 1773// shared across all sequences 1774common_ngram_simple_config config ; 1775 1776common_speculative_impl_ngram_simple ( 1777const common_params_speculative & params ,uint32_t n_seq , 1778common_ngram_simple_config config ) 1779 :common_speculative_impl (COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE ,n_seq ,params .ngram_simple .size_m ) 1780 ,params (params .ngram_simple ) 1781 ,config (config ) 1782 { 1783SPC_TRC ("%s" ,"adding speculative implementation 'ngram-simple'\n" ); 1784SPC_TRC ("- size_n=%d, size_m=%d, min_hits=%d\n" , 1785this -> params .size_n ,this -> params .size_m ,this -> params .min_hits ); 1786 } 1787 1788void begin (llama_seq_id /*seq_id*/ ,const llama_tokens & /*prompt*/ )override { 1789// noop 1790 } 1791 1792bool process (const llama_batch & /*batch*/ )override { 1793// TODO: implement 1794return true; 1795 } 1796 1797void draft (common_speculative_draft_params_vec & dparams )override { 1798assert (dparams .size ()== n_seq ); 1799 1800for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1801auto & dp = dparams [seq_id ]; 1802if (!dp .drafting ) { 1803continue ; 1804 } 1805 1806* dp .result = common_ngram_simple_draft (config ,* dp .prompt ,dp .id_last ); 1807 } 1808 } 1809 1810void accept (llama_seq_id /*seq_id*/ ,uint16_t /*n_accepted*/ ,bool /*is_other*/ )override { 1811// noop 1812 } 1813}; 1814 1815struct common_speculative_impl_ngram_map_k :public common_speculative_impl { 1816// n_seq configs 1817 std::vector < common_ngram_map > config ; 1818 1819common_speculative_impl_ngram_map_k ( 1820const common_ngram_map & config , 1821uint32_t n_seq ) 1822 :common_speculative_impl (config .key_only ?COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K 1823 :COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V ,n_seq ,config .size_value ) 1824 { 1825for (uint32_t i = 0 ;i < n_seq ;i ++ ) { 1826this -> config .push_back (config ); 1827 } 1828 1829SPC_TRC ("adding speculative implementation '%s'\n" ,common_speculative_type_to_str (this -> type ).c_str ()); 1830SPC_TRC ("- size_key=%d, size_value=%d, key_only=%d, min_hits=%d\n" , 1831config .size_key ,config .size_value ,config .key_only ,config .min_hits ); 1832 } 1833 1834void begin (llama_seq_id seq_id ,const llama_tokens & prompt )override { 1835GGML_ASSERT (seq_id < (llama_seq_id )n_seq ); 1836 1837common_ngram_map_begin (config [seq_id ],prompt ); 1838 } 1839 1840bool process (const llama_batch & /*batch*/ )override { 1841// TODO: implement 1842return true; 1843 } 1844 1845void draft (common_speculative_draft_params_vec & dparams )override { 1846assert (dparams .size ()== n_seq ); 1847 1848for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 1849auto & dp = dparams [seq_id ]; 1850if (!dp .drafting ) { 1851continue ; 1852 } 1853 1854common_ngram_map_draft (config [seq_id ],* dp .prompt ,dp .id_last ,* dp .result ); 1855 } 1856 } 1857 1858void accept (llama_seq_id seq_id ,uint16_t n_accepted ,bool is_other )override { 1859GGML_ASSERT ((seq_id < (llama_seq_id )config .size ())); 1860 1861if (is_other ) { 1862return ; 1863 } 1864 1865common_ngram_map_accept (config [seq_id ],n_accepted ); 1866 } 1867}; 1868 1869struct common_speculative_impl_ngram_mod :public common_speculative_impl { 1870common_params_speculative_ngram_mod params ; 1871 1872// shared across all sequences 1873common_ngram_mod mod ; 1874 1875// enable trace logging if LLAMA_TRACE is set 1876const bool verbose ; 1877 1878struct seq_info { 1879// the last position in the prompt that was added to the ngram container 1880size_t i_last = 0 ; 1881 1882// length of the last drafted n-gram (number of tokens returned by draft) 1883size_t n_draft_last = 0 ; 1884 1885// consecutive accept rounds with low acceptance fraction (< 0.5) 1886int n_low = 0 ; 1887 }; 1888 1889 std::vector < seq_info > sinfos ; 1890 1891common_speculative_impl_ngram_mod ( 1892const common_params_speculative & params , 1893uint32_t n_seq ) 1894 :common_speculative_impl (COMMON_SPECULATIVE_TYPE_NGRAM_MOD ,n_seq ,params .ngram_mod .n_max ) 1895 ,params (params .ngram_mod ) 1896 ,mod (params .ngram_mod .n_match ,4 * 1024 * 1024 ) 1897 ,verbose (std::getenv ("LLAMA_TRACE" )!= nullptr ) { 1898 static_assert(sizeof (llama_token )== sizeof (common_ngram_mod::entry_t )); 1899 1900SPC_TRC ("%s" ,"adding speculative implementation 'ngram-mod'\n" ); 1901SPC_TRC ("- n_match=%d, n_max=%d, n_min=%d\n" , 1902this -> params .n_match ,this -> params .n_max ,this -> params .n_min ); 1903SPC_TRC ("- mod size=%zu (%.3f MB)\n" , 1904mod .size (), (float )(mod .size_bytes ())/1024 /1024 ); 1905 1906if (this -> params .n_match < 16 ) { 1907SPC_WRN ("ngram_mod n_match=%d is too small - poor quality is possible, " 1908"see: https://github.com/ggml-org/llama.cpp/pull/19164\n" ,this -> params .n_match ); 1909 } 1910 1911sinfos .resize (n_seq ); 1912 } 1913 1914void begin (llama_seq_id seq_id ,const llama_tokens & prompt )override { 1915auto & sinfo = sinfos [seq_id ]; 1916 1917sinfo .i_last = 0 ; 1918sinfo .n_draft_last = 0 ; 1919 1920const size_t n = mod .get_n (); 1921if (prompt .size ()< n ) { 1922return ; 1923 } 1924 1925for (size_t i = 0 ;i < prompt .size ()- n ;++ i ) { 1926mod .add (prompt .data ()+ i ); 1927 } 1928 1929sinfo .i_last = prompt .size ()- n ; 1930 1931const double f = (double )mod .get_used () / (double )mod .size (); 1932SPC_TRC ("ngram_mod occupancy = %zu/%zu (%.2f)\n" ,mod .get_used (),mod .size (),f ); 1933 1934constexpr double f_thold = 0.25 ; 1935if (f > f_thold ) { 1936SPC_WRN ("ngram_mod occupancy %.2f exceeds threshold (%.2f) - resetting\n" ,f ,f_thold ); 1937 1938mod .reset (); 1939 } 1940 } 1941 1942void draft_one ( 1943llama_seq_id seq_id , 1944common_speculative_draft_params & dparams ) { 1945auto & sinfo = sinfos [seq_id ]; 1946auto & result = * dparams .result ; 1947 1948const auto & prompt = * dparams .prompt ; 1949 1950sinfo .n_draft_last = 0 ; 1951 1952const size_t cur_len = prompt .size (); 1953if (cur_len < mod .get_n ()) { 1954return ; 1955 } 1956 1957const size_t n = mod .get_n (); 1958 1959// add new ngrams in chunks 1960if (sinfo .i_last + 32 < cur_len ) { 1961for (size_t i = sinfo .i_last ;i < cur_len - n ;++ i ) { 1962mod .add (prompt .data ()+ i ); 1963 } 1964 1965sinfo .i_last = cur_len - n ; 1966 } 1967 1968result .resize (n + params .n_max ); 1969for (size_t i = 0 ;i < n - 1 ;++ i ) { 1970result [i ]= prompt .at (cur_len - n + 1 + i ); 1971 } 1972result [n - 1 ]= dparams .id_last ; 1973 1974for (int i = 0 ;i < params .n_max ;++ i ) { 1975const llama_token token = mod .get (result .data ()+ i ); 1976if (token == common_ngram_mod::EMPTY ) { 1977if (i < params .n_min ) { 1978result .clear (); 1979return ; 1980 } 1981 1982result .resize (n + i ); 1983break ; 1984 } 1985result [n + i ]= token ; 1986 } 1987 1988// only return the m tokens that were drafted 1989for (size_t i = 0 ;n + i < result .size ();++ i ) { 1990result [i ]= result [n + i ]; 1991 } 1992result .resize (result .size ()- n ); 1993 1994// store length of drafted n-gram for later acceptance analysis 1995sinfo .n_draft_last = result .size (); 1996 } 1997 1998bool process (const llama_batch & /*batch*/ )override { 1999// TODO: implement 2000return true; 2001 } 2002 2003void draft (common_speculative_draft_params_vec & dparams )override { 2004assert (dparams .size ()== n_seq ); 2005 2006for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 2007auto & dp = dparams [seq_id ]; 2008if (!dp .drafting ) { 2009continue ; 2010 } 2011 2012draft_one (seq_id ,dp ); 2013 } 2014 } 2015 2016void accept (llama_seq_id seq_id ,uint16_t n_accepted ,bool is_other )override { 2017if (is_other ) { 2018return ; 2019 } 2020 2021auto & sinfo = sinfos [seq_id ]; 2022 2023// compute acceptance fraction if we have a recorded draft length 2024if (sinfo .n_draft_last > 0 ) { 2025const double f_acc = (double )n_accepted / (double )sinfo .n_draft_last ; 2026if (f_acc < 0.25 ) { 2027sinfo .n_low ++ ; 2028if (sinfo .n_low >=5 ) { 2029if (verbose ) { 2030SPC_TRC ("low acceptance streak (%d) - resetting ngram_mod\n" ,sinfo .n_low ); 2031 } 2032 2033mod .reset (); 2034sinfo .n_low = 0 ; 2035sinfo .i_last = 0 ; 2036 } 2037 }else { 2038sinfo .n_low = 0 ; 2039 } 2040 } 2041 } 2042}; 2043 2044struct common_speculative_impl_ngram_cache :public common_speculative_impl { 2045common_params_speculative_ngram_cache params ; 2046 2047uint16_t n_draft ; 2048 2049bool save_dynamic ; 2050bool save_static ; 2051 2052struct seq_info { 2053size_t cache_size = 0 ;// number of tokens in n-gram cache 2054 2055common_ngram_cache ngram_cache_context ; 2056common_ngram_cache ngram_cache_dynamic ; 2057common_ngram_cache ngram_cache_static ; 2058 }; 2059 2060 std::vector < seq_info > sinfos ; 2061 2062common_speculative_impl_ngram_cache ( 2063const common_params_speculative & params , 2064uint32_t n_seq , 2065uint16_t n_draft , 2066const std::string & path_static , 2067const std::string & path_dynamic , 2068bool save_dynamic , 2069bool save_static ) 2070 :common_speculative_impl (COMMON_SPECULATIVE_TYPE_NGRAM_CACHE ,n_seq ,n_draft ) 2071 ,params (params .ngram_cache ) 2072 ,n_draft (n_draft ) 2073 ,save_dynamic (save_dynamic ) 2074 ,save_static (save_static ) 2075 { 2076SPC_TRC ("%s" ,"adding speculative implementation 'ngram-cache'\n" ); 2077SPC_TRC ("- n_draft=%d, cache_static=%s, cache_dynamic=%s\n" , 2078n_draft , 2079path_static .empty () ?"none" :path_static .c_str (), 2080path_dynamic .empty () ?"none" :path_dynamic .c_str ()); 2081 2082sinfos .resize (n_seq ); 2083 2084if (!path_static .empty ()) { 2085try { 2086auto ngram_cache_static = common_ngram_cache_load (path_static ); 2087 2088for (auto & sinfo :sinfos ) { 2089sinfo .ngram_cache_static = ngram_cache_static ; 2090 } 2091 }catch (...) { 2092SPC_ERR ("failed to open static lookup cache: %s" ,path_static .c_str ()); 2093GGML_ABORT ("Couldn't read static lookup cache" ); 2094 } 2095 } 2096 2097if (!path_dynamic .empty ()) { 2098try { 2099auto ngram_cache_dynamic = common_ngram_cache_load (path_dynamic ); 2100 2101for (auto & sinfo :sinfos ) { 2102sinfo .ngram_cache_dynamic = ngram_cache_dynamic ; 2103 } 2104 }catch (...) { 2105SPC_ERR ("failed to open dynamic lookup cache: %s" ,path_dynamic .c_str ()); 2106GGML_ABORT ("Couldn't read dynamic lookup cache" ); 2107 } 2108 } 2109 } 2110 2111void begin (llama_seq_id /*seq_id*/ ,const llama_tokens & /*prompt*/ )override { 2112// noop 2113 } 2114 2115void draft_one ( 2116llama_seq_id seq_id , 2117common_speculative_draft_params & dparams ) { 2118auto & sinfo = sinfos [seq_id ]; 2119auto & result = * dparams .result ; 2120 2121const auto & prompt = * dparams .prompt ; 2122 2123if (sinfo .cache_size < prompt .size ()+ 1 ) { 2124llama_tokens tokens_new ; 2125tokens_new .reserve (prompt .size ()+ 1 - sinfo .cache_size ); 2126for (size_t j = sinfo .cache_size ;j < prompt .size ();++ j ) { 2127tokens_new .push_back (prompt [j ]); 2128 } 2129tokens_new .push_back (dparams .id_last );// add the last token 2130 2131// Update context ngram cache with new dparams.prompt: 2132common_ngram_cache_update ( 2133sinfo .ngram_cache_context , 2134LLAMA_NGRAM_MIN ,LLAMA_NGRAM_MAX , 2135tokens_new ,tokens_new .size (), false); 2136sinfo .cache_size = prompt .size ()+ 1 ; 2137 } 2138 2139llama_tokens inp ; 2140inp .reserve (prompt .size ()+ 1 ); 2141for (size_t j = 0 ;j < prompt .size ();++ j ) { 2142inp .push_back (prompt [j ]); 2143 } 2144inp .push_back (dparams .id_last ); 2145 2146result .push_back (dparams .id_last ); 2147 2148common_ngram_cache_draft ( 2149inp ,result ,n_draft ,LLAMA_NGRAM_MIN ,LLAMA_NGRAM_MAX , 2150sinfo .ngram_cache_context , 2151sinfo .ngram_cache_dynamic , 2152sinfo .ngram_cache_static ); 2153 2154if (result .size ()> 0 ) { 2155// delete first token in result (which is the id_last token) 2156result .erase (result .begin ()); 2157 } 2158 } 2159 2160bool process (const llama_batch & /*batch*/ )override { 2161// TODO: implement 2162return true; 2163 } 2164 2165void draft (common_speculative_draft_params_vec & dparams )override { 2166assert (dparams .size ()== n_seq ); 2167 2168for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )n_seq ;++ seq_id ) { 2169auto & dp = dparams [seq_id ]; 2170if (!dp .drafting ) { 2171continue ; 2172 } 2173 2174draft_one (seq_id ,dp ); 2175 } 2176 } 2177 2178void accept (llama_seq_id /*seq_id*/ ,uint16_t /*n_accepted*/ ,bool /*is_other*/ )override { 2179// noop 2180 } 2181}; 2182 2183struct common_speculative { 2184common_speculative_draft_params_vec dparams ; 2185 2186// list of implementations to use and their states 2187 std::vector < std::unique_ptr < common_speculative_impl >> impls ; 2188 2189// which implementaion was used for a given seq_id 2190 std::vector < common_speculative_impl *> impl_last ; 2191 2192 std::vector < double > synth_probs ; 2193}; 2194 2195static common_ngram_map get_common_ngram_map ( 2196common_speculative_type type , 2197const common_params_speculative_ngram_map & config ) { 2198uint16_t size_key = config .size_n ; 2199uint16_t size_value = config .size_m ; 2200bool key_only = type == COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K ; 2201uint16_t min_hits = config .min_hits ; 2202 2203return common_ngram_map (size_key ,size_value ,key_only ,min_hits ); 2204} 2205 2206static common_speculative_impl_ngram_cache create_state_ngram_cache ( 2207const common_speculative_config & config , 2208uint32_t n_seq , 2209const std::string & path_static , 2210const std::string & path_dynamic ) { 2211uint16_t n_draft = 8 ;// TODO get from config? 2212 2213// TODO bool param in common/common.h to set save_static/save_dynamic? 2214bool save_static = false; 2215bool save_dynamic = false; 2216 2217common_speculative_impl_ngram_cache state (config .params ,n_seq ,n_draft ,path_static ,path_dynamic ,save_static ,save_dynamic ); 2218 2219return state ; 2220} 2221 2222std::string common_speculative_type_name_str (const std::vector < common_speculative_type > & types ) { 2223 std::string result ; 2224 2225for (size_t i = 0 ;i < types .size ();i ++ ) { 2226if (i > 0 ) { 2227result += "," ; 2228 } 2229result += common_speculative_type_to_str (types [i ]); 2230 } 2231return result ; 2232} 2233 2234const char * common_speculative_all_types_str () { 2235static std::string all_types_str = []() { 2236 std::vector < common_speculative_type > types ; 2237types .reserve (COMMON_SPECULATIVE_TYPE_COUNT ); 2238for (int i = 0 ;i < COMMON_SPECULATIVE_TYPE_COUNT ;i ++ ) { 2239types .push_back ((common_speculative_type )i ); 2240 } 2241return common_speculative_type_name_str (types ); 2242 }(); 2243return all_types_str .c_str (); 2244} 2245 2246std::string common_speculative_type_to_str (common_speculative_type type ) { 2247switch (type ) { 2248case COMMON_SPECULATIVE_TYPE_NONE :return "none" ; 2249case COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE :return "draft-simple" ; 2250case COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 :return "draft-eagle3" ; 2251case COMMON_SPECULATIVE_TYPE_DRAFT_MTP :return "draft-mtp" ; 2252case COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH :return "draft-dflash" ; 2253case COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK :return "draft-dspark" ; 2254case COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE :return "ngram-simple" ; 2255case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K :return "ngram-map-k" ; 2256case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V :return "ngram-map-k4v" ; 2257case COMMON_SPECULATIVE_TYPE_NGRAM_MOD :return "ngram-mod" ; 2258case COMMON_SPECULATIVE_TYPE_NGRAM_CACHE :return "ngram-cache" ; 2259default :return "unknown" ; 2260 } 2261} 2262 2263std::vector < common_speculative_type > common_speculative_types_from_names (const std::vector < std::string > & names ) { 2264 std::vector < common_speculative_type > types ; 2265types .reserve (names .size ()); 2266 2267for (const auto & name :names ) { 2268auto type = common_speculative_type_from_name_map .find (name ); 2269if (type != common_speculative_type_from_name_map .end ()) { 2270if (type -> second == COMMON_SPECULATIVE_TYPE_NONE ) { 2271return std::vector < common_speculative_type > {COMMON_SPECULATIVE_TYPE_NONE }; 2272 } 2273types .push_back (type -> second ); 2274continue ; 2275 } 2276throw std::invalid_argument ("unknown speculative type: " + name ); 2277 } 2278 2279return types ; 2280} 2281 2282common_speculative_type common_speculative_type_from_name (const std::string & name ) { 2283const auto it = common_speculative_type_from_name_map .find (name ); 2284if (it == common_speculative_type_from_name_map .end ()) { 2285return COMMON_SPECULATIVE_TYPE_COUNT ; 2286 } 2287return it -> second ; 2288} 2289 2290std::vector < common_speculative_type > common_speculative_types_from_gguf (const std::string & path ) { 2291struct gguf_init_params gguf_params = { 2292/* .no_alloc = */ true, 2293/* .ctx = */ nullptr , 2294 }; 2295 2296gguf_context_ptr gguf_ctx (gguf_init_from_file (path .c_str (),gguf_params )); 2297if (!gguf_ctx ) { 2298return {}; 2299 } 2300 2301const int64_t arch_id = gguf_find_key (gguf_ctx .get (),"general.architecture" ); 2302if (arch_id < 0 || gguf_get_kv_type (gguf_ctx .get (),arch_id )!= GGUF_TYPE_STRING ) { 2303return {}; 2304 } 2305 2306const std::string arch = gguf_get_val_str (gguf_ctx .get (),arch_id ); 2307if (arch != "dflash" ) { 2308const uint32_t block_count = gguf_get_val_u32 (gguf_ctx .get (),gguf_find_key (gguf_ctx .get (), (arch + ".block_count" ).c_str ())); 2309 2310if (gguf_find_tensor (gguf_ctx .get (), ("blk." + std::to_string (block_count - 1 )+ ".nextn.eh_proj.weight" ).c_str ()) >=0 ) { 2311return {COMMON_SPECULATIVE_TYPE_DRAFT_MTP }; 2312 } 2313 2314return {}; 2315 } 2316 2317// the Markov head distinguishes draft-dspark from draft-dflash 2318const auto type = gguf_find_tensor (gguf_ctx .get (),"markov_w1.weight" ) >=0 2319 ?COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK 2320 :COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH ; 2321 2322SPC_INF ("auto-detected speculative type '%s' from the draft model metadata\n" ,common_speculative_type_to_str (type ).c_str ()); 2323 2324return {type }; 2325} 2326 2327static uint32_t common_get_enabled_speculative_configs (const std::vector < common_speculative_type > & configs ) { 2328uint32_t result = 0 ; 2329for (size_t i = 0 ;i < configs .size ();i ++ ) { 2330result |= (1u <<configs [i ]); 2331 } 2332return result ; 2333} 2334 2335int32_t common_speculative_n_max (const common_params_speculative * spec ) { 2336int32_t n_max = 0 ; 2337 2338for (const auto type :spec -> types ) { 2339switch (type ) { 2340case COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE : 2341case COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 : 2342case COMMON_SPECULATIVE_TYPE_DRAFT_MTP : 2343case COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH : 2344case COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK : 2345n_max = std::max (n_max , std::max (0 ,spec -> draft .n_max )); 2346break ; 2347case COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE : 2348n_max = std::max (n_max , (int32_t )spec -> ngram_simple .size_m ); 2349break ; 2350case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K : 2351n_max = std::max (n_max , (int32_t )spec -> ngram_map_k .size_m ); 2352break ; 2353case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V : 2354n_max = std::max (n_max , (int32_t )spec -> ngram_map_k4v .size_m ); 2355break ; 2356case COMMON_SPECULATIVE_TYPE_NGRAM_MOD : 2357n_max = std::max (n_max , std::max (0 ,spec -> ngram_mod .n_max )); 2358break ; 2359case COMMON_SPECULATIVE_TYPE_NGRAM_CACHE : 2360n_max = std::max (n_max , (int32_t )8 ); 2361break ; 2362case COMMON_SPECULATIVE_TYPE_NONE : 2363case COMMON_SPECULATIVE_TYPE_COUNT : 2364break ; 2365 } 2366 } 2367 2368return n_max ; 2369} 2370 2371int32_t common_speculative_n_max (const common_speculative * spec ) { 2372int32_t n_max = 0 ; 2373 2374if (spec == nullptr ) { 2375return n_max ; 2376 } 2377 2378for (const auto & impl :spec -> impls ) { 2379n_max = std::max (n_max , std::max (0 ,impl -> n_max )); 2380 } 2381 2382return n_max ; 2383} 2384 2385std::vector < double > common_speculative_synth_rates_resolve (const common_params_speculative * spec ,int32_t n_max ) { 2386const bool has_length = spec -> synth_len != -1.0 ; 2387const bool has_rates = !spec -> synth_rates .empty (); 2388 2389if (!has_length && !has_rates ) { 2390return {}; 2391 } 2392if (has_length && has_rates ) { 2393throw std::invalid_argument ("synthetic acceptance length and rates are mutually exclusive" ); 2394 } 2395 2396if (n_max <=0 ) { 2397throw std::invalid_argument ("synthetic acceptance requires at least one speculative token" ); 2398 } 2399 2400if (has_rates ) { 2401const auto & rates = spec -> synth_rates ; 2402if (rates .size ()!= (size_t )n_max ) { 2403throw std::invalid_argument (string_format ( 2404"synthetic acceptance rates must contain %d values, got %zu" ,n_max ,rates .size ())); 2405 } 2406 2407for (size_t i = 0 ;i < rates .size ();++ i ) { 2408if (!std::isfinite (rates [i ])|| rates [i ]< 0.0 || rates [i ]> 1.0 ) { 2409throw std::invalid_argument ("synthetic acceptance rates must be finite and within [0, 1]" ); 2410 } 2411if (i > 0 && rates [i ]> rates [i - 1 ]) { 2412throw std::invalid_argument ("synthetic acceptance rates must be monotonically non-increasing" ); 2413 } 2414 } 2415 2416return rates ; 2417 } 2418 2419const double length = spec -> synth_len ; 2420const double length_max = (double )n_max + 1.0 ; 2421if (!std::isfinite (length )|| length < 1.0 || length > length_max ) { 2422throw std::invalid_argument (string_format ( 2423"synthetic acceptance length must be finite and within [1, %.0f]" ,length_max )); 2424 } 2425 2426double p = 0.0 ; 2427if (length == length_max ) { 2428p = 1.0 ; 2429 }else if (length > 1.0 ) { 2430double p_min = 0.0 ; 2431double p_max = 1.0 ; 2432for (int i = 0 ;i < 32 ;++ i ) { 2433const double p_mid = 0.5 * (p_min + p_max ); 2434double sum = 0.0 ; 2435double term = p_mid ; 2436for (int32_t j = 0 ;j < n_max ;++ j ) { 2437sum += term ; 2438term *=p_mid ; 2439 } 2440 2441if (sum < length - 1.0 ) { 2442p_min = p_mid ; 2443 }else { 2444p_max = p_mid ; 2445 } 2446 } 2447p = 0.5 * (p_min + p_max ); 2448 } 2449 2450 std::vector < double > rates ; 2451rates .reserve (n_max ); 2452double rate = p ; 2453for (int32_t i = 0 ;i < n_max ;++ i ) { 2454rates .push_back (rate ); 2455rate *=p ; 2456 } 2457 2458return rates ; 2459} 2460 2461const std::vector < double > & common_speculative_get_synth_probs (const common_speculative * spec ) { 2462GGML_ASSERT (spec ); 2463return spec -> synth_probs ; 2464} 2465 2466common_params common_base_params_to_speculative (const common_params & params ) { 2467const bool has_draft = params .speculative .has_dft (); 2468 2469const auto & params_spec = params .speculative .draft ; 2470common_params result = params ; 2471 2472result .embedding = false; 2473result .pooling_type = LLAMA_POOLING_TYPE_UNSPECIFIED ; 2474 2475if (has_draft ) { 2476// default to global devices value 2477if (!params_spec .devices .empty ()) { 2478result .devices = params_spec .devices ; 2479 } 2480result .model = params_spec .mparams ; 2481result .n_gpu_layers = params_spec .n_gpu_layers ; 2482result .tensor_buft_overrides = params_spec .tensor_buft_overrides ; 2483 2484// a draft pinned to a single device doesn't need the meta wrapper an inherited -sm tensor would give it 2485// (the device list is null-terminated, so a single device means size 2) 2486const size_t n_devs = std::count_if (params_spec .devices .begin (),params_spec .devices .end (), 2487 [](ggml_backend_dev_t d ) {return d != nullptr ; }); 2488if (n_devs == 1 ) { 2489result .split_mode = LLAMA_SPLIT_MODE_LAYER ; 2490 } 2491 2492if (params_spec .cpuparams .n_threads > 0 ) { 2493result .cpuparams .n_threads = params_spec .cpuparams .n_threads ; 2494result .cpuparams_batch .n_threads = params_spec .cpuparams_batch .n_threads ; 2495 } 2496 } 2497 2498result .cache_type_k = params_spec .cache_type_k ; 2499result .cache_type_v = params_spec .cache_type_v ; 2500result .n_outputs_max = params .n_parallel ; 2501result .n_outputs_max_per_seq = 1 ; 2502 2503// dflash/dspark decode the whole noise block in a single pass and sample every block position on the backend 2504// TODO: refactor such properties to be announced by the speculative types 2505// something like `struct common_speculative_type_props common_speculative_type_get_props(...);` 2506const bool has_block_draft = std::any_of ( 2507params .speculative .types .begin (),params .speculative .types .end (), 2508 [](common_speculative_type t ) { 2509return t == COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH || t == COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK ; 2510 }); 2511if (has_block_draft ) { 2512// per-seq output positions: DFlash decodes anchor + n_max masks (n_max + 1); DSpark n_max -> +1 covers both 2513const int32_t per_seq = std::max (1 ,params_spec .n_max + 1 ); 2514result .n_outputs_max = params .n_parallel * per_seq ; 2515if (params_spec .backend_sampling ) { 2516result .n_outputs_max_per_seq = per_seq ; 2517 } 2518 } 2519 2520return result ; 2521} 2522 2523struct common_speculative_init_result::impl { 2524impl ()= default ; 2525 ~impl ()= default ; 2526 2527// note: the order in which model, context, etc. are declared matters because their destructors will be called bottom-to-top 2528llama_model_ptr model ; 2529llama_context_ptr context ; 2530}; 2531 2532common_speculative_init_result::common_speculative_init_result ( 2533common_params & params , 2534llama_model * model_tgt , 2535llama_context * ctx_tgt ) : 2536pimpl (new impl {}) { 2537const bool has_draft = params .speculative .has_dft (); 2538const bool spec_mtp = std::find (params .speculative .types .begin (), 2539params .speculative .types .end (), 2540COMMON_SPECULATIVE_TYPE_DRAFT_MTP )!= params .speculative .types .end (); 2541 2542auto mparams = common_model_params_to_llama (params ); 2543auto cparams = common_context_params_to_llama (params ); 2544 2545if (spec_mtp ) { 2546cparams .ctx_type = LLAMA_CONTEXT_TYPE_MTP ; 2547 } 2548 2549// the draft context holds as many tokens per sequence as the target context 2550cparams .n_ctx = llama_n_ctx (ctx_tgt ); 2551 2552// note: for small models maybe we can set this to the maximum possible draft from all speculative types 2553// the extra memory for small models is likely negligible? 2554cparams .n_rs_seq = 0 ; 2555cparams .ctx_other = ctx_tgt ; 2556 2557 std::string model_path ; 2558if (has_draft ) { 2559model_path = params .speculative .draft .mparams .path ; 2560LOG_INF ("%s: loading draft model '%s'\n" ,__func__ ,model_path .c_str ()); 2561 2562llama_model * model_dft = llama_model_load_from_file (params .model .path .c_str (),mparams ); 2563if (model_dft == NULL ) { 2564LOG_ERR ("%s: failed to load draft model, '%s'\n" ,__func__ ,model_path .c_str ()); 2565return ; 2566 } 2567 2568pimpl -> model .reset (model_dft ); 2569 2570llama_context * ctx_dft = llama_init_from_model (model_dft ,cparams ); 2571if (ctx_dft == nullptr ) { 2572LOG_ERR ("%s: failed to create MTP context\n" ,__func__ ); 2573return ; 2574 } 2575 2576pimpl -> context .reset (ctx_dft ); 2577 }else if (spec_mtp ) { 2578model_path = params .model .path ; 2579 2580LOG_INF ("%s: creating MTP draft context against the target model '%s'\n" ,__func__ ,model_path .c_str ()); 2581 2582llama_context * ctx_dft = llama_init_from_model (model_tgt ,cparams ); 2583if (ctx_dft == nullptr ) { 2584LOG_ERR ("%s: failed to create MTP context\n" ,__func__ ); 2585return ; 2586 } 2587 2588pimpl -> context .reset (ctx_dft ); 2589 } 2590} 2591 2592common_speculative_init_result::~common_speculative_init_result ()= default ; 2593 2594llama_model * common_speculative_init_result::model () { 2595return pimpl -> model .get (); 2596} 2597 2598llama_context * common_speculative_init_result::context () { 2599return pimpl -> context .get (); 2600} 2601 2602common_speculative_init_result_ptr common_speculative_init_from_params (common_params & params ,llama_model * model_tgt ,llama_context * ctx_tgt ) { 2603return std::make_unique < common_speculative_init_result > (params ,model_tgt ,ctx_tgt ); 2604} 2605 2606common_speculative_output_limits common_speculative_get_output_limits ( 2607int32_t n_batch ,int32_t n_parallel ,int32_t n_draft ) { 2608const int64_t per_seq = 1 + (int64_t ) std::max (0 ,n_draft ); 2609const int64_t total = (int64_t )n_parallel * per_seq ; 2610 2611return { 2612/* .total = */ (int32_t ) std::min < int64_t > (n_batch ,total ), 2613/* .per_seq = */ (int32_t ) std::min < int64_t > (n_batch ,per_seq ), 2614 }; 2615} 2616 2617// initialization of the speculative decoding system 2618// 2619common_speculative * common_speculative_init (common_params_speculative & params ,uint32_t n_seq ) { 2620// Compute the implementations to use based on the config and their order of preference 2621 std::vector < common_speculative_config > configs = {};// list of speculative configs to try 2622 { 2623uint32_t enabled_configs = common_get_enabled_speculative_configs (params .types ); 2624 2625auto add_config_if_enabled = [& ](common_speculative_type type ,bool available = true) { 2626if (available && (enabled_configs & (1u <<type ))) { 2627configs .emplace_back (type ,params ); 2628 } 2629 }; 2630 2631// when adding a new type - update here the logic above 2632 static_assert(COMMON_SPECULATIVE_TYPE_COUNT == 11 ); 2633 2634// this list here defines the priority of the speculators 2635// the one with highest priority are listed first 2636add_config_if_enabled (COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE ); 2637add_config_if_enabled (COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K ); 2638add_config_if_enabled (COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V ); 2639add_config_if_enabled (COMMON_SPECULATIVE_TYPE_NGRAM_MOD ); 2640add_config_if_enabled (COMMON_SPECULATIVE_TYPE_NGRAM_CACHE ); 2641 2642add_config_if_enabled (COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE ); 2643add_config_if_enabled (COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 ,params .draft .ctx_dft != nullptr ); 2644add_config_if_enabled (COMMON_SPECULATIVE_TYPE_DRAFT_MTP ,params .draft .ctx_dft != nullptr ); 2645add_config_if_enabled (COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH ,params .draft .ctx_dft != nullptr ); 2646add_config_if_enabled (COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK ,params .draft .ctx_dft != nullptr ); 2647 } 2648 2649 std::vector < std::unique_ptr < common_speculative_impl >> impls = {}; 2650 2651for (const common_speculative_config & config :configs ) { 2652switch (config .type ) { 2653case COMMON_SPECULATIVE_TYPE_NONE : 2654break ; 2655case COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE : { 2656impls .push_back (std::make_unique < common_speculative_impl_draft_simple > (config .params ,n_seq )); 2657break ; 2658 } 2659case COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 : { 2660impls .push_back (std::make_unique < common_speculative_impl_draft_eagle3 > (config .params ,n_seq )); 2661break ; 2662 } 2663case COMMON_SPECULATIVE_TYPE_DRAFT_MTP : { 2664impls .push_back (std::make_unique < common_speculative_impl_draft_mtp > (config .params ,n_seq )); 2665break ; 2666 } 2667case COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH : { 2668impls .push_back (std::make_unique < common_speculative_impl_draft_dflash > (config .params ,n_seq )); 2669break ; 2670 } 2671case COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK : { 2672impls .push_back (std::make_unique < common_speculative_impl_draft_dflash > ( 2673config .params ,n_seq ,COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK )); 2674break ; 2675 } 2676case COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE : { 2677common_ngram_map ngram_map = get_common_ngram_map (config .type ,config .params .ngram_simple ); 2678 2679uint16_t ngram_size_key = ngram_map .size_key ; 2680uint16_t mgram_size_value = ngram_map .size_value ; 2681 2682auto config_simple = common_ngram_simple_config { 2683/* .size_ngram = */ ngram_size_key , 2684/* .size_mgram = */ mgram_size_value 2685 }; 2686auto state = std::make_unique < common_speculative_impl_ngram_simple > ( 2687/* .params = */ config .params , 2688/* .n_seq = */ n_seq , 2689/* .state = */ config_simple 2690 ); 2691impls .push_back (std::move (state )); 2692break ; 2693 } 2694case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K : { 2695impls .push_back ( 2696 std::make_unique < common_speculative_impl_ngram_map_k > ( 2697get_common_ngram_map (config .type ,config .params .ngram_map_k ),n_seq )); 2698break ; 2699 } 2700case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V : { 2701impls .push_back ( 2702 std::make_unique < common_speculative_impl_ngram_map_k > ( 2703get_common_ngram_map (config .type ,config .params .ngram_map_k4v ),n_seq )); 2704break ; 2705 } 2706case COMMON_SPECULATIVE_TYPE_NGRAM_MOD : { 2707impls .push_back ( 2708 std::make_unique < common_speculative_impl_ngram_mod > (config .params ,n_seq )); 2709break ; 2710 } 2711case COMMON_SPECULATIVE_TYPE_NGRAM_CACHE : { 2712auto state = create_state_ngram_cache ( 2713config ,n_seq , 2714params .ngram_cache .lookup_cache_static , 2715params .ngram_cache .lookup_cache_dynamic ); 2716impls .push_back (std::make_unique < common_speculative_impl_ngram_cache > (state )); 2717break ; 2718 } 2719default : 2720break ; 2721 } 2722 } 2723 2724if (impls .empty ()) { 2725SPC_TRC ("%s" ,"no implementations specified for speculative decoding\n" ); 2726return nullptr ; 2727 } 2728 2729common_speculative_ptr result (new common_speculative { 2730/* .dparams = */ common_speculative_draft_params_vec (n_seq ), 2731/* .impls = */ std::move (impls ), 2732/* .impl_last = */ std::vector < common_speculative_impl *> (n_seq ,nullptr ), 2733/* .synth_probs = */ {}, 2734 }); 2735 2736const int32_t n_max_configured = common_speculative_n_max (& params ); 2737const int32_t n_max_effective = common_speculative_n_max (result .get ()); 2738const auto rates = common_speculative_synth_rates_resolve (& params ,n_max_effective ); 2739 2740 std::vector < std::string > rates_str ; 2741rates_str .reserve (rates .size ()); 2742result -> synth_probs .reserve (rates .size ()); 2743double rate_prev = 1.0 ; 2744double acceptance_length = 1.0 ; 2745for (const double rate :rates ) { 2746result -> synth_probs .push_back (rate_prev > 0.0 ?rate /rate_prev :0.0 ); 2747rates_str .push_back (string_format ("%.6g" ,rate )); 2748rate_prev = rate ; 2749acceptance_length += rate ; 2750 } 2751if (!result -> synth_probs .empty ()) { 2752SPC_WRN ("%s" ,"synthetic speculative acceptance is enabled for benchmarking; generated output is not valid\n" ); 2753if (n_max_effective != n_max_configured ) { 2754SPC_WRN ("synthetic acceptance draft limit was reduced from %d to %d by the initialized speculative implementations\n" , 2755n_max_configured ,n_max_effective ); 2756 } 2757SPC_INF ("synthetic acceptance: n_max = %zu, mean length = %.6f, rates = [%s]\n" , 2758rates .size (),acceptance_length ,string_join (rates_str ,", " ).c_str ()); 2759 } 2760 2761return result .release (); 2762} 2763 2764void common_speculative_free (common_speculative * spec ) { 2765if (spec == nullptr ) { 2766return ; 2767 } 2768 2769delete spec ; 2770} 2771 2772common_speculative_draft_params & common_speculative_get_draft_params ( 2773common_speculative * spec , 2774llama_seq_id seq_id ) { 2775GGML_ASSERT (spec ); 2776GGML_ASSERT (seq_id < (llama_seq_id )spec -> dparams .size ()); 2777 2778return spec -> dparams [seq_id ]; 2779} 2780 2781void common_speculative_begin (common_speculative * spec ,llama_seq_id seq_id ,const llama_tokens & prompt ) { 2782if (spec == nullptr ) { 2783return ; 2784 } 2785 2786for (auto & impl :spec -> impls ) { 2787common_time_meas tm (impl -> t_begin_us , !impl -> gen_perf ); 2788impl -> begin (seq_id ,prompt ); 2789impl -> n_call_begin ++ ; 2790 } 2791} 2792 2793bool common_speculative_process (common_speculative * spec ,const llama_batch & batch ) { 2794bool result = true; 2795 2796if (spec == nullptr ) { 2797return result ; 2798 } 2799 2800for (auto & impl :spec -> impls ) { 2801result = result && impl -> process (batch ); 2802 } 2803 2804return result ; 2805} 2806 2807void common_speculative_draft (common_speculative * spec ) { 2808if (spec == nullptr ) { 2809return ; 2810 } 2811 2812auto & dparams = spec -> dparams ; 2813 2814 { 2815int n_drafting = 0 ; 2816 2817for (auto & dp :dparams ) { 2818GGML_ASSERT (!dp .drafting || dp .result -> empty ()); 2819 2820if (dp .drafting ) { 2821n_drafting ++ ; 2822 } 2823 } 2824 2825if (n_drafting == 0 ) { 2826return ; 2827 } 2828 } 2829 2830for (auto & impl :spec -> impls ) { 2831 { 2832common_time_meas tm (impl -> t_draft_us , !impl -> gen_perf ); 2833impl -> draft (dparams ); 2834impl -> n_call_draft ++ ; 2835 } 2836 2837int n_drafting = 0 ; 2838 2839for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )dparams .size ();++ seq_id ) { 2840auto & dp = dparams [seq_id ]; 2841 2842if (!dp .drafting ) { 2843continue ; 2844 } 2845 2846auto & result = * dp .result ; 2847 2848// a new draft has been sampled 2849if (dp .drafting && !result .empty ()) { 2850dp .drafting = false; 2851 2852if (dp .n_max > 0 ) { 2853if (!result .empty ()&& (int )result .size ()> dp .n_max ) { 2854SPC_DBG ("truncating draft to %d tokens\n" ,dp .n_max ); 2855result .resize (dp .n_max ); 2856 } 2857 } 2858 2859if (!result .empty ()) { 2860SPC_DBG ("called impl %s, hist size = %zu, call_count = %zu, gen = %zu\n" , 2861common_speculative_type_to_str (impl .get ()-> type ).c_str (),dp .prompt -> size (), 2862impl .get ()-> n_call_draft ,result .size ()); 2863 2864// remember which implementation was used 2865spec -> impl_last [seq_id ]= impl .get (); 2866 2867impl -> n_gen_drafts ++ ; 2868impl -> n_gen_tokens += result .size (); 2869 } 2870 } 2871 2872if (dp .drafting ) { 2873n_drafting ++ ; 2874 } 2875 } 2876 2877if (n_drafting == 0 ) { 2878break ; 2879 } 2880 } 2881 2882// these sequences failed to generate a draft 2883for (llama_seq_id seq_id = 0 ;seq_id < (llama_seq_id )dparams .size ();++ seq_id ) { 2884auto & dp = dparams [seq_id ]; 2885 2886if (dp .drafting ) { 2887dp .drafting = false; 2888 } 2889 } 2890} 2891 2892void common_speculative_accept (common_speculative * spec ,llama_seq_id seq_id ,uint16_t n_accepted ) { 2893common_speculative_impl * impl = spec -> impl_last [seq_id ]; 2894 2895if (impl == nullptr ) { 2896GGML_ASSERT (n_accepted == 0 ); 2897return ; 2898 } 2899 2900 { 2901common_time_meas tm (impl -> t_accept_us , !impl -> gen_perf ); 2902 2903if (impl -> n_acc_tokens_per_pos .size ()< n_accepted ) { 2904impl -> n_acc_tokens_per_pos .resize (n_accepted ,0 ); 2905 } 2906 2907for (size_t i = 0 ;i < n_accepted ;++ i ) { 2908impl -> n_acc_tokens_per_pos [i ]++ ; 2909 } 2910 2911if (n_accepted > 0 ) { 2912impl -> n_acc_drafts ++ ; 2913impl -> n_acc_tokens += n_accepted ; 2914 } 2915 2916impl -> accept (seq_id ,n_accepted , false); 2917impl -> n_call_accept ++ ; 2918 } 2919 2920// accept with the rest of the implementations, using is_other == true 2921for (auto & impl_other :spec -> impls ) { 2922if (impl_other .get ()!= impl ) { 2923impl_other -> accept (seq_id ,n_accepted , true); 2924 } 2925 } 2926} 2927 2928// TODO: support the case of more than one speculative implementations having a state 2929bool common_speculative_get_state (common_speculative * spec ,llama_seq_id seq_id , std::vector < uint8_t > & data ) { 2930if (spec == nullptr ) { 2931return false; 2932 } 2933 2934for (auto & impl :spec -> impls ) { 2935if (impl -> get_state (seq_id ,data )) { 2936return true; 2937 } 2938 } 2939 2940return false; 2941} 2942 2943void common_speculative_set_state (common_speculative * spec ,llama_seq_id seq_id ,const std::vector < uint8_t > & data ) { 2944if (spec == nullptr ) { 2945return ; 2946 } 2947 2948for (auto & impl :spec -> impls ) { 2949impl -> set_state (seq_id ,data ); 2950 } 2951} 2952 2953void common_speculative_print_stats (const common_speculative * spec ) { 2954if (spec == nullptr ) { 2955return ; 2956 } 2957 2958for (const auto & impl :spec -> impls ) { 2959 std::string str_perf ; 2960if (impl -> gen_perf ) { 2961 std::ostringstream oss ; 2962oss << std::fixed << std::setprecision (3 ) <<impl -> t_begin_us /1000.0 <<", " ; 2963oss << std::fixed << std::setprecision (3 ) <<impl -> t_draft_us /1000.0 <<", " ; 2964oss << std::fixed << std::setprecision (3 ) <<impl -> t_accept_us /1000.0 ; 2965str_perf = ", dur(b,g,a) = " + oss .str ()+ " ms" ; 2966 }else { 2967str_perf = "" ; 2968 } 2969 2970 std::string str_stats ; 2971if (impl -> n_call_accept > 0 ) { 2972const double mean = 29731.0 + (double )impl -> n_acc_tokens / (double )impl -> n_call_accept ; 2974 std::ostringstream tmp ; 2975tmp << std::fixed << std::setprecision (3 ); 2976for (size_t i = 0 ;i < impl -> n_acc_tokens_per_pos .size ();++ i ) { 2977if (i > 0 ) { 2978tmp <<", " ; 2979 } 2980tmp << (double )impl -> n_acc_tokens_per_pos [i ] / (double )impl -> n_call_accept ; 2981 } 2982 std::ostringstream oss ; 2983oss << std::fixed << std::setprecision (2 ) <<mean ; 2984str_stats = ", #mean acc len = " + oss .str ()+ ", #acc rate/pos = (" + tmp .str ()+ ")" ; 2985 } 2986 2987SPC_TRC ("statistics %16s: #calls(b,g,a) = %4zu %6zu %6zu, #gen drafts = %6zu, #acc drafts = %5zu, #gen tokens = %6zu, #acc tokens = %5zu%s%s\n" , 2988common_speculative_type_to_str (impl -> type ).c_str (), 2989impl -> n_call_begin ,impl -> n_call_draft ,impl -> n_call_accept , 2990impl -> n_gen_drafts , 2991impl -> n_acc_drafts , 2992impl -> n_gen_tokens , 2993impl -> n_acc_tokens , 2994str_stats .c_str (), 2995str_perf .c_str ()); 2996 } 2997}