---
title: DOD
canonical_url: "https://www.modelscope.cn/models/AIBSECO/DOD"
md_url: "https://www.modelscope.cn/models/AIBSECO/DOD.md"
repository: AIBSECO/DOD
chinese_name: Dingzhen66/DOD
last_updated: 2025-12-05
pipeline_tag: image-object-detection
tasks:
  - image-object-detection
library_name:
  - pytorch
frameworks:
  - Pytorch
downloads: 0
stars: 0
---

# DOD

> DOD - AIBSECO 在 ModelScope 开源的模型。基于icraft的双模态目标检测模型端到端优化部署关键技术

- **Repository**: AIBSECO/DOD
- **Tasks**: image-object-detection
- **Downloads**: 0
- **Stars**: 0
- **Last updated**: 2025-12-05

Source: https://www.modelscope.cn/models/AIBSECO/DOD

---

# 基于icraft的双模态目标检测模型端到端优化部署关键技术

## 1. 摘要

1. 身份编号：fwb0052

2. 类型与序号：

   双模态目标检测模型DOD/双模态目标检测模型端到端优化部署关键技术

3. 进展：

   | item                                    | status | detail                                                       |
   | :-------------------------------------- | ------ | ------------------------------------------------------------ |
   | 方案选择与硬件资源划分                  | 1      |                                                              |
   | 模型导出                                | 1      |                                                              |
   | ~导出模型精度一致，提供python验证脚本   | 1      |                                                              |
   | cpu处理部分c++工程移植                  | 1      |                                                              |
   | ~c++工程精度一致，提供验证脚本          | 0      |                                                              |
   | ~c++工程性能优化                        | 1      |                                                              |
   | icraft编译通过                          | 1      |                                                              |
   | ~存在量化精度调优工作                   | 1      |                                                              |
   | ~完成基本pyrt/crt搭建与结果验证         | 1      |                                                              |
   | ~完成pyrt/crt精度测试与对齐             | 1      |                                                              |
   | 完成上板耗时测试                        | 1      |                                                              |
   | ~使用运行时提供的api进行基本性能优化    | 1      |                                                              |
   | ~存在整体方案各环节优化或优化方案的设计 | 1      |                                                              |
   | 提出bug数                               | 2      | 分别是：编译的量化阶段校准集数量有限制、yolov5的soft_nms有bug，将分别在第6节和第7.1节中说明 |
   

## 2. 方案简介

### 2.1  算法流程介绍

#### 模型介绍

**模型相关信息**
本部署方案模型为Dual-modal Object Detection model(DOD)，是 Cross-Modality Fusion Transformer (CFT) for Multispectral Object Detection一文中提出的CFT 模型的轻量版，CFT在处理多光谱数据时，能够获得更好的结果。CFT发表于 2022 年，以预印本形式收录于 arXiv，并投递至 Elsevier 期刊。作者来自清华大学航空航天学院 。

CFT主要研究了多光谱目标检测，并提出一种基于 Transformer 的跨模态融合方法，以提升多光谱目标检测在复杂环境下的精度与鲁棒性。在可见光摄像头受光照、雨雾、遮挡等影响时，仅凭单一模态难以获得可靠的检测结果，文中提出的 CFT 模块，旨在通过 Transformer 的自注意力机制，在特征提取阶段同时完成 RGB 与热感（Thermal）两种模态的**跨模态融合**，从而提升多光谱目标检测在复杂环境下的精度与健壮性。



**性能对比**
下表为在 FLIR 数据集上，与单模态及其他融合方案的对比（基于 YOLOv5 Backbone） ：

  | 模态      | 方法              | 参数量 (M) | GFLOPs    | mAP₅₀ (%)     | mAP₇₅ (%)     | mAP (%)       |
  | --------- | ----------------- | ---------- | --------- | ------------- | ------------- | ------------- |
  | RGB       | YOLOv5 (baseline) | 47.06      | 115.6     | 67.8          | 25.9          | 31.8          |
  | Thermal   | YOLOv5            | 47.06      | 115.6     | 73.9          | 35.7          | 39.5          |
  | RGB+T     | 两流（no fusion） | 73.72      | 190.1     | 73.0          | 32.0          | 37.4          |
  | **RGB+T** | **+ CFT**  | **206.03** | **224.4** | **78.7 ↑5.7** | **35.5 ↑3.5** | **40.2 ↑2.8** |

**跨数据集表现**
   在 LLVIP 和 VEDAI 数据集上，CFT 同样取得显著提升：

  - **LLVIP**：mAP₅₀ 从 95.8 增至 97.5 (+1.7)，mAP 从 62.3 增至 63.6 (+1.3)。
  - **VEDAI**：mAP₅₀ 从 79.7 增至 85.3 (+5.6)，mAP 从 46.8 增至 56.0 (+9.2) 。

以上结果表明，CFT 模块在保证可接受计算复杂度的同时，显著增强了多光谱目标检测的精度和鲁棒性。



#### 模型结构与创新点
原论文提出的论文模型结构如图所示，基于 YOLOv5 构建了 RGB 和热感两个模态的主干网络，并插入了 CFT 模块，用于跨模态融合。CFT 模块利用全局自注意力机制，在特征提取阶段同时完成 RGB 与热感模态的跨模态融合，从而提升多光谱目标检测在复杂环境下的精度与鲁棒性。

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/image.png"
    <br>		<!--换行-->
    </center>
</div>

其主要创新点在于：
（1）基于 YOLOv5 构建两流（RGB/热感）主干网络；
（2）在多个尺度插入 Cross-Modality Fusion Transformer (CFT) 模块，利用全局自注意力自动执行 **intra-modality**  与 **inter-modality**特征融合；
（3）为降低计算开销，先对特征图进行全局平均。

尽管其在多光谱的任务下获得更好的结果，但 CFT 模块占据了大量的参数占用，因此可以减少CFT模块的计算开销，从而在推理速度上有提升。因此我们对CFT模型进行结构化剪枝和重构，以减少参数占用，从而提高推理速度。模型结构如图所示，我们将CFT模块替换成了ADD+卷积模块，用更少的参数，实现相同的特征融合效果。

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/cft_light.png"
    <br>		<!--换行-->
    </center>
</div>


#### 算法流程
算法流程如图所示，整个流程主要分为三部分，即数据的前后处理以及模型推理。其中，detect头用于将Prediction中的坐标从网格单元解码到输入特征图（640×640尺寸）并拼合成[1, 25200, 11]的张量，其中：

- 25200 = (80×80 + 40×40 + 20×20) × 3（锚框数量）
- 11 = 边界框坐标（cx, cy, w, h） + 目标置信度（obj_conf） + 6个类别置信度（cls_conf）。

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/process_2.png"
    <br>		<!--换行-->
    </center>
</div>

#### 前后处理介绍
该模型的前后处理与YOLOv5的流程一致。

**前处理：**

1. **读取图像，调整尺寸**：

   - 使用 OpenCV 或其他库加载图像。
   - DOD通常要求输入图像的尺寸为 640x640，或者其他特定的倍数（如 416x416）。

   ```
   import cv2
   im = cv2.imread("path_to_image.jpg")
   im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0]  # padded resize
   ```

2. **输入排布**：

   - DOD的输入排布是NCHW
   - DOD输入的通道顺序是RGB

   ```
   im = im.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB
   ```

3. **转换为张量**：

   框架下会将图像转换为 PyTorch 张量，并以符合框架下模型输入的要求。

   ```
   im = np.ascontiguousarray(im)  # contiguous
   im = torch.from_numpy(im)
   im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32
   ```

4. **归一化处理**：

   - 将像素值从 [0, 255] 归一化到 [0, 1] 的范围。

   ```
   img = img / 255.0  # 归一化
   if len(im.shape) == 3:
   	im = im[None]  # expand for batch dim
   ```



**后处理：**

1. **阈值筛选**：

   - 置信度阈值用于筛选检测结果中，只有超过该置信度的检测框才能被保留。通常在模型的输出后，使用 `conf_thres` 参数来设置这个阈值。在 DOD的代码中，这个阈值常常用于 NMS（非极大值抑制）之前。

   ```
   xc = prediction[..., 4] > conf_thres  # candidates
   ```

   

2. **应用非极大值抑制（NMS）**：

   - 对于检测到的多个框，使用 NMS 来消除重叠较大的框，只保留最有可能的框。

   ```
   pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
   ```

   

3. **可视化**：

   - DOD对于每张图片进行保存检测框、写入文件、可视化结果等。

   ```
   # Process predictions
   ...
   gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh
   annotator = Annotator(im0, line_width=line_thickness, example=str(names))
   if len(det):
   	# Rescale boxes from img_size to im0 size
       det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round()
   ...
   ```


### 2.2  硬件资源分配

#### DOD 在板端硬件资源分配如下：

前处理（BGR2RGB、Resize、Pad和将特征图转换为[1, 1, 640, 640 ,4]的排布）：CPU

网络主体：NPU

后处理阈值筛选（detpost）：FPGA

后处理（NMS，坐标缩放）：CPU

可视化：CPU

**模型资源分配图如下：**

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/process_2_hardware.png"
    <br>		<!--换行-->
    </center>
</div>

## 4. 模型导出说明

1. 如下图所示：在模型中，和Yolov5一样，我们将Detect头（用于解码和张量聚合）去除，放到了后处理部分。

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/process_2_save.png"
    <br>		<!--换行-->
    </center>
</div>

2. 在代码中的写法与demo中的Yolov5一样，表示如下：
   ```
    # 修改前向，去除前向中后处理操作
    def new_forward(self, x):
    for i in range(self.nl):
        x[i] = self.m[i](x[i])  # conv
    return x
   ```
3. 配置好权重文件和环境后，脚本可以直接使用python 1_save.py运行



## 5. cpu处理部分c++工程移植说明

1. CPU实现的功能如下：
- 前处理中，实现RGB和IR图片的BGR转RGB：
   ```
    if (this->src_img.channels() == 3){
        :cvtColor(this->src_img, this->src_img, cv::COLOR_BGR2RGB);
		   }
   ```
   
- 前处理中，实现RGB和IR图片的resize和pa（以RGB为例）d：
   ```
  rgb_img.Resize({ netinfo.i_cubic[0].h, netinfo.i_cubic[0].w }, PicPre::LONG_SIDE).rPad();
  ```
  
- 前处理中，显式地实现了RGB和IR图片的imgmake的补通道和维度变换（以RGB为例）：
   ```c++
   cv::Mat mergedImage_rgb;
   mergedImage_rgb.create(640, 640, CV_8SC4);
   cv::parallel_for_(cv::Range(0, 640), [&](const cv::Range& range) {
       for (int r = range.start; r < range.end; ++r) {
           const uchar* src_ptr = rgb_img.dst_img.ptr<uchar>(r);
           schar* dst_ptr_rgb = mergedImage_rgb.ptr<schar>(r);
           for (int c = 0; c < 640; ++c) {
               const int offset = c * 3;
               dst_ptr_rgb[4*c]   = src_ptr[offset]   ^ 0x80;  // B: 位运算替代减法
               dst_ptr_rgb[4*c+1] = src_ptr[offset+1] ^ 0x80;  // G
               dst_ptr_rgb[4*c+2] = src_ptr[offset+2] ^ 0x80;  // R
               dst_ptr_rgb[4*c+3] = 0;                         // Alpha
               }
           }
   ```
   
- 后处理中，实现了对output tensor的解码，nms，坐标缩放和可视化：
   ```
    void post_detpost_hard(const std::vector<Tensor>& output_tensors, PicPre& img, NetInfo& netinfo,
        float conf, float iou_thresh, bool MULTILABEL, bool fpga_nms, int N_CLASS, 
        std::vector<std::vector<std::vector<float>>> &ANCHORS,std::vector<std::string>& LABELS, 
        bool & show, bool & save , std::string &resRoot, std::string & name,icraft::xrt::Device device,bool & run_sim) {
    
        std::vector<int> id_list;
        std::vector<float> socre_list;
        std::vector<cv::Rect2f> box_list;
        std::vector<float> stride = get_stride(netinfo);
        for (size_t i = 0; i < output_tensors.size(); i++) {
            auto host_tensor = output_tensors[i].to(HostDevice::MemRegion());
            int output_tensors_bits = output_tensors[i].dtype()->element_dtype.getStorageType().bits();
            int obj_num = output_tensors[i].dtype()->shape[2];
            int anchor_length = output_tensors[i].dtype()->shape[3];
            if (output_tensors_bits == 16) {
                auto tensor_data = (int16_t*)host_tensor.data().cptr();
                for (size_t obj = 0; obj < obj_num; obj++) {
                    int base_addr = obj * anchor_length; 
                    Grid grid = get_grid(output_tensors_bits, tensor_data, base_addr, anchor_length);
                    get_cls_bbox(id_list, socre_list, box_list, tensor_data, base_addr,grid, netinfo.o_scale[i], stride[i],ANCHORS[i][grid.anchor_index], N_CLASS, conf, MULTILABEL);
                }
            }
            else {
                auto tensor_data = (int8_t*)host_tensor.data().cptr();
                for (size_t obj = 0; obj < obj_num; obj++) {
                    int base_addr = obj * anchor_length; 
                    Grid grid = get_grid(output_tensors_bits, tensor_data, base_addr, anchor_length);
                    get_cls_bbox(id_list, socre_list, box_list, tensor_data, base_addr,grid, netinfo.o_scale[i], stride[i], ANCHORS[i][grid.anchor_index], N_CLASS, conf, MULTILABEL);
    
                }
            }
        }
    
        auto nms_start = std::chrono::system_clock::now();
    
        std::vector<std::tuple<int, float, cv::Rect2f>> nms_res;
        if (fpga_nms&& !run_sim) {
            nms_res = nms_hard(box_list, socre_list, id_list, iou_thresh, device);
        }
        else {
            nms_res = nms_soft(id_list, socre_list, box_list, iou_thresh);   // 后处理 之 NMS
    
        }
        std::vector<std::vector<float>> output_res = coordTrans(nms_res, img);
    
    
        #ifdef _WIN32
        if (show) {
            visualize(output_res, img.ori_img, resRoot, name, LABELS);
        }
        #endif
    }
   ```
2. 在移植后的C++程序中，我们对进行了如下方法验证准确性：
- 对比了C++程序与python runtime程序中icore推理的output tensor的形状
- 对比了C++程序与python runtime程序nms后的tensor的数值
- 对比了可视化后多张图片的锚框位置与置信度差异
3. 带detpost硬算子的8 bit量化模型的各环节耗如下表所示，其中前处理时间为RGB+IR时间，测试方式为推理整个M3FD数据集的验证集，取平均时间。

   | 环节              | 耗时(ms) |
   | :---------------- | -------- |
   | BGR2RGB           | 6.17     |
   | resize+pad        | 12.39    |
   | imgmake           | 7.01     |
   | icore推理         | 30.45    |
   | output tensor解码 | 0.143    |
   | nms与坐标转换     | 0.029    |

​	我们对8bit量化模型的推理进行了速度优化和精度优化，具体优化过程将在第7点详细说明。

## 6. ICRAFT编译

**编译通过**

- 使用运行时仿真得到的仿真效果截图或数据，需提供下述表格:

  | 框架动态图推理                           | 导出静态模型推理                             | 解析组件仿真                       | 量化组件仿真                       | 指令组件仿真                       |
  | ---------------------------------------- | -------------------------------------------- | ---------------------------------- | ---------------------------------- | ---------------------------------- |
  | ![1](./assets/runs/1.png) | ![1](./assets/runs/2.png) | ![1](./assets/runs/3.png) | ![1](./assets/runs/4.png) | ![1](./assets/runs/5.png) |
  
  

- 8 bit精度测试结果如下(python runtime):

| Class     | Images     | Labels      |     P     |      R   |   mAP@.5   |  mAP@.75 | mAP@.5:.95 |
|-----------| ---------- | ----------- | --------- | -------- |------------ |------------ |------------ |
| all       |   840    |    7096   |    0.894  |     0.813  |     0.863    |   0.565    |   0.535|
| People    |   840     |   2505    |   0.871   |    0.783   |    0.827    |   0.462  |     0.461|
| Car       |   840    |    3599     |       0.899  |     0.883    |   0.918   |    0.682   |    0.615|
| Bus       |    840    |     151     |      0.917  |     0.914   |     0.94   |    0.794   |    0.697|
| Lamp      |   840    |     517     |       0.883  |     0.853   |    0.874   |    0.394   |    0.437|
| Motorcycle |   840      |   113    |   0.932     |   0.61   |    0.799   |    0.429    |   0.447|
| Truck     |   840    |     211     |      0.863  |     0.834   |     0.82    |   0.628   |    0.553|
- 16 bit精度测试结果如下(python runtime):

| Class     | Images     | Labels      |     P     |      R   |   mAP@.5   |  mAP@.75 | mAP@.5:.95 |
|-----------| ---------- | ----------- | --------- | -------- |------------ |------------ |------------ |
| all       |   840    |    7096   |    0.859  |     0.847  |     0.864    |   0.598    |   0.552|
| People    |   840     |   2505    |   0.836   |    0.794  |     0.816    |   0.473    |   0.469|
| Car       |   840    |    3599     |  0.876   |    0.894   |     0.92    |    0.71     |  0.654|
| Bus       |    840    |     151     |  0.875   |    0.934   |    0.947    |    0.84     |  0.712|
| Lamp      |   840    |     517     |  0.837   |    0.853   |    0.865    |   0.403     |  0.441|
| Motorcycle |   840      |   113     |  0.914   |    0.752   |     0.81    |   0.504     |  0.463|
| Truck     |   840    |     211     |  0.816   |    0.858    |   0.829    |   0.656     |  0.577|


- 编译过程的一些特殊说明
编译过程中的校准集是使用验证集中的图片，通过人工随机选择的。在量化阶段，我们遇到了量化校准集数量限制的bug，在选用128张图片作为校准集时，遇到了如下报错）：

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/bug1.png"
    <br>		<!--换行-->
    </center>
</div>

​		我们猜测应该是校准集图片数量太多导致的。因此，我们经过测试后，选用了32张图片作为校准集，绕过了bug。
​		此外，我们发现如果使用硬算子imgmake，会导致在板端无法运行，这是因为只有一个硬件应该没有办法支持两个imagemake，因此，我们在generate阶段只使用了硬算子detpost便于加速后处理。



## 7. 上板测试与优化

1. 优化前各环节耗时统计(表格)
   优化前各环节耗时统计表格如下（带detpost硬算子的8位模型）：

   | op_type                | total time(ms) |
   |:-----------------------|---------------|
   | icraft::xir::Output    | 0             |
   | icraft::xir::Add       | 86.230381 |
   | icraft::xir::Add       | 85.979921 |
   | customop::DetPost      | 0.61381       |
   | icraft::xir::AlignAxis | 37.378001 |
   | icraft::xir::Cast      | 102.361661 |
   | icraft::xir::AlignAxis | 36.814211 |
   | icraft::xir::Cast      | 101.109751 |
   | icraft::xir::HardOp    | 12.78774 |
   | icraft::xir::HardOp    | 15.79851 |
2. 优化后耗时统计(表格)
   优化后各环节耗时统计表格如下：

   | 环节              | 耗时(ms) |
   | :---------------- | -------- |
   | BGR2RGB           | 6.17     |
   | resize+pad        | 12.39    |
   | imgmake           | 7.01     |
   | icore推理         | 30.45    |
   | output tensor解码 | 0.143    |
   | nms与坐标转换     | 0.029    |
3. 优化项与效果

- **速度优化**：

  关键技术1： 面向双通道输入的前处理优化

  将模型部署到板端后，我们将模型进行了速度的优化。模型推理速度优化目标为减少端到端的时间，即模型从图片读到PSDDR中后，到最后后处理的坐标缩放结束的时间。使用8位量化模型，在未调优的速度表中，可以看到有3种算子占据了模型推理93%的时间，分别是Cast、Add和alignaxis，在如下模型结构图的红框中：

  <div>			<!--块级封装-->
      <center>	<!--将图片和文字居中-->
      <img src="./assets/model.png"
      <br>		<!--换行-->
      </center>
  </div>
  
  而这几个在PS端运行的算子的用途仅仅是为了适应硬件，添加了一个维度和补了一个全0的通道。这个工作本可以由运行在FPGA上的imagemake硬算子快速完成，但是该模型为双输入，需要编译两个imagemake硬算子，但我们通过实验发现，3.7.1版本的套件无法实现PSin的多个imagemake硬算子推理。在这种条件下，模型端到端推理速度达到了492毫秒，FPS仅约为2帧，因此，解决这几个算子带来的速度瓶颈至关重要。我们首先重新选择使用C++重写推理代码，以便更精细地控制内存的分配和释放，以及更方便地控制线程。然后，我们在推理时使用icraft api，即viewexpect将这几个算子从模型中移除，并使用C++将这几个算子的功能写出，并在保证正确性的前提下尽可能优化速度，将原本的450ms的算子耗时变成了仅需7ms。
  
  然后又由于前处理的BGR2RGB、resize和pad有40ms，有较大改进空间。因此我们还并行化实现了RGB+IR前处理过程。效果很好，BGR2RGB只需6ms，resize和pad只需12ms，加上上一页7的ms的imagemake，前处理时间总共只有25ms。这为接下来的异步流水线并行化推理提供了前置条件。
  
  接下来是我们的第二个关键技术。我们将推理分为三级流水线3种线程，分别是输入线程，icore推理线程和后处理线程。三者是生产者/消费者模式，通过任务队列来实现。
  其中输入线程有4个，负责读入RGB和IR图片，并分别实现BGR-RGB、Resize、pad和补通道的前处理，并初始化一个结构体CFT_InputForIcore，保存预处理后的 image id、rgb_img_tensor和ir_img_tensor，并将该结构体push进icore任务队列。
  icore线程只有1个，这是因为100TAI处理器的NPU为单核。这个线程将从Icore任务队列中读取image id，rgb_img_tensor和ir_img_tensor，用两个张量进行推理，将image id和推理出的output tensor push进后处理队列。
  后处理线程则是根据icore推理的output tensor和对应的image id进行NMS和坐标缩放的后处理，并将结果写回SD卡。
  
  我们的异步流水线设计如下：

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/design1.png"
    <br>		<!--换行-->
    </center>
</div>



​		在时间上的并行效果图如下：

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/time.png"
    <br>		<!--换行-->
    </center>
</div>

​	在T0时刻第一帧开始从SD卡中读出；在T1时刻读取结束后第2帧由第2个线程读入，此时第1帧开始前处理；在T2时刻第1帧前处理完毕，icore线程开始推理，此时第2帧还在前处理，并将在处理结束后等待NPU资源；在T3时刻第1帧icore推理结束，此时也开始了后处理，同时第2帧开始icore推理；在T4时刻第1帧后处理结束。

​	可以看见，由于前处理时间小于icore推理时间，因此前处理线程、icore推理线程和后处理线程是并行化的，这将模型的时间瓶颈限制在icore推理线程的30ms(其中icore推理22.5ms，从PSDDR到PLDDR的memcpy7.5ms)推理上。并且对于从摄像头取帧的真实使用场景，取帧也能并行，进而可以实现输入输出线程全并行。

​		在空间上的并行效果图如下：

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/time2.png"
    <br>		<!--换行-->
    </center>
</div>

​		其中：

​		①：4个输入线程，每个线程在PS端对RGB和IR图像做并行的前处理，并将结果写入PLDDR；

​		②：AI访问PLDDR中存储的数据，完成icore的推理，得到output tensor；

​		③：将PLDDR中的output tensor写入PSDDR（自动完成），在ps端进行多线程后处理，将锚框画在图像上；

​		④：将PSDDR中的结果写回SD卡；

​		通过速度优化，我们将端到端FPS由2帧提升到了16帧，速度上升了8倍。

- **精度优化**：
  解决了速度优化后，我们将模型进行了精度测试，发现icraft模型精度和原始模型精度相差了10%。因此首先通过对比各个阶段生成的模型，发现模型在量化阶段精度正常，在适配阶段精度则少了10%。适配阶段引入了硬算子detpost。此时的可能性有两个，detpost输出异常或者detpost对应的后处理代码异常。由于icraft提供了Yolov5的例子，我们发现带detpost的Yolov5的C++推理程序精度没问题，而python程序精度同样有问题，因此发现了是python版本的nms错误，该nms使用了类间soft_nms，导致了多个重合度很高的但是是预测不同类别的锚框被删去，降低了预测精度。因此，更正这个bug后我们实现了精度优化。

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/acc.png"
    <br>		<!--换行-->
    </center>
</div>

​	实现正常精度推理后，我们来到了第三个关键技术，混合精度优化。16位模型精度高，但icore推理时间达到了53ms（其中HardOp时间45ms，memcpy 8ms）无法满足需要。因此我们继续对8位模型进行了精度测试，发现其精度为85.6，相对于原始模型精度下降了1.8，所以我们考虑混合精度量化。我们使用icraft量化分析工具研究了8位模型的各层的量化余弦相似度cos sim（指量化前的全精度（Float32）张量数据和INT8张量数据在张量展开成向量后的方向一致性度量。）以分析模型各层量化的效果，将1-cos sim和MSE作为该层的local loss，计算全模型的平均local loss，将高于均值的层设置为INT 16。此时模型为混合精度模型，精度达到了86.2，相比8位模型提升了0.6，icore部分速度为31ms，仅比8位模型慢1ms，FPS仍然约有33帧，实现了精度于速度的良好平衡。

<div>			<!--块级封装-->
    <center>	<!--将图片和文字居中-->
    <img src="./assets/acc2.png"
    <br>		<!--换行-->
    </center>
</div>

​	基于最新发布的icraft 3.30套件，我们进一步地做了更多的工作。在3.7.1中我们发现，在PSIN时，使用BOOT_多路_24102404位流的情况下仍然无法使用双imagemake的原因是UDMA内存空间无法初始化，而使用3.30则可以通过手动指定内存空间地址并使用fpgaDma函数便可以使用两个imagemake硬算子同时处理RGB和IR的feature map，因此，此时的mix模型的前处理速度缩减到了18ms，而icore推理速度仍然为约30ms，这是由于imagemake算子虽然运算很快，但是其承担了memcpy的作用，大部分时间在把数据从psddr复制到plddr中。因此此时的FPS仍在33帧左右。

​	我们还讨论了icore推理速度的瓶颈，这将在决赛答辩时展示。

4. 运行时工程的整体介绍

- **0_MOD_CFT**

  该文件夹存放了所有源码。但是不包含数据集。

- **1_scripts**

  该文件夹的0_infer.py 和2_save_infer.py可以直接运行，无需配置参数。

- **2_compile**

  可以在终端打开该文件夹，通过

  ```powershell
  icraft compile .\config\mod_cft_8_hard_1.toml
  icraft compile .\config\mod_cft_16_hard_1.toml
  ```

  来分别编译8位和16位模型。

  通过：

  ```powershell
  icraft compile .\config\mod_cft_8_soft.toml
  ```

  来编译8位的不带硬算子的模型。

- **3_deploy**

  - 在.\cfg中的.yaml文件的sim字段需根据硬件终端不同来配置false和true。

  - 在pyrt文件夹中是python runtime的运行脚本，可运行程序有4个，分别是：

    - mod_cft_psin.py，用于加载模型，加载并前处理图片，推理图片，后处理并存入存储。

      运行方式为：在控制台进入文件夹后，输入命令：

      ```powershell
      python .\mod_cft_psin.py ..\cfg\mod_cft_8_hard_1.yaml
      python .\mod_cft_psin.py ..\cfg\mod_cft_16_hard_1.yaml
      python .\mod_cft_psin.py ..\cfg\mod_cft_soft.yaml
      ```

    - test_new_8，test_new_16，test_new_soft，分别用于测试带硬算子的8位/16位和不带硬算子的8位模型的精度，运行方式为：

      ```powershell
      python .\test_new_8
      python .\test_new_16
      python .\test_new_soft
      ```

  - 在src文件夹中是c++ runtime的推理代码，分别有mod_cft_psin_ori.cpp（未优化版本）、mod_cft_psin.cpp（三级流水线）两个版本，在CMakeLists.txt中配置好编译对象名，进入build_arm文件夹，输入命令：

    ```
    cmake ..
    cmake --build . --config Release
    ```

    即可得到PSIN或PLIN的可执行文件。在板端进入build_arm文件夹，输入命令：

    ```
    ./mod_cft_psin_ori ../cfg/mod_cft_8_hard_1.yaml
    ./mod_cft_psin ../cfg/mod_cft_8_hard_1.yaml
    ```

    来运行不同推理代码和不同模型。其中，要得到7.3中优化模型的效果，需要编译mod_cft_psin.cpp，并使用mod_cft_8_hard_1.yaml配置。
