ember.cpp 0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
TinyLlamaModel Class Reference

Main transformer model class for TinyLlama. More...

#include <model.h>

Collaboration diagram for TinyLlamaModel:
Collaboration graph

Public Member Functions

 TinyLlamaModel (const ModelConfig &config, const SafeTensorsLoader &loader)
 Construct a TinyLlamaModel from a SafeTensorsLoader.
 
 TinyLlamaModel (const ModelConfig &initial_config, const std::string &model_path)
 Construct a TinyLlamaModel from a model path (GGUF or SafeTensors).
 
 TinyLlamaModel (const ModelConfig &config_from_session, std::unique_ptr< GGUFData > gguf_data_from_session)
 Construct a TinyLlamaModel from pre-loaded GGUFData.
 
 ~TinyLlamaModel ()
 Destructor. Cleans up all allocated resources.
 
std::vector< float > forward (std::vector< float > &input, int n_tokens, KVCache *kv_cache, const std::vector< int > *attention_mask)
 Run the forward pass for the model on CPU layers.
 
void ensure_q_proj_dequantized (int layer_idx)
 
void ensure_k_proj_dequantized (int layer_idx)
 
void ensure_v_proj_dequantized (int layer_idx)
 
void ensure_o_proj_dequantized (int layer_idx)
 
void ensure_gate_proj_dequantized (int layer_idx)
 
void ensure_up_proj_dequantized (int layer_idx)
 
void ensure_down_proj_dequantized (int layer_idx)
 
void ensure_lm_head_dequantized ()
 
void ensure_embed_tokens_dequantized ()
 
void ensure_f32_concatenated_weights_loaded ()
 
void ensure_layer_weights_on_gpu (int layer_idx)
 
void free_layer_gpu_weights (int layer_idx)
 
void clear_layer_dequantized_weights (int layer_idx)
 
void initialize_gpu_and_rope ()
 
void ensure_bf16_concatenated_weights_loaded ()
 
void free_bf16_concatenated_weights ()
 
void set_gemm_fp32_only (bool on)
 
bool gemm_fp32_only () const
 
const ModelConfig & get_config () const
 
bool dequantize_all_if_small (size_t max_params)
 
const std::vector< uint16_t > & get_lm_head () const
 
const std::vector< uint16_t > & get_embed_tokens () const
 
std::vector< LayerWeights > & get_layers ()
 
std::vector< float > lookup_embedding (int token_id)
 Lookup the embedding vector for a given token ID.
 
bool ir_only () const
 
int get_vocab_size () const
 Get the vocabulary size for the model.
 
const GGUFData * get_gguf_data () const
 
GGUFData * get_gguf_data_ptr ()
 
void initialize_rope_freqs ()
 
std::vector< float > forward_cpu_batch (const std::vector< float > &batch_input_activations, int num_tokens_in_batch, int num_cpu_layers_to_process, int start_pos_in_sequence, KVCache *kv_cache, const std::vector< int > &prompt_lengths={})
 
std::vector< float > forward_cpu_logits_batch (const std::vector< float > &final_batch_activations, int num_tokens_in_batch)
 
std::vector< std::vector< float > > forward_cpu_batch_generation (const std::vector< float > &batch_input_activations, const std::vector< int > &token_positions, const std::vector< int > &original_sequence_indices, int num_tokens_in_batch, KVCache *kv_cache)
 

Private Member Functions

void initialize_weights (const SafeTensorsLoader *loader, const GGUFData *gguf)
 

Private Attributes

ModelConfig config_
 
bool use_bf16_tensor_cores_ = false
 
bool bf16_batch_gemm_failed_ = false
 
bool gemm_fp32_only_ = false
 
std::vector< uint16_t > embed_tokens
 
std::vector< uint16_t > lm_head
 
std::vector< uint16_t > final_norm
 
std::vector< float > embed_tokens_f32
 
std::vector< float > lm_head_f32
 
std::vector< float > final_norm_f32
 
std::vector< block_q4_K > embed_tokens_q4k
 
std::vector< block_q4_K > lm_head_q4k
 
std::vector< block_q4_K > final_norm_q4k
 
std::vector< block_q5_K > embed_tokens_q5k
 
std::vector< block_q5_K > lm_head_q5k
 
std::vector< block_q6_K > embed_tokens_q6k
 
std::vector< block_q6_K > lm_head_q6k
 
std::vector< block_q6_K > final_norm_q6k
 
std::vector< block_q8_0 > embed_tokens_q8_0
 
std::vector< block_q8_0 > lm_head_q8_0
 
std::vector< block_q8_K > embed_tokens_q8k
 
std::vector< block_q8_K > lm_head_q8k
 
std::vector< LayerWeights > layers
 
std::vector< std::pair< float, float > > precomputed_freqs_cis_
 
std::unique_ptr< GGUFData > gguf_data_
 
bool ir_only_ = false
 
std::string model_path_
 
bool f32_concatenated_weights_loaded_ = false
 
std::unique_ptr< class CPUBatchProcessor > cpu_batch_processor_
 

Friends

class CPUBatchProcessor
 
void map_gguf_weights (const GGUFData &gguf, TinyLlamaModel &model)
 

Detailed Description

Main transformer model class for TinyLlama.

Handles weight loading, forward pass, and GPU/CPU offloading logic. Supports both GGUF and SafeTensors formats.

Definition at line 309 of file model.h.

Constructor & Destructor Documentation

◆ TinyLlamaModel() [1/3]

TinyLlamaModel::TinyLlamaModel ( const ModelConfig &  config,
const SafeTensorsLoader &  loader 
)

Construct a TinyLlamaModel from a SafeTensorsLoader.

Parameters
configModel configuration.
loaderSafeTensorsLoader instance.

Definition at line 143 of file model.cpp.

145 : config_(config) { // Copies the potentially faulty config first
146 config_.is_gguf_file_loaded = false; // Explicitly set to false for SafeTensors path
147 Logger::info("Constructing TinyLlamaModel from SafeTensorsLoader (is_gguf_file_loaded set to false).");
148 initialize_weights(&loader, nullptr);
150 Logger::info("TinyLlamaModel construction from SafeTensorsLoader complete.");
151}
static void info(const std::string &message)
Definition logger.cpp:135
ModelConfig config_
Definition model.h:573
void initialize_weights(const SafeTensorsLoader *loader, const GGUFData *gguf)
Definition model.cpp:39
size_t j
bool is_gguf_file_loaded
Definition model.h:103

References config_, Logger::info(), initialize_gpu_and_rope(), initialize_weights(), ModelConfig::is_gguf_file_loaded, and j.

◆ TinyLlamaModel() [2/3]

TinyLlamaModel::TinyLlamaModel ( const ModelConfig &  initial_config,
const std::string &  model_path 
)

Construct a TinyLlamaModel from a model path (GGUF or SafeTensors).

Parameters
initial_configInitial model configuration (may be overridden by file metadata).
model_pathPath to the model file or directory.

Definition at line 153 of file model.cpp.

156#ifdef HAS_CUDA
157 , cublas_handle_(nullptr), token_embedding_table_dev_(nullptr), lm_head_dev_(nullptr), final_norm_dev(nullptr), w_q_dev_(nullptr), w_k_dev_(nullptr), w_v_dev_(nullptr), w_o_dev_(nullptr), w_gate_dev_(nullptr), w_up_dev_(nullptr), w_down_dev_(nullptr), all_freqs_cis_dev(nullptr), x_dev_(nullptr), x_norm_dev_(nullptr), x_resid1_dev_(nullptr), x_resid2_dev_(nullptr), q_dev_(nullptr), k_dev_(nullptr), v_dev_(nullptr), attn_out_dev_(nullptr), attn_proj_dev_(nullptr), gate_vec_dev_(nullptr), up_vec_dev_(nullptr), swiglu_vec_dev_(nullptr), mlp_down_dev_(nullptr), logits_dev_(nullptr), token_embedding_table_f32_dev_(nullptr), lm_head_f32_dev_(nullptr), w_q_f32_dev_(nullptr), w_k_f32_dev_(nullptr), w_v_f32_dev_(nullptr), w_o_f32_dev_(nullptr), w_gate_f32_dev_(nullptr), w_up_f32_dev_(nullptr), w_down_f32_dev_(nullptr)
158#endif
159{
160 Logger::info("TinyLlamaModel constructor entered. Model path (from string): " + model_path);
161 int cli_gpu_layer_request = initial_config.num_cpu_offload_layers;
162 bool cli_mmap_preference = initial_config.use_mmap_for_gguf;
163 this->config_ = initial_config;
164 if (this->model_path_.empty() && !model_path.empty()) {
165 this->model_path_ = model_path;
166 }
167 std::unique_ptr<SafeTensorsLoader> loader = nullptr;
168 if (!this->model_path_.empty() && this->model_path_.size() > 5 &&
169 this->model_path_.substr(this->model_path_.size() - 5) == ".gguf") {
170 Logger::info("GGUF file detected by path in Model Constructor: " + this->model_path_);
171 try {
173 Logger::info("TinyLlamaModel GGUF path: Using mmap setting " + std::string(force_mmap_for_gguf_load ? "true" : "false") +
174 " for gguf_meta/weight loading based on CLI mmap preference: " +
175 std::string(cli_mmap_preference ? "true" : "false"));
176
177 this->gguf_data_ = std::make_unique<GGUFData>(load_gguf_meta(this->model_path_, force_mmap_for_gguf_load));
178
180 // A paperkiln IR that is not the graph the tuned llama path implements
181 // (ember_ir::tuned_llama_match: a structural match, family_hint only
182 // its pre-filter; or EMBER_IR_ONLY=1): the interpreter serves it, so
183 // the dimensions come from the IR and the llama loader is skipped below.
184 {
185 const std::string ir = ember_ir::find_ir(*this->gguf_data_);
186 const char* only = std::getenv("EMBER_IR_ONLY");
187 if (!ir.empty()) {
188 const auto j = nlohmann::json::parse(ir);
189 std::string why;
190 const bool tuned = ember_ir::tuned_llama_match(ir, *this->gguf_data_, &why);
191 if (!tuned && j.value("family_hint", "") == "llama")
192 Logger::info("[IR] family_hint llama, but not the tuned llama path's graph (" + why +
193 "): the interpreter runs it");
194 if (!tuned || (only && std::string(only) == "1")) {
195 this->ir_only_ = true;
196 const auto& m = j.at("model");
197 config_from_gguf.hidden_size = m.at("d").get<int>();
198 config_from_gguf.num_hidden_layers = j.at("block").at("repeat").get<int>();
199 config_from_gguf.vocab_size = m.at("vocab").get<int>();
200 config_from_gguf.max_position_embeddings = m.value("ctx", config_from_gguf.max_position_embeddings);
201 // EMBER_IR_CTX caps it as it caps the interpreter's kv state (graph_ir.h).
202 if (const char* c = std::getenv("EMBER_IR_CTX"))
203 if (std::atoi(c) > 0)
204 config_from_gguf.max_position_embeddings = std::min(config_from_gguf.max_position_embeddings, std::atoi(c));
205 // Head counts from the kv state; without one (recurrent-only
206 // families), from linear attention's [heads, head_dim] state, else
207 // one head of width d (the llama-side KV cache is then unused).
208 bool kv_heads_set = false;
209 for (const auto& s : j.at("block").value("state", nlohmann::json::array()))
210 if (s.value("kind", "") == "kv") {
211 config_from_gguf.num_attention_heads = s.at("heads").get<int>();
212 config_from_gguf.num_key_value_heads = s.at("kv_heads").get<int>();
213 kv_heads_set = true;
214 }
215 if (!kv_heads_set) {
216 int heads = 1;
217 for (const auto& s : j.at("block").value("state", nlohmann::json::array()))
218 if (s.value("kind", "") == "recurrent" && s.value("op", "") == "linear_attention" &&
219 !s.value("tensors", nlohmann::json::array()).empty())
220 heads = s.at("tensors").at(0).at("shape").at(0).get<int>();
221 config_from_gguf.num_attention_heads = heads;
222 config_from_gguf.num_key_value_heads = heads;
223 }
224 config_from_gguf.num_experts = 0;
225 Logger::info("GGUF served by the paperkiln IR interpreter only (family_hint '" +
226 j.value("family_hint", "") + "'): llama weights are not loaded.");
227 }
228 }
229 }
230 this->config_ = config_from_gguf;
232 this->config_.is_gguf_file_loaded = true;
233 if (cli_gpu_layer_request < 0) {
235 Logger::info("TinyLlamaModel GGUF Ctor CALC: CLI hint < 0 (all GPU). num_cpu_offload_layers set to 0.");
236 } else if (cli_gpu_layer_request == 0) {
238 Logger::info("TinyLlamaModel GGUF Ctor CALC: CLI hint == 0 (all CPU). num_cpu_offload_layers set to num_hidden_layers (" + std::to_string(this->config_.num_cpu_offload_layers) + ").");
239 } else { // CLI hint > 0, meaning cli_gpu_layer_request is the number of desired GPU layers
240 if (this->config_.num_hidden_layers > 0) {
241 if (cli_gpu_layer_request >= this->config_.num_hidden_layers) {
242 this->config_.num_cpu_offload_layers = 0; // More GPU layers requested than available -> all on GPU
243 Logger::info("TinyLlamaModel GGUF Ctor CALC: CLI GPU layer request ("+ std::to_string(cli_gpu_layer_request) +") >= total layers. num_cpu_offload_layers set to 0.");
244 } else {
246 Logger::info("TinyLlamaModel GGUF Ctor CALC: Partial GPU. CLI GPU req: " + std::to_string(cli_gpu_layer_request) + ". num_cpu_offload_layers set to " + std::to_string(this->config_.num_cpu_offload_layers));
247 }
248 } else { // num_hidden_layers is 0 or negative, something is wrong with GGUF. Default to all CPU.
250 Logger::warning("TinyLlamaModel GGUF Ctor CALC: num_hidden_layers from GGUF is <= 0. Defaulting num_cpu_offload_layers to 0. CLI GPU req: " + std::to_string(cli_gpu_layer_request));
251 }
252 }
253 Logger::info("TinyLlamaModel GGUF Ctor: POST-CALC (within GGUF block) final num_cpu_offload_layers = " + std::to_string(this->config_.num_cpu_offload_layers));
254 Logger::info("[CTOR_GGUF_DEBUG_L1860] After CLI hint logic: this->config_.num_cpu_offload_layers = " + std::to_string(this->config_.num_cpu_offload_layers) +
255 ", this->config_.num_hidden_layers = " + std::to_string(this->config_.num_hidden_layers));
256 } catch (const std::exception& e) {
257 Logger::error("Failed to load or parse GGUF file: " + std::string(e.what()));
258 throw;
259 }
260 } else if (model_path.size() > 12 &&
261 model_path.substr(model_path.size() - 12) == ".safetensors") {
262 Logger::info("SafeTensors file detected: " + model_path);
265
266 // For SafeTensors, start with JSON config, then layer CLI preferences.
268 Logger::info("Successfully loaded and parsed config.json for SafeTensors model.");
269 this->config_ = config_from_json; // Base is from JSON
270 } else {
271 Logger::warning("Failed to load config.json or it was not found for SafeTensors model. Proceeding with initial_config defaults and CLI overrides.");
272 }
273 this->config_.is_gguf_file_loaded = false;
274 this->config_.use_mmap_for_gguf = cli_mmap_preference; // This field is GGUF specific, but store CLI pref anyway.
275
276 if (cli_gpu_layer_request < 0) {
278 } else if (cli_gpu_layer_request == 0) {
280 } else {
281 if (this->config_.num_hidden_layers > 0) {
282 if (cli_gpu_layer_request >= this->config_.num_hidden_layers) {
284 } else {
286 }
287 } else {
288 this->config_.num_cpu_offload_layers = 0; // Fallback if num_hidden_layers not known
289 Logger::warning("SafeTensors path: num_hidden_layers is 0 from JSON/default. Defaulting num_cpu_offload_layers to 0 despite CLI GPU request: " + std::to_string(cli_gpu_layer_request));
290 }
291 }
292 Logger::info("SafeTensors path: Calculated num_cpu_offload_layers = " + std::to_string(this->config_.num_cpu_offload_layers));
293
294 try {
295 loader = std::make_unique<SafeTensorsLoader>(model_path);
296 Logger::info("SafeTensorsLoader initialized for: " + model_path);
297 } catch (const std::exception& e) {
298 Logger::error("Failed to initialize SafeTensorsLoader: " + std::string(e.what()));
299 throw;
300 }
301 } else {
302 throw std::runtime_error(
303 "Unsupported model file type. Please use .gguf or .safetensors");
304 }
305
306 Logger::info("TinyLlamaModel constructor: After specific loader block. Current config_.num_cpu_offload_layers = " + std::to_string(this->config_.num_cpu_offload_layers) +
307 ", config_.num_hidden_layers = " + std::to_string(this->config_.num_hidden_layers));
308 Logger::info("TinyLlamaModel constructor: Current config_.use_mmap_for_gguf = " + std::string(this->config_.use_mmap_for_gguf ? "true" : "false"));
309
310 if (this->config_.num_cpu_offload_layers < 0) { // Should not happen if logic above is correct for -1 CLI hint
312 Logger::warning("Clamping num_cpu_offload_layers: was < 0, set to 0.");
313 }
314 if (this->config_.num_hidden_layers > 0 && this->config_.num_cpu_offload_layers > this->config_.num_hidden_layers) {
315 Logger::warning("Clamping num_cpu_offload_layers: Requested CPU offload layers (" + std::to_string(this->config_.num_cpu_offload_layers) +
316 ") exceeds total hidden layers (" + std::to_string(this->config_.num_hidden_layers) +
317 "). Clamping to " + std::to_string(this->config_.num_hidden_layers) + " (all CPU).");
319 }
320 Logger::info("TinyLlamaModel constructor: Final clamped num_cpu_offload_layers = " + std::to_string(this->config_.num_cpu_offload_layers));
321 Logger::info("[CTOR_DEBUG_L1921] End of Model Ctor (before initialize_weights/rope call): this->config_.num_cpu_offload_layers = " + std::to_string(this->config_.num_cpu_offload_layers) +
322 ", this->config_.num_hidden_layers = " + std::to_string(this->config_.num_hidden_layers));
323 Logger::info("Final ModelConfig (before initialize_weights/rope):");
324 Logger::info(" hidden_size: " + std::to_string(config_.hidden_size));
325 Logger::info(" intermediate_size: " + std::to_string(config_.intermediate_size));
326 Logger::info(" num_attention_heads: " + std::to_string(config_.num_attention_heads));
327 Logger::info(" num_key_value_heads: " + std::to_string(config_.num_key_value_heads));
328 Logger::info(" num_hidden_layers: " + std::to_string(config_.num_hidden_layers));
329 Logger::info(" vocab_size: " + std::to_string(config_.vocab_size));
330 Logger::info(" max_position_embeddings: " + std::to_string(config_.max_position_embeddings));
331 Logger::info(" architecture: " + config_.architecture);
332 Logger::info(" is_gguf_file_loaded: " + std::string(config_.is_gguf_file_loaded ? "true" : "false"));
333 Logger::info(" use_mmap_for_gguf: " + std::string(config_.use_mmap_for_gguf ? "true" : "false"));
334 // --- BEGIN GGUFData Integrity Check ---
335 if (this->config_.is_gguf_file_loaded && this->gguf_data_) {
336 if (this->gguf_data_->tensor_infos_map.empty()) {
337 Logger::error("[CTOR_GGUF_PRE_INIT_W] CRITICAL: gguf_data_->tensor_infos_map is EMPTY. Weights will not be loaded by map_gguf_weights.");
338 }
339 } else if (this->config_.is_gguf_file_loaded && !this->gguf_data_) {
340 Logger::error("[CTOR_GGUF_PRE_INIT_W] CRITICAL: config_.is_gguf_file_loaded is TRUE, but gguf_data_ pointer IS NULL. Weights cannot be loaded.");
341 } else if (!this->config_.is_gguf_file_loaded) {
342 Logger::info("[CTOR_GGUF_PRE_INIT_W] Not a GGUF file load context (e.g., SafeTensors). Skipping gguf_data_ check here.");
343 }
344 // --- END GGUFData Integrity Check ---
345 if (this->ir_only_) {
346 // No llama layers to place: the interpreter owns the weights and picks its
347 // own device from the CLI request (api.cpp).
349 Logger::info("TinyLlamaModel: IR-only GGUF, weights left to the interpreter.");
350 return;
351 }
352 initialize_weights(loader.get(), this->gguf_data_.get());
354
355 Logger::info("TinyLlamaModel (from path string) constructed and initialized successfully.");
356}
static void warning(const std::string &message)
Definition logger.cpp:139
static void error(const std::string &message)
Definition logger.cpp:143
static bool load_model_config_from_json(const std::string &model_path_or_dir, ModelConfig &config_to_populate)
Loads model configuration from a JSON file corresponding to a .safetensors model path.
bool ir_only_
Definition model.h:697
std::string model_path_
Definition model.h:698
std::unique_ptr< GGUFData > gguf_data_
Definition model.h:696
GGUFData load_gguf_meta(const std::string &filename, bool use_mmap)
Loads GGUF metadata and optionally memory-maps tensor data.
std::string why
Definition graph_ir.cpp:280
float value
float c
ModelConfig parse_model_config_from_gguf(const GGUFData &gguf)
bool tuned_llama_match(const std::string &ir_json, const GGUFData &gguf, std::string *why)
Definition graph_ir.cpp:440
std::string find_ir(const GGUFData &gguf)
Definition graph_ir.cpp:525
Template get(const std::string &id)
nlohmann::json json
Definition server.cpp:68
Model configuration structure holding architecture and hyperparameters.
Definition model.h:82
int hidden_size
Definition model.h:83
int vocab_size
Definition model.h:88
std::string architecture
Definition model.h:98
int num_attention_heads
Definition model.h:85
bool use_mmap_for_gguf
Definition model.h:104
int intermediate_size
Definition model.h:84
int num_cpu_offload_layers
Definition model.h:106
int num_hidden_layers
Definition model.h:87
int num_key_value_heads
Definition model.h:86
int max_position_embeddings
Definition model.h:89

References ModelConfig::architecture, c, config_, Logger::error(), ember_ir::find_ir(), gguf_data_, ModelConfig::hidden_size, Logger::info(), initialize_gpu_and_rope(), initialize_weights(), ModelConfig::intermediate_size, ir_only_, ModelConfig::is_gguf_file_loaded, j, load_gguf_meta(), SafeTensorsLoader::load_model_config_from_json(), ModelConfig::max_position_embeddings, model_path_, ModelConfig::num_attention_heads, ModelConfig::num_cpu_offload_layers, ModelConfig::num_hidden_layers, ModelConfig::num_key_value_heads, parse_model_config_from_gguf(), ember_ir::tuned_llama_match(), ModelConfig::use_mmap_for_gguf, ModelConfig::vocab_size, Logger::warning(), and why.

◆ TinyLlamaModel() [3/3]

TinyLlamaModel::TinyLlamaModel ( const ModelConfig &  config_from_session,
std::unique_ptr< GGUFData >  gguf_data_from_session 
)

Construct a TinyLlamaModel from pre-loaded GGUFData.

Parameters
config_from_sessionModel configuration.
gguf_data_from_sessionUnique pointer to GGUFData.

Definition at line 357 of file model.cpp.

361 model_path_("loaded_from_gguf_data_memory")
362#ifdef HAS_CUDA
363 // Initialize all CUDA pointers to nullptr as in the other constructor
364 , cublas_handle_(nullptr), token_embedding_table_dev_(nullptr), lm_head_dev_(nullptr), final_norm_dev(nullptr), w_q_dev_(nullptr), w_k_dev_(nullptr), w_v_dev_(nullptr), w_o_dev_(nullptr), w_gate_dev_(nullptr), w_up_dev_(nullptr), w_down_dev_(nullptr), all_freqs_cis_dev(nullptr), x_dev_(nullptr), x_norm_dev_(nullptr), x_resid1_dev_(nullptr), x_resid2_dev_(nullptr), q_dev_(nullptr), k_dev_(nullptr), v_dev_(nullptr), attn_out_dev_(nullptr), attn_proj_dev_(nullptr), gate_vec_dev_(nullptr), up_vec_dev_(nullptr), swiglu_vec_dev_(nullptr), mlp_down_dev_(nullptr), logits_dev_(nullptr), token_embedding_table_f32_dev_(nullptr), lm_head_f32_dev_(nullptr), w_q_f32_dev_(nullptr), w_k_f32_dev_(nullptr), w_v_f32_dev_(nullptr), w_o_f32_dev_(nullptr), w_gate_f32_dev_(nullptr), w_up_f32_dev_(nullptr), w_down_f32_dev_(nullptr)
365#endif
366{
367 Logger::info("TinyLlamaModel constructor entered (with pre-loaded GGUFData). Model path placeholder: " + model_path_);
368 this->config_.is_gguf_file_loaded = true; // Ensure this is set
369
370 if (this->config_.num_cpu_offload_layers < 0) {
372 }
373 if (this->config_.num_hidden_layers > 0 && this->config_.num_cpu_offload_layers > this->config_.num_hidden_layers) {
374 Logger::warning("Requested CPU offload layers (" + std::to_string(this->config_.num_cpu_offload_layers) +
375 ") exceeds total hidden layers (" + std::to_string(this->config_.num_hidden_layers) +
376 "). Clamping to " + std::to_string(this->config_.num_hidden_layers) + " layers on CPU (all CPU).");
378 }
379 Logger::info("TinyLlamaModel (pre-loaded GGUF): Final clamped num_cpu_offload_layers = " + std::to_string(this->config_.num_cpu_offload_layers));
380
381 initialize_weights(nullptr, gguf_data_.get()); // Pass raw GGUFData pointer
383 Logger::info("TinyLlamaModel (with pre-loaded GGUFData) constructed and initialized successfully.");
384}

References config_, gguf_data_, Logger::info(), initialize_gpu_and_rope(), initialize_weights(), ModelConfig::is_gguf_file_loaded, j, model_path_, ModelConfig::num_cpu_offload_layers, ModelConfig::num_hidden_layers, and Logger::warning().

◆ ~TinyLlamaModel()

TinyLlamaModel::~TinyLlamaModel ( )

Destructor. Cleans up all allocated resources.

Definition at line 386 of file model.cpp.

386 {
387#ifdef HAS_CUDA
388 // Only perform GPU cleanup if GPU layers were actually used
390 if (active_num_gpu_layers > 0) {
391 Logger::info("Freeing TinyLlamaModel CUDA resources...");
392 if (cublas_handle_) {
395 Logger::error("cuBLAS handle destruction failed with error code: " +
396 std::to_string(cublas_status));
397 }
398 cublas_handle_ = nullptr;
399 Logger::info("cuBLAS handle destroyed.");
400 }
401 } else {
402 // CPU-only mode: just clean up cuBLAS handle if it exists
403 if (cublas_handle_) {
406 Logger::error("cuBLAS handle destruction failed with error code: " +
407 std::to_string(cublas_status));
408 }
409 cublas_handle_ = nullptr;
410 }
411 }
412 // Continue GPU cleanup only if GPU layers were active
413 if (active_num_gpu_layers > 0) {
414 if (final_norm_dev) {
416 final_norm_dev = nullptr;
417 }
418
419 for (auto& layer : layers) {
420 if (layer.input_layernorm_dev) {
421 gpuErrchk(cudaFree(layer.input_layernorm_dev));
422 layer.input_layernorm_dev = nullptr;
423 }
424 if (layer.post_attention_layernorm_dev) {
425 gpuErrchk(cudaFree(layer.post_attention_layernorm_dev));
426 layer.post_attention_layernorm_dev = nullptr;
427 }
428 }
429
430 if (all_freqs_cis_dev) {
432 all_freqs_cis_dev = nullptr;
433 }
437 }
438 if (lm_head_dev_) {
440 lm_head_dev_ = nullptr;
441 }
442 if (w_q_dev_) {
444 w_q_dev_ = nullptr;
445 }
446 if (w_k_dev_) {
448 w_k_dev_ = nullptr;
449 }
450 if (w_v_dev_) {
452 w_v_dev_ = nullptr;
453 }
454 if (w_o_dev_) {
456 w_o_dev_ = nullptr;
457 }
458 if (w_gate_dev_) {
460 w_gate_dev_ = nullptr;
461 }
462 if (w_up_dev_) {
464 w_up_dev_ = nullptr;
465 }
466 if (w_down_dev_) {
468 w_down_dev_ = nullptr;
469 }
473 }
474 if (lm_head_f32_dev_) {
476 lm_head_f32_dev_ = nullptr;
477 }
478 if (w_q_f32_dev_) {
480 w_q_f32_dev_ = nullptr;
481 }
482 if (w_k_f32_dev_) {
484 w_k_f32_dev_ = nullptr;
485 }
486 if (w_v_f32_dev_) {
488 w_v_f32_dev_ = nullptr;
489 }
490 if (w_o_f32_dev_) {
492 w_o_f32_dev_ = nullptr;
493 }
494 if (w_gate_f32_dev_) {
496 w_gate_f32_dev_ = nullptr;
497 }
498 if (w_up_f32_dev_) {
500 w_up_f32_dev_ = nullptr;
501 }
502 if (w_down_f32_dev_) {
504 w_down_f32_dev_ = nullptr;
505 }
508 if (*p) { cudaFree(*p); *p = nullptr; }
509
510 if (x_dev_) {
512 x_dev_ = nullptr;
513 }
514 if (x_norm_dev_) {
516 x_norm_dev_ = nullptr;
517 }
518 if (x_resid1_dev_) {
520 x_resid1_dev_ = nullptr;
521 }
522 if (x_resid2_dev_) {
524 x_resid2_dev_ = nullptr;
525 }
526 if (q_dev_) {
528 q_dev_ = nullptr;
529 }
530 if (k_dev_) {
532 k_dev_ = nullptr;
533 }
534 if (v_dev_) {
536 v_dev_ = nullptr;
537 }
538 if (attn_out_dev_) {
540 attn_out_dev_ = nullptr;
541 }
542 if (attn_proj_dev_) {
544 attn_proj_dev_ = nullptr;
545 }
546 if (gate_vec_dev_) {
548 gate_vec_dev_ = nullptr;
549 }
550 if (up_vec_dev_) {
552 up_vec_dev_ = nullptr;
553 }
554 if (swiglu_vec_dev_) {
556 swiglu_vec_dev_ = nullptr;
557 }
558 if (mlp_down_dev_) {
560 mlp_down_dev_ = nullptr;
561 }
562 if (logits_dev_) {
564 logits_dev_ = nullptr;
565 }
566 // Free KVCache dequantization buffers
570 }
574 }
575 // Free selective KVCache dequantization buffers
579 }
583 }
584
585 // Free persistent batch processing buffers
587
588 Logger::info("Freed persistent GPU workspace buffers.");
589 Logger::info("Finished freeing TinyLlamaModel CUDA weight memory.");
590 } else {
591 Logger::info("CPU-only mode: No GPU resources to free.");
592 }
593#endif
594}
std::vector< LayerWeights > layers
Definition model.h:587
const float * p[kIrDepthSourcesMax]

References config_, Logger::error(), Logger::info(), j, layers, ModelConfig::num_cpu_offload_layers, ModelConfig::num_hidden_layers, and p.

Member Function Documentation

◆ clear_layer_dequantized_weights()

void TinyLlamaModel::clear_layer_dequantized_weights ( int  layer_idx)

Definition at line 115 of file weight_management.cpp.

115 {
116 if (layer_idx < 0 || layer_idx >= static_cast<int>(layers.size())) {
117 Logger::warning("clear_layer_dequantized_weights: Invalid layer index " + std::to_string(layer_idx));
118 return;
119 }
120
121 // Each f32 copy is cleared only when the weight has a quantised (or BF16) source to re-derive it
122 // from: for F32-native weights (transformer_cpp exports) the f32 vector IS the master copy, and
123 // clearing it is permanent destruction, not a memory optimisation (first hit 2026-07-20 on the
124 // 4-layer mid model: "No Q proj weights" on the second forward pass). Per weight, not per
125 // layer, so a layer whose weights mix sources keeps its f32-only ones.
126 auto& layer = layers[layer_idx];
127 auto clear_if_recoverable = [](std::vector<float>& f32, bool recoverable) {
128 if (!recoverable) return 0;
129 f32.clear();
130 f32.shrink_to_fit();
131 return 1;
132 };
133#define EMBER_RECOVERABLE(w) \
134 (!layer.w##_q4k.empty() || !layer.w##_q5k.empty() || !layer.w##_q6k.empty() || !layer.w##_q8k.empty() || \
135 !layer.w##_q8_0.empty() || !layer.w.empty())
136 int cleared = 0;
137 cleared += clear_if_recoverable(layer.q_proj_f32, EMBER_RECOVERABLE(q_proj));
138 cleared += clear_if_recoverable(layer.k_proj_f32, EMBER_RECOVERABLE(k_proj));
139 cleared += clear_if_recoverable(layer.v_proj_f32, EMBER_RECOVERABLE(v_proj));
140 cleared += clear_if_recoverable(layer.o_proj_f32, EMBER_RECOVERABLE(o_proj));
141 cleared += clear_if_recoverable(layer.gate_proj_f32, EMBER_RECOVERABLE(gate_proj));
142 cleared += clear_if_recoverable(layer.up_proj_f32, EMBER_RECOVERABLE(up_proj));
143 cleared += clear_if_recoverable(layer.down_proj_f32, EMBER_RECOVERABLE(down_proj));
144#undef EMBER_RECOVERABLE
145 if (cleared)
146 Logger::info("Cleared " + std::to_string(cleared) + " dequantized weights of layer " + std::to_string(layer_idx) +
147 " to save memory.");
148}
#define EMBER_RECOVERABLE(w)

References EMBER_RECOVERABLE, Logger::info(), j, layers, and Logger::warning().

Referenced by forward().

◆ dequantize_all_if_small()

bool TinyLlamaModel::dequantize_all_if_small ( size_t  max_params)

Definition at line 32 of file weight_management.cpp.

32 {
34 const size_t kv = hs / std::max(config_.num_attention_heads, 1) * config_.num_key_value_heads;
35 const size_t per_layer = hs * hs * 2 + hs * kv * 2 + hs * is * 3;
36 const size_t params = vs * hs * 2 + per_layer * config_.num_hidden_layers;
37 if (params > max_params) return false;
40 for (auto& lw : layers) { // MoE router (Q8_0 in paperkiln's Q8_0 exports)
41 if (lw.moe_router_f32.empty() && !lw.moe_router_q8_0.empty()) {
42 const size_t n = lw.moe_router_q8_0.size() * GGML_QK8_0;
43 dequantize_vector_q8_0_to_f32(lw.moe_router_q8_0, lw.moe_router_f32, n, 0);
44 lw.moe_router_q8_0.clear();
45 lw.moe_router_q8_0.shrink_to_fit();
46 }
47 }
48 for (int l = 0; l < static_cast<int>(layers.size()); ++l) {
56 }
57 // Free the quantised copies whose f32 copy now exists: nothing can then
58 // take a quantised kernel, and the model is not held twice (WASM memory).
59 auto drop = [](const std::vector<float>& f32, auto&... quant) {
60 if (f32.empty()) return;
61 ((quant.clear(), quant.shrink_to_fit()), ...);
62 };
65 for (auto& lw : layers) {
66 drop(lw.q_proj_f32, lw.q_proj_q4k, lw.q_proj_q5k, lw.q_proj_q6k, lw.q_proj_q8_0, lw.q_proj_q8k);
67 drop(lw.k_proj_f32, lw.k_proj_q4k, lw.k_proj_q5k, lw.k_proj_q6k, lw.k_proj_q8_0, lw.k_proj_q8k);
68 drop(lw.v_proj_f32, lw.v_proj_q4k, lw.v_proj_q5k, lw.v_proj_q6k, lw.v_proj_q8_0, lw.v_proj_q8k);
69 drop(lw.o_proj_f32, lw.o_proj_q4k, lw.o_proj_q5k, lw.o_proj_q6k, lw.o_proj_q8_0, lw.o_proj_q8k);
70 drop(lw.gate_proj_f32, lw.gate_proj_q4k, lw.gate_proj_q5k, lw.gate_proj_q6k, lw.gate_proj_q8_0, lw.gate_proj_q8k);
71 drop(lw.up_proj_f32, lw.up_proj_q4k, lw.up_proj_q5k, lw.up_proj_q6k, lw.up_proj_q8_0, lw.up_proj_q8k);
72 drop(lw.down_proj_f32, lw.down_proj_q4k, lw.down_proj_q5k, lw.down_proj_q6k, lw.down_proj_q8_0, lw.down_proj_q8k);
73 }
74 return true;
75}
std::vector< block_q6_K > embed_tokens_q6k
Definition model.h:584
void ensure_up_proj_dequantized(int layer_idx)
void ensure_v_proj_dequantized(int layer_idx)
std::vector< block_q4_K > lm_head_q4k
Definition model.h:582
std::vector< block_q6_K > lm_head_q6k
Definition model.h:584
std::vector< block_q5_K > lm_head_q5k
Definition model.h:583
void ensure_embed_tokens_dequantized()
std::vector< block_q8_0 > embed_tokens_q8_0
Definition model.h:585
void ensure_o_proj_dequantized(int layer_idx)
std::vector< block_q4_K > embed_tokens_q4k
Definition model.h:582
void ensure_k_proj_dequantized(int layer_idx)
std::vector< block_q8_0 > lm_head_q8_0
Definition model.h:585
std::vector< block_q5_K > embed_tokens_q5k
Definition model.h:583
std::vector< block_q8_K > embed_tokens_q8k
Definition model.h:586
void ensure_q_proj_dequantized(int layer_idx)
void ensure_down_proj_dequantized(int layer_idx)
void ensure_gate_proj_dequantized(int layer_idx)
std::vector< float > embed_tokens_f32
Definition model.h:581
void ensure_lm_head_dequantized()
std::vector< float > lm_head_f32
Definition model.h:581
std::vector< block_q8_K > lm_head_q8k
Definition model.h:586
constexpr size_t GGML_QK8_0
Definition gguf_parser.h:43
int n
void dequantize_vector_q8_0_to_f32(const std::vector< block_q8_0 > &q_weights, std::vector< float > &f32_weights, size_t total_num_elements, int log_first_n_blocks)
Dequantizes a vector of Q8_0 blocks to a vector of float32.

References config_, dequantize_vector_q8_0_to_f32(), embed_tokens_f32, embed_tokens_q4k, embed_tokens_q5k, embed_tokens_q6k, embed_tokens_q8_0, embed_tokens_q8k, ensure_down_proj_dequantized(), ensure_embed_tokens_dequantized(), ensure_gate_proj_dequantized(), ensure_k_proj_dequantized(), ensure_lm_head_dequantized(), ensure_o_proj_dequantized(), ensure_q_proj_dequantized(), ensure_up_proj_dequantized(), ensure_v_proj_dequantized(), GGML_QK8_0, ModelConfig::hidden_size, ModelConfig::intermediate_size, j, layers, lm_head_f32, lm_head_q4k, lm_head_q5k, lm_head_q6k, lm_head_q8_0, lm_head_q8k, n, ModelConfig::num_attention_heads, ModelConfig::num_hidden_layers, ModelConfig::num_key_value_heads, and ModelConfig::vocab_size.

◆ ensure_bf16_concatenated_weights_loaded()

void TinyLlamaModel::ensure_bf16_concatenated_weights_loaded ( )

Definition at line 1242 of file weight_management.cpp.

1242 {
1243 Logger::info("CPU-only build: ensure_bf16_concatenated_weights_loaded is a no-op");
1244}

References Logger::info().

◆ ensure_down_proj_dequantized()

void TinyLlamaModel::ensure_down_proj_dequantized ( int  layer_idx)

Definition at line 232 of file weight_management.cpp.

232 {
233 if (layer_idx < 0 || layer_idx >= layers.size()) return;
234 auto& lw = layers[layer_idx];
235 if (!lw.down_proj_f32.empty()) return;
236
237 int hs = config_.hidden_size;
239 size_t down_proj_elements = static_cast<size_t>(hs) * is;
240
241 if (!lw.down_proj_q6k.empty()) dequantize_vector_q6k_to_f32(lw.down_proj_q6k, lw.down_proj_f32, down_proj_elements, 0);
242 else if (!lw.down_proj_q4k.empty()) dequantize_vector_q4k_to_f32(lw.down_proj_q4k, lw.down_proj_f32, down_proj_elements, 0);
243 else if (!lw.down_proj_q5k.empty()) dequantize_vector_q5k_to_f32(lw.down_proj_q5k, lw.down_proj_f32, down_proj_elements);
244 else if (!lw.down_proj_q8k.empty()) dequantize_q8_k(lw.down_proj_q8k, lw.down_proj_f32, down_proj_elements, false);
245 else if (!lw.down_proj_q8_0.empty()) dequantize_vector_q8_0_to_f32(lw.down_proj_q8_0, lw.down_proj_f32, down_proj_elements, 0);
246 else if (!lw.down_proj.empty()) lw.down_proj_f32 = bf16vec_to_float_vec(lw.down_proj);
247}
void dequantize_vector_q5k_to_f32(const std::vector< block_q5_K > &q_weights, std::vector< float > &f32_weights, size_t total_num_elements)
Dequantizes a vector of Q5_K blocks to float32 (total_num_elements a multiple of GGML_QK_K)
void dequantize_vector_q6k_to_f32(const std::vector< block_q6_K > &q_weights, std::vector< float > &f32_weights, size_t total_num_elements, int log_first_n_blocks)
Dequantizes a vector of Q6_K blocks to a vector of float32.
void dequantize_vector_q4k_to_f32(const std::vector< block_q4_K > &q_weights, std::vector< float > &f32_weights, size_t total_num_elements, int log_first_n_blocks)
Dequantizes a vector of Q4_K blocks to a vector of float32.
void dequantize_q8_k(const std::vector< block_q8_K > &q_data, std::vector< float > &x, int n, bool log_this_block)
std::vector< float > bf16vec_to_float_vec(const std::vector< uint16_t > &v_bf16)
Definition utils.cpp:199

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, ModelConfig::intermediate_size, j, and layers.

Referenced by dequantize_all_if_small(), forward(), CPUBatchProcessor::forward_cpu_batch(), and forward_cpu_batch_generation().

◆ ensure_embed_tokens_dequantized()

void TinyLlamaModel::ensure_embed_tokens_dequantized ( )

Definition at line 13 of file weight_management.cpp.

13 {
14 if (!this->embed_tokens_f32.empty()) return;
15
16 size_t total_elements_embed = static_cast<size_t>(config_.vocab_size) * config_.hidden_size;
17 if (!this->embed_tokens_q6k.empty()) {
19 } else if (!this->embed_tokens_q4k.empty()) {
21 } else if (!this->embed_tokens_q5k.empty()) {
23 } else if (!this->embed_tokens_q8k.empty()) {
25 } else if (!this->embed_tokens_q8_0.empty()) {
27 } else if (!this->embed_tokens.empty()) {
29 }
30}
std::vector< uint16_t > embed_tokens
Definition model.h:578

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), embed_tokens, embed_tokens_f32, embed_tokens_q4k, embed_tokens_q5k, embed_tokens_q6k, embed_tokens_q8_0, embed_tokens_q8k, ModelConfig::hidden_size, j, and ModelConfig::vocab_size.

Referenced by dequantize_all_if_small(), initialize_gpu_and_rope(), and initialize_weights().

◆ ensure_f32_concatenated_weights_loaded()

void TinyLlamaModel::ensure_f32_concatenated_weights_loaded ( )

Definition at line 1238 of file weight_management.cpp.

1238 {
1239 Logger::info("CPU-only build: ensure_f32_concatenated_weights_loaded is a no-op");
1240}

References Logger::info().

◆ ensure_gate_proj_dequantized()

void TinyLlamaModel::ensure_gate_proj_dequantized ( int  layer_idx)

Definition at line 198 of file weight_management.cpp.

198 {
199 if (layer_idx < 0 || layer_idx >= layers.size()) return;
200 auto& lw = layers[layer_idx];
201 if (!lw.gate_proj_f32.empty()) return;
202
203 int hs = config_.hidden_size;
205 size_t gate_proj_elements = static_cast<size_t>(is) * hs;
206
207 if (!lw.gate_proj_q6k.empty()) dequantize_vector_q6k_to_f32(lw.gate_proj_q6k, lw.gate_proj_f32, gate_proj_elements, 0);
208 else if (!lw.gate_proj_q4k.empty()) dequantize_vector_q4k_to_f32(lw.gate_proj_q4k, lw.gate_proj_f32, gate_proj_elements, 0);
209 else if (!lw.gate_proj_q5k.empty()) dequantize_vector_q5k_to_f32(lw.gate_proj_q5k, lw.gate_proj_f32, gate_proj_elements);
210 else if (!lw.gate_proj_q8k.empty()) dequantize_q8_k(lw.gate_proj_q8k, lw.gate_proj_f32, gate_proj_elements, false);
211 else if (!lw.gate_proj_q8_0.empty()) dequantize_vector_q8_0_to_f32(lw.gate_proj_q8_0, lw.gate_proj_f32, gate_proj_elements, 0);
212 else if (!lw.gate_proj.empty()) lw.gate_proj_f32 = bf16vec_to_float_vec(lw.gate_proj);
213}

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, ModelConfig::intermediate_size, j, and layers.

Referenced by dequantize_all_if_small(), forward(), CPUBatchProcessor::forward_cpu_batch(), and forward_cpu_batch_generation().

◆ ensure_k_proj_dequantized()

void TinyLlamaModel::ensure_k_proj_dequantized ( int  layer_idx)

Definition at line 150 of file weight_management.cpp.

150 {
151 if (layer_idx < 0 || layer_idx >= layers.size()) return;
152 auto& lw = layers[layer_idx];
153 if (!lw.k_proj_f32.empty()) return;
154
155 int hs = config_.hidden_size;
156 size_t k_proj_elements = static_cast<size_t>(config_.num_key_value_heads * (hs / config_.num_attention_heads)) * hs;
157
158 if (!lw.k_proj_q6k.empty()) dequantize_vector_q6k_to_f32(lw.k_proj_q6k, lw.k_proj_f32, k_proj_elements, 0);
159 else if (!lw.k_proj_q4k.empty()) dequantize_vector_q4k_to_f32(lw.k_proj_q4k, lw.k_proj_f32, k_proj_elements, 0);
160 else if (!lw.k_proj_q5k.empty()) dequantize_vector_q5k_to_f32(lw.k_proj_q5k, lw.k_proj_f32, k_proj_elements);
161 else if (!lw.k_proj_q8k.empty()) dequantize_q8_k(lw.k_proj_q8k, lw.k_proj_f32, k_proj_elements, false);
162 else if (!lw.k_proj_q8_0.empty()) dequantize_vector_q8_0_to_f32(lw.k_proj_q8_0, lw.k_proj_f32, k_proj_elements, 0);
163 else if (!lw.k_proj.empty()) lw.k_proj_f32 = bf16vec_to_float_vec(lw.k_proj);
164}

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, j, layers, ModelConfig::num_attention_heads, and ModelConfig::num_key_value_heads.

Referenced by dequantize_all_if_small(), forward(), CPUBatchProcessor::forward_cpu_batch(), and forward_cpu_batch_generation().

◆ ensure_layer_weights_on_gpu()

void TinyLlamaModel::ensure_layer_weights_on_gpu ( int  layer_idx)

◆ ensure_lm_head_dequantized()

void TinyLlamaModel::ensure_lm_head_dequantized ( )

Definition at line 77 of file weight_management.cpp.

77 {
78 if (!this->lm_head_f32.empty()) return;
79
80 size_t total_elements_lm_head = static_cast<size_t>(config_.vocab_size) * config_.hidden_size;
81 if (!this->lm_head_q6k.empty()) {
83 } else if (!this->lm_head_q4k.empty()) {
85 } else if (!this->lm_head_q5k.empty()) {
87 } else if (!this->lm_head_q8k.empty()) {
89 } else if (!this->lm_head_q8_0.empty()) {
91 } else if (!this->lm_head.empty()) {
93 }
94}
std::vector< uint16_t > lm_head
Definition model.h:579

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, j, lm_head, lm_head_f32, lm_head_q4k, lm_head_q5k, lm_head_q6k, lm_head_q8_0, lm_head_q8k, and ModelConfig::vocab_size.

Referenced by dequantize_all_if_small(), forward(), forward_cpu_logits_batch(), and initialize_gpu_and_rope().

◆ ensure_o_proj_dequantized()

void TinyLlamaModel::ensure_o_proj_dequantized ( int  layer_idx)

Definition at line 182 of file weight_management.cpp.

182 {
183 if (layer_idx < 0 || layer_idx >= layers.size()) return;
184 auto& lw = layers[layer_idx];
185 if (!lw.o_proj_f32.empty()) return;
186
187 int hs = config_.hidden_size;
188 size_t o_proj_elements = static_cast<size_t>(hs) * hs;
189
190 if (!lw.o_proj_q6k.empty()) dequantize_vector_q6k_to_f32(lw.o_proj_q6k, lw.o_proj_f32, o_proj_elements, 0);
191 else if (!lw.o_proj_q4k.empty()) dequantize_vector_q4k_to_f32(lw.o_proj_q4k, lw.o_proj_f32, o_proj_elements, 0);
192 else if (!lw.o_proj_q5k.empty()) dequantize_vector_q5k_to_f32(lw.o_proj_q5k, lw.o_proj_f32, o_proj_elements);
193 else if (!lw.o_proj_q8k.empty()) dequantize_q8_k(lw.o_proj_q8k, lw.o_proj_f32, o_proj_elements, false);
194 else if (!lw.o_proj_q8_0.empty()) dequantize_vector_q8_0_to_f32(lw.o_proj_q8_0, lw.o_proj_f32, o_proj_elements, 0);
195 else if (!lw.o_proj.empty()) lw.o_proj_f32 = bf16vec_to_float_vec(lw.o_proj);
196}

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, j, and layers.

Referenced by dequantize_all_if_small(), forward(), CPUBatchProcessor::forward_cpu_batch(), and forward_cpu_batch_generation().

◆ ensure_q_proj_dequantized()

void TinyLlamaModel::ensure_q_proj_dequantized ( int  layer_idx)

Definition at line 96 of file weight_management.cpp.

96 {
97 if (layer_idx < 0 || layer_idx >= layers.size()) return;
98 auto& lw = layers[layer_idx];
99 if (!lw.q_proj_f32.empty()) return;
100
101 int hs = config_.hidden_size;
102 size_t q_proj_elements = static_cast<size_t>(hs) * hs;
103 Logger::info("[DEQUANT_MEM] Layer " + std::to_string(layer_idx) + ": Q-proj dequantization starting, elements=" + std::to_string(q_proj_elements));
104
105 if (!lw.q_proj_q6k.empty()) dequantize_vector_q6k_to_f32(lw.q_proj_q6k, lw.q_proj_f32, q_proj_elements, 0);
106 else if (!lw.q_proj_q4k.empty()) dequantize_vector_q4k_to_f32(lw.q_proj_q4k, lw.q_proj_f32, q_proj_elements, 0);
107 else if (!lw.q_proj_q5k.empty()) dequantize_vector_q5k_to_f32(lw.q_proj_q5k, lw.q_proj_f32, q_proj_elements);
108 else if (!lw.q_proj_q8k.empty()) dequantize_q8_k(lw.q_proj_q8k, lw.q_proj_f32, q_proj_elements, true);
109 else if (!lw.q_proj_q8_0.empty()) dequantize_vector_q8_0_to_f32(lw.q_proj_q8_0, lw.q_proj_f32, q_proj_elements, 0);
110 else if (!lw.q_proj.empty()) lw.q_proj_f32 = bf16vec_to_float_vec(lw.q_proj);
111
112 Logger::info("[DEQUANT_MEM] Layer " + std::to_string(layer_idx) + ": Q-proj dequantization completed, f32 size=" + std::to_string(lw.q_proj_f32.size()));
113}

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, Logger::info(), j, and layers.

Referenced by dequantize_all_if_small(), forward(), CPUBatchProcessor::forward_cpu_batch(), and forward_cpu_batch_generation().

◆ ensure_up_proj_dequantized()

void TinyLlamaModel::ensure_up_proj_dequantized ( int  layer_idx)

Definition at line 215 of file weight_management.cpp.

215 {
216 if (layer_idx < 0 || layer_idx >= layers.size()) return;
217 auto& lw = layers[layer_idx];
218 if (!lw.up_proj_f32.empty()) return;
219
220 int hs = config_.hidden_size;
222 size_t up_proj_elements = static_cast<size_t>(is) * hs;
223
224 if (!lw.up_proj_q6k.empty()) dequantize_vector_q6k_to_f32(lw.up_proj_q6k, lw.up_proj_f32, up_proj_elements, 0);
225 else if (!lw.up_proj_q4k.empty()) dequantize_vector_q4k_to_f32(lw.up_proj_q4k, lw.up_proj_f32, up_proj_elements, 0);
226 else if (!lw.up_proj_q5k.empty()) dequantize_vector_q5k_to_f32(lw.up_proj_q5k, lw.up_proj_f32, up_proj_elements);
227 else if (!lw.up_proj_q8k.empty()) dequantize_q8_k(lw.up_proj_q8k, lw.up_proj_f32, up_proj_elements, false);
228 else if (!lw.up_proj_q8_0.empty()) dequantize_vector_q8_0_to_f32(lw.up_proj_q8_0, lw.up_proj_f32, up_proj_elements, 0);
229 else if (!lw.up_proj.empty()) lw.up_proj_f32 = bf16vec_to_float_vec(lw.up_proj);
230}

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, ModelConfig::intermediate_size, j, and layers.

Referenced by dequantize_all_if_small(), forward(), CPUBatchProcessor::forward_cpu_batch(), and forward_cpu_batch_generation().

◆ ensure_v_proj_dequantized()

void TinyLlamaModel::ensure_v_proj_dequantized ( int  layer_idx)

Definition at line 166 of file weight_management.cpp.

166 {
167 if (layer_idx < 0 || layer_idx >= layers.size()) return;
168 auto& lw = layers[layer_idx];
169 if (!lw.v_proj_f32.empty()) return;
170
171 int hs = config_.hidden_size;
172 size_t v_proj_elements = static_cast<size_t>(config_.num_key_value_heads * (hs / config_.num_attention_heads)) * hs;
173
174 if (!lw.v_proj_q6k.empty()) dequantize_vector_q6k_to_f32(lw.v_proj_q6k, lw.v_proj_f32, v_proj_elements, 0);
175 else if (!lw.v_proj_q4k.empty()) dequantize_vector_q4k_to_f32(lw.v_proj_q4k, lw.v_proj_f32, v_proj_elements, 0);
176 else if (!lw.v_proj_q5k.empty()) dequantize_vector_q5k_to_f32(lw.v_proj_q5k, lw.v_proj_f32, v_proj_elements);
177 else if (!lw.v_proj_q8k.empty()) dequantize_q8_k(lw.v_proj_q8k, lw.v_proj_f32, v_proj_elements, false);
178 else if (!lw.v_proj_q8_0.empty()) dequantize_vector_q8_0_to_f32(lw.v_proj_q8_0, lw.v_proj_f32, v_proj_elements, 0);
179 else if (!lw.v_proj.empty()) lw.v_proj_f32 = bf16vec_to_float_vec(lw.v_proj);
180}

References bf16vec_to_float_vec(), config_, dequantize_q8_k(), dequantize_vector_q4k_to_f32(), dequantize_vector_q5k_to_f32(), dequantize_vector_q6k_to_f32(), dequantize_vector_q8_0_to_f32(), ModelConfig::hidden_size, j, layers, ModelConfig::num_attention_heads, and ModelConfig::num_key_value_heads.

Referenced by dequantize_all_if_small(), forward(), CPUBatchProcessor::forward_cpu_batch(), and forward_cpu_batch_generation().

◆ forward()

std::vector< float > TinyLlamaModel::forward ( std::vector< float > &  input,
int  n_tokens,
KVCache *  kv_cache,
const std::vector< int > *  attention_mask 
)

Run the forward pass for the model on CPU layers.

Parameters
inputInput vector (modified in-place).
n_tokensCurrent token position.
kv_cachePointer to the key-value cache.
attention_maskOptional attention mask.
Returns
Output logits or intermediate activations.

Definition at line 595 of file model.cpp.

598 {
599 Logger::info("[CPU_FWD] Entered. Processing up to layer " + std::to_string(config_.num_cpu_offload_layers -1) + ". Input n_tokens: " + std::to_string(n_tokens));
600
601 int hs = config_.hidden_size;
602 int vs = config_.vocab_size;
606 int head_dim = hs / n_heads;
607 float eps = config_.rms_norm_eps;
609
610 bool log_first_gen_step = (n_tokens == 0);
611 bool log_this_step = log_first_gen_step || (n_tokens == 12) || (n_tokens == 13);
612
613 // Layer processing loop - ONLY for CPU-offloaded layers
614 for (int l = 0; l < config_.num_cpu_offload_layers; ++l) {
615 Logger::info("[CPU_FWD_MEM] Starting layer " + std::to_string(l) + " processing");
616
617 bool log_this_layer = log_this_step && (l == 0); // Log details only for layer 0 on specific steps
618 if (log_this_layer) {
619 Logger::info("[CPU_FWD] ------ START Layer " + std::to_string(l) +
620 " (pos=" + std::to_string(n_tokens) + ") ------");
621 log_vector_summary("Layer " + std::to_string(l) + " Input (input)", input);
622 }
623
624 const auto& lw = layers[l];
625 std::vector<float> x_norm_vec1(hs);
626 const std::vector<float>& w_input_norm_vec =
627 lw.input_layernorm_f32.empty()
628 ? bf16vec_to_float_vec(lw.input_layernorm)
629 : lw.input_layernorm_f32;
631 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": Allocating QKV vectors");
632 std::vector<float> q_vec(hs), k_vec(n_kv_heads * head_dim), v_vec(n_kv_heads * head_dim);
633 bool enable_debug_logging = (l == 0);
634 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": About to ensure_q_proj_dequantized");
636 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": ensure_q_proj_dequantized completed");
637 if (!lw.q_proj_f32.empty()) matvec_f32_f32_vector_cpu(lw.q_proj_f32, x_norm_vec1, q_vec, hs, hs);
638 else if (!lw.q_proj_q8k.empty() && config_.is_gguf_file_loaded) matvec_q8k_f32_vector_cpu(lw.q_proj_q8k, x_norm_vec1, q_vec, hs, hs, enable_debug_logging);
639 else if (!lw.q_proj_q8_0.empty() && config_.is_gguf_file_loaded) matvec_q8_0_f32_vector_cpu(lw.q_proj_q8_0, x_norm_vec1, q_vec, hs, hs, enable_debug_logging);
640 else if (!lw.q_proj_q4k.empty() && config_.is_gguf_file_loaded) matvec_q4k_f32_vector_cpu(lw.q_proj_q4k, x_norm_vec1, q_vec, hs, hs, enable_debug_logging);
641 else if (!lw.q_proj_q6k.empty() && config_.is_gguf_file_loaded) matvec_q6k_f32_vector_cpu(lw.q_proj_q6k, x_norm_vec1, q_vec, hs, hs, enable_debug_logging);
642 else if (!lw.q_proj.empty()) matvec_bf16_f32_vector_cpu(lw.q_proj, x_norm_vec1, q_vec, hs, hs); // BF16 from SafeTensors
643 else throw std::runtime_error("Layer " + std::to_string(l) + ": No Q proj weights (f32, q8k, q8, q4k, q6k, bf16) for CPU");
644
645 // ... K, V projections ...
646 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": About to ensure_k_proj_dequantized");
648 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": ensure_k_proj_dequantized completed");
649 if (!lw.k_proj_f32.empty()) matvec_f32_f32_vector_cpu(lw.k_proj_f32, x_norm_vec1, k_vec, n_kv_heads * head_dim, hs);
654 else if (!lw.k_proj.empty()) matvec_bf16_f32_vector_cpu(lw.k_proj, x_norm_vec1, k_vec, n_kv_heads * head_dim, hs);
655 else throw std::runtime_error("Layer " + std::to_string(l) + ": No K proj weights (f32, q8k, q8, q4k, q6k, bf16) for CPU");
656
657 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": About to ensure_v_proj_dequantized");
659 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": ensure_v_proj_dequantized completed");
660 if (!lw.v_proj_f32.empty()) matvec_f32_f32_vector_cpu(lw.v_proj_f32, x_norm_vec1, v_vec, n_kv_heads * head_dim, hs);
665 else if (!lw.v_proj.empty()) matvec_bf16_f32_vector_cpu(lw.v_proj, x_norm_vec1, v_vec, n_kv_heads * head_dim, hs);
666 else throw std::runtime_error("Layer " + std::to_string(l) + ": No V proj weights (f32, q8k, q8, q4k, q6k, bf16) for CPU");
667
670 if (kv_cache) {
671 if (static_cast<size_t>(l) < kv_cache->layers.size()) {
672 KVCacheLayer& kv_layer = kv_cache->layers[l];
673 size_t layer_max_seq_len = static_cast<size_t>(kv_cache->max_seq_len_config_);
674 if (static_cast<size_t>(n_tokens) >= layer_max_seq_len && layer_max_seq_len > 0) {
675 Logger::error("KV Cache access out of bounds in CPU forward. Layer " + std::to_string(l) +
676 ", n_tokens: " + std::to_string(n_tokens) +
677 ", configured layer_max_seq_len: " + std::to_string(layer_max_seq_len) + ". Skipping KV update.");
678 } else if (layer_max_seq_len == 0 && n_tokens > 0) {
679 Logger::error("KV Cache layer_max_seq_len is 0, but n_tokens > 0. Layer " + std::to_string(l) + ". Skipping KV update.");
680 } else {
681 for(int h=0; h < n_kv_heads; ++h) {
682 std::copy(k_vec.begin() + h * head_dim, k_vec.begin() + (h+1) * head_dim, kv_layer.k.begin() + n_tokens * (n_kv_heads * head_dim) + h * head_dim);
683 std::copy(v_vec.begin() + h * head_dim, v_vec.begin() + (h+1) * head_dim, kv_layer.v.begin() + n_tokens * (n_kv_heads * head_dim) + h * head_dim);
684 }
685 }
686 } else {
687 Logger::error("KV Cache layer index " + std::to_string(l) + " out of bounds for kv_cache->layers.size() = " + std::to_string(kv_cache->layers.size()));
688 }
689 }
690
691 std::vector<float> attn_out_vec(hs);
692 std::vector<float> x_resid1_vec = input; // Store residual
693 float att_scale = 1.0f / std::sqrt(static_cast<float>(head_dim));
694 std::fill(attn_out_vec.begin(), attn_out_vec.end(), 0.0f);
695 for (int h = 0; h < n_heads; ++h) {
696 std::vector<float> q_head(head_dim);
697 std::copy(q_vec.begin() + h * head_dim, q_vec.begin() + (h + 1) * head_dim, q_head.begin());
698 std::vector<float> current_multihead_attn_out(head_dim, 0.0f);
699 int kv_cache_num_kv_heads = n_kv_heads; // from KVCache struct if available
701 int kv_head_idx = h / kv_group;
702
703 if (kv_cache && static_cast<size_t>(l) < kv_cache->layers.size()) {
704 const KVCacheLayer& kv_layer = kv_cache->layers[l];
705 int current_seq_len = n_tokens + 1;
706 std::vector<float> scores(current_seq_len);
707 for (int t = 0; t < current_seq_len; ++t) {
708 float score = 0.0f;
709 for (int d = 0; d < head_dim; ++d) {
710 score += q_head[d] * kv_layer.k[t * (n_kv_heads * head_dim) + kv_head_idx * head_dim + d];
711 }
712 scores[t] = score * att_scale;
713 }
714 softmax_vector_cpu(scores, scores); // In-place softmax
715 for (int t = 0; t < current_seq_len; ++t) {
716 for (int d = 0; d < head_dim; ++d) {
718 }
719 }
720 }
721 std::copy(current_multihead_attn_out.begin(), current_multihead_attn_out.end(), attn_out_vec.begin() + h * head_dim);
722 }
723
724
725 std::vector<float> attn_proj_vec(hs);
726 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": About to ensure_o_proj_dequantized");
728 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": ensure_o_proj_dequantized completed");
729 if(!lw.o_proj_f32.empty()) matvec_f32_f32_vector_cpu(lw.o_proj_f32, attn_out_vec, attn_proj_vec, hs, hs);
734 else if(!lw.o_proj.empty()) matvec_bf16_f32_vector_cpu(lw.o_proj, attn_out_vec, attn_proj_vec, hs, hs);
735 else throw std::runtime_error("Layer " + std::to_string(l) + ": No O proj weights (f32, q8k, q8, q4k, q6k, bf16) for CPU");
736
737 for(size_t i=0; i<input.size(); ++i) input[i] = x_resid1_vec[i] + attn_proj_vec[i]; // Update input by reference
738
739 // MLP part
740 std::vector<float> x_norm_vec2(hs);
741 std::vector<float> x_resid2_vec = input; // Store residual for MLP
742 const std::vector<float>& w_post_attn_norm_vec =
743 lw.post_attention_layernorm_f32.empty()
744 ? bf16vec_to_float_vec(lw.post_attention_layernorm)
745 : lw.post_attention_layernorm_f32;
747
748 std::vector<float> mlp_out_vec(hs);
749 if (config_.num_experts > 0 && !lw.moe_gate_exps_f32.empty()) {
750 // Mixture-of-experts FFN (utils.cpp moe_ffn_f32_cpu).
752 lw.moe_router_f32.data(), lw.moe_gate_exps_f32.data(), lw.moe_up_exps_f32.data(),
753 lw.moe_down_exps_f32.data(), mlp_out_vec.data());
754 } else {
755 std::vector<float> gate_vec(is), up_vec(is);
756 // Gate-projection
757 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": About to ensure_gate_proj_dequantized");
759 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": ensure_gate_proj_dequantized completed");
760 if(!lw.gate_proj_f32.empty()) matvec_f32_f32_vector_cpu(lw.gate_proj_f32, x_norm_vec2, gate_vec, is, hs);
761 else if (!lw.gate_proj_q8k.empty() && config_.is_gguf_file_loaded) matvec_q8k_f32_vector_cpu(lw.gate_proj_q8k, x_norm_vec2, gate_vec, is, hs, enable_debug_logging);
762 else if (!lw.gate_proj_q8_0.empty() && config_.is_gguf_file_loaded) matvec_q8_0_f32_vector_cpu(lw.gate_proj_q8_0, x_norm_vec2, gate_vec, is, hs, enable_debug_logging);
763 else if (!lw.gate_proj_q4k.empty() && config_.is_gguf_file_loaded) matvec_q4k_f32_vector_cpu(lw.gate_proj_q4k, x_norm_vec2, gate_vec, is, hs, enable_debug_logging);
764 else if (!lw.gate_proj_q6k.empty() && config_.is_gguf_file_loaded) matvec_q6k_f32_vector_cpu(lw.gate_proj_q6k, x_norm_vec2, gate_vec, is, hs, enable_debug_logging);
765 else if(!lw.gate_proj.empty()) matvec_bf16_f32_vector_cpu(lw.gate_proj, x_norm_vec2, gate_vec, is, hs);
766 else throw std::runtime_error("Layer " + std::to_string(l) + ": No Gate proj weights (f32, q8k, q8, q4k, q6k, bf16) for CPU");
767
768 // Up-projection
769 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": About to ensure_up_proj_dequantized");
771 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": ensure_up_proj_dequantized completed");
772 if(!lw.up_proj_f32.empty()) matvec_f32_f32_vector_cpu(lw.up_proj_f32, x_norm_vec2, up_vec, is, hs);
773 else if (!lw.up_proj_q8k.empty() && config_.is_gguf_file_loaded) matvec_q8k_f32_vector_cpu(lw.up_proj_q8k, x_norm_vec2, up_vec, is, hs, enable_debug_logging);
774 else if (!lw.up_proj_q8_0.empty() && config_.is_gguf_file_loaded) matvec_q8_0_f32_vector_cpu(lw.up_proj_q8_0, x_norm_vec2, up_vec, is, hs, enable_debug_logging);
775 else if (!lw.up_proj_q4k.empty() && config_.is_gguf_file_loaded) matvec_q4k_f32_vector_cpu(lw.up_proj_q4k, x_norm_vec2, up_vec, is, hs, enable_debug_logging);
776 else if (!lw.up_proj_q6k.empty() && config_.is_gguf_file_loaded) matvec_q6k_f32_vector_cpu(lw.up_proj_q6k, x_norm_vec2, up_vec, is, hs, enable_debug_logging);
777 else if(!lw.up_proj.empty()) matvec_bf16_f32_vector_cpu(lw.up_proj, x_norm_vec2, up_vec, is, hs);
778 else throw std::runtime_error("Layer " + std::to_string(l) + ": No Up proj weights (f32, q8k, q8, q4k, q6k, bf16) for CPU");
779
780 // Activation dispatch based on config_.hidden_act
781 std::vector<float> activation_out_vec(is);
782 std::vector<float> mlp_intermediate_vec(is);
783
784 if (config_.hidden_act == "gelu" || config_.hidden_act == "gelu_new" ||
785 config_.hidden_act == "gelu_fast" || config_.hidden_act == "gelu_pytorch_tanh") {
786 // GELU-based activation (Phi models) - no gate projection, just up_proj with GELU
787 // Note: For true Phi support, we'd need to handle missing gate_proj differently
788 // For now, treat as GeGLU (GELU + gate) if gate_proj exists
789 if (!lw.gate_proj_f32.empty() || !lw.gate_proj_q8_0.empty() || !lw.gate_proj_q4k.empty() ||
790 !lw.gate_proj_q6k.empty() || !lw.gate_proj_q8k.empty() || !lw.gate_proj.empty()) {
791 // GeGLU: GELU(gate) * up
793 for(size_t i=0; i<is; ++i) mlp_intermediate_vec[i] = activation_out_vec[i] * up_vec[i];
794 } else {
795 // Standard GELU without gating (true Phi-style)
797 }
798 } else {
799 // Default: SiLU/SwiGLU activation (Llama/Mistral models)
801 for(size_t i=0; i<is; ++i) mlp_intermediate_vec[i] = activation_out_vec[i] * up_vec[i];
802 }
803
804 // Down-projection
805 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": About to ensure_down_proj_dequantized");
807 Logger::info("[CPU_FWD_MEM] Layer " + std::to_string(l) + ": ensure_down_proj_dequantized completed");
808 if(!lw.down_proj_f32.empty()) matvec_f32_f32_vector_cpu(lw.down_proj_f32, mlp_intermediate_vec, mlp_out_vec, hs, is);
813 else if(!lw.down_proj.empty()) matvec_bf16_f32_vector_cpu(lw.down_proj, mlp_intermediate_vec, mlp_out_vec, hs, is);
814 else throw std::runtime_error("Layer " + std::to_string(l) + ": No Down proj weights (f32, q8k, q8, q4k, q6k, bf16) for CPU");
815 } // dense FFN
816
817 for(size_t i=0; i<input.size(); ++i) input[i] = x_resid2_vec[i] + mlp_out_vec[i]; // Update input by reference
818
819 // TINYLLAMA_LAYER_TRACE=1: per-sub-op L2s, format-matched to the
820 // trainer's TCPP_LAYER_TRACE [SUBOP] lines — diff the two on identical
821 // tokens to localize CPU-forward divergence (golden-batch suite).
822 if (std::getenv("TINYLLAMA_LAYER_TRACE") != nullptr) {
823 auto l2 = [](const std::vector<float>& v) {
824 double s = 0.0;
825 for (float x : v) s += double(x) * x;
826 return std::sqrt(s);
827 };
828 fprintf(stderr, "[ENG_SUBOP] L%d pos=%d ln1=%g Vraw=%g attnout=%g attn=%g res1=%g ln2=%g ffn=%g out=%g\n",
830 l2(x_norm_vec2), l2(mlp_out_vec), l2(input));
831 }
832
833 if (log_this_layer) {
834 Logger::info("[CPU_FWD] ------ END Layer " + std::to_string(l) +
835 " (pos=" + std::to_string(n_tokens) + ") ------");
836 }
838 int layer_to_clear = l - 2;
842 }
843 }
844 }
845
847 Logger::info("[CPU_FWD] All layers processed on CPU. Performing final RMSNorm and Logits.");
848 const std::vector<float>& w_final_norm_vec =
851 std::vector<float> x_final_norm_vec(hs);
853
854 std::vector<float> logits(vs);
856 bool enable_lm_head_debug_logging = true; // Always log LM head for debugging
862 else if (!lm_head.empty()) matvec_bf16_f32_vector_cpu(lm_head, x_final_norm_vec, logits, vs, hs); // Fallback for BF16 SafeTensors
863 else throw std::runtime_error("No valid LM Head weights (f32, q8k, q8, q4k, q6k, bf16) found for CPU final stage.");
864
866 log_vector_summary("[CPU_FWD] Final Logits (all CPU, pos=" + std::to_string(n_tokens) + ")", logits, 15);
867 }
868 return logits; // Return final logits if all layers were CPU
869 }
870
871 Logger::info("[CPU_FWD] Finished processing " + std::to_string(config_.num_cpu_offload_layers) + " CPU layers. Output is intermediate activation.");
872 return input; // Return the intermediate activations if not all layers were processed here.
873}
std::vector< float > final_norm_f32
Definition model.h:581
std::vector< uint16_t > final_norm
Definition model.h:580
std::vector< std::pair< float, float > > precomputed_freqs_cis_
Definition model.h:694
void clear_layer_dequantized_weights(int layer_idx)
std::vector< float > v
void log_vector_summary(const std::string &name, const std::vector< float > &v, int head_count=5)
Definition utils.cpp:208
Key-Value cache for a single transformer layer.
Definition model.h:136
float rms_norm_eps
Definition model.h:90
bool enable_memory_efficient_layers
Definition model.h:111
int num_experts_used
Definition model.h:108
int num_experts
Definition model.h:107
std::string hidden_act
Definition model.h:92
void apply_rope_vector(std::vector< float > &x, int num_heads, int head_dim, int current_token_pos, const std::vector< std::pair< float, float > > &all_freqs_cis, int max_pos_embeddings, bool use_adjacent_pairing)
Definition utils.cpp:428
void matvec_q8k_f32_vector_cpu(const std::vector< block_q8_K > &mat_q8k, const std::vector< float > &vec_f32, std::vector< float > &out_f32, int rows, int cols, bool log_first_block)
Definition utils.cpp:399
void matvec_q6k_f32_vector_cpu(const std::vector< block_q6_K > &mat_q6k, const std::vector< float > &vec_f32, std::vector< float > &out_f32, int rows, int cols, bool log_first_block)
Definition utils.cpp:930
void matvec_bf16_f32_vector_cpu(const std::vector< uint16_t > &mat_bf16, const std::vector< float > &vec_f32, std::vector< float > &out_f32, int rows, int cols)
Definition utils.cpp:1192
void matvec_f32_f32_vector_cpu(const std::vector< float > &mat_f32, const std::vector< float > &vec_f32, std::vector< float > &out_f32, int rows, int cols)
Definition utils.cpp:365
void softmax_vector_cpu(const std::vector< float > &x, std::vector< float > &out)
Definition utils.cpp:675
void matvec_q4k_f32_vector_cpu(const std::vector< block_q4_K > &mat_q4k, const std::vector< float > &vec_f32, std::vector< float > &out_f32, int rows, int cols, bool log_first_block)
Definition utils.cpp:983
void gelu_new_cpu(const std::vector< float > &x, std::vector< float > &out)
Definition utils.cpp:860
void silu_cpu(const std::vector< float > &x, std::vector< float > &out)
Definition utils.cpp:842
void moe_ffn_f32_cpu(const float *x, int d, int d_ff, int E, int k, const float *router, const float *gate_exps, const float *up_exps, const float *down_exps, float *out, bool renorm)
Definition utils.cpp:709
void rmsnorm_vector_cpu(const std::vector< float > &x, const std::vector< float > &weight, std::vector< float > &out, float eps)
Definition utils.cpp:648
void matvec_q8_0_f32_vector_cpu(const std::vector< block_q8_0 > &mat_q8_0, const std::vector< float > &vec_f32, std::vector< float > &out_f32, int rows, int cols, bool log_first_block)
Definition utils.cpp:294

References apply_rope_vector(), bf16vec_to_float_vec(), clear_layer_dequantized_weights(), config_, ModelConfig::enable_memory_efficient_layers, ensure_down_proj_dequantized(), ensure_gate_proj_dequantized(), ensure_k_proj_dequantized(), ensure_lm_head_dequantized(), ensure_o_proj_dequantized(), ensure_q_proj_dequantized(), ensure_up_proj_dequantized(), ensure_v_proj_dequantized(), Logger::error(), final_norm, final_norm_f32, gelu_new_cpu(), ModelConfig::hidden_act, ModelConfig::hidden_size, Logger::info(), ModelConfig::intermediate_size, ModelConfig::is_gguf_file_loaded, j, layers, lm_head, lm_head_f32, lm_head_q4k, lm_head_q6k, lm_head_q8_0, lm_head_q8k, log_vector_summary(), matvec_bf16_f32_vector_cpu(), matvec_f32_f32_vector_cpu(), matvec_q4k_f32_vector_cpu(), matvec_q6k_f32_vector_cpu(), matvec_q8_0_f32_vector_cpu(), matvec_q8k_f32_vector_cpu(), ModelConfig::max_position_embeddings, moe_ffn_f32_cpu(), ModelConfig::num_attention_heads, ModelConfig::num_cpu_offload_layers, ModelConfig::num_experts, ModelConfig::num_experts_used, ModelConfig::num_hidden_layers, ModelConfig::num_key_value_heads, precomputed_freqs_cis_, ModelConfig::rms_norm_eps, rmsnorm_vector_cpu(), silu_cpu(), softmax_vector_cpu(), v, and ModelConfig::vocab_size.

◆ forward_cpu_batch()

std::vector< float > TinyLlamaModel::forward_cpu_batch ( const std::vector< float > &  batch_input_activations,
int  num_tokens_in_batch,
int  num_cpu_layers_to_process,
int  start_pos_in_sequence,
KVCache *  kv_cache,
const std::vector< int > &  prompt_lengths = {} 
)

Definition at line 2498 of file model.cpp.

2504 {
2505
2506 if (!cpu_batch_processor_) {
2507 cpu_batch_processor_ = std::make_unique<CPUBatchProcessor>(this);
2508 }
2509
2510 return cpu_batch_processor_->forward_cpu_batch(
2515 kv_cache,
2517 );
2518}
std::unique_ptr< class CPUBatchProcessor > cpu_batch_processor_
Definition model.h:701

References cpu_batch_processor_, and j.

◆ forward_cpu_batch_generation()

std::vector< std::vector< float > > TinyLlamaModel::forward_cpu_batch_generation ( const std::vector< float > &  batch_input_activations,
const std::vector< int > &  token_positions,
const std::vector< int > &  original_sequence_indices,
int  num_tokens_in_batch,
KVCache *  kv_cache 
)

Definition at line 1395 of file model.cpp.

1400 {
1401
1402 Logger::info("[CPU_BATCH_GEN] Entry: num_tokens=" + std::to_string(num_tokens_in_batch));
1403 std::string pos_str = "token_positions=[";
1404 for (int i = 0; i < std::min(num_tokens_in_batch, 3); ++i) {
1405 pos_str += std::to_string(token_positions[i]) + " ";
1406 }
1407 pos_str += "]";
1408 std::string seq_str = "original_sequence_indices=[";
1409 for (int i = 0; i < std::min(num_tokens_in_batch, 3); ++i) {
1410 seq_str += std::to_string(original_sequence_indices[i]) + " ";
1411 }
1412 seq_str += "]";
1413 Logger::info("[CPU_BATCH_GEN] " + pos_str + ", " + seq_str);
1415 Logger::error("[CPU_BATCH_GENERATION] batch_input_activations size mismatch. Expected: " +
1416 std::to_string((size_t)num_tokens_in_batch * config_.hidden_size) + " Got: " +
1417 std::to_string(batch_input_activations.size()));
1418 return {};
1419 }
1420
1421 if (token_positions.size() != static_cast<size_t>(num_tokens_in_batch)) {
1422 Logger::error("[CPU_BATCH_GENERATION] token_positions size mismatch. Expected: " +
1423 std::to_string(num_tokens_in_batch) + " Got: " + std::to_string(token_positions.size()));
1424 return {};
1425 }
1426
1427 int hs = config_.hidden_size;
1431 if (n_heads == 0) {
1432 Logger::error("[CPU_BATCH_GENERATION] Error: num_attention_heads is zero.");
1433 return {};
1434 }
1435 int head_dim = hs / n_heads;
1436 float eps = config_.rms_norm_eps;
1439 float attention_scale = 1.0f / SAFE_SQRT(static_cast<float>(head_dim));
1440 int vs = config_.vocab_size;
1441 int kv_group = n_heads / n_kv_heads; // Pre-calculate GQA grouping
1442
1444 for (int l = 0; l < config_.num_cpu_offload_layers; ++l) {
1445 const auto& lw = layers[l];
1446
1447 // Batch RMSNorm for attention
1448 std::vector<float> batch_x_norm1(current_batch_activations.size());
1449 const std::vector<float>& w_input_norm_vec =
1450 lw.input_layernorm_f32.empty()
1451 ? bf16vec_to_float_vec(lw.input_layernorm)
1452 : lw.input_layernorm_f32;
1454
1456
1457 // Batch Q, K, V projections
1458 std::vector<float> q_batch((size_t)num_tokens_in_batch * hs);
1459 std::vector<float> k_batch((size_t)num_tokens_in_batch * n_kv_heads * head_dim);
1460 std::vector<float> v_batch((size_t)num_tokens_in_batch * n_kv_heads * head_dim);
1461
1462 // Q Projection (batched)
1463 if (!lw.q_proj_f32.empty()) {
1465 } else if (!lw.q_proj_q8_0.empty()) {
1467 } else if (!lw.q_proj_q6k.empty()) {
1469 } else if (!lw.q_proj_q4k.empty()) {
1471 } else {
1472 Logger::error("[CPU_BATCH_GENERATION] Layer " + std::to_string(l) + ": No Q proj weights found for CPU (batched)");
1473 return {};
1474 }
1475
1476 // K Projection (batched)
1477 if (!lw.k_proj_f32.empty()) {
1479 } else if (!lw.k_proj_q8_0.empty()) {
1481 } else if (!lw.k_proj_q6k.empty()) {
1483 } else if (!lw.k_proj_q4k.empty()) {
1485 } else {
1486 Logger::error("[CPU_BATCH_GENERATION] Layer " + std::to_string(l) + ": No K proj weights found for CPU (batched)");
1487 return {};
1488 }
1489
1490 // V Projection (batched)
1491 if (!lw.v_proj_f32.empty()) {
1493 } else if (!lw.v_proj_q8_0.empty()) {
1495 } else if (!lw.v_proj_q6k.empty()) {
1497 } else if (!lw.v_proj_q4k.empty()) {
1499 } else {
1500 Logger::error("[CPU_BATCH_GENERATION] Layer " + std::to_string(l) + ": No V proj weights found for CPU (batched)");
1501 return {};
1502 }
1503
1504 // Optimized RoPE, KV cache update, and attention with OpenMP and SIMD
1505 std::vector<float> batch_attn_output((size_t)num_tokens_in_batch * hs);
1506
1507 // Ensure weights are dequantized before parallel processing
1515
1516 #pragma omp parallel if(num_tokens_in_batch > 1)
1517 {
1518 // Thread-local buffers to avoid allocations in loop
1519 std::vector<float> q_token(hs);
1520 std::vector<float> k_token(n_kv_heads * head_dim);
1521 std::vector<float> v_token(n_kv_heads * head_dim);
1522 std::vector<float> scores_buffer;
1523
1524 #pragma omp for
1525 for (int token_idx = 0; token_idx < num_tokens_in_batch; ++token_idx) {
1527
1528 // Extract Q, K, V for this token (reuse thread-local buffers)
1529 std::copy(q_batch.begin() + (size_t)token_idx * hs,
1530 q_batch.begin() + (size_t)(token_idx + 1) * hs,
1531 q_token.begin());
1532 std::copy(k_batch.begin() + (size_t)token_idx * n_kv_heads * head_dim,
1533 k_batch.begin() + (size_t)(token_idx + 1) * n_kv_heads * head_dim,
1534 k_token.begin());
1535 std::copy(v_batch.begin() + (size_t)token_idx * n_kv_heads * head_dim,
1536 v_batch.begin() + (size_t)(token_idx + 1) * n_kv_heads * head_dim,
1537 v_token.begin());
1538
1539 // Apply RoPE individually
1542
1543 // Update KV cache at specific position - Sequence-Major Layout
1544 if (kv_cache && static_cast<size_t>(l) < kv_cache->layers.size()) {
1545 auto& layer_cache = kv_cache->layers[l];
1546 // Use sequence-major layout to match prefill behavior
1548 int sequence_base_offset = seq_idx * kv_cache->max_seq_len_config_;
1550 #pragma omp critical
1551 {
1552 if (kv_offset + n_kv_heads * head_dim <= static_cast<int>(layer_cache.k.size())) {
1553 std::copy(k_token.begin(), k_token.end(), layer_cache.k.begin() + kv_offset);
1554 std::copy(v_token.begin(), v_token.end(), layer_cache.v.begin() + kv_offset);
1555 }
1556 }
1557 }
1558
1559 // Copy back RoPE'd Q values to batch
1560 std::copy(q_token.begin(), q_token.end(), q_batch.begin() + (size_t)token_idx * hs);
1561
1562 // SIMD-optimized attention computation for this token
1564 int history_len = (seq_idx < kv_cache->current_batch_size) ? kv_cache->batch_seq_lens[seq_idx] : pos + 1;
1565 scores_buffer.resize(history_len);
1566
1567 const float* q_token_ptr = q_batch.data() + (size_t)token_idx * hs;
1569
1570 if (kv_cache && static_cast<size_t>(l) < kv_cache->layers.size()) {
1571 const auto& layer_cache = kv_cache->layers[l];
1572
1573 // Process all heads for this token efficiently with SIMD
1574 for (int h = 0; h < n_heads; ++h) {
1575 int kv_head_idx = h / kv_group; // Use pre-calculated kv_group
1576 const float* q_head_ptr = q_token_ptr + h * head_dim;
1578
1579 // SIMD-optimized attention score computation
1580 for (int t = 0; t < history_len; ++t) {
1581 // sequence-major layout: each sequence has contiguous region
1583 int sequence_base_offset = seq_idx * kv_cache->max_seq_len_config_;
1584 const float* k_ptr = layer_cache.k.data() + (sequence_base_offset + t) * n_kv_heads * head_dim + kv_head_idx * head_dim;
1585
1586 // Use SIMD dot product for Q·K computation
1587#if defined(__AVX2__) || defined(__SSE2__) || defined(__ARM_NEON)
1588 float score = simd_dot_product(q_head_ptr, k_ptr, head_dim);
1589#else
1590 float score = 0.0f;
1591 for (int d = 0; d < head_dim; ++d) {
1592 score += q_head_ptr[d] * k_ptr[d];
1593 }
1594#endif
1595 scores_buffer[t] = score * attention_scale;
1596 }
1597
1598 // Softmax
1600
1601 // SIMD-optimized weighted sum with V
1602 std::fill(head_output_ptr, head_output_ptr + head_dim, 0.0f);
1603 for (int t = 0; t < history_len; ++t) {
1604 // Sequence-major layout: each sequence has contiguous region
1606 int sequence_base_offset = seq_idx * kv_cache->max_seq_len_config_;
1607 const float* v_ptr = layer_cache.v.data() + (sequence_base_offset + t) * n_kv_heads * head_dim + kv_head_idx * head_dim;
1608 float score = scores_buffer[t];
1609
1610 // Use SIMD scaled vector addition for score * V accumulation
1611#if defined(__AVX2__) || defined(__SSE2__) || defined(__ARM_NEON)
1613#else
1614 for (int d = 0; d < head_dim; ++d) {
1615 head_output_ptr[d] += score * v_ptr[d];
1616 }
1617#endif
1618 }
1619 }
1620 } else {
1621 std::fill(attn_output_ptr, attn_output_ptr + hs, 0.0f);
1622 }
1623 }
1624 }
1625 // O-Projection (batched)
1626 std::vector<float> batch_attn_proj_out((size_t)num_tokens_in_batch * hs);
1627 if(!lw.o_proj_f32.empty()) {
1629 } else if (!lw.o_proj_q8_0.empty()) {
1631 } else if (!lw.o_proj_q6k.empty()) {
1633 } else if (!lw.o_proj_q4k.empty()) {
1635 } else {
1636 Logger::error("[CPU_BATCH_GENERATION] Layer " + std::to_string(l) + ": No O proj weights found for CPU");
1637 return {};
1638 }
1639
1640 // First Residual Connection (batched)
1641 for(size_t i=0; i < current_batch_activations.size(); ++i) {
1643 }
1644
1645 // MLP processing (batched where possible)
1647 std::vector<float> batch_x_norm2(current_batch_activations.size());
1648
1649 const std::vector<float>& w_post_attn_norm_vec =
1650 lw.post_attention_layernorm_f32.empty()
1651 ? bf16vec_to_float_vec(lw.post_attention_layernorm)
1652 : lw.post_attention_layernorm_f32;
1654
1655 std::vector<float> batch_gate_proj_out((size_t)num_tokens_in_batch * is);
1656 std::vector<float> batch_up_proj_out((size_t)num_tokens_in_batch * is);
1657
1658 // Gate and Up projections (batched)
1659 if (!lw.gate_proj_f32.empty()) {
1661 } else if (!lw.gate_proj_q8_0.empty()) {
1663 } else if (!lw.gate_proj_q6k.empty()) {
1665 } else if (!lw.gate_proj_q4k.empty()) {
1667 } else {
1668 Logger::error("[CPU_BATCH_GENERATION] Layer " + std::to_string(l) + ": No gate_proj weights found for CPU");
1669 return {};
1670 }
1671
1672 if (!lw.up_proj_f32.empty()) {
1674 } else if (!lw.up_proj_q8_0.empty()) {
1676 } else if (!lw.up_proj_q6k.empty()) {
1678 } else if (!lw.up_proj_q4k.empty()) {
1680 } else {
1681 Logger::error("[CPU_BATCH_GENERATION] Layer " + std::to_string(l) + ": No up_proj weights found for CPU");
1682 return {};
1683 }
1684
1685 // SwiGLU (batched)
1686 std::vector<float> batch_swiglu_out((size_t)num_tokens_in_batch * is);
1687 for (size_t i = 0; i < batch_gate_proj_out.size(); ++i) {
1689 float silu_gate_val = gate_val / (1.0f + std::exp(-gate_val));
1691 }
1692
1693 // Down Projection (batched)
1694 std::vector<float> batch_mlp_down_proj_out((size_t)num_tokens_in_batch * hs);
1695 if (!lw.down_proj_f32.empty()) {
1697 } else if (!lw.down_proj_q8_0.empty()) {
1699 } else if (!lw.down_proj_q6k.empty()) {
1701 } else if (!lw.down_proj_q4k.empty()) {
1703 } else {
1704 Logger::error("[CPU_BATCH_GENERATION] Layer " + std::to_string(l) + ": No down_proj weights found for CPU");
1705 return {};
1706 }
1707
1708 // Second Residual Connection (batched)
1709 for(size_t i = 0; i < current_batch_activations.size(); ++i) {
1711 }
1712 }
1713
1714 // Update KV cache sequence length
1715 if (kv_cache && num_tokens_in_batch > 0) {
1716 // For batch mode, track positions per sequence
1717 if (kv_cache->current_batch_size > 0) {
1718 // Update batch_seq_lens based on the highest position seen for each sequence
1719 std::vector<int> max_positions_per_seq(kv_cache->current_batch_size, -1);
1720
1721 for (int i = 0; i < num_tokens_in_batch; ++i) {
1723 int pos = token_positions[i];
1724
1725 if (seq_idx >= 0 && seq_idx < kv_cache->current_batch_size) {
1727 }
1728 }
1729
1730 // Update batch_seq_lens to reflect new positions (pos + 1 since pos is 0-indexed)
1731 for (int seq_idx = 0; seq_idx < kv_cache->current_batch_size; ++seq_idx) {
1732 if (max_positions_per_seq[seq_idx] >= 0) {
1733 kv_cache->batch_seq_lens[seq_idx] = max_positions_per_seq[seq_idx] + 1;
1734 Logger::info("[CPU_BATCH_GEN] KV Length Max Update: seq_idx=" + std::to_string(seq_idx) +
1735 ", old_batch_seq_len=" + std::to_string(kv_cache->batch_seq_lens[seq_idx]) +
1736 ", new_batch_seq_len=" + std::to_string(max_positions_per_seq[seq_idx] + 1));
1737 }
1738 }
1739 // For single-sequence compatibility, update seq_len to the max
1740 kv_cache->seq_len = *std::max_element(kv_cache->batch_seq_lens.begin(),
1741 kv_cache->batch_seq_lens.begin() + kv_cache->current_batch_size);
1742 } else {
1743 // Fallback for single sequence mode
1744 int max_pos = *std::max_element(token_positions.begin(), token_positions.end());
1745 kv_cache->seq_len = std::max(kv_cache->seq_len, max_pos + 1);
1746 }
1747 }
1748
1749 // Final normalization and logits calculation for ALL tokens
1751
1752 // Convert flat logits to per-token vectors
1753 std::vector<std::vector<float>> all_logits(num_tokens_in_batch, std::vector<float>(vs));
1754 for (int token_idx = 0; token_idx < num_tokens_in_batch; ++token_idx) {
1755 std::copy(batch_logits.begin() + (size_t)token_idx * vs,
1756 batch_logits.begin() + (size_t)(token_idx + 1) * vs,
1757 all_logits[token_idx].begin());
1758 }
1759 return all_logits;
1760}
#define SAFE_SQRT(x)
std::vector< float > forward_cpu_logits_batch(const std::vector< float > &final_batch_activations, int num_tokens_in_batch)
Definition model.cpp:1329
void simd_scaled_add(float *dst, const float *src, float scale, int n)
Definition utils.cpp:93
void matmul_q4k_f32_batch_cpu(const std::vector< block_q4_K > &mat_q4k, const std::vector< float > &batch_input_activations, std::vector< float > &batch_output_activations, int num_tokens, int output_dim, int input_dim)
Definition utils.cpp:1155
float simd_dot_product(const float *a, const float *b, int n)
Definition utils.cpp:36
void matmul_q8_0_f32_batch_cpu(const std::vector< block_q8_0 > &mat_q8_0, const std::vector< float > &batch_input_activations, std::vector< float > &batch_output_activations, int num_tokens, int output_dim, int input_dim)
Definition utils.cpp:1036
void matmul_f32_f32_batch_cpu(const std::vector< float > &mat_weights, const std::vector< float > &batch_input_activations, std::vector< float > &batch_output_activations, int num_tokens, int output_dim, int input_dim)
Definition utils.cpp:872
void matmul_q6k_f32_batch_cpu(const std::vector< block_q6_K > &mat_q6k, const std::vector< float > &batch_input_activations, std::vector< float > &batch_output_activations, int num_tokens, int output_dim, int input_dim)
Definition utils.cpp:1117
void rmsnorm_batch_cpu(const std::vector< float > &x_batch, const std::vector< float > &weight, std::vector< float > &out_batch, int num_tokens, int hidden_size, float eps)
Definition utils.cpp:613

References apply_rope_vector(), bf16vec_to_float_vec(), config_, ensure_down_proj_dequantized(), ensure_gate_proj_dequantized(), ensure_k_proj_dequantized(), ensure_o_proj_dequantized(), ensure_q_proj_dequantized(), ensure_up_proj_dequantized(), ensure_v_proj_dequantized(), Logger::error(), forward_cpu_logits_batch(), ModelConfig::hidden_size, Logger::info(), ModelConfig::intermediate_size, ModelConfig::is_gguf_file_loaded, j, layers, matmul_f32_f32_batch_cpu(), matmul_q4k_f32_batch_cpu(), matmul_q6k_f32_batch_cpu(), matmul_q8_0_f32_batch_cpu(), ModelConfig::max_position_embeddings, ModelConfig::num_attention_heads, ModelConfig::num_cpu_offload_layers, ModelConfig::num_key_value_heads, pos, precomputed_freqs_cis_, ModelConfig::rms_norm_eps, rmsnorm_batch_cpu(), SAFE_SQRT, simd_dot_product(), simd_scaled_add(), softmax_vector_cpu(), and ModelConfig::vocab_size.

◆ forward_cpu_logits_batch()

std::vector< float > TinyLlamaModel::forward_cpu_logits_batch ( const std::vector< float > &  final_batch_activations,
int  num_tokens_in_batch 
)

Definition at line 1329 of file model.cpp.

1331 {
1332
1334 Logger::error("[CPU_LOGITS_BATCH] final_batch_activations size mismatch. Expected: " +
1335 std::to_string((size_t)num_tokens_in_batch * config_.hidden_size) + " Got: " +
1336 std::to_string(final_batch_activations.size()));
1337 return {};
1338 }
1339
1340 int hs = config_.hidden_size;
1341 int vs = config_.vocab_size;
1342 float eps = config_.rms_norm_eps;
1343
1344 // 1. Final RMSNorm
1345 std::vector<float> final_batch_norm_out(num_tokens_in_batch * hs);
1346 const std::vector<float>& w_final_norm_vec =
1349 if (w_final_norm_vec.empty()) {
1350 Logger::error("[CPU_LOGITS_BATCH] Final RMSNorm weights are empty (neither f32 nor bf16 available).");
1351 return {};
1352 }
1353
1356
1357 // 2. Batched LM Head multiplication: from the f32 copy, as forward() does (a Q5_K head has no
1358 // kernel of its own, and every quantised head then gives the decode step's values).
1360 std::vector<float> batch_logits_out(num_tokens_in_batch * vs);
1361
1362 if (!lm_head_f32.empty()) {
1363 Logger::info("[CPU_LOGITS_BATCH] Using F32 LM Head weights.");
1366 } else if (!lm_head_q8_0.empty() && config_.is_gguf_file_loaded) {
1367 Logger::info("[CPU_LOGITS_BATCH] Using Q8_0 LM Head weights.");
1370 } else if (!lm_head_q6k.empty() && config_.is_gguf_file_loaded) {
1371 Logger::info("[CPU_LOGITS_BATCH] Using Q6_K LM Head weights.");
1374 } else if (!lm_head_q4k.empty() && config_.is_gguf_file_loaded) {
1375 Logger::info("[CPU_LOGITS_BATCH] Using Q4_K LM Head weights.");
1378 } else if (!lm_head.empty()) { // BF16 SafeTensors weights
1379 Logger::info("[CPU_LOGITS_BATCH] Using BF16 LM Head weights (converting to F32 for matmul).");
1380 std::vector<float> lm_head_f32_temp = bf16vec_to_float_vec(lm_head);
1381 if (lm_head_f32_temp.empty()) {
1382 Logger::error("[CPU_LOGITS_BATCH] Failed to convert BF16 LM Head to F32.");
1383 return {};
1384 }
1387 } else {
1388 Logger::error("[CPU_LOGITS_BATCH] No valid LM Head weights found (F32, Q8_0, Q6_K, Q4_K, BF16).");
1389 return {};
1390 }
1391
1392 return batch_logits_out;
1393}

References bf16vec_to_float_vec(), config_, ensure_lm_head_dequantized(), Logger::error(), final_norm, final_norm_f32, ModelConfig::hidden_size, Logger::info(), ModelConfig::is_gguf_file_loaded, j, lm_head, lm_head_f32, lm_head_q4k, lm_head_q6k, lm_head_q8_0, matmul_f32_f32_batch_cpu(), matmul_q4k_f32_batch_cpu(), matmul_q6k_f32_batch_cpu(), matmul_q8_0_f32_batch_cpu(), ModelConfig::rms_norm_eps, rmsnorm_batch_cpu(), and ModelConfig::vocab_size.

Referenced by forward_cpu_batch_generation().

◆ free_bf16_concatenated_weights()

void TinyLlamaModel::free_bf16_concatenated_weights ( )

Definition at line 1246 of file weight_management.cpp.

1246 {
1247 Logger::info("CPU-only build: free_bf16_concatenated_weights is a no-op");
1248}

References Logger::info().

◆ free_layer_gpu_weights()

void TinyLlamaModel::free_layer_gpu_weights ( int  layer_idx)

◆ gemm_fp32_only()

bool TinyLlamaModel::gemm_fp32_only ( ) const
inline

Definition at line 386 of file model.h.

386{ return gemm_fp32_only_; }
bool gemm_fp32_only_
Definition model.h:576

References gemm_fp32_only_.

◆ get_config()

const ModelConfig & TinyLlamaModel::get_config ( ) const
inline

Definition at line 509 of file model.h.

509{ return config_; }

References config_.

◆ get_embed_tokens()

const std::vector< uint16_t > & TinyLlamaModel::get_embed_tokens ( ) const
inline

Definition at line 518 of file model.h.

518{ return embed_tokens; }

References embed_tokens.

◆ get_gguf_data()

const GGUFData * TinyLlamaModel::get_gguf_data ( ) const
inline

Definition at line 539 of file model.h.

539 {
540 return gguf_data_ ? gguf_data_.get() : nullptr;
541 }

References gguf_data_.

◆ get_gguf_data_ptr()

GGUFData * TinyLlamaModel::get_gguf_data_ptr ( )
inline

Definition at line 543 of file model.h.

543{ return gguf_data_.get(); }

References gguf_data_.

◆ get_layers()

std::vector< LayerWeights > & TinyLlamaModel::get_layers ( )
inline

Definition at line 520 of file model.h.

520{ return layers; }

References layers.

◆ get_lm_head()

const std::vector< uint16_t > & TinyLlamaModel::get_lm_head ( ) const
inline

Definition at line 516 of file model.h.

516{ return lm_head; }

References lm_head.

◆ get_vocab_size()

int TinyLlamaModel::get_vocab_size ( ) const

Get the vocabulary size for the model.

Returns
Vocabulary size.

Definition at line 256 of file model_utils.cpp.

256 {
257 return config_.vocab_size;
258}

References config_, and ModelConfig::vocab_size.

◆ initialize_gpu_and_rope()

void TinyLlamaModel::initialize_gpu_and_rope ( )

Definition at line 17 of file gpu_initialization.cpp.

17 {
18 Logger::info("[INIT_GPU_ROPE_DEBUG_L1113] Absolute Start of initialize_gpu_and_rope: config_.num_cpu_offload_layers = " + std::to_string(config_.num_cpu_offload_layers) +
19 ", config_.num_hidden_layers = " + std::to_string(config_.num_hidden_layers));
20 Logger::info("[GPU_ROPE_INIT_ENTRY] Entered initialize_gpu_and_rope. Requested CPU Offload Layers: " + std::to_string(config_.num_cpu_offload_layers) + ", Total Hidden Layers: " + std::to_string(config_.num_hidden_layers));
24 int vs = config_.vocab_size;
27
31 Logger::warning("Requested CPU offload layers (" + std::to_string(config_.num_cpu_offload_layers) +
32 ") exceeds total hidden layers (" + std::to_string(nhl) +
33 "). Clamping to " + std::to_string(nhl) + " layers on CPU.");
35 }
38
39 Logger::info("Effective CPU layers for this init: " + std::to_string(active_num_cpu_layers) + ", Effective GPU layers for this init: " + std::to_string(active_num_gpu_layers));
40
41 if (hs <= 0) throw std::runtime_error("Invalid model config: hidden_size must be positive.");
42 if (vs <= 0) throw std::runtime_error("Invalid model config: vocab_size must be positive.");
43 if (n_heads <= 0) throw std::runtime_error("Invalid model config: num_attention_heads must be positive.");
44 if (n_kv_heads <= 0) throw std::runtime_error("Invalid model config: num_key_value_heads must be positive.");
45 if (hs % n_heads != 0) throw std::runtime_error("Invalid model config: hidden_size not divisible by num_attention_heads.");
46
47 int kv_dim = (hs / n_heads) * n_kv_heads;
48 int head_dim = hs / n_heads;
49
50 Logger::info("Precomputing RoPE frequencies on CPU (always done).");
53 float theta = config_.rope_theta;
54 for (int pos = 0; pos < max_seq_len; ++pos) {
55 for (int i_rope = 0; i_rope < head_dim; i_rope += 2) {
56 float freq = std::pow(theta, -((float)i_rope) / head_dim);
57 float angle = pos * freq;
58 precomputed_freqs_cis_[(pos * head_dim / 2) + (i_rope / 2)] = {std::cos(angle), std::sin(angle)};
59 }
60 }
61 Logger::info("Finished precomputing RoPE cos/sin frequencies on CPU.");
62
63#ifdef HAS_CUDA
64#define SAFE_CUDA_FREE(ptr) if(ptr) { cudaFree(ptr); ptr = nullptr; }
65
66 if (active_num_gpu_layers == 0) {
67 Logger::info("No layers assigned to GPU (active_num_gpu_layers = 0). Cleaning up existing CUDA resources and skipping GPU initialization.");
68
70 for (int i = 0; i < nhl; ++i) {
73 }
87
89 return;
90 }
91
92 Logger::info("Initializing CUDA resources for " + std::to_string(active_num_gpu_layers) + " GPU layers.");
93 if (!cublas_handle_) {
94 ember::deterministic_cublas_env(); // EMBER_DETERMINISTIC=1 only (determinism.h)
97 throw std::runtime_error("Failed to initialize cuBLAS: " + std::to_string(cublas_status));
98 }
101 Logger::info("EMBER_DETERMINISTIC: deterministic CUDA mode on (fixed-order decode reductions; cuBLAS "
102 "workspace " + std::string(std::getenv("CUBLAS_WORKSPACE_CONFIG") ? std::getenv("CUBLAS_WORKSPACE_CONFIG") : "default") +
103 ", atomics not allowed).");
104 }
105 Logger::info("cuBLAS handle created successfully.");
106
107 // Check for BF16 Tensor Core support
108 this->use_bf16_tensor_cores_ = false; // Default to false
110 int current_device;
111 gpuErrchk(cudaGetDevice(&current_device));
113
114 bool has_bf16_tensor_core_hw = ((props.major == 7 && props.minor == 5) || props.major >= 8);
116
117 // EMBER_DISABLE_BF16=1 keeps every GEMM in FP32: the reference the
118 // tools/ttft_parity.py check holds the BF16 path and kernel variants to.
119 if (std::getenv("EMBER_DISABLE_BF16") != nullptr) {
120 Logger::info("EMBER_DISABLE_BF16 set: BF16 Tensor Core path disabled, all GEMMs FP32.");
121 } else if (has_bf16_tensor_core_hw) {
123 Logger::info("GPU " + std::string(props.name) + " (CC " + std::to_string(props.major) + "." + std::to_string(props.minor) + ") supports BF16 Tensor Cores AND model dimensions (hs: " + std::to_string(config_.hidden_size) + ", vs: " + std::to_string(config_.vocab_size) + ") are compatible. Enabling Tensor Core path for matvec_bf16_f32.");
124 this->use_bf16_tensor_cores_ = true;
125 } else {
126 Logger::info("GPU " + std::string(props.name) + " (CC " + std::to_string(props.major) + "." + std::to_string(props.minor) + ") supports BF16 Tensor Cores, BUT model dimensions (hs: " + std::to_string(config_.hidden_size) + " (must be div by 8), vs: " + std::to_string(config_.vocab_size) + " (must be div by 4)) are NOT compatible. Disabling Tensor Core path for matvec_bf16_f32.");
127 }
128 } else {
129 Logger::info("GPU " + std::string(props.name) + " (CC " + std::to_string(props.major) + "." + std::to_string(props.minor) + ") does not meet criteria for BF16 Tensor Core use (requires CC >= 7.5). Disabling Tensor Core path for matvec_bf16_f32.");
130 }
131 }
132
133 if (final_norm_f32.empty() && !final_norm.empty()) {
134 Logger::info("Converting final_norm (BF16) to FP32 for GPU.");
136 }
137 if (!final_norm_f32.empty()) {
139 gpuErrchk(cudaMalloc(&final_norm_dev, final_norm_f32.size() * sizeof(float)));
141 Logger::info("Copied final_norm weights (FP32) to GPU.");
142 } else {
143 Logger::warning("Final norm weights (FP32) are empty, skipping GPU copy. This might be an issue if GPU layers are expected to use it.");
144 }
145
146 for (int i = 0; i < active_num_cpu_layers; ++i) {
147 if (static_cast<size_t>(i) < layers.size()) {
150 }
151 }
152 Logger::info("Copying layer norm weights (FP32) to GPU for layers " + std::to_string(active_num_cpu_layers) + " to " + std::to_string(nhl - 1));
153 Logger::info("[INIT_DEBUG_PRE_LOOP] Active CPU layers: " + std::to_string(active_num_cpu_layers));
154 if (nhl > 0 && layers.size() > 0) {
155 Logger::info("[INIT_DEBUG_PRE_LOOP] layers[0].input_layernorm_f32.empty(): " + std::string(layers[0].input_layernorm_f32.empty() ? "YES" : "NO") +
156 ", Size: " + std::to_string(layers[0].input_layernorm_f32.size()));
157 }
158 for (int i = active_num_cpu_layers; i < nhl; ++i) {
159 if (static_cast<size_t>(i) >= layers.size()) {
160 Logger::error("Layer index " + std::to_string(i) + " out of bounds for layers vector (size: " + std::to_string(layers.size()) + ")");
161 continue;
162 }
165
166 if (layers[i].input_layernorm_f32.empty() && !layers[i].input_layernorm.empty()) {
167 layers[i].input_layernorm_f32 = bf16vec_to_float_vec(layers[i].input_layernorm);
168 }
169 if (layers[i].post_attention_layernorm_f32.empty() && !layers[i].post_attention_layernorm.empty()) {
170 layers[i].post_attention_layernorm_f32 = bf16vec_to_float_vec(layers[i].post_attention_layernorm);
171 }
172
173 if (!layers[i].input_layernorm_f32.empty()) {
174 gpuErrchk(cudaMalloc(&layers[i].input_layernorm_dev, layers[i].input_layernorm_f32.size() * sizeof(float)));
175 gpuErrchk(cudaMemcpy(layers[i].input_layernorm_dev, layers[i].input_layernorm_f32.data(), layers[i].input_layernorm_f32.size() * sizeof(float), cudaMemcpyHostToDevice));
176 if (i == active_num_cpu_layers) {
177 Logger::info("[INIT_DEBUG] layers[" + std::to_string(i) + "].input_layernorm_dev allocated. Pointer: " + Logger::ptrToString(layers[i].input_layernorm_dev) +
178 ", Size used for malloc: " + std::to_string(layers[i].input_layernorm_f32.size() * sizeof(float)) + " bytes (" +
179 std::to_string(layers[i].input_layernorm_f32.size()) + " elements). Host vector empty: " + (layers[i].input_layernorm_f32.empty() ? "YES" : "NO"));
180 }
181 } else {
182 throw std::runtime_error("GPU Layer " + std::to_string(i) + ": input_layernorm_f32 weights are empty. Cannot offload to GPU without them.");
183 }
184
185 if (!layers[i].post_attention_layernorm_f32.empty()) {
186 gpuErrchk(cudaMalloc(&layers[i].post_attention_layernorm_dev, layers[i].post_attention_layernorm_f32.size() * sizeof(float)));
187 gpuErrchk(cudaMemcpy(layers[i].post_attention_layernorm_dev, layers[i].post_attention_layernorm_f32.data(), layers[i].post_attention_layernorm_f32.size() * sizeof(float), cudaMemcpyHostToDevice));
188 } else {
189 throw std::runtime_error("GPU Layer " + std::to_string(i) + ": post_attention_layernorm_f32 weights are empty. Cannot offload to GPU without them.");
190 }
191 }
192 Logger::info("Finished processing layer norm weights for GPU layers.");
193
194
199
200 if (active_num_gpu_layers > 0) {
201 if (!embed_tokens.empty()) {
204 Logger::info("Copied token_embedding_table (bf16 direct from model.embed_tokens) to GPU.");
206 }
207 else if (!embed_tokens_f32.empty()) {
208 std::vector<uint16_t> bf16_data(embed_tokens_f32.size());
209 #pragma omp parallel for
210 for (int i = 0; i < (int)embed_tokens_f32.size(); ++i) {
212 }
215 Logger::info("Converted token_embedding_table (fp32 source -> bf16) to GPU.");
217 }
218 else if (!embed_tokens_q8_0.empty()) {
219 std::vector<float> temp_f32_data(embed_tokens_q8_0.size() * GGML_QK8_0);
220 #pragma omp parallel for
221 for (int i = 0; i < (int)embed_tokens_q8_0.size(); ++i) {
223 }
224 std::vector<uint16_t> bf16_data(temp_f32_data.size());
225 #pragma omp parallel for
226 for (int i = 0; i < (int)temp_f32_data.size(); ++i) {
228 }
231 Logger::info("Dequantized token_embedding_table (Q8_0 -> fp32 -> bf16) to GPU.");
233 }
234 else if (!embed_tokens_q4k.empty()) {
235 std::vector<float> temp_f32_data(embed_tokens_q4k.size() * GGML_QK_K);
236 #pragma omp parallel for
237 for (int i = 0; i < (int)embed_tokens_q4k.size(); ++i) {
239 }
240 std::vector<uint16_t> bf16_data(temp_f32_data.size());
241 #pragma omp parallel for
242 for (int i = 0; i < (int)temp_f32_data.size(); ++i) {
244 }
247 Logger::info("Dequantized token_embedding_table (Q4_K -> fp32 -> bf16) to GPU.");
249 }
250 else if (!embed_tokens_q6k.empty()) {
251 std::vector<float> temp_f32_data(embed_tokens_q6k.size() * GGML_QK_K);
252 #pragma omp parallel for
253 for (int i = 0; i < (int)embed_tokens_q6k.size(); ++i) {
255 }
256 std::vector<uint16_t> bf16_data(temp_f32_data.size());
257 #pragma omp parallel for
258 for (int i = 0; i < (int)temp_f32_data.size(); ++i) {
260 }
263 Logger::info("Dequantized token_embedding_table (Q6_K -> fp32 -> bf16) to GPU.");
265 }
266
268 Logger::info("[INIT_DEBUG] token_embedding_table_dev_ (BF16 on GPU) processed. Pointer: " + Logger::ptrToString(token_embedding_table_dev_) +
269 ". Flag token_embeddings_processed_to_gpu_bf16: YES");
270 }
272 Logger::warning("Token embeddings were not processed to GPU as BF16, despite GPU layers being active. This might indicate missing source embedding data in the model structure or an unhandled GGUF type for embeddings.");
273 }
274 } else {
275 Logger::info("No GPU layers active, skipping token embedding table processing for GPU.");
276 }
277
282
283 if (active_num_gpu_layers > 0) {
284 if (!lm_head.empty()) {
285 gpuErrchk(cudaMalloc(&lm_head_dev_, lm_head.size() * sizeof(uint16_t)));
287 Logger::info("Copied lm_head (bf16 direct from model.lm_head) to GPU.");
289 }
290 else if (!lm_head_f32.empty()) {
291 std::vector<uint16_t> bf16_data(lm_head_f32.size());
292 #pragma omp parallel for
293 for (int i = 0; i < (int)lm_head_f32.size(); ++i) {
295 }
298 Logger::info("Converted lm_head (fp32 source -> bf16) to GPU.");
300 }
301 else if (!lm_head_q8_0.empty()) {
302 std::vector<float> temp_f32_data(lm_head_q8_0.size() * GGML_QK8_0);
303 #pragma omp parallel for
304 for (int i = 0; i < (int)lm_head_q8_0.size(); ++i) {
306 }
307 std::vector<uint16_t> bf16_data(temp_f32_data.size());
308 #pragma omp parallel for
309 for (int i = 0; i < (int)temp_f32_data.size(); ++i) {
311 }
314 Logger::info("Dequantized lm_head (Q8_0 -> fp32 -> bf16) to GPU.");
316 }
317 else if (!lm_head_q4k.empty()) {
318 std::vector<float> temp_f32_data(lm_head_q4k.size() * GGML_QK_K);
319 #pragma omp parallel for
320 for (int i = 0; i < (int)lm_head_q4k.size(); ++i) {
322 }
323 std::vector<uint16_t> bf16_data(temp_f32_data.size());
324 #pragma omp parallel for
325 for (int i = 0; i < (int)temp_f32_data.size(); ++i) {
327 }
330 Logger::info("Dequantized lm_head (Q4_K -> fp32 -> bf16) to GPU.");
332 }
333 else if (!lm_head_q6k.empty()) {
334 std::vector<float> temp_f32_data(lm_head_q6k.size() * GGML_QK_K);
335 #pragma omp parallel for
336 for (int i = 0; i < (int)lm_head_q6k.size(); ++i) {
338 }
339 std::vector<uint16_t> bf16_data(temp_f32_data.size());
340 #pragma omp parallel for
341 for (int i = 0; i < (int)temp_f32_data.size(); ++i) {
343 }
346 Logger::info("Dequantized lm_head (Q6_K -> fp32 -> bf16) to GPU.");
348 }
349
351 Logger::warning("LM head was not processed to GPU as BF16, despite GPU layers being active. This might indicate missing source LM head data in the model structure or an unhandled GGUF type for LM head.");
352 }
353 } else {
354 Logger::info("No GPU layers active, skipping LM head processing for GPU.");
355 }
356
358
359 if (active_num_gpu_layers > 0) {
360 if (!lm_head_f32.empty()) {
361 gpuErrchk(cudaMalloc(&lm_head_f32_dev_, lm_head_f32.size() * sizeof(float)));
363 Logger::info("[INIT_GPU_ROPE] Copied lm_head_f32 (host FP32) to GPU for lm_head_f32_dev_. Pointer: " + Logger::ptrToString(lm_head_f32_dev_));
364 } else {
365 Logger::error("[INIT_GPU_ROPE] Host lm_head_f32 is EMPTY. Cannot populate lm_head_f32_dev_. This WILL CAUSE a cublasSgemm error in the final matvec. Check model loading and initialize_weights logic for lm_head_f32 population.");
366 lm_head_f32_dev_ = nullptr;
367 }
368 } else {
369 lm_head_f32_dev_ = nullptr;
370 }
371
372
373 Logger::info("Finished processing embedding and LM head tables for GPU.");
374
376 if (active_num_gpu_layers > 0) {
377 if (!precomputed_freqs_cis_.empty()) {
380 std::vector<float> flat_host_freqs; flat_host_freqs.reserve(total_freq_elements);
381 for (const auto& p : precomputed_freqs_cis_) { flat_host_freqs.push_back(p.first); flat_host_freqs.push_back(p.second); }
383 Logger::info("Copied all precomputed RoPE frequencies to persistent GPU buffer.");
384 } else {
385 Logger::warning("Host precomputed_freqs_cis_ is empty. Skipping GPU RoPE buffer allocation. This WILL cause issues if GPU layers use RoPE.");
386 }
387 Logger::info("Finished processing RoPE frequencies for GPU.");
388 } else {
389 Logger::info("No GPU layers active, skipping RoPE GPU buffer allocation.");
390 }
391
392 if (active_num_gpu_layers > 0) {
393 Logger::info("Allocating/Reallocating persistent GPU workspace buffers for " + std::to_string(active_num_gpu_layers) + " GPU layers.");
394 size_t hs_bytes = (size_t)hs * sizeof(float);
395 size_t is_bytes = (size_t)is * sizeof(float);
396 size_t vs_bytes = (size_t)vs * sizeof(float);
397 size_t k_dev_size_bytes = (size_t)n_kv_heads * head_dim * sizeof(float);
398 size_t v_dev_size_bytes = (size_t)n_kv_heads * head_dim * sizeof(float);
399
400#define REALLOC_GPU_WORKSPACE(ptr, sz) SAFE_CUDA_FREE(ptr); gpuErrchk(cudaMalloc(&ptr, sz));
415 Logger::info("Finished allocating/reallocating GPU workspace buffers.");
416 } else {
417 Logger::info("No GPU layers active, skipping GPU workspace buffer allocation.");
421 }
422
423 if (active_num_gpu_layers > 0) {
426
432 Logger::info("Allocated SELECTIVE KVCache dequantization buffers (K and V) on GPU. Size per buffer: " +
433 std::to_string(selective_buffer_bytes / (1024.0 * 1024.0)) + " MB (vs " +
434 std::to_string((static_cast<size_t>(config_.max_position_embeddings) * n_kv_heads * head_dim * sizeof(float)) / (1024.0 * 1024.0)) + " MB for full buffers)");
435 } else {
436 Logger::warning("Selective KVCache dequantization buffer size is 0. Skipping allocation.");
439 }
440
443 } else {
448 }
449
454
455 std::vector<uint16_t> h_q, h_k, h_v, h_o, h_gate, h_up, h_down;
460
461 Logger::info("Concatenating BF16 weights for GPU layers on host (zero-padding if missing for a layer)...");
462 for (int i = 0; i < active_num_gpu_layers; ++i) {
464 const auto& lw = layers[model_layer_idx];
465
466 if (!lw.q_proj.empty()) {
467 h_q.insert(h_q.end(), lw.q_proj.begin(), lw.q_proj.end());
468 } else {
469 h_q.insert(h_q.end(), layer_q_size, bfloat16::ZERO);
470 }
471
472 if (!lw.k_proj.empty()) {
473 h_k.insert(h_k.end(), lw.k_proj.begin(), lw.k_proj.end());
474 } else {
475 h_k.insert(h_k.end(), layer_k_size, bfloat16::ZERO);
476 }
477
478 if (!lw.v_proj.empty()) {
479 h_v.insert(h_v.end(), lw.v_proj.begin(), lw.v_proj.end());
480 } else {
481 h_v.insert(h_v.end(), layer_v_size, bfloat16::ZERO);
482 }
483
484 if (!lw.o_proj.empty()) {
485 h_o.insert(h_o.end(), lw.o_proj.begin(), lw.o_proj.end());
486 } else {
487 h_o.insert(h_o.end(), layer_o_size, bfloat16::ZERO);
488 }
489
490 if (!lw.gate_proj.empty()) {
491 h_gate.insert(h_gate.end(), lw.gate_proj.begin(), lw.gate_proj.end());
492 } else {
494 }
495
496 if (!lw.up_proj.empty()) {
497 h_up.insert(h_up.end(), lw.up_proj.begin(), lw.up_proj.end());
498 } else {
499 h_up.insert(h_up.end(), layer_up_size, bfloat16::ZERO);
500 }
501
502 if (!lw.down_proj.empty()) {
503 h_down.insert(h_down.end(), lw.down_proj.begin(), lw.down_proj.end());
504 } else {
506 }
507 }
508
509#define ALLOC_COPY_CONCAT_BF16(dev_ptr, host_vec, weight_name_str) \
510 SAFE_CUDA_FREE(dev_ptr); \
511 if (!host_vec.empty()) { \
512 gpuErrchk(cudaMalloc(&dev_ptr, host_vec.size() * sizeof(uint16_t))); \
513 gpuErrchk(cudaMemcpy(dev_ptr, host_vec.data(), host_vec.size() * sizeof(uint16_t), cudaMemcpyHostToDevice)); \
514 Logger::info("Copied concatenated " weight_name_str " (BF16) to GPU for GPU layers."); \
515 } else if (active_num_gpu_layers > 0) { \
516 Logger::info("Host vector for concatenated " weight_name_str " (BF16) is empty. Skipping GPU copy."); \
517 }
518
522#undef ALLOC_COPY_CONCAT_BF16
523
524 } else {
525 Logger::info("Skipping BF16 concatenated layer weight processing (first GPU layer appears not to use BF16 q_proj, or no GPU layers).");
528 }
529
530 Logger::info("DEFERRING concatenated F32 weight processing for GPU layers to save memory during initialization");
531 Logger::info("Concatenated F32 weights will be processed on-demand during first inference");
532
535
536 // Free BF16 concatenated weights
539
540 Logger::info("Finished deferring concatenated F32 weight processing for GPU layers.");
541
542 // Allocate persistent batch processing buffers for GPU memory optimization
543 if (active_num_gpu_layers > 0) {
545 }
546
547#undef SAFE_CUDA_FREE
548#else
549 if (active_num_gpu_layers > 0 && nhl > 0) {
550 Logger::warning("CUDA not available, but " + std::to_string(active_num_gpu_layers) + " layer(s) were configured for GPU. Model will run entirely on CPU.");
551 } else {
552 Logger::info("CUDA not available or no GPU layers configured. Model will run entirely on CPU.");
553 }
554#endif
555}
static std::string ptrToString(const void *ptr)
Definition logger.cpp:225
bool use_bf16_tensor_cores_
Definition model.h:574
constexpr size_t GGML_QK_K
Block size constants for different quantization formats.
Definition gguf_parser.h:42
constexpr uint16_t ZERO
bool deterministic()
Definition determinism.h:22
void deterministic_cublas_env()
Definition determinism.h:32
void dequantize_q4_k_m(const block_q4_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
void dequantize_q8_0_block(const block_q8_0 *qblock, float *output)
Dequantizes a Q8_0 block to float32.
void dequantize_q6_k(const block_q6_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
float rope_theta
Definition model.h:91
uint16_t float32_to_bfloat16(float val)
Definition utils.cpp:137

References bf16vec_to_float_vec(), config_, dequantize_q4_k_m(), dequantize_q6_k(), dequantize_q8_0_block(), ember::deterministic(), ember::deterministic_cublas_env(), embed_tokens, embed_tokens_f32, embed_tokens_q4k, embed_tokens_q6k, embed_tokens_q8_0, ensure_embed_tokens_dequantized(), ensure_lm_head_dequantized(), Logger::error(), final_norm, final_norm_f32, float32_to_bfloat16(), GGML_QK8_0, GGML_QK_K, ModelConfig::hidden_size, Logger::info(), ModelConfig::intermediate_size, j, layers, lm_head, lm_head_f32, lm_head_q4k, lm_head_q6k, lm_head_q8_0, ModelConfig::max_position_embeddings, ModelConfig::num_attention_heads, ModelConfig::num_cpu_offload_layers, ModelConfig::num_hidden_layers, ModelConfig::num_key_value_heads, p, pos, precomputed_freqs_cis_, Logger::ptrToString(), ModelConfig::rope_theta, use_bf16_tensor_cores_, ModelConfig::vocab_size, Logger::warning(), and bfloat16::ZERO.

Referenced by TinyLlamaModel(), TinyLlamaModel(), and TinyLlamaModel().

◆ initialize_rope_freqs()

void TinyLlamaModel::initialize_rope_freqs ( )

Definition at line 196 of file model_utils.cpp.

196 {
197 Logger::info("[ROPE_FREQ_ENTRY] Entered initialize_rope_freqs.");
198
199 Logger::info("[ROPE_FREQ_CHECK] num_attention_heads: " + std::to_string(config_.num_attention_heads));
200 if (config_.num_attention_heads == 0) {
201 Logger::error("Cannot initialize RoPE frequencies: num_attention_heads is zero.");
202 return;
203 }
205 Logger::info("[ROPE_FREQ_CHECK] calculated head_dim: " + std::to_string(head_dim));
206 if (head_dim == 0) {
207 Logger::error("Cannot initialize RoPE frequencies: calculated head_dim is zero.");
208 return;
209 }
210 Logger::info("[ROPE_FREQ_CHECK] head_dim % 2 check. head_dim: " + std::to_string(head_dim));
211 if (head_dim % 2 != 0) {
212 Logger::error("Cannot initialize RoPE frequencies: head_dim must be even.");
213 return;
214 }
215
216 Logger::info("[ROPE_INIT] Initializing RoPE with head_dim=" + std::to_string(head_dim) +
217 ", configured max_pos_emb=" + std::to_string(config_.max_position_embeddings) +
218 ", using internal rope::MAX_SEQUENCE_LENGTH=" + std::to_string(rope::MAX_SEQUENCE_LENGTH) +
219 ", configured rope_theta=" + std::to_string(config_.rope_theta));
220
221
222 if (precomputed_freqs_cis_.empty()) {
224 size_t required_size = (static_cast<size_t>(max_seq_len) * head_dim) / 2;
225 if (required_size == 0) {
226 Logger::warning("RoPE precomputation resulted in zero size. Max seq len: " +
227 std::to_string(max_seq_len) + ", head_dim: " + std::to_string(head_dim));
228 return;
229 }
231
232 float rope_theta = config_.rope_theta > 0 ? config_.rope_theta : rope::ROPE_THETA;
233
234 for (int pos = 0; pos < max_seq_len; ++pos) {
235 for (int i = 0; i < head_dim; i += 2) {
236 float freq = 1.0f / std::pow(rope_theta, float(i) / head_dim);
237 float val = static_cast<float>(pos) * freq;
238 float cos_val = std::cos(val);
239 float sin_val = std::sin(val);
240 size_t flat_idx = (static_cast<size_t>(pos) * head_dim / 2) + (i / 2);
241 if (flat_idx < precomputed_freqs_cis_.size()){
243 } else {
244 Logger::error("RoPE precomputation index out of bounds: " + std::to_string(flat_idx) +
245 " vs size " + std::to_string(precomputed_freqs_cis_.size()));
246 return;
247 }
248 }
249 }
250 Logger::info("Precomputed RoPE frequencies on CPU. Size: " + std::to_string(precomputed_freqs_cis_.size()));
251 } else {
252 Logger::info("RoPE frequencies already precomputed.");
253 }
254}
constexpr float ROPE_THETA
constexpr int MAX_SEQUENCE_LENGTH

References config_, Logger::error(), ModelConfig::hidden_size, Logger::info(), j, ModelConfig::max_position_embeddings, rope::MAX_SEQUENCE_LENGTH, ModelConfig::num_attention_heads, pos, precomputed_freqs_cis_, ModelConfig::rope_theta, rope::ROPE_THETA, and Logger::warning().

◆ initialize_weights()

void TinyLlamaModel::initialize_weights ( const SafeTensorsLoader *  loader,
const GGUFData *  gguf 
)
private

Definition at line 39 of file model.cpp.

40 {
41 Logger::info("Initializing model weights...");
45 int vs = config_.vocab_size;
46 layers.resize(nhl);
47
48 if (gguf) {
49 Logger::info("Processing weights from GGUF data source...");
50
51 if (gguf && (gguf->mapped_tensor_data || !gguf->tensor_data.empty())) {
52 map_gguf_weights(*gguf, *this);
53 Logger::info("[INIT_WEIGHTS_GGUF] map_gguf_weights(*gguf, *this) CALLED (using function parameter).");
54 } else if (gguf_data_ && (gguf_data_->mapped_tensor_data || !gguf_data_->tensor_data.empty())) {
56 Logger::info("[INIT_WEIGHTS_GGUF] map_gguf_weights(*gguf_data_, *this) CALLED (using member gguf_data_).");
57 } else {
58 Logger::error("[INIT_WEIGHTS_GGUF] map_gguf_weights failed - tensor data not available. No GGUF weights mapped.");
59 }
60
61 // LAZY DEQUANTIZATION: Only dequantize what's immediately needed
62 Logger::info("[INIT_WEIGHTS_GGUF] Using lazy dequantization to prevent OOM");
63
64 // Only dequantize embed_tokens and final_norm immediately (small and always needed)
65 if (this->embed_tokens_f32.empty()) {
66 ensure_embed_tokens_dequantized(); // every quantised table type, Q5_K included
67 if (!this->embed_tokens_f32.empty()) {
68 Logger::info("[INIT_WEIGHTS_GGUF_DEQUANT] embed_tokens_f32 populated. Size: " + std::to_string(this->embed_tokens_f32.size()));
69 }
70 }
71
72 if (this->final_norm_f32.empty()) {
73 if (!this->final_norm.empty()) {
75 if (!this->final_norm_f32.empty()) {
76 Logger::info("[INIT_WEIGHTS_GGUF_DEQUANT] Successfully converted final_norm (BF16) to final_norm_f32. Size: " + std::to_string(this->final_norm_f32.size()));
77 }
78 }
79 }
80
81 // DEFER lm_head dequantization until actually needed (it's huge)
82 Logger::info("[INIT_WEIGHTS_GGUF] Deferring lm_head dequantization until needed to save memory");
83 // Tied embeddings: a GGUF with no output.weight (llama.cpp's converter omits it when the checkpoint ties the
84 // head to the embedding, e.g. SmolLM2) uses token_embd as the head, as llama.cpp does. Every head kernel then
85 // reads the f32 copy. Files with output.weight are untouched.
86 if (this->lm_head_f32.empty() && this->lm_head_q8_0.empty() && this->lm_head_q6k.empty() &&
87 this->lm_head_q4k.empty() && this->lm_head_q5k.empty() && this->lm_head_q8k.empty() &&
88 this->lm_head.empty() && !this->embed_tokens_f32.empty()) {
89 this->lm_head_f32 = this->embed_tokens_f32;
90 Logger::info("[INIT_WEIGHTS_GGUF] No output.weight: the head is tied to token_embd.weight");
91 }
92
93 // DEFER all layer weight dequantization until the layer is actually used
94 Logger::info("[INIT_WEIGHTS_GGUF] Deferring all layer weight dequantization until layers are used");
95
96 // Only populate layer norms immediately (small and needed for validation)
97 for (int l = 0; l < nhl; ++l) {
98 auto& lw = layers[l];
99
100 if (lw.input_layernorm_f32.empty() && !lw.input_layernorm.empty()) {
101 lw.input_layernorm_f32 = bf16vec_to_float_vec(lw.input_layernorm);
102 if (!lw.input_layernorm_f32.empty()) Logger::info(" L" + std::to_string(l) + " input_layernorm_f32 populated from BF16. Size: " + std::to_string(lw.input_layernorm_f32.size()));
103 }
104 if (lw.post_attention_layernorm_f32.empty() && !lw.post_attention_layernorm.empty()) {
105 lw.post_attention_layernorm_f32 = bf16vec_to_float_vec(lw.post_attention_layernorm);
106 if (!lw.post_attention_layernorm_f32.empty()) Logger::info(" L" + std::to_string(l) + " post_attention_layernorm_f32 populated from BF16. Size: " + std::to_string(lw.post_attention_layernorm_f32.size()));
107 }
108 }
109
110 // Validation checks for layer norms
111 for (int l = 0; l < nhl; ++l) {
112 const auto& lw = layers[l];
113 if (lw.input_layernorm_f32.empty()) {
114 Logger::error("[INIT_WEIGHTS_GGUF_CHECK] Layer " + std::to_string(l) +
115 ": input_layernorm_f32 is EMPTY post-GGUF. This WILL cause GPU init errors if this layer is on GPU.");
116 }
117 if (lw.post_attention_layernorm_f32.empty()) {
118 Logger::error("[INIT_WEIGHTS_GGUF_CHECK] Layer " + std::to_string(l) +
119 ": post_attention_layernorm_f32 is EMPTY post-GGUF. This WILL cause GPU init errors if this layer is on GPU.");
120 }
121 }
122 Logger::info("[INIT_WEIGHTS_GGUF] Finished per-layer NORM F32 vector checks post-GGUF.");
123
124 } else {
125 Logger::fatal("TinyLlamaModel::initialize_weights called with neither GGUF nor SafeTensors loader. Cannot initialize weights.");
126 throw std::runtime_error("Model weights source (GGUF or SafeTensors) not provided to initialize_weights.");
127 }
128
129 Logger::info("Finished initializing model weights logic block.");
130
131 if (this->final_norm_f32.empty()) {
132 Logger::error("[INIT_WEIGHTS_FINAL_CHECK] final_norm_f32 is EMPTY. This WILL cause errors if final normalization is needed in F32.");
133 } else {
134 Logger::info("[INIT_WEIGHTS_FINAL_CHECK] final_norm_f32 is POPULATED. Size: " + std::to_string(this->final_norm_f32.size()));
135 }
136
137 if (this->embed_tokens_f32.empty()) {
138 Logger::error("[INIT_WEIGHTS_FINAL_CHECK] embed_tokens_f32 is EMPTY. This WILL cause errors if token embeddings are needed in F32.");
139 } else {
140 Logger::info("[INIT_WEIGHTS_FINAL_CHECK] embed_tokens_f32 is POPULATED. Size: " + std::to_string(this->embed_tokens_f32.size()));
141 }
142}
static void fatal(const std::string &message)
Definition logger.cpp:151
friend void map_gguf_weights(const GGUFData &gguf, TinyLlamaModel &model)

References bf16vec_to_float_vec(), config_, embed_tokens_f32, ensure_embed_tokens_dequantized(), Logger::error(), Logger::fatal(), final_norm, final_norm_f32, gguf_data_, ModelConfig::hidden_size, Logger::info(), ModelConfig::intermediate_size, j, layers, lm_head_f32, map_gguf_weights, ModelConfig::num_hidden_layers, and ModelConfig::vocab_size.

Referenced by TinyLlamaModel(), TinyLlamaModel(), and TinyLlamaModel().

◆ ir_only()

bool TinyLlamaModel::ir_only ( ) const
inline

Definition at line 531 of file model.h.

531{ return ir_only_; }

References ir_only_.

◆ lookup_embedding()

std::vector< float > TinyLlamaModel::lookup_embedding ( int  token_id)

Lookup the embedding vector for a given token ID.

Parameters
token_idThe token ID to lookup.
Returns
The embedding vector as a std::vector<float>.

Definition at line 11 of file model_utils.cpp.

11 {
13 int vs = config_.vocab_size;
14
16 Logger::error("Token ID out of bounds in lookup_embedding: " +
17 std::to_string(token_id));
18 return std::vector<float>(hs, 0.0f);
19 }
20
21 std::vector<float> embedding_vec(hs, 0.0f);
22
23 if (!embed_tokens_q4k.empty()) {
24 if (hs % GGML_QK_K != 0) {
25 Logger::error("Hidden size (" + std::to_string(hs) +
26 ") is not divisible by GGML_QK_K (" +
27 std::to_string(GGML_QK_K) + ") for Q4_K embedding lookup.");
28 return embedding_vec;
29 }
30
31 size_t blocks_per_row = hs / GGML_QK_K;
32 size_t start_block_idx = (size_t)token_id * blocks_per_row;
34
35 if (end_block_idx > embed_tokens_q4k.size()) {
37 "Calculated block index out of bounds for Q4_K embedding table. "
38 "Token: " +
39 std::to_string(token_id) +
40 ", StartBlock: " + std::to_string(start_block_idx) +
41 ", EndBlock: " + std::to_string(end_block_idx) +
42 ", TableSize: " + std::to_string(embed_tokens_q4k.size()));
43 return embedding_vec;
44 }
45
47 for (size_t block_n = 0; block_n < blocks_per_row; ++block_n) {
50
51 size_t dest_offset = block_n * GGML_QK_K;
52
53 size_t elements_to_copy = SAFE_MIN((size_t)GGML_QK_K, (size_t)(hs - dest_offset));
55 elements_to_copy * sizeof(float));
56 }
57 return embedding_vec;
58 }
59
60 else if (!embed_tokens_q8_0.empty()) {
61 if (hs % GGML_QK8_0 != 0) {
62 Logger::error("Hidden size (" + std::to_string(hs) +
63 ") is not divisible by GGML_QK8_0 (" +
64 std::to_string(GGML_QK8_0) +
65 ") for Q8_0 embedding lookup.");
66 return embedding_vec;
67 }
68 size_t blocks_per_row = hs / GGML_QK8_0;
69 size_t start_block_idx = (size_t)token_id * blocks_per_row;
71
72 if (end_block_idx > embed_tokens_q8_0.size()) {
74 "Calculated block index out of bounds for Q8_0 embedding table. "
75 "Token: " +
76 std::to_string(token_id) +
77 ", StartBlock: " + std::to_string(start_block_idx) +
78 ", EndBlock: " + std::to_string(end_block_idx) +
79 ", TableSize: " + std::to_string(embed_tokens_q8_0.size()));
80 return embedding_vec;
81 }
82
84
85 for (size_t block_n = 0; block_n < blocks_per_row; ++block_n) {
89 size_t elements_to_copy = SAFE_MIN(static_cast<size_t>(GGML_QK8_0), static_cast<size_t>(hs - dest_offset));
91 elements_to_copy * sizeof(float));
92
93 }
94
95 if (token_id < 2) {
96 float sum = 0.0f, min_val = embedding_vec[0], max_val = embedding_vec[0];
97 for (int i = 0; i < hs; ++i) {
99 min_val = std::min(min_val, embedding_vec[i]);
100 max_val = std::max(max_val, embedding_vec[i]);
101 }
102 Logger::info("[Q8_0_EMBED_FINAL] Token " + std::to_string(token_id) +
103 " embedding stats: sum=" + std::to_string(sum) +
104 ", mean=" + std::to_string(sum / hs) +
105 ", min=" + std::to_string(min_val) +
106 ", max=" + std::to_string(max_val) +
107 ", first_4=[" + std::to_string(embedding_vec[0]) +
108 ", " + std::to_string(embedding_vec[1]) +
109 ", " + std::to_string(embedding_vec[2]) +
110 ", " + std::to_string(embedding_vec[3]) + "]");
111 }
112 return embedding_vec;
113 }
114
115 else if (!embed_tokens_q6k.empty()) {
116 if (hs % GGML_QK_K != 0) {
117 Logger::error("Hidden size (" + std::to_string(hs) +
118 ") is not divisible by GGML_QK_K (" +
119 std::to_string(GGML_QK_K) + ") for Q6_K embedding lookup.");
120 return embedding_vec;
121 }
122 size_t blocks_per_row = hs / GGML_QK_K;
123 size_t start_block_idx = (size_t)token_id * blocks_per_row;
125
126 if (end_block_idx > embed_tokens_q6k.size()) {
128 "Calculated block index out of bounds for Q6_K embedding table. "
129 "Token: " +
130 std::to_string(token_id) +
131 ", StartBlock: " + std::to_string(start_block_idx) +
132 ", EndBlock: " + std::to_string(end_block_idx) +
133 ", TableSize: " + std::to_string(embed_tokens_q6k.size()));
134 return embedding_vec;
135 }
136
138 for (size_t block_n = 0; block_n < blocks_per_row; ++block_n) {
141 size_t dest_offset = block_n * GGML_QK_K;
142 size_t elements_to_copy = SAFE_MIN(static_cast<size_t>(GGML_QK_K), static_cast<size_t>(hs - dest_offset));
144 elements_to_copy * sizeof(float));
145 }
146 return embedding_vec;
147 }
148
149 else if (!embed_tokens_q5k.empty()) {
150 const size_t blocks_per_row = hs / GGML_QK_K, first = (size_t)token_id * blocks_per_row;
151 if (hs % GGML_QK_K != 0 || first + blocks_per_row > embed_tokens_q5k.size()) {
152 Logger::error("Q5_K embedding table: hidden size " + std::to_string(hs) + " or token " +
153 std::to_string(token_id) + " does not fit its " + std::to_string(embed_tokens_q5k.size()) +
154 " blocks");
155 return embedding_vec;
156 }
158 return embedding_vec;
159 }
160
161 else if (!embed_tokens_f32.empty()) {
162 size_t offset = (size_t)token_id * hs;
163 if (offset + hs > embed_tokens_f32.size()) {
164 Logger::error("Embedding offset out of bounds in F32 lookup for token: " +
165 std::to_string(token_id));
166 return embedding_vec;
167 }
168
169 std::copy(embed_tokens_f32.begin() + offset,
170 embed_tokens_f32.begin() + offset + hs, embedding_vec.begin());
171 return embedding_vec;
172
173 } else if (!embed_tokens.empty()) {
174 size_t offset = (size_t)token_id * hs;
175 if (offset + hs > embed_tokens.size()) {
177 "Embedding offset out of bounds in BF16 lookup for token: " +
178 std::to_string(token_id));
179 return embedding_vec;
180 }
181 std::vector<uint16_t> token_embedding_bf16(
182 embed_tokens.begin() + offset, embed_tokens.begin() + offset + hs);
183
185 return embedding_vec;
186
187 } else {
189 "No valid embedding table found (Q4_K, Q8_0, Q6_K, F32, BF16) for token: " +
190 std::to_string(token_id));
191
192 return embedding_vec;
193 }
194}
#define SAFE_MIN(a, b)
void dequantize_q5_k(const block_q5_K *qblock, float *output)

References bf16vec_to_float_vec(), config_, dequantize_q4_k_m(), dequantize_q5_k(), dequantize_q6_k(), dequantize_q8_0_block(), embed_tokens, embed_tokens_f32, embed_tokens_q4k, embed_tokens_q5k, embed_tokens_q6k, embed_tokens_q8_0, Logger::error(), GGML_QK8_0, GGML_QK_K, ModelConfig::hidden_size, Logger::info(), j, SAFE_MIN, and ModelConfig::vocab_size.

◆ set_gemm_fp32_only()

void TinyLlamaModel::set_gemm_fp32_only ( bool  on)
inline

Definition at line 385 of file model.h.

385{ gemm_fp32_only_ = on; }

References gemm_fp32_only_, and j.

Referenced by tinyllama::TinyLlamaSession::score_rows().

Friends And Related Symbol Documentation

◆ CPUBatchProcessor

Definition at line 570 of file model.h.

◆ map_gguf_weights

void map_gguf_weights ( const GGUFData &  gguf,
TinyLlamaModel &  model 
)
friend

Definition at line 879 of file weight_management.cpp.

879 {
880 Logger::info("Mapping GGUF weights to model fields (ULTRA-OPTIMIZED VERSION)...");
881
882 const uint8_t* actual_data_block_start = nullptr;
883
884 // Determine which data source to use
885 if (gguf.mapped_tensor_data != nullptr && gguf.mapped_tensor_data_size > 0) {
886 const uint8_t* mmap_buffer_start = static_cast<const uint8_t*>(gguf.mapped_tensor_data);
887 actual_data_block_start = mmap_buffer_start + gguf.offset_diff_for_mmap;
888 Logger::info("map_gguf_weights: Using mmap mode (ZERO-COPY). Size: " +
889 std::to_string(gguf.mapped_tensor_data_size) + " bytes.");
890 } else if (!gguf.tensor_data.empty()) {
891 actual_data_block_start = gguf.tensor_data.data();
892 Logger::info("map_gguf_weights: Using non-mmap mode. Size: " +
893 std::to_string(gguf.tensor_data.size()) + " bytes.");
894 } else {
895 Logger::error("GGUF tensor data is not available. Cannot map weights.");
896 return;
897 }
898
899 const size_t num_tensors = gguf.tensor_infos_map.size();
900 Logger::info("Processing " + std::to_string(num_tensors) + " tensors with ultra-optimized parallel mapping...");
901
902 // Pre-allocate containers to avoid reallocations during parallel processing
903 std::vector<std::pair<std::string, GGUFTensorInfo>> tensor_pairs;
904 tensor_pairs.reserve(num_tensors);
905 for (const auto& pair : gguf.tensor_infos_map) {
906 tensor_pairs.emplace_back(pair.first, pair.second);
907 }
908
909 // Reserve capacity for major model containers to reduce allocations
910 const size_t typical_blocks = 4096;
911 if (model.lm_head_q8_0.capacity() == 0) model.lm_head_q8_0.reserve(32768);
912 if (model.embed_tokens_q8_0.capacity() == 0) model.embed_tokens_q8_0.reserve(32768);
913
914 for (auto& layer : model.layers) {
915 if (layer.q_proj_q8_0.capacity() == 0) layer.q_proj_q8_0.reserve(typical_blocks);
916 if (layer.k_proj_q8_0.capacity() == 0) layer.k_proj_q8_0.reserve(typical_blocks);
917 if (layer.v_proj_q8_0.capacity() == 0) layer.v_proj_q8_0.reserve(typical_blocks);
918 if (layer.o_proj_q8_0.capacity() == 0) layer.o_proj_q8_0.reserve(typical_blocks);
919 if (layer.gate_proj_q8_0.capacity() == 0) layer.gate_proj_q8_0.reserve(typical_blocks);
920 if (layer.up_proj_q8_0.capacity() == 0) layer.up_proj_q8_0.reserve(typical_blocks);
921 if (layer.down_proj_q8_0.capacity() == 0) layer.down_proj_q8_0.reserve(typical_blocks);
922 }
923
924 // BLAZING FAST: Sort tensors by type and process in bulk
925 std::vector<size_t> global_tensor_indices;
926 std::vector<std::vector<size_t>> layer_tensor_indices(model.layers.size());
927
928 global_tensor_indices.reserve(10); // output.weight, token_embd.weight, output_norm.weight, etc.
929 for (auto& layer_indices : layer_tensor_indices) {
930 layer_indices.reserve(9); // 7 weights + 2 norms per layer
931 }
932
933 // ULTRA-FAST categorization without string operations
934 for (size_t i = 0; i < tensor_pairs.size(); ++i) {
935 const std::string& name = tensor_pairs[i].first;
936 if (name[0] == 'o' || name[0] == 't') { // output.weight, token_embd.weight, output_norm.weight
937 global_tensor_indices.push_back(i);
938 } else if (name.size() > 4 && name[0] == 'b' && name[1] == 'l' && name[2] == 'k' && name[3] == '.') {
939 // Extract layer index without substr - MUCH faster
940 size_t layer_start = 4;
941 size_t layer_end = name.find('.', layer_start);
942 if (layer_end != std::string::npos) {
943 int layer_idx = 0;
944 for (size_t pos = layer_start; pos < layer_end; ++pos) {
945 layer_idx = layer_idx * 10 + (name[pos] - '0');
946 }
947 if (layer_idx >= 0 && static_cast<size_t>(layer_idx) < model.layers.size()) {
948 layer_tensor_indices[layer_idx].push_back(i);
949 }
950 }
951 }
952 }
953
954 std::atomic<int> processed_count{0};
955 std::atomic<int> error_count{0};
956 std::mutex first_error_mu;
957 std::string first_error; // reported if any tensor fails to map
958
959 // Process global tensors sequentially (small count, avoid overhead)
960 for (size_t idx : global_tensor_indices) {
961 try {
962 const std::string& target_field_key = tensor_pairs[idx].first;
963 const GGUFTensorInfo& info = tensor_pairs[idx].second;
965
966 // Global tensors with optimized type dispatch
967 if (target_field_key == "output.weight") {
968 switch (info.type) {
970 size_t num_blocks = info.size_in_bytes / sizeof(block_q6_K);
971 model.lm_head_q6k.resize(num_blocks);
972 std::memcpy(model.lm_head_q6k.data(), tensor_data_ptr, info.size_in_bytes);
973 break;
974 }
976 size_t num_blocks = info.size_in_bytes / sizeof(block_q4_K);
977 model.lm_head_q4k.resize(num_blocks);
978 std::memcpy(model.lm_head_q4k.data(), tensor_data_ptr, info.size_in_bytes);
979 break;
980 }
982 model.lm_head_q5k.resize(info.size_in_bytes / sizeof(block_q5_K));
983 std::memcpy(model.lm_head_q5k.data(), tensor_data_ptr, info.size_in_bytes);
984 break;
985 }
987 size_t num_blocks = info.size_in_bytes / sizeof(block_q8_0);
988 model.lm_head_q8_0.resize(num_blocks);
989 std::memcpy(model.lm_head_q8_0.data(), tensor_data_ptr, info.size_in_bytes);
990 break;
991 }
993 size_t num_blocks = info.size_in_bytes / sizeof(block_q8_K);
994 model.lm_head_q8k.resize(num_blocks);
995 std::memcpy(model.lm_head_q8k.data(), tensor_data_ptr, info.size_in_bytes);
996 break;
997 }
999 size_t num_elements = info.size_in_bytes / sizeof(float);
1000 model.lm_head_f32.resize(num_elements);
1001 std::memcpy(model.lm_head_f32.data(), tensor_data_ptr, info.size_in_bytes);
1002 break;
1003 }
1004 default:
1005 if (!dequant_legacy_to_f32(info, tensor_data_ptr, model.lm_head_f32)) throw std::runtime_error(target_field_key + ": unsupported tensor type " + ggml_type_name(info.type));
1006 break;
1007 }
1009 continue;
1010 }
1011
1012 if (target_field_key == "token_embd.weight") {
1013 switch (info.type) {
1015 size_t num_blocks = info.size_in_bytes / sizeof(block_q4_K);
1016 model.embed_tokens_q4k.resize(num_blocks);
1017 std::memcpy(model.embed_tokens_q4k.data(), tensor_data_ptr, info.size_in_bytes);
1018 break;
1019 }
1021 model.embed_tokens_q5k.resize(info.size_in_bytes / sizeof(block_q5_K));
1022 std::memcpy(model.embed_tokens_q5k.data(), tensor_data_ptr, info.size_in_bytes);
1023 break;
1024 }
1026 size_t num_blocks = info.size_in_bytes / sizeof(block_q8_0);
1027 model.embed_tokens_q8_0.resize(num_blocks);
1028 std::memcpy(model.embed_tokens_q8_0.data(), tensor_data_ptr, info.size_in_bytes);
1029 break;
1030 }
1032 size_t num_blocks = info.size_in_bytes / sizeof(block_q8_K);
1033 model.embed_tokens_q8k.resize(num_blocks);
1034 std::memcpy(model.embed_tokens_q8k.data(), tensor_data_ptr, info.size_in_bytes);
1035 break;
1036 }
1038 size_t num_blocks = info.size_in_bytes / sizeof(block_q6_K);
1039 model.embed_tokens_q6k.resize(num_blocks);
1040 std::memcpy(model.embed_tokens_q6k.data(), tensor_data_ptr, info.size_in_bytes);
1041 break;
1042 }
1044 size_t num_elements = info.size_in_bytes / sizeof(float);
1045 model.embed_tokens_f32.resize(num_elements);
1046 std::memcpy(model.embed_tokens_f32.data(), tensor_data_ptr, info.size_in_bytes);
1047 break;
1048 }
1049 default:
1050 if (!dequant_legacy_to_f32(info, tensor_data_ptr, model.embed_tokens_f32)) throw std::runtime_error(target_field_key + ": unsupported tensor type " + ggml_type_name(info.type));
1051 break;
1052 }
1054 continue;
1055 }
1056
1057 if (target_field_key == "output_norm.weight") {
1058 if (info.type == GGMLType::GGML_TYPE_F32) {
1059 size_t num_elements = info.size_in_bytes / sizeof(float);
1060 model.final_norm_f32.resize(num_elements);
1061 std::memcpy(model.final_norm_f32.data(), tensor_data_ptr, info.size_in_bytes);
1062 } else if (!dequant_legacy_to_f32(info, tensor_data_ptr, model.final_norm_f32)) throw std::runtime_error(target_field_key + ": unsupported tensor type " + ggml_type_name(info.type));
1064 continue;
1065 }
1066
1067 } catch (const std::exception& e) {
1068 error_count++;
1069 std::lock_guard<std::mutex> lk(first_error_mu);
1070 if (first_error.empty()) first_error = e.what();
1071 }
1072 }
1073
1074 // ULTRA-FAST: Process layers in parallel with pre-sorted tensors
1075 #pragma omp parallel for schedule(static) if(model.layers.size() > 4)
1076 for (int layer_idx = 0; layer_idx < (int)layer_tensor_indices.size(); ++layer_idx) {
1078 if (layer_indices.empty()) continue;
1079
1081
1082 try {
1083 for (size_t idx : layer_indices) {
1084 const std::string& name = tensor_pairs[idx].first;
1085 const GGUFTensorInfo& info = tensor_pairs[idx].second;
1087
1088 // BLAZING FAST: Direct character matching (faster than hashing)
1089 const size_t last_dot = name.find_last_of('.');
1090 if (last_dot == std::string::npos) continue;
1091
1092 const char* field = name.c_str() + name.find('.', 4) + 1;
1093
1094 // BLAZING FAST: Direct character-based dispatch without string operations
1095 #define LEGACY_OR_THROW(target_f32) \
1096 default: \
1097 if (!dequant_legacy_to_f32(info, tensor_data_ptr, target_f32)) \
1098 throw std::runtime_error(name + ": unsupported tensor type " + ggml_type_name(info.type)); \
1099 break;
1100 #define FAST_COPY_WEIGHT(target_vec, block_type) \
1101 target_vec.resize(info.size_in_bytes / sizeof(block_type)); \
1102 std::memcpy(target_vec.data(), tensor_data_ptr, info.size_in_bytes);
1103
1104 // IMPROVED: Pattern matching based on tensor name structure
1105 const char* name_cstr = name.c_str();
1106 const size_t name_len = name.length();
1107
1108 if (name_len > 10 && name.find("attn_") != std::string::npos) {
1109 if (name.find("attn_q.weight") != std::string::npos) {
1110 switch (info.type) {
1111 case GGMLType::GGML_TYPE_Q8_0: FAST_COPY_WEIGHT(layer.q_proj_q8_0, block_q8_0); break;
1117 case GGMLType::GGML_TYPE_F32: FAST_COPY_WEIGHT(layer.q_proj_f32, float);
1118 Logger::info("[MAP_DEBUG] " + name + " F32 copied, elems=" +
1119 std::to_string(layer.q_proj_f32.size()) +
1120 " into layer_idx=" + std::to_string(layer_idx));
1121 break; // transformer_cpp fp32 exports
1122 LEGACY_OR_THROW(layer.q_proj_f32)
1123 }
1124 } else if (name.find("attn_k.weight") != std::string::npos) {
1125 switch (info.type) {
1126 case GGMLType::GGML_TYPE_Q8_0: FAST_COPY_WEIGHT(layer.k_proj_q8_0, block_q8_0); break;
1132 case GGMLType::GGML_TYPE_F32: FAST_COPY_WEIGHT(layer.k_proj_f32, float); break; // transformer_cpp fp32 exports
1133 LEGACY_OR_THROW(layer.k_proj_f32)
1134 }
1135 } else if (name.find("attn_v.weight") != std::string::npos) {
1136 switch (info.type) {
1137 case GGMLType::GGML_TYPE_Q8_0: FAST_COPY_WEIGHT(layer.v_proj_q8_0, block_q8_0); break;
1143 case GGMLType::GGML_TYPE_F32: FAST_COPY_WEIGHT(layer.v_proj_f32, float); break; // transformer_cpp fp32 exports
1144 LEGACY_OR_THROW(layer.v_proj_f32)
1145 }
1146 } else if (name.find("attn_output.weight") != std::string::npos) {
1147 switch (info.type) {
1148 case GGMLType::GGML_TYPE_Q8_0: FAST_COPY_WEIGHT(layer.o_proj_q8_0, block_q8_0); break;
1154 case GGMLType::GGML_TYPE_F32: FAST_COPY_WEIGHT(layer.o_proj_f32, float); break; // transformer_cpp fp32 exports
1155 LEGACY_OR_THROW(layer.o_proj_f32)
1156 }
1157 } else if (name.find("attn_norm.weight") != std::string::npos) {
1158 if (info.type == GGMLType::GGML_TYPE_F32) { FAST_COPY_WEIGHT(layer.input_layernorm_f32, float); }
1159 else if (!dequant_legacy_to_f32(info, tensor_data_ptr, layer.input_layernorm_f32))
1160 throw std::runtime_error(name + ": unsupported tensor type " + ggml_type_name(info.type));
1161 }
1162 } else if (name_len > 10 && name.find("ffn_") != std::string::npos) {
1163 if (name.find("ffn_gate_inp.weight") != std::string::npos) { // MoE router
1164 if (info.type == GGMLType::GGML_TYPE_F32) { FAST_COPY_WEIGHT(layer.moe_router_f32, float); }
1165 else if (info.type == GGMLType::GGML_TYPE_Q8_0) { FAST_COPY_WEIGHT(layer.moe_router_q8_0, block_q8_0); }
1166 else if (!dequant_legacy_to_f32(info, tensor_data_ptr, layer.moe_router_f32))
1167 throw std::runtime_error(name + ": unsupported tensor type " + ggml_type_name(info.type));
1168 } else if (name.find("_exps.weight") != std::string::npos) { // MoE expert stacks
1169 std::vector<float>& dst = name.find("ffn_gate_exps") != std::string::npos ? layer.moe_gate_exps_f32
1170 : name.find("ffn_up_exps") != std::string::npos ? layer.moe_up_exps_f32
1171 : layer.moe_down_exps_f32;
1172 if (info.type == GGMLType::GGML_TYPE_F32) { FAST_COPY_WEIGHT(dst, float); }
1173 else if (!dequant_legacy_to_f32(info, tensor_data_ptr, dst))
1174 throw std::runtime_error(name + ": MoE expert stacks must be F32, F16 or Q4_0/Q4_1/Q5_0/Q5_1 (got " +
1175 std::string(ggml_type_name(info.type)) + ")");
1176 } else if (name.find("ffn_gate.weight") != std::string::npos) {
1177 switch (info.type) {
1178 case GGMLType::GGML_TYPE_Q8_0: FAST_COPY_WEIGHT(layer.gate_proj_q8_0, block_q8_0); break;
1179 case GGMLType::GGML_TYPE_Q4_K: FAST_COPY_WEIGHT(layer.gate_proj_q4k, block_q4_K); break;
1180 case GGMLType::GGML_TYPE_Q5_K: FAST_COPY_WEIGHT(layer.gate_proj_q5k, block_q5_K); break;
1181 case GGMLType::GGML_TYPE_Q6_K: FAST_COPY_WEIGHT(layer.gate_proj_q6k, block_q6_K); break;
1182 case GGMLType::GGML_TYPE_Q8_K: FAST_COPY_WEIGHT(layer.gate_proj_q8k, block_q8_K); break;
1184 case GGMLType::GGML_TYPE_F32: FAST_COPY_WEIGHT(layer.gate_proj_f32, float); break; // transformer_cpp fp32 exports
1185 LEGACY_OR_THROW(layer.gate_proj_f32)
1186 }
1187 } else if (name.find("ffn_up.weight") != std::string::npos) {
1188 switch (info.type) {
1189 case GGMLType::GGML_TYPE_Q8_0: FAST_COPY_WEIGHT(layer.up_proj_q8_0, block_q8_0); break;
1190 case GGMLType::GGML_TYPE_Q4_K: FAST_COPY_WEIGHT(layer.up_proj_q4k, block_q4_K); break;
1191 case GGMLType::GGML_TYPE_Q5_K: FAST_COPY_WEIGHT(layer.up_proj_q5k, block_q5_K); break;
1192 case GGMLType::GGML_TYPE_Q6_K: FAST_COPY_WEIGHT(layer.up_proj_q6k, block_q6_K); break;
1193 case GGMLType::GGML_TYPE_Q8_K: FAST_COPY_WEIGHT(layer.up_proj_q8k, block_q8_K); break;
1195 case GGMLType::GGML_TYPE_F32: FAST_COPY_WEIGHT(layer.up_proj_f32, float); break; // transformer_cpp fp32 exports
1196 LEGACY_OR_THROW(layer.up_proj_f32)
1197 }
1198 } else if (name.find("ffn_down.weight") != std::string::npos) {
1199 switch (info.type) {
1200 case GGMLType::GGML_TYPE_Q8_0: FAST_COPY_WEIGHT(layer.down_proj_q8_0, block_q8_0); break;
1201 case GGMLType::GGML_TYPE_Q4_K: FAST_COPY_WEIGHT(layer.down_proj_q4k, block_q4_K); break;
1202 case GGMLType::GGML_TYPE_Q5_K: FAST_COPY_WEIGHT(layer.down_proj_q5k, block_q5_K); break;
1203 case GGMLType::GGML_TYPE_Q6_K: FAST_COPY_WEIGHT(layer.down_proj_q6k, block_q6_K); break;
1204 case GGMLType::GGML_TYPE_Q8_K: FAST_COPY_WEIGHT(layer.down_proj_q8k, block_q8_K); break;
1206 case GGMLType::GGML_TYPE_F32: FAST_COPY_WEIGHT(layer.down_proj_f32, float); break; // transformer_cpp fp32 exports
1207 LEGACY_OR_THROW(layer.down_proj_f32)
1208 }
1209 } else if (name.find("ffn_norm.weight") != std::string::npos) {
1210 if (info.type == GGMLType::GGML_TYPE_F32) { FAST_COPY_WEIGHT(layer.post_attention_layernorm_f32, float); }
1211 else if (!dequant_legacy_to_f32(info, tensor_data_ptr, layer.post_attention_layernorm_f32))
1212 throw std::runtime_error(name + ": unsupported tensor type " + ggml_type_name(info.type));
1213 }
1214 }
1215
1216 #undef FAST_COPY_WEIGHT
1217 #undef LEGACY_OR_THROW
1218 }
1220 } catch (const std::exception& e) {
1221 error_count++;
1222 std::lock_guard<std::mutex> lk(first_error_mu);
1223 if (first_error.empty()) first_error = e.what();
1224 }
1225 }
1226
1227 Logger::info("Finished mapping GGUF weights: " + std::to_string(processed_count.load()) + "/" +
1228 std::to_string(num_tensors) + " tensors processed successfully (errors: " +
1229 std::to_string(error_count.load()) + ") with ultra-optimized parallel mapping");
1230 // A tensor that failed to map would leave the model silently incomplete.
1231 if (error_count.load() > 0)
1232 throw std::runtime_error("GGUF weight mapping failed for " + std::to_string(error_count.load()) +
1233 " layer(s); first error: " + first_error);
1234}
@ GGML_TYPE_F32
Definition ggml_types.h:22
@ GGML_TYPE_BF16
Definition ggml_types.h:40
@ GGML_TYPE_Q8_K
Definition ggml_types.h:36
@ GGML_TYPE_Q6_K
Definition ggml_types.h:35
@ GGML_TYPE_Q8_0
Definition ggml_types.h:29
@ GGML_TYPE_Q5_K
Definition ggml_types.h:34
@ GGML_TYPE_Q4_K
Definition ggml_types.h:33
const char * name
const char * ggml_type_name(GGMLType type)
Gets the string name of a GGML type.
Information about a tensor stored in a GGUF file.
size_t size_in_bytes
uint64_t offset
Structure holding all weights for a single transformer layer.
Definition model.h:253
4-bit K-quantized block structure
5-bit K-quantized block structure (ggml's block_q5_K)
6-bit K-quantized block structure
Simple 8-bit quantized block structure.
8-bit K-quantized block structure with block sums
#define FAST_COPY_WEIGHT(target_vec, block_type)
bool dequant_legacy_to_f32(const GGUFTensorInfo &info, const uint8_t *src, std::vector< float > &out)
#define LEGACY_OR_THROW(target_f32)

Referenced by initialize_weights().

Member Data Documentation

◆ bf16_batch_gemm_failed_

bool TinyLlamaModel::bf16_batch_gemm_failed_ = false
private

Definition at line 575 of file model.h.

◆ config_

◆ cpu_batch_processor_

std::unique_ptr<class CPUBatchProcessor> TinyLlamaModel::cpu_batch_processor_
private

Definition at line 701 of file model.h.

Referenced by forward_cpu_batch().

◆ embed_tokens

std::vector<uint16_t> TinyLlamaModel::embed_tokens
private

◆ embed_tokens_f32

std::vector<float> TinyLlamaModel::embed_tokens_f32
private

◆ embed_tokens_q4k

std::vector<block_q4_K> TinyLlamaModel::embed_tokens_q4k
private

◆ embed_tokens_q5k

std::vector<block_q5_K> TinyLlamaModel::embed_tokens_q5k
private

◆ embed_tokens_q6k

std::vector<block_q6_K> TinyLlamaModel::embed_tokens_q6k
private

◆ embed_tokens_q8_0

std::vector<block_q8_0> TinyLlamaModel::embed_tokens_q8_0
private

◆ embed_tokens_q8k

std::vector<block_q8_K> TinyLlamaModel::embed_tokens_q8k
private

Definition at line 586 of file model.h.

Referenced by dequantize_all_if_small(), and ensure_embed_tokens_dequantized().

◆ f32_concatenated_weights_loaded_

bool TinyLlamaModel::f32_concatenated_weights_loaded_ = false
private

Definition at line 699 of file model.h.

◆ final_norm

std::vector<uint16_t> TinyLlamaModel::final_norm
private

◆ final_norm_f32

std::vector<float> TinyLlamaModel::final_norm_f32
private

◆ final_norm_q4k

std::vector<block_q4_K> TinyLlamaModel::final_norm_q4k
private

Definition at line 582 of file model.h.

◆ final_norm_q6k

std::vector<block_q6_K> TinyLlamaModel::final_norm_q6k
private

Definition at line 584 of file model.h.

◆ gemm_fp32_only_

bool TinyLlamaModel::gemm_fp32_only_ = false
private

Definition at line 576 of file model.h.

Referenced by gemm_fp32_only(), and set_gemm_fp32_only().

◆ gguf_data_

std::unique_ptr<GGUFData> TinyLlamaModel::gguf_data_
private

◆ ir_only_

bool TinyLlamaModel::ir_only_ = false
private

Definition at line 697 of file model.h.

Referenced by ir_only(), and TinyLlamaModel().

◆ layers

◆ lm_head

std::vector<uint16_t> TinyLlamaModel::lm_head
private

◆ lm_head_f32

std::vector<float> TinyLlamaModel::lm_head_f32
private

◆ lm_head_q4k

std::vector<block_q4_K> TinyLlamaModel::lm_head_q4k
private

◆ lm_head_q5k

std::vector<block_q5_K> TinyLlamaModel::lm_head_q5k
private

Definition at line 583 of file model.h.

Referenced by dequantize_all_if_small(), and ensure_lm_head_dequantized().

◆ lm_head_q6k

std::vector<block_q6_K> TinyLlamaModel::lm_head_q6k
private

◆ lm_head_q8_0

std::vector<block_q8_0> TinyLlamaModel::lm_head_q8_0
private

◆ lm_head_q8k

std::vector<block_q8_K> TinyLlamaModel::lm_head_q8k
private

Definition at line 586 of file model.h.

Referenced by dequantize_all_if_small(), ensure_lm_head_dequantized(), and forward().

◆ model_path_

std::string TinyLlamaModel::model_path_
private

Definition at line 698 of file model.h.

Referenced by TinyLlamaModel(), and TinyLlamaModel().

◆ precomputed_freqs_cis_

std::vector<std::pair<float, float> > TinyLlamaModel::precomputed_freqs_cis_
private

◆ use_bf16_tensor_cores_

bool TinyLlamaModel::use_bf16_tensor_cores_ = false
private

Definition at line 574 of file model.h.

Referenced by initialize_gpu_and_rope().


The documentation for this class was generated from the following files: