--iq2auto
Browse files- hexstate_quantize.c +253 -53
- hexstate_requantize.py +41 -2
hexstate_quantize.c
CHANGED
|
@@ -1793,21 +1793,130 @@ void hexstate_set_spectral_params(float dc_lambda, float vw_lambda, float dc_dec
|
|
| 1793 |
g_hex_dc_decay = dc_decay;
|
| 1794 |
}
|
| 1795 |
|
| 1796 |
-
/*
|
| 1797 |
-
*
|
| 1798 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1799 |
static inline float hex_spectral_penalty_ex(const float *e, int n, float dc_carry)
|
| 1800 |
{
|
| 1801 |
if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f) return 0.0f;
|
| 1802 |
-
float
|
| 1803 |
-
|
| 1804 |
-
|
| 1805 |
-
|
| 1806 |
-
dc += v;
|
| 1807 |
-
ves += v * v;
|
| 1808 |
-
}
|
| 1809 |
-
return (HEX_DC_LAMBDA / (float)n) * dc * dc
|
| 1810 |
-
+ (HEX_VW_LAMBDA / (float)n) * ves;
|
| 1811 |
}
|
| 1812 |
|
| 1813 |
static inline float hex_spectral_penalty(const float *e, int n)
|
|
@@ -3851,7 +3960,7 @@ static void quantize_tensor_q2k_hpc(const float *weights, int64_t n_elements,
|
|
| 3851 |
dc_res += x - deq;
|
| 3852 |
}
|
| 3853 |
}
|
| 3854 |
-
rolling_dc = dc_res;
|
| 3855 |
}
|
| 3856 |
}
|
| 3857 |
|
|
@@ -4946,7 +5055,9 @@ static void quantize_tensor_q2k_hpc(const float *weights, int64_t n_elements,
|
|
| 4946 |
float dc_res = 0.0f;
|
| 4947 |
for (int i = 0; i < QK_K; i++)
|
| 4948 |
dc_res += bx[i] - deq[i];
|
| 4949 |
-
|
|
|
|
|
|
|
| 4950 |
}
|
| 4951 |
total_err = 0.0f;
|
| 4952 |
for (int64_t blk = 0; blk < n_blocks; blk++)
|
|
@@ -5767,38 +5878,111 @@ static float iq2xs_block_at_d(const IQ2Book *bk, const float *x, const float *w,
|
|
| 5767 |
return e;
|
| 5768 |
}
|
| 5769 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5770 |
/* Greedy re-selection among top-K codewords per group on
|
| 5771 |
-
* SSE +
|
| 5772 |
-
* with a block SSE cap. This is the fold-through-codebook step.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5773 |
static void iq2xs_shape_block(const IQ2Book *bk, const float *x, const float *w, float d,
|
| 5774 |
const uint8_t ls[IQ2XS_NSUB],
|
| 5775 |
-
uint32_t code[IQ2XS_NGROUP], float
|
|
|
|
| 5776 |
{
|
| 5777 |
-
if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f) return;
|
|
|
|
| 5778 |
|
| 5779 |
IQ2Cand cands[IQ2XS_NGROUP][IQ2XS_TOPK];
|
| 5780 |
int ncand[IQ2XS_NGROUP], cur[IQ2XS_NGROUP];
|
| 5781 |
-
float e[QK_K];
|
| 5782 |
-
float sse = 0.0f
|
| 5783 |
|
| 5784 |
for (int g = 0; g < IQ2XS_NGROUP; g++) {
|
| 5785 |
float db = iq2xs_sub_db(d, ls[g >> 1]);
|
| 5786 |
if (db <= 0.0f) { ncand[g] = 0; cur[g] = -1;
|
| 5787 |
-
for (int j = 0; j < 8; j++) { e[8*g+j] = x[8*g+j]; sse += w[8*g+j]*x[8*g+j]*x[8*g+j];
|
| 5788 |
continue; }
|
| 5789 |
ncand[g] = iq2xs_group_candidates(bk, x + 8*g, w + 8*g, db, IQ2XS_TOPK, cands[g]);
|
| 5790 |
cur[g] = 0;
|
| 5791 |
for (int c = 0; c < ncand[g]; c++)
|
| 5792 |
if (cands[g][c].code == code[g]) { cur[g] = c; break; }
|
| 5793 |
const IQ2Cand *cc = &cands[g][cur[g]];
|
| 5794 |
-
for (int j = 0; j < 8; j++)
|
| 5795 |
sse += cc->sse;
|
| 5796 |
}
|
| 5797 |
const float cap = sse * (1.0f + HEX_DC_SSE_BUDGET);
|
| 5798 |
-
|
| 5799 |
-
|
| 5800 |
-
|
| 5801 |
-
float
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5802 |
|
| 5803 |
for (int pass = 0; pass < 96; pass++) {
|
| 5804 |
int best_g = -1, best_c = 0; float best_m = metric;
|
|
@@ -5810,31 +5994,31 @@ static void iq2xs_shape_block(const IQ2Book *bk, const float *x, const float *w,
|
|
| 5810 |
const IQ2Cand *cn = &cands[g][c];
|
| 5811 |
float sse2 = sse - co->sse + cn->sse;
|
| 5812 |
if (sse2 > cap) continue;
|
| 5813 |
-
float
|
| 5814 |
-
for (int j = 0; j < 8; j++)
|
| 5815 |
-
|
| 5816 |
-
|
| 5817 |
-
dc2 += de;
|
| 5818 |
-
int p = (i < QK_K/2) ? i : i - QK_K/2;
|
| 5819 |
-
float vn = v[p] + de;
|
| 5820 |
-
ves2 += vn * vn - v[p] * v[p];
|
| 5821 |
-
}
|
| 5822 |
-
float m2 = sse2 + ldc * dc2 * dc2 + lvw * ves2;
|
| 5823 |
if (m2 < best_m) { best_m = m2; best_g = g; best_c = c; }
|
| 5824 |
}
|
| 5825 |
}
|
| 5826 |
if (best_g < 0) break;
|
| 5827 |
const IQ2Cand *co = &cands[best_g][cur[best_g]];
|
| 5828 |
const IQ2Cand *cn = &cands[best_g][best_c];
|
| 5829 |
-
|
| 5830 |
-
for (int j = 0; j < 8; j++)
|
| 5831 |
-
|
| 5832 |
-
|
| 5833 |
-
|
| 5834 |
-
|
| 5835 |
-
|
| 5836 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5837 |
}
|
|
|
|
|
|
|
| 5838 |
cur[best_g] = best_c;
|
| 5839 |
code[best_g] = cn->code;
|
| 5840 |
metric = best_m;
|
|
@@ -5990,7 +6174,7 @@ static void quantize_tensor_iq2_hpc(const IQ2Book *bk,
|
|
| 5990 |
|
| 5991 |
/* 4. fold/DC shaping among near-equivalent codewords (carry = 0 here;
|
| 5992 |
* the sequential pass below applies the true residual carry). */
|
| 5993 |
-
iq2xs_shape_block(bk, x, w, best_d, ls, code,
|
| 5994 |
|
| 5995 |
float d_out = best_d;
|
| 5996 |
if (inflate != 0.0f)
|
|
@@ -5998,15 +6182,24 @@ static void quantize_tensor_iq2_hpc(const IQ2Book *bk,
|
|
| 5998 |
iq2_pack(bk, output + blk * BB, d_out, ls, code);
|
| 5999 |
}
|
| 6000 |
|
| 6001 |
-
/* 5. sequential TRUE residual carry along each row
|
| 6002 |
-
|
|
|
|
|
|
|
|
|
|
| 6003 |
int64_t bpr = (row_width > 0 && row_width % QK_K == 0) ? row_width / QK_K : 0;
|
| 6004 |
-
float
|
|
|
|
| 6005 |
uint8_t ls[IQ2XS_NSUB]; uint32_t code[IQ2XS_NGROUP];
|
|
|
|
|
|
|
| 6006 |
for (int64_t blk = 0; blk < n_blocks; blk++) {
|
| 6007 |
-
if (bpr > 0 && (blk % bpr) == 0)
|
| 6008 |
const float *x = weights + blk * QK_K;
|
| 6009 |
uint8_t *b = output + blk * BB;
|
|
|
|
|
|
|
|
|
|
| 6010 |
float d = iq2_unpack(bk, b, ls, code);
|
| 6011 |
if (d > 0.0f) {
|
| 6012 |
float sigma2 = 0.0f;
|
|
@@ -6016,13 +6209,20 @@ static void quantize_tensor_iq2_hpc(const IQ2Book *bk,
|
|
| 6016 |
float base = imat_importance ? imat_importance[blk * QK_K + i] : 1.0f;
|
| 6017 |
w[i] = (wmode == 1) ? base * sqrtf(sigma2 + x[i] * x[i]) : base;
|
| 6018 |
}
|
| 6019 |
-
iq2xs_shape_block(bk, x, w, d, ls, code,
|
| 6020 |
iq2_pack(bk, b, d, ls, code);
|
| 6021 |
}
|
| 6022 |
iq2_dequant_block(bk, b, deq);
|
| 6023 |
-
|
| 6024 |
-
|
| 6025 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6026 |
}
|
| 6027 |
}
|
| 6028 |
|
|
|
|
| 1793 |
g_hex_dc_decay = dc_decay;
|
| 1794 |
}
|
| 1795 |
|
| 1796 |
+
/* ── Fold pyramid ─────────────────────────────────────────────────────────
|
| 1797 |
+
* Vesica is the block folded in half once; DC is the block folded in half
|
| 1798 |
+
* log2(n) times. The levels between are the rest of the same tree:
|
| 1799 |
+
*
|
| 1800 |
+
* v¹[p] = e[p] + e[p+n/2] n/2 nodes (vesica)
|
| 1801 |
+
* vᵏ[p] = vᵏ⁻¹[p] + vᵏ⁻¹[p+n/2ᵏ] n/2ᵏ nodes
|
| 1802 |
+
* vᴸ = Σ e 1 node (DC), L = log2 n
|
| 1803 |
+
*
|
| 1804 |
+
* ‖vᵏ‖² is 2ᵏ× the error energy in the subspace of n/2ᵏ-periodic patterns
|
| 1805 |
+
* (Walsh functions on the low 8−k index bits), so penalising level k drives
|
| 1806 |
+
* the error orthogonal to activations with that period. Level weights are
|
| 1807 |
+
* geometric, λ_k = λ_vw·γᵏ⁻¹/n for k ≤ depth (depth=1 ⇒ the classic single
|
| 1808 |
+
* fold), and the top level keeps λ_dc/n so DC behaviour is unchanged.
|
| 1809 |
+
*
|
| 1810 |
+
* Measured (SmolLM2 ffn_down splice, IQ2_S, λ=(16,1), budget 2e-2): depth 7
|
| 1811 |
+
* γ=2 pulls the level-5..7 row-lane residuals from 0.9 → 0.1–0.4 of white
|
| 1812 |
+
* but costs +2.7% RMSE / +1.7% wRMSE and leaves PPL inside noise. Only DC
|
| 1813 |
+
* is invariant to the (arbitrary) neuron ordering, so the other periodic
|
| 1814 |
+
* lanes have nothing in the activations to cancel against. Default depth is
|
| 1815 |
+
* therefore 1; the tree stays available via hexstate_set_fold_params.
|
| 1816 |
+
*
|
| 1817 |
+
* Pyramid layout: T[0..n/2) level 1, then n/4 level 2, …, T[n-2] = DC.
|
| 1818 |
+
* A carry pyramid C (same layout) holds the decayed cumulative residual per
|
| 1819 |
+
* lane along the row; the penalty is Σ_k λ_k Σ_p (Tᵏ[p] + Cᵏ[p])². */
|
| 1820 |
+
#define HEX_FOLD_LEVELS 8 /* log2(QK_K) */
|
| 1821 |
+
static int g_hex_fold_depth = 1; /* vesica levels 1..depth (7 = every level below DC) */
|
| 1822 |
+
static float g_hex_fold_gamma = 2.0f; /* per-level geometric weight */
|
| 1823 |
+
static int g_hex_carry_cumulative = 1;/* 1: S ← decay·S + Σe (row residual = last miss);
|
| 1824 |
+
0: legacy, carry only the previous block's Σe */
|
| 1825 |
+
|
| 1826 |
+
void hexstate_set_fold_params(int depth, float gamma, int carry_cumulative)
|
| 1827 |
+
{
|
| 1828 |
+
if (depth >= 0 && depth <= HEX_FOLD_LEVELS - 1) g_hex_fold_depth = depth;
|
| 1829 |
+
if (gamma > 0.0f) g_hex_fold_gamma = gamma;
|
| 1830 |
+
if (carry_cumulative >= 0) g_hex_carry_cumulative = carry_cumulative ? 1 : 0;
|
| 1831 |
+
}
|
| 1832 |
+
|
| 1833 |
+
/* ── Activation lanes ─────────────────────────────────────────────────────
|
| 1834 |
+
* The fold tree is a fixed family of index patterns; DC (the root) is the
|
| 1835 |
+
* only member invariant to the arbitrary neuron order, and measured on the
|
| 1836 |
+
* ffn_down input it carries ~0.1% of E[‖a‖²]. What the output error
|
| 1837 |
+
* eᵀE[aaᵀ]e actually lives in is the top eigen-directions u_k of E[aaᵀ]
|
| 1838 |
+
* (25–80% of the trace in the top 16). So the row lanes are generalised to
|
| 1839 |
+
* arbitrary directions: penalty Σ_k λ·ev_k (u_k·e_row + carry_k)², with the
|
| 1840 |
+
* same cumulative carry along the row. ev_k are in E[a²] units, the same as
|
| 1841 |
+
* the imatrix weights on SSE, so λ=1 is the rank-r correction of the
|
| 1842 |
+
* diagonal (imatrix) objective toward the true output error. Nothing is
|
| 1843 |
+
* needed at inference: only the codeword choice changes. */
|
| 1844 |
+
#define HEX_MAX_LANES 64
|
| 1845 |
+
static const float *g_lane_U = NULL; /* r × cols, row-major */
|
| 1846 |
+
static const float *g_lane_ev = NULL; /* r */
|
| 1847 |
+
static int g_lane_r = 0;
|
| 1848 |
+
static int64_t g_lane_cols = 0;
|
| 1849 |
+
static float g_lane_lambda = 1.0f;
|
| 1850 |
+
|
| 1851 |
+
void hexstate_set_activation_lanes(const float *U, const float *ev, int r, int64_t cols, float lambda)
|
| 1852 |
+
{
|
| 1853 |
+
if (!U || !ev || r <= 0 || cols <= 0) { g_lane_U = NULL; g_lane_ev = NULL; g_lane_r = 0; g_lane_cols = 0; return; }
|
| 1854 |
+
g_lane_U = U; g_lane_ev = ev; g_lane_r = r > HEX_MAX_LANES ? HEX_MAX_LANES : r;
|
| 1855 |
+
g_lane_cols = cols; g_lane_lambda = lambda > 0.0f ? lambda : 1.0f;
|
| 1856 |
+
}
|
| 1857 |
+
|
| 1858 |
+
typedef struct {
|
| 1859 |
+
const float *U; /* lane k slice for this block: U + k*stride + i */
|
| 1860 |
+
int64_t stride;
|
| 1861 |
+
const float *ev;
|
| 1862 |
+
int r;
|
| 1863 |
+
const float *carry; /* r decayed cumulative lane residuals */
|
| 1864 |
+
float lambda;
|
| 1865 |
+
} IQ2LaneCtx;
|
| 1866 |
+
|
| 1867 |
+
/* Level weights for a block of n = 2^L. wk[k-1] for k = 1..L. */
|
| 1868 |
+
static inline void hex_fold_weights(int n, float *wk)
|
| 1869 |
+
{
|
| 1870 |
+
int L = 0; while ((1 << L) < n) L++;
|
| 1871 |
+
float g = 1.0f;
|
| 1872 |
+
for (int k = 1; k <= L; k++) {
|
| 1873 |
+
if (k == L) wk[k-1] = HEX_DC_LAMBDA / (float)n;
|
| 1874 |
+
else if (k <= g_hex_fold_depth) wk[k-1] = (HEX_VW_LAMBDA / (float)n) * g;
|
| 1875 |
+
else wk[k-1] = 0.0f;
|
| 1876 |
+
g *= g_hex_fold_gamma;
|
| 1877 |
+
}
|
| 1878 |
+
}
|
| 1879 |
+
|
| 1880 |
+
/* Build the pyramid (n-1 floats) from leaves e[n]. */
|
| 1881 |
+
static inline void hex_fold_build(const float *e, int n, float *T)
|
| 1882 |
+
{
|
| 1883 |
+
const float *src = e; float *dst = T;
|
| 1884 |
+
for (int m = n / 2; m >= 1; m >>= 1) {
|
| 1885 |
+
for (int p = 0; p < m; p++) dst[p] = src[p] + src[p + m];
|
| 1886 |
+
src = dst; dst += m;
|
| 1887 |
+
}
|
| 1888 |
+
}
|
| 1889 |
+
|
| 1890 |
+
/* Σ_k λ_k Σ_p (Tᵏ[p] + Cᵏ[p])²; C may be NULL (no carry). */
|
| 1891 |
+
static inline float hex_fold_energy(const float *T, const float *C, int n)
|
| 1892 |
+
{
|
| 1893 |
+
float wk[HEX_FOLD_LEVELS];
|
| 1894 |
+
hex_fold_weights(n, wk);
|
| 1895 |
+
float acc = 0.0f; int off = 0, k = 0;
|
| 1896 |
+
for (int m = n / 2; m >= 1; m >>= 1, k++) {
|
| 1897 |
+
if (wk[k] != 0.0f) {
|
| 1898 |
+
float s = 0.0f;
|
| 1899 |
+
for (int p = 0; p < m; p++) {
|
| 1900 |
+
float v = T[off + p] + (C ? C[off + p] : 0.0f);
|
| 1901 |
+
s += v * v;
|
| 1902 |
+
}
|
| 1903 |
+
acc += wk[k] * s;
|
| 1904 |
+
}
|
| 1905 |
+
off += m;
|
| 1906 |
+
}
|
| 1907 |
+
return acc;
|
| 1908 |
+
}
|
| 1909 |
+
|
| 1910 |
+
/* Spectral penalty with a scalar DC carry (Q2_K acceptance stages):
|
| 1911 |
+
* Σ_k λ_k‖vᵏ‖² with (vᴸ + dc_carry)² at the top. Reconstruction target is
|
| 1912 |
+
* always the true weight; we never quantize x−bias. */
|
| 1913 |
static inline float hex_spectral_penalty_ex(const float *e, int n, float dc_carry)
|
| 1914 |
{
|
| 1915 |
if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f) return 0.0f;
|
| 1916 |
+
float T[QK_K];
|
| 1917 |
+
hex_fold_build(e, n, T);
|
| 1918 |
+
T[n - 2] += dc_carry;
|
| 1919 |
+
return hex_fold_energy(T, NULL, n);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1920 |
}
|
| 1921 |
|
| 1922 |
static inline float hex_spectral_penalty(const float *e, int n)
|
|
|
|
| 3960 |
dc_res += x - deq;
|
| 3961 |
}
|
| 3962 |
}
|
| 3963 |
+
rolling_dc = g_hex_carry_cumulative ? block_dc_carry[blk] + dc_res : dc_res;
|
| 3964 |
}
|
| 3965 |
}
|
| 3966 |
|
|
|
|
| 5055 |
float dc_res = 0.0f;
|
| 5056 |
for (int i = 0; i < QK_K; i++)
|
| 5057 |
dc_res += bx[i] - deq[i];
|
| 5058 |
+
/* cumulative: S ← decay·S + Σe, so the metric (Σe + carry)² is
|
| 5059 |
+
* S² and the row residual after each block is just its miss. */
|
| 5060 |
+
rolling_dc = g_hex_carry_cumulative ? carry + dc_res : dc_res;
|
| 5061 |
}
|
| 5062 |
total_err = 0.0f;
|
| 5063 |
for (int64_t blk = 0; blk < n_blocks; blk++)
|
|
|
|
| 5878 |
return e;
|
| 5879 |
}
|
| 5880 |
|
| 5881 |
+
/* Change in fold energy if the 8 leaves of group g move by de[8].
|
| 5882 |
+
* Leaf i lives at node (i & (m-1)) of the level with m nodes; the 8
|
| 5883 |
+
* contiguous leaves of a group hit 8 distinct nodes while m ≥ 8 and fold
|
| 5884 |
+
* onto all m nodes below that. O(8·log n) per evaluation. */
|
| 5885 |
+
static inline float iq2_fold_delta(const float *T, const float *C, const float *wk,
|
| 5886 |
+
int g, const float de[8])
|
| 5887 |
+
{
|
| 5888 |
+
float acc = 0.0f; int off = 0, k = 0;
|
| 5889 |
+
for (int m = QK_K / 2; m >= 1; m >>= 1, k++) {
|
| 5890 |
+
if (wk[k] != 0.0f) {
|
| 5891 |
+
if (m >= 8) {
|
| 5892 |
+
int base = (8 * g) & (m - 1);
|
| 5893 |
+
for (int j = 0; j < 8; j++) {
|
| 5894 |
+
int q = off + base + j;
|
| 5895 |
+
float t = T[q] + (C ? C[q] : 0.0f);
|
| 5896 |
+
acc += wk[k] * de[j] * (2.0f * t + de[j]);
|
| 5897 |
+
}
|
| 5898 |
+
} else {
|
| 5899 |
+
float dn[8] = {0};
|
| 5900 |
+
for (int j = 0; j < 8; j++) dn[j & (m - 1)] += de[j];
|
| 5901 |
+
for (int p = 0; p < m; p++) {
|
| 5902 |
+
int q = off + p;
|
| 5903 |
+
float t = T[q] + (C ? C[q] : 0.0f);
|
| 5904 |
+
acc += wk[k] * dn[p] * (2.0f * t + dn[p]);
|
| 5905 |
+
}
|
| 5906 |
+
}
|
| 5907 |
+
}
|
| 5908 |
+
off += m;
|
| 5909 |
+
}
|
| 5910 |
+
return acc;
|
| 5911 |
+
}
|
| 5912 |
+
|
| 5913 |
+
static inline void iq2_fold_apply(float *T, int g, const float de[8])
|
| 5914 |
+
{
|
| 5915 |
+
int off = 0;
|
| 5916 |
+
for (int m = QK_K / 2; m >= 1; m >>= 1) {
|
| 5917 |
+
if (m >= 8) {
|
| 5918 |
+
int base = (8 * g) & (m - 1);
|
| 5919 |
+
for (int j = 0; j < 8; j++) T[off + base + j] += de[j];
|
| 5920 |
+
} else {
|
| 5921 |
+
for (int j = 0; j < 8; j++) T[off + (j & (m - 1))] += de[j];
|
| 5922 |
+
}
|
| 5923 |
+
off += m;
|
| 5924 |
+
}
|
| 5925 |
+
}
|
| 5926 |
+
|
| 5927 |
/* Greedy re-selection among top-K codewords per group on
|
| 5928 |
+
* SSE + Σ_k λ_k Σ_p (vᵏ[p] + carryᵏ[p])² (fold pyramid, DC at the top)
|
| 5929 |
+
* with a block SSE cap. This is the fold-through-codebook step. carry is a
|
| 5930 |
+
* pyramid (QK_K-1 floats) of decayed cumulative lane residuals, or NULL. */
|
| 5931 |
+
static inline float iq2_lane_delta(const IQ2LaneCtx *lc, const float *Lv, int g, const float de[8])
|
| 5932 |
+
{
|
| 5933 |
+
float acc = 0.0f;
|
| 5934 |
+
for (int k = 0; k < lc->r; k++) {
|
| 5935 |
+
const float *u = lc->U + (int64_t)k * lc->stride + 8 * g;
|
| 5936 |
+
float dL = 0.0f;
|
| 5937 |
+
for (int j = 0; j < 8; j++) dL += u[j] * de[j];
|
| 5938 |
+
float t = Lv[k] + (lc->carry ? lc->carry[k] : 0.0f);
|
| 5939 |
+
acc += lc->lambda * lc->ev[k] * dL * (2.0f * t + dL);
|
| 5940 |
+
}
|
| 5941 |
+
return acc;
|
| 5942 |
+
}
|
| 5943 |
+
|
| 5944 |
static void iq2xs_shape_block(const IQ2Book *bk, const float *x, const float *w, float d,
|
| 5945 |
const uint8_t ls[IQ2XS_NSUB],
|
| 5946 |
+
uint32_t code[IQ2XS_NGROUP], const float *carry,
|
| 5947 |
+
const IQ2LaneCtx *lc)
|
| 5948 |
{
|
| 5949 |
+
if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f && !(lc && lc->r > 0)) return;
|
| 5950 |
+
if (lc && lc->r <= 0) lc = NULL;
|
| 5951 |
|
| 5952 |
IQ2Cand cands[IQ2XS_NGROUP][IQ2XS_TOPK];
|
| 5953 |
int ncand[IQ2XS_NGROUP], cur[IQ2XS_NGROUP];
|
| 5954 |
+
float e[QK_K], T[QK_K], wk[HEX_FOLD_LEVELS], Lv[HEX_MAX_LANES];
|
| 5955 |
+
float sse = 0.0f;
|
| 5956 |
|
| 5957 |
for (int g = 0; g < IQ2XS_NGROUP; g++) {
|
| 5958 |
float db = iq2xs_sub_db(d, ls[g >> 1]);
|
| 5959 |
if (db <= 0.0f) { ncand[g] = 0; cur[g] = -1;
|
| 5960 |
+
for (int j = 0; j < 8; j++) { e[8*g+j] = x[8*g+j]; sse += w[8*g+j]*x[8*g+j]*x[8*g+j]; }
|
| 5961 |
continue; }
|
| 5962 |
ncand[g] = iq2xs_group_candidates(bk, x + 8*g, w + 8*g, db, IQ2XS_TOPK, cands[g]);
|
| 5963 |
cur[g] = 0;
|
| 5964 |
for (int c = 0; c < ncand[g]; c++)
|
| 5965 |
if (cands[g][c].code == code[g]) { cur[g] = c; break; }
|
| 5966 |
const IQ2Cand *cc = &cands[g][cur[g]];
|
| 5967 |
+
for (int j = 0; j < 8; j++) e[8*g+j] = x[8*g+j] - cc->deq[j];
|
| 5968 |
sse += cc->sse;
|
| 5969 |
}
|
| 5970 |
const float cap = sse * (1.0f + HEX_DC_SSE_BUDGET);
|
| 5971 |
+
hex_fold_weights(QK_K, wk);
|
| 5972 |
+
hex_fold_build(e, QK_K, T);
|
| 5973 |
+
float fold = hex_fold_energy(T, carry, QK_K);
|
| 5974 |
+
float lane = 0.0f;
|
| 5975 |
+
if (lc) {
|
| 5976 |
+
for (int k = 0; k < lc->r; k++) {
|
| 5977 |
+
const float *u = lc->U + (int64_t)k * lc->stride;
|
| 5978 |
+
float s = 0.0f;
|
| 5979 |
+
for (int i = 0; i < QK_K; i++) s += u[i] * e[i];
|
| 5980 |
+
Lv[k] = s;
|
| 5981 |
+
float t = s + (lc->carry ? lc->carry[k] : 0.0f);
|
| 5982 |
+
lane += lc->lambda * lc->ev[k] * t * t;
|
| 5983 |
+
}
|
| 5984 |
+
}
|
| 5985 |
+
float metric = sse + fold + lane;
|
| 5986 |
|
| 5987 |
for (int pass = 0; pass < 96; pass++) {
|
| 5988 |
int best_g = -1, best_c = 0; float best_m = metric;
|
|
|
|
| 5994 |
const IQ2Cand *cn = &cands[g][c];
|
| 5995 |
float sse2 = sse - co->sse + cn->sse;
|
| 5996 |
if (sse2 > cap) continue;
|
| 5997 |
+
float de[8];
|
| 5998 |
+
for (int j = 0; j < 8; j++) de[j] = co->deq[j] - cn->deq[j]; /* e_new − e_old */
|
| 5999 |
+
float m2 = sse2 + fold + iq2_fold_delta(T, carry, wk, g, de)
|
| 6000 |
+
+ lane + (lc ? iq2_lane_delta(lc, Lv, g, de) : 0.0f);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6001 |
if (m2 < best_m) { best_m = m2; best_g = g; best_c = c; }
|
| 6002 |
}
|
| 6003 |
}
|
| 6004 |
if (best_g < 0) break;
|
| 6005 |
const IQ2Cand *co = &cands[best_g][cur[best_g]];
|
| 6006 |
const IQ2Cand *cn = &cands[best_g][best_c];
|
| 6007 |
+
float de[8];
|
| 6008 |
+
for (int j = 0; j < 8; j++) de[j] = co->deq[j] - cn->deq[j];
|
| 6009 |
+
fold += iq2_fold_delta(T, carry, wk, best_g, de);
|
| 6010 |
+
iq2_fold_apply(T, best_g, de);
|
| 6011 |
+
if (lc) {
|
| 6012 |
+
lane += iq2_lane_delta(lc, Lv, best_g, de);
|
| 6013 |
+
for (int k = 0; k < lc->r; k++) {
|
| 6014 |
+
const float *u = lc->U + (int64_t)k * lc->stride + 8 * best_g;
|
| 6015 |
+
float dL = 0.0f;
|
| 6016 |
+
for (int j = 0; j < 8; j++) dL += u[j] * de[j];
|
| 6017 |
+
Lv[k] += dL;
|
| 6018 |
+
}
|
| 6019 |
}
|
| 6020 |
+
for (int j = 0; j < 8; j++) e[8*best_g + j] += de[j];
|
| 6021 |
+
sse += cn->sse - co->sse;
|
| 6022 |
cur[best_g] = best_c;
|
| 6023 |
code[best_g] = cn->code;
|
| 6024 |
metric = best_m;
|
|
|
|
| 6174 |
|
| 6175 |
/* 4. fold/DC shaping among near-equivalent codewords (carry = 0 here;
|
| 6176 |
* the sequential pass below applies the true residual carry). */
|
| 6177 |
+
iq2xs_shape_block(bk, x, w, best_d, ls, code, NULL, NULL);
|
| 6178 |
|
| 6179 |
float d_out = best_d;
|
| 6180 |
if (inflate != 0.0f)
|
|
|
|
| 6182 |
iq2_pack(bk, output + blk * BB, d_out, ls, code);
|
| 6183 |
}
|
| 6184 |
|
| 6185 |
+
/* 5. sequential TRUE residual carry along each row — one lane per
|
| 6186 |
+
* pyramid node (255 lanes: 128 vesica pairs … 1 DC). S ← decay·S + vᵏ,
|
| 6187 |
+
* carry = decay·S, so each lane's row residual is just its last miss. */
|
| 6188 |
+
const int use_lanes = (g_lane_r > 0 && g_lane_U && row_width > 0 && g_lane_cols == row_width);
|
| 6189 |
+
if ((HEX_DC_LAMBDA > 0.0f || HEX_VW_LAMBDA > 0.0f || use_lanes) && g_hex_dc_decay > 0.0f) {
|
| 6190 |
int64_t bpr = (row_width > 0 && row_width % QK_K == 0) ? row_width / QK_K : 0;
|
| 6191 |
+
float S[QK_K], C[QK_K], T[QK_K], e[QK_K], w[QK_K], deq[QK_K];
|
| 6192 |
+
float LS[HEX_MAX_LANES], LC[HEX_MAX_LANES];
|
| 6193 |
uint8_t ls[IQ2XS_NSUB]; uint32_t code[IQ2XS_NGROUP];
|
| 6194 |
+
IQ2LaneCtx lc = { NULL, g_lane_cols, g_lane_ev, use_lanes ? g_lane_r : 0, LC, g_lane_lambda };
|
| 6195 |
+
memset(S, 0, sizeof(S)); memset(LS, 0, sizeof(LS));
|
| 6196 |
for (int64_t blk = 0; blk < n_blocks; blk++) {
|
| 6197 |
+
if (bpr > 0 && (blk % bpr) == 0) { memset(S, 0, sizeof(S)); memset(LS, 0, sizeof(LS)); }
|
| 6198 |
const float *x = weights + blk * QK_K;
|
| 6199 |
uint8_t *b = output + blk * BB;
|
| 6200 |
+
for (int q = 0; q < QK_K - 1; q++) C[q] = g_hex_dc_decay * S[q];
|
| 6201 |
+
for (int k = 0; k < lc.r; k++) LC[k] = g_hex_dc_decay * LS[k];
|
| 6202 |
+
if (use_lanes) lc.U = g_lane_U + (bpr > 0 ? (blk % bpr) * QK_K : 0);
|
| 6203 |
float d = iq2_unpack(bk, b, ls, code);
|
| 6204 |
if (d > 0.0f) {
|
| 6205 |
float sigma2 = 0.0f;
|
|
|
|
| 6209 |
float base = imat_importance ? imat_importance[blk * QK_K + i] : 1.0f;
|
| 6210 |
w[i] = (wmode == 1) ? base * sqrtf(sigma2 + x[i] * x[i]) : base;
|
| 6211 |
}
|
| 6212 |
+
iq2xs_shape_block(bk, x, w, d, ls, code, C, use_lanes ? &lc : NULL);
|
| 6213 |
iq2_pack(bk, b, d, ls, code);
|
| 6214 |
}
|
| 6215 |
iq2_dequant_block(bk, b, deq);
|
| 6216 |
+
for (int i = 0; i < QK_K; i++) e[i] = x[i] - deq[i];
|
| 6217 |
+
hex_fold_build(e, QK_K, T);
|
| 6218 |
+
for (int q = 0; q < QK_K - 1; q++)
|
| 6219 |
+
S[q] = g_hex_carry_cumulative ? C[q] + T[q] : T[q];
|
| 6220 |
+
for (int k = 0; k < lc.r; k++) {
|
| 6221 |
+
const float *u = lc.U + (int64_t)k * lc.stride;
|
| 6222 |
+
float s = 0.0f;
|
| 6223 |
+
for (int i = 0; i < QK_K; i++) s += u[i] * e[i];
|
| 6224 |
+
LS[k] = g_hex_carry_cumulative ? LC[k] + s : s;
|
| 6225 |
+
}
|
| 6226 |
}
|
| 6227 |
}
|
| 6228 |
|
hexstate_requantize.py
CHANGED
|
@@ -155,6 +155,20 @@ def _load_hexstate_lib():
|
|
| 155 |
budget = '0.02'
|
| 156 |
if budget is not None and hasattr(lib, 'hexstate_set_sse_budget'):
|
| 157 |
lib.hexstate_set_sse_budget(ctypes.c_float(float(budget)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
_HEXSTATE_LIB = lib
|
| 159 |
return lib
|
| 160 |
except Exception as e:
|
|
@@ -852,9 +866,14 @@ def _copy_bytes(fin, fout, abs_offset, n_bytes):
|
|
| 852 |
return written
|
| 853 |
|
| 854 |
|
| 855 |
-
def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs'):
|
| 856 |
"""IQ2_XS (74 B) or IQ2_S (82 B) per 256 weights via the HPC C library.
|
| 857 |
-
Returns (bytes, n_blocks, dequant_f32).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 858 |
suffix = {'iq2xs': 'iq2_xs', 'iq2s': 'iq2_s'}[kind]
|
| 859 |
block_bytes = LOWBIT_KINDS[kind][1]
|
| 860 |
lib = _load_hexstate_lib()
|
|
@@ -872,6 +891,20 @@ def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs'
|
|
| 872 |
imat_c = np.ascontiguousarray(importance, dtype=np.float32).reshape(-1)
|
| 873 |
if imat_c.size == n:
|
| 874 |
imat_ptr = imat_c.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 875 |
getattr(lib, f'hexstate_quantize_tensor_{suffix}_hpc')(
|
| 876 |
f32.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 877 |
ctypes.c_int64(n),
|
|
@@ -881,6 +914,9 @@ def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs'
|
|
| 881 |
ctypes.c_int(0),
|
| 882 |
ctypes.c_int64(int(row_width)),
|
| 883 |
)
|
|
|
|
|
|
|
|
|
|
| 884 |
deq = np.zeros(n, dtype=np.float32)
|
| 885 |
getattr(lib, f'hexstate_dequant_{suffix}')(
|
| 886 |
out.ctypes.data_as(ctypes.c_void_p), ctypes.c_int64(n_blocks),
|
|
@@ -1161,6 +1197,9 @@ def main():
|
|
| 1161 |
print(" HEX_VW_LAMBDA vesica weight (default 1)")
|
| 1162 |
print(" HEX_DC_DECAY rolling residual carry 0..1 (default 0.85)")
|
| 1163 |
print(" HEX_SSE_BUDGET relative SSE the shaper may spend (Q2_K 5e-4, IQ2 2e-2)")
|
|
|
|
|
|
|
|
|
|
| 1164 |
sys.exit(1)
|
| 1165 |
|
| 1166 |
global LOWBIT_FORMAT
|
|
|
|
| 155 |
budget = '0.02'
|
| 156 |
if budget is not None and hasattr(lib, 'hexstate_set_sse_budget'):
|
| 157 |
lib.hexstate_set_sse_budget(ctypes.c_float(float(budget)))
|
| 158 |
+
# Fold pyramid: HEX_FOLD_DEPTH levels below DC get vesica weight
|
| 159 |
+
# (1 = classic single-fold vesica [default], 7 = full tree), geometric
|
| 160 |
+
# per-level weight HEX_FOLD_GAMMA. HEX_CARRY_CUM=0 restores the legacy
|
| 161 |
+
# previous-block-only carry (default carries the cumulative residual).
|
| 162 |
+
fd = os.environ.get('HEX_FOLD_DEPTH')
|
| 163 |
+
fg = os.environ.get('HEX_FOLD_GAMMA')
|
| 164 |
+
fc = os.environ.get('HEX_CARRY_CUM')
|
| 165 |
+
if hasattr(lib, 'hexstate_set_fold_params') and (fd or fg or fc):
|
| 166 |
+
lib.hexstate_set_fold_params.restype = None
|
| 167 |
+
lib.hexstate_set_fold_params.argtypes = [ctypes.c_int, ctypes.c_float, ctypes.c_int]
|
| 168 |
+
lib.hexstate_set_fold_params(
|
| 169 |
+
ctypes.c_int(int(fd) if fd else -1),
|
| 170 |
+
ctypes.c_float(float(fg) if fg else 0.0),
|
| 171 |
+
ctypes.c_int(int(fc) if fc else -1))
|
| 172 |
_HEXSTATE_LIB = lib
|
| 173 |
return lib
|
| 174 |
except Exception as e:
|
|
|
|
| 866 |
return written
|
| 867 |
|
| 868 |
|
| 869 |
+
def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs', lanes=None):
|
| 870 |
"""IQ2_XS (74 B) or IQ2_S (82 B) per 256 weights via the HPC C library.
|
| 871 |
+
Returns (bytes, n_blocks, dequant_f32).
|
| 872 |
+
|
| 873 |
+
lanes: optional (U, ev[, lambda]) — U is (r, row_width) activation
|
| 874 |
+
directions over the input columns (top eigenvectors of E[a aᵀ]) and ev
|
| 875 |
+
their eigenvalues in E[a²] units; the sequential pass then also cancels
|
| 876 |
+
the row error along each u_k with a cumulative carry."""
|
| 877 |
suffix = {'iq2xs': 'iq2_xs', 'iq2s': 'iq2_s'}[kind]
|
| 878 |
block_bytes = LOWBIT_KINDS[kind][1]
|
| 879 |
lib = _load_hexstate_lib()
|
|
|
|
| 891 |
imat_c = np.ascontiguousarray(importance, dtype=np.float32).reshape(-1)
|
| 892 |
if imat_c.size == n:
|
| 893 |
imat_ptr = imat_c.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
|
| 894 |
+
lane_keep = None
|
| 895 |
+
if lanes is not None and hasattr(lib, 'hexstate_set_activation_lanes') and row_width > 0:
|
| 896 |
+
U = np.ascontiguousarray(lanes[0], dtype=np.float32).reshape(-1, int(row_width))
|
| 897 |
+
ev = np.ascontiguousarray(lanes[1], dtype=np.float32).reshape(-1)
|
| 898 |
+
lam = float(lanes[2]) if len(lanes) > 2 else 1.0
|
| 899 |
+
lib.hexstate_set_activation_lanes.restype = None
|
| 900 |
+
lib.hexstate_set_activation_lanes.argtypes = [
|
| 901 |
+
ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float),
|
| 902 |
+
ctypes.c_int, ctypes.c_int64, ctypes.c_float]
|
| 903 |
+
lib.hexstate_set_activation_lanes(
|
| 904 |
+
U.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 905 |
+
ev.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 906 |
+
ctypes.c_int(int(min(U.shape[0], ev.size))), ctypes.c_int64(int(row_width)), ctypes.c_float(lam))
|
| 907 |
+
lane_keep = (U, ev)
|
| 908 |
getattr(lib, f'hexstate_quantize_tensor_{suffix}_hpc')(
|
| 909 |
f32.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 910 |
ctypes.c_int64(n),
|
|
|
|
| 914 |
ctypes.c_int(0),
|
| 915 |
ctypes.c_int64(int(row_width)),
|
| 916 |
)
|
| 917 |
+
if lane_keep is not None:
|
| 918 |
+
lib.hexstate_set_activation_lanes(None, None, ctypes.c_int(0), ctypes.c_int64(0), ctypes.c_float(0.0))
|
| 919 |
+
del lane_keep
|
| 920 |
deq = np.zeros(n, dtype=np.float32)
|
| 921 |
getattr(lib, f'hexstate_dequant_{suffix}')(
|
| 922 |
out.ctypes.data_as(ctypes.c_void_p), ctypes.c_int64(n_blocks),
|
|
|
|
| 1197 |
print(" HEX_VW_LAMBDA vesica weight (default 1)")
|
| 1198 |
print(" HEX_DC_DECAY rolling residual carry 0..1 (default 0.85)")
|
| 1199 |
print(" HEX_SSE_BUDGET relative SSE the shaper may spend (Q2_K 5e-4, IQ2 2e-2)")
|
| 1200 |
+
print(" HEX_FOLD_DEPTH fold-pyramid levels below DC to shape, 1=vesica only (default 1, 7=full tree)")
|
| 1201 |
+
print(" HEX_FOLD_GAMMA per-level geometric weight of the pyramid (default 2)")
|
| 1202 |
+
print(" HEX_CARRY_CUM 1: carry cumulative row residual (default), 0: previous block only")
|
| 1203 |
sys.exit(1)
|
| 1204 |
|
| 1205 |
global LOWBIT_FORMAT
|