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

Weight quantization structures and functions for model compression. More...

#include <cstddef>
#include <cstdint>
#include <limits>
#include <vector>
#include "ggml_types.h"
#include "gguf_parser.h"
Include dependency graph for quantization.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  block_q4_K
 4-bit K-quantized block structure More...
 
struct  block_q5_K
 5-bit K-quantized block structure (ggml's block_q5_K) More...
 
struct  block_q6_K
 6-bit K-quantized block structure More...
 
struct  block_q2_K
 2-bit K-quantized block structure More...
 
struct  block_q3_K
 3-bit K-quantized block structure More...
 
struct  block_q8_K
 8-bit K-quantized block structure with block sums More...
 
struct  block_q8_0
 Simple 8-bit quantized block structure. More...
 

Macros

#define RESTRICT   __restrict__
 

Functions

float fp16_to_fp32 (uint16_t h, bool is_gguf_scale_field=false)
 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.
 
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.
 
void dequantize_q2_k (const void *q_data, float *f_data, int num_weights_in_block, bool log_details_for_this_block=false)
 Dequantizes a Q2_K quantized block to float32.
 
void dequantize_q4_k_m (const block_q4_K *qblock, float *RESTRICT output_f32, int num_elements, bool log_this_block=false)
 Dequantizes a Q4_K quantized block to float32.
 
void dequantize_q5_k (const block_q5_K *qblock, float *RESTRICT output_f32)
 Dequantizes a Q5_K block (256 weights) to float32, as ggml's dequantize_row_q5_K.
 
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 *RESTRICT output_f32, int num_elements, bool log_this_block=false)
 Dequantizes a Q6_K quantized 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=0)
 Dequantizes a vector of Q6_K blocks to a vector of float32.
 
void dequantize_q3_k (const void *q_data, float *f_data, int num_weights_in_block)
 Dequantizes a Q3_K quantized block to float32.
 
void handle_i8_tensor (const void *i8_data, float *f_data, size_t num_elements)
 Handles conversion of int8 tensor data to float32.
 
void quantize_q4_k_m (const float *f_data, void *q_data, int num_elements)
 Quantizes float32 data to Q4_K format.
 
void quantize_q6_k (const float *f_data, void *q_data, int num_elements)
 Quantizes float32 data to Q6_K format.
 
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, const std::vector< block_q8_K > &y, 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_0_block (const block_q8_0 *qblock, float *output)
 Dequantizes a Q8_0 block to 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=0)
 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=0)
 Dequantizes a vector of Q8_0 blocks to a vector of float32.
 

Detailed Description

Weight quantization structures and functions for model compression.

This file contains the definitions for various quantization formats and functions to convert between them. The quantization methods include Q2_K, Q3_K, Q4_K, Q6_K, and Q8_0 formats, each offering different compression ratios and precision tradeoffs.

Definition in file quantization.h.

Macro Definition Documentation

◆ RESTRICT

#define RESTRICT   __restrict__

Definition at line 15 of file quantization.h.

Function Documentation

◆ dequantize_q2_k()

void dequantize_q2_k ( const void *  q_data,
float *  f_data,
int  num_weights_in_block,
bool  log_details_for_this_block = false 
)

Dequantizes a Q2_K quantized block to float32.

Parameters
q_dataPointer to quantized data
f_dataOutput float array
num_weights_in_blockNumber of weights to dequantize
log_details_for_this_blockWhether to log dequantization details

◆ 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 size_t GGML_QK_K
Block size constants for different quantization formats.
Definition gguf_parser.h:42
size_t j
float fp16_to_fp32(uint16_t h, bool is_gguf_scale_field)
Converts a 16-bit floating point number to 32-bit float.
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 *RESTRICT  output_f32,
int  num_elements,
bool  log_this_block = false 
)

Dequantizes a Q4_K quantized block to float32.

Parameters
qblockPointer to Q4_K block
output_f32Output float array
num_elementsNumber of elements to dequantize
log_this_blockWhether to log dequantization details

◆ dequantize_q5_k()

void dequantize_q5_k ( const block_q5_K *  qblock,
float *RESTRICT  output_f32 
)

Dequantizes a Q5_K block (256 weights) to float32, as ggml's dequantize_row_q5_K.

Parameters
qblockPointer to Q5_K block
output_f32Output float array (GGML_QK_K values)

◆ dequantize_q6_k()

void dequantize_q6_k ( const block_q6_K *  qblock,
float *RESTRICT  output_f32,
int  num_elements,
bool  log_this_block = false 
)

Dequantizes a Q6_K quantized block to float32.

Parameters
qblockPointer to Q6_K block
output_f32Output float array
num_elementsNumber of elements to dequantize
log_this_blockWhether to log dequantization details

◆ 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_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().

◆ 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}
2-bit K-quantized block structure
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}
static void debug(const std::string &message)
Definition logger.cpp:131
constexpr float Q8K_SCALE_FACTOR
Definition gguf_parser.h:58
#define SAFE_MAX(a, b)
#define SAFE_MIN(a, b)
uint16_t fp32_to_fp16(float f)
Converts a 32-bit float to 16-bit floating point.
8-bit K-quantized block structure with block sums

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}
int n
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().