18#ifdef JEVOIS_PLATFORM_PRO 
   25#include <vsi_nn_version.h> 
   28#define VNN_APP_DEBUG (FALSE) 
   34#define NEW_VXNODE(_node, _type, _in, _out, _uid) do {          \ 
   35    _node = vsi_nn_AddNode(itsGraph, _type, _in, _out, NULL);   \ 
   36    _node->uid = (uint32_t)_uid;                                \ 
   37    if (NULL == _node) LFATAL("NEW_VXNODE failed");             \ 
 
   40#define NEW_VIRTUAL_TENSOR(_id, _attr, _dtype) do {                     \ 
   41    memset(_attr.size, 0, VSI_NN_MAX_DIM_NUM * sizeof(vsi_size_t));     \ 
   42    _attr.dim_num = VSI_NN_DIM_AUTO;                                    \ 
   43    _attr.vtl = !VNN_APP_DEBUG;                                         \ 
   44    _attr.is_const = FALSE;                                             \ 
   45    _attr.dtype.vx_type = _dtype;                                       \ 
   46    _id = vsi_nn_AddTensor(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, NULL); \ 
   47    if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_VIRTUAL_TENSOR failed"); \ 
 
   51#define NEW_CONST_TENSOR(_id, _attr, _dtype, _ofst, _size) do {         \ 
   52    data = load_data(fp, _ofst, _size);                                 \ 
   54    _attr.is_const = TRUE;                                              \ 
   55    _attr.dtype.vx_type = _dtype;                                       \ 
   56    _id = vsi_nn_AddTensor(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, data); \ 
   58    if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_CONST_TENSOR failed");  \ 
 
   62#define NEW_NORM_TENSOR(_id, _attr, _dtype) do {                        \ 
   64    _attr.is_const = FALSE;                                             \ 
   65    _attr.dtype.vx_type = _dtype;                                       \ 
   66    _id = vsi_nn_AddTensor(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, NULL); \ 
   67    if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_NORM_TENSOR failed");   \ 
 
   71#define NEW_NORM_TENSOR_FROM_HANDLE(_id, _attr, _dtype) do {            \ 
   73    _attr.is_const = FALSE;                                             \ 
   74    _attr.dtype.vx_type = _dtype;                                       \ 
   75    _id = vsi_nn_AddTensorFromHandle(itsGraph, VSI_NN_TENSOR_ID_AUTO, & _attr, NULL); \ 
   76    if (VSI_NN_TENSOR_ID_NA == _id) LFATAL("NEW_NORM_TENSOR_FROM_HANDLE failed"); \ 
 
  102  if (library::get().empty() == 
false)
 
  104    if (
ready() == 
false) 
LFATAL(
"Network is not ready");
 
  105    std::vector<vsi_nn_tensor_attr_t> ret;
 
  106    for (uint32_t i = 0; i < itsGraph->input.num; ++i)
 
  108      ret.emplace_back(vsi_nn_GetTensor(itsGraph, itsGraph->input.tensors[i])->attr);
 
  112      if (library::get().empty() == 
false && ret.back().dim_num >= 3)
 
  114        vsi_nn_tensor_attr_t & attr = ret.back();
 
  115        switch (attr.dtype.fmt)
 
  117        case VSI_NN_DIM_FMT_NCHW:
 
  118          if (attr.size[2]  > attr.size[0] ) attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
 
  120        case VSI_NN_DIM_FMT_NHWC:
 
  121          if (attr.size[0]  > attr.size[1] ) attr.dtype.fmt = VSI_NN_DIM_FMT_NCHW;
 
 
  138  if (library::get().empty() == 
false)
 
  140    if (ready() == 
false) 
LFATAL(
"Network is not ready");
 
  141    std::vector<vsi_nn_tensor_attr_t> ret;
 
  142    for (uint32_t i = 0; i < itsGraph->output.num; ++i)
 
  143      ret.emplace_back(vsi_nn_GetTensor(itsGraph, itsGraph->output.tensors[i])->attr);
 
 
  152void jevois::dnn::NetworkNPU::create_tensors(std::vector<vsi_nn_tensor_attr_t> & attrs, vsi_nn_node_t * node, 
bool isin)
 
  154  if (attrs.empty()) 
LFATAL(
"Invalid empty " << (isin ? 
"in" : 
"out") << 
"tensors specification");
 
  156  for (
int tnum = 0; vsi_nn_tensor_attr_t & attr : attrs)
 
  159    vsi_nn_tensor_id_t id;
 
  165      node->input.tensors[tnum] = id;
 
  166      itsGraph->input.tensors[tnum] = id;
 
  171      node->output.tensors[tnum] = id;
 
  172      itsGraph->output.tensors[tnum] = id;
 
  183  if (itsGraph) vsi_nn_ReleaseGraph(&itsGraph);
 
  184  if (itsCtx) vsi_nn_ReleaseContext(&itsCtx);
 
 
  192  dataroot::freeze(doit);
 
  194  library::freeze(doit);
 
  195  intensors::freeze(doit);
 
  196  outtensors::freeze(doit);
 
  197  ovxver::freeze(doit);
 
 
  205  if (itsGraph) { vsi_nn_ReleaseGraph(&itsGraph); itsGraph = 
nullptr; }
 
  208  if (itsCtx == 0) itsCtx = vsi_nn_CreateContext();
 
  214  if (std::filesystem::exists(m) == 
false) 
LFATAL(
"Missing network file " << m << 
" -- ABORT");
 
  218  std::string libname = library::get();
 
  224    size_t const numin = iattrs.size();
 
  225    size_t const numout = oattrs.size();
 
  228    itsGraph = vsi_nn_CreateGraph(itsCtx, numin + numout * 2, 1);
 
  229    if (itsGraph == NULL) 
LFATAL(
"Graph creation failed");
 
  231    if (ovxver::get().empty() == 
false)
 
  233      std::vector<std::string> tok = 
jevois::split(ovxver::get(), 
"\\.");
 
  234      if (tok.size() != 3) 
LFATAL(
"Malformed ovxver version [" << ovxver::get() <<
"] -- should be x.y.z");
 
  235      vsi_nn_SetGraphVersion(itsGraph, std::stoi(tok[0]), std::stoi(tok[1]), std::stoi(tok[2]));
 
  238      vsi_nn_SetGraphVersion(itsGraph, VSI_NN_VERSION_MAJOR, VSI_NN_VERSION_MINOR, VSI_NN_VERSION_PATCH);
 
  240    vsi_nn_SetGraphInputs(itsGraph, NULL, numin);
 
  241    vsi_nn_SetGraphOutputs(itsGraph, NULL, numout);
 
  243    LINFO(
"Created graph with " << numin << 
" inputs and " << numout << 
" outputs");
 
  246    vsi_nn_node_t * node[1];
 
  247    NEW_VXNODE(node[0], VSI_NN_OP_NBG, numin, numout, 0);
 
  248    node[0]->nn_param.nbg.type = VSI_NN_NBG_FILE;
 
  249    node[0]->nn_param.nbg.url = m.c_str();
 
  252    create_tensors(oattrs, node[0], 
false);
 
  253    create_tensors(iattrs, node[0], 
true);
 
  256    auto status = vsi_nn_SetupGraph(itsGraph, FALSE);
 
  257    if (status != VSI_SUCCESS)
 
  258      LFATAL(
"Failed to setup graph -- Possible causes:\n" 
  259             "- Incorrect intensors/outtensors in your YAML file?\n" 
  260             "- Wrong NPU model? Check --optimize VIPNANOQI_PID0X88\n" 
  261             "- Wrong NPU SDK version? Running ovxlib " <<
 
  262             VSI_NN_VERSION_MAJOR << 
'.' << VSI_NN_VERSION_MINOR << 
'.' << VSI_NN_VERSION_PATCH);
 
  269    if (std::filesystem::exists(libpath) == 
false) 
LFATAL(
"Missing library file " << libpath << 
" -- ABORT");
 
  272    typedef vsi_nn_graph_t*(signature)(
char const * ,
 
  279    auto createmodel = itsLibLoader->load<signature>(
"vnn_CreateModel");
 
  281    itsGraph = createmodel(m.c_str(), itsCtx, 
nullptr, 0, 
nullptr, 0);
 
  285    if (itsGraph == NULL)
 
  286      LFATAL(
"Graph creation using library failed:\n" 
  287             "- Wrong NPU model? Use kboard=VIM3 in convert\n" 
  288             "- Wrong NPU SDK version? Running ovxlib " <<
 
  289             VSI_NN_VERSION_MAJOR << 
'.' << VSI_NN_VERSION_MINOR << 
'.' << VSI_NN_VERSION_PATCH);
 
  290    LINFO(
"Graph successfully created using library.");
 
  293    for (uint32_t i = 0; i < itsGraph->input.num; ++i)
 
  294      LINFO(
"Input tensor " << i << 
": " <<
 
  297    for (uint32_t i = 0; i < itsGraph->output.num; ++i)
 
  298      LINFO(
"Output tensor " << i << 
": " <<
 
  302  LINFO(
"Graph ready.");
 
  304  if (verifygraph::get())
 
  306    auto status = vsi_nn_VerifyGraph(itsGraph);
 
  307    if (status != VSI_SUCCESS) 
LFATAL(
"Graph verification failed -- \n" 
  308                                      "check that intensors/outtensors specs exactly match\n" 
  309                                      "those provided during model conversion.");
 
  310    else LINFO(
"Graph verification ok");
 
 
  319  static std::function<std::string(vsi_nn_graph_t *, 
size_t, cv::Mat &)>
 
  320  dequantize_one = [](vsi_nn_graph_t * graph, 
size_t i, cv::Mat & 
o) -> std::string
 
  322    vsi_nn_tensor_t * ot = vsi_nn_GetTensor(graph, graph->output.tensors[i]);
 
  323    vsi_nn_tensor_attr_t 
const & oattr = ot->attr;
 
  324    uint8_t * tensor_data = (uint8_t *)vsi_nn_ConvertTensorToData(graph, ot);
 
  330      vsi_nn_Free(tensor_data);
 
  339                                                        std::vector<std::string> & info)
 
  341  if (blobs.size() != itsGraph->input.num)
 
  342    LFATAL(
"Received " << blobs.size() << 
" blobs, but network has " << itsGraph->input.num << 
" inputs");
 
  349  for (
size_t b = 0; b < blobs.size(); ++b)
 
  351    cv::Mat 
const & blob = blobs[b];
 
  354    vsi_nn_tensor_t * tensor = vsi_nn_GetTensor(itsGraph, itsGraph->input.tensors[b]);
 
  355    if (tensor == 
nullptr) 
LFATAL(
"Network does not have input tensor " << b);
 
  356    auto const & iattr = tensor->attr;
 
  364    auto status = vsi_nn_CopyDataToTensor(itsGraph, tensor, (uint8_t *)blob.data);
 
  365    if (status != VSI_SUCCESS) 
LFATAL(
"Error setting input tensor: " << status);
 
  369  info.emplace_back(intimer.
stop());
 
  373  auto status = vsi_nn_RunGraph(itsGraph);
 
  374  if (status != VSI_SUCCESS) 
LFATAL(
"Error running graph: " << status);
 
  375  info.emplace_back(infertimer.
stop());
 
  378  size_t const numouts = itsGraph->output.num;
 
  379  if (numouts == 0) 
return std::vector<cv::Mat>();
 
  381  std::vector<cv::Mat> outs(numouts);
 
  389      info.emplace_back(dequantize_one(itsGraph, 0, std::ref(outs[0])));
 
  393      std::vector<std::future<std::string>> fvec;
 
  395      for (uint32_t i = 0; i < numouts; ++i)
 
  396        fvec.emplace_back(
jevois::async(dequantize_one, itsGraph, i, std::ref(outs[i])));
 
  402      info.insert(info.end(), std::make_move_iterator(retvec.begin()), std::make_move_iterator(retvec.end()));
 
  404    info.emplace_back(dqtimer.
stop());
 
  409    for (uint32_t i = 0; i < numouts; ++i)
 
  411      vsi_nn_tensor_t * ot = vsi_nn_GetTensor(itsGraph, itsGraph->output.tensors[i]);
 
  412      vsi_nn_tensor_attr_t 
const & oattr = ot->attr;
 
  413      uint8_t * tensor_data = (uint8_t *)vsi_nn_ConvertTensorToData(itsGraph, ot);
 
  418        outs[i] = rawout.clone();
 
  423      vsi_nn_Free(tensor_data);
 
 
#define NEW_NORM_TENSOR(_id, _attr, _dtype)
#define NEW_VXNODE(_node, _type, _in, _out, _uid)
Class to open shared object (.so) files and load functions contained in them.
Simple one-shot timer class.
std::string stop(double *seconds)
End a time measurement period, report time spent as: 'prefix: ms (fps)' where % is replaced by values...
void start()
Start a time measurement period.
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.
bool ready()
Returns true when network is ready to run (loaded and initialized)
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::vector< T > joinall(std::vector< std::future< T > > &fvec, bool multiline=true)
Collect results from several async threads that are all returning a T result.
std::future< std::invoke_result_t< std::decay_t< Function >, std::decay_t< Args >... > > async(Function &&f, Args &&... args)
Async execution using a thread pool.
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...
uint32_t postprocess_count
uint32_t graph_output_idx
vsi_nn_postprocess_base_t * postprocesses
vsi_nn_preprocess_base_t * preprocesses
uint32_t preprocess_count