nx_f32_llama_layer_lazy_load.nx source
↩ module page · 323 lines · 14871 B
1// nx_f32_llama_layer_lazy_load.nx -- bind one layer's 9 tensors into
2// NxF32LlamaLayerLazy.
3//
4// For each tensor:
5// * F32 source -> dequant once into f32 storage, wrap as
6// NxF32LazyWeight tagged F32.
7// * F16 source -> widen to f32, store, tag F32.
8// * Q4_K source -> DO NOT DEQUANT. Record the GGUF buffer + byte
9// offset directly, tag Q4_K. The forward path (v4 block) will
10// stream Q4_K super-blocks during matmul.
11//
12// gamma_attn / gamma_ffn (RMSNorm scales) are always loaded as f32
13// raw bits (they're 1D vectors, small).
14//
15// genealogy_id: ggml_format_taxonomy + standard_layer_binding
16// lineage_id: substrate_f32_llama_layer_lazy_load_v1
17
18import "nx_syscalls.nx"
19import "nx_tier.nx"
20import "nx_dec_emit.nx"
21import "nx_le.nx"
22import "nx_gguf.nx"
23import "nx_gguf_load.nx"
24import "nx_gguf_load_f32.nx"
25import "nx_f32_cvt.nx"
26import "nx_f32_lazy_weight.nx"
27import "nx_f32_llama_block_v4.nx"
28import "nx_q5_k_to_f32.nx"
29import "nx_q6_k_to_f32.nx"
30import "nx_q4k_to_f32.nx"
31import "nx_q8_0_to_f32.nx"
32import "nx_q8_0_from_q5_0.nx"
33import "nx_q8_0_from_f32.nx"
34
35const NX_FLLL_OK: nx_int = 0
36const NX_FLLL_ERR_BAD_LAYER: nx_int = 1
37const NX_FLLL_ERR_NOT_FOUND: nx_int = 2
38const NX_FLLL_ERR_NULL: nx_int = 3
39const NX_FLLL_ERR_BAD_TYPE: nx_int = 4
40const NX_FLLL_N_VERDICTS: nx_int = 5
41
42func nx_flll_verdict_is_valid(v: nx_int) -> nx_int {
43 if v < 0 { return 0 }
44 if v >= NX_FLLL_N_VERDICTS { return 0 }
45 return 1
46}
47
48func _flll_fmt_name(layer_idx: nx_int, suffix: *u8, suffix_len: nx_int,
49 name_out: *u8) -> nx_int {
50 name_out[0] = 0x62 as u8
51 name_out[1] = 0x6c as u8
52 name_out[2] = 0x6b as u8
53 name_out[3] = 0x2e as u8
54 let li_len: i64 = nx_dec_emit_u63(name_out, 4, layer_idx as i64)
55 let after_idx: nx_int = 4 + (li_len as nx_int)
56 name_out[after_idx] = 0x2e as u8
57 var i: nx_int = 0
58 while i < suffix_len {
59 name_out[after_idx + 1 + i] = suffix[i]
60 i = i + 1
61 }
62 return after_idx + 1 + suffix_len
63}
64
65// Build a NxF32LazyWeight for a named tensor. F32/F16 -> eager f32;
66// Q4_K -> record offset only. Returns 0 on not-found.
67
68func _flll_build_lazy(buf: *u8, hdr: *NxGgufHeader,
69 name: *u8, name_len: nx_int) -> *NxF32LazyWeight {
70 let idx: nx_int = nx_gguf_find_tensor(hdr, name, name_len)
71 if idx < 0 { return 0 as *NxF32LazyWeight }
72 let ti: *NxGgufTensorInfo = nx_gguf_tensor_at(hdr, idx)
73
74 // Dims: tensor info stores up to 4 dims; we want rows/cols.
75 let rows: nx_int = ti.dim_0 as nx_int
76 var cols: nx_int = 1
77 if ti.n_dims >= 2 { cols = ti.dim_1 as nx_int }
78
79 let data_off: i64 = hdr.data_off + ti.offset
80
81 if ti.ggml_type == NX_GGML_TYPE_Q4_K {
82 // LAZY: keep the Q4_K bytes + offset; the fixed streaming nx_f32_q4k_matmul (fq4m_rows) dequants one
83 // output row at a time so the weight stays quantized in memory (a 7B = ~4.5GB, not ~28GB f32). The
84 // earlier eager-dequant here was a memory-blowup shortcut; the streaming kernel is now correct.
85 return nx_f32_lazy_weight_new_q4k(buf, data_off, rows, cols)
86 }
87 if ti.ggml_type == NX_GGML_TYPE_Q8_0 {
88 // LAZY (2026-07-08): keep Q8_0 quantized -> the dispatcher's SIMD
89 // __f32_i8dot32 dequant-dot (PROVEN 10.2x). This model has NO Q8_0
90 // BLOCK weights (they're Q5_0; Q8_0 is only embed/lm_head), so this
91 // is a NO-OP here -- but a Q8_0-quantized model runs EVERY block
92 // matmul through the SIMD path with zero further work. k is 32-aligned
93 // for all LLM reduction dims.
94 return nx_f32_lazy_weight_new_q8_0(buf, data_off, rows, cols)
95 }
96 if ti.ggml_type == NX_GGML_TYPE_Q5_0 {
97 // ★ RE-QUANTIZE Q5_0 -> Q8_0 ONCE AT LOAD (2026-07-08). Q5_0->Q8_0 is
98 // EXACT (5-bit vals -16..15 fit int8, same per-block f16 d). This
99 // AMORTIZES the nibble+qh unpack to load-time (the very cost that made
100 // a per-token Q5_0 SIMD dequant-dot 2x SLOWER) so the forward then runs
101 // the TRIVIAL Q8_0 SIMD dequant-dot (__f32_i8dot32, PROVEN 10.2x) on
102 // ALL 79%-Q5_0 weights. RAM 1.5x the Q5_0 bytes (still << F32 eager).
103 let nvq: i64 = nx_gguf_tensor_n_values(ti)
104 let nblkq: i64 = (nvq + NX_Q8_0_VPB - 1) / NX_Q8_0_VPB
105 let q8buf: *u8 = sys_mmap(nblkq * NX_Q8_0_BPB)
106 nx_q8_0_from_q5_0(buf, data_off, nvq, q8buf)
107 return nx_f32_lazy_weight_new_q8_0(q8buf, 0, rows, cols)
108 }
109 if ti.ggml_type == NX_GGML_TYPE_F32 {
110 let nv: i64 = nx_gguf_tensor_n_values(ti)
111 let storage: *i64 = sys_mmap(nv * 8) as *i64
112 var i: i64 = 0
113 while i < nv {
114 storage[i] = nx_le_read_u32(buf, data_off + i * 4)
115 i = i + 1
116 }
117 return nx_f32_lazy_weight_new_f32(storage, rows, cols)
118 }
119 if ti.ggml_type == NX_GGML_TYPE_F16 {
120 let nv: i64 = nx_gguf_tensor_n_values(ti)
121 let storage: *i64 = sys_mmap(nv * 8) as *i64
122 var i2: i64 = 0
123 while i2 < nv {
124 let raw_f16: i64 = nx_le_read_u16(buf, data_off + i2 * 2)
125 storage[i2] = nx_f16_to_f32(raw_f16)
126 i2 = i2 + 1
127 }
128 return nx_f32_lazy_weight_new_f32(storage, rows, cols)
129 }
130 if ti.ggml_type == NX_GGML_TYPE_Q5_K {
131 let nv5: i64 = nx_gguf_tensor_n_values(ti)
132 let st5: *i64 = sys_mmap(nv5 * 8) as *i64
133 nx_q5_k_to_f32(buf, data_off, nv5, st5)
134 return nx_f32_lazy_weight_new_f32(st5, rows, cols)
135 }
136 if ti.ggml_type == NX_GGML_TYPE_Q6_K {
137 // dequant Q6_K -> F32, then re-quantize -> Q8_0 (near-lossless: 8-bit >=
138 // 6-bit) so this 8% runs the SIMD Q8_0 dequant-dot too -> FULLY-Q8_0
139 // block matmul. Q8_0 temp replaces the F32 temp (freed).
140 let nv6: i64 = nx_gguf_tensor_n_values(ti)
141 let st6: *i64 = sys_mmap(nv6 * 8) as *i64
142 nx_q6_k_to_f32(buf, data_off, nv6, st6)
143 let nb6: i64 = (nv6 + NX_Q8_0_VPB - 1) / NX_Q8_0_VPB
144 let q86: *u8 = sys_mmap(nb6 * NX_Q8_0_BPB)
145 nx_q8_0_from_f32(st6, nv6, q86)
146 sys_munmap(st6, nv6 * 8)
147 return nx_f32_lazy_weight_new_q8_0(q86, 0, rows, cols)
148 }
149 // Q5_0 / Q8_0: eager dequant via the unified loader (which
150 // handles all 6 supported types). Wraps result as F32 lazy weight.
151 let nv_out: *i64 = sys_mmap(8) as *i64
152 let inner_err: *i64 = sys_mmap(8) as *i64
153 let name_buf: *u8 = sys_mmap(64)
154 var n_len: nx_int = 0
155 var k: nx_int = 0
156 while k < ti.name_len {
157 name_buf[k] = ti.name[k]
158 n_len = n_len + 1
159 k = k + 1
160 }
161 let storage: *i64 = nx_gguf_load_tensor_to_f32(buf, hdr, name_buf, n_len,
162 nv_out, inner_err)
163 if inner_err[0] != NX_GLF_OK { return 0 as *NxF32LazyWeight }
164 return nx_f32_lazy_weight_new_f32(storage, rows, cols)
165}
166
167// Load a 1-D f32 gamma vector (RMSNorm scale) into a raw *i64.
168
169func _flll_load_gamma(buf: *u8, hdr: *NxGgufHeader,
170 name: *u8, name_len: nx_int) -> *i64 {
171 let n_out: *i64 = sys_mmap(8) as *i64
172 let err: *i64 = sys_mmap(8) as *i64
173 let storage: *i64 = nx_gguf_load_tensor_to_f32(buf, hdr, name, name_len,
174 n_out, err)
175 if err[0] != NX_GLF_OK { return 0 as *i64 }
176 return storage
177}
178
179// Public: populate NxF32LlamaLayerLazy by loading all 9 tensors for layer_idx.
180
181func nx_f32_llama_layer_lazy_load_from_gguf(buf: *u8, hdr: *NxGgufHeader,
182 layer_idx: nx_int,
183 layer_out: *NxF32LlamaLayerLazy,
184 out_err: *i64) -> nx_int {
185 if layer_idx < 0 {
186 out_err[0] = NX_FLLL_ERR_BAD_LAYER
187 return NX_FLLL_ERR_BAD_LAYER
188 }
189 if layer_out == (0 as *NxF32LlamaLayerLazy) {
190 out_err[0] = NX_FLLL_ERR_NULL
191 return NX_FLLL_ERR_NULL
192 }
193
194 // Suffix byte arrays (mirror nx_f32_llama_layer_load).
195 let s_an: *u8 = sys_mmap(16)
196 s_an[0]=0x61 as u8; s_an[1]=0x74 as u8; s_an[2]=0x74 as u8; s_an[3]=0x6e as u8
197 s_an[4]=0x5f as u8; s_an[5]=0x6e as u8; s_an[6]=0x6f as u8; s_an[7]=0x72 as u8
198 s_an[8]=0x6d as u8; s_an[9]=0x2e as u8; s_an[10]=0x77 as u8; s_an[11]=0x65 as u8
199 s_an[12]=0x69 as u8; s_an[13]=0x67 as u8; s_an[14]=0x68 as u8; s_an[15]=0x74 as u8
200
201 let s_q: *u8 = sys_mmap(13)
202 s_q[0]=0x61 as u8; s_q[1]=0x74 as u8; s_q[2]=0x74 as u8; s_q[3]=0x6e as u8
203 s_q[4]=0x5f as u8; s_q[5]=0x71 as u8; s_q[6]=0x2e as u8; s_q[7]=0x77 as u8
204 s_q[8]=0x65 as u8; s_q[9]=0x69 as u8; s_q[10]=0x67 as u8; s_q[11]=0x68 as u8
205 s_q[12]=0x74 as u8
206
207 let s_k: *u8 = sys_mmap(13)
208 s_k[0]=0x61 as u8; s_k[1]=0x74 as u8; s_k[2]=0x74 as u8; s_k[3]=0x6e as u8
209 s_k[4]=0x5f as u8; s_k[5]=0x6b as u8; s_k[6]=0x2e as u8; s_k[7]=0x77 as u8
210 s_k[8]=0x65 as u8; s_k[9]=0x69 as u8; s_k[10]=0x67 as u8; s_k[11]=0x68 as u8
211 s_k[12]=0x74 as u8
212
213 let s_v: *u8 = sys_mmap(13)
214 s_v[0]=0x61 as u8; s_v[1]=0x74 as u8; s_v[2]=0x74 as u8; s_v[3]=0x6e as u8
215 s_v[4]=0x5f as u8; s_v[5]=0x76 as u8; s_v[6]=0x2e as u8; s_v[7]=0x77 as u8
216 s_v[8]=0x65 as u8; s_v[9]=0x69 as u8; s_v[10]=0x67 as u8; s_v[11]=0x68 as u8
217 s_v[12]=0x74 as u8
218
219 let s_o: *u8 = sys_mmap(18)
220 s_o[0]=0x61 as u8; s_o[1]=0x74 as u8; s_o[2]=0x74 as u8; s_o[3]=0x6e as u8
221 s_o[4]=0x5f as u8; s_o[5]=0x6f as u8; s_o[6]=0x75 as u8; s_o[7]=0x74 as u8
222 s_o[8]=0x70 as u8; s_o[9]=0x75 as u8; s_o[10]=0x74 as u8; s_o[11]=0x2e as u8
223 s_o[12]=0x77 as u8; s_o[13]=0x65 as u8; s_o[14]=0x69 as u8; s_o[15]=0x67 as u8
224 s_o[16]=0x68 as u8; s_o[17]=0x74 as u8
225
226 let s_fn: *u8 = sys_mmap(15)
227 s_fn[0]=0x66 as u8; s_fn[1]=0x66 as u8; s_fn[2]=0x6e as u8; s_fn[3]=0x5f as u8
228 s_fn[4]=0x6e as u8; s_fn[5]=0x6f as u8; s_fn[6]=0x72 as u8; s_fn[7]=0x6d as u8
229 s_fn[8]=0x2e as u8; s_fn[9]=0x77 as u8; s_fn[10]=0x65 as u8; s_fn[11]=0x69 as u8
230 s_fn[12]=0x67 as u8; s_fn[13]=0x68 as u8; s_fn[14]=0x74 as u8
231
232 let s_fg: *u8 = sys_mmap(15)
233 s_fg[0]=0x66 as u8; s_fg[1]=0x66 as u8; s_fg[2]=0x6e as u8; s_fg[3]=0x5f as u8
234 s_fg[4]=0x67 as u8; s_fg[5]=0x61 as u8; s_fg[6]=0x74 as u8; s_fg[7]=0x65 as u8
235 s_fg[8]=0x2e as u8; s_fg[9]=0x77 as u8; s_fg[10]=0x65 as u8; s_fg[11]=0x69 as u8
236 s_fg[12]=0x67 as u8; s_fg[13]=0x68 as u8; s_fg[14]=0x74 as u8
237
238 let s_fu: *u8 = sys_mmap(13)
239 s_fu[0]=0x66 as u8; s_fu[1]=0x66 as u8; s_fu[2]=0x6e as u8; s_fu[3]=0x5f as u8
240 s_fu[4]=0x75 as u8; s_fu[5]=0x70 as u8; s_fu[6]=0x2e as u8; s_fu[7]=0x77 as u8
241 s_fu[8]=0x65 as u8; s_fu[9]=0x69 as u8; s_fu[10]=0x67 as u8; s_fu[11]=0x68 as u8
242 s_fu[12]=0x74 as u8
243
244 let s_fd: *u8 = sys_mmap(15)
245 s_fd[0]=0x66 as u8; s_fd[1]=0x66 as u8; s_fd[2]=0x6e as u8; s_fd[3]=0x5f as u8
246 s_fd[4]=0x64 as u8; s_fd[5]=0x6f as u8; s_fd[6]=0x77 as u8; s_fd[7]=0x6e as u8
247 s_fd[8]=0x2e as u8; s_fd[9]=0x77 as u8; s_fd[10]=0x65 as u8; s_fd[11]=0x69 as u8
248 s_fd[12]=0x67 as u8; s_fd[13]=0x68 as u8; s_fd[14]=0x74 as u8
249
250 // Qwen2 attention biases: "attn_q.bias" / "attn_k.bias" / "attn_v.bias" (11 bytes each).
251 let s_bq: *u8 = sys_mmap(11)
252 s_bq[0]=0x61 as u8; s_bq[1]=0x74 as u8; s_bq[2]=0x74 as u8; s_bq[3]=0x6e as u8
253 s_bq[4]=0x5f as u8; s_bq[5]=0x71 as u8; s_bq[6]=0x2e as u8; s_bq[7]=0x62 as u8
254 s_bq[8]=0x69 as u8; s_bq[9]=0x61 as u8; s_bq[10]=0x73 as u8
255
256 let s_bk: *u8 = sys_mmap(11)
257 s_bk[0]=0x61 as u8; s_bk[1]=0x74 as u8; s_bk[2]=0x74 as u8; s_bk[3]=0x6e as u8
258 s_bk[4]=0x5f as u8; s_bk[5]=0x6b as u8; s_bk[6]=0x2e as u8; s_bk[7]=0x62 as u8
259 s_bk[8]=0x69 as u8; s_bk[9]=0x61 as u8; s_bk[10]=0x73 as u8
260
261 let s_bv: *u8 = sys_mmap(11)
262 s_bv[0]=0x61 as u8; s_bv[1]=0x74 as u8; s_bv[2]=0x74 as u8; s_bv[3]=0x6e as u8
263 s_bv[4]=0x5f as u8; s_bv[5]=0x76 as u8; s_bv[6]=0x2e as u8; s_bv[7]=0x62 as u8
264 s_bv[8]=0x69 as u8; s_bv[9]=0x61 as u8; s_bv[10]=0x73 as u8
265
266 let name_buf: *u8 = sys_mmap(64)
267
268 // gamma_attn (1D)
269 let n_an: nx_int = _flll_fmt_name(layer_idx, s_an, 16, name_buf)
270 layer_out.gamma_attn = _flll_load_gamma(buf, hdr, name_buf, n_an)
271 if (layer_out.gamma_attn as i64) == 0 {
272 out_err[0] = NX_FLLL_ERR_NOT_FOUND
273 return NX_FLLL_ERR_NOT_FOUND
274 }
275
276 // W_q (2D, possibly Q4_K)
277 let n_q: nx_int = _flll_fmt_name(layer_idx, s_q, 13, name_buf)
278 layer_out.W_q = _flll_build_lazy(buf, hdr, name_buf, n_q)
279 if (layer_out.W_q as i64) == 0 {
280 out_err[0] = NX_FLLL_ERR_NOT_FOUND
281 return NX_FLLL_ERR_NOT_FOUND
282 }
283
284 let n_k: nx_int = _flll_fmt_name(layer_idx, s_k, 13, name_buf)
285 layer_out.W_k = _flll_build_lazy(buf, hdr, name_buf, n_k)
286 if (layer_out.W_k as i64) == 0 { out_err[0] = NX_FLLL_ERR_NOT_FOUND; return NX_FLLL_ERR_NOT_FOUND }
287
288 let n_v: nx_int = _flll_fmt_name(layer_idx, s_v, 13, name_buf)
289 layer_out.W_v = _flll_build_lazy(buf, hdr, name_buf, n_v)
290 if (layer_out.W_v as i64) == 0 { out_err[0] = NX_FLLL_ERR_NOT_FOUND; return NX_FLLL_ERR_NOT_FOUND }
291
292 let n_o: nx_int = _flll_fmt_name(layer_idx, s_o, 18, name_buf)
293 layer_out.W_o = _flll_build_lazy(buf, hdr, name_buf, n_o)
294 if (layer_out.W_o as i64) == 0 { out_err[0] = NX_FLLL_ERR_NOT_FOUND; return NX_FLLL_ERR_NOT_FOUND }
295
296 let n_fn: nx_int = _flll_fmt_name(layer_idx, s_fn, 15, name_buf)
297 layer_out.gamma_ffn = _flll_load_gamma(buf, hdr, name_buf, n_fn)
298 if (layer_out.gamma_ffn as i64) == 0 { out_err[0] = NX_FLLL_ERR_NOT_FOUND; return NX_FLLL_ERR_NOT_FOUND }
299
300 let n_fg: nx_int = _flll_fmt_name(layer_idx, s_fg, 15, name_buf)
301 layer_out.W_gate = _flll_build_lazy(buf, hdr, name_buf, n_fg)
302 if (layer_out.W_gate as i64) == 0 { out_err[0] = NX_FLLL_ERR_NOT_FOUND; return NX_FLLL_ERR_NOT_FOUND }
303
304 let n_fu: nx_int = _flll_fmt_name(layer_idx, s_fu, 13, name_buf)
305 layer_out.W_up = _flll_build_lazy(buf, hdr, name_buf, n_fu)
306 if (layer_out.W_up as i64) == 0 { out_err[0] = NX_FLLL_ERR_NOT_FOUND; return NX_FLLL_ERR_NOT_FOUND }
307
308 let n_fd: nx_int = _flll_fmt_name(layer_idx, s_fd, 15, name_buf)
309 layer_out.W_down = _flll_build_lazy(buf, hdr, name_buf, n_fd)
310 if (layer_out.W_down as i64) == 0 { out_err[0] = NX_FLLL_ERR_NOT_FOUND; return NX_FLLL_ERR_NOT_FOUND }
311
312 // Qwen2 attention biases (1D f32). NOT an error if absent -- Llama-style models have none;
313 // block_v4 guards on (bias_q != 0). This was the DROPPED TERM behind the garbage forward.
314 let n_bq: nx_int = _flll_fmt_name(layer_idx, s_bq, 11, name_buf)
315 layer_out.bias_q = _flll_load_gamma(buf, hdr, name_buf, n_bq)
316 let n_bk: nx_int = _flll_fmt_name(layer_idx, s_bk, 11, name_buf)
317 layer_out.bias_k = _flll_load_gamma(buf, hdr, name_buf, n_bk)
318 let n_bv: nx_int = _flll_fmt_name(layer_idx, s_bv, 11, name_buf)
319 layer_out.bias_v = _flll_load_gamma(buf, hdr, name_buf, n_bv)
320
321 out_err[0] = NX_FLLL_OK
322 return NX_FLLL_OK
323}