q / forge /gguf-forge-iq-dequant.mjs
Humuhumu33's picture
Upload folder using huggingface_hub
3365e13 verified
Raw
History Blame Contribute Delete
11.6 kB
// IQ-quant dequantization, transcribed line-for-line from ggml-quants.c
// (llama.cpp b7248): dequantize_row_iq2_xxs:3077 iq2_xs:3105 iq2_s:3132
// iq3_xxs:3164 iq3_s:3196 iq1_s:3239 iq1_m:3264 iq4_nl:3314 iq4_xs:3332.
// Block layouts: ggml-common.h:485-563.
//
// ONE source of truth, two behaviours: makeIQ(fr, f16ToF32) binds the rounding
// function. The Tier-A oracle passes Math.fround (binary32-exact, witnessed
// bit-for-bit vs ggml to_float in gguf-forge-iq.test.mjs); the runtime passes
// identity (float64, fine for the GPU engine which re-quantizes anyway).
//
// Codebook grids are flattened little-endian byte runs (gguf-forge-iq-grids.mjs):
// an entry `idx` of stride S occupies bytes [idx*S .. idx*S+S). iq2*/iq3* read
// uint8, iq1s_grid / kvalues_iq4nl read int8.
import {
iq2xxs_grid, iq2xs_grid, iq2s_grid, iq3xxs_grid, iq3s_grid, iq1s_grid,
ksigns_iq2xs, kmask_iq2xs, kvalues_iq4nl,
} from "./gguf-forge-iq-grids.mjs";
const QK_K = 256;
const IQ1S_DELTA = 0.125, IQ1M_DELTA = 0.125;
const s8 = (b) => (b << 24) >> 24; // uint8 -> int8
export function makeIQ(fr, f16ToF32) {
const sign1 = (signs, j) => (signs & kmask_iq2xs[j] ? -1 : 1);
// dequantize_row_iq2_xxs (:3077). Block 66 B: d:f16 qs:uint16[32].
function dequantIQ2XXS(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 66, qs = bp + 2;
const d = f16ToF32(dv.getUint16(bp, true));
for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
const a0 = dv.getUint32(qs + 8 * ib32, true), a1 = dv.getUint32(qs + 8 * ib32 + 4, true);
const db = fr(fr(d * fr(0.5 + (a1 >>> 28))) * 0.25);
for (let l = 0; l < 4; ++l) {
const idx = (a0 >>> (8 * l)) & 0xff;
const signs = ksigns_iq2xs[(a1 >>> (7 * l)) & 127];
for (let j = 0; j < 8; ++j) out[o++] = sign1(signs, j) * fr(db * iq2xxs_grid[idx * 8 + j]);
}
}
}
return out;
}
// dequantize_row_iq2_xs (:3105). Block 74 B: d:f16 qs:uint16[32] scales:uint8[8].
function dequantIQ2XS(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 74, qs = bp + 2, scB = bp + 66;
const d = f16ToF32(dv.getUint16(bp, true));
for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
const db = [fr(fr(d * fr(0.5 + (raw[scB + ib32] & 0xf))) * 0.25),
fr(fr(d * fr(0.5 + (raw[scB + ib32] >> 4))) * 0.25)];
for (let l = 0; l < 4; ++l) {
const q = dv.getUint16(qs + (4 * ib32 + l) * 2, true);
const idx = q & 511, signs = ksigns_iq2xs[q >> 9], dl = db[l >> 1];
for (let j = 0; j < 8; ++j) out[o++] = sign1(signs, j) * fr(dl * iq2xs_grid[idx * 8 + j]);
}
}
}
return out;
}
// dequantize_row_iq2_s (:3132). Block 82 B: d:f16 qs:uint8[64] qh:uint8[8] scales:uint8[8].
// signs = qs + 32 (second half of qs); idx = qs[l] | ((qh[ib32]<<(8-2l)) & 0x300).
function dequantIQ2S(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 82, qhB = bp + 66, scB = bp + 74;
const d = f16ToF32(dv.getUint16(bp, true));
let qs = bp + 2, signs = bp + 2 + 32;
for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
const db = [fr(fr(d * fr(0.5 + (raw[scB + ib32] & 0xf))) * 0.25),
fr(fr(d * fr(0.5 + (raw[scB + ib32] >> 4))) * 0.25)];
for (let l = 0; l < 4; ++l) {
const dl = db[l >> 1];
const idx = raw[qs + l] | (((raw[qhB + ib32] << (8 - 2 * l)) & 0x300));
for (let j = 0; j < 8; ++j) out[o++] = sign1(raw[signs + l], j) * fr(dl * iq2s_grid[idx * 8 + j]);
}
qs += 4; signs += 4;
}
}
return out;
}
// dequantize_row_iq3_xxs (:3164). Block 98 B: d:f16 qs:uint8[96].
// qs[0..63]=grid idx; scales_and_signs = qs+64 (8 uint32). db scale uses *0.5.
function dequantIQ3XXS(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 98, ss = bp + 2 + 64;
const d = f16ToF32(dv.getUint16(bp, true));
let qs = bp + 2;
for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
const a32 = dv.getUint32(ss + 4 * ib32, true);
const db = fr(fr(d * fr(0.5 + (a32 >>> 28))) * 0.5);
for (let l = 0; l < 4; ++l) {
const signs = ksigns_iq2xs[(a32 >>> (7 * l)) & 127];
const g1 = raw[qs + 2 * l] * 4, g2 = raw[qs + 2 * l + 1] * 4;
for (let j = 0; j < 4; ++j) {
out[o + j + 0] = sign1(signs, j + 0) * fr(db * iq3xxs_grid[g1 + j]);
out[o + j + 4] = sign1(signs, j + 4) * fr(db * iq3xxs_grid[g2 + j]);
}
o += 8;
}
qs += 8;
}
}
return out;
}
// dequantize_row_iq3_s (:3196). Block 110 B: d:f16 qs:uint8[64] qh:uint8[8] signs:uint8[32] scales:uint8[4].
function dequantIQ3S(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 110, scB = bp + 106;
const d = f16ToF32(dv.getUint16(bp, true));
let qs = bp + 2, qh = bp + 66, signs = bp + 74;
for (let ib32 = 0; ib32 < QK_K / 32; ib32 += 2) {
const db1 = fr(d * (1 + 2 * (raw[scB + (ib32 >> 1)] & 0xf)));
const db2 = fr(d * (1 + 2 * (raw[scB + (ib32 >> 1)] >> 4)));
for (let l = 0; l < 4; ++l) {
const g1 = (raw[qs + 2 * l] | ((raw[qh] << (8 - 2 * l)) & 256)) * 4;
const g2 = (raw[qs + 2 * l + 1] | ((raw[qh] << (7 - 2 * l)) & 256)) * 4;
for (let j = 0; j < 4; ++j) {
out[o + j + 0] = sign1(raw[signs + l], j + 0) * fr(db1 * iq3s_grid[g1 + j]);
out[o + j + 4] = sign1(raw[signs + l], j + 4) * fr(db1 * iq3s_grid[g2 + j]);
}
o += 8;
}
qs += 8; signs += 4;
for (let l = 0; l < 4; ++l) {
const g1 = (raw[qs + 2 * l] | ((raw[qh + 1] << (8 - 2 * l)) & 256)) * 4;
const g2 = (raw[qs + 2 * l + 1] | ((raw[qh + 1] << (7 - 2 * l)) & 256)) * 4;
for (let j = 0; j < 4; ++j) {
out[o + j + 0] = sign1(raw[signs + l], j + 0) * fr(db2 * iq3s_grid[g1 + j]);
out[o + j + 4] = sign1(raw[signs + l], j + 4) * fr(db2 * iq3s_grid[g2 + j]);
}
o += 8;
}
qh += 2; qs += 8; signs += 4;
}
}
return out;
}
// dequantize_row_iq1_s (:3239). Block 50 B: d:f16 qs:uint8[32] qh:uint16[8]. grid int8.
function dequantIQ1S(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 50, qhB = bp + 34;
const d = f16ToF32(dv.getUint16(bp, true));
let qs = bp + 2;
for (let ib = 0; ib < QK_K / 32; ++ib) {
const qh = dv.getUint16(qhB + 2 * ib, true);
const dl = fr(d * (2 * ((qh >> 12) & 7) + 1));
const delta = (qh & 0x8000) ? -IQ1S_DELTA : IQ1S_DELTA;
for (let l = 0; l < 4; ++l) {
const g = (raw[qs + l] | (((qh >> (3 * l)) & 7) << 8)) * 8;
for (let j = 0; j < 8; ++j) out[o++] = fr(dl * fr(s8(iq1s_grid[g + j]) + delta));
}
qs += 4;
}
}
return out;
}
// dequantize_row_iq1_m (:3264). Block 56 B: qs:uint8[32] qh:uint8[16] scales:uint8[8].
// No d field — f16 scale is woven from the four scale uint16s. grid int8.
function dequantIQ1M(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
const delta = new Float32Array(4), idx = new Uint16Array(4);
for (let i = 0; i < nb; i++) {
const bp = i * 56, scB = bp + 48;
const sc = [dv.getUint16(scB, true), dv.getUint16(scB + 2, true), dv.getUint16(scB + 4, true), dv.getUint16(scB + 6, true)];
const u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000);
const d = f16ToF32(u16);
let qs = bp, qh = bp + 32;
for (let ib = 0; ib < QK_K / 32; ++ib) {
const dl1 = fr(d * (2 * ((sc[ib >> 1] >> (6 * (ib % 2) + 0)) & 0x7) + 1));
const dl2 = fr(d * (2 * ((sc[ib >> 1] >> (6 * (ib % 2) + 3)) & 0x7) + 1));
idx[0] = raw[qs + 0] | ((raw[qh + 0] << 8) & 0x700);
idx[1] = raw[qs + 1] | ((raw[qh + 0] << 4) & 0x700);
idx[2] = raw[qs + 2] | ((raw[qh + 1] << 8) & 0x700);
idx[3] = raw[qs + 3] | ((raw[qh + 1] << 4) & 0x700);
delta[0] = raw[qh + 0] & 0x08 ? -IQ1M_DELTA : IQ1M_DELTA;
delta[1] = raw[qh + 0] & 0x80 ? -IQ1M_DELTA : IQ1M_DELTA;
delta[2] = raw[qh + 1] & 0x08 ? -IQ1M_DELTA : IQ1M_DELTA;
delta[3] = raw[qh + 1] & 0x80 ? -IQ1M_DELTA : IQ1M_DELTA;
for (let l = 0; l < 2; ++l) {
const g = idx[l] * 8;
for (let j = 0; j < 8; ++j) out[o++] = fr(dl1 * fr(s8(iq1s_grid[g + j]) + delta[l]));
}
for (let l = 2; l < 4; ++l) {
const g = idx[l] * 8;
for (let j = 0; j < 8; ++j) out[o++] = fr(dl2 * fr(s8(iq1s_grid[g + j]) + delta[l]));
}
qs += 4; qh += 2;
}
}
return out;
}
// dequantize_row_iq4_nl (:3314). Block 18 B / 32 elems: d:f16 qs:uint8[16]. kvalues int8.
function dequantIQ4NL(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / 32; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 18, qs = bp + 2;
const d = f16ToF32(dv.getUint16(bp, true));
for (let j = 0; j < 16; ++j) {
out[o + j] = fr(d * s8(kvalues_iq4nl[raw[qs + j] & 0xf]));
out[o + 16 + j] = fr(d * s8(kvalues_iq4nl[raw[qs + j] >> 4]));
}
o += 32;
}
return out;
}
// dequantize_row_iq4_xs (:3332). Block 136 B: d:f16 scales_h:uint16 scales_l:uint8[4] qs:uint8[128].
function dequantIQ4XS(raw, elements) {
const out = new Float32Array(elements);
const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
const nb = elements / QK_K; let o = 0;
for (let i = 0; i < nb; i++) {
const bp = i * 136, slB = bp + 4;
const d = f16ToF32(dv.getUint16(bp, true));
const sh = dv.getUint16(bp + 2, true);
let qs = bp + 8;
for (let ib = 0; ib < QK_K / 32; ++ib) {
const ls = ((raw[slB + (ib >> 1)] >> (4 * (ib % 2))) & 0xf) | (((sh >> (2 * ib)) & 3) << 4);
const dl = fr(d * (ls - 32));
for (let j = 0; j < 16; ++j) {
out[o + j] = fr(dl * s8(kvalues_iq4nl[raw[qs + j] & 0xf]));
out[o + 16 + j] = fr(dl * s8(kvalues_iq4nl[raw[qs + j] >> 4]));
}
o += 32; qs += 16;
}
}
return out;
}
return { dequantIQ2XXS, dequantIQ2XS, dequantIQ2S, dequantIQ3XXS, dequantIQ3S, dequantIQ1S, dequantIQ1M, dequantIQ4NL, dequantIQ4XS };
}