use pagesift_infer::{Conv2d, LayerNorm, Linear, Tensor, Weights, ops};
const NECK_EPS: f32 = 1e-6;
pub(crate) struct Neck {
conv1: Linear,
ln1: LayerNorm,
conv2: Conv2d,
ln2: LayerNorm,
}
impl Neck {
pub(crate) fn load(w: &Weights, p: &str) -> Result<Neck, String> {
let k = w.get(&format!("{p}.conv1.weight"))?;
if k.shape.len() != 4 || k.shape[2] != 1 || k.shape[3] != 1 {
return Err(format!("{p}.conv1 is not a 1x1 convolution: {:?}", k.shape));
}
let flat = Tensor::new(vec![k.shape[0], k.shape[1]], k.data.clone());
Ok(Neck {
conv1: Linear {
weight_t: ops::transpose(&flat),
bias: None,
},
ln1: LayerNorm::load(w, &format!("{p}.layer_norm1"), NECK_EPS)?,
conv2: Conv2d::load(w, &format!("{p}.conv2"), (1, 1), (1, 1), (1, 1), 1)?,
ln2: LayerNorm::load(w, &format!("{p}.layer_norm2"), NECK_EPS)?,
})
}
pub(crate) fn forward(&self, x: &Tensor, grid: usize) -> Tensor {
let s = self.ln1.forward(&self.conv1.forward(x));
let y = self.conv2.forward(&ops::seq_to_chw(&s, grid, grid));
let s = self.ln2.forward(&ops::chw_to_seq(&y));
ops::seq_to_chw(&s, grid, grid)
}
}
pub(crate) struct Projector {
conv1: Conv2d,
conv2: Conv2d,
lin1: Linear,
lin2: Linear,
}
impl Projector {
pub(crate) fn load(w: &Weights, p: &str) -> Result<Projector, String> {
let conv = |n: &str| Conv2d::load(w, &format!("{p}.{n}"), (2, 2), (1, 1), (1, 1), 1);
Ok(Projector {
conv1: conv("conv1")?,
conv2: conv("conv2")?,
lin1: Linear::load(w, &format!("{p}.linear_1"))?,
lin2: Linear::load(w, &format!("{p}.linear_2"))?,
})
}
pub(crate) fn forward(&self, x: &Tensor) -> Tensor {
let y = self.conv2.forward(&self.conv1.forward(x));
let s = ops::chw_to_seq(&y);
self.lin2.forward(&self.lin1.forward(&s))
}
}