1use std::path::Path;
11
12use pagesift_infer::{Activation, LayerNorm, Linear, Tensor, Weights, ops};
13use serde_json::Value;
14
15use super::attention::Attention;
16
17const LN_EPS: f32 = 1e-5;
19const POSITION_OFFSET: usize = 2;
21const PREFIX: &str = "model.decoder";
23
24struct Layer {
25 self_ln: LayerNorm,
26 self_attn: Attention,
27 cross_ln: LayerNorm,
28 cross_attn: Attention,
29 final_ln: LayerNorm,
30 fc1: Linear,
31 fc2: Linear,
32 act: Activation,
33}
34
35struct LayerCache {
37 k: Vec<f32>,
38 v: Vec<f32>,
39 cross_k: Vec<f32>,
40 cross_v: Vec<f32>,
41}
42
43pub(super) struct Cache {
45 layers: Vec<LayerCache>,
46 len: usize,
48 memory_len: usize,
50}
51
52impl Layer {
53 fn load(w: &Weights, p: &str, heads: usize, act: Activation) -> Result<Layer, String> {
54 Ok(Layer {
55 self_ln: LayerNorm::load(w, &format!("{p}.self_attn_layer_norm"), LN_EPS)?,
56 self_attn: Attention::load(w, &format!("{p}.self_attn"), heads)?,
57 cross_ln: LayerNorm::load(w, &format!("{p}.encoder_attn_layer_norm"), LN_EPS)?,
58 cross_attn: Attention::load(w, &format!("{p}.encoder_attn"), heads)?,
59 final_ln: LayerNorm::load(w, &format!("{p}.final_layer_norm"), LN_EPS)?,
60 fc1: Linear::load(w, &format!("{p}.fc1"))?,
61 fc2: Linear::load(w, &format!("{p}.fc2"))?,
62 act,
63 })
64 }
65
66 fn forward(&self, x: Tensor, c: &mut LayerCache, past: usize, memory_len: usize) -> Tensor {
68 let n = self.self_ln.forward(&x);
69 c.k.extend_from_slice(&self.self_attn.k.forward(&n).data);
70 c.v.extend_from_slice(&self.self_attn.v.forward(&n).data);
71 let a = self.self_attn.attend(&n, &c.k, &c.v, |i| past + i + 1);
72 let x = ops::add(&x, &a);
73
74 let n = self.cross_ln.forward(&x);
75 let a = self
76 .cross_attn
77 .attend(&n, &c.cross_k, &c.cross_v, |_| memory_len);
78 let x = ops::add(&x, &a);
79
80 let mut h = self.fc1.forward(&self.final_ln.forward(&x));
81 self.act.apply_all(&mut h);
82 ops::add(&x, &self.fc2.forward(&h))
83 }
84}
85
86pub struct Decoder {
88 embed_tokens: Tensor,
90 embed_positions: Tensor,
92 embed_scale: f32,
93 layernorm_embedding: LayerNorm,
94 layers: Vec<Layer>,
95 layer_norm: LayerNorm,
96 lm_head: Linear,
97 d_model: usize,
98 start: u32,
99 eos: u32,
100 forced_eos: Option<u32>,
101 max_length: usize,
102}
103
104fn cfg_usize(c: &Value, key: &str) -> Result<usize, String> {
105 c[key]
106 .as_u64()
107 .map(|v| v as usize)
108 .ok_or_else(|| format!("the config has no {key}"))
109}
110
111impl Decoder {
112 pub fn load(dir: &Path) -> Result<Decoder, String> {
114 let cfg = crate::read_json(dir, "config.json")?;
115 let generation = crate::read_json(dir, "generation_config.json")?;
116 let w = crate::read_weights(dir)?;
117 Decoder::from_weights(&w, &cfg["text_config"], &generation)
118 }
119
120 pub fn from_weights(w: &Weights, text: &Value, generation: &Value) -> Result<Decoder, String> {
123 let d_model = cfg_usize(text, "d_model")?;
124 let heads = cfg_usize(text, "decoder_attention_heads")?;
125 if heads == 0 || !d_model.is_multiple_of(heads) {
126 return Err(format!(
127 "d_model {d_model} is not divisible by {heads} heads"
128 ));
129 }
130 let act = match text["activation_function"].as_str().unwrap_or("") {
131 "gelu" => Activation::Gelu,
132 "relu" => Activation::Relu,
133 "silu" | "swish" => Activation::Silu,
134 a => return Err(format!("unsupported activation {a:?}")),
135 };
136 let layers = (0..cfg_usize(text, "decoder_layers")?)
137 .map(|i| Layer::load(w, &format!("{PREFIX}.layers.{i}"), heads, act))
138 .collect::<Result<Vec<_>, _>>()?;
139 let embed_tokens = w.get(&format!("{PREFIX}.embed_tokens.weight"))?.clone();
140 let embed_positions = w.get(&format!("{PREFIX}.embed_positions.weight"))?.clone();
141 if embed_tokens.tc().1 != d_model || embed_positions.tc().1 != d_model {
142 return Err(format!(
143 "token or position embedding size does not match d_model {d_model}"
144 ));
145 }
146 let embed_scale = if text["scale_embedding"].as_bool().unwrap_or(false) {
147 (d_model as f32).sqrt()
148 } else {
149 1.0
150 };
151 let token = |key: &str| cfg_usize(generation, key).map(|v| v as u32);
152 Ok(Decoder {
153 embed_tokens,
154 embed_positions,
155 embed_scale,
156 layernorm_embedding: LayerNorm::load(
157 w,
158 &format!("{PREFIX}.layernorm_embedding"),
159 LN_EPS,
160 )?,
161 layers,
162 layer_norm: LayerNorm::load(w, &format!("{PREFIX}.layer_norm"), LN_EPS)?,
163 lm_head: Linear::load(w, "lm_head")?,
164 d_model,
165 start: token("decoder_start_token_id")?,
166 eos: token("eos_token_id")?,
167 forced_eos: token("forced_eos_token_id").ok(),
168 max_length: cfg_usize(generation, "max_length")?,
169 })
170 }
171
172 pub fn max_length(&self) -> usize {
174 self.max_length
175 }
176
177 pub fn generate(&self, memory: &Tensor, max_len: usize) -> Result<Vec<u32>, String> {
185 let max_len = max_len.min(self.max_positions());
186 let mut cache = self.new_cache(memory)?;
187 let mut last = self.start;
188 let mut out = Vec::new();
189 for len in 1..max_len {
191 let hidden = self.forward(&[last], &mut cache)?;
192 let next = match self.forced_eos {
193 Some(f) if len + 1 == max_len => f,
194 _ => argmax(&self.logits(&hidden)?),
195 };
196 if next == self.eos {
197 break;
198 }
199 out.push(next);
200 last = next;
201 }
202 Ok(out)
203 }
204
205 fn max_positions(&self) -> usize {
207 self.embed_positions.tc().0.saturating_sub(POSITION_OFFSET)
208 }
209
210 pub(super) fn new_cache(&self, memory: &Tensor) -> Result<Cache, String> {
212 if memory.shape.len() != 2 || memory.shape[1] != self.d_model || memory.shape[0] == 0 {
213 return Err(format!(
214 "memory must be [L, {}], got {:?}",
215 self.d_model, memory.shape
216 ));
217 }
218 let layers = self
219 .layers
220 .iter()
221 .map(|l| LayerCache {
222 k: Vec::new(),
223 v: Vec::new(),
224 cross_k: l.cross_attn.k.forward(memory).data,
225 cross_v: l.cross_attn.v.forward(memory).data,
226 })
227 .collect();
228 Ok(Cache {
229 layers,
230 len: 0,
231 memory_len: memory.shape[0],
232 })
233 }
234
235 pub(super) fn forward(&self, ids: &[u32], cache: &mut Cache) -> Result<Tensor, String> {
237 let (vocab, d) = self.embed_tokens.tc();
238 let (past, memory_len) = (cache.len, cache.memory_len);
239 if past + ids.len() > self.max_positions() {
240 return Err(format!(
241 "sequence length {} exceeds the position table of {}",
242 past + ids.len(),
243 self.max_positions()
244 ));
245 }
246 let mut x = Vec::with_capacity(ids.len() * d);
247 for (i, &id) in ids.iter().enumerate() {
248 let id = id as usize;
249 if id >= vocab {
250 return Err(format!("token {id} is outside the vocabulary of {vocab}"));
251 }
252 let tok = &self.embed_tokens.data[id * d..(id + 1) * d];
253 let at = (past + i + POSITION_OFFSET) * d;
254 let pos = &self.embed_positions.data[at..at + d];
255 x.extend(tok.iter().zip(pos).map(|(t, p)| t * self.embed_scale + p));
256 }
257 let mut x = self
258 .layernorm_embedding
259 .forward(&Tensor::new(vec![ids.len(), d], x));
260 for (layer, c) in self.layers.iter().zip(&mut cache.layers) {
261 x = layer.forward(x, c, past, memory_len);
262 }
263 cache.len += ids.len();
264 Ok(self.layer_norm.forward(&x))
265 }
266
267 pub(super) fn logits(&self, hidden: &Tensor) -> Result<Vec<f32>, String> {
269 let (t, d) = hidden.tc();
270 let last = Tensor::new(vec![1, d], hidden.data[(t - 1) * d..].to_vec());
271 let y = self.lm_head.forward(&last).data;
272 if y.iter().any(|v| !v.is_finite()) {
273 return Err("NaN or infinity in the logits".into());
274 }
275 Ok(y)
276 }
277}
278
279fn argmax(v: &[f32]) -> u32 {
281 let (mut arg, mut m) = (0, f32::NEG_INFINITY);
282 for (i, &x) in v.iter().enumerate() {
283 if x > m {
284 (arg, m) = (i, x);
285 }
286 }
287 arg as u32
288}
289
290#[cfg(test)]
291#[path = "decoder_tests.rs"]
292mod tests;