nx_gguf_load_model_test.nx source
↩ module page · 185 lines · 7488 B
1// nx_gguf_load_model_test.nx -- smoke for nx_gguf_load_model.nx.
2//
3// Builds two synthetic GGUFs:
4// A) Full model (3 tensors): token_embd + output_norm + output
5// B) Tied-embedding model (2 tensors): token_embd + output_norm
6// (no output.weight; caller expected to reuse token_embd)
7//
8// Verifies:
9// - Bundle struct populated correctly when all 3 tensors present
10// - is_output_tied flag and null output_weight when output.weight
11// is missing
12// - Verdict-range gate
13
14import "nx_syscalls.nx"
15import "nx_tier.nx"
16import "nx_le.nx"
17import "nx_tensor.nx"
18import "nx_gguf.nx"
19import "nx_gguf_load.nx"
20import "nx_gguf_load_model.nx"
21
22// Helper: write a tensor_info entry at a given offset.
23// Returns the offset AFTER this entry.
24func _write_ti(buf: *u8, off: i64,
25 name: *u8, name_len: i64,
26 n_dims: i64, dim_0: i64, dim_1: i64,
27 ggml_type: i64, data_offset: i64) -> i64 {
28 nx_le_write_u64(buf, off, name_len)
29 var o: i64 = off + 8
30 var i: i64 = 0
31 while i < name_len { buf[o + i] = name[i]; i = i + 1 }
32 o = o + name_len
33 nx_le_write_u32(buf, o, n_dims); o = o + 4
34 nx_le_write_u64(buf, o, dim_0); o = o + 8
35 if n_dims >= 2 { nx_le_write_u64(buf, o, dim_1); o = o + 8 }
36 nx_le_write_u32(buf, o, ggml_type); o = o + 4
37 nx_le_write_u64(buf, o, data_offset); o = o + 8
38 return o
39}
40
41func main() -> i64 {
42 // ----- Verdict gate -----
43 var vi: nx_int = 0
44 while vi < NX_GML_N_VERDICTS {
45 if nx_gml_verdict_is_valid(vi) != 1 { return 5 + vi }
46 vi = vi + 1
47 }
48
49 // ----- A) Full model: 3 tensors -----
50 let buf_a: *u8 = sys_mmap(2048)
51 buf_a[0]=0x47; buf_a[1]=0x47; buf_a[2]=0x55; buf_a[3]=0x46
52 buf_a[4]=3
53 nx_le_write_u64(buf_a, 8, 3)
54 nx_le_write_u64(buf_a, 16, 0)
55
56 // Tensor names
57 let n_te: *u8 = sys_mmap(17)
58 n_te[0]=0x74; n_te[1]=0x6f; n_te[2]=0x6b; n_te[3]=0x65
59 n_te[4]=0x6e; n_te[5]=0x5f; n_te[6]=0x65; n_te[7]=0x6d
60 n_te[8]=0x62; n_te[9]=0x64; n_te[10]=0x2e; n_te[11]=0x77
61 n_te[12]=0x65; n_te[13]=0x69; n_te[14]=0x67; n_te[15]=0x68
62 n_te[16]=0x74
63
64 let n_on: *u8 = sys_mmap(18)
65 n_on[0]=0x6f; n_on[1]=0x75; n_on[2]=0x74; n_on[3]=0x70
66 n_on[4]=0x75; n_on[5]=0x74; n_on[6]=0x5f; n_on[7]=0x6e
67 n_on[8]=0x6f; n_on[9]=0x72; n_on[10]=0x6d; n_on[11]=0x2e
68 n_on[12]=0x77; n_on[13]=0x65; n_on[14]=0x69; n_on[15]=0x67
69 n_on[16]=0x68; n_on[17]=0x74
70
71 let n_ow: *u8 = sys_mmap(13)
72 n_ow[0]=0x6f; n_ow[1]=0x75; n_ow[2]=0x74; n_ow[3]=0x70
73 n_ow[4]=0x75; n_ow[5]=0x74; n_ow[6]=0x2e; n_ow[7]=0x77
74 n_ow[8]=0x65; n_ow[9]=0x69; n_ow[10]=0x67; n_ow[11]=0x68
75 n_ow[12]=0x74
76
77 // ti[0] token_embd F32 [4,2] (vocab=4, hidden=2) data_off rel = 0
78 var pa: i64 = 24
79 pa = _write_ti(buf_a, pa, n_te, 17, 2, 4, 2, NX_GGML_TYPE_F32, 0)
80 // ti[1] output_norm F32 [2] data_off rel = 32 (4*2*4=32)
81 pa = _write_ti(buf_a, pa, n_on, 18, 1, 2, 1, NX_GGML_TYPE_F32, 32)
82 // ti[2] output F32 [2,4] data_off rel = 40 (32+2*4=40)
83 pa = _write_ti(buf_a, pa, n_ow, 13, 2, 2, 4, NX_GGML_TYPE_F32, 40)
84
85 // data_off = align_up(pa, 32).
86 let data_off_a: i64 = (pa + 31) / 32 * 32
87
88 // token_embd [4,2] = 8 F32 values: 0.5, 1.0, 1.5, 2.0, -0.5, -1.0, -1.5, -2.0
89 nx_le_write_u32(buf_a, data_off_a + 0, 0x3F000000) // 0.5
90 nx_le_write_u32(buf_a, data_off_a + 4, 0x3F800000) // 1.0
91 nx_le_write_u32(buf_a, data_off_a + 8, 0x3FC00000) // 1.5
92 nx_le_write_u32(buf_a, data_off_a + 12, 0x40000000) // 2.0
93 nx_le_write_u32(buf_a, data_off_a + 16, 0xBF000000) // -0.5
94 nx_le_write_u32(buf_a, data_off_a + 20, 0xBF800000) // -1.0
95 nx_le_write_u32(buf_a, data_off_a + 24, 0xBFC00000) // -1.5
96 nx_le_write_u32(buf_a, data_off_a + 28, 0xC0000000) // -2.0
97
98 // output_norm [2] = 1.0, 1.0
99 nx_le_write_u32(buf_a, data_off_a + 32, 0x3F800000)
100 nx_le_write_u32(buf_a, data_off_a + 36, 0x3F800000)
101
102 // output [2,4] = 8 F32 values: 1, 2, 3, 4, 5, 6, 7, 8 (just nonzero markers)
103 nx_le_write_u32(buf_a, data_off_a + 40, 0x3F800000) // 1.0
104 nx_le_write_u32(buf_a, data_off_a + 44, 0x40000000) // 2.0
105 nx_le_write_u32(buf_a, data_off_a + 48, 0x40400000) // 3.0
106 nx_le_write_u32(buf_a, data_off_a + 52, 0x40800000) // 4.0
107 nx_le_write_u32(buf_a, data_off_a + 56, 0x40A00000) // 5.0
108 nx_le_write_u32(buf_a, data_off_a + 60, 0x40C00000) // 6.0
109 nx_le_write_u32(buf_a, data_off_a + 64, 0x40E00000) // 7.0
110 nx_le_write_u32(buf_a, data_off_a + 68, 0x41000000) // 8.0
111
112 let hdr_a: *NxGgufHeader = sys_mmap(NX_GGUF_HDR_BYTES) as *NxGgufHeader
113 let vp_a: nx_int = nx_gguf_parse(buf_a, 2048, hdr_a)
114 if vp_a != NX_GGUF_OK { return 20 + vp_a }
115 if hdr_a.n_tensors != 3 { return 30 }
116
117 let bundle_a: *NxGgufModelWeights = sys_mmap(NX_GML_BUNDLE_BYTES) as *NxGgufModelWeights
118 let err: *i64 = sys_mmap(8) as *i64
119 err[0] = 0
120 let v_a: nx_int = nx_gguf_load_model_weights(buf_a, hdr_a, bundle_a, err)
121 if v_a != NX_GML_OK { return 40 + v_a }
122 if err[0] != NX_GML_OK { return 50 }
123 if bundle_a.is_output_tied != 0 { return 51 }
124 if bundle_a.token_embd.numel != 8 { return 52 }
125 if bundle_a.output_weight.numel != 8 { return 53 }
126
127 let tep: *i64 = bundle_a.token_embd.storage as *i64
128 if tep[0] != 512 { return 60 } // 0.5 -> Q10 512
129 if tep[3] != 2048 { return 61 } // 2.0 -> Q10 2048
130 if tep[4] != (0 - 512) { return 62 }
131 if tep[7] != (0 - 2048) { return 63 }
132
133 if bundle_a.output_norm_gamma[0] != 1024 { return 70 }
134 if bundle_a.output_norm_gamma[1] != 1024 { return 71 }
135
136 let owp: *i64 = bundle_a.output_weight.storage as *i64
137 if owp[0] != 1024 { return 80 } // 1.0
138 if owp[7] != 8192 { return 81 } // 8.0 -> 8192
139
140 // ----- B) Tied-embedding: only 2 tensors (no output.weight) -----
141 let buf_b: *u8 = sys_mmap(2048)
142 buf_b[0]=0x47; buf_b[1]=0x47; buf_b[2]=0x55; buf_b[3]=0x46
143 buf_b[4]=3
144 nx_le_write_u64(buf_b, 8, 2) // 2 tensors
145 nx_le_write_u64(buf_b, 16, 0)
146
147 var pb: i64 = 24
148 pb = _write_ti(buf_b, pb, n_te, 17, 2, 4, 2, NX_GGML_TYPE_F32, 0)
149 pb = _write_ti(buf_b, pb, n_on, 18, 1, 2, 1, NX_GGML_TYPE_F32, 32)
150 let data_off_b: i64 = (pb + 31) / 32 * 32
151
152 // Same data layout for token_embd + output_norm
153 var bi: nx_int = 0
154 while bi < 8 {
155 // Re-use the F32 patterns by copying from buf_a data section
156 var bj: nx_int = 0
157 while bj < 4 {
158 buf_b[data_off_b + bi * 4 + bj] = buf_a[data_off_a + bi * 4 + bj]
159 bj = bj + 1
160 }
161 bi = bi + 1
162 }
163 // output_norm bytes
164 var bk: nx_int = 0
165 while bk < 8 {
166 buf_b[data_off_b + 32 + bk] = buf_a[data_off_a + 32 + bk]
167 bk = bk + 1
168 }
169
170 let hdr_b: *NxGgufHeader = sys_mmap(NX_GGUF_HDR_BYTES) as *NxGgufHeader
171 let vp_b: nx_int = nx_gguf_parse(buf_b, 2048, hdr_b)
172 if vp_b != NX_GGUF_OK { return 90 + vp_b }
173 if hdr_b.n_tensors != 2 { return 100 }
174
175 let bundle_b: *NxGgufModelWeights = sys_mmap(NX_GML_BUNDLE_BYTES) as *NxGgufModelWeights
176 err[0] = 0
177 let v_b: nx_int = nx_gguf_load_model_weights(buf_b, hdr_b, bundle_b, err)
178 if v_b != NX_GML_OK { return 110 + v_b }
179 if err[0] != NX_GML_OK { return 120 }
180 if bundle_b.is_output_tied != 1 { return 121 }
181 if bundle_b.output_weight != (0 as *NxTensor) { return 122 }
182 if bundle_b.token_embd.numel != 8 { return 123 }
183
184 return 0
185}