Skip to content

Commit bec4772

Browse files
Add Q2_0 quantization: type definition and CPU backend (ggml-org#24448)
1 parent c198af4 commit bec4772

17 files changed

Lines changed: 262 additions & 3 deletions

File tree

ggml/include/ggml.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,8 @@ extern "C" {
429429
GGML_TYPE_MXFP4 = 39, // MXFP4 (1 block)
430430
GGML_TYPE_NVFP4 = 40, // NVFP4 (4 blocks, E4M3 scale)
431431
GGML_TYPE_Q1_0 = 41,
432-
GGML_TYPE_COUNT = 42,
432+
GGML_TYPE_Q2_0 = 42,
433+
GGML_TYPE_COUNT = 43,
433434
};
434435

435436
// precision
@@ -473,6 +474,7 @@ extern "C" {
473474
GGML_FTYPE_MOSTLY_MXFP4 = 25, // except 1d tensors
474475
GGML_FTYPE_MOSTLY_NVFP4 = 26, // except 1d tensors
475476
GGML_FTYPE_MOSTLY_Q1_0 = 27, // except 1d tensors
477+
GGML_FTYPE_MOSTLY_Q2_0 = 28, // except 1d tensors
476478
};
477479

478480
// available tensor operations:

ggml/src/ggml-common.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ typedef sycl::half2 ggml_half2;
9696
#define QI1_0 (QK1_0 / 32)
9797
#define QR1_0 1
9898

99+
#define QI2_0 (QK2_0 / 32)
100+
#define QR2_0 1
101+
99102

100103
#define QI4_0 (QK4_0 / (4 * QR4_0))
101104
#define QR4_0 2
@@ -181,6 +184,13 @@ typedef struct {
181184
} block_q1_0;
182185
static_assert(sizeof(block_q1_0) == sizeof(ggml_half) + QK1_0 / 8, "wrong q1_0 block size/padding");
183186

187+
#define QK2_0 64
188+
typedef struct {
189+
ggml_half d; // delta (scale)
190+
uint8_t qs[QK2_0 / 4]; // 2 bits per element
191+
} block_q2_0;
192+
static_assert(sizeof(block_q2_0) == sizeof(ggml_half) + QK2_0 / 4, "wrong q2_0 block size/padding");
193+
184194
#define QK4_0 32
185195
typedef struct {
186196
ggml_half d; // delta

ggml/src/ggml-cpu/arch-fallback.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define ggml_vec_dot_mxfp4_q8_0_generic ggml_vec_dot_mxfp4_q8_0
1818
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
1919
#define ggml_vec_dot_q1_0_q8_0_generic ggml_vec_dot_q1_0_q8_0
20+
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
2021
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
2122
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
2223
#define ggml_vec_dot_q2_K_q8_K_generic ggml_vec_dot_q2_K_q8_K
@@ -82,6 +83,7 @@
8283
#define ggml_gemm_q2_K_8x8_q8_K_generic ggml_gemm_q2_K_8x8_q8_K
8384
#elif defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
8485
// quants.c
86+
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
8587
// repack.cpp
8688
#define ggml_quantize_mat_q8_0_4x4_generic ggml_quantize_mat_q8_0_4x4
8789
#define ggml_quantize_mat_q8_K_4x4_generic ggml_quantize_mat_q8_K_4x4
@@ -113,6 +115,7 @@
113115
#define quantize_row_q8_K_generic quantize_row_q8_K
114116
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
115117
#define ggml_vec_dot_q1_0_q8_0_generic ggml_vec_dot_q1_0_q8_0
118+
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
116119
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
117120
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
118121
#define ggml_vec_dot_iq1_m_q8_K_generic ggml_vec_dot_iq1_m_q8_K
@@ -162,6 +165,7 @@
162165
#define ggml_vec_dot_mxfp4_q8_0_generic ggml_vec_dot_mxfp4_q8_0
163166
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
164167
#define ggml_vec_dot_q1_0_q8_0_generic ggml_vec_dot_q1_0_q8_0
168+
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
165169
// repack.cpp
166170
#define ggml_quantize_mat_q8_0_4x4_generic ggml_quantize_mat_q8_0_4x4
167171
#define ggml_quantize_mat_q8_0_4x8_generic ggml_quantize_mat_q8_0_4x8
@@ -202,6 +206,7 @@
202206
#elif defined(__riscv)
203207
// quants.c
204208
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
209+
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
205210
// repack.cpp
206211
#define ggml_quantize_mat_q8_0_4x1_generic ggml_quantize_mat_q8_0_4x1
207212
#define ggml_quantize_mat_q8_0_4x4_generic ggml_quantize_mat_q8_0_4x4
@@ -243,6 +248,7 @@
243248
#define quantize_row_q8_K_generic quantize_row_q8_K
244249
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
245250
#define ggml_vec_dot_q1_0_q8_0_generic ggml_vec_dot_q1_0_q8_0
251+
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
246252
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
247253
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
248254
#define ggml_vec_dot_q2_K_q8_K_generic ggml_vec_dot_q2_K_q8_K
@@ -306,6 +312,7 @@
306312
#define ggml_vec_dot_mxfp4_q8_0_generic ggml_vec_dot_mxfp4_q8_0
307313
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
308314
#define ggml_vec_dot_q1_0_q8_0_generic ggml_vec_dot_q1_0_q8_0
315+
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
309316
// repack.cpp
310317
#define ggml_quantize_mat_q8_0_4x4_generic ggml_quantize_mat_q8_0_4x4
311318
#define ggml_quantize_mat_q8_0_4x8_generic ggml_quantize_mat_q8_0_4x8

ggml/src/ggml-cpu/arch/arm/quants.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,80 @@ void ggml_vec_dot_q1_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const voi
219219
#endif
220220
}
221221

222+
void ggml_vec_dot_q2_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {
223+
const int qk = QK2_0;
224+
const int nb = n / qk;
225+
226+
assert(n % qk == 0);
227+
assert(nrc == 1);
228+
UNUSED(nrc);
229+
UNUSED(bx);
230+
UNUSED(by);
231+
UNUSED(bs);
232+
233+
const block_q2_0 * GGML_RESTRICT x = vx;
234+
const block_q8_0 * GGML_RESTRICT y = vy;
235+
236+
float sumf = 0.0f;
237+
238+
#if defined(__ARM_NEON)
239+
// Replicate pattern: each byte repeated 4 times
240+
static const uint8_t tbl_idx_lo[16] = {0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3};
241+
static const uint8_t tbl_idx_hi[16] = {4,4,4,4, 5,5,5,5, 6,6,6,6, 7,7,7,7};
242+
// Right-shift amounts: 0,2,4,6 repeated for each group of 4
243+
static const int8_t shift_vals[16] = {0,-2,-4,-6, 0,-2,-4,-6, 0,-2,-4,-6, 0,-2,-4,-6};
244+
245+
const uint8x16_t idx_lo = vld1q_u8(tbl_idx_lo);
246+
const uint8x16_t idx_hi = vld1q_u8(tbl_idx_hi);
247+
const int8x16_t shifts = vld1q_s8(shift_vals);
248+
const uint8x16_t mask2 = vdupq_n_u8(0x03);
249+
const int8x16_t one = vdupq_n_s8(1);
250+
251+
float32x4_t sumv = vdupq_n_f32(0.0f);
252+
253+
for (int i = 0; i < nb; i++) {
254+
const float d0 = GGML_CPU_FP16_TO_FP32(x[i].d);
255+
256+
// group 64: one Q2_0 block (64 weights) maps to two Q8_0 blocks (2 * 32 = 64)
257+
for (int k = 0; k < 2; k++) {
258+
const block_q8_0 * GGML_RESTRICT yb = &y[i * 2 + k];
259+
const float d1 = GGML_CPU_FP16_TO_FP32(yb->d);
260+
261+
// Load 8 bytes of packed 2-bit values
262+
const uint8x8_t raw = vld1_u8(&x[i].qs[k * 8]);
263+
const uint8x16_t raw16 = vcombine_u8(raw, raw);
264+
265+
// First 16 elements: replicate bytes 0-3, shift, mask, subtract 1
266+
uint8x16_t bytes0 = vqtbl1q_u8(raw16, idx_lo);
267+
int8x16_t qv0 = vsubq_s8(
268+
vreinterpretq_s8_u8(vandq_u8(vshlq_u8(bytes0, shifts), mask2)),
269+
one);
270+
271+
// Second 16 elements: replicate bytes 4-7, shift, mask, subtract 1
272+
uint8x16_t bytes1 = vqtbl1q_u8(raw16, idx_hi);
273+
int8x16_t qv1 = vsubq_s8(
274+
vreinterpretq_s8_u8(vandq_u8(vshlq_u8(bytes1, shifts), mask2)),
275+
one);
276+
277+
// Load Q8_0 values and dot product
278+
const int8x16_t y0 = vld1q_s8(yb->qs);
279+
const int8x16_t y1 = vld1q_s8(yb->qs + 16);
280+
281+
int32x4_t p0 = ggml_vdotq_s32(vdupq_n_s32(0), qv0, y0);
282+
int32x4_t p1 = ggml_vdotq_s32(p0, qv1, y1);
283+
284+
sumv = vmlaq_n_f32(sumv, vcvtq_f32_s32(p1), d0 * d1);
285+
}
286+
}
287+
288+
sumf = vaddvq_f32(sumv);
289+
#else
290+
ggml_vec_dot_q2_0_q8_0_generic(n, s, bs, vx, bx, vy, by, nrc);
291+
return;
292+
#endif
293+
294+
*s = sumf;
295+
}
222296

223297
void ggml_vec_dot_q4_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {
224298
const int qk = QK8_0;

ggml/src/ggml-cpu/ggml-cpu.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,12 @@ static const struct ggml_type_traits_cpu type_traits_cpu[GGML_TYPE_COUNT] = {
230230
.vec_dot_type = GGML_TYPE_Q8_0,
231231
.nrows = 1,
232232
},
233+
[GGML_TYPE_Q2_0] = {
234+
.from_float = quantize_row_q2_0,
235+
.vec_dot = ggml_vec_dot_q2_0_q8_0,
236+
.vec_dot_type = GGML_TYPE_Q8_0,
237+
.nrows = 1,
238+
},
233239
[GGML_TYPE_Q4_0] = {
234240
.from_float = quantize_row_q4_0,
235241
.vec_dot = ggml_vec_dot_q4_0_q8_0,

ggml/src/ggml-cpu/ops.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ void ggml_compute_forward_add(
665665
ggml_compute_forward_add_non_quantized(params, dst);
666666
} break;
667667
case GGML_TYPE_Q1_0:
668+
case GGML_TYPE_Q2_0:
668669
case GGML_TYPE_Q4_0:
669670
case GGML_TYPE_Q4_1:
670671
case GGML_TYPE_Q5_0:
@@ -1115,6 +1116,7 @@ void ggml_compute_forward_add1(
11151116
}
11161117
} break;
11171118
case GGML_TYPE_Q1_0:
1119+
case GGML_TYPE_Q2_0:
11181120
case GGML_TYPE_Q4_0:
11191121
case GGML_TYPE_Q4_1:
11201122
case GGML_TYPE_Q5_0:
@@ -1245,6 +1247,7 @@ void ggml_compute_forward_acc(
12451247
case GGML_TYPE_F16:
12461248
case GGML_TYPE_BF16:
12471249
case GGML_TYPE_Q1_0:
1250+
case GGML_TYPE_Q2_0:
12481251
case GGML_TYPE_Q4_0:
12491252
case GGML_TYPE_Q4_1:
12501253
case GGML_TYPE_Q5_0:
@@ -4454,6 +4457,7 @@ void ggml_compute_forward_out_prod(
44544457

44554458
switch (src0->type) {
44564459
case GGML_TYPE_Q1_0:
4460+
case GGML_TYPE_Q2_0:
44574461
case GGML_TYPE_Q4_0:
44584462
case GGML_TYPE_Q4_1:
44594463
case GGML_TYPE_Q5_0:
@@ -4730,6 +4734,7 @@ void ggml_compute_forward_set(
47304734
case GGML_TYPE_F16:
47314735
case GGML_TYPE_BF16:
47324736
case GGML_TYPE_Q1_0:
4737+
case GGML_TYPE_Q2_0:
47334738
case GGML_TYPE_Q4_0:
47344739
case GGML_TYPE_Q4_1:
47354740
case GGML_TYPE_Q5_0:
@@ -4954,6 +4959,7 @@ void ggml_compute_forward_get_rows(
49544959

49554960
switch (src0->type) {
49564961
case GGML_TYPE_Q1_0:
4962+
case GGML_TYPE_Q2_0:
49574963
case GGML_TYPE_Q4_0:
49584964
case GGML_TYPE_Q4_1:
49594965
case GGML_TYPE_Q5_0:
@@ -5680,6 +5686,7 @@ void ggml_compute_forward_clamp(
56805686
} break;
56815687
case GGML_TYPE_BF16:
56825688
case GGML_TYPE_Q1_0:
5689+
case GGML_TYPE_Q2_0:
56835690
case GGML_TYPE_Q4_0:
56845691
case GGML_TYPE_Q4_1:
56855692
case GGML_TYPE_Q5_0:

ggml/src/ggml-cpu/quants.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ void quantize_row_q1_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, in
2626
quantize_row_q1_0_ref(x, y, k);
2727
}
2828

29+
void quantize_row_q2_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k) {
30+
quantize_row_q2_0_ref(x, y, k);
31+
}
32+
2933
void quantize_row_q4_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k) {
3034
quantize_row_q4_0_ref(x, y, k);
3135
}
@@ -170,6 +174,53 @@ void ggml_vec_dot_q1_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, c
170174
*s = sumf;
171175
}
172176

177+
void ggml_vec_dot_q2_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {
178+
const int qk = QK2_0;
179+
const int nb = n / qk;
180+
181+
assert(n % qk == 0);
182+
assert(nrc == 1);
183+
UNUSED(nrc);
184+
UNUSED(bx);
185+
UNUSED(by);
186+
UNUSED(bs);
187+
188+
const block_q2_0 * GGML_RESTRICT x = vx;
189+
const block_q8_0 * GGML_RESTRICT y = vy;
190+
191+
float sumf = 0.0f;
192+
193+
for (int i = 0; i < nb; i++) {
194+
const float d0 = GGML_CPU_FP16_TO_FP32(x[i].d);
195+
196+
float sumi = 0.0f;
197+
198+
// group 64: one Q2_0 block (64 weights) maps to two Q8_0 blocks (2 * 32 = 64)
199+
for (int k = 0; k < 2; k++) {
200+
const block_q8_0 * GGML_RESTRICT yb = &y[i * 2 + k];
201+
const float d1 = GGML_CPU_FP16_TO_FP32(yb->d);
202+
int sumi_block = 0;
203+
204+
const uint8_t * GGML_RESTRICT qs = &x[i].qs[k * 8];
205+
const int8_t * GGML_RESTRICT qy = yb->qs;
206+
207+
for (int b = 0; b < 8; ++b) {
208+
const uint8_t byte = qs[b];
209+
// Extract 4 two-bit values, map {0,1,2,3} -> {-1,0,1,2}
210+
sumi_block += ((int)((byte >> 0) & 3) - 1) * qy[b*4 + 0];
211+
sumi_block += ((int)((byte >> 2) & 3) - 1) * qy[b*4 + 1];
212+
sumi_block += ((int)((byte >> 4) & 3) - 1) * qy[b*4 + 2];
213+
sumi_block += ((int)((byte >> 6) & 3) - 1) * qy[b*4 + 3];
214+
}
215+
216+
sumi += d1 * sumi_block;
217+
}
218+
219+
sumf += d0 * sumi;
220+
}
221+
222+
*s = sumf;
223+
}
173224

174225
void ggml_vec_dot_q4_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {
175226
const int qk = QK8_0;

ggml/src/ggml-cpu/quants.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern "C" {
1313

1414
// Quantization
1515
void quantize_row_q1_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
16+
void quantize_row_q2_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
1617
void quantize_row_q4_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
1718
void quantize_row_q4_1(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
1819
void quantize_row_q5_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
@@ -38,6 +39,7 @@ void quantize_row_iq4_xs (const float * GGML_RESTRICT x, void * GGML_RESTRICT y,
3839

3940
// Dot product
4041
void ggml_vec_dot_q1_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
42+
void ggml_vec_dot_q2_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
4143
void ggml_vec_dot_q4_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
4244
void ggml_vec_dot_q4_1_q8_1(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
4345
void ggml_vec_dot_q5_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
@@ -71,6 +73,7 @@ void quantize_row_q8_0_generic(const float * GGML_RESTRICT x, void * GGML_RESTRI
7173
void quantize_row_q8_1_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k);
7274
void quantize_row_q8_K_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
7375
void ggml_vec_dot_q1_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
76+
void ggml_vec_dot_q2_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
7477
void ggml_vec_dot_q4_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
7578
void ggml_vec_dot_q4_1_q8_1_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
7679
void ggml_vec_dot_q5_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);

0 commit comments

Comments
 (0)