这一篇没有漂亮数字,全是摔出来的记性。把 YOLOv8n 跑上 Core Ultra 235H 的 NPU,前前后后踩了十二个坑,从'手写 OpenVINO 前后处理'这种架构级错误,到 'findstr 一个空格杀全系统进程'这种低级事故。都记下来,希望你在核显/NPU 上跑推理时少走这三个月的弯路。
环境:Core Ultra 5 235H / Arc 140T / Intel AI Boost NPU / OpenVINO 2026.5.0.dev / Windows / ultralytics + Python。以下按'从模型到服务'的顺序排列。2026-09-12 实测。
架构级:手写 OpenVINO 前后处理必炸
坑 1:自己实现 letterbox / BGR / NMS 坐标解码全部失败。我把导出后的 IR 模型用 OpenVINO Python API 手动喂输入、手写 NMS,换了几套方案——FCOS 解码、坐标逆变换——结果没一个对,最后只能放弃手写解析。
正解就一句话:推理必须走 ultralytics 官方路径 model.predict(..., device="intel:NPU", classes=[0])。前处理后处理它全包,永不手写。这不是'建议'而是'必须'——在这块 OpenVINO 版本上,自己写就一定翻车。
喂料类:cv2 解码是性能刺客
坑 2:cv2 全量解码测出'GPU 很慢'的假结论。刚开始用 cv2 逐帧解码 + 推理,GPU 只有几十张/s,一度以为核显不行。后来换 ffmpeg 抽帧(-vf fps=1 + 内存管道),GPU 单进程直接从'慢'涨到 65.6 张/s——真相是 cv2 的 hwdownload 回读占满了 CPU,GPU 一直在空等解码。
坑 3:落盘 JPG 再读回来也慢。既不用 cv2 全量解码,也不要先把帧写成一堆 JPG 再读——磁盘 IO 瓶颈会让 CPU 忙于解码,喂不饱 GPU/NPU。最正确是 rawvideo 管道直接喂内存:检测从 32.6s 降到 25.0s(-23%)。
并发类:多进程的 Windows 特供雷
坑 4:multiprocessing Pool 在 Windows spawn 下递归卡死。脚本顶层就建 Pool,Windows 用 spawn 起子进程时会重新执行整个模块,于是递归创建池子直到卡死。正解是 if __name__ == "__main__": 保护——只在主入口建池。
坑 5:Pool.map 不是线程安全的。常驻服务多线程时并发调 map,反而降低吞吐。生产里改成客户端串行逐目录调用服务,规避掉这个炸弹。
跨进程坑:HTTP 服务与工具环境
坑 6:urllib timeout=0 是'非阻塞模式'不是'不超时'。设 0 直接抛 BlockingIOError(10035)。必须给具体超时秒数。
坑 7:工具环境会杀后台进程。assets/检测服务在会话结束后就被干掉了。正式跑必须用常驻服务 + 计划任务(Windows 调度器独立进程),或者用户自己开 cmd 窗口运行启动脚本。
文件级坑:BOM 与 glob
坑 8:UTF8 BOM 让 ffmpeg concat 列表首行报 unknown keyword。用 Python 写 concat 列表文件时默认带 BOM,ffmpeg 读到首个 #EXTM3U/file ... 前多了不可见字节直接误解。写文件必须用无 BOM UTF8。
坑 9:glob 通配符漏文件。监控文件名 NNM43S_ 这类带采样秒的格式,用 0*.mp4 只匹配到 00-09 分钟的文件,直接漏掉 5/6 的输入。正解 *M*S_*.mp4 匹配全部;且按文件名里的 unix 时间戳排序,保证时间轴连续。
音量最大的教训:findstr 杀全系统进程
坑 10:findstr ":8765 LISTENING" 里的空格是 OR 条件。一个不小心匹配到系统里所有含 :8765 或 LISTENING 的进程,一条 taskkill 下去差点带走半个系统。停止服务必须用 PowerShell Get-NetTCPConnection -LocalPort 精准杀端口。
视频处理坑
坑 11:inpoint/outpoint + copy 对 HEVC 截断会破坏流(moov 缺失导致文件打不开)。别用 copy 模式精确截 HEVC,用 filter_complex 或切片方案。
坑 12:处理目标目录前先复制到副本。几 GB 的监控目录直接拿原目录试跑,出任何意外都可能损伤源数据。正规流程是 先 copy 副本再处理,绝不直接改 D 盘源目录;成功成片后再考虑归档。
常驻服务设计(绕开工具环境)
:: detect_server.py 常驻:GPU4+NPU3 双池混合,模型仅加载一次(~30s),接口调用零加载
:: POST /detect {"dir":..} -> 检测 JSON ; GET /health -> 就绪探测
:: start_server.cmd / stop_server.cmd 手动启停(关窗即停)
最终形态是一个常驻检测服务 + 模型只加载一次:detect_server.py 起 GPU4+NPU3 双池,启动约 30s 后每个请求零加载;批量客户端 batch_run.py 扫目录逐个调服务;全套部署细节和端到端数字见监控只留有人画面实战。
十二条速查
- 手写 OpenVINO 前后处理必炸 → 只走 ultralytics 官方
model.predict - cv2 全量解码是假慢 → 用 ffmpeg 抽帧喂内存
- 落盘 JPG 也慢 → rawvideo 管道直达
- Windows spawn 递归 →
if __name__保护 - Pool.map 非线程安全 → 客户端串行调
- urllib timeout=0 是非阻塞 → 给具体秒数
- 工具环境杀后台 → 常驻服务 + 计划任务
- BOM 毁 concat 列表 → 无 BOM UTF8
- glob 漏文件 →
*M*S_*.mp4+ 按时间戳排序 - findstr 空格=OR →
Get-NetTCPConnection杀端口 - copy 截 HEVC 破坏流 → filter_complex/切片
- 直接改源目录 → 先复制副本
