seedpack 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- seedpack/__init__.py +6 -0
- seedpack/__main__.py +3 -0
- seedpack/bf16codec.py +103 -0
- seedpack/bf16v2.py +421 -0
- seedpack/bundle.py +36 -0
- seedpack/cli.py +413 -0
- seedpack/codecs_gguf.py +344 -0
- seedpack/container.py +106 -0
- seedpack/ggml/LICENSE +21 -0
- seedpack/ggml/build.sh +14 -0
- seedpack/ggml/export.c +10 -0
- seedpack/ggml/ggml-alloc.h +87 -0
- seedpack/ggml/ggml-backend.h +463 -0
- seedpack/ggml/ggml-common.h +1911 -0
- seedpack/ggml/ggml-cpu/ggml-cpu-impl.h +540 -0
- seedpack/ggml/ggml-cpu.h +152 -0
- seedpack/ggml/ggml-impl.h +795 -0
- seedpack/ggml/ggml-quants.c +5639 -0
- seedpack/ggml/ggml-quants.h +115 -0
- seedpack/ggml/ggml.h +3049 -0
- seedpack/ggml/gguf.h +211 -0
- seedpack/ggml/iqtables.npz +0 -0
- seedpack/ggml/stubs.c +29 -0
- seedpack/ggml/variants/ggml-quants.pre-f95b0d9539.c +5667 -0
- seedpack/gguf_reader.py +121 -0
- seedpack/gpu2.py +874 -0
- seedpack/gpu3.py +639 -0
- seedpack/gpu_bf16.py +530 -0
- seedpack/gpu_codec.py +353 -0
- seedpack/gpuquant.py +416 -0
- seedpack/ptxfix.py +78 -0
- seedpack/qr.py +735 -0
- seedpack/rans.py +164 -0
- seedpack/refcodec.py +314 -0
- seedpack/repo.py +597 -0
- seedpack/repo2.py +160 -0
- seedpack/repo3.py +931 -0
- seedpack/requant.py +117 -0
- seedpack/seed.py +160 -0
- seedpack-0.1.0.dist-info/METADATA +111 -0
- seedpack-0.1.0.dist-info/RECORD +47 -0
- seedpack-0.1.0.dist-info/WHEEL +5 -0
- seedpack-0.1.0.dist-info/entry_points.txt +2 -0
- seedpack-0.1.0.dist-info/licenses/LICENSE +202 -0
- seedpack-0.1.0.dist-info/licenses/NOTICE +6 -0
- seedpack-0.1.0.dist-info/licenses/seedpack/ggml/LICENSE +21 -0
- seedpack-0.1.0.dist-info/top_level.txt +1 -0
seedpack/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"""SeedPack: lossless GPU archiver for GGUF model repositories.
|
|
2
|
+
|
|
3
|
+
The quants of a repository are re-derived on the GPU from its most precise model (the seed) with
|
|
4
|
+
a bit-exact port of llama.cpp's quantisers; only what differs is stored. Command line: `seedpack`.
|
|
5
|
+
"""
|
|
6
|
+
__version__ = "0.1.0"
|
seedpack/__main__.py
ADDED
seedpack/bf16codec.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Method 22: lossless BF16 GGUF codec (no reference model).
|
|
2
|
+
|
|
3
|
+
A bf16 weight = sign(1) | exponent(8) | mantissa(7). Trained weights use ~2.6 of the 8
|
|
4
|
+
exponent bits (the DFloat11 / ZipNN observation); on top of that this codec models
|
|
5
|
+
* exponent | predicted exponent (rank-1 variance model: row factor + column factor,
|
|
6
|
+
quarter-octave side info per row and per column)
|
|
7
|
+
* mantissa | exponent - predicted exponent (density slope inside an octave)
|
|
8
|
+
* sign | column mean-bias class
|
|
9
|
+
Each stream is coded with static rANS, tables per tensor. Everything outside 2-D bf16
|
|
10
|
+
tensors (header, norms, padding) goes through the tokenizer-aware header codec.
|
|
11
|
+
"""
|
|
12
|
+
import json
|
|
13
|
+
import struct
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from . import rans
|
|
18
|
+
from .codecs_gguf import pack, unpack, zstd_c, zstd_d
|
|
19
|
+
from .gguf_reader import GGUF, GGML_BF16
|
|
20
|
+
from .gpu2 import header_pairs_c, header_pairs_d, xz_chunks_c, xz_chunks_d, rest_of
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _contexts(rfi, cfi, ex=None):
|
|
24
|
+
pred4 = rfi[:, None].astype(np.int32) + cfi[None, :].astype(np.int32) # log2 sigma in 1/4 octave
|
|
25
|
+
eb = np.clip((pred4 + 4 * 27) // 2, 0, 127).astype(np.int16) # half-octave bins
|
|
26
|
+
if ex is None:
|
|
27
|
+
return eb, pred4
|
|
28
|
+
rel = np.clip(ex.astype(np.int32) - (pred4 + 508) // 4 + 8, 0, 15).astype(np.int16)
|
|
29
|
+
return eb, rel
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class M22BF16:
|
|
33
|
+
name = "M22 BF16: exponent/mantissa/sign context rANS"
|
|
34
|
+
|
|
35
|
+
def compress(self, data):
|
|
36
|
+
g = GGUF.from_bytes(data)
|
|
37
|
+
ts = sorted((t for t in g.tensors if t.type == GGML_BF16 and len(t.shape) == 2), key=lambda t: t.offset)
|
|
38
|
+
layout = {"size": len(data), "t": [[t.offset, t.nbytes, t.shape[0], "bf16"] for t in ts]}
|
|
39
|
+
bufs, tabs, side = [], [], []
|
|
40
|
+
for t in ts:
|
|
41
|
+
rowlen = t.shape[0]
|
|
42
|
+
u = np.frombuffer(data, np.uint16, t.nbytes // 2, t.offset).reshape(-1, rowlen)
|
|
43
|
+
w = (u.astype(np.uint32) << 16).view(np.float32)
|
|
44
|
+
rf = np.log2(np.sqrt((w.astype(np.float64) ** 2).mean(1)) + 1e-30)
|
|
45
|
+
cf = np.log2(np.sqrt(((w / np.exp2(rf)[:, None]).astype(np.float64) ** 2).mean(0)) + 1e-30)
|
|
46
|
+
rfi = np.clip(np.rint(rf * 4), -32768, 32767).astype(np.int16)
|
|
47
|
+
cfi = np.clip(np.rint(cf * 4), -32768, 32767).astype(np.int16)
|
|
48
|
+
bias = (w / np.exp2(rf)[:, None]).mean(0) / np.exp2(cfi / 4.0)
|
|
49
|
+
sc = np.clip(np.floor(bias * 16) + 8, 0, 15).astype(np.int16)
|
|
50
|
+
ex = ((u >> 7) & 255).astype(np.uint8); man = (u & 127).astype(np.uint8); sg = (u >> 15).astype(np.uint8)
|
|
51
|
+
eb, rel = _contexts(rfi, cfi, ex)
|
|
52
|
+
sctx = np.broadcast_to(sc[None, :], u.shape)
|
|
53
|
+
for sym, ctx, nctx in ((ex, eb, 128), (man, rel, 16), (sg, sctx, 16)):
|
|
54
|
+
sym = sym.ravel(); ctx = np.ascontiguousarray(ctx.ravel())
|
|
55
|
+
f = rans.build_freqs(sym, ctx, nctx)
|
|
56
|
+
tabs.append(f); bufs.append(rans.encode(sym, ctx, f))
|
|
57
|
+
side.append(rfi.tobytes() + cfi.tobytes() + sc.astype(np.int8).tobytes())
|
|
58
|
+
h = header_pairs_c(data, g, layout)
|
|
59
|
+
rest = b"P" + h if h is not None else b"X" + xz_chunks_c(rest_of(data, layout))
|
|
60
|
+
ch = {
|
|
61
|
+
"layout": zstd_c(json.dumps(layout).encode()),
|
|
62
|
+
"side": zstd_c(b"".join(side), 19),
|
|
63
|
+
"tables": zstd_c(b"".join(f.astype(np.uint16).tobytes() for f in tabs), 19),
|
|
64
|
+
"streams": b"".join(struct.pack("<Q", len(b)) + b for b in bufs),
|
|
65
|
+
"rest": rest,
|
|
66
|
+
}
|
|
67
|
+
return pack(ch)
|
|
68
|
+
|
|
69
|
+
def decompress(self, buf):
|
|
70
|
+
ch = unpack(buf)
|
|
71
|
+
layout = json.loads(zstd_d(ch["layout"]))
|
|
72
|
+
side = zstd_d(ch["side"]); tabs = np.frombuffer(zstd_d(ch["tables"]), np.uint16)
|
|
73
|
+
sbuf, spos, tpos, dpos = ch["streams"], 0, 0, 0
|
|
74
|
+
r = ch["rest"]
|
|
75
|
+
rest = header_pairs_d(r[1:]) if r[:1] == b"P" else xz_chunks_d(r[1:])
|
|
76
|
+
out = np.empty(layout["size"], np.uint8)
|
|
77
|
+
pos = rpos = 0
|
|
78
|
+
|
|
79
|
+
def next_stream():
|
|
80
|
+
nonlocal spos
|
|
81
|
+
(ln,) = struct.unpack_from("<Q", sbuf, spos); spos += 8
|
|
82
|
+
b = sbuf[spos:spos + ln]; spos += ln
|
|
83
|
+
return b
|
|
84
|
+
|
|
85
|
+
for off, nbytes, rowlen, _ in layout["t"]:
|
|
86
|
+
n = nbytes // 2; nrows = n // rowlen
|
|
87
|
+
rfi = np.frombuffer(side, np.int16, nrows, dpos); dpos += 2 * nrows
|
|
88
|
+
cfi = np.frombuffer(side, np.int16, rowlen, dpos); dpos += 2 * rowlen
|
|
89
|
+
sc = np.frombuffer(side, np.int8, rowlen, dpos).astype(np.int16); dpos += rowlen
|
|
90
|
+
res = []
|
|
91
|
+
for nctx in (128, 16, 16):
|
|
92
|
+
res.append(tabs[tpos:tpos + nctx * 256].reshape(nctx, 256)); tpos += nctx * 256
|
|
93
|
+
eb, pred4 = _contexts(rfi, cfi)
|
|
94
|
+
ex = rans.decode(next_stream(), eb.ravel(), res[0]).reshape(nrows, rowlen)
|
|
95
|
+
_, rel = _contexts(rfi, cfi, ex)
|
|
96
|
+
man = rans.decode(next_stream(), np.ascontiguousarray(rel.ravel()), res[1]).reshape(nrows, rowlen)
|
|
97
|
+
sg = rans.decode(next_stream(), np.ascontiguousarray(np.broadcast_to(sc[None, :], (nrows, rowlen)).ravel()), res[2])
|
|
98
|
+
u = (sg.reshape(nrows, rowlen).astype(np.uint16) << 15) | (ex.astype(np.uint16) << 7) | man.astype(np.uint16)
|
|
99
|
+
gap = off - pos
|
|
100
|
+
out[pos:off] = np.frombuffer(rest, np.uint8, gap, rpos); rpos += gap
|
|
101
|
+
out[off:off + nbytes] = u.view(np.uint8).ravel(); pos = off + nbytes
|
|
102
|
+
out[pos:] = np.frombuffer(rest, np.uint8, len(rest) - rpos, rpos)
|
|
103
|
+
return out
|
seedpack/bf16v2.py
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"""R2: BF16 GGUF codec v2 (candidate successor of M24).
|
|
2
|
+
|
|
3
|
+
Changes against M24 (src/gpu_bf16.py):
|
|
4
|
+
* 1/8-octave variance side info (rfi/cfi = rint(8*log2 rms)) instead of 1/4 octave;
|
|
5
|
+
exponent context = predicted log2 sigma in 1/8 octave (512 ctx), mantissa context =
|
|
6
|
+
exponent - prediction in 1/8 octave (128 ctx), sign context = column bias class (16 ctx);
|
|
7
|
+
* frequency tables are SHARED by all tensors of the same role (blk.*.ffn_up, ...), which makes
|
|
8
|
+
the finer contexts affordable (table cost ~0.06 MB instead of ~0.3 MB for M24's coarser ones);
|
|
9
|
+
* exact duplicate rows (e.g. untrained token embeddings) are coded once + a row map;
|
|
10
|
+
* bounded GPU memory: tensors are processed in groups of <= group_bytes; the file is kept
|
|
11
|
+
on the GPU between the histogram and the encode pass only when it fits `budget` bytes.
|
|
12
|
+
Exactness: contexts are pure integer functions of side info stored in the archive.
|
|
13
|
+
"""
|
|
14
|
+
import json, os, re, sys, struct
|
|
15
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
16
|
+
|
|
17
|
+
import cupy as cp
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
from .codecs_gguf import pack, unpack, zstd_c, zstd_d
|
|
22
|
+
from .gguf_reader import GGUF, GGML_BF16
|
|
23
|
+
from .gpu2 import normalize_gpu, cum_of, store_tables, load_tables, Timer, GPU2
|
|
24
|
+
PB = 15 # probability resolution (M24: 12); +0.25 MB gain, see pb_study.py
|
|
25
|
+
from .gpu_bf16 import M24BF16GPU
|
|
26
|
+
|
|
27
|
+
SEG = 16384
|
|
28
|
+
K = 8 # side info resolution: 1/K octave
|
|
29
|
+
NE, NM, NS = 512, 128, 16
|
|
30
|
+
TPT = NE + NM + NS # tables per role group
|
|
31
|
+
|
|
32
|
+
KERNELS = r"""
|
|
33
|
+
#define PB %(PB)d
|
|
34
|
+
#define PSCALE (1u << PB)
|
|
35
|
+
#define RANS_L (1u << 23)
|
|
36
|
+
|
|
37
|
+
struct TB { long long doff; int rowlen, rowbase, colbase, tab, rmap, pad; };
|
|
38
|
+
struct SG { int t; int n; long long i0; };
|
|
39
|
+
|
|
40
|
+
#define PUT(tab, s) { \
|
|
41
|
+
int tt_ = remap[tab]; unsigned int s_ = (s); \
|
|
42
|
+
unsigned int f_ = freq[tt_ * 256 + s_], c_ = cum[tt_ * 257 + s_]; \
|
|
43
|
+
unsigned int xm_ = ((RANS_L >> PB) << 8) * f_; \
|
|
44
|
+
while (x >= xm_) { *--ptr = (unsigned char)(x & 0xff); x >>= 8; } \
|
|
45
|
+
x = ((x / f_) << PB) + (x % f_) + c_; }
|
|
46
|
+
|
|
47
|
+
#define GET(tab, out) { \
|
|
48
|
+
int tt_ = remap[tab]; unsigned int slot_ = x & (PSCALE - 1); \
|
|
49
|
+
int s_ = lut[(size_t)tt_ * PSCALE + slot_]; \
|
|
50
|
+
x = freq[tt_ * 256 + s_] * (x >> PB) + slot_ - cum[tt_ * 257 + s_]; \
|
|
51
|
+
while (x < RANS_L) x = (x << 8) | *ptr++; \
|
|
52
|
+
out = s_; }
|
|
53
|
+
|
|
54
|
+
__device__ __forceinline__ int clampi(int v, int lo, int hi) { return v < lo ? lo : (v > hi ? hi : v); }
|
|
55
|
+
|
|
56
|
+
// compact row rc -> original row
|
|
57
|
+
#define OROW(rc) (T.rmap >= 0 ? rowmap[T.rmap + (rc)] : (rc))
|
|
58
|
+
#define CTX \
|
|
59
|
+
int pred = rfi[T.rowbase + orow] + cfi[T.colbase + j]; \
|
|
60
|
+
int pe = clampi(pred + 256, 0, 511);
|
|
61
|
+
#define MCTX int rl = clampi(8 * ex - pred - 1016 + 64, 0, 127);
|
|
62
|
+
|
|
63
|
+
extern "C" __global__ void v2_hist(const unsigned char* dev, const TB* tb, const SG* sg, int nseg,
|
|
64
|
+
const short* rfi, const short* cfi, const signed char* scl, const int* rowmap,
|
|
65
|
+
unsigned int* counts) {
|
|
66
|
+
int s = blockIdx.x * blockDim.x + threadIdx.x;
|
|
67
|
+
if (s >= nseg) return;
|
|
68
|
+
TB T = tb[sg[s].t];
|
|
69
|
+
const unsigned short* W = (const unsigned short*)(dev + T.doff);
|
|
70
|
+
int rc = (int)(sg[s].i0 / T.rowlen), j = (int)(sg[s].i0 % T.rowlen);
|
|
71
|
+
int orow = OROW(rc);
|
|
72
|
+
const unsigned short* w = W + (size_t)orow * T.rowlen;
|
|
73
|
+
for (int k = 0; k < sg[s].n; k++) {
|
|
74
|
+
unsigned int u = w[j];
|
|
75
|
+
int ex = (u >> 7) & 255, man = u & 127, sgn = u >> 15;
|
|
76
|
+
CTX MCTX
|
|
77
|
+
atomicAdd(&counts[(size_t)(T.tab + pe) * 256 + ex], 1u);
|
|
78
|
+
atomicAdd(&counts[(size_t)(T.tab + 512 + rl) * 256 + man], 1u);
|
|
79
|
+
atomicAdd(&counts[(size_t)(T.tab + 640 + scl[T.colbase + j]) * 256 + sgn], 1u);
|
|
80
|
+
if (++j == T.rowlen) { j = 0; rc++; if (k + 1 < sg[s].n) { orow = OROW(rc); w = W + (size_t)orow * T.rowlen; } }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
extern "C" __global__ void v2_enc(const unsigned char* dev, const TB* tb, const SG* sg, int nseg,
|
|
85
|
+
const short* rfi, const short* cfi, const signed char* scl, const int* rowmap,
|
|
86
|
+
const int* remap, const unsigned short* freq, const unsigned int* cum,
|
|
87
|
+
unsigned char* out, size_t cap, unsigned int* out_len) {
|
|
88
|
+
int s = blockIdx.x * blockDim.x + threadIdx.x;
|
|
89
|
+
if (s >= nseg) return;
|
|
90
|
+
TB T = tb[sg[s].t];
|
|
91
|
+
const unsigned short* W = (const unsigned short*)(dev + T.doff);
|
|
92
|
+
long long last = sg[s].i0 + sg[s].n - 1;
|
|
93
|
+
int rc = (int)(last / T.rowlen), j = (int)(last % T.rowlen);
|
|
94
|
+
int orow = OROW(rc);
|
|
95
|
+
const unsigned short* w = W + (size_t)orow * T.rowlen;
|
|
96
|
+
unsigned char* start = out + (size_t)s * cap;
|
|
97
|
+
unsigned char* end = start + cap; unsigned char* ptr = end;
|
|
98
|
+
unsigned int x = RANS_L;
|
|
99
|
+
for (int k = sg[s].n - 1; k >= 0; k--) {
|
|
100
|
+
unsigned int u = w[j];
|
|
101
|
+
int ex = (u >> 7) & 255, man = u & 127, sgn = u >> 15;
|
|
102
|
+
CTX MCTX
|
|
103
|
+
PUT(T.tab + 640 + scl[T.colbase + j], sgn);
|
|
104
|
+
PUT(T.tab + 512 + rl, man);
|
|
105
|
+
PUT(T.tab + pe, ex);
|
|
106
|
+
if (ptr - start < 64) { out_len[s] = 0xffffffffu; return; }
|
|
107
|
+
if (--j < 0) { j = T.rowlen - 1; rc--; if (k > 0) { orow = OROW(rc); w = W + (size_t)orow * T.rowlen; } }
|
|
108
|
+
}
|
|
109
|
+
for (int i = 0; i < 4; i++) { *--ptr = (unsigned char)(x & 0xff); x >>= 8; }
|
|
110
|
+
out_len[s] = (unsigned int)(end - ptr);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
extern "C" __global__ void v2_dec(const unsigned char* in, const unsigned long long* in_off,
|
|
114
|
+
unsigned char* dev, const TB* tb, const SG* sg, int nseg,
|
|
115
|
+
const short* rfi, const short* cfi, const signed char* scl, const int* rowmap,
|
|
116
|
+
const int* remap, const unsigned short* freq, const unsigned int* cum,
|
|
117
|
+
const unsigned char* lut) {
|
|
118
|
+
int s = blockIdx.x * blockDim.x + threadIdx.x;
|
|
119
|
+
if (s >= nseg) return;
|
|
120
|
+
TB T = tb[sg[s].t];
|
|
121
|
+
unsigned short* W = (unsigned short*)(dev + T.doff);
|
|
122
|
+
int rc = (int)(sg[s].i0 / T.rowlen), j = (int)(sg[s].i0 % T.rowlen);
|
|
123
|
+
int orow = OROW(rc);
|
|
124
|
+
unsigned short* w = W + (size_t)orow * T.rowlen;
|
|
125
|
+
const unsigned char* ptr = in + in_off[s]; unsigned int x = 0;
|
|
126
|
+
for (int i = 0; i < 4; i++) x = (x << 8) | *ptr++;
|
|
127
|
+
for (int k = 0; k < sg[s].n; k++) {
|
|
128
|
+
int ex, man, sgn;
|
|
129
|
+
CTX
|
|
130
|
+
GET(T.tab + pe, ex);
|
|
131
|
+
MCTX
|
|
132
|
+
GET(T.tab + 512 + rl, man);
|
|
133
|
+
GET(T.tab + 640 + scl[T.colbase + j], sgn);
|
|
134
|
+
w[j] = (unsigned short)((sgn << 15) | (ex << 7) | man);
|
|
135
|
+
if (++j == T.rowlen) { j = 0; rc++; if (k + 1 < sg[s].n) { orow = OROW(rc); w = W + (size_t)orow * T.rowlen; } }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
extern "C" __global__ void build_lut(const unsigned int* cum, int ntab, unsigned char* lut) {
|
|
140
|
+
int tb = blockIdx.x;
|
|
141
|
+
if (tb >= ntab) return;
|
|
142
|
+
for (int sym = threadIdx.x; sym < 256; sym += blockDim.x)
|
|
143
|
+
for (unsigned int i = cum[tb * 257 + sym]; i < cum[tb * 257 + sym + 1]; i++)
|
|
144
|
+
lut[(size_t)tb * PSCALE + i] = (unsigned char)sym;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 64-bit row fingerprints for duplicate-row detection
|
|
148
|
+
extern "C" __global__ void row_hash(const unsigned short* w, int nrows, int rowlen, unsigned long long* h) {
|
|
149
|
+
int r = blockIdx.x * blockDim.x + threadIdx.x;
|
|
150
|
+
if (r >= nrows) return;
|
|
151
|
+
unsigned long long a = 1469598103934665603ull;
|
|
152
|
+
const unsigned short* p = w + (size_t)r * rowlen;
|
|
153
|
+
for (int j = 0; j < rowlen; j++) { a ^= p[j]; a *= 1099511628211ull; a ^= a >> 29; }
|
|
154
|
+
h[r] = a;
|
|
155
|
+
}
|
|
156
|
+
""".replace("%(PB)d", str(PB))
|
|
157
|
+
|
|
158
|
+
TB_DT = np.dtype([("doff", "<i8"), ("rowlen", "<i4"), ("rowbase", "<i4"), ("colbase", "<i4"), ("tab", "<i4"), ("rmap", "<i4"), ("pad", "<i4")])
|
|
159
|
+
SG_DT = np.dtype([("t", "<i4"), ("n", "<i4"), ("i0", "<i8")])
|
|
160
|
+
_mod = None
|
|
161
|
+
_g2 = GPU2()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def kern(name):
|
|
165
|
+
global _mod
|
|
166
|
+
if _mod is None:
|
|
167
|
+
_mod = cp.RawModule(code=KERNELS, options=("-std=c++17",))
|
|
168
|
+
return _mod.get_function(name)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def role(name):
|
|
172
|
+
return re.sub(r"blk\.\d+\.", "", name)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class BF16v2:
|
|
176
|
+
name = "R2 BF16 v2: 1/8-octave contexts, role-shared tables, row dedup, bounded GPU memory"
|
|
177
|
+
|
|
178
|
+
def __init__(self, budget=2_000_000_000, group_bytes=400 << 20, dedup=True):
|
|
179
|
+
self.budget, self.group_bytes, self.dedup = budget, group_bytes, dedup
|
|
180
|
+
self.timing = {}
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------------- layout
|
|
183
|
+
@staticmethod
|
|
184
|
+
def _layout(g, size):
|
|
185
|
+
ts = sorted((t for t in g.tensors if t.type == GGML_BF16 and len(t.shape) == 2), key=lambda t: t.offset)
|
|
186
|
+
roles = []
|
|
187
|
+
for t in ts:
|
|
188
|
+
if role(t.name) not in roles:
|
|
189
|
+
roles.append(role(t.name))
|
|
190
|
+
return {"size": size, "t": [[t.offset, t.nbytes, t.shape[0], "bf16"] for t in ts],
|
|
191
|
+
"role": [roles.index(role(t.name)) for t in ts], "nroles": len(roles)}
|
|
192
|
+
|
|
193
|
+
def _groups(self, layout):
|
|
194
|
+
gs, cur, cb = [], [], 0
|
|
195
|
+
for i, (off, nb, rl, _) in enumerate(layout["t"]):
|
|
196
|
+
if cur and cb + nb > self.group_bytes:
|
|
197
|
+
gs.append(cur); cur, cb = [], 0
|
|
198
|
+
cur.append(i); cb += nb
|
|
199
|
+
if cur:
|
|
200
|
+
gs.append(cur)
|
|
201
|
+
return gs
|
|
202
|
+
|
|
203
|
+
@staticmethod
|
|
204
|
+
def _bases(layout):
|
|
205
|
+
rb, cb, rowbase, colbase = [], [], 0, 0
|
|
206
|
+
for off, nb, rl, _ in layout["t"]:
|
|
207
|
+
rb.append(rowbase); cb.append(colbase)
|
|
208
|
+
rowbase += nb // 2 // rl; colbase += rl
|
|
209
|
+
return rb, cb, rowbase, colbase
|
|
210
|
+
|
|
211
|
+
def _plan(self, layout, gi, grp, nrows_c, rmap_off):
|
|
212
|
+
"""descriptors for one group: TB array (device offsets relative to the group buffer), segments"""
|
|
213
|
+
rb, cb, _, _ = self._bases(layout)
|
|
214
|
+
tb = np.zeros(len(grp), TB_DT); segs = []
|
|
215
|
+
a = layout["t"][grp[0]][0]
|
|
216
|
+
for k, i in enumerate(grp):
|
|
217
|
+
off, nb, rl, _ = layout["t"][i]
|
|
218
|
+
tb[k] = (off - a, rl, rb[i], cb[i], layout["role"][i] * TPT, rmap_off.get(i, -1), 0)
|
|
219
|
+
n = nrows_c[i] * rl
|
|
220
|
+
for i0 in range(0, n, SEG):
|
|
221
|
+
segs.append((k, min(SEG, n - i0), i0))
|
|
222
|
+
return tb, np.array(segs, SG_DT)
|
|
223
|
+
|
|
224
|
+
# ---------------------------------------------------------------- compression
|
|
225
|
+
def _stats(self, dev, rl):
|
|
226
|
+
"""side info for one tensor in row chunks: rfi (rows), cfi, scl (cols)"""
|
|
227
|
+
u = dev.view(cp.uint16).reshape(-1, rl)
|
|
228
|
+
nr = u.shape[0]; step = max(1, (16 << 20) // rl)
|
|
229
|
+
rf = cp.empty(nr, cp.float64)
|
|
230
|
+
for r0 in range(0, nr, step):
|
|
231
|
+
w = (u[r0:r0 + step].astype(cp.uint32) << 16).view(cp.float32)
|
|
232
|
+
rf[r0:r0 + step] = cp.log2(cp.sqrt((w * w).mean(1, dtype=cp.float64)) + 1e-30)
|
|
233
|
+
rfa = cp.exp2(rf).astype(cp.float32)
|
|
234
|
+
s2 = cp.zeros(rl, cp.float64); s1 = cp.zeros(rl, cp.float64)
|
|
235
|
+
for r0 in range(0, nr, step):
|
|
236
|
+
w = (u[r0:r0 + step].astype(cp.uint32) << 16).view(cp.float32) / rfa[r0:r0 + step, None]
|
|
237
|
+
s2 += (w * w).sum(0, dtype=cp.float64); s1 += w.sum(0, dtype=cp.float64)
|
|
238
|
+
cf = cp.log2(cp.sqrt(s2 / nr) + 1e-30)
|
|
239
|
+
rfi = cp.clip(cp.rint(rf * K), -32768, 32767).astype(cp.int16)
|
|
240
|
+
cfi = cp.clip(cp.rint(cf * K), -32768, 32767).astype(cp.int16)
|
|
241
|
+
bias = (s1 / nr) / cp.exp2(cfi.astype(cp.float64) / K)
|
|
242
|
+
scl = cp.clip(cp.floor(bias * 16) + 8, 0, 15).astype(cp.int8)
|
|
243
|
+
return rfi, cfi, scl
|
|
244
|
+
|
|
245
|
+
def _dups(self, dev, rl, host):
|
|
246
|
+
"""exact duplicate rows -> (keep rows (sorted), [(dup row, source row)])"""
|
|
247
|
+
u = dev.view(cp.uint16).reshape(-1, rl)
|
|
248
|
+
nr = u.shape[0]
|
|
249
|
+
h = cp.empty(nr, cp.uint64)
|
|
250
|
+
kern("row_hash")(((nr + 127) // 128,), (128,), (u, np.int32(nr), np.int32(rl), h))
|
|
251
|
+
h = h.get()
|
|
252
|
+
order = np.argsort(h, kind="stable")
|
|
253
|
+
hs = h[order]
|
|
254
|
+
same = np.flatnonzero(hs[1:] == hs[:-1])
|
|
255
|
+
if len(same) == 0:
|
|
256
|
+
return None, []
|
|
257
|
+
hu = host.reshape(-1, rl)
|
|
258
|
+
pairs, isdup = [], np.zeros(nr, bool)
|
|
259
|
+
first = {}
|
|
260
|
+
for k in np.unique(np.concatenate([same, same + 1])):
|
|
261
|
+
r = int(order[k]); key = int(hs[k])
|
|
262
|
+
cands = first.setdefault(key, [])
|
|
263
|
+
src = next((c for c in cands if np.array_equal(hu[c], hu[r])), None)
|
|
264
|
+
if src is None:
|
|
265
|
+
cands.append(r)
|
|
266
|
+
else:
|
|
267
|
+
pairs.append((r, src)); isdup[r] = True
|
|
268
|
+
if not pairs:
|
|
269
|
+
return None, []
|
|
270
|
+
return np.flatnonzero(~isdup).astype(np.int32), sorted(pairs)
|
|
271
|
+
|
|
272
|
+
def compress(self, data):
|
|
273
|
+
ev = Timer()
|
|
274
|
+
g = GGUF.from_bytes(data)
|
|
275
|
+
layout = self._layout(g, len(data))
|
|
276
|
+
hdr_job = ThreadPoolExecutor(1).submit(M24BF16GPU._header_c, data, g, layout)
|
|
277
|
+
host = np.frombuffer(data, np.uint8)
|
|
278
|
+
groups = self._groups(layout)
|
|
279
|
+
resident = sum(nb for _, nb, _, _ in layout["t"]) + 2 * self.group_bytes < self.budget
|
|
280
|
+
nt = len(layout["t"])
|
|
281
|
+
rfi_l, cfi_l, scl_l = [None] * nt, [None] * nt, [None] * nt
|
|
282
|
+
nrows_c, rowmaps, dup_pairs = {}, {}, {}
|
|
283
|
+
counts = cp.zeros((layout["nroles"] * TPT, 256), cp.uint32)
|
|
284
|
+
devs, plans = {}, {}
|
|
285
|
+
rmap_all = []
|
|
286
|
+
ev("parse")
|
|
287
|
+
# pass 1: statistics, duplicate rows, histograms
|
|
288
|
+
for gi, grp in enumerate(groups):
|
|
289
|
+
a, b = layout["t"][grp[0]][0], layout["t"][grp[-1]][0] + layout["t"][grp[-1]][1]
|
|
290
|
+
dev = cp.asarray(host[a:b])
|
|
291
|
+
rmap_off = {}
|
|
292
|
+
for i in grp:
|
|
293
|
+
off, nb, rl, _ = layout["t"][i]
|
|
294
|
+
d = dev[off - a:off - a + nb]
|
|
295
|
+
rfi_l[i], cfi_l[i], scl_l[i] = self._stats(d, rl)
|
|
296
|
+
keep, pairs = self._dups(d, rl, host[off:off + nb].view(np.uint16)) if self.dedup else (None, [])
|
|
297
|
+
nrows_c[i] = nb // 2 // rl if keep is None else len(keep)
|
|
298
|
+
if keep is not None:
|
|
299
|
+
rmap_off[i] = sum(len(x) for x in rmap_all); rmap_all.append(keep)
|
|
300
|
+
dup_pairs[i] = pairs
|
|
301
|
+
rowmaps[gi] = rmap_off
|
|
302
|
+
plans[gi] = self._plan(layout, gi, grp, nrows_c, rmap_off)
|
|
303
|
+
if gi == 0:
|
|
304
|
+
pass
|
|
305
|
+
devs[gi] = (dev, a) if resident else (None, a)
|
|
306
|
+
rfi = cp.concatenate(rfi_l); cfi = cp.concatenate(cfi_l); scl = cp.concatenate(scl_l)
|
|
307
|
+
rowmap = cp.asarray(np.concatenate(rmap_all)) if rmap_all else cp.zeros(1, cp.int32)
|
|
308
|
+
ev("statistics + dedup")
|
|
309
|
+
for gi, grp in enumerate(groups):
|
|
310
|
+
dev, a = devs[gi]
|
|
311
|
+
if dev is None:
|
|
312
|
+
b = layout["t"][grp[-1]][0] + layout["t"][grp[-1]][1]; dev = cp.asarray(host[a:b])
|
|
313
|
+
tb, sg = plans[gi]
|
|
314
|
+
kern("v2_hist")(((len(sg) + 63) // 64,), (64,),
|
|
315
|
+
(dev, cp.asarray(tb.view(np.uint8)), cp.asarray(sg.view(np.uint8)), np.int32(len(sg)),
|
|
316
|
+
rfi, cfi, scl, rowmap, counts))
|
|
317
|
+
ev("histogram")
|
|
318
|
+
self.last_counts = counts.get()
|
|
319
|
+
freq, used = normalize_gpu(counts, 1 << PB)
|
|
320
|
+
remap = cp.full(counts.shape[0], -1, cp.int32); remap[used] = cp.arange(len(used), dtype=cp.int32)
|
|
321
|
+
cum = cum_of(freq)
|
|
322
|
+
streams, lens_all = [], []
|
|
323
|
+
cap = SEG * 2 + 1024
|
|
324
|
+
for gi, grp in enumerate(groups):
|
|
325
|
+
dev, a = devs[gi]
|
|
326
|
+
if dev is None:
|
|
327
|
+
b = layout["t"][grp[-1]][0] + layout["t"][grp[-1]][1]; dev = cp.asarray(host[a:b])
|
|
328
|
+
tb, sg = plans[gi]
|
|
329
|
+
out = cp.empty(len(sg) * cap, cp.uint8); out_len = cp.zeros(len(sg), cp.uint32)
|
|
330
|
+
kern("v2_enc")(((len(sg) + 63) // 64,), (64,),
|
|
331
|
+
(dev, cp.asarray(tb.view(np.uint8)), cp.asarray(sg.view(np.uint8)), np.int32(len(sg)),
|
|
332
|
+
rfi, cfi, scl, rowmap, remap, freq, cum, out, np.uint64(cap), out_len))
|
|
333
|
+
lens = out_len.get()
|
|
334
|
+
if (lens == 0xffffffff).any():
|
|
335
|
+
raise RuntimeError("rANS segment overflow")
|
|
336
|
+
offs = cp.zeros(len(sg) + 1, cp.uint64); offs[1:] = cp.cumsum(out_len.astype(cp.uint64))
|
|
337
|
+
dst = cp.empty(int(offs[-1]), cp.uint8)
|
|
338
|
+
_g2.kern("gather")((len(sg),), (256,), (out, np.uint64(cap), out_len, offs, np.int32(len(sg)), dst))
|
|
339
|
+
streams.append(dst.get().tobytes()); lens_all.append(lens)
|
|
340
|
+
del out, dst
|
|
341
|
+
devs[gi] = None
|
|
342
|
+
ev("encode")
|
|
343
|
+
dups = [[i, r, s] for i, ps in dup_pairs.items() for r, s in ps]
|
|
344
|
+
meta = dict(layout=layout, dups=dups, nrows_c=[nrows_c[i] for i in range(nt)])
|
|
345
|
+
ch = {
|
|
346
|
+
"meta": zstd_c(json.dumps(meta).encode()),
|
|
347
|
+
"side": zstd_c(rfi.get().tobytes() + cfi.get().tobytes() + scl.get().tobytes(), 19),
|
|
348
|
+
"tables": store_tables(freq, used),
|
|
349
|
+
"lens": zstd_c(np.concatenate(lens_all).astype(np.uint32).tobytes()),
|
|
350
|
+
"stream": b"".join(streams),
|
|
351
|
+
"rest": hdr_job.result(),
|
|
352
|
+
}
|
|
353
|
+
ev("header")
|
|
354
|
+
self.timing["compress"] = ev.parts
|
|
355
|
+
return pack(ch)
|
|
356
|
+
|
|
357
|
+
# ---------------------------------------------------------------- decompression
|
|
358
|
+
def decompress(self, buf):
|
|
359
|
+
ev = Timer()
|
|
360
|
+
ch = unpack(buf)
|
|
361
|
+
meta = json.loads(zstd_d(ch["meta"]))
|
|
362
|
+
layout = meta["layout"]; nt = len(layout["t"])
|
|
363
|
+
hdr_job = ThreadPoolExecutor(1).submit(M24BF16GPU._header_d, ch["rest"])
|
|
364
|
+
_, _, nrow, ncol = self._bases(layout)
|
|
365
|
+
side = zstd_d(ch["side"])
|
|
366
|
+
rfi = cp.asarray(np.frombuffer(side, np.int16, nrow, 0))
|
|
367
|
+
cfi = cp.asarray(np.frombuffer(side, np.int16, ncol, 2 * nrow))
|
|
368
|
+
scl = cp.asarray(np.frombuffer(side, np.int8, ncol, 2 * nrow + 2 * ncol))
|
|
369
|
+
freq_h, used_h = load_tables(ch["tables"])
|
|
370
|
+
freq = cp.asarray(freq_h); cum = cum_of(freq)
|
|
371
|
+
lut = cp.empty((len(freq_h), 1 << PB), cp.uint8)
|
|
372
|
+
kern("build_lut")((len(freq_h),), (256,), (cum, np.int32(len(freq_h)), lut))
|
|
373
|
+
remap = cp.full(layout["nroles"] * TPT, -1, cp.int32); remap[cp.asarray(used_h)] = cp.arange(len(used_h), dtype=cp.int32)
|
|
374
|
+
lens = np.frombuffer(zstd_d(ch["lens"]), np.uint32)
|
|
375
|
+
nrows_c = {i: n for i, n in enumerate(meta["nrows_c"])}
|
|
376
|
+
dups = {}
|
|
377
|
+
for i, r, s in meta["dups"]:
|
|
378
|
+
dups.setdefault(i, []).append((r, s))
|
|
379
|
+
# row maps (same construction order as the encoder)
|
|
380
|
+
rmap_all, rmap_off_t = [], {}
|
|
381
|
+
for i in range(nt):
|
|
382
|
+
if i in dups:
|
|
383
|
+
rl = layout["t"][i][2]; nr = layout["t"][i][1] // 2 // rl
|
|
384
|
+
isdup = np.zeros(nr, bool); isdup[[r for r, _ in dups[i]]] = True
|
|
385
|
+
rmap_off_t[i] = sum(len(x) for x in rmap_all); rmap_all.append(np.flatnonzero(~isdup).astype(np.int32))
|
|
386
|
+
rowmap = cp.asarray(np.concatenate(rmap_all)) if rmap_all else cp.zeros(1, cp.int32)
|
|
387
|
+
out = np.empty(layout["size"], np.uint8)
|
|
388
|
+
stream_h = np.frombuffer(ch["stream"], np.uint8)
|
|
389
|
+
ev("unpack")
|
|
390
|
+
spos, lpos = 0, 0
|
|
391
|
+
for gi, grp in enumerate(self._groups(layout)):
|
|
392
|
+
rmap_off = {i: rmap_off_t[i] for i in grp if i in rmap_off_t}
|
|
393
|
+
tb, sg = self._plan(layout, gi, grp, nrows_c, rmap_off)
|
|
394
|
+
gl = lens[lpos:lpos + len(sg)]; lpos += len(sg)
|
|
395
|
+
nbytes = int(gl.sum(dtype=np.uint64))
|
|
396
|
+
offs = np.zeros(len(sg), np.uint64); offs[1:] = np.cumsum(gl.astype(np.uint64))[:-1]
|
|
397
|
+
a = layout["t"][grp[0]][0]; b = layout["t"][grp[-1]][0] + layout["t"][grp[-1]][1]
|
|
398
|
+
dev = cp.empty(b - a, cp.uint8)
|
|
399
|
+
kern("v2_dec")(((len(sg) + 63) // 64,), (64,),
|
|
400
|
+
(cp.asarray(stream_h[spos:spos + nbytes]), cp.asarray(offs), dev,
|
|
401
|
+
cp.asarray(tb.view(np.uint8)), cp.asarray(sg.view(np.uint8)), np.int32(len(sg)),
|
|
402
|
+
rfi, cfi, scl, rowmap, remap, freq, cum, lut))
|
|
403
|
+
spos += nbytes
|
|
404
|
+
for i in grp:
|
|
405
|
+
if i in dups:
|
|
406
|
+
off, nb, rl, _ = layout["t"][i]
|
|
407
|
+
u = dev[off - a:off - a + nb].view(cp.uint16).reshape(-1, rl)
|
|
408
|
+
d = np.array(dups[i], np.int64)
|
|
409
|
+
u[cp.asarray(d[:, 0])] = u[cp.asarray(d[:, 1])]
|
|
410
|
+
dev.get(out=out[a:b])
|
|
411
|
+
del dev
|
|
412
|
+
ev("decode + download")
|
|
413
|
+
rest = np.frombuffer(hdr_job.result(), np.uint8)
|
|
414
|
+
pos = rpos = 0
|
|
415
|
+
for off, nbytes, _, _ in layout["t"]:
|
|
416
|
+
gap = off - pos
|
|
417
|
+
out[pos:off] = rest[rpos:rpos + gap]; rpos += gap; pos = off + nbytes
|
|
418
|
+
out[pos:] = rest[rpos:]
|
|
419
|
+
ev("header")
|
|
420
|
+
self.timing["decompress"] = ev.parts
|
|
421
|
+
return out
|
seedpack/bundle.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Method 23: self-contained archive of a model *repository* (several files of one model).
|
|
2
|
+
|
|
3
|
+
The BF16 original is coded with M22; every quantised file of the same model is then coded
|
|
4
|
+
relative to the BF16 weights that are already inside the same archive (refcodec predictor:
|
|
5
|
+
re-quantise + context-coded correction). The receiver needs nothing but the archive.
|
|
6
|
+
"""
|
|
7
|
+
import struct
|
|
8
|
+
|
|
9
|
+
from .codecs_gguf import pack, unpack
|
|
10
|
+
from .bf16codec import M22BF16
|
|
11
|
+
from .gguf_reader import GGUF
|
|
12
|
+
from .refcodec import RefCodec, sha
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _InArchiveRef(RefCodec):
|
|
16
|
+
def __init__(self, ref_bytes):
|
|
17
|
+
super().__init__([])
|
|
18
|
+
self._refs = [(GGUF.from_bytes(ref_bytes), sha(ref_bytes))]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class M23Bundle:
|
|
22
|
+
name = "M23 model-repo bundle: BF16 (M22) + quants coded against it"
|
|
23
|
+
|
|
24
|
+
def compress_files(self, base: bytes, others: list) -> bytes:
|
|
25
|
+
ch = {"base": M22BF16().compress(base)}
|
|
26
|
+
rc = _InArchiveRef(base)
|
|
27
|
+
for i, d in enumerate(others):
|
|
28
|
+
ch[f"q{i}"] = rc.compress(d)
|
|
29
|
+
return pack(ch)
|
|
30
|
+
|
|
31
|
+
def decompress_files(self, buf: bytes):
|
|
32
|
+
ch = unpack(buf)
|
|
33
|
+
base = M22BF16().decompress(ch["base"]).tobytes()
|
|
34
|
+
rc = _InArchiveRef(base)
|
|
35
|
+
others = [rc.decompress(ch[k]) for k in sorted(k for k in ch if k.startswith("q"))]
|
|
36
|
+
return base, others
|