nncase
模型模拟器API手册#
概述#
除了编译模型 API,nncase
还提供了推理模型的 API,使用 Python
在 PC 上可推理编译模型生成的 kmodel
,用来验证 nncase
推理结果和相应深度学习框架的 runtime 下生成的结果是否一致。本文档提供的 API 用于在本地 PC 上验证 kmodel
转换的正确性,并不是在 k230
上运行的代码。关于 nncase
的学习,请参考:nncase github repo 。
API 介绍#
MemoryRange#
【描述】
MemoryRange类, 用于表示内存范围。
【定义】
py::class_<memory_range>(m, "MemoryRange")
.def_readwrite("location", &memory_range::memory_location)
.def_property(
"dtype", [](const memory_range &range) { return to_dtype(range.datatype); },
[](memory_range &range, py::object dtype) { range.datatype = from_dtype(py::dtype::from_args(dtype)); })
.def_readwrite("start", &memory_range::start)
.def_readwrite("size", &memory_range::size);
【属性】
名称 |
类型 |
描述 |
---|---|---|
location |
int |
内存位置, 0表示input, 1表示output, 2表示rdata, 3表示data, 4表示shared_data |
dtype |
python数据类型 |
数据类型 |
start |
int |
内存起始地址 |
Size |
int |
内存大小 |
【示例】
mr = nncase.MemoryRange()
RuntimeTensor#
【描述】
RuntimeTensor类, 用于表示运行时tensor。
【定义】
py::class_<runtime_tensor>(m, "RuntimeTensor")
.def_static("from_numpy", [](py::array arr) {
auto src_buffer = arr.request();
auto datatype = from_dtype(arr.dtype());
auto tensor = host_runtime_tensor::create(
datatype,
to_rt_shape(src_buffer.shape),
to_rt_strides(src_buffer.itemsize, src_buffer.strides),
gsl::make_span(reinterpret_cast<gsl::byte *>(src_buffer.ptr), src_buffer.size * src_buffer.itemsize),
[=](gsl::byte *) { arr.dec_ref(); })
.unwrap_or_throw();
arr.inc_ref();
return tensor;
})
.def("copy_to", [](runtime_tensor &from, runtime_tensor &to) {
from.copy_to(to).unwrap_or_throw();
})
.def("to_numpy", [](runtime_tensor &tensor) {
auto host = tensor.as_host().unwrap_or_throw();
auto src_map = std::move(hrt::map(host, hrt::map_read).unwrap_or_throw());
auto src_buffer = src_map.buffer();
return py::array(
to_dtype(tensor.datatype()),
tensor.shape(),
to_py_strides(runtime::get_bytes(tensor.datatype()), tensor.strides()),
src_buffer.data());
})
.def_property_readonly("dtype", [](runtime_tensor &tensor) {
return to_dtype(tensor.datatype());
})
.def_property_readonly("shape", [](runtime_tensor &tensor) {
return to_py_shape(tensor.shape());
})
【属性】
名称 |
类型 |
描述 |
---|---|---|
dtype |
python数据类型 |
Tensor的数据类型 |
shape |
list |
tensor的形状 |
from_numpy#
【描述】
从numpy.ndarray构造RuntimeTensor对象。
【定义】
from_numpy(py::array arr)
【参数】
名称 |
类型 |
描述 |
---|---|---|
Arr |
numpy.ndarray |
numpy.ndarray对象 |
【返回值】
RuntimeTensor对象。
【示例】
tensor = nncase.RuntimeTensor.from_numpy(self.inputs[i]['data'])
copy_to#
【描述】
拷贝RuntimeTensor。
【定义】
copy_to(RuntimeTensor to)
【参数】
名称 |
类型 |
描述 |
---|---|---|
to |
RuntimeTensor |
RuntimeTensor对象 |
【返回值】
无。
【示例】
sim.get_output_tensor(i).copy_to(to)
to_numpy#
【描述】
将RuntimeTensor转换为numpy.ndarray对象。
【定义】
to_numpy()
【参数】
无。
【返回值】
numpy.ndarray对象。
【示例】
arr = sim.get_output_tensor(i).to_numpy()
Simulator#
【描述】
Simulator类, 用于在PC上推理kmodel。
【定义】
py::class_<interpreter>(m, "Simulator")
.def(py::init())
.def("load_model", [](interpreter &interp, gsl::span<const gsl::byte> buffer) { interp.load_model(buffer).unwrap_or_throw(); })
.def_property_readonly("inputs_size", &interpreter::inputs_size)
.def_property_readonly("outputs_size", &interpreter::outputs_size)
.def("get_input_desc", &interpreter::input_desc)
.def("get_output_desc", &interpreter::output_desc)
.def("get_input_tensor", [](interpreter &interp, size_t index) { return interp.input_tensor(index).unwrap_or_throw(); })
.def("set_input_tensor", [](interpreter &interp, size_t index, runtime_tensor tensor) { return interp.input_tensor(index, tensor).unwrap_or_throw(); })
.def("get_output_tensor", [](interpreter &interp, size_t index) { return interp.output_tensor(index).unwrap_or_throw(); })
.def("set_output_tensor", [](interpreter &interp, size_t index, runtime_tensor tensor) { return interp.output_tensor(index, tensor).unwrap_or_throw(); })
.def("run", [](interpreter &interp) { interp.run().unwrap_or_throw(); })
【属性】
名称 |
类型 |
描述 |
---|---|---|
inputs_size |
int |
输入个数 |
outputs_size |
int |
输出个数 |
【示例】
sim = nncase.Simulator()
load_model#
【描述】
加载kmodel。
【定义】
load_model(model_content)
【参数】
名称 |
类型 |
描述 |
---|---|---|
model_content |
byte[] |
kmodel字节流 |
【返回值】
无。
【示例】
sim.load_model(kmodel)
get_input_desc#
【描述】
获取指定索引的输入的描述信息。
【定义】
get_input_desc(index)
【参数】
名称 |
类型 |
描述 |
---|---|---|
index |
int |
输入的索引 |
【返回值】
MemoryRange
【示例】
input_desc_0 = sim.get_input_desc(0)
get_output_desc#
【描述】
获取指定索引的输出的描述信息。
【定义】
get_output_desc(index)
【参数】
名称 |
类型 |
描述 |
---|---|---|
index |
int |
输出的索引 |
【返回值】
MemoryRange
【示例】
output_desc_0 = sim.get_output_desc(0)
get_input_tensor#
【描述】
获取指定索引的输入的RuntimeTensor。
【定义】
get_input_tensor(index)
【参数】
名称 |
类型 |
描述 |
---|---|---|
index |
int |
输入tensor的索引 |
【返回值】
RuntimeTensor
【示例】
input_tensor_0 = sim.get_input_tensor(0)
set_input_tensor#
【描述】
设置指定索引的输入的RuntimeTensor。
【定义】
set_input_tensor(index, tensor)
【参数】
名称 |
类型 |
描述 |
---|---|---|
index |
int |
输入tensor的索引 |
tensor |
RuntimeTensor |
输入tensor |
【返回值】
无。
【示例】
sim.set_input_tensor(0, nncase.RuntimeTensor.from_numpy(self.inputs[0]['data']))
get_output_tensor#
【描述】
获取指定索引的输出的RuntimeTensor。
【定义】
get_output_tensor(index)
【参数】
名称 |
类型 |
描述 |
---|---|---|
index |
int |
输出tensor的索引 |
【返回值】
RuntimeTensor
【示例】
output_arr_0 = sim.get_output_tensor(0).to_numpy()
set_output_tensor#
【描述】
设置指定索引的输出的RuntimeTensor。
【定义】
set_output_tensor(index, tensor)
【参数】
名称 |
类型 |
描述 |
---|---|---|
index |
int |
输出tensor的索引 |
tensor |
RuntimeTensor |
输出tensor |
【返回值】
无。
【示例】
sim.set_output_tensor(0, tensor)
run#
【描述】
运行kmodel推理。
【定义】
run()
【参数】
无。
【返回值】
无。
【示例】
sim.run()
示例#
前置条件: yolov5s_onnx.py脚本已编译过yolov5s.onnx模型。
yolov5s_onnx_simu.py位于/path/to/k230_sdk/src/big/nncase/examples/scripts子目录,内容如下:
import os
import copy
import argparse
import numpy as np
import onnx
import onnxruntime as ort
import nncase
def read_model_file(model_file):
with open(model_file, 'rb') as f:
model_content = f.read()
return model_content
def cosine(gt, pred):
return (gt @ pred) / (np.linalg.norm(gt, 2) * np.linalg.norm(pred, 2))
def main():
parser = argparse.ArgumentParser(prog="nncase")
parser.add_argument("--model", type=str, help='original model file')
parser.add_argument("--model_input", type=str, help='input bin file for original model')
parser.add_argument("--kmodel", type=str, help='kmodel file')
parser.add_argument("--kmodel_input", type=str, help='input bin file for kmodel')
args = parser.parse_args()
# cpu inference
ort_session = ort.InferenceSession(args.model)
output_names = []
model_outputs = ort_session.get_outputs()
for i in range(len(model_outputs)):
output_names.append(model_outputs[i].name)
model_input = ort_session.get_inputs()[0]
model_input_name = model_input.name
model_input_type = np.float32
model_input_shape = model_input.shape
model_input_data = np.fromfile(args.model_input, model_input_type).reshape(model_input_shape)
cpu_results = []
cpu_results = ort_session.run(output_names, { model_input_name : model_input_data })
# create simulator
sim = nncase.Simulator()
# read kmodel
kmodel = read_model_file(args.kmodel)
# load kmodel
sim.load_model(kmodel)
# read input.bin
# input_tensor=sim.get_input_tensor(0).to_numpy()
dtype = sim.get_input_desc(0).dtype
input = np.fromfile(args.kmodel_input, dtype).reshape([1, 3, 320, 320])
# set input for simulator
sim.set_input_tensor(0, nncase.RuntimeTensor.from_numpy(input))
# simulator inference
nncase_results = []
sim.run()
for i in range(sim.outputs_size):
nncase_result = sim.get_output_tensor(i).to_numpy()
nncase_results.append(copy.deepcopy(nncase_result))
# compare
for i in range(sim.outputs_size):
cos = cosine(np.reshape(nncase_results[i], (-1)), np.reshape(cpu_results[i], (-1)))
print('output {0} cosine similarity : {1}'.format(i, cos))
if __name__ == '__main__':
main()
执行推理脚本
root@5f718e19f8a7:/mnt/# cd src/big/nncase/examples
root@5f718e19f8a7:/mnt/src/big/nncase/examples # export PATH=$PATH:/usr/local/lib/python3.8/dist-packages/
root@5f718e19f8a7:/mnt/src/big/nncase/examples # python3 scripts/yolov5s_onnx_simu.py --model models/yolov5s.onnx --model_input object_detect/data/input_fp32.bin --kmodel tmp/yolov5s_onnx/test.kmodel --kmodel_input object_detect/data/input_uint8.bin
nncase simulator和CPU推理结果对比如下
output 0 cosine similarity : 0.9997244477272034
output 1 cosine similarity : 0.999757707118988
output 2 cosine similarity : 0.9997308850288391