nx_nofloat_olmoe.nx source
↩ module page · 185 lines · 7629 B
1// nx_nofloat_olmoe.nx -- the faithful OLMoE transformer LAYER in deterministic no-float (MoE rung 4,
2// 2026-07-15). OLMoE-1B-7B blk shape (recon-verified): D=2048, 16 heads x head_dim 128, NO GQA, NO biases,
3// **QK-norm = RMSNorm over the FULL 2048-dim Q and K projections** (gamma[2048], the OLMoE/Qwen3 variant --
4// applied AFTER projection, BEFORE RoPE), RoPE base 1e4, then MoE-FFN (64 experts top-8, lazy). Two
5// sublayers; the caller (gate/serve) does the residual adds + owns all scratch (lean frames, no big-frame
6// GP-fault). Composes ONLY proven primitives: rmsnorm_gamma_row / mm_out_in / rope_apply / fx_exp / silu /
7// qmul / dequant_to_q16 / nf_expert_byteoff. Deterministic by construction (exact integer sums, positional
8// tie-breaks). license_tier: ORIGINAL (lib: no main)
9import "nx_syscalls.nx"
10import "nx_nofloat_llm.nx"
11
12// ATTENTION sublayer -> writes attn projection (PRE-residual) to `out`. ap bundle:
13// [0]=x(T*D Q16) [1]=out(T*D) [2]=T [3]=D [4]=nh [5]=hd [6]=scale_q16
14// [7]=gAttn(D) [8]=Wq(D*D) [9]=Wk(D*D) [10]=Wv(D*D) [11]=Wo(D*D)
15// [12]=gQ(D) [13]=gK(D) [14]=freqs(hd/2) [15]=scr
16// scr layout (i64): xn[T*D] Q[T*D] K[T*D] V[T*D] sc[T] at[T] concat[T*D]
17func nolmoe_attn(ap: *i64) -> i64 {
18 let x: *i64 = ap[0] as *i64
19 let out: *i64 = ap[1] as *i64
20 let T: i64 = ap[2]
21 let D: i64 = ap[3]
22 let nh: i64 = ap[4]
23 let hd: i64 = ap[5]
24 let scale: i64 = ap[6]
25 let gA: *i64 = ap[7] as *i64
26 let Wq: *i64 = ap[8] as *i64
27 let Wk: *i64 = ap[9] as *i64
28 let Wv: *i64 = ap[10] as *i64
29 let Wo: *i64 = ap[11] as *i64
30 let gQ: *i64 = ap[12] as *i64
31 let gK: *i64 = ap[13] as *i64
32 let freqs: *i64 = ap[14] as *i64
33 let scr: *i64 = ap[15] as *i64
34 let xn: *i64 = scr
35 let Q: *i64 = ((scr as i64) + T*D*8) as *i64
36 let K: *i64 = ((Q as i64) + T*D*8) as *i64
37 let V: *i64 = ((K as i64) + T*D*8) as *i64
38 let sc: *i64 = ((V as i64) + T*D*8) as *i64
39 let at: *i64 = ((sc as i64) + T*8) as *i64
40 let concat: *i64 = ((at as i64) + T*8) as *i64
41 // per token: pre-norm -> QKV -> QK-norm -> RoPE
42 var t: i64 = 0
43 while t < T {
44 rmsnorm_gamma_row(x, gA, t*D, D, xn, t*D)
45 mm_out_in(((xn as i64) + t*D*8) as *i64, Wq, ((Q as i64) + t*D*8) as *i64, 1, D, D, 0)
46 mm_out_in(((xn as i64) + t*D*8) as *i64, Wk, ((K as i64) + t*D*8) as *i64, 1, D, D, 0)
47 mm_out_in(((xn as i64) + t*D*8) as *i64, Wv, ((V as i64) + t*D*8) as *i64, 1, D, D, 0)
48 // QK-norm: RMSNorm over the FULL D on Q and K (in place -- reads-then-writes each index, safe)
49 rmsnorm_gamma_row(Q, gQ, t*D, D, Q, t*D)
50 rmsnorm_gamma_row(K, gK, t*D, D, K, t*D)
51 var h: i64 = 0
52 while h < nh {
53 rope_apply(((Q as i64) + (t*D + h*hd)*8) as *i64, hd, t, freqs)
54 rope_apply(((K as i64) + (t*D + h*hd)*8) as *i64, hd, t, freqs)
55 h = h + 1
56 }
57 t = t + 1
58 }
59 // causal MHA
60 t = 0
61 while t < T {
62 var h: i64 = 0
63 while h < nh {
64 let qb: i64 = h*hd
65 var s: i64 = 0
66 while s <= t {
67 var dot: i64 = 0
68 var d: i64 = 0
69 while d < hd { dot = dot + (Q[t*D + qb + d] * K[s*D + qb + d]); d = d + 1 }
70 sc[s] = qmul(dot >> 16, scale)
71 s = s + 1
72 }
73 var mmax: i64 = sc[0]
74 var j: i64 = 1
75 while j <= t { if sc[j] > mmax { mmax = sc[j] } j = j + 1 }
76 var sum: i64 = 0
77 j = 0
78 while j <= t { let e: i64 = fx_exp(sc[j] - mmax); at[j] = e; sum = sum + e; j = j + 1 }
79 if sum < 1 { sum = 1 }
80 j = 0
81 while j <= t { at[j] = (at[j] << 16) / sum; j = j + 1 }
82 var d2: i64 = 0
83 while d2 < hd {
84 var acc: i64 = 0
85 s = 0
86 while s <= t { acc = acc + (at[s] * V[s*D + qb + d2]); s = s + 1 }
87 concat[t*D + qb + d2] = acc >> 16
88 d2 = d2 + 1
89 }
90 h = h + 1
91 }
92 t = t + 1
93 }
94 // output projection
95 t = 0
96 while t < T { mm_out_in(((concat as i64) + t*D*8) as *i64, Wo, ((out as i64) + t*D*8) as *i64, 1, D, D, 0); t = t + 1 }
97 return 0
98}
99
100// MoE-FFN sublayer (per-token, LAZY top-K expert fetch) -> writes MoE output (PRE-residual) to `out`.
101// mp bundle: [0]=x(T*D Q16) [1]=out(T*D) [2]=T [3]=D [4]=ff [5]=E [6]=K [7]=gFfn(D) [8]=Wr(E*D Q16)
102// [9]=buf [10]=eb(ptr to [bG,tyG,bU,tyU,bD,tyD]) [11]=scr [12]=cnt(E)
103// scr layout: xn[D] r[E] sel[K] w[K] gs[ff*D] us[ff*D] ds[D*ff] g[ff] u[ff] hh[ff] eo[D]
104func nolmoe_moe(mp: *i64) -> i64 {
105 let x: *i64 = mp[0] as *i64
106 let out: *i64 = mp[1] as *i64
107 let T: i64 = mp[2]
108 let D: i64 = mp[3]
109 let ff: i64 = mp[4]
110 let E: i64 = mp[5]
111 let K: i64 = mp[6]
112 let gF: *i64 = mp[7] as *i64
113 let Wr: *i64 = mp[8] as *i64
114 let buf: *u8 = mp[9] as *u8
115 let eb: *i64 = mp[10] as *i64
116 let scr: *i64 = mp[11] as *i64
117 let cnt: *i64 = mp[12] as *i64
118 let bG: i64 = eb[0]
119 let tyG: i64 = eb[1]
120 let bU: i64 = eb[2]
121 let tyU: i64 = eb[3]
122 let bD: i64 = eb[4]
123 let tyD: i64 = eb[5]
124 let xn: *i64 = scr
125 let r: *i64 = ((xn as i64) + D*8) as *i64
126 let sel: *i64 = ((r as i64) + E*8) as *i64
127 let w: *i64 = ((sel as i64) + K*8) as *i64
128 let gs: *i64 = ((w as i64) + K*8) as *i64
129 let us: *i64 = ((gs as i64) + ff*D*8) as *i64
130 let ds: *i64 = ((us as i64) + ff*D*8) as *i64
131 let g: *i64 = ((ds as i64) + D*ff*8) as *i64
132 let u: *i64 = ((g as i64) + ff*8) as *i64
133 let hh: *i64 = ((u as i64) + ff*8) as *i64
134 let eo: *i64 = ((hh as i64) + ff*8) as *i64
135 var t: i64 = 0
136 while t < T {
137 rmsnorm_gamma_row(x, gF, t*D, D, xn, 0)
138 mm_out_in(xn, Wr, r, 1, D, E, 0)
139 // top-K by router logit (strict >, lowest index on ties)
140 var ki: i64 = 0
141 while ki < K {
142 var best: i64 = 0 - 1
143 var bestv: i64 = 0
144 var e: i64 = 0
145 while e < E {
146 var taken: i64 = 0
147 var q: i64 = 0
148 while q < ki { if sel[q] == e { taken = 1 } q = q + 1 }
149 if taken == 0 { if best < 0 { best = e; bestv = r[e] } else { if r[e] > bestv { best = e; bestv = r[e] } } }
150 e = e + 1
151 }
152 sel[ki] = best
153 ki = ki + 1
154 }
155 var m: i64 = r[sel[0]]
156 var i: i64 = 1
157 while i < K { if r[sel[i]] > m { m = r[sel[i]] } i = i + 1 }
158 var sum: i64 = 0
159 i = 0
160 while i < K { let ev: i64 = fx_exp(r[sel[i]] - m); w[i] = ev; sum = sum + ev; i = i + 1 }
161 if sum < 1 { sum = 1 }
162 i = 0
163 while i < K { w[i] = (w[i] << 16) / sum; i = i + 1 }
164 var d: i64 = 0
165 while d < D { out[t*D + d] = 0; d = d + 1 }
166 i = 0
167 while i < K {
168 let e2: i64 = sel[i]
169 cnt[e2] = cnt[e2] + 1
170 dequant_to_q16(buf, bG + nf_expert_byteoff(tyG, e2*ff*D), tyG, ff*D, gs)
171 dequant_to_q16(buf, bU + nf_expert_byteoff(tyU, e2*ff*D), tyU, ff*D, us)
172 dequant_to_q16(buf, bD + nf_expert_byteoff(tyD, e2*D*ff), tyD, D*ff, ds)
173 mm_out_in(xn, gs, g, 1, D, ff, 0)
174 mm_out_in(xn, us, u, 1, D, ff, 0)
175 var j: i64 = 0
176 while j < ff { hh[j] = qmul(silu(g[j]), u[j]); j = j + 1 }
177 mm_out_in(hh, ds, eo, 1, ff, D, 0)
178 d = 0
179 while d < D { out[t*D + d] = out[t*D + d] + qmul(w[i], eo[d]); d = d + 1 }
180 i = i + 1
181 }
182 t = t + 1
183 }
184 return 0
185}