18#ifdef JEVOIS_PLATFORM_PRO
23#include <vsi_nn_version.h>
26#define VNN_APP_DEBUG (FALSE)
32#define NEW_VXNODE(_node, _type, _in, _out, _uid) do { \
33 _node = vsi_nn_AddNode(itsGraph, _type, _in, _out, NULL); \
34 _node->uid = (uint32_t)_uid; \
35 if (NULL == _node) LFATAL("NEW_VXNODE failed"); \
38#define NEW_VIRTUAL_TENSOR(_id, _attr, _dtype) do { \
39 memset(_attr.size, 0, VSI_NN_MAX_DIM_NUM * sizeof(vsi_size_t)); \
40 _attr.dim_num = VSI_NN_DIM_AUTO; \
41 _attr.vtl = !VNN_APP_DEBUG; \
42 _attr.is_const = FALSE; \
43 _attr.dtype.vx_type = _dtype; \
44 _id = vsi_nn_AddTensor(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, NULL); \
45 if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_VIRTUAL_TENSOR failed"); \
49#define NEW_CONST_TENSOR(_id, _attr, _dtype, _ofst, _size) do { \
50 data = load_data(fp, _ofst, _size); \
52 _attr.is_const = TRUE; \
53 _attr.dtype.vx_type = _dtype; \
54 _id = vsi_nn_AddTensor(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, data); \
56 if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_CONST_TENSOR failed"); \
60#define NEW_NORM_TENSOR(_id, _attr, _dtype) do { \
62 _attr.is_const = FALSE; \
63 _attr.dtype.vx_type = _dtype; \
64 _id = vsi_nn_AddTensor(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, NULL); \
65 if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_NORM_TENSOR failed"); \
69#define NEW_NORM_TENSOR_FROM_HANDLE(_id, _attr, _dtype) do { \
71 _attr.is_const = FALSE; \
72 _attr.dtype.vx_type = _dtype; \
73 _id = vsi_nn_AddTensorFromHandle(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, NULL); \
74 if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_NORM_TENSOR_FROM_HANDLE failed"); \
90void jevois::dnn::NetworkNPU::create_tensors(std::vector<vsi_nn_tensor_attr_t> & attrs, vsi_nn_node_t * node,
bool isin)
92 if (attrs.empty())
LFATAL(
"Invalid empty " << (isin ?
"in" :
"out") <<
"tensors specification");
94 for (
int tnum = 0; vsi_nn_tensor_attr_t & attr : attrs)
97 vsi_nn_tensor_id_t id;
103 node->input.tensors[tnum] = id;
104 itsGraph->input.tensors[tnum] = id;
109 node->output.tensors[tnum] = id;
110 itsGraph->output.tensors[tnum] = id;
121 if (itsGraph) vsi_nn_ReleaseGraph(&itsGraph);
122 if (itsCtx) vsi_nn_ReleaseContext(&itsCtx);
128 dataroot::freeze(doit);
130 intensors::freeze(doit);
131 outtensors::freeze(doit);
132 ovxver::freeze(doit);
140 if (itsGraph) { vsi_nn_ReleaseGraph(&itsGraph); itsGraph =
nullptr; }
143 if (itsCtx == 0) itsCtx = vsi_nn_CreateContext();
148 size_t const numin = iattrs.size();
149 size_t const numout = oattrs.size();
152 itsGraph = vsi_nn_CreateGraph(itsCtx, numin + numout * 2, 1);
153 if (itsGraph == NULL)
LFATAL(
"Graph creation failed");
155 if (ovxver::get().empty() ==
false)
157 std::vector<std::string> tok =
jevois::split(ovxver::get(),
"\\.");
158 if (tok.size() != 3)
LFATAL(
"Malformed ovxver version [" << ovxver::get() <<
"] -- should be x.y.z");
159 vsi_nn_SetGraphVersion(itsGraph, std::stoi(tok[0]), std::stoi(tok[1]), std::stoi(tok[2]));
162 vsi_nn_SetGraphVersion(itsGraph, VSI_NN_VERSION_MAJOR, VSI_NN_VERSION_MINOR, VSI_NN_VERSION_PATCH);
164 vsi_nn_SetGraphInputs(itsGraph, NULL, numin);
165 vsi_nn_SetGraphOutputs(itsGraph, NULL, numout);
167 LINFO(
"Created graph with " << numin <<
" inputs and " << numout <<
" outputs");
173 if (std::filesystem::exists(m) ==
false)
LFATAL(
"Missing network file " << m <<
" -- ABORT");
176 vsi_nn_node_t * node[1];
177 NEW_VXNODE(node[0], VSI_NN_OP_NBG, numin, numout, 0);
178 node[0]->nn_param.nbg.type = VSI_NN_NBG_FILE;
179 node[0]->nn_param.nbg.url = m.c_str();
182 create_tensors(oattrs, node[0],
false);
183 create_tensors(iattrs, node[0],
true);
186 auto status = vsi_nn_SetupGraph(itsGraph, FALSE);
187 if (status != VSI_SUCCESS)
188 LFATAL(
"Failed to setup graph -- Possible causes:\n"
189 "- Incorrect intensors/outtensors in your YAML file?\n"
190 "- Wrong NPU model? Check --optimize VIPNANOQI_PID0X88\n"
191 "- Wrong NPU SDK version? Running ovxlib " <<
192 VSI_NN_VERSION_MAJOR <<
'.' << VSI_NN_VERSION_MINOR <<
'.' << VSI_NN_VERSION_PATCH);
193 LINFO(
"Graph ready.");
195 if (verifygraph::get())
197 status = vsi_nn_VerifyGraph(itsGraph);
198 if (status != VSI_SUCCESS)
LFATAL(
"Graph verification failed -- \n"
199 "check that intensors/outtensors specs exactly match\n"
200 "those provided during model conversion.");
201 else LINFO(
"Graph verification ok");
207 std::vector<std::string> & info)
209 if (blobs.size() != itsGraph->input.num)
210 LFATAL(
"Received " << blobs.size() <<
" blobs, but network has " << itsGraph->input.num <<
" inputs");
212 for (
size_t b = 0; b < blobs.size(); ++b)
214 cv::Mat
const & blob = blobs[b];
217 vsi_nn_tensor_t * tensor = vsi_nn_GetTensor(itsGraph, itsGraph->input.tensors[b]);
218 if (tensor ==
nullptr)
LFATAL(
"Network does not have input tensor " << b);
219 auto const & iattr = tensor->attr;
227 auto status = vsi_nn_CopyDataToTensor(itsGraph, tensor, (uint8_t *)blob.data);
228 if (status != VSI_SUCCESS)
LFATAL(
"Error setting input tensor: " << status);
234 auto status = vsi_nn_RunGraph(itsGraph);
235 if (status != VSI_SUCCESS)
LFATAL(
"Error running graph: " << status);
236 info.emplace_back(
"- Network forward pass ok");
239 std::vector<cv::Mat> outs;
240 for (uint32_t i = 0; i < itsGraph->output.num; ++i)
242 vsi_nn_tensor_t * ot = vsi_nn_GetTensor(itsGraph, itsGraph->output.tensors[i]);
243 vsi_nn_tensor_attr_t
const & oattr = ot->attr;
244 uint8_t * tensor_data = (uint8_t *)vsi_nn_ConvertTensorToData(itsGraph, ot);
253 info.emplace_back(
"- Out " + std::to_string(i) +
": " +
jevois::dnn::attrstr(oattr) +
" -> 32F");
257 outs.emplace_back(rawout.clone());
262 vsi_nn_Free(tensor_data);
#define NEW_NORM_TENSOR(_id, _attr, _dtype)
#define NEW_VXNODE(_node, _type, _in, _out, _uid)
virtual std::vector< vsi_nn_tensor_attr_t > inputShapes() override
Get shapes of all input tensors.
virtual std::vector< vsi_nn_tensor_attr_t > outputShapes() override
Get shapes of all output tensors.
virtual ~NetworkNPU()
Destructor.
std::vector< cv::Mat > doprocess(std::vector< cv::Mat > const &blobs, std::vector< std::string > &info) override
Process input blobs and obtain output blobs.
void freeze(bool doit) override
Freeze/unfreeze parameters that users should not change while running.
void load() override
Load from disk.
virtual void freeze(bool doit)
Freeze/unfreeze parameters that users should not change while running.
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
void warnAndRethrowException(std::string const &prefix="")
Convenience function to catch an exception, issue some LERROR (depending on type),...
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
std::vector< vsi_nn_tensor_attr_t > parseTensorSpecs(std::string const &specs)
Parse tensor specification.
std::string attrstr(vsi_nn_tensor_attr_t const &attr)
Get a string describing the specs of a tensor, including quantification specs (not provided by shapes...
cv::Mat attrmat(vsi_nn_tensor_attr_t const &attr, void *dataptr=nullptr)
Construct a cv::Mat from attr and possibly data pointer.
cv::Mat dequantize(cv::Mat const &m, vsi_nn_tensor_attr_t const &attr)
Dequantize an output to float32 according to the quantization spec in attr.
std::string shapestr(cv::Mat const &m)
Get a string of the form: "nD AxBxC... TYPE" from an n-dimensional cv::Mat with data type TYPE.
bool attrmatch(vsi_nn_tensor_attr_t const &attr, cv::Mat const &blob)
Check that a cv::Mat blob matches exactly the spec of an attr.
std::filesystem::path absolutePath(std::filesystem::path const &root, std::filesystem::path const &path)
Compute an absolute path from two paths.
std::vector< std::string > split(std::string const &input, std::string const ®ex="\\s+")
Split string into vector of tokens using a regex to specify what to split on; default regex splits by...