1use crate::attn::{AttnConfig, KvCache};
12use crate::config::TransformerConfig;
13use crate::layers::{decoder_layer_forward, encoder_layer_forward, DecoderLayer, EncoderLayer};
14use crate::math;
15use crate::norm::zc_rms_norm_vec;
16use crate::rope::RopeCache;
17use alloc::vec;
18use alloc::vec::Vec;
19
20pub struct NeedleModel {
21 pub cfg: TransformerConfig,
22
23 pub embedding: Vec<f32>,
25
26 pub encoder_layers: Vec<EncoderLayer>,
27 pub decoder_layers: Vec<DecoderLayer>,
28
29 pub encoder_final_norm: Vec<f32>,
31 pub decoder_final_norm: Vec<f32>,
33
34 rope: RopeCache,
36
37 attn_cfg: AttnConfig,
38
39 embed_scale: f32,
41}
42
43impl NeedleModel {
44 pub fn new(
45 cfg: TransformerConfig,
46 embedding: Vec<f32>,
47 encoder_layers: Vec<EncoderLayer>,
48 decoder_layers: Vec<DecoderLayer>,
49 encoder_final_norm: Vec<f32>,
50 decoder_final_norm: Vec<f32>,
51 ) -> Self {
52 let rope = RopeCache::new(
53 cfg.max_enc_len.max(cfg.max_dec_len),
54 cfg.head_dim(),
55 cfg.rope_theta,
56 );
57 let attn_cfg = AttnConfig {
58 num_heads: cfg.num_heads,
59 num_kv_heads: cfg.num_kv_heads,
60 head_dim: cfg.head_dim(),
61 d_model: cfg.d_model,
62 };
63 let embed_scale = math::sqrt(cfg.d_model as f32);
64 Self {
65 cfg,
66 embedding,
67 encoder_layers,
68 decoder_layers,
69 encoder_final_norm,
70 decoder_final_norm,
71 rope,
72 attn_cfg,
73 embed_scale,
74 }
75 }
76
77 fn embed_scaled(&self, token_id: u32) -> Vec<f32> {
79 let d = self.cfg.d_model;
80 let idx = token_id as usize;
81 debug_assert!(idx < self.cfg.vocab_size);
82 let row = &self.embedding[idx * d..(idx + 1) * d];
83 row.iter().map(|v| v * self.embed_scale).collect()
84 }
85
86 fn lm_head(&self, hidden: &[f32], logits: &mut [f32]) {
90 debug_assert_eq!(hidden.len(), self.cfg.d_model);
91 debug_assert_eq!(logits.len(), self.cfg.vocab_size);
92
93 #[cfg(all(target_arch = "x86_64", feature = "simd"))]
94 if crate::quant::has_avx2() {
95 return unsafe { self.lm_head_avx2(hidden, logits) };
97 }
98
99 self.lm_head_scalar(hidden, logits);
100 }
101
102 #[allow(clippy::needless_range_loop)]
103 fn lm_head_scalar(&self, hidden: &[f32], logits: &mut [f32]) {
104 let d = self.cfg.d_model;
105 let v = self.cfg.vocab_size;
106 for tok in 0..v {
107 let emb = &self.embedding[tok * d..(tok + 1) * d];
108 let mut acc = 0.0f32;
109 for i in 0..d {
110 acc += hidden[i] * emb[i];
111 }
112 logits[tok] = acc;
113 }
114 }
115
116 #[cfg(all(target_arch = "x86_64", feature = "simd"))]
117 #[target_feature(enable = "avx2")]
118 #[allow(clippy::needless_range_loop)]
119 unsafe fn lm_head_avx2(&self, hidden: &[f32], logits: &mut [f32]) {
120 use core::arch::x86_64::*;
121 let d = self.cfg.d_model;
122 let v = self.cfg.vocab_size;
123 let chunks = d / 8;
124
125 for tok in 0..v {
126 let emb_ptr = self.embedding.as_ptr().add(tok * d);
127 let mut acc = _mm256_setzero_ps();
128 for c in 0..chunks {
129 let h = _mm256_loadu_ps(hidden.as_ptr().add(c * 8));
130 let e = _mm256_loadu_ps(emb_ptr.add(c * 8));
131 acc = _mm256_fmadd_ps(h, e, acc);
132 }
133 let hi128 = _mm256_extractf128_ps(acc, 1);
135 let lo128 = _mm256_castps256_ps128(acc);
136 let sum128 = _mm_add_ps(hi128, lo128);
137 let shuf = _mm_shuffle_ps(sum128, sum128, 0x4E);
138 let sum64 = _mm_add_ps(sum128, shuf);
139 let shuf2 = _mm_shuffle_ps(sum64, sum64, 0xB1);
140 let sum32 = _mm_add_ss(sum64, shuf2);
141 let mut result = _mm_cvtss_f32(sum32);
142 for i in chunks * 8..d {
144 result += hidden[i] * *emb_ptr.add(i);
145 }
146 logits[tok] = result;
147 }
148 }
149
150 pub fn encode(&self, input_ids: &[u32], enc_kv_caches: &mut [KvCache]) -> Vec<f32> {
154 let seq_len = input_ids.len();
155 let d = self.cfg.d_model;
156
157 let mut x = vec![0.0f32; seq_len * d];
159 for (t, &tok) in input_ids.iter().enumerate() {
160 let row = &self.embedding[tok as usize * d..(tok as usize + 1) * d];
161 for (dst, &src) in x[t * d..(t + 1) * d].iter_mut().zip(row.iter()) {
162 *dst = src * self.embed_scale;
163 }
164 }
165
166 let mut tmp = Vec::with_capacity(seq_len * d);
167 let mut normed = vec![0.0f32; seq_len * d]; for layer in self.encoder_layers.iter() {
171 encoder_layer_forward(
172 &mut x,
173 layer,
174 &self.attn_cfg,
175 &self.rope,
176 seq_len,
177 None,
178 &mut tmp,
179 &mut normed,
180 );
181 }
182
183 for t in 0..seq_len {
185 zc_rms_norm_vec(&mut x[t * d..(t + 1) * d], &self.encoder_final_norm);
186 }
187
188 self.fill_cross_kv(&x, seq_len, enc_kv_caches);
190
191 x
192 }
193
194 fn fill_cross_kv(&self, enc_hidden: &[f32], seq_len: usize, kv_caches: &mut [KvCache]) {
197 let kv_h = self.cfg.num_kv_heads;
198 let hd = self.cfg.head_dim();
199 let kv_dim = kv_h * hd;
200
201 for (li, layer) in self.decoder_layers.iter().enumerate() {
202 let kv = &mut kv_caches[li];
203 kv.reset();
204
205 let mut k_all = vec![0.0f32; seq_len * kv_dim];
206 let mut v_all = vec![0.0f32; seq_len * kv_dim];
207
208 layer.cross_attn.wk.matmul(enc_hidden, seq_len, &mut k_all);
209 layer.cross_attn.wv.matmul(enc_hidden, seq_len, &mut v_all);
210
211 for t in 0..seq_len {
213 for ki in 0..kv_h {
214 crate::norm::zc_rms_norm_vec(
215 &mut k_all[(t * kv_h + ki) * hd..(t * kv_h + ki + 1) * hd],
216 &layer.cross_attn.k_norm,
217 );
218 }
219 }
220
221 let kv_stride = kv_h * hd;
224 for t in 0..seq_len {
225 kv.push_kv(
226 &k_all[t * kv_stride..(t + 1) * kv_stride],
227 &v_all[t * kv_stride..(t + 1) * kv_stride],
228 );
229 }
230 }
231 }
232
233 pub fn decode_step(
236 &self,
237 token_id: u32,
238 enc_kv_caches: &[KvCache],
239 dec_kv_caches: &mut [KvCache],
240 logits: &mut [f32],
241 ) {
242 let d = self.cfg.d_model;
243
244 let mut x: Vec<f32> = self.embed_scaled(token_id);
246 let mut tmp = Vec::with_capacity(d);
247 let mut normed = vec![0.0f32; d]; for (li, layer) in self.decoder_layers.iter().enumerate() {
250 decoder_layer_forward(
251 &mut x,
252 layer,
253 &self.attn_cfg,
254 &self.rope,
255 &enc_kv_caches[li],
256 &mut dec_kv_caches[li],
257 &mut tmp,
258 &mut normed,
259 );
260 }
261
262 zc_rms_norm_vec(&mut x, &self.decoder_final_norm);
264 self.lm_head(&x, logits);
265 }
266
267 pub fn make_enc_kv_caches(&self, enc_len: usize) -> Vec<KvCache> {
269 (0..self.cfg.num_dec_layers)
270 .map(|_| KvCache::new(enc_len, self.cfg.num_kv_heads, self.cfg.head_dim()))
271 .collect()
272 }
273
274 pub fn make_dec_kv_caches(&self) -> Vec<KvCache> {
276 (0..self.cfg.num_dec_layers)
277 .map(|_| {
278 KvCache::new(
279 self.cfg.max_dec_len,
280 self.cfg.num_kv_heads,
281 self.cfg.head_dim(),
282 )
283 })
284 .collect()
285 }
286}