char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
defa95c30
char/aliceai-t5-moe
1#include "common.h" 2#include "log.h" 3#include "ngram-map.h" 4 5#include <cinttypes> 6#include <cstdint> 7#include <cstdio> 8#include <sstream> 9 10// prime number used for LCG hash function (32 bit), it is near (sqrt(5) - 1)/2 * 2^32. 11#define LCG_FACTOR 2654435761UL 12 13// Compute the LCG hash of a n-gram of size len at offset start. 14static uint32_t common_ngram_map_hash (const llama_tokens & tokens ,size_t start ,size_t len ) { 15uint32_t hash = 0 ; 16for (size_t i = 0 ;i < len ;++ i ) { 17hash = hash * LCG_FACTOR + tokens [start + i ]; 18 } 19return hash ; 20} 21 22// Print the values of a sublist of `llama_tokens & inp` to a string in the form [v0, v1, v2, ...]. 23static std::string common_tokens_to_str (const llama_tokens & inp ,size_t start ,size_t length ) { 24 std::ostringstream oss ; 25oss <<'[' ; 26for (size_t i = 0 ;i < length ;++ i ) { 27if (i > 0 ) { 28oss <<", " ; 29 } 30oss <<inp [start + i ]; 31 } 32oss <<']' ; 33return oss .str (); 34} 35 36 37// n-gram simple 38// 39 40/** 41* Perform speculative generation using the model's own token history. 42* Searches for a matching pattern in the token history and returns draft tokens. 43* 44* @param state Current state of this implementation 45* @param tokens Token history to search in 46* @param sampled Last sampled token 47* @return Vector of draft tokens, empty if no matching pattern is found 48*/ 49llama_tokens common_ngram_simple_draft ( 50const common_ngram_simple_config & config , 51const llama_tokens & tokens ,llama_token sampled ) { 52 53// Simple implementation of self-speculative decoding without a draft model. 54// 55const size_t cur_len = tokens .size (); 56 57const size_t n_draft_min = config .size_ngram ;// size of n-gram to lookup in token history 58const size_t n_draft_max = config .size_mgram ;// the m-gram following the found n-gram is used for draft 59 60// vector for tokens we want to verify. 61// return empty vector if there is no match. 62llama_tokens draft_tokens ; 63 64// We need at least n_draft_min + n_draft_max + 1 tokens. 65if (cur_len <=static_cast < size_t > (n_draft_min + n_draft_max + 1 )) { 66return draft_tokens ; 67 } 68 69// pattern search 70llama_tokens pattern ; 71pattern .reserve (n_draft_min ); 72for (size_t j = cur_len - n_draft_min + 1 ;j < cur_len ;++ j ) { 73pattern .push_back (tokens [j ]); 74 } 75pattern .push_back (sampled );// add the last token to the pattern 76 77size_t match_pos = 0 ;// we ignore position 0, position 0 == no match 78// search backwards, but skip the current match (we are currently there) 79for (size_t j = cur_len - n_draft_min - 1 ;j > 0 ;-- j ) { 80bool match = true; 81for (size_t k = 0 ;k < pattern .size ();++ k ) { 82if (tokens [j + k ]!= pattern [k ]) { 83match = false; 84break ; 85 } 86 } 87if (match ) { 88match_pos = j ; 89break ; 90 } 91 } 92if (match_pos == 0 ) { 93return draft_tokens ; 94 } 95 96const size_t copy_max = std::min ( 97n_draft_max , 98cur_len - (match_pos + n_draft_min ) 99 ); 100if (copy_max < n_draft_min ) { 101return draft_tokens ; 102 } 103LOG_DBG ("%s: #tokens = %zu: found matching pattern at pos %zu, length %zu, draft length %zu\n" , 104__func__ ,cur_len , 105match_pos ,pattern .size (),copy_max ); 106 107draft_tokens .reserve (copy_max ); 108for (size_t j = 0 ;j < copy_max ;++ j ) { 109draft_tokens .push_back (tokens [match_pos + n_draft_min + j ]); 110 } 111return draft_tokens ; 112} 113 114 115// n-gram map 116// 117 118// maximum number of counted values of a ngram map value. 119#define COMMON_NGRAM_MAX_VALUE_COUNT 16380 120 121void common_ngram_map_begin ( 122common_ngram_map & map ,const llama_tokens & tokens ) { 123size_t size_begin = tokens .size (); 124 125LOG_DBG ("%s: begin, idx_last_draft=%zu, new begin=%zu, #keys=%zu\n" ,__func__ , 126map .idx_last_check ,size_begin ,map .keys .size ()); 127 128size_t idx_begin_cleanup = map .size_last_begin ; 129if (idx_begin_cleanup > size_begin ) { 130if (size_begin > (size_t )map .size_key + map .size_value ) { 131idx_begin_cleanup = size_begin - map .size_key - map .size_value ; 132 }else { 133idx_begin_cleanup = 0 ; 134 } 135LOG_INF ("%s: shrink cleanup begin: %zu -> %zu\n" ,__func__ ,map .size_last_begin ,idx_begin_cleanup ); 136 } 137 138size_t count_map_entries_upd = 0 ; 139if (!map .key_map .empty ()&& size_begin < map .idx_last_check ) { 140if (map .show_key_map_stats ) { 141// Print statistics of hash map map_key. 142size_t count_nonzero = 0 ; 143uint32_t min_idx = UINT32_MAX ; 144uint32_t max_idx = 0 ; 145for (size_t i = 0 ;i < map .key_map .size ();++ i ) { 146uint32_t key_idx = map .key_map [i ]; 147if (key_idx != 0 ) { 148++ count_nonzero ; 149if (key_idx < min_idx )min_idx = key_idx ; 150if (key_idx > max_idx )max_idx = key_idx ; 151 } 152 } 153if (count_nonzero == 0 ) { 154min_idx = 0 ; 155 } 156LOG_INF ("%s: key_map stats: entries=%zu, min_idx=%u, max_idx=%u, key_map_last_idx=%u\n" , 157__func__ ,count_nonzero ,min_idx ,max_idx ,map .key_map_last_idx ); 158 } 159 160// Update the map from hash to key index (clear outdated entries). 161for (size_t i = 0 ;i < map .key_map .size ();++ i ) { 162uint32_t key_idx = map .key_map [i ]; 163if (key_idx != 0 && key_idx >=idx_begin_cleanup ) { 164map .key_map [i ]= 0 ; 165count_map_entries_upd ++ ; 166 } 167 } 168map .key_map_last_idx = (idx_begin_cleanup > 0 ) ? (uint32_t ) (idx_begin_cleanup - 1 ) :0 ; 169 } 170 171if (size_begin < map .idx_last_check && !map .keys .empty ()) { 172size_t count_keys = map .keys .size (); 173size_t count_keys_del = 0 ; 174size_t count_values_del = 0 ; 175for (int32_t i = map .keys .size ()- 1 ;i >=0 ;-- i ) { 176common_ngram_map_key & key = map .keys [i ]; 177if (key .key_idx >=idx_begin_cleanup ) { 178// Delete the key. 179LOG_DBG ("%s: delete key %d at index %zu (>= idx_begin_cleanup=%zu)\n" ,__func__ ,i ,key .key_idx ,idx_begin_cleanup ); 180map .keys .erase (map .keys .begin ()+ i ); 181count_keys_del ++ ; 182continue ; 183 } 184if (map .key_only ) { 185continue ; 186 } 187 188// Check the indices of the values. 189for (int16_t j = COMMON_NGRAM_MAX_VALUES - 1 ;j >=0 ;-- j ) { 190common_ngram_map_value & value = key .values [j ]; 191if (value .value_idx != 0 && value .value_idx >=idx_begin_cleanup ) { 192// Delete the value. 193count_values_del ++ ; 194 195// Move all values after this value to the left. 196for (uint16_t k = j ;k < COMMON_NGRAM_MAX_VALUES - 1 ;++ k ) { 197key .values [k ]= key .values [k + 1 ]; 198 } 199// Clear the last value. 200key .values [COMMON_NGRAM_MAX_VALUES - 1 ].value_idx = 0 ; 201key .values [COMMON_NGRAM_MAX_VALUES - 1 ].value_num = 0 ; 202 } 203 } 204if (key .values [0 ].value_idx == 0 ) { 205// No values left, delete the key. 206LOG_DBG ("%s: delete key %d at index %zu (no values left)\n" ,__func__ ,i ,key .key_idx ); 207map .keys .erase (map .keys .begin ()+ i ); 208count_keys_del ++ ; 209 } 210 } 211 212LOG_INF ("%s: refresh map: idx_last_draft=%zu, new begin=%zu, #keys_checked=%zu, #keys_del=%zu, #values_del=%zu, #hashes_upd=%zu\n" ,__func__ , 213map .idx_last_check ,size_begin , 214count_keys ,count_keys_del ,count_values_del ,count_map_entries_upd ); 215 } 216 217map .idx_last_check = size_begin ; 218map .size_last_begin = size_begin ; 219} 220 221void common_ngram_map_draft (common_ngram_map & map , 222const llama_tokens & inp ,llama_token sampled , 223llama_tokens & draft ) { 224// reset last key and value. 225map .last_draft_created = false; 226map .last_draft_key_idx = 0 ; 227map .last_draft_value_idx = 0 ; 228 229const size_t cur_len = inp .size (); 230const uint16_t n = map .size_key ; 231const uint16_t m = map .size_value ; 232if (cur_len < static_cast < size_t > (2 * n + m )) { 233return ; 234 } 235if (cur_len >=static_cast < size_t > (UINT32_MAX )) { 236// key_map uses uint32_t instead of size_t. 237GGML_ABORT ("%s: cur_len exceeds UINT32_MAX: %zu" ,__func__ ,cur_len ); 238 } 239 240if (map .idx_last_check > cur_len ) { 241// Should not happen because of common_ngram_map_begin(). 242GGML_ABORT ("%s: map.idx_last_check > cur_len: %zu > %zu" ,__func__ ,map .idx_last_check ,cur_len ); 243 } 244map .idx_last_check = cur_len ; 245 246// search pattern, the key n-gram 247 std::vector < llama_token > key_tokens ; 248key_tokens .reserve (n ); 249for (size_t j = cur_len - n + 1 ;j < cur_len ;++ j ) { 250key_tokens .push_back (inp [j ]); 251 } 252key_tokens .push_back (sampled ); 253 254// search for the key in the map 255size_t match_pos = 0 ; 256if (map .size_last_begin > cur_len ) { 257GGML_ABORT ("%s: map.size_last_begin > cur_len: %zu > %zu" ,__func__ ,map .size_last_begin ,cur_len ); 258 } 259if (!map .key_map .empty ()) { 260// Search for the key in the map key_map from hash of ngrams to index of ngram. 261uint32_t idx_hash = (common_ngram_map_hash (key_tokens ,0 ,n ) %map .key_map .size ()); 262uint32_t idx_key = map .key_map [idx_hash ]; 263if (idx_key != 0 && idx_key < cur_len - n - m - 1 ) { 264// Check if the key matches the key at idx_key (because of possible collisions). 265bool match = true; 266for (size_t k = 0 ;k < n ;++ k ) { 267if (inp [idx_key + k ]!= key_tokens [k ]) { 268match = false; 269break ; 270 } 271 } 272LOG_DBG ("%s: key hash %x -> idx_key %d: match %d\n" ,__func__ ,idx_hash ,idx_key ,match ?1 :0 ); 273if (match ) { 274match_pos = idx_key ; 275 } 276 } 277 } 278if (match_pos == 0 && map .size_last_begin > (size_t ) (n + m + 1 )) { 279// Search for the key in [1, map.size_last_begin - n - m -1], descending. 280for (size_t j = map .size_last_begin - n - m - 1 ;j > map .key_map_last_idx ;-- j ) { 281// Check if the key matches the key. 282bool match = true; 283for (size_t k = 0 ;k < n ;++ k ) { 284if (inp [j + k ]!= key_tokens [k ]) { 285match = false; 286break ; 287 } 288 } 289if (match ) { 290match_pos = j ; 291break ; 292 } 293 } 294 } 295if (match_pos == 0 ) { 296// In case of a reasoning chat, the part after size_last_begin may be deleted/reordered later. 297// 298// Search in [size_last_begin, cur_len - n - m - 1], descending. 299for (size_t j = cur_len - n - m - 1 ;j > map .size_last_begin && j > map .key_map_last_idx ;-- j ) { 300bool match = true; 301for (size_t k = 0 ;k < n ;++ k ) { 302if (inp [j + k ]!= key_tokens [k ]) { 303match = false; 304break ; 305 } 306 } 307if (match ) { 308match_pos = j ; 309break ; 310 } 311 } 312 } 313if (match_pos > 0 ) { 314LOG_DBG ("%s: cur_len = %zu, n = %d, m = %d, sz_tkns = %zu, sampled = %d, match_pos = %zu\n" ,__func__ , 315cur_len ,n ,m ,key_tokens .size (),sampled ,match_pos ); 316 } 317 318if (!map .key_map .empty ()) { 319// Add hashes of new ngrams in key_map. 320// 321// Use the same order as above. 322if (map .size_last_begin > (size_t ) (n + m + 1 )) { 323for (size_t j = map .size_last_begin - n - m - 1 ;j > map .key_map_last_idx ;-- j ) { 324// compute hash and store index of ngram at idx j in the map. 325uint32_t idx_hash = (common_ngram_map_hash (inp ,j ,n ) %map .key_map .size ()); 326if (map .key_map [idx_hash ]== 0 ) { 327map .key_map [idx_hash ]= j ;// collisions may occur 328 } 329 } 330 } 331 332for (size_t j = cur_len - n - m - 1 ;j > map .size_last_begin && j > map .key_map_last_idx ;-- j ) { 333// compute hash and store index of ngram at idx j in the map. 334uint32_t idx_hash = (common_ngram_map_hash (inp ,j ,n ) %map .key_map .size ()); 335if (map .key_map [idx_hash ]== 0 ) { 336map .key_map [idx_hash ]= j ; 337 } 338 } 339map .key_map_last_idx = std::max (static_cast < uint32_t > (cur_len - n - m - 1 ),map .key_map_last_idx ); 340 } 341 342if (match_pos == 0 ) { 343return ; 344 } 345 346// We have a match, now we look for the statistics of the key. 347size_t key_offset = map .keys .size ();// offset in the map 348// We iterate through the std::vector<common_ngram_map_key> map->keys. 349for (size_t i = 0 ;i < map .keys .size ();++ i ) { 350bool match = true; 351for (size_t j = 0 ;j < n ;++ j ) { 352if (inp [map .keys [i ].key_idx + j ]!= key_tokens [j ]) { 353match = false; 354break ; 355 } 356 } 357if (match ) { 358key_offset = i ; 359break ; 360 } 361 } 362if (key_offset == map .keys .size ()) { 363// We create a new key-entry, it will get offset key_offset. 364common_ngram_map_key new_key ; 365new_key .key_idx = match_pos ; 366new_key .stat_idx = 0 ; 367new_key .key_num = 0 ; 368for (int i = 0 ;i < COMMON_NGRAM_MAX_VALUES ;++ i ) { 369new_key .values [i ].value_num = 0 ; 370new_key .values [i ].n_accepted = m ; 371 } 372map .keys .push_back (new_key ); 373 } 374 375// our key n-gram: 376common_ngram_map_key & curr_key = map .keys [key_offset ]; 377 378// update number of key hits 379curr_key .key_num = (uint16_t ) std::min ((int )map .keys [key_offset ].key_num + 1 , 380 (int )COMMON_NGRAM_MAX_VALUE_COUNT ); 381 382if (map .key_only ) { 383// simple mode: 384// Fill in the draft with the m tokens following the key. 385// We work with value values[0] only. 386int n_draft_tokens = std::min ((int )m , (int )curr_key .values [0 ].n_accepted ); 387 388for (int i = 0 ;i < n_draft_tokens ;++ i ) { 389draft .push_back (inp [match_pos + n + i ]); 390 } 391 392LOG_DBG ("%s: key_idx = %zu, key_offset = %zu, key_num = %d, draft.size = %zu\n" ,__func__ , 393curr_key .key_idx ,key_offset ,curr_key .key_num ,draft .size ()); 394 395map .last_draft_created = true; 396map .last_draft_key_idx = key_offset ; 397map .last_draft_value_idx = 0 ;// value 0 is used for simple mode 398return ; 399 } 400 401if (curr_key .key_num < map .min_hits ) { 402// not enough hits to consider this a good draft 403LOG_DBG ("%s: key_offset = %zu, key_num = %d, min_hits = %d, no draft\n" ,__func__ , 404key_offset ,curr_key .key_num ,map .min_hits ); 405return ; 406 } 407 408// complex mode: examine the different m-grams after this key n-gram. 409// 410 411// determine all (max COMMON_NGRAM_MAX_VALUES) m-grams after the key n-gram. 412for (size_t i = curr_key .stat_idx ;i <=match_pos ;++ i ) { 413// begins the key n-gram at index i? 414bool match_key = true; 415for (size_t k = 0 ;k < n ;++ k ) { 416if (inp [i + k ]!= key_tokens [k ]) { 417match_key = false; 418break ; 419 } 420 } 421if (!match_key ) { 422continue ; 423 } 424 425// Do we haven a existing value m-gram or a new one after the key at index i? 426size_t idx_begin_value_key = i + n ; 427int idx_value = -1 ; 428for (int v = 0 ;v < COMMON_NGRAM_MAX_VALUES ;++ v ) { 429size_t idx_begin_value_v = curr_key .values [v ].value_idx ; 430if (idx_begin_value_v == 0 ) { 431// We found an empty value slot => we found a new value m-gram after the key n-gram. 432curr_key .values [v ].value_idx = idx_begin_value_key ; 433curr_key .values [v ].value_num = 0 ; 434curr_key .values [v ].n_accepted = m ; 435idx_value = v ; 436break ; 437 } 438bool match = true; 439for (size_t j = 0 ;j < m ;++ j ) { 440if (inp [idx_begin_value_key + j ]!= inp [idx_begin_value_v + j ]) { 441match = false; 442break ; 443 } 444 } 445if (match ) { 446// We found an existing value m-gram after the key n-gram. 447idx_value = v ; 448break ; 449 } 450 } 451if (idx_value >=0 ) { 452// We found a value m-gram of the key n-gram. 453curr_key .values [idx_value ].value_num = (uint16_t ) std::min ((int )curr_key .values [idx_value ].value_num + 1 , 454 (int )COMMON_NGRAM_MAX_VALUE_COUNT ); 455 } 456 } 457// the statistics are updated up to match_pos. 458curr_key .stat_idx = match_pos ; 459 460// Do we have a value we could use for the draft? 461uint16_t max_occur = 0 ; 462int slot_max = 0 ; 463for (int v = 0 ;v < COMMON_NGRAM_MAX_VALUES ;++ v ) { 464uint16_t curr_occur = curr_key .values [v ].value_num ; 465if (curr_occur > max_occur ) { 466max_occur = curr_occur ; 467slot_max = v ; 468 } 469 } 470// What is sum of the other occurrences? 471uint32_t sum_occur = 0 ; 472for (int v = 0 ;v < COMMON_NGRAM_MAX_VALUES ;++ v ) { 473if (v == slot_max ) { 474continue ; 475 } 476uint16_t curr_occur = curr_key .values [v ].value_num ; 477sum_occur += curr_occur ; 478 } 479 480LOG_DBG ("%s: key_offset = %zu, max_occur = %d, sum_occur = %d, slot_max = %d [%zu/%d, %zu/%d, %zu/%d, %zu/%d]\n" ,__func__ , 481key_offset , 482max_occur ,sum_occur ,slot_max , 483curr_key .values [0 ].value_idx ,curr_key .values [0 ].value_num , 484curr_key .values [1 ].value_idx ,curr_key .values [1 ].value_num , 485curr_key .values [2 ].value_idx ,curr_key .values [2 ].value_num , 486curr_key .values [3 ].value_idx ,curr_key .values [3 ].value_num 487 ); 488// Print the tokens of the four values (if idx != 0), use LOG_INF 489for (int v = 0 ;v < COMMON_NGRAM_MAX_VALUES ;++ v ) { 490if (curr_key .values [v ].value_idx != 0 ) { 491LOG_DBG ("%s: value[%d] = %s\n" ,__func__ ,v ,common_tokens_to_str (inp ,curr_key .values [v ].value_idx ,m ).c_str ()); 492 } 493 } 494 495if (sum_occur > 0 && max_occur < 2 * sum_occur ) { 496// The most frequent value is not much more frequent than the other values. 497// We do not use the draft. 498return ; 499 } 500 501// We use the most frequent value values[slot_max] for the draft. 502// Fill in the draft with the m tokens following the key. 503int n_draft_tokens = std::min ((int )m , (int )curr_key .values [slot_max ].n_accepted ); 504 505for (int i = 0 ;i < n_draft_tokens ;++ i ) { 506draft .push_back (inp [match_pos + n + i ]); 507 } 508 509LOG_DBG ("%s: key_offset = %zu, slot_max = %d, key_num = %d, draft.size = %zu\n" ,__func__ , 510key_offset ,slot_max , 511curr_key .key_num ,draft .size ()); 512 513map .last_draft_created = true; 514map .last_draft_key_idx = key_offset ; 515map .last_draft_value_idx = slot_max ;// value used for draft generation. 516} 517 518void common_ngram_map_accept (common_ngram_map & map ,uint16_t n_accepted ) { 519if (!map .last_draft_created ) { 520return ; 521 } 522 523// find the key and its chosen value. 524const size_t key_idx = map .last_draft_key_idx ; 525const size_t val_idx = map .last_draft_value_idx ; 526 527// find key corresponding to key_idx. 528common_ngram_map_key & curr_key = map .keys [key_idx ]; 529// find value corresponding to val_idx. 530struct common_ngram_map_value & curr_value = curr_key .values [val_idx ];// value used for draft generation. 531 532// update the value statistics 533LOG_DBG ("common_ngram_map_send_accepted: n_accepted = %d, prev value_num = %d\n" , 534n_accepted ,curr_value .n_accepted ); 535curr_value .n_accepted = n_accepted ; 536}