GlauClsDRGrading 是基于 ConvNeXt-tiny 架构的眼科医学影像分类模型,可同时进行青光眼 (Glaucoma) 二分类检测和糖尿病视网膜病变 (Diabetic Retinopathy, DR) 五分级评估。模型使用 Refuge 训练集和 Aptos 训练集训练,在眼底图像 (Fundus Image) 分析场景中有较好的表现。
本仓库将 GlauClsDRGrading 模型从 ONNX 格式转换为 PyTorch 格式,并适配到华为昇腾 (Ascend) NPU 上运行,支持 NPU 推理加速。
| 输出名称 | 维度 | 含义 |
|---|---|---|
| Glau (青光眼) | 2 分类 | 青光眼检测:正常 / 青光眼 |
| DR (糖尿病视网膜病变) | 5 分类 | DR 分级:0~4 级 |
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt| 包名 | 版本要求 | 说明 |
|---|---|---|
| torch | >=2.0.0 | 深度学习框架 |
| torch_npu | >=2.0.0 | 昇腾 NPU 支持 |
| onnx | >=1.14.0 | ONNX 模型格式支持 |
| onnx2torch | >=1.5.0 | ONNX 到 PyTorch 转换 |
| onnxruntime | >=1.15.0 | ONNX Runtime (CPU 推理备选) |
| numpy | >=1.21.0 | 数值计算 |
将 ONNX 模型迁移到华为昇腾 NPU 的过程:
model.onnx)onnx2torch 将 ONNX 模型转换为 PyTorch 模型.to(torch.device("npu:0")) 迁移到 NPUtorch.from_numpy(input).to(device)onnx2torch.convert() 将 ConvNeXt-tiny 的 ONNX 计算图转换为 PyTorch 模型torch.device("npu:0")torch.npu.synchronize() 确保 NPU 操作完成后再计时| 文件 | 说明 |
|---|---|
inference.py | CPU 和 NPU 推理脚本,支持 --device cpu/npu 切换 |
compare_cpu_npu.py | CPU 与 NPU 精度对比脚本(自动运行推理和对比) |
requirements.txt | 依赖包列表 |
readme.md | 本文件 |
model/ | 原始模型文件(ONNX 格式) |
output/ | 推理和对比结果(含日志和 JSON 报告) |
python inference.py --device cpu \
--model-dir ./model/flyer123/GlauClsDRGrading \
--output-dir ./outputpython inference.py --device npu \
--model-dir ./model/flyer123/GlauClsDRGrading \
--output-dir ./outputpython inference.py --device npu \
--model-dir ./model/flyer123/GlauClsDRGrading \
--image /path/to/fundus_image.jpg \
--output-dir ./output| 类别 | Logits (CPU) | Logits (NPU) | 概率 (CPU) | 概率 (NPU) |
|---|---|---|---|---|
| 正常 (Class 0) | 0.0076 | 0.0076 | 0.5498 | 0.5498 |
| 青光眼 (Class 1) | -0.1924 | -0.1924 | 0.4502 | 0.4502 |
| 等级 | Logits (CPU) | Logits (NPU) | 概率 (CPU) | 概率 (NPU) |
|---|---|---|---|---|
| Grade 0 | 1.3796 | 1.3796 | 0.5753 | 0.5753 |
| Grade 1 | -0.3839 | -0.3839 | 0.0986 | 0.0986 |
| Grade 2 | -0.4710 | -0.4710 | 0.0904 | 0.0904 |
| Grade 3 | -0.3593 | -0.3593 | 0.1011 | 0.1011 |
| Grade 4 | -0.0729 | -0.0729 | 0.1346 | 0.1346 |
预测一致: CPU 和 NPU 的 Top-1 预测类别完全一致(青光眼: Class 0, DR: Grade 0)。
使用相同的合成眼底图像 (448×448 RGB) 作为输入,分别在 CPU 和 NPU 上运行推理,对比 4 个输出头的 logits 值和 softmax 概率分布。计算指标包括:
| 指标 | 数值 |
|---|---|
| 总体 L1 误差 | 0.000006 |
| 总体 L2 误差 | 0.000007 |
| 总体余弦相似度 | 0.9999999999 |
| 总体最大绝对误差 | 0.000015 |
| 总体相对误差 | 0.0099% |
| Top-1 预测一致性 | 全部一致 (4/4) |
| 输出头 | L1 误差 | 最大绝对误差 | 余弦相似度 | 相对误差 | Top-1 一致 | 是否 < 1% |
|---|---|---|---|---|---|---|
| glaucoma_logits | 0.000004 | 0.000007 | 1.000000 | 0.0442% | 一致 | PASS |
| dr_logits | 0.000008 | 0.000015 | 1.000000 | 0.0027% | 一致 | PASS |
| aux_0 | 0.000004 | 0.000006 | 1.000000 | 0.0020% | 一致 | PASS |
| aux_1 | 0.000003 | 0.000005 | 1.000000 | 0.0016% | 一致 | PASS |
| 类别 | CPU Logit | NPU Logit | 绝对差异 | CPU 概率 | NPU 概率 | 概率差异 |
|---|---|---|---|---|---|---|
| Class 0 | 0.007562 | 0.007568 | 6.6×10⁻⁶ | 0.549825 | 0.549827 | 1.8×10⁻⁶ |
| Class 1 | -0.192402 | -0.192403 | 7.6×10⁻⁷ | 0.450175 | 0.450173 | 1.8×10⁻⁶ |
| 等级 | CPU Logit | NPU Logit | 绝对差异 | CPU 概率 | NPU 概率 | 概率差异 |
|---|---|---|---|---|---|---|
| Grade 0 | 1.379584 | 1.379596 | 1.2×10⁻⁵ | 0.575276 | 0.575280 | 4.0×10⁻⁶ |
| Grade 1 | -0.383915 | -0.383930 | 1.5×10⁻⁵ | 0.098628 | 0.098626 | 2.0×10⁻⁶ |
| Grade 2 | -0.470993 | -0.470997 | 3.6×10⁻⁶ | 0.090403 | 0.090402 | 1.0×10⁻⁶ |
| Grade 3 | -0.359306 | -0.359298 | 7.1×10⁻⁶ | 0.101085 | 0.101085 | 0.0×10⁻⁶ |
| Grade 4 | -0.072888 | -0.072892 | 4.3×10⁻⁶ | 0.134610 | 0.134608 | 2.0×10⁻⁶ |
| 设备 | 平均推理耗时 | 最小耗时 | 最大耗时 | P50 耗时 | P90 耗时 | 加速比 |
|---|---|---|---|---|---|---|
| CPU | 1630.82ms | 1624.17ms | 1646.08ms | 1628.04ms | 1637.30ms | 1.00× |
| NPU (Ascend910) | 11.60ms | 11.54ms | 11.70ms | 11.60ms | 11.64ms | 140.57× |
测试条件: 10 次推理 (3 次 warmup),输入尺寸 (1, 3, 448, 448)。
NPU 推理速度约为 CPU 的 140.6 倍,满足实时医学影像分析需求。
NPU 与 CPU 推理结果误差 < 1%。
import torch
import numpy as np
from onnx2torch import convert
import onnx
# 加载模型 (ONNX → PyTorch)
onnx_path = "./model/flyer123/GlauClsDRGrading/model.onnx"
onnx_model = onnx.load(onnx_path)
model = convert(onnx_model)
# 迁移到 NPU
device = torch.device("npu:0")
model = model.to(device)
model.eval()
# 准备输入 (RGB 448×448 眼底图像, 像素值 [0, 1])
# 假设使用 OpenCV 读取: img = cv2.imread("fundus.jpg")
# img = img[..., ::-1] # BGR → RGB
# img = cv2.resize(img, (448, 448))
# img = img.transpose(2, 0, 1)[np.newaxis].astype(np.float32) / 255.0
input_tensor = np.random.randn(1, 3, 448, 448).astype(np.float32)
x = torch.from_numpy(input_tensor).to(device)
# 推理
with torch.no_grad():
outputs = model(x)
# 解析结果
glaucoma_logits = outputs[0].cpu().numpy() # (1, 2) 青光眼分类
dr_logits = outputs[1].cpu().numpy() # (1, 5) DR 分级
# Softmax 概率
glaucoma_probs = torch.softmax(torch.tensor(glaucoma_logits), dim=-1).numpy()
dr_probs = torch.softmax(torch.tensor(dr_logits), dim=-1).numpy()
print(f"青光眼: 正常={glaucoma_probs[0][0]:.4f}, 青光眼={glaucoma_probs[0][1]:.4f}")
print(f"DR 分级: Grade0={dr_probs[0][0]:.4f}, Grade1={dr_probs[0][1]:.4f}, "
f"Grade2={dr_probs[0][2]:.4f}, Grade3={dr_probs[0][3]:.4f}, Grade4={dr_probs[0][4]:.4f}")GlauClsDRGrading-npu/
├── inference.py # 推理脚本(支持 CPU/NPU)
├── compare_cpu_npu.py # CPU/NPU 精度对比脚本
├── requirements.txt # 依赖列表
├── readme.md # 本文件
├── model/
│ └── flyer123/
│ └── GlauClsDRGrading/
│ ├── model.onnx # 原始 ONNX 模型
│ ├── configuration.json
│ └── README.md # 原始模型卡片
└── output/
├── cpu_result.json # CPU 推理结果
├── npu_result.json # NPU 推理结果
├── cpu_all_logits.npy # CPU 全部 logits
├── npu_all_logits.npy # NPU 全部 logits
└── comparison_report.json # 精度对比完整报告| 组件 | 版本 |
|---|---|
| CANN | 8.5.1 |
| torch | 2.9.0 |
| torch_npu | 2.9.0.post1 |
| onnx | 1.21.0 |
| onnx2torch | 1.5.15 |
| onnxruntime | 1.26.0 |
| NPU | Ascend910 (64GB HBM) |
| 操作系统 | Linux 5.10.0 aarch64 |
input — (1, 3, 448, 448) float32output (1×2), 837 (1×5), 838 (1×2), 839 (1×2)由于模型由 ONNX 转换为 PyTorch 后部署到 NPU,NPU 上的浮点运算精度 (float32) 与 CPU 保持一致。极小误差来源于:
这些差异完全在可接受范围内(< 0.01%),不影响模型的实际预测结果。
#NPU #Ascend #昇腾 #ConvNeXt #ImageClassification #Glaucoma #DiabeticRetinopathy #MedicalImaging #PyTorch #模型适配 #ONNX
本仓库提供完整的推理脚本,支持 CPU 和 NPU 双平台推理:
# NPU 推理
python3 inference.py --device npu
# CPU 推理
python3 inference.py --device cpu推理完成后会输出推理结果和耗时,表明模型在 NPU 上推理成功。