use anyhow::Result;
use mecha10_core::model::PreprocessingConfig;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ModelCatalogEntry {
pub name: String,
pub description: String,
pub task: String,
pub repo: String,
pub filename: String,
#[serde(default)]
pub preprocessing_preset: Option<String>,
#[serde(default)]
pub classes: Vec<String>,
#[serde(default)]
pub quantize: Option<QuantizeConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct QuantizeConfig {
pub enabled: bool,
pub method: String,
}
#[derive(Debug, Deserialize)]
pub(super) struct ModelCatalog {
pub(super) models: Vec<ModelCatalogEntry>,
}
#[derive(Debug, Clone, Copy)]
pub enum PreprocessingPreset {
ImageNet,
Yolo,
Coco,
Zero255,
}
impl PreprocessingPreset {
pub fn from_name(name: &str) -> Result<Self> {
match name.to_lowercase().as_str() {
"imagenet" => Ok(Self::ImageNet),
"yolo" => Ok(Self::Yolo),
"coco" => Ok(Self::Coco),
"zero255" | "0-255" => Ok(Self::Zero255),
_ => anyhow::bail!("Unknown preprocessing preset: {}", name),
}
}
pub fn to_config(self) -> PreprocessingConfig {
match self {
Self::ImageNet | Self::Coco => PreprocessingConfig {
mean: [0.485, 0.456, 0.406],
std: [0.229, 0.224, 0.225],
channel_order: "RGB".to_string(),
},
Self::Yolo => PreprocessingConfig {
mean: [0.0, 0.0, 0.0],
std: [255.0, 255.0, 255.0],
channel_order: "RGB".to_string(),
},
Self::Zero255 => PreprocessingConfig {
mean: [0.0, 0.0, 0.0],
std: [1.0, 1.0, 1.0],
channel_order: "RGB".to_string(),
},
}
}
}
#[cfg(feature = "model-download")]
#[derive(Debug, Clone, Deserialize)]
pub(super) struct HFPreprocessorConfig {
#[serde(default)]
pub(super) image_mean: Option<Vec<f32>>,
#[serde(default)]
pub(super) image_std: Option<Vec<f32>>,
#[serde(default)]
pub(super) size: Option<HFSize>,
#[serde(default)]
pub(super) crop_size: Option<HFSize>,
}
#[cfg(feature = "model-download")]
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub(super) enum HFSize {
Dict { height: u32, width: u32 },
ShortestEdge { shortest_edge: u32 },
Single(u32), }
#[cfg(feature = "model-download")]
impl HFPreprocessorConfig {
pub(super) fn to_preprocessing(&self) -> PreprocessingConfig {
PreprocessingConfig {
mean: [
self.image_mean.as_ref().and_then(|v| v.first()).copied().unwrap_or(0.0),
self.image_mean.as_ref().and_then(|v| v.get(1)).copied().unwrap_or(0.0),
self.image_mean.as_ref().and_then(|v| v.get(2)).copied().unwrap_or(0.0),
],
std: [
self.image_std.as_ref().and_then(|v| v.first()).copied().unwrap_or(1.0),
self.image_std.as_ref().and_then(|v| v.get(1)).copied().unwrap_or(1.0),
self.image_std.as_ref().and_then(|v| v.get(2)).copied().unwrap_or(1.0),
],
channel_order: "RGB".to_string(),
}
}
pub(super) fn input_size(&self) -> Option<[u32; 2]> {
if let Some(crop_size) = &self.crop_size {
return match crop_size {
HFSize::Dict { height, width } => Some([*width, *height]),
HFSize::ShortestEdge { shortest_edge } => Some([*shortest_edge, *shortest_edge]),
HFSize::Single(s) => Some([*s, *s]),
};
}
match &self.size {
Some(HFSize::Dict { height, width }) => Some([*width, *height]),
Some(HFSize::ShortestEdge { shortest_edge }) => Some([*shortest_edge, *shortest_edge]),
Some(HFSize::Single(s)) => Some([*s, *s]),
None => None,
}
}
}