1use pagesift_infer::{Activation, Tensor, Weights, ops};
6
7use super::layers::{conv_layer, count};
8use crate::lcnet::ConvBn;
9
10#[derive(Debug, Clone)]
12enum Layer {
13 Plain(ConvBn),
15 Light(ConvBn, ConvBn),
17}
18
19impl Layer {
20 fn load(w: &Weights, p: &str) -> Result<Layer, String> {
21 if w.opt(&format!("{p}.conv1.convolution.weight")).is_some() {
22 Ok(Layer::Light(
23 conv_layer(w, &format!("{p}.conv1"), 1, false, Activation::Identity)?,
24 conv_layer(w, &format!("{p}.conv2"), 1, true, Activation::Relu)?,
25 ))
26 } else {
27 Ok(Layer::Plain(conv_layer(w, p, 1, false, Activation::Relu)?))
28 }
29 }
30
31 fn forward(&self, x: &Tensor) -> Tensor {
32 match self {
33 Layer::Plain(c) => c.forward(x),
34 Layer::Light(a, b) => b.forward(&a.forward(x)),
35 }
36 }
37}
38
39#[derive(Debug, Clone)]
41struct Block {
42 layers: Vec<Layer>,
43 squeeze: ConvBn,
44 excite: ConvBn,
45 residual: bool,
46}
47
48impl Block {
49 fn load(w: &Weights, p: &str, residual: bool) -> Result<Block, String> {
50 let n = count(w, |i| format!("{p}.layers.{i}.convolution.weight")).max(count(w, |i| {
52 format!("{p}.layers.{i}.conv1.convolution.weight")
53 }));
54 if n == 0 {
55 return Err(format!("{p} has no convolution layers"));
56 }
57 let layers = (0..n)
58 .map(|i| Layer::load(w, &format!("{p}.layers.{i}")))
59 .collect::<Result<_, _>>()?;
60 Ok(Block {
61 layers,
62 squeeze: conv_layer(w, &format!("{p}.aggregation.0"), 1, false, Activation::Relu)?,
63 excite: conv_layer(w, &format!("{p}.aggregation.1"), 1, false, Activation::Relu)?,
64 residual,
65 })
66 }
67
68 fn forward(&self, x: &Tensor) -> Tensor {
69 let mut outs = Vec::with_capacity(self.layers.len());
70 for l in &self.layers {
71 let y = l.forward(outs.last().unwrap_or(x));
72 outs.push(y);
73 }
74 let mut parts: Vec<&Tensor> = Vec::with_capacity(outs.len() + 1);
75 parts.push(x);
76 parts.extend(outs.iter());
77 let cat = ops::concat_channels(&parts);
78 drop(outs);
79 let y = self.excite.forward(&self.squeeze.forward(&cat));
80 if self.residual { ops::add(&y, x) } else { y }
81 }
82}
83
84#[derive(Debug, Clone)]
86struct Stage {
87 down: Option<ConvBn>,
88 blocks: Vec<Block>,
89}
90
91const STAGE_STRIDE: usize = 2;
93
94impl Stage {
95 fn load(w: &Weights, p: &str) -> Result<Stage, String> {
96 let dp = format!("{p}.downsample");
97 let down = if w.opt(&format!("{dp}.convolution.weight")).is_some() {
98 Some(conv_layer(
99 w,
100 &dp,
101 STAGE_STRIDE,
102 true,
103 Activation::Identity,
104 )?)
105 } else {
106 None
107 };
108 let n = count(w, |i| {
109 format!("{p}.blocks.{i}.aggregation.0.convolution.weight")
110 });
111 let blocks = (0..n)
113 .map(|i| Block::load(w, &format!("{p}.blocks.{i}"), i != 0))
114 .collect::<Result<_, _>>()?;
115 Ok(Stage { down, blocks })
116 }
117
118 fn forward(&self, x: Tensor) -> Tensor {
119 let mut h = match &self.down {
120 Some(d) => d.forward(&x),
121 None => x,
122 };
123 for b in &self.blocks {
124 h = b.forward(&h);
125 }
126 h
127 }
128}
129
130#[derive(Debug, Clone)]
132pub struct Backbone {
133 stem1: ConvBn,
134 stem2a: ConvBn,
135 stem2b: ConvBn,
136 stem3: ConvBn,
137 stem4: ConvBn,
138 stages: Vec<Stage>,
139}
140
141impl Backbone {
142 pub fn load(w: &Weights, p: &str) -> Result<Backbone, String> {
144 let s = |name: &str, stride: usize| {
146 conv_layer(
147 w,
148 &format!("{p}.embedder.{name}"),
149 stride,
150 false,
151 Activation::Relu,
152 )
153 };
154 let n = count(w, |i| {
155 format!("{p}.encoder.stages.{i}.blocks.0.aggregation.0.convolution.weight")
156 });
157 if n == 0 {
158 return Err(format!("{p} has no stages"));
159 }
160 let stages = (0..n)
161 .map(|i| Stage::load(w, &format!("{p}.encoder.stages.{i}")))
162 .collect::<Result<_, _>>()?;
163 Ok(Backbone {
164 stem1: s("stem1", 2)?,
165 stem2a: s("stem2a", 1)?,
166 stem2b: s("stem2b", 1)?,
167 stem3: s("stem3", 2)?,
168 stem4: s("stem4", 1)?,
169 stages,
170 })
171 }
172
173 pub fn forward(&self, x: &Tensor) -> Vec<Tensor> {
175 let e = ops::pad_right_bottom(&self.stem1.forward(x), 1, 1);
176 let a = ops::pad_right_bottom(&self.stem2a.forward(&e), 1, 1);
177 let a = self.stem2b.forward(&a);
178 let pooled = ops::max_pool2d(&e, (2, 2), (1, 1), true);
179 let cat = ops::concat_channels(&[&pooled, &a]);
180 let mut h = self.stem4.forward(&self.stem3.forward(&cat));
181 let mut outs = Vec::with_capacity(self.stages.len());
182 for st in &self.stages {
183 h = st.forward(h);
184 outs.push(h.clone());
185 }
186 outs
187 }
188}