推理
ai.infer("a.jpg")?; ai.infer(&bytes)?; ai.infer(&dynamic_image)?;
调用失败错误写进 last_error(),成功即清空,Phase 保持 Opened。
快速开始
let mut ai = Model::new("model.darmodel")?;
ai.open(None)?;
let inf = ai.infer_file("a.jpg", None)?;
println!("{inf:?}");
方法
| 类别 | 方法 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| 推理 | infer_file() | Result<InferenceResult, AiError> | 写 | 读取图片文件并推理 |
| 推理 | infer_image() | Result<String, AiError> | 写 | 对内存里的图像推理 |
| 推理 | infer_buffer() | Result<String, AiError> | 写 | 对裸像素缓冲推理 |
| Session | infer_tensors() | Result<Vec<Tensor>, Error> | 写 | 多输入张量推理(属于 Session 高级面,不是 Model 的成员) |
| 控制 | cancel() | Result<(), AiError> | 写 | 取消正在跑的或下一次推理 |
| 并发 | submit() | Result<u64, AiError> | 写 | 提交一张图进去,返回任务句柄 |
| 并发 | wait() | Result<String, AiError> | 写 | 等待结果 JSON |
| 并发 | set_device_weight() | Result<(), Error> | 写 | 运行时改每张卡的权重,只影响之后提交的任务 |
infer_file()
pub fn infer_file(&self, image_path: impl AsRef<Path>, thresholds: Option<&LabelThresholds>)
-> Result<InferenceResult, AiError>
支持 JPG、PNG、BMP,格式自动识别。
参数:
image_path(impl AsRef<Path>) — 图片文件路径thresholds(Option<&LabelThresholds>) — 只覆盖这一次调用的阈值。传None就用实例默认表
示例:
for path in ["a.jpg", "b.jpg", "c.jpg"] {
match ai.infer_file(path, None) {
Ok(inf) => println!("{inf:?}"),
Err(e) => eprintln!("{path} 失败: {}", e.message),
}
}
infer_image()
pub fn infer_image(&self, image: &[u8], desc: &ImageDesc, thresholds: Option<&LabelThresholds>)
-> Result<String, AiError>
编码过的字节配 ImageDesc::auto()。
参数:
image(&[u8]) — 图片字节(编码流或裸像素)desc(&ImageDesc) — 图像描述thresholds(Option<&LabelThresholds>) — 同infer_file
示例:
let json = ai.infer_image(&photo, &ImageDesc::auto(), None)?;
println!("{json}");
infer_buffer()
pub fn infer_buffer(&self, data: &[u8], desc: &ImageDesc, thresholds: Option<&LabelThresholds>) -> Result<String, AiError>
这是裸像素缓冲的入口,比如相机缓冲或内存位图。data 是像素字节,宽高与格式写进 ImageDesc。
参数:
data(&[u8]) — 像素字节desc(&ImageDesc) — 宽高与格式必填(裸缓冲禁 Auto)thresholds(Option) — 本次阈值覆盖
示例:
use darra_ai::ImageDesc;
match m.infer_buffer(&raw, &ImageDesc::rgb888(640, 480, 0), None) {
Ok(json) => println!("{json}"),
Err(e) => eprintln!("推理失败 {} {}", e.code, e.message),
}
infer_tensors()
pub fn infer_tensors(&self, inputs: &[Tensor]) -> Result<Vec<Tensor>, Error>
这是 Session 的方法(不在 Model 上),直接把张量喂给模型。
参数:
inputs(&[Tensor]) — 输入张量列表,name对齐 schema I/O 名
示例:
match session.infer_tensors(&[input]) {
Ok(outs) => println!("输出 {} 个张量", outs.len()),
Err(Error::MetaMismatch { message, .. }) => eprintln!("与模型对不上: {message}"),
Err(e) => eprintln!("张量推理失败: {}", e.message()),
}
cancel()
pub fn cancel(&self) -> Result<(), AiError>
取消正在跑的或下一次推理的可中断等待,取消标志用一次就消耗掉。未 open 先取消属参数契约违反。
参数: 无
示例:
// 在飞取消:另起线程调用
let h = std::thread::spawn(|| {
if let Err(e) = m.cancel() {
eprintln!("取消失败 {} {}", e.code, e.message);
}
});
阈值
default_thresholds 是实例的默认表。标签名映射到分数下限 [0,1]。
let t = LabelThresholds::from_pairs([("缺陷", 0.5), ("划痕", 0.8)])?;
ai.set_default_thresholds(t)?;
let one = LabelThresholds::from_pairs([("缺陷", 0.9)])?;
match ai.infer_file("a.jpg", Some(&one)) {
Ok(inf) => println!("{inf:?}"),
Err(e) => eprintln!("{} {}", e.code, e.message),
}
并发推理
一个 Model 只装一个模型。要跑两个模型,建两个实例,各自 open。
空闲机实测(197,det.onnx,3 轮中位):
- 单任务基线:1×(约 0.2s)
- 池
workers=2双投:两任务同时完成,各约 1–1.5 倍单任务 - 多实例 2–4 个:总吞吐约等于串行(0.88–0.94×) 并发收益随机器负载变化。
submit
pub fn submit(&self, image: &[u8], desc: &ImageDesc) -> Result<u64, AiError>
把一张图提交进池队列,立即返回 ticket(u64)。图像字节会被拷走,所以入参切片在返回后就可以释放。
参数:
image(&[u8]) — 图像字节(编码流或裸像素)desc(&ImageDesc) — 图像描述
示例:
let t = m.submit(&bytes, &ImageDesc::auto())?;
wait
pub fn wait(&self, ticket: u64) -> Result<String, AiError>
按 ticket 取这个任务的结果 JSON,会阻塞到任务完成或等待预算耗尽。
参数:
ticket(u64) —submit返回的票据,必填
示例:
let json = m.wait(t)?;
set_device_weight()
pub fn set_device_weight(&self, gpu_device: i32, weight: i32) -> Result<(), Error>
这个方法在运行期修改某张卡的权重。传 1 到 10000 表示新权重。
参数:
gpu_device(i32) — GPU 卡号weight(i32) — 新权重,1 到 10000
示例:
pool.set_device_weight(1, 50)?;
线程安全
不同的会话互不干扰,可以并发调用。Drop 只在没有正在执行的调用时才会真正释放。
队列满与挤掉(overflow 三态)
InferOverflow 有三个值。Fail 是默认,submit 立即失败。
| 现象 | 返回 | 处置 |
|---|---|---|
Fail 队列满的 submit | Error::Busy | 加大 queue_capacity,或降低提交速率 |
DropOldest 挤掉后 wait 取该票 | Error::Busy | 计入 report 的 dropped;要保帧用 Fail 或加大 queue_capacity |
try_wait 还没好 | Error::Busy | 轮询重试,或改用 wait 阻塞取 |
| 等待预算耗尽 | Error::Timeout | 加大 timeout_ms 或降并发。深层 Provider Run 不受这条裁决 |
被 cancel() / 协作标志打断 | Error::Cancelled | 被取消帧按丢帧处理 |
| 缺 Provider 运行时包 | Error::ProviderMissing | 装对应 Provider 运行时包 |