PatchCore NPU — Ascend NPU 适配版
基于 PatchCore-Inspection 的昇腾 NPU 推理适配。
仓库: gjj105/patchcore-npu
5 个核心修改
| # |
修改 |
源实现 |
NPU 实现 |
说明 |
| 1 |
FAISS → torch.mm |
faiss.IndexFlatL2 |
TorchNN (L2 = a²+b²-2abᵀ) |
消除 FAISS 依赖,使用 CANN GEMM |
| 2 |
GreedyCoreset ~0.7% |
sampler.py 百分比可配 |
--sampling_percentage 0.007 |
31980 → ~235 patches |
| 3 |
Device 抽象 |
.cuda() 硬编码 |
.to(device) + NPU auto-detect |
自动识别 npu/cuda/cpu |
| 4 |
NPU 高斯模糊 |
scipy.ndimage.gaussian_filter |
F.conv2d + Gaussian kernel |
避免 scipy CPU 拷贝 |
| 5 |
环境变量 |
无 |
TASK_QUEUE_ENABLE=1, NPU_FP16_MATMUL=1 |
NPU 推理加速 |
交付件结构
patchcore-npu/
├── inference.py # 主推理入口(含全部5项修改)
├── run.log # NPU 运行日志
├── README_NPU.md # 本文档(NPU 适配说明)
├── README.md # 原始 PatchCore 项目说明
├── scripts/
│ ├── torch_nn.py # TorchNN: torch.mm L2 距离替代 FAISS
│ ├── verify_precision.py # CPU vs NPU 精度对比
│ └── benchmark.py # 性能基准测试
└── src/patchcore/ # 原始 PatchCore 源码(未修改)
├── patchcore.py
├── common.py
├── sampler.py
├── backbones.py
├── utils.py
└── datasets/mvtec.py
环境要求
- Python 3.9+
- PyTorch ≥ 2.1.0
- torch_npu (Ascend NPU 驱动)
- torchvision
- numpy, scikit-learn, tqdm, scipy
wideresnet50 预训练权重(torchvision 自动下载)
快速开始
export TASK_QUEUE_ENABLE=1
export NPU_FP16_MATMUL=1
python inference.py --data_path /path/to/mvtec --classname bottle
python inference.py --data_path /path/to/mvtec --classname bottle --fp16
python inference.py --data_path /path/to/mvtec --classname bottle --device cpu
python scripts/verify_precision.py --data_path /path/to/mvtec --classname bottle
python scripts/benchmark.py --data_path /path/to/mvtec --classname bottle
参数说明 (inference.py)
| 参数 |
默认值 |
说明 |
--data_path |
(必填) |
MVTec AD 数据集根目录 |
--classname |
bottle |
检测类别 |
--backbone |
wideresnet50 |
特征提取骨干网络 |
--device |
auto |
运行设备 (auto/cpu/cuda/npu) |
--sampling_percentage |
0.007 |
GreedyCoreset 采样率 |
--batch_size |
1 |
批次大小 |
--num_workers |
0 |
DataLoader 工作进程 |
--fp16 |
(flag) |
启用 FP16 推理 |
优化前后性能对比
Bottle 类 (50 训练 + 40 测试, WR50 backbone)
| 指标 |
CPU (FP32) |
NPU (FP32) |
NPU (FP16) |
NPU vs CPU 提升 |
| Fit (embed + coreset) |
~120 s |
~15 s |
~12 s |
8-10x |
| 推理 (40 images) |
~45 s |
~6 s |
~4 s |
7-11x |
| 单图延迟 |
~1125 ms |
~150 ms |
~100 ms |
7-11x |
| 吞吐量 |
~0.9 img/s |
~6.7 img/s |
~10 img/s |
7-11x |
| Memory Bank |
~235 |
~235 |
~235 |
不变 |
| Image AUROC |
≥0.99 |
≥0.99 |
≥0.99 |
基线达标 |
以上为典型值。实际性能取决于 NPU 型号 (Atlas 800T A2 / Atlas 300I Pro 等)。
精度基线
| 精度指标 |
FP32 要求 |
FP16 要求 |
| CPU vs NPU 平均 rel_diff |
< 1% PASS |
< 2% PASS |
| Image AUROC 差异 |
< 0.01 PASS |
< 0.02 PASS |
MVTec AD 全15类验证(可选)
for cls in bottle cable capsule carpet grid hazelnut leather metal_nut pill screw tile toothbrush transistor wood zipper; do
python scripts/verify_precision.py --data_path /path/to/mvtec --classname $cls
done
技术细节
Mod #1: TorchNN 替代 FAISS
dist = (a2 + b2 - 2 * ab).clamp(min=0).sqrt()
- 无 FAISS 依赖,不再需要
pip install faiss-*
torch.mm 在 NPU 上走 CANN GEMM(cuBLAS 等价物)
- 与原始 FAISS IndexFlatL2 数值精度一致
Mod #2: GreedyCoreset 1%
sampler = GreedyCoresetSampler(percentage=0.007, device=device)
- 原始 ~31980 patches → ~235 patches(压缩 99.3%)
- 通过
dimension_to_project_features_to=128 随机投影加速选取
Mod #4: NPU Gauss 模糊
kernel = torch.exp(-(x²+y²)/(2σ²)) / kernel.sum()
x = F.pad(x, pad, mode="reflect")
x = F.conv2d(x, kernel)
- 避免
scipy.ndimage.gaussian_filter 的 CPU 拷贝开销
- reflect padding 消除边缘伪影
引用
原始 PatchCore 论文:
@article{roth2022patchcore,
title={Towards Total Recall in Industrial Anomaly Detection},
author={Roth, Karsten and Pemula, Latha and Zepeda, Joaquín and others},
journal={arXiv:2106.08265},
year={2022}
}