ember.cpp 0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
quantization.cpp
Go to the documentation of this file.
1#include "quantization.h"
2#include "model_macros.h"
3
4#include <algorithm>
5#include <atomic>
6#include <cassert>
7#include <cmath>
8#include <cstdint>
9#include <cstring>
10#include <iomanip>
11#include <iostream>
12#include <limits>
13#include <numeric>
14#include <sstream>
15#include <stdexcept>
16#include <string>
17#include <vector>
18
19#include "logger.h"
20#include "gguf_parser.h"
21
22constexpr float K_SCALE_VALUES[64] = {
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};
31
32constexpr float K_MIN_VALUES[64] = {
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};
44
45static std::atomic<int> g_vec_dot_q4_k_q8_k_log_count{0};
46
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}
91
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}
137
138namespace {
139
140std::vector<float> k_lookup_table_scale;
141std::vector<float> k_lookup_table_min;
142
143} // namespace
144
145static inline void get_scale_min_k4(int j, const uint8_t * q, uint8_t * d_val, uint8_t * m_val) {
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}
156
157static inline void get_scale_min_indices_q4_K(
158 int j,
159 const uint8_t* scales,
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}
170
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}
222
223// ggml-quants.c dequantize_row_q5_K (and gguf-py's Q5_K.dequantize_blocks): Q4_K's scales and
224// minimums, with the fifth bit of element l of sub-block s at bit s of qh[l]. The same float
225// operations in the same order (d * sc, then (d * sc) * q - dmin * m), so the values are equal.
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}
246
247void dequantize_vector_q5k_to_f32(const std::vector<block_q5_K>& q_weights, std::vector<float>& f32_weights,
248 size_t total_num_elements) {
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}
255
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}
300
301void handle_i8_tensor(const void* input_data, float* output_data,
302 size_t num_elements) {
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}
308
309void quantize_q4_k_m(const float* input, void* output_qblock_void,
310 int num_elements) {
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}
427
428void dequantize_q2_k(const void* qblock_void, float* output,
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}
508
509void dequantize_q3_k(const void* qblock_void, float* output,
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}
581
582void quantize_q6_k(const float* input, void* output_qblock_void,
583 int num_elements) {
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}
633
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}
678
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}
726
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}
761
762std::vector<block_q8_K> quantize_fp32_to_q8_K(
763 const std::vector<float>& f_data) {
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}
814
815float vec_dot_q6_k_q8_k_cpu(int n, const std::vector<block_q6_K>& x_vec,
816 const std::vector<block_q8_K>& y_vec,
817 bool log_this_call) {
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}
939
940void matvec_q6k_q8k_cpu(const std::vector<block_q6_K>& mat_q6k,
941 const std::vector<block_q8_K>& vec_q8k,
942 std::vector<float>& out_f32, int rows, int cols,
943 bool log_calls) {
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}
964
965float vec_dot_q4_k_q8_k_cpu(int n, const std::vector<block_q4_K>& x_vec,
966 const std::vector<block_q8_K>& y_vec,
967 bool log_this_call) {
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}
1024
1025void matvec_q4k_q8k_cpu(const std::vector<block_q4_K>& mat_q4k,
1026 const std::vector<block_q8_K>& vec_q8k,
1027 std::vector<float>& out_f32, int rows, int cols,
1028 bool log_calls) {
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}
1051
1052void dequantize_q8_k(const std::vector<block_q8_K>& q_data,
1053 std::vector<float>& x, int n, bool log_this_block) {
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}
1089
1090// qs[j] * h(d), as ggml's dequantize_row_q8_0 (paperkiln spec/IR_SPEC.md 4.7): d keeps its sign (a
1091// negative or -0 scale is not made positive; ggml's quantiser writes d >= 0, so real files are unchanged).
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}
1098
1099void dequantize_vector_q6k_to_f32(const std::vector<block_q6_K>& q_weights,
1100 std::vector<float>& f32_weights,
1101 size_t total_num_elements,
1102 int log_first_n_blocks) {
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}
1153
1154void dequantize_vector_q4k_to_f32(const std::vector<block_q4_K>& q_weights,
1155 std::vector<float>& f32_weights,
1156 size_t total_num_elements,
1157 int log_first_n_blocks) {
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}
1209
1210void dequantize_vector_q8_0_to_f32(const std::vector<block_q8_0>& q_weights,
1211 std::vector<float>& f32_weights,
1212 size_t total_num_elements,
1213 int log_first_n_blocks) {
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}
static void debug(const std::string &message)
Definition logger.cpp:131
static void warning(const std::string &message)
Definition logger.cpp:139
static void error(const std::string &message)
Definition logger.cpp:143
GGMLType
Enumeration of GGML tensor data types.
Definition ggml_types.h:21
@ GGML_TYPE_Q8_1
Definition ggml_types.h:30
@ 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_Q8_K
Definition ggml_types.h:36
@ 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_COUNT
Definition ggml_types.h:41
@ GGML_TYPE_Q4_K
Definition ggml_types.h:33
@ GGML_TYPE_Q4_0
Definition ggml_types.h:24
Parser for GGUF (GPT-Generated Unified Format) files.
constexpr float TENSOR_SCALE_MAX
Constants for tensor value validation.
Definition gguf_parser.h:50
constexpr int8_t Q4K_OFFSET
Offset values for quantization methods.
Definition gguf_parser.h:63
constexpr int8_t Q6K_OFFSET
Definition gguf_parser.h:64
constexpr float Q8K_SCALE_FACTOR
Definition gguf_parser.h:58
constexpr float Q4K_SCALE_FACTOR
Scale factors for different quantization methods.
Definition gguf_parser.h:56
constexpr float TENSOR_SCALE_MIN
Definition gguf_parser.h:51
constexpr float Q6K_SCALE_FACTOR
Definition gguf_parser.h:57
constexpr float GGUF_EPSILON
Constants for numeric stability in calculations.
Definition gguf_parser.h:36
constexpr size_t GGML_QK8_0
Definition gguf_parser.h:43
constexpr size_t GGML_QK_K
Block size constants for different quantization formats.
Definition gguf_parser.h:42
constexpr float GGUF_SMALL_VAL
Definition gguf_parser.h:37
int n
std::vector< E > a
node sub
node scale
size_t j
enum ember_ir::@44::Value::Type type
Logging utilities for the TinyLlama implementation.
#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.
void dequantize_q3_k(const void *qblock_void, float *output, int num_weights_in_block)
Dequantizes a Q3_K quantized block to float32.
size_t ggml_type_block_size(GGMLType type)
Gets the block size for a GGML type.
void dequantize_q4_k_m(const block_q4_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
static void get_scale_min_k4(int j, const uint8_t *q, uint8_t *d_val, uint8_t *m_val)
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)
size_t ggml_type_size(GGMLType type)
Gets the size in bytes of a GGML type.
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.
const char * ggml_type_name(GGMLType type)
Gets the string name of a GGML type.
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.
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 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.
static void get_scale_min_indices_q4_K(int j, const uint8_t *scales, uint8_t *scale_index, uint8_t *min_index)
void dequantize_q5_k(const block_q5_K *qblock, float *output)
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_q2_k(const void *qblock_void, float *output, int num_weights_in_block)
std::vector< block_q8_K > quantize_fp32_to_q8_K(const std::vector< float > &f_data)
Quantizes float32 data to Q8_K format.
float fp16_to_fp32(uint16_t h, bool is_gguf_scale_field)
Converts a 16-bit floating point number to 32-bit float.
static std::atomic< int > g_vec_dot_q4_k_q8_k_log_count
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.
void quantize_q6_k(const float *input, void *output_qblock_void, int num_elements)
Quantizes float32 data to Q6_K format.
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.
constexpr float K_MIN_VALUES[64]
void dequantize_vector_q4k_to_f32(const std::vector< block_q4_K > &q_weights, std::vector< float > &f32_weights, size_t total_num_elements, int log_first_n_blocks)
Dequantizes a vector of Q4_K blocks to a vector of float32.
void dequantize_q8_0_block(const block_q8_0 *qblock, float *output)
Dequantizes a Q8_0 block to float32.
void dequantize_q8_k(const std::vector< block_q8_K > &q_data, std::vector< float > &x, int n, bool log_this_block)
constexpr float K_SCALE_VALUES[64]
void dequantize_q6_k(const block_q6_K *qblock, float *output, int num_weights_in_block, bool log_this_block)
Weight quantization structures and functions for model compression.
2-bit K-quantized block structure
3-bit K-quantized block structure
4-bit K-quantized block structure
5-bit K-quantized block structure (ggml's block_q5_K)
6-bit K-quantized block structure
uint8_t ql[GGML_QK_K/2]
Simple 8-bit quantized block structure.
8-bit K-quantized block structure with block sums
int8_t qs[GGML_QK_K]