# MODNet 与 RVM 模型制品仓库 (Model Artifact Registry) > **用途**:集中托管 MODNet 与 RVM 的模型制品(ckpt / onnx / rknn 文件本身) > **不包含**:训练代码与 C++ 推理代码——这些在配套的私有仓库中维护 > > **维护者**:PotterWhite > **最后更新**:2026-07-03 > **许可证(License)**:MIT --- ## 目录(Table of Contents) 1. [MODNet 模型](#1-modnet-模型) - [1.1 官方预训练模型](#11-官方预训练模型) - [1.2 微调模型 — 摄影数据集](#12-微调模型--摄影数据集) - [1.3 ONNX 模型变体](#13-onnx-模型变体) - [1.4 目录结构](#14-目录结构) - [1.5 速查表](#15-速查表) 2. [RVM 模型](#2-rvm-模型) - [2.1 ONNX 模型](#21-onnx-模型) - [2.2 RKNN 模型](#22-rknn-模型) - [2.3 质量总结](#23-质量总结) - [2.4 推荐模型选择](#24-推荐模型选择) - [2.5 Graph Surgery:移除最终的 Resize 及以后的算子](#25-graph-surgery移除最终的-resize-及以后的算子) 3. [相关文档](#3-相关文档) 4. [附录:训练日志摘要](#附录训练日志摘要) --- ## 1. MODNet 模型 ### 1.1 官方预训练模型 #### 摄影人像抠图(Photographic Portrait Matting) **文件**:`photographic/modnet_photographic_portrait_matting.ckpt` ``` 原始 MODNet 检查点,在人像抠图数据集上训练 - 来源:作者 Google Drive(ZHKKKe/MODNet) - 格式:PyTorch .ckpt(state_dict) - 架构:MODNet + IBNorm + InstanceNormalization - 输入尺寸:512×512 - 用途:微调实验的基线参考 - 状态:✓ 生产基线 ``` #### 摄像头人像抠图(Webcam Portrait Matting) **文件**:`modnet_webcam_portrait_matting.ckpt` ``` 针对摄像头实时抠图优化的 MODNet 检查点 - 来源:作者 Google Drive - 格式:PyTorch .ckpt(state_dict) - 架构:MODNet + IBNorm + InstanceNormalization - 输入尺寸:384×384(更低延迟) - 用途:实时视频/直播场景 - 状态:✓ 可用,当前管线未使用 ``` #### MobileNetV2 人体分割(Human Segmentation) **文件**:`mobilenetv2_human_seg.ckpt` ``` 辅助分割模型,用于预处理阶段 - 来源:作者 Google Drive - 格式:PyTorch .ckpt - 用途:可选预处理阶段(当前未部署) - 状态:✓ 可用作参考 ``` --- ### 1.2 微调模型 — 摄影数据集 #### 纯批归一化变体(Pure Batch Normalization Variant) **训练轮次**:Block 1.2 微调(2026-03-19 ~ 2026-03-19) ##### 概要 ``` 在 P3M-10k 摄影数据集上微调 MODNet-BN - 将所有 IBNorm + InstanceNormalization 替换为纯 BatchNorm2d - 15 个 Epoch 的监督训练,含学习率调度(Learning Rate Schedule) - 最佳模型:验证集 L1 Loss 0.0062 ``` ##### 训练配置 | 参数 | 值 | |------|-----| | 数据集(Dataset) | P3M-10k(Photographic 子集) | | 训练样本数 | 9,421 | | 验证样本数 | 500 | | 批大小(Batch Size) | 8 | | 轮次(Epochs) | 15 | | 初始学习率(Learning Rate) | 0.01 | | 学习率调度 | StepLR:γ=0.1 @ epoch 5, 10 | | 输入尺寸 | 512×512 | | 优化器(Optimizer) | Adam (β₁=0.9, β₂=0.999) | | 损失函数(Loss Function) | L1(MAE),作用于 alpha 遮罩 | | 设备(Device) | NVIDIA A100 (CUDA 11.8) | | 训练时长 | ~4 小时 | | 时间戳 | 2026-03-19 15:40:18 | ##### 生成的制品(Artifacts) ``` photographic/finetune/ ├── checkpoints/ │ ├── modnet_bn_best.ckpt # ★ 最佳模型(Val L1: 0.0062) │ ├── modnet_bn_epoch_01.ckpt │ ├── modnet_bn_epoch_02.ckpt │ ├── ...(epoch 3-14 省略) │ └── modnet_bn_epoch_15.ckpt ├── logs/ │ └── block1_2_training_20260319_154018.log # 训练日志(详细) ├── onnx/ │ └── modnet_bn_best_pureBN.onnx # ★ ONNX 导出(见 §1.3.3) └── output/ ├── epoch_01_val.png # 验证预览(第 1 轮) ├── epoch_02_val.png ├── ...(epoch 3-14 省略) └── epoch_15_val.png # 最终验证可视化 ``` ##### 验证损失曲线(Validation Loss Curve) ``` Epoch | Val L1 Loss | 改进幅度 ------|-------------|------------------- 1 | 0.0264 | Δ = -0.0202(新最佳) 2 | 0.0175 | Δ = -0.0089(新最佳) 3 | 0.0121 | Δ = -0.0054(新最佳) 4 | 0.0098 | Δ = -0.0023(新最佳) 5 | 0.0089 | Δ = -0.0009(新最佳) 6 | 0.0081 | Δ = -0.0008(新最佳) 7 | 0.0076 | Δ = -0.0005(新最佳) 8 | 0.0074 | Δ = -0.0002(新最佳) 9 | 0.0072 | Δ = -0.0002(新最佳) 10 | 0.0070 | Δ = -0.0002(新最佳) 11 | 0.0068 | Δ = -0.0002(新最佳) 12 | 0.0066 | Δ = -0.0002(新最佳) 13 | 0.0065 | Δ = -0.0001(新最佳) 14 | 0.0063 | Δ = -0.0002(新最佳) 15 | 0.0062 | Δ = -0.0001(最终) → 第 5 轮后收敛(学习率调度生效),持续稳步改进 ``` ##### 使用方法 ```python # PyTorch 推理 import torch from modnet import MODNet checkpoint = torch.load('photographic/finetune/checkpoints/modnet_bn_best.ckpt') model = MODNet() model.load_state_dict(checkpoint) model.eval() # 或使用 ONNX 推理(推荐用于部署) import onnxruntime sess = onnxruntime.InferenceSession('photographic/finetune/onnx/modnet_bn_best_pureBN.onnx') ``` --- ### 1.3 ONNX 模型变体 #### 官方原始版本(Photographic) **文件**:`photographic/modnet_photographic_portrait_matting.onnx` ``` 从官方检查点直接导出的 ONNX - 来源:作者 Google Drive - 格式:ONNX opset 11 - 包含:InstanceNormalization 算子 - 输入:[1, 3, 512, 512](float32,[-1, 1] 归一化) - 输出:[1, 1, 512, 512](float32,[0, 1] 范围) - 状态:✓ 对比参考 - 注意:InstanceNormalization 在 NPU 上会回退到 CPU,**不推荐用于边缘部署** ``` #### 折叠变体(Folded Variant,Anti-fusion) **文件**:`photographic/modnet_photographic_portrait_matting_in_folded.onnx` ``` 通过 anti-fusion 方法展开 InstanceNormalization - 优化者:PotterWhite (potter_white@outlook.com) - 日期:2026-03-11 16:11 - 方法:将 InstanceNorm 展开为算术原语 - Var(x) = E[x²] − (E[x])² - 防止 RKNN 编译器重新识别 InstanceNormalization - 强制在 CPU 上执行(负面效果) - 状态:⚠️ 实验性,不推荐 - 分析:违背了优化初衷 ``` #### 纯批归一化版本(ONNX 导出) **文件**:`photographic/finetune/onnx/modnet_bn_best_pureBN.onnx` ``` 从 modnet_bn_best.ckpt(微调模型)导出的 ONNX - 来源:PyTorch 微调训练(第 15 轮) - 导出日期:2026-03-31 16:15 - 格式:ONNX opset 11 - 架构:纯 BatchNormalization(无 InstanceNorm) - 输入:[1, 3, 512, 512](float32,[-1, 1] 归一化) - 输出:[1, 1, 512, 512](float32,[0, 1] 范围) - 文件大小:25 MB - 状态:⚠️ 参考用。纯 BN 变体在当前量化/部署路径上仍有数值问题, **生产部署请用 §1.3.1 官方原版(带 InstanceNorm)**。 技术说明(仅供对比研究): - 无 InstanceNormalization → 理论上是 NPU 友好 - 全部算子:Conv2d, BatchNorm2d, ReLU 等(硬件友好) - 但实测在某些量化路径上数值偏移较大,需进一步调试 已测试环境: - ONNX Runtime 1.16.3(CPU, x86_64) - ONNX Runtime 1.16.3(aarch64, 模拟环境) - RKNN 工具链 v2.3.2(编译阶段验证) ``` ##### 验证结果(对比参考) ``` 黄金测试向量(Golden Test Vector):green-fall-girl-point-to.png (1803×1019) - Python 推理输出:py_08_inference-Output.bin ✓ - C++ 推理输出:cpp_08_inference-Output.bin(待 C++ 构建) - 预期匹配:像素级 L∞ 误差 < 1e-5(float32 精度) ``` --- ### 1.4 目录结构 ``` MODNet/ │ ├── README.md ← 当前文件 │ ├── [官方模型 - 根目录] │ ├── mobilenetv2_human_seg.ckpt (备份,非活跃) │ └── modnet_webcam_portrait_matting.ckpt (参考用,384×384) │ └── photographic/ ← ★ 活跃部署变体 │ ├── README.md (历史文件,已被取代) │ ├── [官方基线] │ ├── modnet_photographic_portrait_matting.ckpt (1.8 GB) │ ├── modnet_photographic_portrait_matting.onnx (26 MB, InstanceNorm) │ └── modnet_photographic_portrait_matting_in_folded.onnx (26 MB, folded) │ └── finetune/ ← ★ 活跃训练输出 │ ├── checkpoints/ (PyTorch 制品) │ ├── modnet_bn_best.ckpt ★ (1.8 GB, 最佳模型) │ ├── modnet_bn_epoch_01.ckpt │ ├── modnet_bn_epoch_02.ckpt │ ├── ... (epoch 3-14) │ └── modnet_bn_epoch_15.ckpt │ ├── onnx/ (部署用) │ └── modnet_bn_best_pureBN.onnx ★ (25 MB, 推荐) │ ├── logs/ (元数据) │ └── block1_2_training_20260319_154018.log │ └── output/ (验证可视化) ├── epoch_01_val.png ├── epoch_02_val.png ├── ... (epoch 3-14) └── epoch_15_val.png ``` --- ### 1.5 速查表 | 模型 | 文件 | 大小 | 用途 | 状态 | |------|------|------|------|------| | **官方摄影模型** | `photographic/modnet_photographic_portrait_matting.ckpt` | 1.8 GB | 基线参考 | ✓ 参考 | | **官方 ONNX** | `photographic/modnet_photographic_portrait_matting.onnx` | 26 MB | InstanceNorm 变体 | ⚠️ 不推荐 | | **微调最佳模型** | `photographic/finetune/checkpoints/modnet_bn_best.ckpt` | 1.8 GB | PyTorch 部署 | ✓ 生产 | | **微调 ONNX** | `photographic/finetune/onnx/modnet_bn_best_pureBN.onnx` | 25 MB | C++/RKNN 部署 | ★ **推荐** | | **摄像头模型** | `modnet_webcam_portrait_matting.ckpt` | 1.8 GB | 实时流媒体 | ✓ 可用 | --- ## 2. RVM 模型 ### 2.1 ONNX 模型 位于 `RobustVideoMatting/onnx/`。 | 模型 | 文件 | 大小 | 骨干网络(Backbone) | 深度导向滤波(Deep Guided Filter) | 来源 | |------|------|------|----------|-----------------|------| | **MobileNetV3 FP32** | `rvm_mobilenetv3_fp32.onnx` | 14.3MB | MobileNetV3 | ✓ | PeterL1n/RobustVideoMatting v1.0.0 | | **MobileNetV3 FP16** | `rvm_mobilenetv3_fp16.onnx` | 7.2MB | MobileNetV3 | ✓ | FP16 导出 | | **MobileNetV3 FP32** | `rvm_mobilenetv3_fp32_no_refiner.onnx` | 14.3MB | MobileNetV3 | — | 移除 Deep Guided Filter | | **ResNet50 FP32** | `rvm_resnet50_fp32.onnx` | ~90MB | ResNet50 | ✓ | PeterL1n v1.0.0 | | **ResNet50 FP16** | `rvm_resnet50_fp16.onnx` | ~45MB | ResNet50 | ✓ | FP16 导出 | **关键模型属性**(MobileNetV3): - Opset 12,IR version 6,353 个节点 - 零个 InstanceNorm 节点(NPU 友好) - 6 个输入:`src [1,3,H,W]`、`r1i~r4i`(ConvGRU 状态)、`downsample_ratio [1]` - 经 ArcFoundry `fold_constant_inputs` 处理后:5 个输入(downsample_ratio 烘焙为常量) ### 2.2 RKNN 模型 位于 `RobustVideoMatting/rknn/`,目标平台 RK3588 / RK3588S。 > **全部 RKNN 都已应用 no-resize graph surgery**(详见 §2.5):refiner 末尾的 > 2× Resize + Mul/Add/Split/Clip 链已从 NPU 图中移除,由 C++ 后处理端实现 > guided-filter 组合 + 上采样。下表不再单独标注 no-resize 变体。 | 模型 | 文件 | 大小 | 分辨率 | 精度 | dsr | 状态 | |------|------|------|--------|------|-----|------| | **1080×1920 FP16** | `rvm_mobilenetv3_fp16_1080x1920_0.25-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 10.9MB | 1080×1920 | FP16 | 0.25 | 默认 | | **736×1280 FP16** | `rvm_mobilenetv3_fp16_736x1280_0.5-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 11.3MB | 736×1280 | FP16 | 0.5 | 较高质量 | | **736×1280 FP16** | `rvm_mobilenetv3_fp16_736x1280_0.25-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 9.9MB | 736×1280 | FP16 | 0.25 | — | | **544×960 FP16** | `rvm_mobilenetv3_fp16_544x960_0.5-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 10.3MB | 544×960 | FP16 | 0.5 | 中等质量 | | **544×960 FP16** | `rvm_mobilenetv3_fp16_544x960_0.25-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 9.5MB | 544×960 | FP16 | 0.25 | — | | **416×736 FP16** | `rvm_mobilenetv3_fp16_416x736_0.5-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 9.8MB | 416×736 | FP16 | 0.5 | — | | **416×736 FP16** | `rvm_mobilenetv3_fp16_416x736_0.25-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 9.3MB | 416×736 | FP16 | 0.25 | — | | **320×576 FP16** | `rvm_mobilenetv3_fp16_320x576_0.5-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 9.5MB | 320×576 | FP16 | 0.5 | — | | **320×576 FP16** | `rvm_mobilenetv3_fp16_320x576_0.25-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 9.1MB | 320×576 | FP16 | 0.25 | — | | **288×512 FP16** | `rvm_mobilenetv3_fp16_288x512_0.25-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 9.1MB | 288×512 | FP16 | 0.25 | 早期验证 | | **256×256 FP16** | `rvm_mobilenetv3_fp16_256x256_0.25-dsr_rk3588s_20260603_rk3588_fp16.rknn` | 8.8MB | 256×256 | FP16 | 0.25 | 早期验证 | **转换工具**:[ArcFoundry](https://github.com/PotterWhite/ArcFoundry.git) v0.15.0 - 配置目录:`ArcFoundry.git/configs/rvm/` - 目标平台:RK3588 / RK3588S - 归一化:`mean=[0,0,0], std=[255,255,255]`(RKNN 运行时执行 `/255.0`) ### 2.3 质量总结 > 当前批次(`rk3588s_20260603`)的板端 benchmark 正在收集中。 > 旧的 s14/s20/s21 数据对应的是已下线的 `rk3588` 批次,不再适用。 通用预期(基于已知的 RVM 行为规律): - **dsr 越大,质量越好、速度越慢**(decoder 工作在 `H×dsr × W×dsr` 分辨率上) - **处理分辨率越大,alpha 边缘越锐利**,但 NPU 推理时间近似线性增长 - 1080p 输入 + `dsr=0.25` 是速度最优档(decoder 工作在 270×480) - 1080p 输入 + `dsr=0.5` 是质量最优档(decoder 工作在 540×960)—— 当前批次未提供该组合 > 详细 benchmark 数据待补。 ### 2.4 推荐模型选择 > 待补。当前批次(`rk3588s_20260603`)的 benchmark 数据收集中。 > 一般规则:质量优先选 `dsr=0.5` 中最大处理分辨率(候选:544×960 / 736×1280), > 速度优先选 `1080×1920 / dsr=0.25`,低内存选 `256×256 / dsr=0.25`。 > 选定后填入下表。 | 使用场景 | 推荐模型 | 理由 | |----------|---------|------| | **质量优先** | _(待补)_ | _(待补)_ | | **速度优先** | _(待补)_ | _(待补)_ | | **低内存** | _(待补)_ | _(待补)_ | ### 2.5 Graph Surgery:移除最终的 Resize 及以后的算子 > **本仓库全部 RKNN 模型都已应用此 graph surgery**(见 §2.2 表前的说明)。 > 原始 RVM ONNX 的 refiner 末尾含 2 个 `Resize` + 后续 element-wise 链(Mul、Add、 > Split、Clip 等),通过 ArcFoundry 的 `graph_surgery` 步骤把这些节点从 NPU 图中 > 移除,由 C++ 后处理端自行完成 guided-filter 组合 + 上采样。 #### 裁剪点 | 项目 | 数值 | |------|-----| | 原始 ONNX 总节点数 | 353 | | 被删除的"尾部"命名算子 | 2× Resize + Mul + Add + Split + Add + 2× Clip(共 8 个) | | `graph.cleanup()` 级联删除的死节点 | 28 个 | | **图清理后净减少的节点(实测)** | **36 个**(353 → 317) | | 裁剪版图输出 tensor | `777`(Conv_316 输出,refiner A,4ch,272×480)、`779`(Sub_318 输出,refiner b,4ch,272×480),外加 `r1o~r4o` | #### 实测算子分类对比 | op_type | 原版 | 裁剪版 | Δ(原版 − 裁剪版) | |---------|----:|-----:|------------------:| | Constant | 48 | 32 | +16 | | Shape | 12 | 8 | +4 | | Slice | 12 | 8 | +4 | | Concat | 23 | 20 | +3 | | Add | 16 | 14 | +2 | | Clip | 2 | 0 | +2 | | Resize | 7 | 5 | +2 | | Mul | 47 | 46 | +1 | | ReduceMean | 2 | 1 | +1 | | Split | 10 | 9 | +1 | | **合计** | | | **+36** | > 上表只列出发生变化的 `op_type`(未变的不列出)。 **为什么 `Constant` 减少了 16 个?** 因为 `graph.cleanup()` 会同时清理那些原本只为 被删节点提供常量输入的 Constant 节点;而 `Shape`/`Slice`/`Concat` 的减少则来自 refiner 内 Concat_311 上游、只为已删除 Resize 准备 shape/slice 信息的辅助节点。 **为什么 `Conv` 一颗没少?** 裁剪只动 refiner 尾巴(ID 195-202 对应的算子), refiner 内部产生 A/b 的 Conv 网络(Conv_312/314/316)被保留——它输出的 A(4ch,272×480) + b(4ch,272×480) 是 C++ 后处理 guided-filter 组合的输入。 --- ## 3. 相关文档 本仓库**仅托管模型制品**(ckpt / onnx / rknn 文件),不包含训练代码和 C++ 推理代码。 - 训练流程、ONNX 导出、C++ 推理、RKNN 转换等代码均在配套的私有仓库中维护 - 公开可见的模型来源: - MODNet:作者 Google Drive(ZHKKKe/MODNet) - RVM:[PeterL1n/RobustVideoMatting](https://github.com/PeterL1n/RobustVideoMatting) v1.0.0 - RKNN 转换 pipeline:[ArcFoundry](https://github.com/PotterWhite/ArcFoundry.git)(配置文件位于其 `configs/rvm/`) --- ## 附录:训练日志摘要 ``` [Config] Device: cuda [Config] Epochs: 15, BS: 8, LR: 0.01, Input: 512×512 [Dataset] Loaded 9421 samples (P3M-10k train) [Model] Total parameters: 6,487,795 [Model] Trainable parameters: 6,487,795 Training Results (15 epochs): - Epoch 1: Avg Loss 0.5410 → Val L1 0.0264 (new best) - Epoch 2: Avg Loss 0.3054 → Val L1 0.0175 (new best) - Epoch 3: Avg Loss 0.2634 → Val L1 0.0121 (new best) - ... - Epoch 15: Avg Loss 0.1820 → Val L1 0.0062 (final) Convergence: ✓ Steady improvement through all 15 epochs Overfitting: ✓ No significant degradation, clean convergence ``` --- **文档版本**:1.4 **最后更新**:2026-07-03 by PotterWhite **提交历史**:通过 Git commit message 追踪