模型加速器 Batch 批处理加速
下面以猫狗分类和气球实例分割为例,演示模型加速、C# 测速和批量调用。
同一批输入图片的宽和高必须一致。
1. 准备模型和图片
- 准备猫狗分类和气球实例分割的 DVP 模型。将每个模型复制成两份,放在不同文件夹,分别生成单张模型和批处理模型。
- 准备好输入图片:猫狗图片为 224 × 224,气球图片为 640 × 640。可直接使用下文展示的图片。
2. 猫狗分类:加速与测速
猫图和狗图均为 224 × 224。两组测速都使用 cat.jpg。
| 猫:cat.jpg,224 × 224 | 狗:dog.jpg,224 × 224 |
|---|---|
![]() | ![]() |
2.1 生成单张和批处理模型
- 打开模型加速器,选择猫狗分类 DVP、GPU 和已授权的加密狗,推理后端选择 TensorRT。
- 开启 FP16,关闭“通用架构 PLUS”和“使用多尺度输入”。
- 不勾选“使用批处理”,点击“加速”。将生成的 DVT 命名为
猫狗分类_batch1.dvt。 - 选择另一份猫狗分类 DVP,勾选“使用批处理”。这个选项让模型可以一次处理多张图片;保留默认推荐值 128,即一次最多处理 128 张图片。
- 点击“加速”,将生成的 DVT 命名为
猫狗分类_batch128.dvt。
下图左侧为单张模型,右侧为批处理模型,橙色框标出了设置位置。图片可以点击放大。
| 左:模型加速器,batch=1 | 右:模型加速器,默认 batch=128 |
|---|---|
![]() | ![]() |
2.2 用 C# 测试程序测速
- 打开 C# 测试程序,加载
猫狗分类_batch1.dvt,选择加速时使用的 GPU,设置 batch_size=1、线程数=1。 - 将 threshold 设为 0.50,关闭 RPC 和均值计算。点击“打开图片推理”,加载
cat.jpg,确认显示分类结果。 - 点击“多线程测试”,运行 10 秒后停止,记录结果。
- 换成
猫狗分类_batch128.dvt,将 batch_size 设为 32,也就是每次推理处理 32 张图片。线程数仍为 1,保持单线程进行对比。 - 对同一张
cat.jpg再次运行“多线程测试”。
| 左:C# 测试程序,batch=1、线程=1 | 右:C# 测试程序,batch=32、线程=1 |
|---|---|
![]() | ![]() |
2.3 速度与模型大小
| 指标 | batch=1 | batch=32 |
|---|---|---|
| 实时速率 | 1444.11 张/秒 | 9211.77 张/秒 |
| 平均延迟 | 0.81 ms | 3.29 ms |
| 模型大小 | 23.98 MB | 24.93 MB |
3. 气球实例分割:加速与测速
3.1 生成单张和批处理模型
- 在模型加速器中选择气球实例分割 DVP,使用同一块 GPU、已授权的加密狗和 TensorRT,开启 FP16。
- 保留“使用多尺度输入”,IoU 阈值设为 0.2、检测数量设为 100,关闭均值计算和“通用架构 PLUS”。
- 不勾选“使用批处理”,点击“加速”,将生成的 DVT 命名为
气球实例分割_batch1.dvt。 - 选择另一份气球实例分割 DVP,勾选“使用批处理”,保留默认推荐值 4,点击“加速”,将生成的 DVT 命名为
气球实例分割_batch4.dvt。
| 左:模型加速器,batch=1 | 右:模型加速器,batch=4 |
|---|---|
![]() | ![]() |
3.2 用 C# 测试程序测速
- 加载
气球实例分割_batch1.dvt,设置 batch_size=1、线程数=1,其余设置与分类测速相同。 - 点击“打开图片推理”,加载 640 × 640 的
balloon-1.jpg,再点击“多线程测试”,运行 10 秒后停止。 - 加载
气球实例分割_batch4.dvt,将 batch_size 设为 4、线程数保持 1。每次推理处理 4 张图片,对同一张balloon-1.jpg重复测速。
| 左:C# 测试程序,batch=1、线程=1 | 右:C# 测试程序,batch=4、线程=1 |
|---|---|
![]() | ![]() |
3.3 速度与模型大小
| 指标 | batch=1 | batch=4 |
|---|---|---|
| 实时速率 | 203.44 张/秒 | 292.38 张/秒 |
| 平均延迟 | 4.87 ms | 13.59 ms |
| 模型大小 | 31.32 MB | 32.12 MB |
4. 用 C# 批量处理两张图片
4.1 读取两张气球图片
加载 气球实例分割_batch4.dvt,读取下面两张图片,并将颜色通道从 BGR 转为 RGB。
两张输入图片均为 640 × 640,按以下顺序放入同一个 List:
| images[0]:balloon-1.jpg,640 × 640 | images[1]:balloon-2.jpg,640 × 640 |
|---|---|
![]() | ![]() |
4.2 调用 InferBatch
将两张图片放入 List<Mat>,调用一次 InferBatch。与逐张调用相比:
| 调用方式 | 单张模型逐张处理 | 批处理模型一次传多张 |
|---|---|---|
| 加载模型 | new Model("气球实例分割_batch1.dvt", 0) | new Model("气球实例分割_batch4.dvt", 0) |
| 输入 | 每次一个 Mat | new List<Mat> { rgb0, rgb1 } |
| 调用 | 两次 Infer | 一次 InferBatch |
| 返回值 | 每次一个 CSharpResult,各含一份图片结果 | 一个 CSharpResult,按输入顺序含两份图片结果 |
| 第一张图片 | 第一次结果的 SampleResults[0] | 批量结果的 SampleResults[0] |
| 第二张图片 | 第二次结果的 SampleResults[0] | 批量结果的 SampleResults[1] |
核心调用如下;rgb0、rgb1 是两张已转换为 RGB 的图片,parameters 是下方完整示例中的参数对象:
// 单张调用:分别读取每次返回的 SampleResults[0]。
Utils.CSharpResult first = singleModel.Infer(rgb0, parameters);
Utils.CSharpResult second = singleModel.Infer(rgb1, parameters);
// 批量调用:列表顺序就是 SampleResults 的图片顺序。
var images = new List<Mat> { rgb0, rgb1 };
Utils.CSharpResult batch = batchModel.InferBatch(images, parameters);
List<Utils.CSharpObjectResult> objects0 = batch.SampleResults[0].Results;
List<Utils.CSharpObjectResult> objects1 = batch.SampleResults[1].Results;
本次加载的气球模型支持最多 4 张图片,GetMaxBatchSize() 返回 4。这里传入 2 张图片,就返回 2 份图片结果。
分类使用同一套接口:一次传入 32 张 RGB 图片,从 SampleResults[0] 到 SampleResults[31] 读取对应图片的分类结果。Results.Count > 0 时读取该图片的 Results[0]。
4.3 运行完整 C# 示例
创建 .NET Framework 4.7.2、x64 控制台项目,按 C# 接口说明引用 DlcvCsharpApi.dll、OpenCvSharp.dll、Newtonsoft.Json.dll,并保持高性能 SDK 的原生运行库可用。输入是普通彩色 JPG,OpenCV 读取为 BGR,调用前转换为 RGB。
将下方代码放入控制台项目,编译后传入模型路径和两张图片路径:
.\BatchBalloonExample.exe ".\气球实例分割_batch4.dvt" ".\balloon-1.jpg" ".\balloon-2.jpg"
展开完整 C# 代码
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using dlcv_infer_csharp;
using Newtonsoft.Json.Linq;
using OpenCvSharp;
class BatchBalloonExample
{
static void Main(string[] args)
{
Console.OutputEncoding = new UTF8Encoding(false);
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
if (args.Length != 3)
throw new ArgumentException("需要模型路径和两张图片路径。");
Model.EnableConsoleLog = false;
using (var model = new Model(args[0], 0))
using (var bgr0 = Cv2.ImRead(args[1], ImreadModes.Color))
using (var bgr1 = Cv2.ImRead(args[2], ImreadModes.Color))
using (var rgb0 = new Mat())
using (var rgb1 = new Mat())
{
if (bgr0.Empty() || bgr1.Empty())
throw new InvalidOperationException("图片读取失败。");
if (bgr0.Width != bgr1.Width || bgr0.Height != bgr1.Height)
throw new ArgumentException("同一批图片的宽和高必须一致。");
if (model.GetMaxBatchSize() < 2)
throw new InvalidOperationException("需要支持至少两张图片的批处理模型。");
Cv2.CvtColor(bgr0, rgb0, ColorConversionCodes.BGR2RGB);
Cv2.CvtColor(bgr1, rgb1, ColorConversionCodes.BGR2RGB);
var images = new List<Mat> { rgb0, rgb1 };
var parameters = new JObject
{
["threshold"] = 0.5,
["with_mask"] = true,
["calc_mean"] = false
};
Utils.CSharpResult result = model.InferBatch(images, parameters);
try
{
if (result.SampleResults.Count != images.Count)
throw new InvalidOperationException("返回图片数量与输入数量不一致。");
var text = new StringBuilder();
text.AppendLine("C# InferBatch: two different balloon images");
text.AppendLine($"Input size = {bgr0.Width}x{bgr0.Height}");
text.AppendLine("GetMaxBatchSize() = " + model.GetMaxBatchSize());
text.AppendLine("images.Count = " + images.Count);
text.AppendLine("result.SampleResults.Count = " + result.SampleResults.Count);
text.AppendLine();
for (int i = 0; i < result.SampleResults.Count; i++)
{
List<Utils.CSharpObjectResult> objects = result.SampleResults[i].Results;
text.AppendLine($"SampleResults[{i}] <- {Path.GetFileName(args[i + 1])}");
text.AppendLine($" Results.Count = {objects.Count}");
for (int j = 0; j < objects.Count; j++)
{
var obj = objects[j];
text.AppendLine($" Results[{j}]: CategoryId={obj.CategoryId}, CategoryName={obj.CategoryName}");
text.AppendLine($" Score={obj.Score:F4}, Bbox=[{string.Join(", ", obj.Bbox.ConvertAll(v => v.ToString("F1")))}]");
text.AppendLine($" WithMask={obj.WithMask}, Mask={obj.Mask.Width}x{obj.Mask.Height}");
}
text.AppendLine();
}
Console.Write(text.ToString());
File.WriteAllText("batch-result.txt", text.ToString(), new UTF8Encoding(false));
List<Mat> painted = Utils.VisualizeResults(new List<Mat> { bgr0, bgr1 }, result);
try
{
for (int i = 0; i < painted.Count; i++)
Cv2.ImWrite($"balloon-{i + 1}-result.png", painted[i]);
}
finally
{
foreach (Mat image in painted) image.Dispose();
}
}
finally
{
foreach (var sample in result.SampleResults)
foreach (var obj in sample.Results)
obj.Mask?.Dispose();
}
}
}
}
程序输出 batch-result.txt、balloon-1-result.png、balloon-2-result.png。代码中的两张图片、批量结果和可视化结果使用相同的顺序。
5. 读取每张图片的结果
5.1 按图片读取目标
InferBatch 返回 Utils.CSharpResult。通过 SampleResults 逐图读取结果,再通过每张图片的 Results 读取目标:
CSharpResult
└─ SampleResults:List<CSharpSampleResult>,Count = 2
├─ [0] 对应 images[0],即 balloon-1.jpg
│ └─ Results:List<CSharpObjectResult>,Count = 1
│ └─ [0] 黑色气球
└─ [1] 对应 images[1],即 balloon-2.jpg
└─ Results:List<CSharpObjectResult>,Count = 3
├─ [0] 左侧黄色气球
├─ [1] 右侧绿色气球
└─ [2] 中间浅色气球
外层按图片组织,内层按目标组织。本次输入 2 张图片,SampleResults.Count 为 2;两张图片分别检测到 1 个和 3 个气球,各自的 Results.Count 为 1 和 3。
5.2 C# 输出与结果图
以下为 C# 程序保存的结果列表,在控制台中展示:

与列表对应的可视化图由同次调用结果经 Utils.VisualizeResults 保存:
| SampleResults[0]:1 个气球 | SampleResults[1]:3 个气球 |
|---|---|
![]() | ![]() |
本次 SampleResults[0].Results[0] 的主要值为:
| C# 字段 | 实际值 | 读取说明 |
|---|---|---|
CategoryId / CategoryName | 0 / 气球 | 模型类别编号与名称 |
Score | 0.9893 | 置信度,对应 98.93% |
Bbox | [25.6, 22.8, 324.4, 521.3] | [x, y, width, height],对应原图中的左上角坐标、宽度和高度 |
WithMask | true | 本目标包含分割 mask |
Mask | 324 × 521 的 Mat | 目标区域 mask,使用 SDK 可视化放回原图 |
通过 WithMask 判断目标是否包含 mask,通过 Mask 读取分割图。使用完毕后释放各个 Mask、输入图片和模型。
6. 测试记录与相关文档
下载 测试记录。
本次测试环境与设置
| 项目 | 本文设置 |
|---|---|
| 测试日期与系统 | 2026-09-29,气球 batch=4 重测于 2026-09-30;Windows x64 |
| 显卡 | NVIDIA GeForce RTX 5080 |
| 模型加速器 | 模型加速器 dlcvpro_deploy-2026.9.28.1 |
| C# 测试程序 | C# 测试程序 dlcvpro_infer_csharp-2026.9.29.0 |
| 推理运行库 | 分类与气球 batch=1:dlcvpro_infer-2026.9.28.0a0;气球 batch=4:dlcvpro_infer-2026.9.29.0 |
| 加速后端 | TensorRT,开启 FP16,关闭通用架构 PLUS |
| C# 参数 | GPU 0;线程数 1;threshold=0.50;关闭 RPC;关闭均值计算 |
| 测速图片 | 同组使用同一张已读入内存的图片,按 batch_size 重复组批后连续推理 |
| 测速方法 | 加载模型、完成首次图片推理后,运行“多线程测试”,各组串行运行 |
| 实例分割输出 | 保留 mask;IoU 阈值 0.2;检测数量 100 |













