pagesift_ocr/formula_enc/
mod.rs1mod attention;
19mod neck;
20mod par;
21mod preprocess;
22mod vit;
23
24use std::path::Path;
25
26use pagesift_infer::{Conv2d, Tensor, Weights, ops};
27
28pub use preprocess::{SIZE, preprocess};
29
30const PREFIX: &str = "model.encoder";
32
33#[derive(Debug, Clone, PartialEq)]
35pub struct Config {
36 pub image_size: usize,
37 pub patch_size: usize,
38 pub hidden_size: usize,
39 pub layers: usize,
40 pub heads: usize,
41 pub window_size: usize,
42 pub global_attn_indexes: Vec<usize>,
43 pub layer_norm_eps: f32,
44}
45
46impl Config {
47 pub fn from_json(v: &serde_json::Value) -> Result<Config, String> {
50 let c = &v["vision_config"];
51 let int = |k: &str| {
52 c[k].as_u64()
53 .map(|x| x as usize)
54 .ok_or_else(|| format!("vision_config has no integer {k}"))
55 };
56 for k in ["use_abs_pos", "use_rel_pos"] {
57 if c[k].as_bool() != Some(true) {
58 return Err(format!("only {k} = true is supported"));
59 }
60 }
61 if c["hidden_act"].as_str().unwrap_or("gelu") != "gelu" {
62 return Err("only hidden_act = gelu is supported".into());
63 }
64 let global_attn_indexes = c["global_attn_indexes"]
65 .as_array()
66 .ok_or("vision_config has no global_attn_indexes")?
67 .iter()
68 .map(|x| {
69 x.as_u64()
70 .map(|x| x as usize)
71 .ok_or("global_attn_indexes must be integers")
72 })
73 .collect::<Result<_, _>>()?;
74 let cfg = Config {
75 image_size: int("image_size")?,
76 patch_size: int("patch_size")?,
77 hidden_size: int("hidden_size")?,
78 layers: int("num_hidden_layers")?,
79 heads: int("num_attention_heads")?,
80 window_size: int("window_size")?,
81 global_attn_indexes,
82 layer_norm_eps: c["layer_norm_eps"]
83 .as_f64()
84 .ok_or("vision_config has no layer_norm_eps")? as f32,
85 };
86 if cfg.image_size != SIZE {
87 return Err(format!(
88 "preprocessing always outputs {SIZE}, the config says {}",
89 cfg.image_size
90 ));
91 }
92 if cfg.patch_size == 0 || !cfg.image_size.is_multiple_of(cfg.patch_size) {
93 return Err("image_size is not a multiple of patch_size".into());
94 }
95 if cfg.heads == 0 || !cfg.hidden_size.is_multiple_of(cfg.heads) {
96 return Err("hidden_size is not divisible by the number of heads".into());
97 }
98 Ok(cfg)
99 }
100
101 pub fn grid(&self) -> usize {
103 self.image_size / self.patch_size
104 }
105}
106
107pub struct Encoder {
109 cfg: Config,
110 patch: Conv2d,
111 pos: Vec<f32>,
113 layers: Vec<vit::Layer>,
114 neck: neck::Neck,
115 proj: neck::Projector,
116}
117
118impl Encoder {
119 pub fn load(dir: &Path) -> Result<Encoder, String> {
121 let cfg = Config::from_json(&crate::read_json(dir, "config.json")?)?;
122 Encoder::from_weights(&crate::read_weights(dir)?, cfg)
123 }
124
125 pub fn from_weights(w: &Weights, cfg: Config) -> Result<Encoder, String> {
127 let (g, c) = (cfg.grid(), cfg.hidden_size);
128 let ps = cfg.patch_size;
129 let patch = Conv2d::load(
130 w,
131 &format!("{PREFIX}.patch_embed.projection"),
132 (ps, ps),
133 (0, 0),
134 (1, 1),
135 1,
136 )?;
137 let pos = w.get(&format!("{PREFIX}.pos_embed"))?;
138 if pos.shape != [1, g, g, c] {
140 return Err(format!(
141 "pos_embed has shape {:?}, expected [1, {g}, {g}, {c}]",
142 pos.shape
143 ));
144 }
145 let mut layers = Vec::with_capacity(cfg.layers);
146 for i in 0..cfg.layers {
147 let window = if cfg.global_attn_indexes.contains(&i) {
148 0
149 } else {
150 cfg.window_size
151 };
152 layers.push(vit::Layer::load(
153 w,
154 &format!("{PREFIX}.layers.{i}"),
155 cfg.heads,
156 window,
157 g,
158 cfg.layer_norm_eps,
159 )?);
160 }
161 Ok(Encoder {
162 patch,
163 pos: pos.data.clone(),
164 layers,
165 neck: neck::Neck::load(w, &format!("{PREFIX}.neck"))?,
166 proj: neck::Projector::load(w, &format!("{PREFIX}.multi_modal_projector"))?,
167 cfg,
168 })
169 }
170
171 pub fn config(&self) -> &Config {
172 &self.cfg
173 }
174
175 pub fn encode(&self, x: &Tensor) -> Result<Tensor, String> {
177 self.encode_traced(x, |_, _| {})
178 }
179
180 pub fn encode_traced(
182 &self,
183 x: &Tensor,
184 mut trace: impl FnMut(&str, &Tensor),
185 ) -> Result<Tensor, String> {
186 let s = self.cfg.image_size;
187 if x.shape != [3, s, s] {
189 return Err(format!("input must be [3, {s}, {s}], got {:?}", x.shape));
190 }
191 let g = self.cfg.grid();
192 let mut h = ops::chw_to_seq(&self.patch.forward(x));
193 for (v, p) in h.data.iter_mut().zip(&self.pos) {
194 *v += p;
195 }
196 trace("patch_embed+pos", &h);
197 for (i, l) in self.layers.iter().enumerate() {
198 h = l.forward(h, g);
199 trace(&format!("layer{i}"), &h);
200 }
201 let n = self.neck.forward(&h, g);
202 trace("neck", &n);
203 let m = self.proj.forward(&n);
204 trace("projector", &m);
205 Ok(m)
206 }
207}