pub mod backbone;
pub mod detector;
pub mod head;
pub mod loss;
pub mod neck;
pub use detector::Helios;
pub use loss::{CIoULoss, HeliosLoss, TaskAlignedAssigner};
use axonml_autograd::Variable;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum HeliosSize {
Nano,
Small,
Medium,
Large,
XLarge,
}
#[derive(Debug, Clone)]
pub struct HeliosConfig {
pub num_classes: usize,
pub input_size: usize,
pub size: HeliosSize,
pub width_mul: f32,
pub depth_mul: f32,
pub reg_max: usize,
pub score_threshold: f32,
pub nms_threshold: f32,
pub strides: Vec<usize>,
}
impl HeliosConfig {
pub fn nano(num_classes: usize) -> Self {
Self {
num_classes,
input_size: 640,
size: HeliosSize::Nano,
width_mul: 0.25,
depth_mul: 0.33,
reg_max: 16,
score_threshold: 0.25,
nms_threshold: 0.45,
strides: vec![8, 16, 32],
}
}
pub fn small(num_classes: usize) -> Self {
Self {
size: HeliosSize::Small,
width_mul: 0.50,
depth_mul: 0.33,
..Self::nano(num_classes)
}
}
pub fn medium(num_classes: usize) -> Self {
Self {
size: HeliosSize::Medium,
width_mul: 0.75,
depth_mul: 0.67,
..Self::nano(num_classes)
}
}
pub fn large(num_classes: usize) -> Self {
Self {
size: HeliosSize::Large,
width_mul: 1.00,
depth_mul: 1.00,
..Self::nano(num_classes)
}
}
pub fn xlarge(num_classes: usize) -> Self {
Self {
size: HeliosSize::XLarge,
width_mul: 1.25,
depth_mul: 1.00,
..Self::nano(num_classes)
}
}
pub fn stage_channels(&self) -> [usize; 5] {
let base = [64, 128, 256, 512, 1024];
let mut out = [0usize; 5];
for (i, &b) in base.iter().enumerate() {
out[i] = make_divisible((b as f32 * self.width_mul) as usize, 8).max(8);
}
out
}
pub fn stage_depths(&self) -> [usize; 4] {
let base = [3, 6, 6, 3];
let mut out = [0usize; 4];
for (i, &b) in base.iter().enumerate() {
out[i] = ((b as f32 * self.depth_mul).ceil() as usize).max(1);
}
out
}
}
fn make_divisible(v: usize, divisor: usize) -> usize {
let d = divisor;
((v + d / 2) / d) * d
}
pub struct HeliosScaleOutput {
pub cls_logits: Variable,
pub bbox_dfl: Variable,
pub stride: usize,
}
pub struct HeliosTrainOutput {
pub scales: Vec<HeliosScaleOutput>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_nano() {
let cfg = HeliosConfig::nano(80);
assert_eq!(cfg.num_classes, 80);
let ch = cfg.stage_channels();
assert_eq!(ch, [16, 32, 64, 128, 256]);
let depths = cfg.stage_depths();
assert_eq!(depths, [1, 2, 2, 1]);
}
#[test]
fn test_config_small() {
let cfg = HeliosConfig::small(80);
let ch = cfg.stage_channels();
assert_eq!(ch, [32, 64, 128, 256, 512]);
}
#[test]
fn test_config_large() {
let cfg = HeliosConfig::large(80);
let ch = cfg.stage_channels();
assert_eq!(ch, [64, 128, 256, 512, 1024]);
let depths = cfg.stage_depths();
assert_eq!(depths, [3, 6, 6, 3]);
}
#[test]
fn test_make_divisible() {
assert_eq!(make_divisible(15, 8), 16);
assert_eq!(make_divisible(64, 8), 64);
assert_eq!(make_divisible(48, 8), 48);
assert_eq!(make_divisible(100, 8), 104);
}
}