Compare commits
6
Commits
master
...
bbc407139b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbc407139b | ||
|
|
b3323108b5 | ||
|
|
e1fd6e0a13 | ||
|
|
d4343d0c5c | ||
|
|
948f51d274 | ||
|
|
4d9a6f55b6 |
+3
-1
@@ -430,7 +430,8 @@ extern "C" {
|
||||
GGML_TYPE_NVFP4 = 40, // NVFP4 (4 blocks, E4M3 scale)
|
||||
GGML_TYPE_Q1_0 = 41,
|
||||
GGML_TYPE_Q2_0 = 42,
|
||||
GGML_TYPE_COUNT = 43,
|
||||
GGML_TYPE_DT3 = 43, // DT3 (dual-plane ternary)
|
||||
GGML_TYPE_COUNT = 44,
|
||||
};
|
||||
|
||||
// precision
|
||||
@@ -475,6 +476,7 @@ extern "C" {
|
||||
GGML_FTYPE_MOSTLY_NVFP4 = 26, // except 1d tensors
|
||||
GGML_FTYPE_MOSTLY_Q1_0 = 27, // except 1d tensors
|
||||
GGML_FTYPE_MOSTLY_Q2_0 = 28, // except 1d tensors
|
||||
GGML_FTYPE_MOSTLY_DT3 = 29, // except 1d tensors
|
||||
};
|
||||
|
||||
// available tensor operations:
|
||||
|
||||
@@ -287,6 +287,26 @@ typedef struct {
|
||||
} block_tq2_0;
|
||||
static_assert(sizeof(block_tq2_0) == sizeof(ggml_half) + QK_K / 4, "wrong tq2_0 block size/padding");
|
||||
|
||||
//
|
||||
// Dual-plane ternary quantization (DT3)
|
||||
//
|
||||
// w_i = d[0]*t0_i + d[1]*t1_i, with t in {-1, 0, +1}. Two ternary planes buy
|
||||
// back most of the quality a single one loses, at 3.5 bpw instead of 1.6875.
|
||||
//
|
||||
// Each plane is packed exactly like tq1_0 with every constant halved, since the
|
||||
// block is 128 elements instead of QK_K: qs 48 -> 24 bytes, qh 4 -> 2 bytes,
|
||||
// and the two qs passes go over 16 and then 8 bytes instead of 32 and 16.
|
||||
//
|
||||
#define QK_DT3 128
|
||||
|
||||
// 3.5 bpw
|
||||
typedef struct {
|
||||
uint8_t qs[2][(QK_DT3 - 4 * QK_DT3 / 64) / 5]; // 2 planes, 5 elements per byte (3^5 = 243 < 256)
|
||||
uint8_t qh[2][QK_DT3 / 64]; // 2 planes, 4 elements per byte
|
||||
ggml_half d[2]; // one scale per plane
|
||||
} block_dt3;
|
||||
static_assert(sizeof(block_dt3) == 2 * (sizeof(ggml_half) + QK_DT3 / 64 + (QK_DT3 - 4 * QK_DT3 / 64) / 5), "wrong dt3 block size/padding");
|
||||
|
||||
//
|
||||
// Super-block quantization structures
|
||||
//
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
|
||||
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
|
||||
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
#define ggml_vec_dot_q2_K_q8_K_generic ggml_vec_dot_q2_K_q8_K
|
||||
#define ggml_vec_dot_q3_K_q8_K_generic ggml_vec_dot_q3_K_q8_K
|
||||
#define ggml_vec_dot_q4_K_q8_K_generic ggml_vec_dot_q4_K_q8_K
|
||||
@@ -72,6 +73,8 @@
|
||||
#define ggml_gemm_q8_0_4x4_q8_0_generic ggml_gemm_q8_0_4x4_q8_0
|
||||
#define ggml_gemm_q8_0_4x8_q8_0_generic ggml_gemm_q8_0_4x8_q8_0
|
||||
#elif defined(__aarch64__) || defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64)
|
||||
// quants.c
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
// repack.cpp
|
||||
#define ggml_quantize_mat_q8_K_4x4_generic ggml_quantize_mat_q8_K_4x4
|
||||
#define ggml_quantize_mat_q8_K_4x8_generic ggml_quantize_mat_q8_K_4x8
|
||||
@@ -84,6 +87,7 @@
|
||||
#elif defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
|
||||
// quants.c
|
||||
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
// repack.cpp
|
||||
#define ggml_quantize_mat_q8_0_4x4_generic ggml_quantize_mat_q8_0_4x4
|
||||
#define ggml_quantize_mat_q8_K_4x4_generic ggml_quantize_mat_q8_K_4x4
|
||||
@@ -118,6 +122,7 @@
|
||||
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
|
||||
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
|
||||
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
#define ggml_vec_dot_iq1_m_q8_K_generic ggml_vec_dot_iq1_m_q8_K
|
||||
// repack.cpp
|
||||
#define ggml_quantize_mat_q8_0_4x4_generic ggml_quantize_mat_q8_0_4x4
|
||||
@@ -161,6 +166,7 @@
|
||||
#define quantize_row_q8_K_generic quantize_row_q8_K
|
||||
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
|
||||
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
#define ggml_vec_dot_iq1_m_q8_K_generic ggml_vec_dot_iq1_m_q8_K
|
||||
#define ggml_vec_dot_mxfp4_q8_0_generic ggml_vec_dot_mxfp4_q8_0
|
||||
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
|
||||
@@ -207,6 +213,7 @@
|
||||
// quants.c
|
||||
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
|
||||
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
// repack.cpp
|
||||
#define ggml_quantize_mat_q8_0_4x1_generic ggml_quantize_mat_q8_0_4x1
|
||||
#define ggml_quantize_mat_q8_0_4x4_generic ggml_quantize_mat_q8_0_4x4
|
||||
@@ -251,6 +258,7 @@
|
||||
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
|
||||
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
|
||||
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
#define ggml_vec_dot_q2_K_q8_K_generic ggml_vec_dot_q2_K_q8_K
|
||||
#define ggml_vec_dot_iq2_xxs_q8_K_generic ggml_vec_dot_iq2_xxs_q8_K
|
||||
#define ggml_vec_dot_iq2_xs_q8_K_generic ggml_vec_dot_iq2_xs_q8_K
|
||||
@@ -300,6 +308,7 @@
|
||||
// quants.c
|
||||
#define ggml_vec_dot_tq1_0_q8_K_generic ggml_vec_dot_tq1_0_q8_K
|
||||
#define ggml_vec_dot_tq2_0_q8_K_generic ggml_vec_dot_tq2_0_q8_K
|
||||
#define ggml_vec_dot_dt3_q8_0_generic ggml_vec_dot_dt3_q8_0
|
||||
#define ggml_vec_dot_iq2_xxs_q8_K_generic ggml_vec_dot_iq2_xxs_q8_K
|
||||
#define ggml_vec_dot_iq2_xs_q8_K_generic ggml_vec_dot_iq2_xs_q8_K
|
||||
#define ggml_vec_dot_iq2_s_q8_K_generic ggml_vec_dot_iq2_s_q8_K
|
||||
|
||||
@@ -409,6 +409,14 @@ static const struct ggml_type_traits_cpu type_traits_cpu[GGML_TYPE_COUNT] = {
|
||||
.vec_dot_type = GGML_TYPE_Q8_K,
|
||||
.nrows = 1,
|
||||
},
|
||||
[GGML_TYPE_DT3] = {
|
||||
.from_float = quantize_row_dt3,
|
||||
.vec_dot = ggml_vec_dot_dt3_q8_0,
|
||||
// Q8_0 on purpose: DT3 has no zero-point, so the q8_K bsums are dead
|
||||
// weight, and 32-element blocks allow any row size multiple of 128
|
||||
.vec_dot_type = GGML_TYPE_Q8_0,
|
||||
.nrows = 1,
|
||||
},
|
||||
[GGML_TYPE_I32] = {
|
||||
.from_float = (ggml_from_float_t) ggml_cpu_fp32_to_i32,
|
||||
},
|
||||
|
||||
@@ -680,6 +680,7 @@ void ggml_compute_forward_add(
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
@@ -1132,6 +1133,7 @@ void ggml_compute_forward_add1(
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
@@ -1263,6 +1265,7 @@ void ggml_compute_forward_acc(
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
@@ -4536,6 +4539,7 @@ void ggml_compute_forward_out_prod(
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
@@ -4813,6 +4817,7 @@ void ggml_compute_forward_set(
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
@@ -5038,6 +5043,7 @@ void ggml_compute_forward_get_rows(
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
@@ -5795,6 +5801,7 @@ void ggml_compute_forward_clamp(
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
|
||||
@@ -116,6 +116,12 @@ void quantize_row_tq2_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy,
|
||||
quantize_row_tq2_0_ref(x, y, k);
|
||||
}
|
||||
|
||||
void quantize_row_dt3(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k) {
|
||||
assert(k % QK_DT3 == 0);
|
||||
block_dt3 * GGML_RESTRICT y = vy;
|
||||
quantize_row_dt3_ref(x, y, k);
|
||||
}
|
||||
|
||||
//===================================== Q8_K ==============================================
|
||||
|
||||
void quantize_row_q8_K_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k) {
|
||||
@@ -562,6 +568,51 @@ void ggml_vec_dot_tq2_0_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs,
|
||||
*s = sumf;
|
||||
}
|
||||
|
||||
void ggml_vec_dot_dt3_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) {
|
||||
const int qk = QK_DT3;
|
||||
const int nb = n / qk;
|
||||
|
||||
assert(n % qk == 0);
|
||||
assert(nrc == 1);
|
||||
UNUSED(nrc);
|
||||
UNUSED(bx);
|
||||
UNUSED(by);
|
||||
UNUSED(bs);
|
||||
|
||||
const block_dt3 * GGML_RESTRICT x = vx;
|
||||
const block_q8_0 * GGML_RESTRICT y = vy;
|
||||
|
||||
float sumf = 0.0f;
|
||||
|
||||
for (int i = 0; i < nb; i++) {
|
||||
int8_t t1[QK_DT3];
|
||||
int8_t t2[QK_DT3];
|
||||
|
||||
unpack_plane_dt3(x[i].qs[0], x[i].qh[0], t1);
|
||||
unpack_plane_dt3(x[i].qs[1], x[i].qh[1], t2);
|
||||
|
||||
const float d1 = GGML_CPU_FP16_TO_FP32(x[i].d[0]);
|
||||
const float d2 = GGML_CPU_FP16_TO_FP32(x[i].d[1]);
|
||||
|
||||
// one DT3 block (128 weights) maps to four q8_0 blocks (4 * 32 = 128)
|
||||
for (int k = 0; k < 4; k++) {
|
||||
const block_q8_0 * GGML_RESTRICT yb = &y[i*4 + k];
|
||||
const float dy = GGML_CPU_FP16_TO_FP32(yb->d);
|
||||
|
||||
int sumi1 = 0;
|
||||
int sumi2 = 0;
|
||||
for (int j = 0; j < QK8_0; j++) {
|
||||
sumi1 += t1[k*QK8_0 + j] * yb->qs[j];
|
||||
sumi2 += t2[k*QK8_0 + j] * yb->qs[j];
|
||||
}
|
||||
|
||||
sumf += dy * (d1*sumi1 + d2*sumi2);
|
||||
}
|
||||
}
|
||||
|
||||
*s = sumf;
|
||||
}
|
||||
|
||||
void ggml_vec_dot_q2_K_q8_K_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) {
|
||||
assert(nrc == 1);
|
||||
UNUSED(nrc);
|
||||
|
||||
@@ -33,6 +33,7 @@ void quantize_row_q8_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, in
|
||||
|
||||
void quantize_row_tq1_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
|
||||
void quantize_row_tq2_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
|
||||
void quantize_row_dt3 (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
|
||||
|
||||
void quantize_row_iq4_nl (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
|
||||
void quantize_row_iq4_xs (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
|
||||
@@ -57,6 +58,7 @@ void ggml_vec_dot_q6_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const voi
|
||||
|
||||
void ggml_vec_dot_tq1_0_q8_K(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);
|
||||
void ggml_vec_dot_tq2_0_q8_K(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);
|
||||
void ggml_vec_dot_dt3_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);
|
||||
|
||||
void ggml_vec_dot_iq2_xxs_q8_K(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);
|
||||
void ggml_vec_dot_iq2_xs_q8_K (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);
|
||||
@@ -85,6 +87,7 @@ void ggml_vec_dot_nvfp4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs,
|
||||
|
||||
void ggml_vec_dot_tq1_0_q8_K_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);
|
||||
void ggml_vec_dot_tq2_0_q8_K_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);
|
||||
void ggml_vec_dot_dt3_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);
|
||||
|
||||
void ggml_vec_dot_q2_K_q8_K_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);
|
||||
void ggml_vec_dot_q3_K_q8_K_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);
|
||||
|
||||
@@ -2483,6 +2483,191 @@ void dequantize_row_tq2_0(const block_tq2_0 * GGML_RESTRICT x, float * GGML_REST
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== Dual-plane ternary (de)-quantization (DT3)
|
||||
|
||||
// packs one plane of QK_DT3 trits in {-1, 0, 1}, exactly like tq1_0 with all
|
||||
// constants halved (see block_dt3 in ggml-common.h)
|
||||
static void pack_plane_dt3(const int8_t * GGML_RESTRICT t, uint8_t * GGML_RESTRICT qs, uint8_t * GGML_RESTRICT qh) {
|
||||
// 5 elements per byte, along 16 bytes
|
||||
for (size_t m = 0; m < 16; ++m) {
|
||||
uint8_t q = 0;
|
||||
for (size_t n = 0; n < 5; ++n) {
|
||||
const int xi = t[m + n*16] + 1; // -1, 0, 1 -> 0, 1, 2
|
||||
q *= 3;
|
||||
q += xi;
|
||||
}
|
||||
// ceiling division (243 == pow(3, 5))
|
||||
q = ((uint16_t)q * 256 + (243 - 1)) / 243;
|
||||
qs[m] = q;
|
||||
}
|
||||
// along 8 bytes
|
||||
for (size_t m = 0; m < 8; ++m) {
|
||||
uint8_t q = 0;
|
||||
for (size_t n = 0; n < 5; ++n) {
|
||||
const int xi = t[80 + m + n*8] + 1; // -1, 0, 1 -> 0, 1, 2
|
||||
q *= 3;
|
||||
q += xi;
|
||||
}
|
||||
// ceiling division (243 == pow(3, 5))
|
||||
q = ((uint16_t)q * 256 + (243 - 1)) / 243;
|
||||
qs[16 + m] = q;
|
||||
}
|
||||
// 4 elements per byte
|
||||
for (size_t j = 0; j < 2; ++j) {
|
||||
uint8_t q = 0;
|
||||
for (size_t m = 0; m < 4; ++m) {
|
||||
const int xi = t[120 + j + m*2] + 1; // -1, 0, 1 -> 0, 1, 2
|
||||
q *= 3;
|
||||
q += xi;
|
||||
}
|
||||
// shift the first value to the most significant trit
|
||||
q *= 3;
|
||||
// ceiling division (243 == pow(3, 5))
|
||||
q = ((uint16_t)q * 256 + (243 - 1)) / 243;
|
||||
qh[j] = q;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this is NOT the PTQTP coordinate-descent solver used to produce the
|
||||
// published DT3 models; that solver lives in the ternaria project and its
|
||||
// output is packed directly into this layout. This reference is a greedy
|
||||
// two-pass quantization (plane 1 by absolute max, plane 2 on the residual)
|
||||
// plus two rounds of alternating least-squares refits — good enough for the
|
||||
// type to be usable from float, but the measured quality of DT3 is only
|
||||
// obtained through the external PTQTP pipeline.
|
||||
void quantize_row_dt3_ref(const float * GGML_RESTRICT x, block_dt3 * GGML_RESTRICT y, int64_t k) {
|
||||
assert(k % QK_DT3 == 0);
|
||||
const int64_t nb = k / QK_DT3;
|
||||
|
||||
for (int64_t i = 0; i < nb; i++) {
|
||||
int8_t t1[QK_DT3];
|
||||
int8_t t2[QK_DT3];
|
||||
float d1;
|
||||
float d2;
|
||||
|
||||
// plane 1: ternary quantization by absolute max, like tq1_0
|
||||
{
|
||||
float amax = 0.0f;
|
||||
for (int j = 0; j < QK_DT3; j++) {
|
||||
amax = MAX(amax, fabsf(x[j]));
|
||||
}
|
||||
d1 = amax;
|
||||
const float id = d1 ? 1.0f/d1 : 0.0f;
|
||||
for (int j = 0; j < QK_DT3; j++) {
|
||||
t1[j] = (int8_t) lroundf(x[j] * id); // -1, 0, 1
|
||||
}
|
||||
}
|
||||
|
||||
// plane 2: ternary quantization of the residual
|
||||
{
|
||||
float amax = 0.0f;
|
||||
for (int j = 0; j < QK_DT3; j++) {
|
||||
amax = MAX(amax, fabsf(x[j] - d1*t1[j]));
|
||||
}
|
||||
d2 = amax;
|
||||
const float id = d2 ? 1.0f/d2 : 0.0f;
|
||||
for (int j = 0; j < QK_DT3; j++) {
|
||||
t2[j] = (int8_t) lroundf((x[j] - d1*t1[j]) * id); // -1, 0, 1
|
||||
}
|
||||
}
|
||||
|
||||
// two rounds of alternating refits: least-squares scale given the
|
||||
// trits, then re-solve the trits given the scale, holding the other
|
||||
// plane fixed
|
||||
for (int it = 0; it < 2; ++it) {
|
||||
for (int p = 0; p < 2; ++p) {
|
||||
int8_t * t = p == 0 ? t1 : t2;
|
||||
const int8_t * tother = p == 0 ? t2 : t1;
|
||||
float * d = p == 0 ? &d1 : &d2;
|
||||
const float dother = p == 0 ? d2 : d1;
|
||||
|
||||
float sum_rt = 0.0f;
|
||||
float sum_tt = 0.0f;
|
||||
for (int j = 0; j < QK_DT3; j++) {
|
||||
const float r = x[j] - dother*tother[j];
|
||||
sum_rt += r * t[j];
|
||||
sum_tt += (float)(t[j] * t[j]);
|
||||
}
|
||||
if (sum_tt > 0.0f) {
|
||||
*d = sum_rt / sum_tt;
|
||||
}
|
||||
const float id = *d ? 1.0f/(*d) : 0.0f;
|
||||
for (int j = 0; j < QK_DT3; j++) {
|
||||
const float r = x[j] - dother*tother[j];
|
||||
const int v = (int) lroundf(r * id);
|
||||
t[j] = (int8_t) MAX(-1, MIN(1, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
y[i].d[0] = GGML_FP32_TO_FP16(d1);
|
||||
y[i].d[1] = GGML_FP32_TO_FP16(d2);
|
||||
|
||||
pack_plane_dt3(t1, y[i].qs[0], y[i].qh[0]);
|
||||
pack_plane_dt3(t2, y[i].qs[1], y[i].qh[1]);
|
||||
|
||||
x += QK_DT3;
|
||||
}
|
||||
}
|
||||
|
||||
size_t quantize_dt3(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) {
|
||||
(void)quant_weights; // not used
|
||||
const size_t row_size = ggml_row_size(GGML_TYPE_DT3, n_per_row);
|
||||
quantize_row_dt3_ref(src, dst, (int64_t)nrow*n_per_row);
|
||||
return nrow * row_size;
|
||||
}
|
||||
|
||||
void unpack_plane_dt3(const uint8_t * GGML_RESTRICT qs, const uint8_t * GGML_RESTRICT qh, int8_t * GGML_RESTRICT t) {
|
||||
const uint8_t pow3[6] = {1, 3, 9, 27, 81, 243};
|
||||
|
||||
// 5 elements per byte, along 16 bytes
|
||||
for (size_t n = 0; n < 5; ++n) {
|
||||
for (size_t m = 0; m < 16; ++m) {
|
||||
const uint8_t q = qs[m] * pow3[n]; // the product wraps around on purpose
|
||||
const int16_t xi = ((uint16_t) q * 3) >> 8;
|
||||
*t++ = (int8_t)(xi - 1);
|
||||
}
|
||||
}
|
||||
// along 8 bytes
|
||||
for (size_t n = 0; n < 5; ++n) {
|
||||
for (size_t m = 0; m < 8; ++m) {
|
||||
const uint8_t q = qs[16 + m] * pow3[n];
|
||||
const int16_t xi = ((uint16_t) q * 3) >> 8;
|
||||
*t++ = (int8_t)(xi - 1);
|
||||
}
|
||||
}
|
||||
// 4 elements per byte — NOT 5: each qh byte stores only 4 trits, and its
|
||||
// 5th base-3 digit is padding from the packer's extra q *= 3 shift which
|
||||
// always decodes to -1; reading it would inject spurious values
|
||||
for (size_t n = 0; n < 4; ++n) {
|
||||
for (size_t j = 0; j < 2; ++j) {
|
||||
const uint8_t q = qh[j] * pow3[n];
|
||||
const int16_t xi = ((uint16_t) q * 3) >> 8;
|
||||
*t++ = (int8_t)(xi - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dequantize_row_dt3(const block_dt3 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k) {
|
||||
assert(k % QK_DT3 == 0);
|
||||
const int64_t nb = k / QK_DT3;
|
||||
|
||||
for (int64_t i = 0; i < nb; ++i) {
|
||||
int8_t t1[QK_DT3];
|
||||
int8_t t2[QK_DT3];
|
||||
|
||||
unpack_plane_dt3(x[i].qs[0], x[i].qh[0], t1);
|
||||
unpack_plane_dt3(x[i].qs[1], x[i].qh[1], t2);
|
||||
|
||||
const float d1 = GGML_FP16_TO_FP32(x[i].d[0]);
|
||||
const float d2 = GGML_FP16_TO_FP32(x[i].d[1]);
|
||||
|
||||
for (int j = 0; j < QK_DT3; ++j) {
|
||||
*y++ = d1*t1[j] + d2*t2[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== "True" 2-bit (de)-quantization
|
||||
|
||||
void dequantize_row_iq2_xxs(const block_iq2_xxs * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k) {
|
||||
@@ -5604,6 +5789,15 @@ bool ggml_validate_row_data(enum ggml_type type, const void * data, size_t nbyte
|
||||
{
|
||||
VALIDATE_ROW_DATA_D_F16_IMPL(block_tq2_0, data, nb);
|
||||
} break;
|
||||
case GGML_TYPE_DT3:
|
||||
{
|
||||
const block_dt3 * q = (const block_dt3 *) data;
|
||||
for (size_t i = 0; i < nb; ++i) {
|
||||
if (!validate_fp16(q[i].d[0], i) || !validate_fp16(q[i].d[1], i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case GGML_TYPE_IQ1_S:
|
||||
{
|
||||
VALIDATE_ROW_DATA_D_F16_IMPL(block_iq1_s, data, nb);
|
||||
|
||||
@@ -35,6 +35,7 @@ GGML_API void quantize_row_q8_K_ref(const float * GGML_RESTRICT x, block_q8_K *
|
||||
|
||||
GGML_API void quantize_row_tq1_0_ref(const float * GGML_RESTRICT x, block_tq1_0 * GGML_RESTRICT y, int64_t k);
|
||||
GGML_API void quantize_row_tq2_0_ref(const float * GGML_RESTRICT x, block_tq2_0 * GGML_RESTRICT y, int64_t k);
|
||||
GGML_API void quantize_row_dt3_ref (const float * GGML_RESTRICT x, block_dt3 * GGML_RESTRICT y, int64_t k);
|
||||
|
||||
GGML_API void quantize_row_iq3_xxs_ref(const float * GGML_RESTRICT x, block_iq3_xxs * GGML_RESTRICT y, int64_t k);
|
||||
GGML_API void quantize_row_iq4_nl_ref (const float * GGML_RESTRICT x, block_iq4_nl * GGML_RESTRICT y, int64_t k);
|
||||
@@ -64,6 +65,12 @@ GGML_API void dequantize_row_q8_K(const block_q8_K * GGML_RESTRICT x, float * GG
|
||||
|
||||
GGML_API void dequantize_row_tq1_0(const block_tq1_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k);
|
||||
GGML_API void dequantize_row_tq2_0(const block_tq2_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k);
|
||||
GGML_API void dequantize_row_dt3 (const block_dt3 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k);
|
||||
|
||||
// unpacks one DT3 plane (128 trits in {-1, 0, 1}) in the original element order;
|
||||
// shared between dequantize_row_dt3 and the CPU vec_dot so that the trit
|
||||
// decoding exists in exactly one place
|
||||
GGML_API void unpack_plane_dt3(const uint8_t * GGML_RESTRICT qs, const uint8_t * GGML_RESTRICT qh, int8_t * GGML_RESTRICT t);
|
||||
|
||||
GGML_API void dequantize_row_iq2_xxs(const block_iq2_xxs * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k);
|
||||
GGML_API void dequantize_row_iq2_xs (const block_iq2_xs * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k);
|
||||
@@ -88,6 +95,7 @@ GGML_API size_t quantize_iq3_s (const float * GGML_RESTRICT src, void * GGML_RE
|
||||
|
||||
GGML_API size_t quantize_tq1_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
|
||||
GGML_API size_t quantize_tq2_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
|
||||
GGML_API size_t quantize_dt3 (const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
|
||||
|
||||
GGML_API size_t quantize_q2_K(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
|
||||
GGML_API size_t quantize_q3_K(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
|
||||
|
||||
@@ -924,6 +924,14 @@ static const struct ggml_type_traits type_traits[GGML_TYPE_COUNT] = {
|
||||
.to_float = (ggml_to_float_t) dequantize_row_tq2_0,
|
||||
.from_float_ref = (ggml_from_float_t) quantize_row_tq2_0_ref,
|
||||
},
|
||||
[GGML_TYPE_DT3] = {
|
||||
.type_name = "dt3",
|
||||
.blck_size = QK_DT3,
|
||||
.type_size = sizeof(block_dt3),
|
||||
.is_quantized = true,
|
||||
.to_float = (ggml_to_float_t) dequantize_row_dt3,
|
||||
.from_float_ref = (ggml_from_float_t) quantize_row_dt3_ref,
|
||||
},
|
||||
[36] = { // GGML_TYPE_IQ4_NL_4_4
|
||||
.type_name = "TYPE_IQ4_NL_4_4 REMOVED, use IQ4_NL with runtime repacking",
|
||||
.blck_size = 0,
|
||||
@@ -1434,6 +1442,7 @@ enum ggml_type ggml_ftype_to_ggml_type(enum ggml_ftype ftype) {
|
||||
case GGML_FTYPE_MOSTLY_Q4_1: wtype = GGML_TYPE_Q4_1; break;
|
||||
case GGML_FTYPE_MOSTLY_Q1_0: wtype = GGML_TYPE_Q1_0; break;
|
||||
case GGML_FTYPE_MOSTLY_Q2_0: wtype = GGML_TYPE_Q2_0; break;
|
||||
case GGML_FTYPE_MOSTLY_DT3: wtype = GGML_TYPE_DT3; break;
|
||||
case GGML_FTYPE_MOSTLY_Q5_0: wtype = GGML_TYPE_Q5_0; break;
|
||||
case GGML_FTYPE_MOSTLY_Q5_1: wtype = GGML_TYPE_Q5_1; break;
|
||||
case GGML_FTYPE_MOSTLY_Q8_0: wtype = GGML_TYPE_Q8_0; break;
|
||||
@@ -7957,6 +7966,7 @@ size_t ggml_quantize_chunk(
|
||||
case GGML_TYPE_Q6_K: result = quantize_q6_K (src + start, (char *) dst + start_row * row_size, nrows, n_per_row, imatrix); break;
|
||||
case GGML_TYPE_TQ1_0: result = quantize_tq1_0 (src + start, (char *) dst + start_row * row_size, nrows, n_per_row, imatrix); break;
|
||||
case GGML_TYPE_TQ2_0: result = quantize_tq2_0 (src + start, (char *) dst + start_row * row_size, nrows, n_per_row, imatrix); break;
|
||||
case GGML_TYPE_DT3: result = quantize_dt3 (src + start, (char *) dst + start_row * row_size, nrows, n_per_row, imatrix); break;
|
||||
case GGML_TYPE_IQ2_XXS: result = quantize_iq2_xxs(src + start, (char *) dst + start_row * row_size, nrows, n_per_row, imatrix); break;
|
||||
case GGML_TYPE_IQ2_XS: result = quantize_iq2_xs (src + start, (char *) dst + start_row * row_size, nrows, n_per_row, imatrix); break;
|
||||
case GGML_TYPE_IQ3_XXS: result = quantize_iq3_xxs(src + start, (char *) dst + start_row * row_size, nrows, n_per_row, imatrix); break;
|
||||
|
||||
@@ -5019,6 +5019,7 @@ class GGMLQuantizationType(IntEnum):
|
||||
NVFP4 = 40
|
||||
Q1_0 = 41
|
||||
Q2_0 = 42
|
||||
DT3 = 43
|
||||
|
||||
|
||||
class ExpertGatingFuncType(IntEnum):
|
||||
@@ -5075,6 +5076,7 @@ class LlamaFileType(IntEnum):
|
||||
MOSTLY_NVFP4 = 39 # except 1d tensors
|
||||
MOSTLY_Q1_0 = 40 # except 1d tensors
|
||||
MOSTLY_Q2_0 = 41 # except 1d tensors
|
||||
MOSTLY_DT3 = 42 # except 1d tensors
|
||||
|
||||
GUESSED = 1024 # not specified in the model file
|
||||
|
||||
@@ -5206,6 +5208,7 @@ GGML_QUANT_SIZES: dict[GGMLQuantizationType, tuple[int, int]] = {
|
||||
GGMLQuantizationType.NVFP4: (64, 4 + 32),
|
||||
GGMLQuantizationType.Q1_0: (128, 2 + 16),
|
||||
GGMLQuantizationType.Q2_0: (64, 2 + 16),
|
||||
GGMLQuantizationType.DT3: (128, 2 * (24 + 2 + 2)),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -654,6 +654,42 @@ class TQ2_0(__Quant, qtype=GGMLQuantizationType.TQ2_0):
|
||||
return (d * qs.astype(np.float32))
|
||||
|
||||
|
||||
class DT3(__Quant, qtype=GGMLQuantizationType.DT3):
|
||||
# Dual-plane ternary: w = d1 * t1 + d2 * t2 with t in {-1, 0, 1}. Each of
|
||||
# the two planes is packed like TQ1_0 with all constants halved (blocks of
|
||||
# 128 elements): 24 bytes of qs (passes of 16 and 8 bytes) and 2 bytes of
|
||||
# qh per plane, then the two fp16 scales.
|
||||
# Quantization is intentionally not implemented here: DT3 planes are
|
||||
# produced by an external solver (PTQTP) and packed directly.
|
||||
@classmethod
|
||||
def dequantize_blocks(cls, blocks: np.ndarray) -> np.ndarray:
|
||||
n_blocks = blocks.shape[0]
|
||||
|
||||
qs, rest = np.hsplit(blocks, [2 * 24])
|
||||
qh, d = np.hsplit(rest, [2 * 2])
|
||||
|
||||
d = d.view(np.float16).astype(np.float32).reshape((n_blocks, 2, 1))
|
||||
|
||||
planes = []
|
||||
for p in range(2):
|
||||
pqs = qs[..., p * 24:(p + 1) * 24]
|
||||
pqh = qh[..., p * 2:(p + 1) * 2]
|
||||
|
||||
qs0, qs1 = pqs[..., :16], pqs[..., 16:]
|
||||
qs0 = qs0.reshape((n_blocks, -1, 1, 16)) * np.array([1, 3, 9, 27, 81], dtype=np.uint8).reshape((1, 1, 5, 1))
|
||||
qs0 = qs0.reshape((n_blocks, -1))
|
||||
qs1 = qs1.reshape((n_blocks, -1, 1, 8)) * np.array([1, 3, 9, 27, 81], dtype=np.uint8).reshape((1, 1, 5, 1))
|
||||
qs1 = qs1.reshape((n_blocks, -1))
|
||||
# only 4 trits per qh byte, the 5th base-3 digit is packer padding
|
||||
pqh = pqh.reshape((n_blocks, -1, 1, 2)) * np.array([1, 3, 9, 27], dtype=np.uint8).reshape((1, 1, 4, 1))
|
||||
pqh = pqh.reshape((n_blocks, -1))
|
||||
pq = np.concatenate([qs0, qs1, pqh], axis=-1)
|
||||
pq = ((pq.astype(np.uint16) * 3) >> 8).astype(np.int8) - np.int8(1)
|
||||
planes.append(pq.astype(np.float32))
|
||||
|
||||
return d[:, 0] * planes[0] + d[:, 1] * planes[1]
|
||||
|
||||
|
||||
class MXFP4(__Quant, qtype=GGMLQuantizationType.MXFP4):
|
||||
# e2m1 values (doubled)
|
||||
# ref: https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
|
||||
|
||||
@@ -156,6 +156,7 @@ extern "C" {
|
||||
LLAMA_FTYPE_MOSTLY_NVFP4 = 39, // except 1d tensors
|
||||
LLAMA_FTYPE_MOSTLY_Q1_0 = 40, // except 1d tensors
|
||||
LLAMA_FTYPE_MOSTLY_Q2_0 = 41, // except 1d tensors
|
||||
LLAMA_FTYPE_MOSTLY_DT3 = 42, // except 1d tensors
|
||||
|
||||
LLAMA_FTYPE_GUESSED = 1024, // not specified in the model file
|
||||
};
|
||||
|
||||
@@ -58,6 +58,7 @@ const char * llama_ftype_name(llama_ftype ftype) {
|
||||
case LLAMA_FTYPE_MOSTLY_Q6_K: name = LLAMA_FTYPE_PREFIX "Q6_K"; break;
|
||||
case LLAMA_FTYPE_MOSTLY_TQ1_0: name = LLAMA_FTYPE_PREFIX "TQ1_0 - 1.69 bpw ternary"; break;
|
||||
case LLAMA_FTYPE_MOSTLY_TQ2_0: name = LLAMA_FTYPE_PREFIX "TQ2_0 - 2.06 bpw ternary"; break;
|
||||
case LLAMA_FTYPE_MOSTLY_DT3: name = LLAMA_FTYPE_PREFIX "DT3 - 3.5 bpw dual-plane ternary"; break;
|
||||
case LLAMA_FTYPE_MOSTLY_IQ2_XXS: name = LLAMA_FTYPE_PREFIX "IQ2_XXS - 2.0625 bpw"; break;
|
||||
case LLAMA_FTYPE_MOSTLY_IQ2_XS: name = LLAMA_FTYPE_PREFIX "IQ2_XS - 2.3125 bpw"; break;
|
||||
case LLAMA_FTYPE_MOSTLY_IQ2_S: name = LLAMA_FTYPE_PREFIX "IQ2_S - 2.5 bpw"; break;
|
||||
@@ -747,6 +748,7 @@ llama_model_loader::llama_model_loader(
|
||||
case GGML_TYPE_Q6_K: ftype = LLAMA_FTYPE_MOSTLY_Q6_K; break;
|
||||
case GGML_TYPE_TQ1_0: ftype = LLAMA_FTYPE_MOSTLY_TQ1_0; break;
|
||||
case GGML_TYPE_TQ2_0: ftype = LLAMA_FTYPE_MOSTLY_TQ2_0; break;
|
||||
case GGML_TYPE_DT3: ftype = LLAMA_FTYPE_MOSTLY_DT3; break;
|
||||
case GGML_TYPE_IQ2_XXS: ftype = LLAMA_FTYPE_MOSTLY_IQ2_XXS; break;
|
||||
case GGML_TYPE_IQ2_XS: ftype = LLAMA_FTYPE_MOSTLY_IQ2_XS; break;
|
||||
case GGML_TYPE_IQ2_S: ftype = LLAMA_FTYPE_MOSTLY_IQ2_S; break;
|
||||
|
||||
+4
-2
@@ -396,7 +396,8 @@ static ggml_type tensor_type_fallback(quantize_state_impl & qs, const ggml_tenso
|
||||
case GGML_TYPE_Q2_K:
|
||||
case GGML_TYPE_Q3_K:
|
||||
case GGML_TYPE_TQ1_0:
|
||||
case GGML_TYPE_TQ2_0: return_type = GGML_TYPE_Q4_0; break;
|
||||
case GGML_TYPE_TQ2_0:
|
||||
case GGML_TYPE_DT3: return_type = GGML_TYPE_Q4_0; break;
|
||||
case GGML_TYPE_Q4_K: return_type = GGML_TYPE_Q5_0; break;
|
||||
case GGML_TYPE_Q5_K: return_type = GGML_TYPE_Q5_1; break;
|
||||
case GGML_TYPE_Q6_K: return_type = GGML_TYPE_Q8_0; break;
|
||||
@@ -493,7 +494,7 @@ static ggml_type llama_tensor_get_type_impl(quantize_state_impl & qs, ggml_type
|
||||
else if (ftype == LLAMA_FTYPE_MOSTLY_IQ3_XXS) {
|
||||
new_type = GGML_TYPE_IQ3_S;
|
||||
}
|
||||
else if (ftype == LLAMA_FTYPE_MOSTLY_TQ1_0 || ftype == LLAMA_FTYPE_MOSTLY_TQ2_0 || ftype == LLAMA_FTYPE_MOSTLY_Q2_0) {
|
||||
else if (ftype == LLAMA_FTYPE_MOSTLY_TQ1_0 || ftype == LLAMA_FTYPE_MOSTLY_TQ2_0 || ftype == LLAMA_FTYPE_MOSTLY_Q2_0 || ftype == LLAMA_FTYPE_MOSTLY_DT3) {
|
||||
new_type = GGML_TYPE_Q4_K;
|
||||
}
|
||||
}
|
||||
@@ -831,6 +832,7 @@ ggml_type llama_ftype_get_default_type(llama_ftype ftype) {
|
||||
case LLAMA_FTYPE_MOSTLY_Q6_K: return GGML_TYPE_Q6_K;
|
||||
case LLAMA_FTYPE_MOSTLY_TQ1_0: return GGML_TYPE_TQ1_0;
|
||||
case LLAMA_FTYPE_MOSTLY_TQ2_0: return GGML_TYPE_TQ2_0;
|
||||
case LLAMA_FTYPE_MOSTLY_DT3: return GGML_TYPE_DT3;
|
||||
case LLAMA_FTYPE_MOSTLY_IQ2_XXS: return GGML_TYPE_IQ2_XXS;
|
||||
case LLAMA_FTYPE_MOSTLY_IQ2_XS: return GGML_TYPE_IQ2_XS;
|
||||
case LLAMA_FTYPE_MOSTLY_IQ2_S: return GGML_TYPE_IQ2_XS;
|
||||
|
||||
@@ -289,6 +289,7 @@ if (NOT GGML_BACKEND_DL)
|
||||
# these tests use the backends directly and cannot be built with dynamic loading
|
||||
llama_build_and_test(test-barrier.cpp)
|
||||
llama_build_and_test(test-quantize-fns.cpp)
|
||||
llama_build_and_test(test-dt3.cpp)
|
||||
llama_build_and_test(test-quantize-perf.cpp)
|
||||
llama_build_and_test(test-rope.cpp)
|
||||
llama_build_and_test(test-col2im-1d.cpp)
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python3
|
||||
# Parity check between ternaria's Rust DT3 packer and llama.cpp's C
|
||||
# dequantization: blocks packed by pack_dt3 must dequantize (through
|
||||
# dequantize_row_dt3, exposed by `test-dt3 --dequant`) to exactly
|
||||
# d1*t1 + d2*t2 computed independently in numpy from the same trits and
|
||||
# fp16-rounded scales.
|
||||
#
|
||||
# Must run inside the ternaria environment, e.g.:
|
||||
# cd /path/to/ternaria && uv run python /path/to/llama.cpp/tests/test-dt3-rust-parity.py \
|
||||
# /path/to/llama.cpp/build/bin/test-dt3
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ternaria._core import pack_dt3
|
||||
|
||||
QK_DT3 = 128
|
||||
BLOCK_BYTES = 56
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) != 2:
|
||||
print(f"usage: {sys.argv[0]} /path/to/test-dt3", file=sys.stderr)
|
||||
return 1
|
||||
test_bin = Path(sys.argv[1])
|
||||
|
||||
rng = np.random.default_rng(20260810)
|
||||
|
||||
rows, cols = 8, 1024
|
||||
t1 = rng.integers(-1, 2, size=(rows, cols)).astype(np.int8)
|
||||
t2 = rng.integers(-1, 2, size=(rows, cols)).astype(np.int8)
|
||||
s1 = rng.normal(size=(rows, cols // QK_DT3)).astype(np.float32)
|
||||
s2 = (0.25 * rng.normal(size=(rows, cols // QK_DT3))).astype(np.float32)
|
||||
|
||||
# edge cases: an all-zero block, a block with negative scales, and a
|
||||
# block that is non-trivial only in the qh region (elements 120..127)
|
||||
t1[0, :QK_DT3] = 0
|
||||
t2[0, :QK_DT3] = 0
|
||||
s1[0, 0] = 0.0
|
||||
s2[0, 0] = 0.0
|
||||
s1[0, 1] = -abs(s1[0, 1])
|
||||
s2[0, 1] = -abs(s2[0, 1])
|
||||
t1[1, :QK_DT3] = 0
|
||||
t2[1, :QK_DT3] = 0
|
||||
t1[1, 120:128] = [-1, 1, 0, -1, 1, -1, 0, 1]
|
||||
t2[1, 120:128] = [1, -1, 1, 0, 0, 1, -1, -1]
|
||||
|
||||
raw = np.asarray(pack_dt3(t1, s1, t2, s2), dtype=np.uint8)
|
||||
assert raw.size == rows * (cols // QK_DT3) * BLOCK_BYTES, raw.size
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
raw_path = Path(tmp) / "dt3.bin"
|
||||
out_path = Path(tmp) / "out.f32"
|
||||
raw_path.write_bytes(raw.tobytes())
|
||||
subprocess.run([str(test_bin), "--dequant", str(raw_path), str(out_path)], check=True)
|
||||
got = np.fromfile(out_path, dtype=np.float32).reshape(rows, cols)
|
||||
|
||||
# what the packed bytes mean: fp16-rounded scales times the trits
|
||||
d1 = s1.astype(np.float16).astype(np.float32).repeat(QK_DT3, axis=1)
|
||||
d2 = s2.astype(np.float16).astype(np.float32).repeat(QK_DT3, axis=1)
|
||||
expected = d1 * t1.astype(np.float32) + d2 * t2.astype(np.float32)
|
||||
|
||||
if not np.array_equal(got, expected):
|
||||
bad = np.nonzero(got != expected)
|
||||
print(f"FAILED: {len(bad[0])} of {got.size} elements differ", file=sys.stderr)
|
||||
r, c = bad[0][0], bad[1][0]
|
||||
print(f"first mismatch at ({r}, {c}): got {got[r, c]}, expected {expected[r, c]}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(f"ok: {got.size} weights bit-exact between Rust pack_dt3 and C dequantize_row_dt3")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,416 @@
|
||||
// Bit-level unit tests for the DT3 dual-plane ternary format
|
||||
//
|
||||
// DT3 packs 128 weights as two ternary planes (w = d1*t1 + d2*t2), each plane
|
||||
// laid out exactly like tq1_0 with all constants halved. A block with
|
||||
// misplaced bits still loads and generates, so the layout is checked here
|
||||
// bit by bit against an independent packer that implements the format
|
||||
// specification directly.
|
||||
//
|
||||
// Extra mode for cross-implementation parity checks (see
|
||||
// tests/test-dt3-rust-parity.py):
|
||||
// test-dt3 --dequant IN.bin OUT.f32
|
||||
// dequantizes raw DT3 blocks from IN.bin into float32 little-endian OUT.f32.
|
||||
|
||||
#include "ggml.h"
|
||||
#include "ggml-cpu.h"
|
||||
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
constexpr int QK_DT3 = 128;
|
||||
constexpr size_t DT3_QS_BYTES = 24; // per plane
|
||||
constexpr size_t DT3_QH_BYTES = 2; // per plane
|
||||
constexpr size_t DT3_BLOCK_SIZE = 2*DT3_QS_BYTES + 2*DT3_QH_BYTES + 2*sizeof(uint16_t);
|
||||
|
||||
// byte offsets inside a block (spec: qs[2][24] | qh[2][2] | d[2])
|
||||
constexpr size_t OFF_QS = 0;
|
||||
constexpr size_t OFF_QH = 2*DT3_QS_BYTES;
|
||||
constexpr size_t OFF_D = 2*DT3_QS_BYTES + 2*DT3_QH_BYTES;
|
||||
|
||||
// Independent packer, written from the format specification (not from
|
||||
// ggml-quants.c): trits in {-1, 0, 1}, element i of the plane goes to
|
||||
// region A: qs[m], m in [0,16), digit n: elements m + n*16 (0..79)
|
||||
// region B: qs[16+m], m in [0,8), digit n: elements 80 + m + n*8 (80..119)
|
||||
// region C: qh[j], j in [0,2), digit n: elements 120 + j + n*2 (120..127)
|
||||
// with the first element in the most significant trit, an extra *3 shift in
|
||||
// region C, and ceiling division by 243 to fit 5 trits per byte.
|
||||
static void ref_pack_plane(const int8_t * t, uint8_t * qs, uint8_t * qh) {
|
||||
for (int m = 0; m < 16; ++m) {
|
||||
uint32_t q = 0;
|
||||
for (int n = 0; n < 5; ++n) {
|
||||
q = q*3 + (uint32_t)(t[m + n*16] + 1);
|
||||
}
|
||||
qs[m] = (uint8_t)((q*256 + 242)/243);
|
||||
}
|
||||
for (int m = 0; m < 8; ++m) {
|
||||
uint32_t q = 0;
|
||||
for (int n = 0; n < 5; ++n) {
|
||||
q = q*3 + (uint32_t)(t[80 + m + n*8] + 1);
|
||||
}
|
||||
qs[16 + m] = (uint8_t)((q*256 + 242)/243);
|
||||
}
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
uint32_t q = 0;
|
||||
for (int n = 0; n < 4; ++n) {
|
||||
q = q*3 + (uint32_t)(t[120 + j + n*2] + 1);
|
||||
}
|
||||
q *= 3; // shift the first value to the most significant trit
|
||||
qh[j] = (uint8_t)((q*256 + 242)/243);
|
||||
}
|
||||
}
|
||||
|
||||
static void ref_pack_block(const int8_t * t1, float d1, const int8_t * t2, float d2, uint8_t * block) {
|
||||
ref_pack_plane(t1, block + OFF_QS, block + OFF_QH);
|
||||
ref_pack_plane(t2, block + OFF_QS + DT3_QS_BYTES, block + OFF_QH + DT3_QH_BYTES);
|
||||
const uint16_t h1 = ggml_fp32_to_fp16(d1);
|
||||
const uint16_t h2 = ggml_fp32_to_fp16(d2);
|
||||
memcpy(block + OFF_D, &h1, sizeof(h1));
|
||||
memcpy(block + OFF_D + 2, &h2, sizeof(h2));
|
||||
}
|
||||
|
||||
// deterministic PRNG so failures are reproducible
|
||||
static uint32_t rng_state = 0x12345678;
|
||||
static uint32_t rng_next(void) {
|
||||
rng_state ^= rng_state << 13;
|
||||
rng_state ^= rng_state >> 17;
|
||||
rng_state ^= rng_state << 5;
|
||||
return rng_state;
|
||||
}
|
||||
static int8_t rng_trit(void) {
|
||||
return (int8_t)(rng_next() % 3) - 1;
|
||||
}
|
||||
|
||||
static int test_layout_constants(void) {
|
||||
int num_failed = 0;
|
||||
|
||||
if (ggml_blck_size(GGML_TYPE_DT3) != QK_DT3) {
|
||||
printf("FAILED: blck_size is %" PRId64 ", expected %d\n", ggml_blck_size(GGML_TYPE_DT3), QK_DT3);
|
||||
num_failed++;
|
||||
}
|
||||
if (ggml_type_size(GGML_TYPE_DT3) != DT3_BLOCK_SIZE) {
|
||||
printf("FAILED: type_size is %zu, expected %zu\n", ggml_type_size(GGML_TYPE_DT3), DT3_BLOCK_SIZE);
|
||||
num_failed++;
|
||||
}
|
||||
// 56 bytes / 128 weights = 3.5 bpw exactly
|
||||
if (DT3_BLOCK_SIZE*8 != (size_t)QK_DT3*7/2) {
|
||||
printf("FAILED: not 3.5 bpw\n");
|
||||
num_failed++;
|
||||
}
|
||||
|
||||
return num_failed;
|
||||
}
|
||||
|
||||
// a single trit set to -1 or +1 at each position of each plane must come back
|
||||
// at the same position, scaled by that plane's scale only
|
||||
static int test_single_trits(const ggml_type_traits * qfns) {
|
||||
int num_failed = 0;
|
||||
|
||||
const float d1 = 1.0f; // exact in fp16
|
||||
const float d2 = 0.25f; // exact in fp16
|
||||
|
||||
for (int plane = 0; plane < 2; ++plane) {
|
||||
for (int pos = 0; pos < QK_DT3; ++pos) {
|
||||
for (int val = -1; val <= 1; val += 2) {
|
||||
int8_t t1[QK_DT3] = {0};
|
||||
int8_t t2[QK_DT3] = {0};
|
||||
(plane == 0 ? t1 : t2)[pos] = (int8_t)val;
|
||||
|
||||
uint8_t block[DT3_BLOCK_SIZE];
|
||||
ref_pack_block(t1, d1, t2, d2, block);
|
||||
|
||||
float out[QK_DT3];
|
||||
qfns->to_float(block, out, QK_DT3);
|
||||
|
||||
for (int j = 0; j < QK_DT3; ++j) {
|
||||
const float expected = j == pos ? (plane == 0 ? d1 : d2)*val : 0.0f;
|
||||
if (out[j] != expected) {
|
||||
printf("FAILED: plane %d pos %d val %d: out[%d] = %f, expected %f\n",
|
||||
plane, pos, val, j, out[j], expected);
|
||||
num_failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_failed;
|
||||
}
|
||||
|
||||
// spot-check the byte positions of the region boundaries against values
|
||||
// computed by hand from the packing formula
|
||||
static int test_byte_positions(void) {
|
||||
int num_failed = 0;
|
||||
|
||||
// verify the element -> byte mapping structurally: flipping element `pos`
|
||||
// must change EXACTLY the one byte the formula says, and no other
|
||||
struct pos_case {
|
||||
int pos;
|
||||
size_t off; // expected changed byte, offset inside plane data
|
||||
};
|
||||
const pos_case pcases[] = {
|
||||
{ 0, 0 }, // region A, byte 0
|
||||
{ 15, 15 }, // region A, byte 15
|
||||
{ 16, 0 }, // region A, digit 1 of byte 0
|
||||
{ 64, 0 }, // region A, digit 4 of byte 0
|
||||
{ 79, 15 }, // region A boundary: last element, byte 15
|
||||
{ 80, 16 }, // region B boundary: first element, byte 16
|
||||
{ 87, 23 }, // region B, byte 23
|
||||
{ 119, 23 }, // region B boundary: last element, byte 23
|
||||
{ 120, 24 }, // region C boundary: first element, qh[0]
|
||||
{ 121, 25 }, // region C, qh[1]
|
||||
{ 126, 24 }, // region C, digit 3 of qh[0]
|
||||
{ 127, 25 }, // region C, last element, qh[1]
|
||||
};
|
||||
|
||||
uint8_t zero_plane[DT3_QS_BYTES + DT3_QH_BYTES];
|
||||
{
|
||||
const int8_t t0[QK_DT3] = {0};
|
||||
ref_pack_plane(t0, zero_plane, zero_plane + DT3_QS_BYTES);
|
||||
}
|
||||
|
||||
for (size_t c = 0; c < sizeof(pcases)/sizeof(pcases[0]); ++c) {
|
||||
int8_t t[QK_DT3] = {0};
|
||||
t[pcases[c].pos] = -1;
|
||||
|
||||
uint8_t plane[DT3_QS_BYTES + DT3_QH_BYTES];
|
||||
ref_pack_plane(t, plane, plane + DT3_QS_BYTES);
|
||||
|
||||
for (size_t b = 0; b < sizeof(plane); ++b) {
|
||||
const bool should_differ = b == pcases[c].off;
|
||||
const bool differs = plane[b] != zero_plane[b];
|
||||
if (differs != should_differ) {
|
||||
printf("FAILED: pos %d: byte %zu %s, expected %s\n",
|
||||
pcases[c].pos, b,
|
||||
differs ? "changed" : "unchanged",
|
||||
should_differ ? "changed" : "unchanged");
|
||||
num_failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_failed;
|
||||
}
|
||||
|
||||
// random trits and scales (negative scales included) must round-trip exactly
|
||||
static int test_roundtrip(const ggml_type_traits * qfns) {
|
||||
int num_failed = 0;
|
||||
|
||||
const float scales[][2] = {
|
||||
{ 1.0f, 0.25f },
|
||||
{ 0.5f, -0.125f }, // negative second plane
|
||||
{-2.0f, 0.75f }, // negative first plane
|
||||
{ 0.0f, 0.0f }, // all-zero scales
|
||||
};
|
||||
|
||||
for (size_t sc = 0; sc < sizeof(scales)/sizeof(scales[0]); ++sc) {
|
||||
for (int rep = 0; rep < 64; ++rep) {
|
||||
int8_t t1[QK_DT3];
|
||||
int8_t t2[QK_DT3];
|
||||
for (int j = 0; j < QK_DT3; ++j) {
|
||||
t1[j] = rng_trit();
|
||||
t2[j] = rng_trit();
|
||||
}
|
||||
|
||||
const float d1 = ggml_fp16_to_fp32(ggml_fp32_to_fp16(scales[sc][0]));
|
||||
const float d2 = ggml_fp16_to_fp32(ggml_fp32_to_fp16(scales[sc][1]));
|
||||
|
||||
uint8_t block[DT3_BLOCK_SIZE];
|
||||
ref_pack_block(t1, d1, t2, d2, block);
|
||||
|
||||
float out[QK_DT3];
|
||||
qfns->to_float(block, out, QK_DT3);
|
||||
|
||||
for (int j = 0; j < QK_DT3; ++j) {
|
||||
const float expected = d1*t1[j] + d2*t2[j];
|
||||
if (out[j] != expected) {
|
||||
printf("FAILED: roundtrip scales (%f, %f) rep %d: out[%d] = %f, expected %f\n",
|
||||
d1, d2, rep, j, out[j], expected);
|
||||
num_failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_failed;
|
||||
}
|
||||
|
||||
// the in-tree quantizer must produce the same bytes as the independent packer
|
||||
// when the input is already exactly ternary (plane 1 = input, plane 2 = 0)
|
||||
static int test_quantize_pack_parity(const ggml_type_traits_cpu * qfns_cpu) {
|
||||
int num_failed = 0;
|
||||
|
||||
for (int rep = 0; rep < 64; ++rep) {
|
||||
int8_t t1[QK_DT3];
|
||||
const int8_t t2[QK_DT3] = {0};
|
||||
float x[QK_DT3];
|
||||
for (int j = 0; j < QK_DT3; ++j) {
|
||||
t1[j] = rng_trit();
|
||||
x[j] = (float) t1[j];
|
||||
}
|
||||
// make sure the block is not all zeros so that d1 == 1.0
|
||||
t1[0] = 1;
|
||||
x[0] = 1.0f;
|
||||
|
||||
uint8_t expected[DT3_BLOCK_SIZE];
|
||||
ref_pack_block(t1, 1.0f, t2, 0.0f, expected);
|
||||
|
||||
uint8_t block[DT3_BLOCK_SIZE];
|
||||
qfns_cpu->from_float(x, block, QK_DT3);
|
||||
|
||||
if (memcmp(block, expected, DT3_BLOCK_SIZE) != 0) {
|
||||
for (size_t b = 0; b < DT3_BLOCK_SIZE; ++b) {
|
||||
if (block[b] != expected[b]) {
|
||||
printf("FAILED: quantize pack parity rep %d: byte %zu is 0x%02x, expected 0x%02x\n",
|
||||
rep, b, block[b], expected[b]);
|
||||
}
|
||||
}
|
||||
num_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_failed;
|
||||
}
|
||||
|
||||
// vec_dot against a hand-made sum over the KNOWN trits (not against our own
|
||||
// dequantization): sum_i y_i * (d1*t1_i + d2*t2_i) with y from q8_0's own
|
||||
// to_float. Random trits make the qh bytes non-trivial, which would expose a
|
||||
// vectorization that reads the padding 5th trit of the qh bytes.
|
||||
static int test_vec_dot(const ggml_type_traits_cpu * qfns_cpu) {
|
||||
int num_failed = 0;
|
||||
|
||||
const auto * vdot_traits = ggml_get_type_traits_cpu(qfns_cpu->vec_dot_type);
|
||||
const auto * vdot_qfns = ggml_get_type_traits(qfns_cpu->vec_dot_type);
|
||||
|
||||
if (qfns_cpu->vec_dot_type != GGML_TYPE_Q8_0) {
|
||||
printf("FAILED: vec_dot_type is %s, expected q8_0\n", ggml_type_name(qfns_cpu->vec_dot_type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int nblocks = 4;
|
||||
const int n = nblocks*QK_DT3;
|
||||
|
||||
for (int rep = 0; rep < 64; ++rep) {
|
||||
std::vector<int8_t> t1(n);
|
||||
std::vector<int8_t> t2(n);
|
||||
std::vector<float> d1(nblocks);
|
||||
std::vector<float> d2(nblocks);
|
||||
std::vector<uint8_t> xq(nblocks*DT3_BLOCK_SIZE);
|
||||
|
||||
for (int i = 0; i < nblocks; ++i) {
|
||||
for (int j = 0; j < QK_DT3; ++j) {
|
||||
t1[i*QK_DT3 + j] = rng_trit();
|
||||
t2[i*QK_DT3 + j] = rng_trit();
|
||||
}
|
||||
// fp16-exact scales of both signs
|
||||
d1[i] = (float)((int)(rng_next() % 9) - 4) * 0.25f;
|
||||
d2[i] = (float)((int)(rng_next() % 9) - 4) * 0.0625f;
|
||||
ref_pack_block(&t1[i*QK_DT3], d1[i], &t2[i*QK_DT3], d2[i], &xq[i*DT3_BLOCK_SIZE]);
|
||||
}
|
||||
|
||||
std::vector<float> y(n);
|
||||
for (int j = 0; j < n; ++j) {
|
||||
y[j] = 0.1f + 2.0f*cosf((float)(j + rep));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> yq(ggml_row_size(qfns_cpu->vec_dot_type, n));
|
||||
vdot_traits->from_float(y.data(), yq.data(), n);
|
||||
|
||||
// exact values the integer path sees
|
||||
std::vector<float> ydq(n);
|
||||
vdot_qfns->to_float(yq.data(), ydq.data(), n);
|
||||
|
||||
double ref = 0.0;
|
||||
for (int i = 0; i < nblocks; ++i) {
|
||||
for (int j = 0; j < QK_DT3; ++j) {
|
||||
const int ij = i*QK_DT3 + j;
|
||||
ref += (double)ydq[ij] * ((double)d1[i]*t1[ij] + (double)d2[i]*t2[ij]);
|
||||
}
|
||||
}
|
||||
|
||||
float result = INFINITY;
|
||||
qfns_cpu->vec_dot(n, &result, 0, xq.data(), 0, yq.data(), 0, 1);
|
||||
|
||||
const float err = fabsf(result - (float)ref);
|
||||
const float tol = 1e-4f * (float)n;
|
||||
if (!(err <= tol)) {
|
||||
printf("FAILED: vec_dot rep %d: got %f, expected %f (err %f)\n", rep, result, (float)ref, err);
|
||||
num_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_failed;
|
||||
}
|
||||
|
||||
// --dequant IN.bin OUT.f32 : dequantize raw DT3 blocks, for parity checks
|
||||
// against external packers (ternaria's Rust pack_dt3)
|
||||
static int run_dequant_file(const char * in_path, const char * out_path) {
|
||||
FILE * fin = fopen(in_path, "rb");
|
||||
if (!fin) {
|
||||
fprintf(stderr, "error: cannot open %s\n", in_path);
|
||||
return 1;
|
||||
}
|
||||
fseek(fin, 0, SEEK_END);
|
||||
const long size = ftell(fin);
|
||||
fseek(fin, 0, SEEK_SET);
|
||||
if (size <= 0 || size % DT3_BLOCK_SIZE != 0) {
|
||||
fprintf(stderr, "error: %s size %ld is not a multiple of %zu\n", in_path, size, DT3_BLOCK_SIZE);
|
||||
fclose(fin);
|
||||
return 1;
|
||||
}
|
||||
std::vector<uint8_t> data(size);
|
||||
if (fread(data.data(), 1, size, fin) != (size_t)size) {
|
||||
fprintf(stderr, "error: short read on %s\n", in_path);
|
||||
fclose(fin);
|
||||
return 1;
|
||||
}
|
||||
fclose(fin);
|
||||
|
||||
const int64_t nel = (int64_t)(size/DT3_BLOCK_SIZE)*QK_DT3;
|
||||
std::vector<float> out(nel);
|
||||
ggml_get_type_traits(GGML_TYPE_DT3)->to_float(data.data(), out.data(), nel);
|
||||
|
||||
FILE * fout = fopen(out_path, "wb");
|
||||
if (!fout) {
|
||||
fprintf(stderr, "error: cannot open %s\n", out_path);
|
||||
return 1;
|
||||
}
|
||||
fwrite(out.data(), sizeof(float), nel, fout);
|
||||
fclose(fout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (argc == 4 && strcmp(argv[1], "--dequant") == 0) {
|
||||
return run_dequant_file(argv[2], argv[3]);
|
||||
}
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "usage: %s [--dequant IN.bin OUT.f32]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ggml_cpu_init();
|
||||
|
||||
const auto * qfns = ggml_get_type_traits(GGML_TYPE_DT3);
|
||||
const auto * qfns_cpu = ggml_get_type_traits_cpu(GGML_TYPE_DT3);
|
||||
|
||||
int num_failed = 0;
|
||||
|
||||
num_failed += test_layout_constants();
|
||||
num_failed += test_single_trits(qfns);
|
||||
num_failed += test_byte_positions();
|
||||
num_failed += test_roundtrip(qfns);
|
||||
num_failed += test_quantize_pack_parity(qfns_cpu);
|
||||
num_failed += test_vec_dot(qfns_cpu);
|
||||
|
||||
printf("%d tests failed\n", num_failed);
|
||||
|
||||
return num_failed > 0;
|
||||
}
|
||||
@@ -158,6 +158,7 @@ static int test_vec_dot_q(bool verbose) {
|
||||
type == GGML_TYPE_Q1_0 ? MAX_QUANTIZATION_TOTAL_ERROR_BINARY :
|
||||
type == GGML_TYPE_TQ1_0 ? MAX_QUANTIZATION_TOTAL_ERROR_TERNARY :
|
||||
type == GGML_TYPE_TQ2_0 ? MAX_QUANTIZATION_TOTAL_ERROR_TERNARY :
|
||||
type == GGML_TYPE_DT3 ? MAX_QUANTIZATION_TOTAL_ERROR_TERNARY :
|
||||
type == GGML_TYPE_Q2_0 ? MAX_QUANTIZATION_TOTAL_ERROR_TERNARY :
|
||||
type == GGML_TYPE_Q2_K ? MAX_QUANTIZATION_TOTAL_ERROR_2BITS :
|
||||
type == GGML_TYPE_IQ2_S ? MAX_QUANTIZATION_TOTAL_ERROR_2BITS :
|
||||
@@ -184,7 +185,7 @@ static int test_vec_dot_q(bool verbose) {
|
||||
? MAX_DOT_PRODUCT_ERROR_LOWBIT
|
||||
: type == GGML_TYPE_Q1_0
|
||||
? MAX_DOT_PRODUCT_ERROR_BINARY
|
||||
: type == GGML_TYPE_TQ1_0 || type == GGML_TYPE_TQ2_0 || type == GGML_TYPE_Q2_0
|
||||
: type == GGML_TYPE_TQ1_0 || type == GGML_TYPE_TQ2_0 || type == GGML_TYPE_Q2_0 || type == GGML_TYPE_DT3
|
||||
? MAX_DOT_PRODUCT_ERROR_TERNARY
|
||||
: type == GGML_TYPE_NVFP4
|
||||
? MAX_DOT_PRODUCT_ERROR_FP4
|
||||
|
||||
@@ -47,6 +47,7 @@ static const std::vector<quant_option> QUANT_OPTIONS = {
|
||||
{ "IQ1_M", LLAMA_FTYPE_MOSTLY_IQ1_M, " 1.75 bpw quantization", },
|
||||
{ "TQ1_0", LLAMA_FTYPE_MOSTLY_TQ1_0, " 1.69 bpw ternarization", },
|
||||
{ "TQ2_0", LLAMA_FTYPE_MOSTLY_TQ2_0, " 2.06 bpw ternarization", },
|
||||
{ "DT3", LLAMA_FTYPE_MOSTLY_DT3, " 3.5 bpw dual-ternary (REF quantizer only - use ternaria's PTQTP for quality)", },
|
||||
{ "Q2_K", LLAMA_FTYPE_MOSTLY_Q2_K, " 2.96G, +3.5199 ppl @ Llama-3-8B", },
|
||||
{ "Q2_K_S", LLAMA_FTYPE_MOSTLY_Q2_K_S, " 2.96G, +3.1836 ppl @ Llama-3-8B", },
|
||||
{ "IQ3_XXS", LLAMA_FTYPE_MOSTLY_IQ3_XXS, " 3.06 bpw quantization", },
|
||||
|
||||
Reference in New Issue
Block a user