char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
230ea9d21
char/aliceai-t5-moe
1#include "llama-memory-hybrid.h" 2 3#include "llama-impl.h" 4#include "llama-model.h" 5#include "llama-context.h" 6 7// 8// llama_memory_hybrid 9// 10 11llama_memory_hybrid::llama_memory_hybrid ( 12const llama_model & model , 13/* attn */ 14ggml_type type_k , 15ggml_type type_v , 16bool v_trans , 17uint32_t kv_size , 18uint32_t n_pad , 19uint32_t n_swa , 20llama_swa_type swa_type , 21/* recurrent */ 22ggml_type type_r , 23ggml_type type_s , 24uint32_t rs_size , 25/* common */ 26uint32_t n_seq_max , 27uint32_t n_rs_seq , 28bool offload , 29bool unified , 30/* layer filters */ 31const layer_filter_cb & filter_attn , 32const layer_filter_cb & filter_recr ) : 33hparams (model .hparams ), 34mem_attn (new llama_kv_cache ( 35model , 36model .hparams , 37type_k , 38type_v , 39v_trans , 40offload , 41unified , 42kv_size , 43n_seq_max , 44n_pad , 45n_swa , 46swa_type , 47nullptr , 48filter_attn == nullptr ? 49 [& ](int32_t il ) {return !hparams .is_recr (il ); } 50 :filter_attn , 51nullptr , 52nullptr 53 )), 54mem_recr (new llama_memory_recurrent ( 55model , 56type_r , 57type_s , 58offload , 59rs_size , 60n_seq_max , 61n_rs_seq , 62filter_recr == nullptr ? 63 [& ](int32_t il ) {return hparams .is_recr (il ); } 64 :filter_recr 65 )) {} 66 67llama_memory_context_ptr llama_memory_hybrid::init_batch (llama_batch_allocr & balloc ,uint32_t n_ubatch ,bool embd_all ) { 68do { 69balloc .split_reset (); 70 71// follow the recurrent pattern for creating the ubatch splits 72 std::vector < llama_ubatch > ubatches ; 73 74while (true) { 75llama_ubatch ubatch ; 76 77if (embd_all ) { 78// if all tokens are output, split by sequence 79ubatch = balloc .split_seq (n_ubatch ); 80 }else { 81// Use non-sequential split when KV cache is unified (needed for hellaswag/winogrande/multiple-choice) 82const bool unified = (mem_attn -> get_n_stream ()== 1 ); 83 84// [TAG_RECURRENT_ROLLBACK_SPLITS] 85// the trailing (1 + n_rs_seq) tokens of each seq must stay in the same ubatch 86// so that the rollback snapshots remain valid 87const uint32_t n_rs_seq = mem_recr -> n_rs_seq ; 88 89ubatch = balloc .split_equal (n_ubatch , !unified ,n_rs_seq > 0 ?n_rs_seq + 1 :0 ); 90 } 91 92if (ubatch .n_tokens == 0 ) { 93break ; 94 } 95 96ubatches .push_back (std::move (ubatch ));// NOLINT 97 } 98 99if (balloc .get_n_used ()< balloc .get_n_tokens ()) { 100// failed to find a suitable split 101break ; 102 } 103 104// prepare the recurrent batches first 105if (!mem_recr -> prepare (ubatches )) { 106// TODO: will the recurrent cache be in an undefined context at this point? 107LLAMA_LOG_ERROR ("%s: failed to prepare recurrent ubatches\n" ,__func__ ); 108return std::make_unique < llama_memory_hybrid_context > (LLAMA_MEMORY_STATUS_FAILED_PREPARE ); 109 } 110 111// prepare the attention cache 112auto heads_attn = mem_attn -> prepare (ubatches ); 113if (heads_attn .empty ()) { 114LLAMA_LOG_ERROR ("%s: failed to prepare attention ubatches\n" ,__func__ ); 115return std::make_unique < llama_memory_hybrid_context > (LLAMA_MEMORY_STATUS_FAILED_PREPARE ); 116 } 117 118return std::make_unique < llama_memory_hybrid_context > ( 119this , std::move (heads_attn ), std::move (ubatches )); 120 }while (false); 121 122return std::make_unique < llama_memory_hybrid_context > (LLAMA_MEMORY_STATUS_FAILED_PREPARE ); 123} 124 125llama_memory_context_ptr llama_memory_hybrid::init_full () { 126return std::make_unique < llama_memory_hybrid_context > (this ); 127} 128 129llama_memory_context_ptr llama_memory_hybrid::init_update (llama_context * lctx ,bool optimize ) { 130return std::make_unique < llama_memory_hybrid_context > (this ,lctx ,optimize ); 131} 132 133bool llama_memory_hybrid::get_can_shift ()const { 134// Shifting is trivially supported for recurrent 135return mem_attn -> get_can_shift (); 136} 137 138void llama_memory_hybrid::clear (bool data ) { 139mem_attn -> clear (data ); 140mem_recr -> clear (data ); 141} 142 143bool llama_memory_hybrid::seq_rm (llama_seq_id seq_id ,llama_pos p0 ,llama_pos p1 ) { 144// Try removing from the recurrent cache first since it may fail. If it does 145// fail, the cache will not have been mutated. 146if (!mem_recr -> seq_rm (seq_id ,p0 ,p1 )) { 147return false; 148 } 149return mem_attn -> seq_rm (seq_id ,p0 ,p1 ); 150} 151 152void llama_memory_hybrid::seq_cp (llama_seq_id seq_id_src ,llama_seq_id seq_id_dst ,llama_pos p0 ,llama_pos p1 ) { 153mem_attn -> seq_cp (seq_id_src ,seq_id_dst ,p0 ,p1 ); 154mem_recr -> seq_cp (seq_id_src ,seq_id_dst ,p0 ,p1 ); 155} 156 157void llama_memory_hybrid::seq_keep (llama_seq_id seq_id ) { 158mem_attn -> seq_keep (seq_id ); 159mem_recr -> seq_keep (seq_id ); 160} 161 162void llama_memory_hybrid::seq_add (llama_seq_id seq_id ,llama_pos p0 ,llama_pos p1 ,llama_pos shift ) { 163mem_attn -> seq_add (seq_id ,p0 ,p1 ,shift ); 164mem_recr -> seq_add (seq_id ,p0 ,p1 ,shift ); 165} 166 167void llama_memory_hybrid::seq_div (llama_seq_id seq_id ,llama_pos p0 ,llama_pos p1 ,int d ) { 168mem_attn -> seq_div (seq_id ,p0 ,p1 ,d ); 169mem_recr -> seq_div (seq_id ,p0 ,p1 ,d ); 170} 171 172llama_pos llama_memory_hybrid::seq_pos_min (llama_seq_id seq_id )const { 173// the min of the total cache is the max of the two caches' min values 174return std::max (mem_attn -> seq_pos_min (seq_id ),mem_recr -> seq_pos_min (seq_id )); 175} 176 177llama_pos llama_memory_hybrid::seq_pos_max (llama_seq_id seq_id )const { 178// the max of the total cache is the min of the two caches' max values 179return std::min (mem_attn -> seq_pos_max (seq_id ),mem_recr -> seq_pos_max (seq_id )); 180} 181 182std::map < ggml_backend_buffer_type_t ,size_t > llama_memory_hybrid::memory_breakdown ()const { 183 std::map < ggml_backend_buffer_type_t ,size_t > mb = mem_attn -> memory_breakdown (); 184for (const auto & buft_size :mem_recr -> memory_breakdown ()) { 185mb [buft_size .first ]+= buft_size .second ; 186 } 187return mb ; 188} 189 190void llama_memory_hybrid::state_write (llama_io_write_i & io ,llama_seq_id seq_id ,llama_state_seq_flags flags )const { 191if ((flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY )== 0 ) { 192mem_attn -> state_write (io ,seq_id ,flags ); 193 } 194mem_recr -> state_write (io ,seq_id ,flags ); 195} 196 197void llama_memory_hybrid::state_read (llama_io_read_i & io ,llama_seq_id seq_id ,llama_state_seq_flags flags ) { 198if ((flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY )== 0 ) { 199mem_attn -> state_read (io ,seq_id ,flags ); 200 } 201mem_recr -> state_read (io ,seq_id ,flags ); 202} 203 204llama_kv_cache * llama_memory_hybrid::get_mem_attn ()const { 205return mem_attn .get (); 206} 207 208llama_memory_recurrent * llama_memory_hybrid::get_mem_recr ()const { 209return mem_recr .get (); 210} 211 212llama_memory_hybrid_context::llama_memory_hybrid_context (llama_memory_status status ) :status (status ) {} 213 214llama_memory_hybrid_context::llama_memory_hybrid_context (llama_memory_hybrid * mem ) : 215ctx_attn (mem -> get_mem_attn ()-> init_full ()), 216ctx_recr (mem -> get_mem_recr ()-> init_full ()), 217status (llama_memory_status_combine (ctx_attn -> get_status (),ctx_recr -> get_status ())) { 218} 219 220llama_memory_hybrid_context::llama_memory_hybrid_context ( 221llama_memory_hybrid * mem , 222llama_context * lctx , 223bool optimize ) : 224ctx_attn (mem -> get_mem_attn ()-> init_update (lctx ,optimize )), 225ctx_recr (mem -> get_mem_recr ()-> init_update (lctx ,optimize )), 226status (llama_memory_status_combine (ctx_attn -> get_status (),ctx_recr -> get_status ())) { 227} 228 229llama_memory_hybrid_context::llama_memory_hybrid_context ( 230llama_memory_hybrid * mem , 231slot_info_vec_t sinfos_attn , 232 std::vector < llama_ubatch > ubatches ) : 233ubatches (std::move (ubatches )), 234// note: here we copy the ubatches. not sure if this is ideal 235ctx_attn (new llama_kv_cache_context (mem -> get_mem_attn (), std::move (sinfos_attn ),this -> ubatches )), 236ctx_recr (new llama_memory_recurrent_context (mem -> get_mem_recr (),this -> ubatches )), 237status (llama_memory_status_combine (ctx_attn -> get_status (),ctx_recr -> get_status ())) { 238} 239 240bool llama_memory_hybrid_context::next () { 241assert (status == LLAMA_MEMORY_STATUS_SUCCESS ); 242 243ctx_attn -> next (); 244ctx_recr -> next (); 245 246if (++ i_next >=ubatches .size ()) { 247return false; 248 } 249 250return true; 251} 252 253bool llama_memory_hybrid_context::apply () { 254assert (!llama_memory_status_is_fail (status )); 255 256bool res = true; 257 258res = res & ctx_attn -> apply (); 259res = res & ctx_recr -> apply (); 260 261return res ; 262} 263 264llama_memory_status llama_memory_hybrid_context::get_status ()const { 265return status ; 266} 267 268const llama_ubatch & llama_memory_hybrid_context::get_ubatch ()const { 269assert (status == LLAMA_MEMORY_STATUS_SUCCESS ); 270return ubatches [i_next ]; 271} 272 273const llama_kv_cache_context * llama_memory_hybrid_context::get_attn ()const { 274return static_cast < const llama_kv_cache_context *> (ctx_attn .get ()); 275} 276 277const llama_memory_recurrent_context * llama_memory_hybrid_context::get_recr ()const { 278return static_cast < const llama_memory_recurrent_context *> (ctx_recr .get ()); 279}