ErfNet图像分割模型
2. 方案简介
2.1 算法流程介绍
1. 模型背景
ErfNet(Efficient Residual Factorized Network) 是一款专为高效语义分割任务设计的神经网络结构,由 西班牙巴利亚多利德大学(University of Valladolid) 的研究团队于 2017 年在论文《ErfNet: Efficient Residual Factorized ConvNet for Real-time Semantic Segmentation》中首次提出,并发表在 arXiv 上。该模型主要面向自动驾驶场景中的城市街景语义分割任务,强调在保持较高准确率的同时实现低延迟与低计算成本。
ErfNet 的核心创新点体现在其提出的两项关键设计:
- 残差结构(Residual Connections):提高深层网络的可训练性,缓解梯度消失;
- 卷积因式分解(Factorized Convolutions):将常规的 3×3 卷积分解为连续的 1×3 和 3×1 卷积,大幅减少参数与计算量。
此外,ErfNet 引入了高效的 非对称残差模块(Non-bottleneck-1D block),结合上述设计在语义表达能力与推理速度之间取得了良好平衡。
其结构包含:
- 初始下采样层(Downsampling Blocks):快速压缩空间分辨率;
- 编码器(Encoder):堆叠多个非对称残差模块提取深层语义信息;
- 解码器(Decoder):通过反卷积逐步恢复空间分辨率;
- 跳跃连接(Optional Skip Connections):增强低层细节。
该网络具备以下特点:
- 所有卷积层均使用残差连接以确保信息流动顺畅;
- 不采用传统的大型预训练主干网络(如 ResNet),而是从零设计轻量结构,适用于实时推理和嵌入式部署;
- 不使用显式注意力机制,而是依靠结构本身完成特征融合与压缩。
2. 算法流程图
graph TD
A[输入图像] --> B[前处理]
B --> C[ErfNet模块]
C --> D[后处理]
3. 前处理(Host端CPU处理)
前处理流程:
graph LR
A[输入图像路径] --> B[图像加载]
B --> C[尺寸变换 + Padding]
C --> D[张量转换]
D --> E[DMA准备]
subgraph 前处理流程
B -->|cv::IMREAD_COLOR| B1["示例:/data/street.png"]
C --> C1[Resize长边1024px] --> C2["示例:1024x2048→512x1024"]
C2 --> C3[rPad填充] --> C4["示例:补高后→1024x1024"]
D --> D1["数据类型转换 uint8→float32"]
D1 --> D2["归一化 /255.0"]
D2 --> D3["通道转换 BGR→RGB"]
D3 --> D4["添加Batch维度 [1,3,1024,1024]"]
E --> E1["配置DMA参数"] --> E2["Host→NPU数据传输"]
end
style B fill:#F8CECC,stroke:#B85450
style C fill:#D5E8D4,stroke:#82B366
style D fill:#DAE8FC,stroke:#6C8EBF
style E fill:#FFF2CC,stroke:#D6B656
关键操作:
PicPre img(img_path, cv::IMREAD_COLOR); // 图像加载
img.Resize({ netinfo.i_cubic[0].h, netinfo.i_cubic[0].w }, PicPre::LONG_SIDE).rPad(); // 调整尺寸 + Padding填充
Tensor img_tensor = CvMat2Tensor(img.dst_img, network); // OpenCV Mat转Tensor
dmaInit(run_sim, netinfo.ImageMake_on, img_tensor, device); // DMA传输初始化
具体处理流程:
- 图像加载:通过 OpenCV 读取原始图像(
cv::IMREAD_COLOR保持 RGB 格式)- 示例:输入
img_path为"/data/street.png",图像尺寸为 1024×2048(高×宽)
- 示例:输入
- 尺寸变换与补边:
Resize:以 长边为基准(此处为宽 = 2048),将图像缩放,使其长边匹配目标尺寸(如输入为 512×1024,则长边为1024)- 缩放比例 = 1024 / 2048 = 0.5
- 缩放后图像尺寸为 512×1024
rPad:在 短边方向(此处为高 = 512) 进行对称补零,补成最终输入尺寸(如目标为 512×1024,实际已满足则无需额外 padding)- 若目标为正方形输入(如 1024×1024),则:
- 当前图像已为 512×1024,需要在高方向补齐至1024,高度补 512 像素(上下各补 256)
- 最终尺寸为 1024×1024
- 张量转换:
CvMat2Tensor完成以下处理:- 数据类型转换:
uint8 → float32 - 像素归一化(例如除以 255.0)
- 通道顺序调整:如 BGR → RGB(若模型要求)
- 添加 Batch 维度:转换后张量尺寸为
[1, 3, H, W],如[1, 3, 1024, 1024]
- 数据类型转换:
- DMA准备:
dmaInit函数配置 DMA 传输,将图像张量从主机内存拷贝至 NPU 设备端,用于硬件加速推理。
4. 后处理(Host端CPU处理)
后处理机制:
graph LR
A[NPU输出张量] --> B[数据回传]
B --> C[结果解析]
C --> D[尺寸调整]
D --> E[类别映射]
E --> F[可视化处理]
subgraph 后处理流程
B --> B1["to(HostDevice::MemRegion())"]
B1 --> B2["示例:shape=[1,512,512,19]"]
C --> C1["(float*/int8_t*)host_tensor.data().cptr()"]
D --> D1["resize(原图尺寸)"] --> D2["示例:512x512→1024x2048"]
E --> E1["map_plot颜色映射"] --> E2["使用Cityscapes调色板"]
F --> F1["cv::imwrite保存"] --> F2["示例:road→灰色,car→蓝色"]
end
style B fill:#F8CECC,stroke:#B85450
style C fill:#D5E8D4,stroke:#82B366
style D fill:#DAE8FC,stroke:#6C8EBF
style E fill:#FFF2CC,stroke:#D6B656
style F fill:#E1D5E7,stroke:#9673A6
关键操作:
// 数据回传
auto host_tensor = result_tensor[0].to(HostDevice::MemRegion());
// 结果解析(多通道float/单通道int8)
if (output_channel == 1) {
auto tensor_data = (int8_t*)host_tensor.data().cptr();
net_result_mat = cv::Mat(h,w,CV_8SC1,tensor_data);
} else {
auto tensor_data = (float*)host_tensor.data().cptr();
net_result_mat = cv::Mat(h,w,CV_32FC19,tensor_data);
}
// 尺寸调整
cv::resize(net_result_mat, resultMat, cv::Size(orig_w,orig_h), cv::INTER_LINEAR);
// 类别映射与可视化
map_plot(resultMat, img_id_mat, img_color_mat, img.dst_img);
具体处理流程:
-
数据回传
to(HostDevice::MemRegion())将NPU输出的分割张量复制到Host内存- 示例输出shape为
[1,512,512,19](Cityscapes的19类分割任务)
-
结果解析
- 根据输出类型(float多通道/int8单通道)转换数据指针
- 构建OpenCV矩阵:多通道用
CV_32FC19,单通道用CV_8SC1
-
尺寸调整
- 将网络输出resize到原始图像尺寸(如1024x2048)
- 使用双线性插值保持边缘平滑
-
类别映射
-
map_plot函数核心操作:解释// 像素级类别索引→调色板颜色 for(auto i : img_id){ if(i >= 19) color = [0,0,0]; // 未知类别用黑色 else color = PALETTE_CITYSCAPES[i]; // 按预设调色板着色 }
-
-
结果保存
- Windows/Linux路径差异化处理
- 保存两种结果:
img_id_mat:单通道类别ID图(可用于量化分析)img_color_mat:三通道伪彩色图(直观可视化)
2.2 硬件资源分配
1. 硬件映射策略
graph TD
subgraph CPU前处理
B1[图像加载: OpenCV读取] --> B2[尺寸变换: Resize]
B2 --> B3[补边处理: rPad]
B3 --> B4[张量转换: uint8转float32等]
end
subgraph ImageMake硬件加速
C1[DMA传输初始化: 主机到NPU]
end
subgraph NPU推理
D1[NPU推理计算]
end
subgraph CPU后处理
E1[数据回传: NPU到主机] --> E2[结果解析: float/int8转OpenCV矩阵]
E2 --> E3[尺寸调整: 调整到原始尺寸]
E3 --> E4[类别映射: 像素索引到颜色]
end
A[输入图像] --> B[CPU前处理]
B --> C[ImageMake硬件加速]
C --> D[NPU推理]
D --> E[detpost硬件加速]
E --> F[CPU后处理]
2. 硬件资源分配方案总表
| ** 硬件分配** | 代码/模块对应位置 | 关键变更说明 | ||
|---|---|---|---|---|
| 1. CPU前处理 | ||||
| - 图像加载 | OpenCV读取图像文件 | CPU | cv::imread(img_path) |
新增补边处理环节 |
| - 尺寸变换 | 动态Resize(保持长宽比) | CPU | cv::resize(..., INTER_LINEAR) |
支持非方形输入 |
| - 补边处理 | 四周Padding填充(常量值) | CPU | cv::copyMakeBorder() |
新增预处理步骤 |
| - 张量转换 | uint8转float32/归一化 | CPU | convertTo(CV_32F, 1/255.0) |
归一化合并到转换 |
| 2. ImageMake加速 | ||||
| - DMA传输初始化 | 主机内存→NPU内存 | FPGA | dmaInit(host_ptr, npu_ptr, size) |
硬件自动完成数据对齐 |
| 3. NPU推理 | ||||
| - 双分支卷积计算 | 细节分支+语义分支并行 | NPU | session.forward() |
新增双分支支持 |
| - BGALayer特征融合 | 动态加权融合双分支特征 | NPU | 编译器自动优化 | 新增硬件融合模块 |
| 4. CPU后处理 | ||||
| - 数据回传 | NPU内存→主机内存 | FPGA/CPU | tensor.to(HostDevice::MemRegion()) |
支持int8/float多格式 |
| - 结果解析 | 原始数据转OpenCV矩阵 | CPU | cv::Mat(..., data_ptr) |
自动识别单通道/多通道 |
| - 尺寸调整 | 还原至原始图像尺寸 | CPU | cv::resize(..., orig_h, orig_w) |
双线性插值保持边缘 |
| - 类别映射 | 像素索引→Cityscapes调色板 | CPU | map_plot()中的PALETTE_CITYSCAPES |
新增未知类别处理(填充黑色) |
| - 掩膜渲染 | 伪彩色结果叠加原始图 | CPU | cv::addWeighted() |
可调节透明度 |
3. 硬件-软件交互示意图
sequenceDiagram
participant Host as Host CPU
participant NPU as NPU/PL
participant DDR as 设备内存
Host->>Host: 图像加载/Resize/Crop
Host->>DDR: DMA传输预处理数据
NPU->>NPU: 执行模型推理
DDR->>Host: DMA回传输出张量
Host->>Host: Softmax/TopK处理
Host->>Host: 结果可视化与保存
3. 模型导出说明
ErfNet 主干
1)基础卷积算子:
- 常规卷积:
nn.Conv2d直接实现 - 转置卷积(上采样):
nn.ConvTranspose2d实现 - 批归一化:
nn.BatchNorm2d直接实现 - 池化操作:
nn.MaxPool2d实现下采样 - 正则化:
nn.Dropout2d实现通道随机失活
2)特殊卷积结构:
- 非对称卷积分解:
- 3x1卷积+1x3卷积:
nn.Conv2d组合实现 - 带膨胀率的非对称卷积:通过
dilation参数实现
- 3x1卷积+1x3卷积:
- 残差连接:通过张量相加实现
3)下采样模块:
- DownsamplerBlock:
- 并行路径:
- 卷积路径:
nn.Conv2d+nn.BatchNorm2d - 池化路径:
nn.MaxPool2d
- 卷积路径:
- 特征合并:通道维度拼接
- 批归一化:
nn.BatchNorm2d统一处理合并特征
- 并行路径:
4)上采样模块:
- UpsamplerBlock:
- 转置卷积:
nn.ConvTranspose2d实现2倍上采样 - 批归一化:
nn.BatchNorm2d处理上采样结果
- 转置卷积:
5)核心残差模块:
- non_bottleneck_1d:
- 双分支非对称卷积:
- 第一组:3x1→1x3卷积+BN
- 第二组:带膨胀率的3x1→1x3卷积+BN
- 残差连接:输入输出直接相加
- 正则化:
nn.Dropout2d
- 双分支非对称卷积:
6)编解码结构:
- 编码器(Encoder):
- 初始下采样块→多级下采样→系列non_bottleneck_1d
- 输出卷积:1x1卷积降维
- 解码器(Decoder):
- 上采样块→non_bottleneck_1d→上采样→输出转置卷积
7)特殊参数配置:
- 膨胀率设置:采用[1,2,4,8,16]的指数增长模式
- 批归一化参数:固定eps=0.001,momentum=0.1
- Dropout配置:编码器p=0.1,解码器p=0
8)维度变化处理:
- 下采样时通道扩展:通过concat合并卷积和池化路径
- 上采样时通道压缩:通过转置卷积同步调整空间和通道维度
5)ErfNet 与 Icraft 硬件支持算子对应表
| ERFNet 功能组件 | PyTorch 实现方式 | iCraft 对应算子组合 |
|---|---|---|
| 基础卷积算子 | ||
| 常规卷积 | nn.Conv2d |
Conv2d |
| 转置卷积(上采样) | nn.ConvTranspose2d |
ConvTranspose2d |
| 批归一化 | nn.BatchNorm2d |
BatchNorm2d |
| 最大池化 | nn.MaxPool2d |
MaxPool2d |
| Dropout正则化 | nn.Dropout2d |
不支持二维Dropout |
| 下采样模块 | ||
| DownsamplerBlock双路径 | Conv2d+MaxPool2d并行 → 通道拼接 |
Conv2d + MaxPool2d + Concat |
| 合并后批归一化 | nn.BatchNorm2d |
BatchNorm2d |
| 上采样模块 | ||
| UpsamplerBlock | ConvTranspose2d + BN |
ConvTranspose2d + BatchNorm2d |
| 核心残差模块 | ||
| non_bottleneck_1d | 3x1→1x3非对称卷积组合 | Conv2d(k=3x1) + Conv2d(k=1x3) ×2 |
| 带膨胀率的卷积 | dilation=[1,2,4,8,16] |
Conv2d(dilation=*) |
| 残差连接 | 张量相加 | Add |
| 编解码结构 | ||
| 编码器初始块 | DownsamplerBlock |
见下采样模块 |
| 编码器层级结构 | 交替使用下采样和non_bottleneck_1d | 组合对应算子 |
| 解码器上采样块 | UpsamplerBlock + non_bottleneck_1d |
见上采样模块和核心残差模块 |
| 特殊操作 | ||
| 输出卷积 | 1x1卷积降维 | Conv2d(k=1x1) |
| 多尺度膨胀卷积 | 膨胀率指数增长 | Conv2d(dilation=2^n) |
| 特征维度处理 | 通道拼接/维度调整 | Concat/Reshape |
| 激活函数 | ||
| ReLU(隐含) | 默认激活 | ReLU |
导出过程和1_scripts中的脚本运行说明
直接加载模型,只导出ErfNet 主干,前后处理不保存在在导出模型中。
├── 0_infer.py >框架下推断脚本
├── 1_save.py >trace模型保存onnx/pt脚本
├── 2_save_infer.py >onnx/pt推断脚本
-
0_infer.py
- 可以推理一张图(或其他格式数据)并得到最终结果,目的是为了快速跑通推理代码,为后续剥离/移植前后处理做准备。为了实现快速不能用整个数据集作为输入。
- 用法: python 0_infer.py
-
1_save.py
-
保存模型,导出的模型默认存放至
2_compile/fmodel路径下,如../2_compile/fmodel/erfnet_512x1048.pt -
用法: python 1_save.py
-
导出过程修改点
-
(1)因为icraft不支持
nn.Dropout2d,原本在non_bottleneck_1d.forward中会使用nn.Dropout2d,直接去掉这个算子,生成一个新的forward。# 1_save.py文件中 # -------- 修改 non_bottleneck_1d 的 forward -------- def new_forward(self, input): output = self.conv3x1_1(input) output = F.relu(output) output = self.conv1x3_1(output) output = self.bn1(output) output = F.relu(output) output = self.conv3x1_2(output) output = F.relu(output) output = self.conv1x3_2(output) output = self.bn2(output) return F.relu(output + input) non_bottleneck_1d.forward = new_forward
-
(2)分析parsed后的模型最后一层,可以看到最后一层是Conv2dTranspose算子,因为要使用segpost FPGA硬算子加速,要求最后一层是普通卷积。所以在Conv2dTranspose后再加一个恒等卷积。
-
# -------- ERFNet + 非分组恒等卷积 -------- class ERFNetWithIdentityConv(nn.Module): def __init__(self, base_model, n_classes): super().__init__() self.base = base_model self.final_conv = nn.Conv2d(n_classes, n_classes, kernel_size=1, bias=False) # 默认 groups=1 # 初始化为恒等变换 (单位矩阵形式) with torch.no_grad(): self.final_conv.weight.zero_() # 所有权重先清零 for i in range(n_classes): self.final_conv.weight[i, i, 0, 0] = 1.0 # 对角线设置为1 def forward(self, x): out = self.base(x) out = self.final_conv(out) return out
-
-
最后一层是一个恒等卷积(不需训练)。
-
-
-
-
2_save_infer.py
- 用修改后保存的模型做前向推理,目的是为了与0_infer的结果对比,确保导出静态模型的正确性。
- 用法: python 2_save_infer.py
4. cpu处理部分c++工程移植说明
4.1 cpu环节实现的功能
CPU(Host 端)承担了模型部署与推理流程中大量关键的前处理、后处理和控制逻辑。
1)配置与初始化(控制逻辑)
- 读取 YAML 配置文件:
- 包括模型路径、仿真与实卡运行开关、是否可视化输出、是否保存结果等。
- 加载图像路径、类别标签文件、网络输入尺寸等信息。
- 构建模型路径、打开设备并加载模型:
- 根据配置动态拼接 JSON 模型路径和 RAW 参数路径。
- 判断是否在仿真(sim)还是实际设备(实卡)上运行。
- 加载网络结构并初始化
Session和Device。
2)前处理(Preprocess)
这是典型的 在 CPU 上运行的图像前处理操作,目标是将原始图片转为模型输入格式:
- 图像读取:
- 使用 OpenCV 加载图像为 BGR 格式。
- 尺寸变换与补边:
Resize:以 长边为基准(此处为宽 = 2048),将图像缩放,使其长边匹配目标尺寸(如输入为 512×1024,则长边为1024)- 缩放比例 = 1024 / 2048 = 0.5
- 缩放后图像尺寸为 512×1024
rPad:在 短边方向(此处为高 = 512) 进行对称补零,补成最终输入尺寸(如目标为 512×1024,实际已满足则无需额外 padding)- 若目标为正方形输入(如 1024×1024),则:
- 当前图像已为 512×1024,需要在高方向补齐至1024,高度补 512 像素(上下各补 256)
- 最终尺寸为 1024×1024
- 图像转换为张量:
- 将裁剪后的图像转为 NCHW 格式、float 类型张量,用于输入模型(
CvMat2Tensor())。
- 将裁剪后的图像转为 NCHW 格式、float 类型张量,用于输入模型(
- 输入 DMA 传输:
- 将 CPU 中的图像张量传输给设备端执行推理(
dmaInit())。
- 将 CPU 中的图像张量传输给设备端执行推理(
3)模型执行控制
- 执行模型前向推理:
- 由 CPU 调用
session.forward()启动一次推理流程,控制输入和获取输出。 - 返回的是在设备端计算完成的结果张量。
- 由 CPU 调用
- 设备端输出转回 Host 内存:
- 将设备端输出张量(float*)搬运回 CPU 内存空间供后处理使用(
to(HostDevice::MemRegion()))。
- 将设备端输出张量(float*)搬运回 CPU 内存空间供后处理使用(
4)后处理(Postprocess)
这些操作也是由 CPU 进行的,主要包括:
- 数据回传
to(HostDevice::MemRegion())将NPU输出的分割张量复制到Host内存。- 这里使用segpost FPGA硬算子加速。
- 示例输出shape为
[1,512,1024,19](Cityscapes的19类分割任务)
- 结果解析
- 根据输出类型(float多通道/int8单通道)转换数据指针
- 构建OpenCV矩阵:多通道用
CV_32FC19,单通道用CV_8SC1
- 尺寸调整
- 将网络输出resize到原始图像尺寸(如1024x2048)
- 使用双线性插值保持边缘平滑
- 类别映射
- 将每个类别用不同颜色表示。
4.2 各环节耗时
命令行输入icraft run ./config/ErfNet_8.toml,以仿真int8量化后的模型为例,单一输入图像对理时间输如下:
# ErfNet_8.toml文件中
[run]
log_time = true
log_io = true
dump_format = "SFB"
json = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_BY.json"
raw = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_BY.raw"
input = "./qtset/cityscapes/frankfurt_000000_000294_leftImg8bit.png"
log_path = "./logs/"
D:\dtpw\Desktop\icraft_workplace\erfnet\2_compile>icraft run ./config/ErfNet_8.toml
[06/30/25 17:55:49.661] [I] ImageMake Version is 3.8.1.0
SegPost Version is 3.8.1.0
[06/30/25 17:55:49.741] [W] Turn on both dump and calctime will get wrong timing results.
Running : [██████████████████████████████████████████████████ ] 100% [00m:22s]
Input 0 In: Out: (0|-1,-1,-1,-1)
Resize 1 In: (0|-1,-1,-1,-1) Out: (1|1,512,1024,3)
ImageMake 609 In: (1|1,512,1024,3) Out: (1295|1,1,512,1024,4)
HardOp 902 In: (1295|1,1,512,1024,4) Out: (443|1,1,512,1024,32)
SegPost 610 In: (443|1,1,512,1024,32) Out: (1296|1,512,1024,1)
Output 215 In: (1296|1,512,1024,1) Out:
[06/30/25 17:56:12.117] [I] network wall: 0.0162 ms
Load Json Time: 43.718 ms
Load Raw Time: 32.475 ms
opId: 0 opType: Input wall: 32.332 ms mem: 0.000 ms hard: 0.000 ms other: 32.332 ms
opId: 1 opType: Resize wall: 50.862 ms mem: 0.000 ms hard: 0.000 ms other: 50.862 ms
opId: 609 opType: ImageMake wall: 130.088 ms mem: 0.000 ms hard: 0.000 ms other: 130.088 ms
opId: 902 opType: HardOp wall: 19747.800 ms mem: 0.000 ms hard: 0.000 ms other: 19747.800 ms
opId: 610 opType: SegPost wall: 2015.161 ms mem: 0.000 ms hard: 0.000 ms other: 2015.161 ms
opId: 215 opType: Output wall: 0.013 ms mem: 0.000 ms hard: 0.000 ms other: 0.013 ms
################# SUMMARY #################
OpNum 1 OpType HardOp total_wall: 19747.800 ms total_mem: 0.000 ms total_hard: 0.000 ms total_other: 19747.800 ms
OpNum 1 OpType ImageMake total_wall: 130.088 ms total_mem: 0.000 ms total_hard: 0.000 ms total_other: 130.088 ms
OpNum 1 OpType Input total_wall: 32.332 ms total_mem: 0.000 ms total_hard: 0.000 ms total_other: 32.332 ms
OpNum 1 OpType Output total_wall: 0.013 ms total_mem: 0.000 ms total_hard: 0.000 ms total_other: 0.013 ms
OpNum 1 OpType Resize total_wall: 50.862 ms total_mem: 0.000 ms total_hard: 0.000 ms total_other: 50.862 ms
OpNum 1 OpType SegPost total_wall: 2015.161 ms total_mem: 0.000 ms total_hard: 0.000 ms total_other: 2015.161 ms
total_time: 0.016 ms, total_hard_time: 0.000 ms
ImageMake: 0.000 ms
SegPost: 0.000 ms
当前仿真系统的cpu配置情况(不同配置运行速度不同,只作参考)
D:\dtpw\Desktop\icraft_workplace\ErfNet\2_compile>wmic cpu get name,numberofcores,numberoflogicalprocessors,maxclockspeed
MaxClockSpeed Name NumberOfCores NumberOfLogicalProcessors
1800 AMD Ryzen 7 4800U with Radeon Graphics 8 16
分析
- 核心推理耗时在
HardOp,即模型主干部分(19747.800 ms),这是真正的前向计算阶段; - 前处理部分(Resize + ImageMake)耗时约 130.088ms;
- 类型转换和输出阶段使用SegPost耗时2015.161 ms;
6. ICRAFT编译
-
不支持算子(但通过前面所述手段绕过)
在icraft logs中找到不支持的算子序列、在源码中定位对应的源码、实现的功能
算子序列 对应源码 实现的功能 aten::feature_dropout nn.Dropout2d整个通道置零
编译通过
-
使用运行时仿真得到的仿真效果截图或数据,需提供表格
比赛报告中要求有:框架动态图推理、导出静态模型推理、解析组件仿真、量化组件仿真、指令组件仿真的仿真效果截图或数据。对于解析组件仿真、量化组件仿真、指令组件仿真等中间过程仿真该怎么做?文档中并没写明,只能参考[docs/Part 2_2 icraft tools.md · spiger/TUTORIAL - 码云 - 开源中国](https://gitee.com/mxh-spiger/tutorial-runtime/blob/tt3.7.1/docs/Part 2_2 icraft tools.md#34-结果分析)中的
icraft run工作简单输出每个组件的仿真。
1. 框架动态图推理
-
输入图片
-
-
框架推理
-
python 0_infer.py -
输出结果:
-
2. 导出静态模型推理
-
输入图片:同上
-
导出静态模型推理
python 2_save_infer.py
3. 解析组件仿真(icraft run命令)
-
命令:
-
# ErfNet_8.toml文件中 [run] log_time = true log_io = true dump_format = "SFB" json = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_parsed.json" raw = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_parsed.raw" input = "./qtset/cityscapes/frankfurt_000000_000294_leftImg8bit.png" backends = "Host"
-
命令行运行
\ErfNet\2_compile>icraft run ./config/ErfNet_8.toml
-
-
输出截图(使用仿真命令icraft run)
-
4. 量化组件仿真(icraft run命令)
-
命令:
-
# ErfNet_8.toml文件中 [run] log_time = true log_io = true dump_format = "SFB" json = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_quantized.json" raw = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_quantized.raw" input = "./qtset/cityscapes/frankfurt_000000_000294_leftImg8bit.png" backends = "Host"
-
命令行运行
\ErfNet\2_compile>icraft run ./config/ErfNet_8.toml
-
-
输出截图
-
5. 指令组件仿真(icraft run命令)
-
命令:
-
# ErfNet_8.toml文件中 [run] log_time = true log_io = true dump_format = "SFB" json = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_BY.json" raw = "../3_deploy/modelzoo/ErfNet/imodel/8/ErfNet_BY.raw" input = "./qtset/cityscapes/frankfurt_000000_000294_leftImg8bit.png" backends = "Host"
-
命令行运行
\Bisenet\2_compile>icraft run ./config/ErfNet_8.toml
-
-
输出截图
-
6. 完整的c++工程仿真输出(c++ runtime)
-
在
3_deploy/modelzoo/ErfNet/build_win目录下运行:Release\ErfNet_psin.exe ..\cfg\ErfNet_8.yaml #注意,windows中一般用\,而/可以用但有些时假会报错,仿真时分割任务时间长,请等待。 Release\ErfNet_psin.exe ..\cfg\ErfNet_16.yaml Release\ErfNet_psin.exe ..\cfg\ErfNet_mix.yaml
-
输出截图
-
7. 8bit,16bit,混合精度的精度测试结果
- 分别运行以下命令,得到8bit,16bit,混合精度模型在CITYSCAPES验证集图像上的分类结果。
Release\ErfNet_psin.exe ..\cfg\ErfNet_test_8.yaml # 注意,windows中一般用\,而/可以用但有些时假会报错
Release\ErfNet_psin.exe ..\cfg\ErfNet_test_16.yaml
Release\ErfNet_psin.exe ..\cfg\ErfNet_test_mix.yaml
结果分别保存在
3_deploy\modelzoo\ErfNet\io\output\8\val_5000
3_deploy\modelzoo\ErfNet\io\output\16\val_5000
3_deploy\modelzoo\ErfNet\io\output\mix\val_5000
-
运行精度测试命令
\Release\ErfNet_psin.exe ..\cfg\ErfNet_test_8.yaml后,使用metrics测试脚本,根据保存的测试结果计算出精度指标。metrics测试脚本使用与配置说明:
- 精度测试脚本存放于:https://gitee.com/mxh-spiger/benchmark
- 因为该模型是在512x1024的输入和输出下训练的,CITYSCAPES验证集的GT大小都为1024x2028,所以可使用我提供的erfnet\3_deploy\modelzoo\ErfNet\io\output\8\leftImg8bit\val\myresizeGT.py的这个脚本resize到1024x2028大小,再进行精度测试。
-
精度结果
-
ErfNet input shape 精度 int8 [1, 3, 512,1024] allAcc/mAcc/mIoU 93.11%/71.78%/61.67% int16 [1, 3, 512,1024] allAcc/mAcc/mIoU 94.94%/81.27%/71.23% mix(混合精度) [1, 3, 512,1024] allAcc/mAcc/mIoU 93.43%/70.61%/63.32%
-
8. 编译过程的一些特殊说明
-
注意,windows中的命令行中,一般用左,右/可以用但有些时假会报错
-
编译命令注意事项
-
cd 3_deploy\modelzoo\ErfNet mkdir -p build_win cd build_win cmake -G "Visual Studio 17 2022" -A x64 .. # 不要直接cmake .. cmake --build . --config Release
-
不能直接使用
cmake ..命令,因为如果系统上多种编译器,且默认cmake使用的编译器不是visualstudio2022会出错,所以使用-G "Visual Studio 17 2022" -A x64命令,让cmake使用visualstudio2022编译器编译。
-