refactor(load,tract):将 ModelMetadata JSON 加载逻辑解耦至 ddddocr-tract, 优化 Error 枚举结构与错误透传
- 在 load 模块中精简 Error 与 Result 别名定义 - 增加 ParseError 子类型区分路径与字节流加载失败 - 支持通过 #[from] 自动转换 Tract 引擎底层错误 - 移出 core 中的 serde 依赖,保持核心库纯洁 - 在 tract 中实现 TractModelMetadata 扩展 trait 加载解析配置
This commit is contained in:
@@ -1,68 +1,45 @@
|
||||
use crate::loader::ModelLoader;
|
||||
use anyhow::Context;
|
||||
use ddddocr_core::error::{DdddError, Result, TensorErrorReason};
|
||||
use crate::types::Session;
|
||||
use ddddocr_core::error::{Result, TensorError};
|
||||
use ddddocr_core::{DetEngine, DetOutput, InferenceEngine};
|
||||
use ndarray::Ix3;
|
||||
use std::path::Path;
|
||||
use tract_onnx::prelude::{Graph, IntoTensor, RunnableModel, Tensor, TypedFact, TypedOp, tvec};
|
||||
use tract_onnx::prelude::{tvec, IntoTensor, Tensor};
|
||||
#[derive(Debug)]
|
||||
pub struct DetSession {
|
||||
pub session: RunnableModel<TypedFact, Box<dyn TypedOp>, Graph<TypedFact, Box<dyn TypedOp>>>,
|
||||
pub session: Session,
|
||||
}
|
||||
|
||||
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 new(session: Session) -> Self {
|
||||
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> {
|
||||
fn inference(&self, input_array: ndarray::Array4<f32>) -> Result<Self::Output, TensorError> {
|
||||
// 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())).map_err(|_| {
|
||||
DdddError::Inference(TensorErrorReason::EngineError(
|
||||
"执行模型推理失败".to_string(),
|
||||
))
|
||||
})?;
|
||||
let mut result = self
|
||||
.session
|
||||
.run(tvec!(tensor.into()))
|
||||
.map_err(|_| TensorError::Engine("执行模型推理失败".to_string()))?;
|
||||
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>().map_err(|_| {
|
||||
DdddError::Inference(TensorErrorReason::EngineError(
|
||||
"Tract 实体张量无法转换为 ndarray::ArrayD".to_string(),
|
||||
))
|
||||
TensorError::Engine("Tract 实体张量无法转换为 ndarray::ArrayD".to_string())
|
||||
})?;
|
||||
// 提前利用克隆(Clone)备份好当前未转维度前的真实 shape (Vec<usize>)
|
||||
let actual_shape = array_d.shape().to_vec();
|
||||
|
||||
let array3 = array_d.into_dimensionality::<Ix3>().map_err(|_| {
|
||||
DdddError::Inference(TensorErrorReason::TensorDimensionMismatch {
|
||||
TensorError::DimensionMismatch {
|
||||
expected: "3D 检测矩阵 [Batch, Box_Count, Box_Attributes]".to_string(),
|
||||
actual: actual_shape, // 优雅降维失败时动态捕获
|
||||
})
|
||||
}
|
||||
})?;
|
||||
Ok(DetOutput::Detection(array3))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user