fix: ACL bytes_to_ptr GC bug + 添加 NPU 模型转换指南

python/infer_server.py:
- 修复 acl.util.bytes_to_ptr() 后 bytes 被 GC 回收导致全零输出的 bug
- 保持 bytes 引用直到 memcpy 完成
- 正确解析 FP16 模型输出 (half precision -> float32)

docs/CONVERSION_GUIDE.md:
- 完整的 YOLOv8 ONNX->OM 转换流程文档
- ATC 转换参数详解及低内存设备配置
- 已知问题排查表 (OOM/全零输出/算子不支持)
- 其他 YOLOv8 尺寸模型参考

start.sh: 一键启动脚本
This commit is contained in:
2026-05-06 23:30:49 +08:00
parent c69d9b1457
commit ee9be85292
3 changed files with 238 additions and 3 deletions

View File

@@ -112,10 +112,15 @@ class AclModel:
def run(self, blob):
"""Push blob to NPU, execute, pull outputs back as numpy arrays."""
in_ds = acl.mdl.create_dataset()
# Host input buffer - MUST keep reference alive during memcpy
host_buf = np.ascontiguousarray(blob)
host_bytes = host_buf.tobytes()
host_addr = acl.util.bytes_to_ptr(host_bytes)
# Device input buffer
in_buf, ret = acl.rt.malloc(self.input_size, ACL_MEM_MALLOC_NORMAL_ONLY)
assert ret == 0
ret = acl.rt.memcpy(in_buf, self.input_size,
blob.tobytes(), self.input_size,
host_addr, self.input_size,
ACL_MEMCPY_HOST_TO_DEVICE)
assert ret == 0
db = acl.create_data_buffer(in_buf, self.input_size)
@@ -135,11 +140,27 @@ class AclModel:
for i in range(self.output_num):
sz = self.out_sizes[i]
host = np.zeros(sz, dtype=np.uint8)
ret = acl.rt.memcpy(host.ctypes.data, sz,
# Keep reference alive during memcpy
host_bytes = host.tobytes()
host_addr = acl.util.bytes_to_ptr(host_bytes)
ret = acl.rt.memcpy(host_addr, sz,
self.out_bufs[i], sz,
ACL_MEMCPY_DEVICE_TO_HOST)
assert ret == 0
outputs.append(host.view(np.float32).reshape(self.output_shapes[i]))
# Read back from host_bytes (memcpy modified it)
host_from_bytes = np.frombuffer(host_bytes, dtype=np.uint8)
# FP16 model outputs are half precision (2 bytes)
num_fp16 = sz // 2
num_fp32 = sz // 4
expected = self.output_shapes[i][0] * self.output_shapes[i][1] * self.output_shapes[i][2]
if num_fp16 == expected:
out_fp16 = host_from_bytes.view(np.float16)
outputs.append(out_fp16.astype(np.float32).reshape(self.output_shapes[i]))
elif num_fp32 == expected:
outputs.append(host_from_bytes.view(np.float32).reshape(self.output_shapes[i]))
else:
out_fp16 = host_from_bytes.view(np.float16)
outputs.append(out_fp16.astype(np.float32).reshape(self.output_shapes[i]))
acl.rt.free(in_buf)
acl.mdl.destroy_dataset(in_ds)