ember.cpp 0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
quantization.cpp File Reference
#include "quantization.h"
#include "model_macros.h"
#include <algorithm>
#include <atomic>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <limits>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "logger.h"
#include "gguf_parser.h"
Include dependency graph for quantization.cpp:

Go to the source code of this file.

Functions

float fp16_to_fp32 (uint16_t h, bool is_gguf_scale_field)
 Converts a 16-bit floating point number to 32-bit float.
 
uint16_t fp32_to_fp16 (float f)
 Converts a 32-bit float to 16-bit floating point.
 
static void get_scale_min_k4 (int j, const uint8_t *q, uint8_t *d_val, uint8_t *m_val)
 
static void get_scale_min_indices_q4_K (int j, const uint8_t *scales, uint8_t *scale_index, uint8_t *min_index)
 
void dequantize_q4_k_m (const block_q4_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
 
void dequantize_q5_k (const block_q5_K *qblock, float *output)
 
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_q6_k (const block_q6_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
 
void handle_i8_tensor (const void *input_data, float *output_data, size_t num_elements)
 Handles conversion of int8 tensor data to float32.
 
void quantize_q4_k_m (const float *input, void *output_qblock_void, int num_elements)
 Quantizes float32 data to Q4_K format.
 
void dequantize_q2_k (const void *qblock_void, float *output, int num_weights_in_block)
 
void dequantize_q3_k (const void *qblock_void, float *output, int num_weights_in_block)
 Dequantizes a Q3_K quantized block to float32.
 
void quantize_q6_k (const float *input, void *output_qblock_void, int num_elements)
 Quantizes float32 data to Q6_K format.
 
const char * ggml_type_name (GGMLType type)
 Gets the string name of a GGML type.
 
size_t ggml_type_size (GGMLType type)
 Gets the size in bytes of a GGML type.
 
size_t ggml_type_block_size (GGMLType type)
 Gets the block size for a GGML type.
 
std::vector< block_q8_K > quantize_fp32_to_q8_K (const std::vector< float > &f_data)
 Quantizes float32 data to Q8_K format.
 
float vec_dot_q6_k_q8_k_cpu (int n, const std::vector< block_q6_K > &x_vec, const std::vector< block_q8_K > &y_vec, bool log_this_call)
 Computes dot product between Q6_K and Q8_K vectors on CPU.
 
void matvec_q6k_q8k_cpu (const std::vector< block_q6_K > &mat_q6k, const std::vector< block_q8_K > &vec_q8k, std::vector< float > &out_f32, int rows, int cols, bool log_calls)
 Computes matrix-vector product between Q6_K matrix and Q8_K vector on CPU.
 
float vec_dot_q4_k_q8_k_cpu (int n, const std::vector< block_q4_K > &x_vec, const std::vector< block_q8_K > &y_vec, bool log_this_call)
 Computes dot product between Q4_K and Q8_K vectors on CPU.
 
void matvec_q4k_q8k_cpu (const std::vector< block_q4_K > &mat_q4k, const std::vector< block_q8_K > &vec_q8k, std::vector< float > &out_f32, int rows, int cols, bool log_calls)
 Computes matrix-vector product between Q4_K matrix and Q8_K vector on CPU.
 
void dequantize_q8_k (const std::vector< block_q8_K > &q_data, std::vector< float > &x, int n, 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_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_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.
 

Variables

constexpr float K_SCALE_VALUES [64]
 
constexpr float K_MIN_VALUES [64]
 
static std::atomic< int > g_vec_dot_q4_k_q8_k_log_count {0}
 

Function Documentation

◆ dequantize_q2_k()

void dequantize_q2_k ( const void *  qblock_void,
float *  output,
int  num_weights_in_block 
)

Definition at line 428 of file quantization.cpp.

429 {
431 throw std::invalid_argument(
432 "dequantize_q2_k currently only supports block size " +
433 std::to_string(GGML_QK_K));
434 }
435
436 const block_q2_K* qblock = static_cast<const block_q2_K*>(qblock_void);
437
438 const float d_float_raw = fp16_to_fp32(qblock->d);
439 const float dmin_float_raw = fp16_to_fp32(qblock->dmin);
440
441 const float d_float = (!std::isfinite(d_float_raw)) ? 0.0f : d_float_raw;
442 const float dmin_float =
443 (!std::isfinite(dmin_float_raw)) ? 0.0f : dmin_float_raw;
444
447
448 const uint8_t* scales_ptr = qblock->scales;
449 const uint8_t* qs_ptr = qblock->qs;
450 int weight_index = 0;
451 float dequantized_scales[16];
452
453 for (int i = 0; i < 8; ++i) {
457
458 dequantized_scales[i * 2 + 0] =
459 d_float_clamped * static_cast<float>(scale_low);
460 dequantized_scales[i * 2 + 1] =
461 d_float_clamped * static_cast<float>(scale_high);
462
463 dequantized_scales[i * 2 + 0] =
465 dequantized_scales[i * 2 + 1] =
467 }
468
469 weight_index = 0;
470 for (int j = 0; j < GGML_QK_K / 16; ++j) {
472
473 const uint8_t* qs_subblock_ptr = qs_ptr + j * 4;
474
475 for (int i = 0; i < 4; ++i) {
477
478 uint8_t q0 = (packed_weights >> 0) & 0x03;
479 uint8_t q1 = (packed_weights >> 2) & 0x03;
480 uint8_t q2 = (packed_weights >> 4) & 0x03;
481 uint8_t q3 = (packed_weights >> 6) & 0x03;
482
483 float val0 =
484 sub_block_scale * static_cast<float>(q0) + dmin_float_clamped;
485 float val1 =
486 sub_block_scale * static_cast<float>(q1) + dmin_float_clamped;
487 float val2 =
488 sub_block_scale * static_cast<float>(q2) + dmin_float_clamped;
489 float val3 =
490 sub_block_scale * static_cast<float>(q3) + dmin_float_clamped;
491
496
498
500
502
504 }
505 }
507}
constexpr float TENSOR_SCALE_MAX
Constants for tensor value validation.
Definition gguf_parser.h:50
constexpr float TENSOR_SCALE_MIN
Definition gguf_parser.h:51
constexpr size_t GGML_QK_K
Block size constants for different quantization formats.
Definition gguf_parser.h:42
size_t j
#define SAFE_MAX(a, b)
#define SAFE_MIN(a, b)
float fp16_to_fp32(uint16_t h, bool is_gguf_scale_field)
Converts a 16-bit floating point number to 32-bit float.
2-bit K-quantized block structure

References fp16_to_fp32(), GGML_QK_K, j, SAFE_MAX, SAFE_MIN, TENSOR_SCALE_MAX, and TENSOR_SCALE_MIN.

◆ dequantize_q3_k()

void dequantize_q3_k ( const void *  q_data,
float *  f_data,
int  num_weights_in_block 
)

Dequantizes a Q3_K quantized block to float32.

Parameters
q_dataPointer to quantized data
f_dataOutput float array
num_weights_in_blockNumber of weights to dequantize

Definition at line 509 of file quantization.cpp.

510 {
512 throw std::invalid_argument(
513 "dequantize_q3_k currently only supports block size " +
514 std::to_string(GGML_QK_K));
515 }
516
517 const block_q3_K* qblock = static_cast<const block_q3_K*>(qblock_void);
518
519 const float d_float_raw = fp16_to_fp32(qblock->d);
520 const float dmin_float_raw = fp16_to_fp32(qblock->dmin);
521
522 const float d_float = (!std::isfinite(d_float_raw)) ? 0.0f : d_float_raw;
523 const float dmin_float =
524 (!std::isfinite(dmin_float_raw)) ? 0.0f : dmin_float_raw;
525
526 const uint8_t* hmask_ptr = qblock->hmask;
527 const uint8_t* qs_ptr = qblock->qs;
528 const uint8_t* scales_ptr = qblock->scales;
529
530 int weight_index = 0;
531
532 for (int j = 0; j < GGML_QK_K / 16; ++j) {
534
535 if (j < 8) {
536 scale_idx = scales_ptr[j] & 0x3F;
537 } else {
538 scale_idx = scales_ptr[j + 4] & 0x3F;
539 }
540
541 assert(scale_idx < 64 && "Scale index out of bounds for Q3_K lookup");
543
545 const float final_sub_block_min = dmin_float;
546
547 for (int i = 0; i < 4; ++i) {
548 uint8_t qs_byte = qs_ptr[j * 4 + i];
550
551 for (int bit_pos = 0; bit_pos < 8; bit_pos += 2) {
552 uint8_t lower_bits = (qs_byte >> bit_pos) & 0x3;
553
554 int hmask_bit_idx = (i * 4) + (bit_pos / 2);
555
557
558 uint8_t q_val = (high_bit << 2) | lower_bits;
559
560 float val = final_sub_block_scale * static_cast<float>(q_val) +
562
563 if (!std::isfinite(val)) {
564 val = 0.0f;
565 }
566
568 }
569 }
570 }
571
572 if (weight_index != GGML_QK_K) {
573 std::cout << "ERROR: Processed " << weight_index << " weights instead of "
574 << GGML_QK_K << std::endl;
575
576 while (weight_index < GGML_QK_K) {
577 output[weight_index++] = 0.0f;
578 }
579 }
580}
constexpr float K_SCALE_VALUES[64]
3-bit K-quantized block structure

References fp16_to_fp32(), GGML_QK_K, j, and K_SCALE_VALUES.

◆ dequantize_q4_k_m()

void dequantize_q4_k_m ( const block_q4_K *  qblock,
float *  output,
int  num_weights_in_block,
bool  log_this_block 
)

Definition at line 171 of file quantization.cpp.

172 {
174 std::cout
175 << "Warning: dequantize_q4_k_m called with num_weights != GGML_QK_K ("
176 << num_weights_in_block << ")" << std::endl;
177 std::memset(output, 0, num_weights_in_block * sizeof(float));
178 return;
179 }
180
181 const float d_super_scale = fp16_to_fp32(qblock->d, false);
182 const float d_super_min = fp16_to_fp32(qblock->dmin, false);
183
184 const uint8_t * q_bytes_ptr = qblock->qs; // Pointer to the start of quantized data for the block
185 float * y_ptr = output; // Pointer to the start of output float data for the block
186
187 int scale_group_idx = 0; // This will be the 'is' in llama.cpp reference (0, 2, 4, 6)
188
189 // Loop 4 times, processing 64 elements (four 16-element sub-sub-blocks) in each iteration.
190 // This corresponds to the outer j loop in dequantize_row_q4_K from llama.cpp (j from 0 to QK_K, step 64)
194
195 // Get scales/mins for the two 32-element halves of this 64-element chunk
196 // The `j` for get_scale_min_k4 is the 32-element group index (0-7)
199
200 const float d1 = d_super_scale * static_cast<float>(sc_val1);
201 const float m1 = d_super_min * static_cast<float>(m_val1);
202 const float d2 = d_super_scale * static_cast<float>(sc_val2);
203 const float m2 = d_super_min * static_cast<float>(m_val2);
204
205 // Dequantize the first 32 elements of this 64-element chunk
206 for (int l = 0; l < 32; ++l) {
207 // q_bytes_ptr points to the start of the 32 bytes for these 64 quants
208 uint8_t quant_nibble = (q_bytes_ptr[l] & 0x0F); // First nibble for first element
209 *y_ptr++ = d1 * static_cast<float>(quant_nibble) - m1;
210 }
211
212 // Dequantize the second 32 elements of this 64-element chunk
213 for (int l = 0; l < 32; ++l) {
214 uint8_t quant_nibble = (q_bytes_ptr[l] >> 4); // Upper nibble from the same byte
215 *y_ptr++ = d2 * static_cast<float>(quant_nibble) - m2;
216 }
217
218 q_bytes_ptr += 32; // Advance q_bytes_ptr by 32 bytes (covering 64 quants)
219 scale_group_idx += 2; // Advance the scale group index for get_scale_min_k4
220 }
221}
static void get_scale_min_k4(int j, const uint8_t *q, uint8_t *d_val, uint8_t *m_val)

References fp16_to_fp32(), get_scale_min_k4(), GGML_QK_K, and j.

Referenced by dequant_span_to_f32(), dequantize_vector_q4k_to_f32(), TinyLlamaModel::initialize_gpu_and_rope(), TinyLlamaModel::lookup_embedding(), and matvec_q4k_f32_vector_cpu().

◆ dequantize_q5_k()

void dequantize_q5_k ( const block_q5_K *  qblock,
float *  output 
)

Definition at line 226 of file quantization.cpp.

226 {
227 const float d = fp16_to_fp32(qblock->d, false);
228 const float dmin = fp16_to_fp32(qblock->dmin, false);
229 const uint8_t* ql = qblock->qs;
230 const uint8_t* qh = qblock->qh;
231 float* y = output;
232 uint8_t u1 = 1, u2 = 2;
233 for (int j = 0, is = 0; j < GGML_QK_K; j += 64, is += 2) {
234 uint8_t sc, m;
235 get_scale_min_k4(is + 0, qblock->scales, &sc, &m);
236 const float d1 = d * static_cast<float>(sc), m1 = dmin * static_cast<float>(m);
237 get_scale_min_k4(is + 1, qblock->scales, &sc, &m);
238 const float d2 = d * static_cast<float>(sc), m2 = dmin * static_cast<float>(m);
239 for (int l = 0; l < 32; ++l) *y++ = d1 * static_cast<float>((ql[l] & 0x0F) + (qh[l] & u1 ? 16 : 0)) - m1;
240 for (int l = 0; l < 32; ++l) *y++ = d2 * static_cast<float>((ql[l] >> 4) + (qh[l] & u2 ? 16 : 0)) - m2;
241 ql += 32;
242 u1 <<= 2;
243 u2 <<= 2;
244 }
245}

References fp16_to_fp32(), get_scale_min_k4(), GGML_QK_K, and j.

Referenced by dequant_span_to_f32(), dequantize_vector_q5k_to_f32(), and TinyLlamaModel::lookup_embedding().

◆ dequantize_q6_k()

void dequantize_q6_k ( const block_q6_K *  qblock,
float *  output,
int  num_weights_in_block,
bool  log_this_block 
)

Definition at line 256 of file quantization.cpp.

257 {
259 std::cout
260 << "Warning: dequantize_q6_k called with num_weights != GGML_QK_K ("
261 << num_weights_in_block << ")" << std::endl;
262 std::memset(output, 0, num_weights_in_block * sizeof(float));
263 return;
264 }
265
266 const float d = fp16_to_fp32(qblock->d, false);
267
268 // Pointers to the start of the whole block's data
269 const uint8_t * p_ql = qblock->ql;
270 const uint8_t * p_qh = qblock->qh;
271 const int8_t * p_sc = qblock->scales;
272 float * p_y = output;
273
274 // Process the 256 elements of the block.
275 // The llama.cpp code structure processes it in two 128-element chunks.
276 for (int half_idx = 0; half_idx < 2; ++half_idx) { // Process first 128, then next 128
277 // Set up pointers for the current 128-element half
278 const uint8_t * ql = p_ql + (half_idx * 64); // Each half uses 64 bytes of ql
279 const uint8_t * qh = p_qh + (half_idx * 32); // Each half uses 32 bytes of qh
280 const int8_t * sc = p_sc + (half_idx * 8); // Each half uses 8 scales for these 128 elements
281 float * y = p_y + (half_idx * 128); // Output pointer for this half
282
283 // Inner loop processes 32 sets of 4 values = 128 floats
284 for (int l = 0; l < 32; ++l) {
285 int is = l / 16; // Scale sub-group index within this half's 8 scales (0 for l=0..15, 1 for l=16..31)
286
287 // Extract the four 6-bit quantized values, already offset by -32
288 const int8_t q1 = (int8_t)(((ql[l + 0] & 0x0F) | (((qh[l] >> 0) & 0x03) << 4))) - 32;
289 const int8_t q2 = (int8_t)(((ql[l + 32] & 0x0F) | (((qh[l] >> 2) & 0x03) << 4))) - 32;
290 const int8_t q3 = (int8_t)(((ql[l + 0] >> 4) | (((qh[l] >> 4) & 0x03) << 4))) - 32;
291 const int8_t q4 = (int8_t)(((ql[l + 32] >> 4) | (((qh[l] >> 6) & 0x03) << 4))) - 32;
292
293 y[l + 0] = d * sc[is + 0] * q1;
294 y[l + 32] = d * sc[is + 2] * q2;
295 y[l + 64] = d * sc[is + 4] * q3;
296 y[l + 96] = d * sc[is + 6] * q4;
297 }
298 }
299}

References fp16_to_fp32(), GGML_QK_K, and j.

Referenced by dequant_span_to_f32(), dequantize_vector_q6k_to_f32(), TinyLlamaModel::initialize_gpu_and_rope(), TinyLlamaModel::lookup_embedding(), and matvec_q6k_f32_vector_cpu().

◆ dequantize_q8_0_block()

void dequantize_q8_0_block ( const block_q8_0 *  qblock,
float *  output 
)

Dequantizes a Q8_0 block to float32.

Parameters
qblockPointer to Q8_0 block
outputOutput float array

Definition at line 1092 of file quantization.cpp.

1092 {
1093 const float d_fp32 = fp16_to_fp32(qblock->d, false);
1094 for (int i = 0; i < GGML_QK8_0; ++i) {
1095 output[i] = d_fp32 * static_cast<float>(qblock->qs[i]);
1096 }
1097}
constexpr size_t GGML_QK8_0
Definition gguf_parser.h:43

References fp16_to_fp32(), GGML_QK8_0, and j.

Referenced by dequant_span_to_f32(), dequantize_vector_q8_0_to_f32(), TinyLlamaModel::initialize_gpu_and_rope(), TinyLlamaModel::lookup_embedding(), and matvec_q8_0_f32_vector_cpu().

◆ dequantize_q8_k()

void dequantize_q8_k ( const std::vector< block_q8_K > &  q_data,
std::vector< float > &  x,
int  n,
bool  log_this_block 
)

Definition at line 1052 of file quantization.cpp.

1053 {
1054 if (n % GGML_QK_K != 0) {
1055 std::cerr
1056 << "Error: n must be a multiple of GGML_QK_K for Q8_K dequantization."
1057 << std::endl;
1058 return;
1059 }
1060 size_t num_blocks = n / GGML_QK_K;
1061 if (q_data.size() < num_blocks) {
1062 std::cerr << "Error: Not enough Q8_K blocks provided for dequantization."
1063 << std::endl;
1064 return;
1065 }
1066
1067 static std::atomic<int> log_count_q8k_dequant_scales = 0;
1068
1069 for (size_t i = 0; i < num_blocks; ++i) {
1070 const block_q8_K* qblock = &q_data[i];
1071 float* x_block = &x[i * GGML_QK_K];
1072
1073 const float d = fp16_to_fp32(qblock->d, true);
1074
1076 std::stringstream scale_log_ss;
1077 scale_log_ss << "[Q8K_DEQUANT_SCALES] Block #"
1078 << (log_count_q8k_dequant_scales.load()) << " Raw_d_fp16=0x"
1079 << std::hex << qblock->d << std::dec << " -> d=" << d;
1082 }
1083
1084 for (int j = 0; j < GGML_QK_K; ++j) {
1085 x_block[j] = d * static_cast<float>(qblock->qs[j]);
1086 }
1087 }
1088}
static void debug(const std::string &message)
Definition logger.cpp:131
int n
8-bit K-quantized block structure with block sums

References Logger::debug(), fp16_to_fp32(), GGML_QK_K, j, and n.

Referenced by TinyLlamaModel::ensure_down_proj_dequantized(), TinyLlamaModel::ensure_embed_tokens_dequantized(), TinyLlamaModel::ensure_gate_proj_dequantized(), TinyLlamaModel::ensure_k_proj_dequantized(), TinyLlamaModel::ensure_lm_head_dequantized(), TinyLlamaModel::ensure_o_proj_dequantized(), TinyLlamaModel::ensure_q_proj_dequantized(), TinyLlamaModel::ensure_up_proj_dequantized(), TinyLlamaModel::ensure_v_proj_dequantized(), and matvec_q8k_f32_vector_cpu().

◆ dequantize_vector_q4k_to_f32()

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 = 0 
)

Dequantizes a vector of Q4_K blocks to a vector of float32.

Parameters
q_weightsInput vector of Q4_K blocks
f32_weightsOutput vector of float32 values (will be resized)
total_num_elementsTotal number of float elements expected after dequantization
log_first_n_blocksNumber of initial blocks to log dequantization details for (0 for no logging)

Definition at line 1154 of file quantization.cpp.

1157 {
1158 if (q_weights.empty()) {
1159 Logger::warning("[DEQUANT_VEC_Q4K] Input Q4_K weight vector is empty. Output float vector will be empty.");
1160 f32_weights.clear();
1161 return;
1162 }
1163
1166
1167 if (q_weights.size() != expected_blocks) {
1168 Logger::error("[DEQUANT_VEC_Q4K] Mismatch in Q4_K block count. Expected: " +
1169 std::to_string(expected_blocks) + ", Got: " + std::to_string(q_weights.size()) +
1170 ". Total elements: " + std::to_string(total_num_elements));
1171 }
1172
1173 float* current_output_ptr = f32_weights.data();
1174 size_t elements_processed = 0;
1175
1176 for (size_t i = 0; i < q_weights.size(); ++i) {
1179
1182 }
1183
1184 if (elements_in_this_block <= 0) {
1185 Logger::warning("[DEQUANT_VEC_Q4K] Zero or negative elements requested for block " + std::to_string(i) + ". Skipping.");
1186 continue;
1187 }
1188
1189 bool log_this_specific_block = (log_first_n_blocks > 0 && static_cast<int>(i) < log_first_n_blocks);
1190
1191 // Enhanced logging: Log block index for all blocks during the first dequantization call
1192 static std::atomic<bool> first_call_ever{true};
1193 bool is_first_call = first_call_ever.exchange(false);
1194
1195 // Call the Q4_K specific single-block dequantizer
1197
1198
1201
1202 }
1203
1205 Logger::warning("[DEQUANT_VEC_Q4K] Processed " + std::to_string(elements_processed) +
1206 " elements, but expected " + std::to_string(total_num_elements) + ".");
1207 }
1208}
static void warning(const std::string &message)
Definition logger.cpp:139
static void error(const std::string &message)
Definition logger.cpp:143
void dequantize_q4_k_m(const block_q4_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
4-bit K-quantized block structure

References dequantize_q4_k_m(), Logger::error(), GGML_QK_K, j, and Logger::warning().

Referenced by TinyLlamaModel::ensure_down_proj_dequantized(), TinyLlamaModel::ensure_embed_tokens_dequantized(), TinyLlamaModel::ensure_gate_proj_dequantized(), TinyLlamaModel::ensure_k_proj_dequantized(), TinyLlamaModel::ensure_lm_head_dequantized(), TinyLlamaModel::ensure_o_proj_dequantized(), TinyLlamaModel::ensure_q_proj_dequantized(), TinyLlamaModel::ensure_up_proj_dequantized(), and TinyLlamaModel::ensure_v_proj_dequantized().

◆ dequantize_vector_q5k_to_f32()

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)

Definition at line 247 of file quantization.cpp.

248 {
250 throw std::runtime_error("dequantize_vector_q5k_to_f32: " + std::to_string(q_weights.size()) +
251 " Q5_K blocks for " + std::to_string(total_num_elements) + " elements");
253 for (size_t i = 0; i < q_weights.size(); ++i) dequantize_q5_k(&q_weights[i], f32_weights.data() + i * GGML_QK_K);
254}
void dequantize_q5_k(const block_q5_K *qblock, float *output)

References dequantize_q5_k(), GGML_QK_K, and j.

Referenced by TinyLlamaModel::ensure_down_proj_dequantized(), TinyLlamaModel::ensure_embed_tokens_dequantized(), TinyLlamaModel::ensure_gate_proj_dequantized(), TinyLlamaModel::ensure_k_proj_dequantized(), TinyLlamaModel::ensure_lm_head_dequantized(), TinyLlamaModel::ensure_o_proj_dequantized(), TinyLlamaModel::ensure_q_proj_dequantized(), TinyLlamaModel::ensure_up_proj_dequantized(), and TinyLlamaModel::ensure_v_proj_dequantized().

◆ dequantize_vector_q6k_to_f32()

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 = 0 
)

Dequantizes a vector of Q6_K blocks to a vector of float32.

Parameters
q_weightsInput vector of Q6_K blocks
f32_weightsOutput vector of float32 values (will be resized)
total_num_elementsTotal number of float elements expected after dequantization
log_first_n_blocksNumber of initial blocks to log dequantization details for (0 for no logging)

Definition at line 1099 of file quantization.cpp.

1102 {
1103 if (q_weights.empty()) {
1104 Logger::warning("[DEQUANT_VEC_Q6K] Input Q6_K weight vector is empty. Output float vector will be empty.");
1105 f32_weights.clear();
1106 return;
1107 }
1108
1111
1112 if (q_weights.size() != expected_blocks) {
1113 Logger::error("[DEQUANT_VEC_Q6K] Mismatch in Q6_K block count. Expected: " +
1114 std::to_string(expected_blocks) + ", Got: " + std::to_string(q_weights.size()) +
1115 ". Total elements: " + std::to_string(total_num_elements));
1116 }
1117
1118
1119 float* current_output_ptr = f32_weights.data();
1120 size_t elements_processed = 0;
1121
1122 for (size_t i = 0; i < q_weights.size(); ++i) {
1125
1128 }
1129
1130 if (elements_in_this_block <= 0) {
1131 Logger::warning("[DEQUANT_VEC_Q6K] Zero or negative elements requested for block " + std::to_string(i) + ". Skipping.");
1132 continue;
1133 }
1134
1135 bool log_this_specific_block = (log_first_n_blocks > 0 && static_cast<int>(i) < log_first_n_blocks);
1136
1137 // Enhanced logging: Log block index for all blocks during the first dequantization call
1138 static std::atomic<bool> first_call_ever{true};
1139 bool is_first_call = first_call_ever.exchange(false);
1140
1142
1145
1146 }
1147
1149 Logger::warning("[DEQUANT_VEC_Q6K] Processed " + std::to_string(elements_processed) +
1150 " elements, but expected " + std::to_string(total_num_elements) + ".");
1151 }
1152}
void dequantize_q6_k(const block_q6_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
6-bit K-quantized block structure

References dequantize_q6_k(), Logger::error(), GGML_QK_K, j, and Logger::warning().

Referenced by TinyLlamaModel::ensure_down_proj_dequantized(), TinyLlamaModel::ensure_embed_tokens_dequantized(), TinyLlamaModel::ensure_gate_proj_dequantized(), TinyLlamaModel::ensure_k_proj_dequantized(), TinyLlamaModel::ensure_lm_head_dequantized(), TinyLlamaModel::ensure_o_proj_dequantized(), TinyLlamaModel::ensure_q_proj_dequantized(), TinyLlamaModel::ensure_up_proj_dequantized(), and TinyLlamaModel::ensure_v_proj_dequantized().

◆ dequantize_vector_q8_0_to_f32()

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 = 0 
)

Dequantizes a vector of Q8_0 blocks to a vector of float32.

Parameters
q_weightsInput vector of Q8_0 blocks
f32_weightsOutput vector of float32 values (will be resized)
total_num_elementsTotal number of float elements expected after dequantization
log_first_n_blocksNumber of initial blocks to log dequantization details for (0 for no logging)

Definition at line 1210 of file quantization.cpp.

1213 {
1214 if (q_weights.empty()) {
1215 Logger::warning("[DEQUANT_VEC_Q8_0] Input Q8_0 weight vector is empty. Output float vector will be empty.");
1216 f32_weights.clear();
1217 return;
1218 }
1219
1221
1223
1224 if (q_weights.size() != expected_blocks) {
1225 Logger::error("[DEQUANT_VEC_Q8_0] Mismatch in Q8_0 block count. Expected: " +
1226 std::to_string(expected_blocks) + ", Got: " + std::to_string(q_weights.size()) +
1227 ". Total elements: " + std::to_string(total_num_elements));
1228 }
1229
1230 float* current_output_ptr = f32_weights.data();
1231 size_t elements_processed = 0;
1232
1233 for (size_t i = 0; i < q_weights.size(); ++i) {
1236
1239 }
1240
1241 if (elements_in_this_block <= 0) {
1242 Logger::warning("[DEQUANT_VEC_Q8_0] Zero or negative elements requested for block " + std::to_string(i) + ". Skipping.");
1243 continue;
1244 }
1245
1246 bool log_this_specific_block = (log_first_n_blocks > 0 && static_cast<int>(i) < log_first_n_blocks);
1247
1248 static std::atomic<bool> first_call_ever{true};
1249 bool is_first_call = first_call_ever.exchange(false);
1250
1253 } else {
1254 // Handle partial block
1255 float temp_block[GGML_QK8_0];
1257 std::memcpy(current_output_ptr, temp_block, elements_in_this_block * sizeof(float));
1258 }
1259
1262 }
1263
1265 Logger::warning("[DEQUANT_VEC_Q8_0] Processed " + std::to_string(elements_processed) +
1266 " elements, but expected " + std::to_string(total_num_elements) + ".");
1267 }
1268}
void dequantize_q8_0_block(const block_q8_0 *qblock, float *output)
Dequantizes a Q8_0 block to float32.
Simple 8-bit quantized block structure.

References dequantize_q8_0_block(), Logger::error(), GGML_QK8_0, j, and Logger::warning().

Referenced by ember_ir::Interpreter::bind_tensor(), TinyLlamaModel::dequantize_all_if_small(), TinyLlamaModel::ensure_down_proj_dequantized(), TinyLlamaModel::ensure_embed_tokens_dequantized(), TinyLlamaModel::ensure_gate_proj_dequantized(), TinyLlamaModel::ensure_k_proj_dequantized(), TinyLlamaModel::ensure_lm_head_dequantized(), TinyLlamaModel::ensure_o_proj_dequantized(), TinyLlamaModel::ensure_q_proj_dequantized(), TinyLlamaModel::ensure_up_proj_dequantized(), and TinyLlamaModel::ensure_v_proj_dequantized().

◆ fp16_to_fp32()

float fp16_to_fp32 ( uint16_t  h,
bool  is_gguf_scale_field = false 
)

Converts a 16-bit floating point number to 32-bit float.

Parameters
hThe 16-bit float value to convert
is_gguf_scale_fieldWhether this value is from a GGUF scale field
Returns
The converted 32-bit float value

Definition at line 47 of file quantization.cpp.

47 {
49 bool original_sign_bit_was_set = (h & 0x8000);
50 uint32_t sign = (h_to_convert >> 15) & 1;
51 uint32_t exp_fp16 = (h_to_convert >> 10) & 0x1f;
53 uint32_t x;
54
55 if (exp_fp16 == 0) {
56 if (mant_fp16 == 0) {
57 x = (sign << 31);
58
59 } else {
60 exp_fp16 = 1;
61 while ((mant_fp16 & 0x400) == 0) {
62 mant_fp16 <<= 1;
63 exp_fp16--;
64 }
65 mant_fp16 &= ~0x400;
66 uint32_t exp_fp32 = (exp_fp16 - 15 + 127);
68 x = (sign << 31) | (exp_fp32 << 23) | mant_fp32;
69 }
70 } else if (exp_fp16 == 0x1f) {
71 x = (sign << 31) | (0xff << 23) | (mant_fp16 << 13);
72 } else {
73 uint32_t exp_fp32 = (exp_fp16 - 15 + 127);
75 x = (sign << 31) | (exp_fp32 << 23) | mant_fp32;
76 }
77
78 float f;
79 std::memcpy(&f, &x, sizeof(float));
80
82 static std::atomic<int> q8_scale_f_log_count{0};
83 }
84
85 if (is_gguf_scale_field && f < 0.0f && !(std::isnan(f) || std::isinf(f))) {
86 f = std::abs(f);
87 }
88
89 return f;
90}

References j.

Referenced by dequant_span_to_f32(), dequantize_q2_k(), dequantize_q3_k(), dequantize_q4_k_m(), dequantize_q5_k(), dequantize_q6_k(), dequantize_q8_0_block(), dequantize_q8_k(), vec_dot_q4_k_q8_k_cpu(), and vec_dot_q6_k_q8_k_cpu().

◆ fp32_to_fp16()

uint16_t fp32_to_fp16 ( float  f)

Converts a 32-bit float to 16-bit floating point.

Parameters
fThe 32-bit float value to convert
Returns
The converted 16-bit float value

Definition at line 92 of file quantization.cpp.

92 {
93 uint32_t x;
94 std::memcpy(&x, &f, sizeof(float));
95
96 uint32_t sign = (x >> 31) & 1;
97 uint32_t exp_fp32 = (x >> 23) & 0xff;
98 uint32_t mant_fp32 = x & 0x7fffff;
99
100 uint16_t u;
101
102 if (exp_fp32 == 0xff) {
103 u = (sign << 15) | 0x7c00 | (mant_fp32 != 0 ? 0x200 : 0);
104 } else {
105 int exp_fp16 = (int)exp_fp32 - 127 + 15;
106
107 if (exp_fp16 >= 0x1f) {
108 u = (sign << 15) | 0x7c00;
109 } else if (exp_fp16 <= 0) {
110 if (exp_fp16 < -10) {
111 u = (sign << 15);
112 } else {
113 mant_fp32 = (mant_fp32 | 0x800000) >> (1 - exp_fp16);
114
115 if ((mant_fp32 >> 13) & 1) {
116 mant_fp32 += (1 << 13);
117 }
118 u = (sign << 15) | (mant_fp32 >> 13);
119 }
120 } else {
121 if ((mant_fp32 >> 13) & 1) {
122 mant_fp32 += (1 << 13);
123 if ((mant_fp32 >> 23) == 1) {
124 mant_fp32 = 0;
125 exp_fp16++;
126 if (exp_fp16 >= 0x1f) {
127 u = (sign << 15) | 0x7c00;
128 return u;
129 }
130 }
131 }
132 u = (sign << 15) | (exp_fp16 << 10) | (mant_fp32 >> 13);
133 }
134 }
135 return u;
136}

References j.

Referenced by quantize_fp32_to_q8_K(), quantize_q4_k_m(), and quantize_q6_k().

◆ get_scale_min_indices_q4_K()

static void get_scale_min_indices_q4_K ( int  j,
const uint8_t *  scales,
uint8_t *  scale_index,
uint8_t *  min_index 
)
inlinestatic

Definition at line 157 of file quantization.cpp.

161 {
162 assert(j >= 0 && j < 16);
163
164 *scale_index = scales[j % 8] >> (4 * (j / 8));
165 *scale_index &= 0x0F;
166
167 *min_index = scales[j % 4 + 8] >> (4 * (j / 4));
168 *min_index &= 0x0F;
169}

References j.

Referenced by vec_dot_q4_k_q8_k_cpu().

◆ get_scale_min_k4()

static void get_scale_min_k4 ( int  j,
const uint8_t *  q,
uint8_t *  d_val,
uint8_t *  m_val 
)
inlinestatic

Definition at line 145 of file quantization.cpp.

145 {
146 // j is the index for the 32-element group (0 to 7 for a QK_K block)
147 // q is x[i].scales which is uint8_t scales[12] in block_q4_K
148 if (j < 4) { // For first 4 groups of 32 (i.e., first 128 elements, using scales[0..7])
149 *d_val = q[j] & 63; // Takes lower 6 bits from q[j] (scales[0..3])
150 *m_val = q[j + 4] & 63; // Takes lower 6 bits from q[j+4] (scales[4..7])
151 } else { // For next 4 groups of 32 (i.e., next 128 elements, using scales[8..11] and bits from scales[0..7])
152 *d_val = (q[j+4] & 0x0F) | ((q[j-4] >> 6) << 4); // Lower 4 bits from q[8..11] and upper 2 bits from q[0..3]
153 *m_val = (q[j+4] >> 4) | ((q[j-0] >> 6) << 4); // Upper 4 bits from q[8..11] and upper 2 bits from q[4..7]
154 }
155}

References j.

Referenced by dequantize_q4_k_m(), and dequantize_q5_k().

◆ ggml_type_block_size()

size_t ggml_type_block_size ( GGMLType  type)

Gets the block size for a GGML type.

Parameters
typeThe GGML type
Returns
Block size in elements

Definition at line 727 of file quantization.cpp.

727 {
728 switch (type) {
734
735 return GGML_QK_K;
736
742
743 return 32;
744
751 return 1;
752
753 default:
754 std::cout << "Warning: Unknown GGMLType in ggml_type_block_size: "
755 << static_cast<int>(type) << std::endl;
756 return 0;
757 }
758
759 return 0;
760}
@ GGML_TYPE_Q2_K
Definition ggml_types.h:31
@ GGML_TYPE_F32
Definition ggml_types.h:22
@ GGML_TYPE_I16
Definition ggml_types.h:38
@ GGML_TYPE_BF16
Definition ggml_types.h:40
@ GGML_TYPE_Q5_0
Definition ggml_types.h:27
@ GGML_TYPE_I8
Definition ggml_types.h:37
@ GGML_TYPE_F16
Definition ggml_types.h:23
@ GGML_TYPE_Q3_K
Definition ggml_types.h:32
@ GGML_TYPE_Q6_K
Definition ggml_types.h:35
@ GGML_TYPE_Q4_1
Definition ggml_types.h:25
@ GGML_TYPE_Q8_0
Definition ggml_types.h:29
@ GGML_TYPE_I32
Definition ggml_types.h:39
@ GGML_TYPE_Q5_K
Definition ggml_types.h:34
@ GGML_TYPE_Q5_1
Definition ggml_types.h:28
@ GGML_TYPE_Q4_K
Definition ggml_types.h:33
@ GGML_TYPE_Q4_0
Definition ggml_types.h:24
enum ember_ir::@44::Value::Type type

References GGML_QK_K, GGML_TYPE_BF16, GGML_TYPE_F16, GGML_TYPE_F32, GGML_TYPE_I16, GGML_TYPE_I32, GGML_TYPE_I8, GGML_TYPE_Q2_K, GGML_TYPE_Q3_K, GGML_TYPE_Q4_0, GGML_TYPE_Q4_1, GGML_TYPE_Q4_K, GGML_TYPE_Q5_0, GGML_TYPE_Q5_1, GGML_TYPE_Q5_K, GGML_TYPE_Q6_K, GGML_TYPE_Q8_0, and type.

Referenced by load_gguf_meta().

◆ ggml_type_name()

const char * ggml_type_name ( GGMLType  type)

Gets the string name of a GGML type.

Parameters
typeThe GGML type
Returns
String representation of the type

Definition at line 634 of file quantization.cpp.

634 {
635 switch (type) {
637 return "F32";
639 return "F16";
641 return "Q4_0";
643 return "Q4_1";
645 return "Q5_0";
647 return "Q5_1";
649 return "Q8_0";
651 return "Q8_1";
653 return "Q2_K";
655 return "Q3_K";
657 return "Q4_K";
659 return "Q5_K";
661 return "Q6_K";
663 return "Q8_K";
665 return "I8";
667 return "I16";
669 return "I32";
671 return "BF16";
673 return "COUNT";
674 default:
675 return "Unknown";
676 }
677}
@ GGML_TYPE_Q8_1
Definition ggml_types.h:30
@ GGML_TYPE_Q8_K
Definition ggml_types.h:36
@ GGML_TYPE_COUNT
Definition ggml_types.h:41

References GGML_TYPE_BF16, GGML_TYPE_COUNT, GGML_TYPE_F16, GGML_TYPE_F32, GGML_TYPE_I16, GGML_TYPE_I32, GGML_TYPE_I8, GGML_TYPE_Q2_K, GGML_TYPE_Q3_K, GGML_TYPE_Q4_0, GGML_TYPE_Q4_1, GGML_TYPE_Q4_K, GGML_TYPE_Q5_0, GGML_TYPE_Q5_1, GGML_TYPE_Q5_K, GGML_TYPE_Q6_K, GGML_TYPE_Q8_0, GGML_TYPE_Q8_1, GGML_TYPE_Q8_K, and type.

Referenced by ember_ir::Interpreter::bind_tensor(), dequant_legacy_to_f32(), and load_gguf_meta().

◆ ggml_type_size()

size_t ggml_type_size ( GGMLType  type)

Gets the size in bytes of a GGML type.

Parameters
typeThe GGML type
Returns
Size in bytes

Definition at line 679 of file quantization.cpp.

679 {
680 switch (type) {
682 return sizeof(float);
684 return sizeof(uint16_t);
686 return sizeof(int8_t);
688 return sizeof(block_q4_K);
690 return sizeof(block_q2_K);
692 return sizeof(block_q3_K);
694 return sizeof(block_q6_K);
696 return 18;
698 return 20;
700 return 22;
702 return 24;
703
705 return 34;
707 return 40;
709 return sizeof(block_q5_K); // 176 (ggml's block_q5_K)
711 return 290;
713 return sizeof(int16_t);
715 return sizeof(int32_t);
717 return sizeof(uint16_t);
719 default:
720 std::cout << " UNKNOWN GGML TYPE: " << static_cast<int>(type)
721 << std::endl;
722 throw std::invalid_argument("Unknown GGML type in ggml_type_size: " +
723 std::to_string(static_cast<int>(type)));
724 }
725}
5-bit K-quantized block structure (ggml's block_q5_K)

References GGML_TYPE_BF16, GGML_TYPE_COUNT, GGML_TYPE_F16, GGML_TYPE_F32, GGML_TYPE_I16, GGML_TYPE_I32, GGML_TYPE_I8, GGML_TYPE_Q2_K, GGML_TYPE_Q3_K, GGML_TYPE_Q4_0, GGML_TYPE_Q4_1, GGML_TYPE_Q4_K, GGML_TYPE_Q5_0, GGML_TYPE_Q5_1, GGML_TYPE_Q5_K, GGML_TYPE_Q6_K, GGML_TYPE_Q8_0, GGML_TYPE_Q8_1, GGML_TYPE_Q8_K, j, and type.

Referenced by ember_ir::Interpreter::bind_tensor(), dequant_legacy_to_f32(), dequant_span_to_f32(), and load_gguf_meta().

◆ handle_i8_tensor()

void handle_i8_tensor ( const void *  i8_data,
float *  f_data,
size_t  num_elements 
)

Handles conversion of int8 tensor data to float32.

Parameters
i8_dataInput int8 data
f_dataOutput float array
num_elementsNumber of elements to convert

Definition at line 301 of file quantization.cpp.

302 {
303 const int8_t* input_ptr = static_cast<const int8_t*>(input_data);
304 for (size_t i = 0; i < num_elements; ++i) {
305 output_data[i] = static_cast<float>(input_ptr[i]);
306 }
307}

References j.

◆ matvec_q4k_q8k_cpu()

void matvec_q4k_q8k_cpu ( const std::vector< block_q4_K > &  mat_q4k,
const std::vector< block_q8_K > &  vec_q8k,
std::vector< float > &  out_f32,
int  rows,
int  cols,
bool  log_calls 
)

Computes matrix-vector product between Q4_K matrix and Q8_K vector on CPU.

Parameters
mat_q4kQ4_K matrix
vec_q8kQ8_K vector
out_f32Output float vector
rowsNumber of matrix rows
colsNumber of matrix columns
log_callsWhether to log computation details

Definition at line 1025 of file quantization.cpp.

1028 {
1029 if (cols % GGML_QK_K != 0) {
1030 throw std::runtime_error(
1031 "matvec_q4k_q8k_cpu: cols must be divisible by GGML_QK_K");
1032 }
1033 size_t blocks_per_row = cols / GGML_QK_K;
1034 if (mat_q4k.size() != (size_t)rows * blocks_per_row) {
1035 throw std::runtime_error("matvec_q4k_q8k_cpu: mat_q4k size mismatch");
1036 }
1037 if (vec_q8k.size() != blocks_per_row) {
1038 throw std::runtime_error("matvec_q4k_q8k_cpu: vec_q8k size mismatch");
1039 }
1040 out_f32.resize(rows);
1041
1042#pragma omp parallel for
1043 for (int r = 0; r < rows; ++r) {
1044 const std::vector<block_q4_K> row_q4k(
1045 mat_q4k.begin() + r * blocks_per_row,
1046 mat_q4k.begin() + (r + 1) * blocks_per_row);
1047
1049 }
1050}
float vec_dot_q4_k_q8_k_cpu(int n, const std::vector< block_q4_K > &x_vec, const std::vector< block_q8_K > &y_vec, bool log_this_call)
Computes dot product between Q4_K and Q8_K vectors on CPU.

References GGML_QK_K, j, and vec_dot_q4_k_q8_k_cpu().

◆ matvec_q6k_q8k_cpu()

void matvec_q6k_q8k_cpu ( const std::vector< block_q6_K > &  mat_q6k,
const std::vector< block_q8_K > &  vec_q8k,
std::vector< float > &  out_f32,
int  rows,
int  cols,
bool  log_calls 
)

Computes matrix-vector product between Q6_K matrix and Q8_K vector on CPU.

Parameters
mat_q6kQ6_K matrix
vec_q8kQ8_K vector
out_f32Output float vector
rowsNumber of matrix rows
colsNumber of matrix columns
log_callsWhether to log computation details

Definition at line 940 of file quantization.cpp.

943 {
944 if (cols % GGML_QK_K != 0) {
945 throw std::runtime_error(
946 "matvec_q6k_q8k_cpu: cols must be divisible by GGML_QK_K");
947 }
948 size_t blocks_per_row = cols / GGML_QK_K;
949 if (mat_q6k.size() != (size_t)rows * blocks_per_row) {
950 throw std::runtime_error("matvec_q6k_q8k_cpu: mat_q6k size mismatch");
951 }
952 if (vec_q8k.size() != blocks_per_row) {
953 throw std::runtime_error("matvec_q6k_q8k_cpu: vec_q8k size mismatch");
954 }
955 out_f32.resize(rows);
956 for (int r = 0; r < rows; ++r) {
957 const std::vector<block_q6_K> row_q6k(
958 mat_q6k.begin() + r * blocks_per_row,
959 mat_q6k.begin() + (r + 1) * blocks_per_row);
960
962 }
963}
float vec_dot_q6_k_q8_k_cpu(int n, const std::vector< block_q6_K > &x_vec, const std::vector< block_q8_K > &y_vec, bool log_this_call)
Computes dot product between Q6_K and Q8_K vectors on CPU.

References GGML_QK_K, j, and vec_dot_q6_k_q8_k_cpu().

◆ quantize_fp32_to_q8_K()

std::vector< block_q8_K > quantize_fp32_to_q8_K ( const std::vector< float > &  f_data)

Quantizes float32 data to Q8_K format.

Parameters
f_dataInput float vector
Returns
Vector of Q8_K blocks

Definition at line 762 of file quantization.cpp.

763 {
764 if (f_data.size() % GGML_QK_K != 0) {
765 throw std::runtime_error(
766 "Input vector size must be a multiple of GGML_QK_K (" +
767 std::to_string(GGML_QK_K) + ")");
768 }
769
770 size_t num_blocks = f_data.size() / GGML_QK_K;
771 std::vector<block_q8_K> q_data(num_blocks);
772 const float* x = f_data.data();
773 block_q8_K* y = q_data.data();
774
775 static std::atomic<int> log_count_q8k_quant_scales = 0;
776
777 for (size_t i = 0; i < num_blocks; ++i) {
778 float amax = 0.0f;
779 for (int j = 0; j < GGML_QK_K; ++j) {
780 amax = SAFE_MAX(amax, std::abs(x[j]));
781 }
782
783 const float d_fp32 = amax / Q8K_SCALE_FACTOR;
784 const float id = (d_fp32 != 0.f) ? 1.0f / d_fp32 : 0.0f;
785 y[i].d = fp32_to_fp16(d_fp32);
786
788 std::stringstream q8k_scale_log_ss;
789 q8k_scale_log_ss << "[Q8K_QUANT_SCALES] Block #" << i
790 << " Input amax=" << amax << " -> d_fp32=" << d_fp32
791 << " -> Stored d_fp16=0x" << std::hex << y[i].d
792 << std::dec;
795 }
796
797 int16_t block_sum[16] = {0};
798 for (int j = 0; j < GGML_QK_K; ++j) {
799 const float val_scaled = x[j] * id;
800
801 int8_t q_val = static_cast<int8_t>(
802 SAFE_MAX(-128.0f, SAFE_MIN(127.0f, std::round(val_scaled))));
803 y[i].qs[j] = q_val;
804 block_sum[j / 16] += q_val;
805 }
806
807 std::memcpy(y[i].bsums, block_sum, sizeof(block_sum));
808
809 x += GGML_QK_K;
810 }
811
812 return q_data;
813}
constexpr float Q8K_SCALE_FACTOR
Definition gguf_parser.h:58
uint16_t fp32_to_fp16(float f)
Converts a 32-bit float to 16-bit floating point.

References Logger::debug(), fp32_to_fp16(), GGML_QK_K, id, j, Q8K_SCALE_FACTOR, SAFE_MAX, and SAFE_MIN.

◆ quantize_q4_k_m()

void quantize_q4_k_m ( const float *  f_data,
void *  q_data,
int  num_elements 
)

Quantizes float32 data to Q4_K format.

Parameters
f_dataInput float array
q_dataOutput quantized data
num_elementsNumber of elements to quantize

Definition at line 309 of file quantization.cpp.

310 {
311 if (num_elements != GGML_QK_K) {
312 throw std::invalid_argument(
313 "quantize_q4_k_m currently only supports block size " +
314 std::to_string(GGML_QK_K));
315 }
316
318
319 std::memset(output_qblock->scales, 0, sizeof(output_qblock->scales));
320 std::memset(output_qblock->qs, 0, sizeof(output_qblock->qs));
321
322 float block_min_val = std::numeric_limits<float>::max();
323 float block_max_val = std::numeric_limits<float>::lowest();
324 for (int i = 0; i < num_elements; ++i) {
327 }
328
331 }
334 block_min_val = 0.0f;
335 }
336
338 const float d_super =
340 const float min_super = block_min_val;
341
344
345 for (int j = 0; j < GGML_QK_K / 16; ++j) {
346 const float* sub_block_input = input + j * 16;
347
348 float sub_min_val = sub_block_input[0];
349 float sub_max_val = sub_block_input[0];
350 for (int i = 1; i < 16; ++i) {
353 }
354
355 float ideal_scale = 0.0f;
358 }
359 float ideal_min = sub_min_val;
360
362 float min_scale_err = std::numeric_limits<float>::max();
363 if (d_super > GGUF_EPSILON) {
364 for (uint8_t k = 0; k < 16; ++k) {
366 float err = std::abs(candidate_scale - ideal_scale);
367 if (err < min_scale_err) {
370 }
371 }
372 }
373
375 float min_min_err = std::numeric_limits<float>::max();
376
377 for (uint8_t l = 0; l < 16; ++l) {
379 float err = std::abs(candidate_min - ideal_min);
380 if (err < min_min_err) {
382 best_min_idx = l;
383 }
384 }
385
386 int scale_byte_idx = j % 8;
387 int scale_shift = 4 * (j / 8);
389
390 int min_byte_idx = (j % 4) + 8;
391 int min_shift = 4 * (j / 4);
393
397 ? 1.0f / actual_scale
398 : 0.0f;
399
401
402 std::memset(packed_qs, 0, sizeof(packed_qs));
403
404 for (int i = 0; i < 16; ++i) {
405 float val = sub_block_input[i];
406
407 int quant_val = 0;
408 if (inv_actual_scale != 0.0f) {
409 quant_val =
410 static_cast<int>(std::round((val - actual_min) * inv_actual_scale)) + Q4K_OFFSET;
411 }
413
414 int byte_idx_qs = i / 2;
415 int shift_qs = (i % 2) * 4;
416 packed_qs[byte_idx_qs] |= (static_cast<uint8_t>(quant_val) << shift_qs);
417 }
418
419 uint8_t* qs_target = output_qblock->qs + j * 8;
420 for (int i = 0; i < 8; ++i) {
422 uint8_t high_nibble_val = (packed_qs[i] >> 4) & 0x0F;
424 }
425 }
426}
constexpr int8_t Q4K_OFFSET
Offset values for quantization methods.
Definition gguf_parser.h:63
constexpr float Q4K_SCALE_FACTOR
Scale factors for different quantization methods.
Definition gguf_parser.h:56
constexpr float GGUF_EPSILON
Constants for numeric stability in calculations.
Definition gguf_parser.h:36
constexpr float GGUF_SMALL_VAL
Definition gguf_parser.h:37
constexpr float K_MIN_VALUES[64]

References fp32_to_fp16(), GGML_QK_K, GGUF_EPSILON, GGUF_SMALL_VAL, j, k, K_MIN_VALUES, K_SCALE_VALUES, Q4K_OFFSET, Q4K_SCALE_FACTOR, SAFE_MAX, and SAFE_MIN.

◆ quantize_q6_k()

void quantize_q6_k ( const float *  f_data,
void *  q_data,
int  num_elements 
)

Quantizes float32 data to Q6_K format.

Parameters
f_dataInput float array
q_dataOutput quantized data
num_elementsNumber of elements to quantize

Definition at line 582 of file quantization.cpp.

583 {
584 if (num_elements != GGML_QK_K) {
585 throw std::invalid_argument(
586 "quantize_q6_k currently only supports block size " +
587 std::to_string(GGML_QK_K));
588 }
589
591
592 uint8_t* ql = output_qblock->ql;
593 uint8_t* qh = output_qblock->qh;
594 int8_t* scales = output_qblock->scales;
595 std::memset(ql, 0, GGML_QK_K / 2);
596 std::memset(qh, 0, GGML_QK_K / 4);
597
598 float amax = 0.0f;
599 for (int i = 0; i < num_elements; ++i) {
600 amax = SAFE_MAX(amax, std::abs(input[i]));
601 }
602
603 const float d_float = (amax > GGUF_EPSILON) ? (amax / Q6K_SCALE_FACTOR) : GGUF_EPSILON;
605
606 for (int sub = 0; sub < GGML_QK_K / 16; ++sub) {
607 const float* sub_in = input + sub * 16;
608
609 float sub_amax = 0.0f;
610 for (int i = 0; i < 16; ++i) {
611 sub_amax = SAFE_MAX(sub_amax, std::abs(sub_in[i]));
612 }
613
614 int8_t scale = (d_float > 0.0f) ? std::round(sub_amax / d_float) : 1;
615 if (scale == 0) scale = 1;
616 scales[sub] = scale;
617
618 for (int i = 0; i < 16; ++i) {
619 float val = sub_in[i];
620 int q = static_cast<int>(std::round(val / (d_float * scale))) + Q6K_OFFSET;
621 q = SAFE_MAX(0, SAFE_MIN(63, q));
622
623 int idx = sub * 16 + i;
624 int ql_idx = idx / 2;
625 int ql_shift = (idx % 2) * 4;
626 ql[ql_idx] |= (q & 0x0F) << ql_shift;
627 int qh_idx = idx / 4;
628 int qh_shift = (idx % 4) * 2;
629 qh[qh_idx] |= ((q >> 4) & 0x03) << qh_shift;
630 }
631 }
632}
constexpr int8_t Q6K_OFFSET
Definition gguf_parser.h:64
constexpr float Q6K_SCALE_FACTOR
Definition gguf_parser.h:57
node sub
node scale
uint8_t ql[GGML_QK_K/2]

References fp32_to_fp16(), GGML_QK_K, GGUF_EPSILON, j, Q6K_OFFSET, Q6K_SCALE_FACTOR, block_q6_K::ql, SAFE_MAX, SAFE_MIN, scale, and sub.

◆ vec_dot_q4_k_q8_k_cpu()

float vec_dot_q4_k_q8_k_cpu ( int  n,
const std::vector< block_q4_K > &  x_vec,
const std::vector< block_q8_K > &  y_vec,
bool  log_this_call 
)

Computes dot product between Q4_K and Q8_K vectors on CPU.

Parameters
nNumber of blocks
x_vecQ4_K vector
y_vecQ8_K vector
log_this_callWhether to log computation details
Returns
Dot product result

Definition at line 965 of file quantization.cpp.

967 {
969 if (log_count_now >= 5) log_this_call = false;
970
971 if (n % GGML_QK_K != 0) {
972 throw std::runtime_error("vec_dot_q4_k_q8_k: n must be multiple of QK_K");
973 }
974 size_t nb = n / GGML_QK_K;
975 if (x_vec.size() != nb || y_vec.size() != nb) {
976 throw std::runtime_error("vec_dot_q4_k_q8_k: vector block count mismatch");
977 }
978
979 const block_q4_K* x = x_vec.data();
980 const block_q8_K* y = y_vec.data();
981
982 float sumf = 0.0f;
983 for (size_t i = 0; i < nb; ++i) {
985 const uint8_t* q4 = x[i].qs;
986 for (int j = 0; j < GGML_QK_K / 2; ++j) {
987 q4_vals[2 * j + 0] = static_cast<int8_t>(q4[j] & 0xF);
988 q4_vals[2 * j + 1] = static_cast<int8_t>(q4[j] >> 4);
989 }
990
991 const int8_t* q8 = y[i].qs;
992
993 for (int sub = 0; sub < 16; ++sub) {
997 float minv = fp16_to_fp32(x[i].dmin) * K_MIN_VALUES[min_idx];
998 for (int k = 0; k < 16; ++k) {
999 int idx = sub * 16 + k;
1000 float q4_val = static_cast<float>(q4_vals[idx]) - 8.0f;
1001 float q8_val = static_cast<float>(q8[idx]);
1002 sumf += (scale * q4_val + minv) * q8_val;
1003 }
1004 }
1005
1006 if (i == 0 && log_this_call) {
1007 std::stringstream ss;
1008 ss << "[Q4K_Q8K] Block #0: d: " << fp16_to_fp32(x[i].d)
1009 << ", dmin: " << fp16_to_fp32(x[i].dmin);
1010 Logger::debug(ss.str());
1011 ss.str("");
1012 ss << "[Q4K_Q8K] Block #0: Q8_K input (first 16): ";
1013 for (int k = 0; k < 16; ++k) ss << (int)q8[k] << " ";
1014 Logger::debug(ss.str());
1015 ss.str("");
1016 ss << "[Q4K_Q8K] Block #0: Q4_K unpacked (first 16): ";
1017 for (int k = 0; k < 16; ++k) ss << (int)q4_vals[k] << " ";
1018 Logger::debug(ss.str());
1019 ss.str("");
1020 }
1021 }
1022 return sumf;
1023}
static void get_scale_min_indices_q4_K(int j, const uint8_t *scales, uint8_t *scale_index, uint8_t *min_index)
static std::atomic< int > g_vec_dot_q4_k_q8_k_log_count
int8_t qs[GGML_QK_K]

References Logger::debug(), fp16_to_fp32(), g_vec_dot_q4_k_q8_k_log_count, get_scale_min_indices_q4_K(), GGML_QK_K, j, k, K_MIN_VALUES, K_SCALE_VALUES, n, block_q8_K::qs, scale, and sub.

Referenced by matvec_q4k_q8k_cpu().

◆ vec_dot_q6_k_q8_k_cpu()

float vec_dot_q6_k_q8_k_cpu ( int  n,
const std::vector< block_q6_K > &  x,
const std::vector< block_q8_K > &  y,
bool  log_this_call 
)

Computes dot product between Q6_K and Q8_K vectors on CPU.

Parameters
nNumber of blocks
xQ6_K vector
yQ8_K vector
log_this_callWhether to log computation details
Returns
Dot product result

Definition at line 815 of file quantization.cpp.

817 {
818 if (n % GGML_QK_K != 0) {
819 throw std::runtime_error("vec_dot_q6_k_q8_k: n must be multiple of QK_K");
820 }
821 size_t nb = n / GGML_QK_K;
822 if (x_vec.size() != nb || y_vec.size() != nb) {
823 throw std::runtime_error("vec_dot_q6_k_q8_k: vector block count mismatch");
824 }
825
826 const block_q6_K* x = x_vec.data();
827 const block_q8_K* y = y_vec.data();
828
830 int16_t aux16[8];
831 float sums[8];
832 int32_t aux32[8];
833 std::memset(sums, 0, 8 * sizeof(float));
834
835 float sumf = 0.0f;
836
837 static std::atomic<int> log_count_dot = 0;
839
840 for (size_t i = 0; i < nb; ++i) {
841 const uint8_t* ql = x[i].ql;
842 const uint8_t* qh = x[i].qh;
843 const int8_t* q8 = y[i].qs;
844 std::memset(aux32, 0, 8 * sizeof(int32_t));
845
846 int8_t* a = aux8;
847 for (int j = 0; j < GGML_QK_K; j += 128) {
848 for (int l = 0; l < 32; ++l) {
849 a[l + 0] = static_cast<int8_t>(
850 ((ql[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32);
851 a[l + 32] = static_cast<int8_t>(
852 ((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32);
853 a[l + 64] = static_cast<int8_t>(
854 ((ql[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32);
855 a[l + 96] = static_cast<int8_t>(
856 ((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32);
857 }
858 a += 128;
859 ql += 64;
860 qh += 32;
861 }
862
863 a = aux8;
864 int is = 0;
865 for (int j = 0; j < GGML_QK_K / 16; ++j) {
866 int scale = x[i].scales[is++];
867 for (int l = 0; l < 8; ++l)
868 aux16[l] = static_cast<int16_t>(q8[l]) * static_cast<int16_t>(a[l]);
869 for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l];
870 q8 += 8;
871 a += 8;
872 for (int l = 0; l < 8; ++l)
873 aux16[l] = static_cast<int16_t>(q8[l]) * static_cast<int16_t>(a[l]);
874 for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l];
875 q8 += 8;
876 a += 8;
877 }
878
879 int32_t sumi_mins = 0;
880 for (int j = 0; j < GGML_QK_K / 16; ++j) {
881 sumi_mins += static_cast<int32_t>(y[i].bsums[j]) *
882 static_cast<int32_t>(x[i].scales[j]);
883 }
884
885 const float d_q6 = fp16_to_fp32(x[i].d);
886 const float d_q8 = fp16_to_fp32(y[i].d);
887 const float d = d_q6 * d_q8;
888
889 float block_contribution = 0.0f;
890 for (int l = 0; l < 8; ++l) {
891 float term = d * (aux32[l] - 32 * sumi_mins / 8);
892 sums[l] += term;
894 }
895
896 if (i == 0 && should_log_this_block) {
897 std::stringstream ss_log;
898 ss_log << "[DOT_Q6K_Q8K] Call #" << (log_count_dot.load() + 1)
899 << ", Block #0:";
900 Logger::debug(ss_log.str());
901 ss_log.str("");
902 ss_log << " Q6_K Scale d_q6: " << d_q6 << " (Raw FP16: 0x" << std::hex
903 << x[i].d << std::dec << ")";
904 Logger::debug(ss_log.str());
905 ss_log.str("");
906 ss_log << " Q8_K Scale d_q8: " << d_q8;
907 Logger::debug(ss_log.str());
908 ss_log.str("");
909 ss_log << " Combined Scale d: " << d;
910 Logger::debug(ss_log.str());
911 ss_log.str("");
912 ss_log << " Q6_K Sub-scales (int8): ";
913 for (int k = 0; k < 16; ++k) ss_log << (int)x[i].scales[k] << " ";
914 Logger::debug(ss_log.str());
915 ss_log.str("");
916 ss_log << " Int32 Sums (aux32, before compensation): ";
917 for (int l = 0; l < 8; ++l) ss_log << aux32[l] << " ";
918 Logger::debug(ss_log.str());
919 ss_log.str("");
920 ss_log << " Compensation term (sumi_mins): " << sumi_mins
921 << ", -32 * sumi_mins: " << (-32 * sumi_mins);
922 Logger::debug(ss_log.str());
923 ss_log.str("");
924 ss_log << " Block #0 Contribution to Sums (after compensation): "
926 Logger::debug(ss_log.str());
927 }
928 }
929
930 for (int l = 0; l < 8; ++l) {
931 sumf += sums[l];
932 }
933
936 }
937 return sumf;
938}
std::vector< E > a

References a, Logger::debug(), fp16_to_fp32(), GGML_QK_K, j, k, n, and scale.

Referenced by matvec_q6k_q8k_cpu().

Variable Documentation

◆ g_vec_dot_q4_k_q8_k_log_count

std::atomic<int> g_vec_dot_q4_k_q8_k_log_count {0}
static

Definition at line 45 of file quantization.cpp.

45{0};

Referenced by vec_dot_q4_k_q8_k_cpu().

◆ K_MIN_VALUES

constexpr float K_MIN_VALUES[64]
constexpr
Initial value:
= {
0.0f, -0.0078125f, -0.015625f, -0.0234375f, -0.03125f, -0.0390625f,
-0.046875f, -0.0546875f, -0.0625f, -0.0703125f, -0.078125f, -0.0859375f,
-0.09375f, -0.1015625f, -0.109375f, -0.1171875f, -0.125f, -0.140625f,
-0.15625f, -0.171875f, -0.1875f, -0.203125f, -0.21875f, -0.234375f,
-0.25f, -0.265625f, -0.28125f, -0.296875f, -0.3125f, -0.328125f,
-0.34375f, -0.359375f, -0.375f, -0.40625f, -0.4375f, -0.46875f,
-0.5f, -0.53125f, -0.5625f, -0.59375f, -0.625f, -0.65625f,
-0.6875f, -0.71875f, -0.75f, -0.78125f, -0.8125f, -0.84375f,
-0.875f, -0.9375f, -1.0f, -1.0625f, -1.125f, -1.1875f,
-1.25f, -1.3125f, -1.375f, -1.4375f, -1.5f, -1.5625f,
-1.625f, -1.6875f, -1.75f, -1.8125f}

Definition at line 32 of file quantization.cpp.

32 {
33 0.0f, -0.0078125f, -0.015625f, -0.0234375f, -0.03125f, -0.0390625f,
34 -0.046875f, -0.0546875f, -0.0625f, -0.0703125f, -0.078125f, -0.0859375f,
35 -0.09375f, -0.1015625f, -0.109375f, -0.1171875f, -0.125f, -0.140625f,
36 -0.15625f, -0.171875f, -0.1875f, -0.203125f, -0.21875f, -0.234375f,
37 -0.25f, -0.265625f, -0.28125f, -0.296875f, -0.3125f, -0.328125f,
38 -0.34375f, -0.359375f, -0.375f, -0.40625f, -0.4375f, -0.46875f,
39 -0.5f, -0.53125f, -0.5625f, -0.59375f, -0.625f, -0.65625f,
40 -0.6875f, -0.71875f, -0.75f, -0.78125f, -0.8125f, -0.84375f,
41 -0.875f, -0.9375f, -1.0f, -1.0625f, -1.125f, -1.1875f,
42 -1.25f, -1.3125f, -1.375f, -1.4375f, -1.5f, -1.5625f,
43 -1.625f, -1.6875f, -1.75f, -1.8125f};

Referenced by quantize_q4_k_m(), and vec_dot_q4_k_q8_k_cpu().

◆ K_SCALE_VALUES

constexpr float K_SCALE_VALUES[64]
constexpr
Initial value:
= {
1.0f, 1.0625f, 1.125f, 1.1875f, 1.25f, 1.3125f, 1.375f, 1.4375f,
1.5f, 1.5625f, 1.625f, 1.6875f, 1.75f, 1.8125f, 1.875f, 1.9375f,
2.0f, 2.125f, 2.25f, 2.375f, 2.5f, 2.625f, 2.75f, 2.875f,
3.0f, 3.125f, 3.25f, 3.375f, 3.5f, 3.625f, 3.75f, 3.875f,
4.0f, 4.25f, 4.5f, 4.75f, 5.0f, 5.25f, 5.5f, 5.75f,
6.0f, 6.25f, 6.5f, 6.75f, 7.0f, 7.25f, 7.5f, 7.75f,
8.0f, 8.5f, 9.0f, 9.5f, 10.0f, 10.5f, 11.0f, 11.5f,
12.0f, 12.5f, 13.0f, 13.5f, 14.0f, 14.5f, 15.0f, 15.5f}

Definition at line 22 of file quantization.cpp.

22 {
23 1.0f, 1.0625f, 1.125f, 1.1875f, 1.25f, 1.3125f, 1.375f, 1.4375f,
24 1.5f, 1.5625f, 1.625f, 1.6875f, 1.75f, 1.8125f, 1.875f, 1.9375f,
25 2.0f, 2.125f, 2.25f, 2.375f, 2.5f, 2.625f, 2.75f, 2.875f,
26 3.0f, 3.125f, 3.25f, 3.375f, 3.5f, 3.625f, 3.75f, 3.875f,
27 4.0f, 4.25f, 4.5f, 4.75f, 5.0f, 5.25f, 5.5f, 5.75f,
28 6.0f, 6.25f, 6.5f, 6.75f, 7.0f, 7.25f, 7.5f, 7.75f,
29 8.0f, 8.5f, 9.0f, 9.5f, 10.0f, 10.5f, 11.0f, 11.5f,
30 12.0f, 12.5f, 13.0f, 13.5f, 14.0f, 14.5f, 15.0f, 15.5f};

Referenced by dequantize_q3_k(), quantize_q4_k_m(), and vec_dot_q4_k_q8_k_cpu().