推理
m.infer("a.jpg"); m.infer(bytes); m.infer(image);
调用失败不抛异常,错误留在 AiResult 与 getLastError(),模型 Phase 保持 Opened。
快速开始
Model m = new Model("yolov8n.darmodel");
if (!m.open()) {
System.out.println(m.getLastError());
return;
}
AiResult<InferenceResult> r = m.inferFile("photo.jpg");
if (r.isSuccess()) {
for (InferenceItem it : r.getContent().items())
System.out.println(it.label() + " " + it.score());
}
m.close();
基础用法
inferFile()
public AiResult<InferenceResult> inferFile(String imagePath)
public AiResult<InferenceResult> inferFile(Path imagePath)
按图片文件推理,JPG/PNG/BMP 自动识别。文件不存在即失败,失败读结果里的错误码。
参数:
imagePath(String 或 Path) — 图片文件路径
inferImage()
public AiResult<InferenceResult> inferImage(byte[] imageBytes, ImageDesc desc)
public AiResult<InferenceResult> inferImage(ByteBuffer buf, ImageDesc desc)
public AiResult<InferenceResult> inferImage(BufferedImage img)
内存里已解码的图直接传,裸像素走 inferBuffer。
参数:
imageBytes(byte[] 或 ByteBuffer) — 编码字节流或裸像素。BufferedImage重载传已解码图像desc(ImageDesc) — 图像描述,决定解码口径
示例:
byte[] bytes = Files.readAllBytes(Path.of("photo.jpg"));
AiResult<InferenceResult> r = m.inferImage(bytes, ImageDesc.auto());
inferBuffer()
public AiResult<InferenceResult> inferBuffer(byte[] pixels, ImageDesc desc)
public AiResult<InferenceResult> inferBuffer(ByteBuffer buf, ImageDesc desc)
裸像素缓冲入口(相机缓冲、内存位图)。宽高与像素格式写进 ImageDesc,格式必须显式指定,禁止 AUTO。
参数:
pixels/buf(byte[] / ByteBuffer) — 裸像素,必填desc(ImageDesc) — 宽高与像素格式,必填
cancel()
public void cancel()
取消正在跑的推理,回执走 AiResult;深层推理会跑完再丢结果,硬截止配合 setTimeout。
示例:
m.cancel();
批量
逐张排队,失败记日志,不中断整批:
for (String path : files) {
AiResult<InferenceResult> r = ai.inferFile(path);
if (!r.isSuccess()) {
log.add(path + " " + r.getMessage());
continue;
}
}
并发推理
一个 Model 只绑一个模型路径。
空闲机实测(197,det.onnx,3 轮中位):
- 单任务基线:1×(约 0.2s)
- 池
workers=2双投:两任务同时完成,各约 1–1.5 倍单任务 - 多实例 2–4 个:总吞吐约等于串行(0.88–0.94×) 并发收益随机器负载变化。
Model 不暴露 weight,多模型设权重走 SessionOptions.weight。
setDeviceWeight()
public void setDeviceWeight(int gpuDevice, int weight)
运行期改某张卡的接活权重,只影响新进件,不抢在跑任务、不加卡。weight 1–10000 为新权重,0 表示不再接新活;长期分活比例约等于权重占比。
参数:
gpuDevice(int) — 卡号weight(int) — 1 到 10000 新权重,0 = 不再接新活
示例:
pool.setDeviceWeight(0, 500);
long t = pool.submit(jpg, ImageDesc.auto(), -1);
String json = pool.wait(t);
submit 的 gpuDevice 传 -1 按权重分活,传具体卡号钉到该卡;DROP_OLDEST 挤掉的任务 wait 报失败。
submit / wait:submit() 投池队列返回 ticket,用 waitFor(ticket) 或 wait(ticket) 取结果。
long ticket = pool.submit(bytes, ImageDesc.auto());
String json = pool.waitFor(ticket);
线程安全:
| 调用 | 线程安全 | 备注 |
|---|---|---|
| ModelProbe.probe | 是 | 只读文件解析,不会建会话 |
| Model 推理入口(inferFile / inferImage / inferBuffer) | 否 | 单会话互斥,并发走 InferPool |
| AiDevicePool.submit | 是 | 可多线程提交,图像字节会被拷走 |
| AiDevicePool.setDeviceWeight | 是 | 运行期改每卡接活权重,只影响新进件、不抢占、不加卡 |
| AiDevicePool.close | 否 | 不能和 submit / wait 并发 |
阈值
getDefaultThresholds() 返回实例默认表(键为标签名,值为分数下限 [0,1],空表或 null 不过滤)。infer 各入口的 thresholds 参数按标签名只覆盖本次调用。
m.setDefaultThresholds(Map.of("person", 0.5));
AiResult<InferenceResult> r = m.inferFile("photo.jpg", Map.of("person", 0.6));
当前 Core 推理签名没有 per-call 阈值形参,覆盖走默认阈值路径。