# 帖子标题

【A733】ACUITY 导出 YOLOv5nu 模型 nbg_compile error 512 — DFL 层移除后仍失败

---

# 帖子正文

## 一、问题描述

在 **Orange Pi 4 Pro（全志 A733）** 上使用 **ACUITY 工具链（v6.30.22）** 将自训练的 **YOLOv5nu** ONNX 模型转换为 **VIPLite NPU .nb 格式**时，`pegasus_export_ovx.sh` 的 **nbg_compile 步骤始终报 error 512**。

已尝试 **3 种不同的 ONNX 变体**（原始含 DFL、去除 DFL 单输出、多输出分离），均无法通过编译。

---

## 二、硬件环境

| 项目 | 详情 |
|---|---|
| 开发板 | Orange Pi 4 Pro |
| SoC | 全志 Allwinner A733 |
| NPU | VIPLite NPU，3 TOPS |
| NPU 驱动 | viplite v2.0.3.2 |
| 目标模型格式 | `.nb`（NBG），通过 ACUITY Docker 容器转换 |

---

## 三、软件环境

| 项目 | 版本/路径 |
|---|---|
| ACUITY Toolkit | **6.30.22**（Docker 容器内运行） |
| Docker 镜像 | ai-sdk 提供的 NPU 转换环境 |
| 转换脚本目录 | `/workspace/ai-sdk/models/`（容器内） |
| 训练框架 | ultralytics 8.3.226（YOLOv5u） |
| ONNX opset | 12 |
| 输入尺寸 | 640×640 |
| 模型来源 | 自训练 best.pt（7 类颜色方块检测） |

---

## 四、模型详情

### 4.1 任务类型

- **目标检测**：识别 7 种颜色方块（Blue / DGreen / LGreen / Pink / Purple / Red / Yellow）
- 3 种尺寸：3cm / 5cm / 7cm
- 数据集：1100+ 张图片，35 张手动标注 + 批量推理标注

### 4.2 原始 YOLOv5nu 检测头结构

```
Detect Head:
  ├── cv2: Conv2d (bbox 分支, 64ch → 4 anchors × 4 coords = 64ch)
  ├── cv3: Conv2d (cls 分支, 128ch → 4 anchors × 7 classes = 28ch)
  └── DFL (Distribution Focal Loss) ← 问题所在
        将 4 分布 → 4 坐标值（cx, cy, w, h）
```

**标准输出格式**: `[batch, 4+7, 8400] = [1, 11, 8400]`

---

## 五、转换流程与报错日志

### 5.1 标准四步流程

```bash
# Step 1: import（ONNX → ACUITY 内部格式）
./pegasus_import.sh my_yolov5u   # ✓ 成功

# Step 2: scale（输入归一化）
sed -i 's/scale: 1/scale: 0.00392157/' my_yolov5u_inputmeta.yml

# Step 3: quantize（INT8 量化）
./pegasus_quantize.sh my_yolov5u uint8   # ✓ 成功

# Step 4: export（编译为 .nb）
./pegasus_export_ovx.sh my_yolov5u uint8  # ✗ 失败！
```

### 5.2 关键错误信息

**Step 1~3 全部正常完成，唯独 Step 4 报错：**

```
=== Step4: export ===
[INFO] start to export model...
[INFO] load quantized data ...
[INFO] start nbg_compile ...
[ERROR] nbg_compile failed! error code: 512
```

> **注意**：import 和 quantize 都成功了，说明 ONNX 解析和量化都没问题。问题出在最后一步——NPU 编译器（nbg_compile）无法将量化后的网络编译为 NBG 二进制。

---

## 六、尝试过的方案（共 3 轮）

### 方案 A：原始 YOLOv5nu ONNX（含 DFL）

**操作**：
- 直接用 ultralytics 导出：`model.export(format='onnx', imgsz=640, opset=12)`
- 标准 YOLOv5u 检测头，包含 DFL 层

**结果**：❌ nbg_compile error 512

**推测原因**：VIPLite NPU 不支持 DFL（Distribution Focal Loss）操作

---

### 方案 B：去除 DFL，单输出 `[1, 71, 8400]`

**思路**：既然 DFL 不支持，那就把检测头替换掉，去掉 DFL，直接输出 raw distribution + class scores。

**修改代码** (`export_no_dfl.py`)：

```python
class SimpleDetect(torch.nn.Module):
    def __init__(self, detect):
        super().__init__()
        self.nl = detect.nl; self.nc = detect.nc
        self.f = detect.f; self.i = detect.i
        self.cv2 = torch.nn.ModuleList(detect.cv2)
        self.cv3 = torch.nn.ModuleList(detect.cv3)

    def forward(self, x):
        results = []
        for i in range(self.nl):
            # 拼接 bbox分支(64ch) + cls分支(28ch) = 72ch（实际约71ch）
            t = torch.cat([self.cv2[i](x[i]), self.cv3[i](x[i])], dim=1)
            bs, ch, h, w = t.shape
            results.append(t.view(bs, ch, -1))  # reshape 为 [bs, ch, H*W]
        return torch.cat(results, dim=2)         # concat 三个尺度
```

**ONNX 输出形状**：`[1, ~71, 8400]`

**结果**：❌ nbg_compile error 512（同样的错误）

**推测原因**：虽然去掉了 DFL，但 SiLU 激活 + 多通道卷积组合可能仍有不支持的算子；或者 71 通道的单输出结构不被支持

---

### 方案 C：多输出分离，3 个独立 feature map

**思路**：模仿旧版 YOLOv5（非 ultralytics 版）的输出方式——检测头输出 **3 个分离的特征图**，不做 concat 和 reshape，全部留给后处理。

**修改代码** (`export_multi_out.py`)：

```python
class MultiOutDetect(nn.Module):
    def __init__(self, detect):
        super().__init__()
        self.nl = detect.nl       # 3 个尺度
        self.nc = detect.nc       # 7 类
        self.f = detect.f
        self.i = detect.i
        self.cv2 = nn.ModuleList(detect.cv2)
        self.cv3 = nn.ModuleList(detect.cv3)

    def forward(self, x):
        # 返回 3 个分离的 tensor，每个 shape=[1, 72, H_i, W_i]
        return [
            torch.cat([self.cv2[i](x[i]), self.cv3[i](x[i])], dim=1)
            for i in range(self.nl)
        ]
```

**ONNX 输出**：3 个 output，shape 分别约为 `[1, 72, 80, 80]`、`[1, 72, 40, 40]`、`[1, 72, 20, 20]`

**结果**：❌ nbg_compile error 512（仍然相同错误）

---

## 七、对照实验：官方示例可以正常工作

为了排除环境和工具链问题，用 ACUITY 自带的 **yolov5s-sim 示例模型**做了完整转换：

```bash
cd models/yolov5s-sim/
./pegasus_import.sh yolov5s-sim    # ✓
./pegasus_quantize.sh yolov5s-sim uint8  # ✓
./pegasus_export_ovx.sh yolov5s-sim uint8  # ✓ 成功！
ls -lh wksp/*/network_binary.nb     # .nb 文件正常生成
```

**结论**：工具链本身没问题。问题确实出在我的模型结构上。

---

## 八、关键疑问

1. **error 512 具体代表什么？** 有没有详细的错误码说明文档？
2. **VIPLite NPU 到底不支持哪些算子？** 目前怀疑是 DFL、SiLU、或者某种 Conv 组合
3. **有没有成功部署 YOLOv5u/v8 到 A733 的案例或参考模型？**
4. **是否需要换用 YOLOv5（非 u 版，即带 objectness 的旧版检测头）？** 如果是的话，ultralytics 是否支持导出这种格式？

---

## 九、附件清单（可按需补充）

- [ ] `best.pt` — 训练好的权重文件
- [ ] 原始导出的 ONNX（含 DFL）
- [ ] 去除 DFL 后的 ONNX（单输出版）
- [ ] 多输出分离版 ONNX
- [ ] 完整的 convert.sh 脚本
- [ ] `export_no_dfl.py` 和 `export_multi_out.py`
- [ ] nbg_compile 完整日志（未截断版）

---

## 十、额外说明

- 个人开发者，非企业用户，无法使用全志企业客服渠道
- 已查阅论坛历史帖子和 AI-SDK 文档，未找到类似问题的解决方案
- PC 端（Windows, ONNX Runtime + OpenCV）推理验证已通过，C++ 后处理代码已就绪，只差板端 .nb 模型
- 如需更多信息请告知，感谢！

