- 移除 核心层与 tract/Tensor 的强耦合,前/后处理全线转用标准 ndarray - 针对 OCR 与目标检测(Det)分别设计独立的强类型输出小枚举(OcrOutput/DetOutput) - 利用 Trait 关联类型(Associated Type)InferenceEngine,OcrEngine,DetEngine 统一接口,实现多后端解耦 - 引入 thiserror 库,建立完备的强类型错误处理机制(DdddError/Result) - 完成项目结构初拆,剥离为 ddddocr-core 和 ddddocr-tract
81 lines
3.0 KiB
Rust
81 lines
3.0 KiB
Rust
use crate::loader::{ModelLoader, ModelSession, ModelType};
|
|
use anyhow::Context;
|
|
use ddddocr_core::error::{DdddError, Result};
|
|
use ddddocr_core::{DetEngine, DetOutput, InferenceEngine};
|
|
use ndarray::Ix3;
|
|
use std::path::Path;
|
|
use tract_onnx::prelude::{Graph, IntoTensor, RunnableModel, Tensor, TypedFact, TypedOp, tvec};
|
|
#[derive(Debug)]
|
|
pub struct DetSession {
|
|
pub session: RunnableModel<TypedFact, Box<dyn TypedOp>, Graph<TypedFact, Box<dyn TypedOp>>>,
|
|
}
|
|
|
|
impl ModelSession for DetSession {
|
|
fn get_model_type(&self) -> ModelType {
|
|
todo!()
|
|
}
|
|
fn desc(&self) -> String {
|
|
"Detection Model 加载成功".to_string()
|
|
}
|
|
}
|
|
|
|
impl DetSession {
|
|
pub fn new<P>(model_path: P) -> Result<Self>
|
|
where
|
|
P: AsRef<Path>,
|
|
{
|
|
let session = ModelLoader::model_for_path(&model_path)?.session;
|
|
Ok(Self { session })
|
|
}
|
|
|
|
pub fn model_from_bytes(model_bytes: &[u8]) -> Result<Self> {
|
|
let session = ModelLoader::model_from_bytes(model_bytes)?.session;
|
|
Ok(Self { session })
|
|
}
|
|
// pub fn inference(&self, tensor: Tensor) -> anyhow::Result<Tensor> {
|
|
// // tract 的 run 会返回一个 Vec<TValue>,我们通常只需要第一个输出
|
|
// // let result = self.ocr.run(tvec!(tensor.into()))?;
|
|
// let mut result = self
|
|
// .session
|
|
// .run(tvec!(tensor.into()))
|
|
// .context("执行模型推理失败")?;
|
|
// println!("模型输出原始数据: {:?}", result);
|
|
// Ok(result.swap_remove(0).into_tensor())
|
|
// }
|
|
}
|
|
|
|
impl InferenceEngine for DetSession {
|
|
type Output = DetOutput; // 明确绑定 OCR 小枚举
|
|
fn inference(&self, input_array: ndarray::Array4<f32>) -> Result<Self::Output> {
|
|
// tract 的 run 会返回一个 Vec<TValue>,我们通常只需要第一个输出
|
|
// let result = self.ocr.run(tvec!(tensor.into()))?;
|
|
let tensor = Tensor::from(input_array);
|
|
|
|
let mut result = self
|
|
.session
|
|
.run(tvec!(tensor.into()))
|
|
.context("执行模型推理失败")?;
|
|
println!("模型输出原始数据: {:?}", result);
|
|
// Ok(result.swap_remove(0).into_tensor())
|
|
let raw_tensor = result.swap_remove(0).into_tensor();
|
|
let array_d = raw_tensor
|
|
.into_array::<f32>()
|
|
.context("Tract 实体张量无法转换为 ndarray::ArrayD")?;
|
|
// 提前利用克隆(Clone)备份好当前未转维度前的真实 shape (Vec<usize>)
|
|
let actual_shape = array_d.shape().to_vec();
|
|
|
|
let array3 =
|
|
array_d
|
|
.into_dimensionality::<Ix3>()
|
|
.map_err(|_| DdddError::DimensionMismatch {
|
|
expected: "3D 检测矩阵 [Batch, Box_Count, Box_Attributes]".to_string(),
|
|
actual: actual_shape, // 优雅降维失败时动态捕获
|
|
})?;
|
|
Ok(DetOutput::Detection(array3))
|
|
|
|
// 在引擎内部消化掉 DatumType 强耦合
|
|
}
|
|
}
|
|
|
|
impl DetEngine for DetSession {}
|