Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ggml/include/ggml.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,12 @@ 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,
// Prism-private ternary at group size 128, ported from PrismML-Eng/llama.cpp
// (Ternary-Bonsai GGUFs). High id so it slots above upstream types; type_traits
// is sized to COUNT with 43..142 unused. PQ2_0 (142) is deliberately not ported:
// it has no Vulkan kernels upstream of us either.
GGML_TYPE_PTQ1_0 = 143,
GGML_TYPE_COUNT = 144,
};

// [TAG_GGML_PREC]
Expand Down Expand Up @@ -486,6 +491,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_PTQ1_0 = 129, // except 1d tensors (Prism-private group-128 ternary)
};

// available tensor operations:
Expand Down
13 changes: 13 additions & 0 deletions ggml/src/ggml-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,19 @@ typedef struct {
} block_q2_0;
static_assert(sizeof(block_q2_0) == sizeof(ggml_half) + QK2_0 / 4, "wrong q2_0 block size/padding");

// PTQ1_0: Prism-private ternary at group size 128 (ported from PrismML-Eng/llama.cpp).
// Same base-3 trit packing as upstream TQ1_0 (type 34) but one fp16 scale per 128
// weights instead of per 256. 1.75 bpw, and lossless for checkpoints that are already
// ternary at group 128 -- TQ1_0 cannot represent those, because a 256-wide scale has
// to discard one of the two group scales it straddles.
#define QK_PTQ1_0 128
typedef struct {
uint8_t qs[(QK_PTQ1_0 - 4*QK_PTQ1_0/64)/5]; // 24 B, 5 trits per byte -> 120 values
uint8_t qh[QK_PTQ1_0/64]; // 2 B, 4 trits per byte -> 8 values
ggml_half d; // scale
} block_ptq1_0;
static_assert(sizeof(block_ptq1_0) == sizeof(ggml_half) + QK_PTQ1_0/64 + (QK_PTQ1_0 - 4*QK_PTQ1_0/64)/5, "wrong ptq1_0 block size/padding");

#define QK4_0 32
typedef struct {
ggml_half d; // delta
Expand Down
16 changes: 16 additions & 0 deletions ggml/src/ggml-cpu/arch-fallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// This effectively selects the generic implementation.

#if defined(GGML_CPU_GENERIC)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_q8_0
// quants.c
#define quantize_row_q8_0_generic quantize_row_q8_0
#define quantize_row_q8_1_generic quantize_row_q8_1
Expand Down Expand Up @@ -72,6 +74,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)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_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
Expand All @@ -82,6 +86,8 @@
#define ggml_gemm_mxfp4_8x8_q8_0_generic ggml_gemm_mxfp4_8x8_q8_0
#define ggml_gemm_q2_K_8x8_q8_K_generic ggml_gemm_q2_K_8x8_q8_K
#elif defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_q8_0
// quants.c
#define ggml_vec_dot_q2_0_q8_0_generic ggml_vec_dot_q2_0_q8_0
// repack.cpp
Expand Down Expand Up @@ -110,6 +116,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(__POWERPC__) || defined(__powerpc__)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_q8_0
// ref: https://github.com/ggml-org/llama.cpp/pull/14146#issuecomment-2972561679
// quants.c
#define quantize_row_q8_K_generic quantize_row_q8_K
Expand Down Expand Up @@ -157,6 +165,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(__loongarch64)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_q8_0
// quants.c
#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
Expand Down Expand Up @@ -204,6 +214,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(__riscv)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_q8_0
// 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
Expand Down Expand Up @@ -244,6 +256,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(__s390x__)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_q8_0
// quants.c
#define quantize_row_q8_K_generic quantize_row_q8_K
#define ggml_vec_dot_nvfp4_q8_0_generic ggml_vec_dot_nvfp4_q8_0
Expand Down Expand Up @@ -293,6 +307,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(__wasm__)
// PTQ1_0 has no arch-specific kernel on any target; always use the generic one.
#define ggml_vec_dot_ptq1_0_q8_0_generic ggml_vec_dot_ptq1_0_q8_0
// 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
Expand Down
6 changes: 6 additions & 0 deletions ggml/src/ggml-cpu/ggml-cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ static const struct ggml_type_traits_cpu type_traits_cpu[GGML_TYPE_COUNT] = {
.vec_dot_type = GGML_TYPE_Q8_0,
.nrows = 1,
},
[GGML_TYPE_PTQ1_0] = {
.from_float = quantize_row_ptq1_0,
.vec_dot = ggml_vec_dot_ptq1_0_q8_0,
.vec_dot_type = GGML_TYPE_Q8_0,
.nrows = 1,
},
[GGML_TYPE_Q4_0] = {
.from_float = quantize_row_q4_0,
.vec_dot = ggml_vec_dot_q4_0_q8_0,
Expand Down
7 changes: 7 additions & 0 deletions ggml/src/ggml-cpu/ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ void ggml_compute_forward_add(
} break;
case GGML_TYPE_Q1_0:
case GGML_TYPE_Q2_0:
case GGML_TYPE_PTQ1_0:
case GGML_TYPE_Q4_0:
case GGML_TYPE_Q4_1:
case GGML_TYPE_Q5_0:
Expand Down Expand Up @@ -1117,6 +1118,7 @@ void ggml_compute_forward_add1(
} break;
case GGML_TYPE_Q1_0:
case GGML_TYPE_Q2_0:
case GGML_TYPE_PTQ1_0:
case GGML_TYPE_Q4_0:
case GGML_TYPE_Q4_1:
case GGML_TYPE_Q5_0:
Expand Down Expand Up @@ -1248,6 +1250,7 @@ void ggml_compute_forward_acc(
case GGML_TYPE_BF16:
case GGML_TYPE_Q1_0:
case GGML_TYPE_Q2_0:
case GGML_TYPE_PTQ1_0:
case GGML_TYPE_Q4_0:
case GGML_TYPE_Q4_1:
case GGML_TYPE_Q5_0:
Expand Down Expand Up @@ -4651,6 +4654,7 @@ void ggml_compute_forward_out_prod(
switch (src0->type) {
case GGML_TYPE_Q1_0:
case GGML_TYPE_Q2_0:
case GGML_TYPE_PTQ1_0:
case GGML_TYPE_Q4_0:
case GGML_TYPE_Q4_1:
case GGML_TYPE_Q5_0:
Expand Down Expand Up @@ -4927,6 +4931,7 @@ void ggml_compute_forward_set(
case GGML_TYPE_BF16:
case GGML_TYPE_Q1_0:
case GGML_TYPE_Q2_0:
case GGML_TYPE_PTQ1_0:
case GGML_TYPE_Q4_0:
case GGML_TYPE_Q4_1:
case GGML_TYPE_Q5_0:
Expand Down Expand Up @@ -5152,6 +5157,7 @@ void ggml_compute_forward_get_rows(
switch (src0->type) {
case GGML_TYPE_Q1_0:
case GGML_TYPE_Q2_0:
case GGML_TYPE_PTQ1_0:
case GGML_TYPE_Q4_0:
case GGML_TYPE_Q4_1:
case GGML_TYPE_Q5_0:
Expand Down Expand Up @@ -5909,6 +5915,7 @@ void ggml_compute_forward_clamp(
case GGML_TYPE_BF16:
case GGML_TYPE_Q1_0:
case GGML_TYPE_Q2_0:
case GGML_TYPE_PTQ1_0:
case GGML_TYPE_Q4_0:
case GGML_TYPE_Q4_1:
case GGML_TYPE_Q5_0:
Expand Down
72 changes: 72 additions & 0 deletions ggml/src/ggml-cpu/quants.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ void quantize_row_q2_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, in
quantize_row_q2_0_ref(x, y, k);
}

void quantize_row_ptq1_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k) {
quantize_row_ptq1_0_ref(x, y, k);
}

void quantize_row_q4_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k) {
quantize_row_q4_0_ref(x, y, k);
}
Expand Down Expand Up @@ -1337,3 +1341,71 @@ void quantize_row_iq4_xs(const float * GGML_RESTRICT x, void * GGML_RESTRICT y,
assert(k % QK_K == 0);
quantize_iq4_xs(x, y, 1, k, NULL);
}

// PTQ1_0 x Q8_0. The trits are stored base-3 interleaved rather than in element
// order, so decode a block into element order first using the same traversal as
// dequantize_row_ptq1_0 -- that keeps the two provably in step. Four Q8_0 blocks
// cover one 128-wide PTQ1_0 block.
void ggml_vec_dot_ptq1_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) {
const int qk = QK_PTQ1_0;
const int nb = n / qk;

assert(n % qk == 0);
assert(nrc == 1);
UNUSED(nrc);
UNUSED(bx);
UNUSED(by);
UNUSED(bs);

const block_ptq1_0 * GGML_RESTRICT x = vx;
const block_q8_0 * GGML_RESTRICT y = vy;

static const uint8_t pow3[6] = {1, 3, 9, 27, 81, 243};
static const size_t stages[3] = {32, 16, 8};

float sumf = 0.0f;

for (int i = 0; i < nb; i++) {
int8_t q[QK_PTQ1_0];
int o = 0;

size_t j = 0;
for (size_t st = 0; st < 3; ++st) {
const size_t c = stages[st];
for (; j + c <= sizeof(x->qs); j += c) {
for (size_t nn = 0; nn < 5; ++nn) {
for (size_t m = 0; m < c; ++m) {
const uint8_t v = x[i].qs[j + m] * pow3[nn];
const int16_t xi = ((uint16_t) v * 3) >> 8;
q[o++] = (int8_t) (xi - 1);
}
}
}
}
for (size_t nn = 0; nn < 4; ++nn) {
for (size_t h = 0; h < sizeof(x->qh); ++h) {
const uint8_t v = x[i].qh[h] * pow3[nn];
const int16_t xi = ((uint16_t) v * 3) >> 8;
q[o++] = (int8_t) (xi - 1);
}
}
assert(o == QK_PTQ1_0);

const float d0 = GGML_CPU_FP16_TO_FP32(x[i].d);
float sumi = 0.0f;

for (int k = 0; k < 4; k++) {
const block_q8_0 * GGML_RESTRICT yb = &y[i * 4 + k];
const float d1 = GGML_CPU_FP16_TO_FP32(yb->d);
int sumi_block = 0;
for (int b = 0; b < 32; ++b) {
sumi_block += (int) q[k*32 + b] * (int) yb->qs[b];
}
sumi += d1 * sumi_block;
}

sumf += d0 * sumi;
}

*s = sumf;
}
3 changes: 3 additions & 0 deletions ggml/src/ggml-cpu/quants.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ void quantize_row_q6_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, in
void quantize_row_q8_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);

void quantize_row_tq1_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
void quantize_row_ptq1_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_iq4_nl (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
Expand All @@ -56,6 +57,7 @@ void ggml_vec_dot_q5_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const voi
void ggml_vec_dot_q6_K_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_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_ptq1_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);
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_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);
Expand Down Expand Up @@ -84,6 +86,7 @@ void ggml_vec_dot_mxfp4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs,
void ggml_vec_dot_nvfp4_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_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_ptq1_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);
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_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);
Expand Down
101 changes: 101 additions & 0 deletions ggml/src/ggml-quants.c
Original file line number Diff line number Diff line change
Expand Up @@ -2125,6 +2125,107 @@ size_t quantize_q2_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst,
return nrow * row_size;
}

// ====================== PTQ1_0 (Prism ternary, group 128) ======================
// Base-3 trit packing identical to upstream TQ1_0, but at block 128 so one fp16
// scale covers 128 weights. qs is 24 bytes, which TQ1_0's fixed 32-then-16 byte
// staging cannot cover, so the stages are generalised to 32/16/8; at TQ1_0's
// 48-byte qs this reduces to exactly its original 32-then-16 behaviour.
static const size_t ptq1_0_stages[3] = {32, 16, 8};

void quantize_row_ptq1_0_ref(const float * GGML_RESTRICT x, block_ptq1_0 * GGML_RESTRICT y, int64_t k) {
assert(k % QK_PTQ1_0 == 0);
const int64_t nb = k / QK_PTQ1_0;

for (int64_t i = 0; i < nb; i++) {
float amax = 0.0f;
for (int j = 0; j < QK_PTQ1_0; j++) {
amax = MAX(amax, fabsf(x[j]));
}

const float d = amax;
const float id = d ? 1.0f/d : 0.0f;

y[i].d = GGML_FP32_TO_FP16(d);

size_t j = 0;
for (size_t s = 0; s < 3; ++s) {
const size_t c = ptq1_0_stages[s];
for (; j + c <= sizeof(y->qs); j += c) {
for (size_t m = 0; m < c; ++m) {
uint8_t q = 0;
for (size_t n = 0; n < 5; ++n) {
int xi = lroundf(x[m + n*c] * id) + 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;
y[i].qs[j + m] = q;
}
x += 5*c;
}
}
// 4 elements per byte
for (size_t h = 0; h < sizeof(y->qh); ++h) {
uint8_t q = 0;
for (size_t m = 0; m < 4; ++m) {
int xi = lroundf(x[h + m*sizeof(y->qh)] * id) + 1;
q *= 3;
q += xi;
}
// shift the first value to the most significant trit
q *= 3;
q = ((uint16_t)q * 256 + (243 - 1)) / 243;
y[i].qh[h] = q;
}
x += 4*sizeof(y->qh);
}
}

void dequantize_row_ptq1_0(const block_ptq1_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k) {
assert(k % QK_PTQ1_0 == 0);
const int64_t nb = k / QK_PTQ1_0;

const uint8_t pow3[6] = {1, 3, 9, 27, 81, 243};

for (int64_t i = 0; i < nb; ++i) {
const float d = GGML_FP16_TO_FP32(x[i].d);

size_t j = 0;
for (size_t s = 0; s < 3; ++s) {
const size_t c = ptq1_0_stages[s];
for (; j + c <= sizeof(x->qs); j += c) {
for (size_t n = 0; n < 5; ++n) {
for (size_t m = 0; m < c; ++m) {
uint8_t q = x[i].qs[j + m] * pow3[n];
int16_t xi = ((uint16_t) q * 3) >> 8;
*y++ = (float) (xi - 1) * d;
}
}
}
}
for (size_t n = 0; n < 4; ++n) {
for (size_t h = 0; h < sizeof(x->qh); ++h) {
uint8_t q = x[i].qh[h] * pow3[n];
int16_t xi = ((uint16_t) q * 3) >> 8;
*y++ = (float) (xi - 1) * d;
}
}
}
}

size_t quantize_ptq1_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) {
(void)quant_weights; // ternary codes come from the weights themselves; an imatrix has no role
const size_t row_size = ggml_row_size(GGML_TYPE_PTQ1_0, n_per_row);
char * qrow = (char *)dst;
for (int64_t row = 0; row < nrow; ++row) {
quantize_row_ptq1_0_ref(src, (block_ptq1_0 *)qrow, n_per_row);
src += n_per_row;
qrow += row_size;
}
return nrow * row_size;
}

size_t quantize_q4_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) {
if (!quant_weights) {
quantize_row_q4_0_ref(src, dst, (int64_t)nrow*n_per_row);
Expand Down
Loading
Loading