edgefirst_decoder/per_scale/
mod.rs1pub mod helper;
8pub(crate) mod kernels;
9pub(crate) mod outputs;
10pub(crate) mod pipeline;
11pub(crate) mod plan;
12pub(crate) mod prefilter;
13
14pub use helper::apply_schema_quant;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22pub enum DecodeDtype {
23 #[default]
25 F32,
26 F16,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
38#[allow(dead_code)] pub(crate) enum Activation {
40 #[default]
41 None,
42 Sigmoid,
43}
44
45impl Activation {
46 #[allow(dead_code)] pub(crate) fn from_schema(s: Option<crate::schema::Activation>) -> Self {
50 match s {
51 Some(crate::schema::Activation::Sigmoid) => Self::Sigmoid,
52 _ => Self::None,
53 }
54 }
55}
56
57pub(crate) use outputs::{DecodedOutputBuffers, DecodedOutputsRef};
58pub(crate) use plan::PerScalePlan;
59
60#[derive(Debug)]
63#[allow(dead_code)] pub(crate) struct PerScaleDecoder {
65 pub(crate) plan: PerScalePlan,
66 pub(crate) buffers: DecodedOutputBuffers,
67}
68
69impl PerScaleDecoder {
70 #[allow(dead_code)] pub(crate) fn new(plan: PerScalePlan) -> Self {
73 let buffers = DecodedOutputBuffers::new(
74 plan.out_dtype,
75 plan.total_anchors,
76 plan.num_classes,
77 plan.num_mask_coefs,
78 plan.proto_nhwc_shape.as_deref(),
79 );
80 Self { plan, buffers }
81 }
82
83 #[allow(dead_code)] pub(crate) fn run<'a>(
90 &'a mut self,
91 inputs: &[&edgefirst_tensor::TensorDyn],
92 score_threshold: Option<f32>,
93 ) -> crate::DecoderResult<DecodedOutputsRef<'a>> {
94 pipeline::run(&self.plan, &mut self.buffers, inputs, score_threshold)
95 }
96}
97
98#[doc(hidden)]
104pub struct PreNmsCapture {
105 pub boxes_xywh: ndarray::Array2<f32>,
106 pub scores: ndarray::Array2<f32>,
107 pub mask_coefs: Option<ndarray::Array2<f32>>,
108 pub protos: Option<ndarray::Array4<f32>>,
109}
110
111#[doc(hidden)]
113pub mod bench {
114 use super::kernels::dfl_lut::{decode_dfl_lut, DflExpTable};
115 use super::kernels::grids::make_anchor_grid;
116 use super::kernels::level_box;
117 use super::plan::{Layout, LevelPlan};
118 use crate::Quantization;
119
120 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
122 pub enum DflKernel {
123 Softmax,
125 Lut,
127 NeonFused,
129 NeonFusedFp16,
131 LutNeon,
133 }
134
135 impl DflKernel {
136 pub fn available() -> Vec<Self> {
138 let v = vec![Self::Softmax, Self::Lut];
139 #[cfg(target_arch = "aarch64")]
140 let v = {
141 let mut v = v;
142 v.extend([Self::NeonFused, Self::LutNeon]);
143 if std::arch::is_aarch64_feature_detected!("fp16") {
144 v.push(Self::NeonFusedFp16);
145 }
146 v
147 };
148 v
149 }
150 }
151
152 pub struct DflLevel {
154 plan: LevelPlan,
155 q: Quantization,
156 table: DflExpTable,
157 }
158
159 impl DflLevel {
160 pub fn new(w: usize, h: usize, stride: f32, scale: f32, zero_point: i32) -> Self {
161 let (grid_x, grid_y) = make_anchor_grid(h, w);
162 Self {
163 plan: LevelPlan {
164 stride,
165 h,
166 w,
167 reg_max: 16,
168 anchor_offset: 0,
169 grid_x,
170 grid_y,
171 box_shape: vec![1, h, w, 64].into_boxed_slice(),
172 score_shape: vec![1, h, w, 1].into_boxed_slice(),
173 mc_shape: None,
174 layout: Layout::Nhwc,
175 },
176 q: Quantization::new(scale, zero_point),
177 table: DflExpTable::new(scale),
178 }
179 }
180
181 pub fn anchors(&self) -> usize {
182 self.plan.h * self.plan.w
183 }
184
185 pub fn decode(&self, kernel: DflKernel, input: &[i8], dst: &mut [f32]) {
187 let (p, q) = (&self.plan, self.q);
188 match kernel {
189 DflKernel::Softmax => level_box::decode_box_level_dfl_i8_to_f32(input, q, p, dst),
190 DflKernel::Lut => decode_dfl_lut(input, &self.table, p, dst),
191 #[cfg(target_arch = "aarch64")]
192 DflKernel::NeonFused => {
193 level_box::decode_box_level_dfl_i8_to_f32_neon_fused(input, q, p, dst)
194 }
195 #[cfg(target_arch = "aarch64")]
196 DflKernel::NeonFusedFp16 => {
197 assert!(std::arch::is_aarch64_feature_detected!("fp16"));
198 level_box::decode_box_level_dfl_i8_to_f32_neon_fused_fp16(input, q, p, dst)
199 }
200 #[cfg(target_arch = "aarch64")]
201 DflKernel::LutNeon => {
202 super::kernels::dfl_lut::decode_dfl_lut_neon(input, &self.table, p, dst)
203 }
204 #[cfg(not(target_arch = "aarch64"))]
205 _ => panic!("{kernel:?} is not available on this CPU"),
206 }
207 }
208 }
209}