pub mod helper;
pub(crate) mod kernels;
pub(crate) mod outputs;
pub(crate) mod pipeline;
pub(crate) mod plan;
pub(crate) mod prefilter;
pub use helper::apply_schema_quant;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DecodeDtype {
#[default]
F32,
F16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[allow(dead_code)] pub(crate) enum Activation {
#[default]
None,
Sigmoid,
}
impl Activation {
#[allow(dead_code)] pub(crate) fn from_schema(s: Option<crate::schema::Activation>) -> Self {
match s {
Some(crate::schema::Activation::Sigmoid) => Self::Sigmoid,
_ => Self::None,
}
}
}
pub(crate) use outputs::{DecodedOutputBuffers, DecodedOutputsRef};
pub(crate) use plan::PerScalePlan;
#[derive(Debug)]
#[allow(dead_code)] pub(crate) struct PerScaleDecoder {
pub(crate) plan: PerScalePlan,
pub(crate) buffers: DecodedOutputBuffers,
}
impl PerScaleDecoder {
#[allow(dead_code)] pub(crate) fn new(plan: PerScalePlan) -> Self {
let buffers = DecodedOutputBuffers::new(
plan.out_dtype,
plan.total_anchors,
plan.num_classes,
plan.num_mask_coefs,
plan.proto_nhwc_shape.as_deref(),
);
Self { plan, buffers }
}
#[allow(dead_code)] pub(crate) fn run<'a>(
&'a mut self,
inputs: &[&edgefirst_tensor::TensorDyn],
score_threshold: Option<f32>,
) -> crate::DecoderResult<DecodedOutputsRef<'a>> {
pipeline::run(&self.plan, &mut self.buffers, inputs, score_threshold)
}
}
#[doc(hidden)]
pub struct PreNmsCapture {
pub boxes_xywh: ndarray::Array2<f32>,
pub scores: ndarray::Array2<f32>,
pub mask_coefs: Option<ndarray::Array2<f32>>,
pub protos: Option<ndarray::Array4<f32>>,
}
#[doc(hidden)]
pub mod bench {
use super::kernels::dfl_lut::{decode_dfl_lut, DflExpTable};
use super::kernels::grids::make_anchor_grid;
use super::kernels::level_box;
use super::plan::{Layout, LevelPlan};
use crate::Quantization;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DflKernel {
Softmax,
Lut,
NeonFused,
NeonFusedFp16,
LutNeon,
}
impl DflKernel {
pub fn available() -> Vec<Self> {
let v = vec![Self::Softmax, Self::Lut];
#[cfg(target_arch = "aarch64")]
let v = {
let mut v = v;
v.extend([Self::NeonFused, Self::LutNeon]);
if std::arch::is_aarch64_feature_detected!("fp16") {
v.push(Self::NeonFusedFp16);
}
v
};
v
}
}
pub struct DflLevel {
plan: LevelPlan,
q: Quantization,
table: DflExpTable,
}
impl DflLevel {
pub fn new(w: usize, h: usize, stride: f32, scale: f32, zero_point: i32) -> Self {
let (grid_x, grid_y) = make_anchor_grid(h, w);
Self {
plan: LevelPlan {
stride,
h,
w,
reg_max: 16,
anchor_offset: 0,
grid_x,
grid_y,
box_shape: vec![1, h, w, 64].into_boxed_slice(),
score_shape: vec![1, h, w, 1].into_boxed_slice(),
mc_shape: None,
layout: Layout::Nhwc,
},
q: Quantization::new(scale, zero_point),
table: DflExpTable::new(scale),
}
}
pub fn anchors(&self) -> usize {
self.plan.h * self.plan.w
}
pub fn decode(&self, kernel: DflKernel, input: &[i8], dst: &mut [f32]) {
let (p, q) = (&self.plan, self.q);
match kernel {
DflKernel::Softmax => level_box::decode_box_level_dfl_i8_to_f32(input, q, p, dst),
DflKernel::Lut => decode_dfl_lut(input, &self.table, p, dst),
#[cfg(target_arch = "aarch64")]
DflKernel::NeonFused => {
level_box::decode_box_level_dfl_i8_to_f32_neon_fused(input, q, p, dst)
}
#[cfg(target_arch = "aarch64")]
DflKernel::NeonFusedFp16 => {
assert!(std::arch::is_aarch64_feature_detected!("fp16"));
level_box::decode_box_level_dfl_i8_to_f32_neon_fused_fp16(input, q, p, dst)
}
#[cfg(target_arch = "aarch64")]
DflKernel::LutNeon => {
super::kernels::dfl_lut::decode_dfl_lut_neon(input, &self.table, p, dst)
}
#[cfg(not(target_arch = "aarch64"))]
_ => panic!("{kernel:?} is not available on this CPU"),
}
}
}
}