35 std::map<int, std::string> ret;
36 for (
auto c : tok) ret[classid++] = c;
44 std::ifstream ifs(fname);
45 if (ifs.is_open() ==
false)
LFATAL(
"Failed to open file " << fname);
47 size_t linenum = 1; std::map<int, std::string> ret;
int id = 0;
48 for (std::string line; std::getline(ifs, line); ++linenum)
50 size_t idx1 = line.find_first_not_of(
" \t");
if (idx1 == line.npos)
continue;
51 size_t idx2 = line.find_last_not_of(
" \t\r\n");
if (idx2 == line.npos)
continue;
52 if (line[idx1] ==
'#')
continue;
54 try {
id = std::stoi(line, &idx1); idx1 = line.find_first_not_of(
"0123456789 \t,:", idx1); }
catch (...) { }
56 std::string classname;
59 LERROR(fname <<
':' << linenum <<
": empty class name -- REPLACING BY 'unspecified'");
60 classname =
"unspecified";
62 else classname = line.substr(idx1, idx2 + 1 - idx1);
68 size_t len = classname.length();
69 if (len > 1 && classname[0] ==
'"' && classname[len-1] ==
'"') classname = classname.substr(1, len-2);
79 LINFO(
"Loaded " << ret.size() <<
" class names from " << fname);
87 auto itr = labels.find(
id);
88 if (itr == labels.end())
90 if (namedonly)
return std::string();
91 else return std::to_string(
id);
100 for (
char const c : label) col = c + ((col << 5) - col);
101 col = (col & 0xffffff) | (alpha << 24);
106void jevois::dnn::topK(
float const * pfProb,
float * pfMaxProb, uint32_t * pMaxClass, uint32_t outputCount,
109 memset(pfMaxProb, 0xfe,
sizeof(
float) * topNum);
110 memset(pMaxClass, 0xff,
sizeof(
float) * topNum);
112 for (uint32_t j = 0; j < topNum; ++j)
114 for (uint32_t i = 0; i < outputCount; ++i)
117 for (k = 0; k < topNum; ++k)
if (i == pMaxClass[k])
break;
118 if (k != topNum)
continue;
120 if (pfProb[i] > pfMaxProb[j]) { pfMaxProb[j] = pfProb[i]; pMaxClass[j] = i; }
128 cv::MatSize
const & ms = m.size;
int const nd = ms.dims();
129 std::string ret = std::to_string(nd) +
"D ";
130 for (
int i = 0; i < nd; ++i) ret += std::to_string(ms[i]) + (i < nd-1 ?
"x" :
"");
138 int const nd = int(dims.size());
139 std::string ret = std::to_string(nd) +
"D ";
140 for (
int i = 0; i < nd; ++i) ret += std::to_string(dims[i]) + (i < nd-1 ?
"x" :
"");
148 int const nd = int(dims.size());
149 std::string ret = std::to_string(nd) +
"D ";
150 for (
int i = 0; i < nd; ++i) ret += std::to_string(dims[i]) + (i < nd-1 ?
"x" :
"");
159 TfLiteIntArray
const & dims = *t->dims;
160 std::string ret = std::to_string(dims.size) +
"D ";
161 for (
int i = 0; i < dims.size; ++i) ret += std::to_string(dims.data[i]) + (i < dims.size-1 ?
"x" :
"");
166 case kTfLiteNoType: ret +=
" NoType";
break;
167 case kTfLiteFloat32: ret +=
" 32F";
break;
168 case kTfLiteInt32: ret +=
" 32S";
break;
169 case kTfLiteUInt8: ret +=
" 8U";
break;
170 case kTfLiteInt64: ret +=
" 64S";
break;
171 case kTfLiteString: ret +=
" String";
break;
172 case kTfLiteBool: ret +=
" 8B";
break;
173 case kTfLiteInt16: ret +=
" 16S";
break;
174 case kTfLiteComplex64: ret +=
" 64C";
break;
175 case kTfLiteInt8: ret +=
" 8I";
break;
176 case kTfLiteFloat16: ret +=
" 16F";
break;
177 case kTfLiteFloat64: ret +=
" 64F";
break;
178 case kTfLiteComplex128: ret +=
" 128C";
break;
179 default: ret +=
" UnknownType";
break;
187 std::string ret = std::to_string(attr.dim_num) +
"D ";
188 for (uint32_t i = 0; i < attr.dim_num; ++i)
189 ret += std::to_string(attr.size[attr.dim_num-1-i]) + (i < attr.dim_num-1 ?
"x" :
"");
192 switch (attr.dtype.vx_type)
194 case VSI_NN_TYPE_UINT8: ret +=
" 8U";
break;
195 case VSI_NN_TYPE_INT8: ret +=
" 8S";
break;
196 case VSI_NN_TYPE_BOOL8: ret +=
" 8B";
break;
197 case VSI_NN_TYPE_UINT16: ret +=
" 16U";
break;
198 case VSI_NN_TYPE_INT16: ret +=
" 16S";
break;
199 case VSI_NN_TYPE_FLOAT16: ret +=
" 16F";
break;
200 case VSI_NN_TYPE_BFLOAT16: ret +=
" 16B";
break;
201 case VSI_NN_TYPE_UINT32: ret +=
" 32U";
break;
202 case VSI_NN_TYPE_INT32: ret +=
" 32S";
break;
203 case VSI_NN_TYPE_FLOAT32: ret +=
" 32F";
break;
204 case VSI_NN_TYPE_UINT64: ret +=
" 64U";
break;
205 case VSI_NN_TYPE_INT64: ret +=
" 64S";
break;
206 case VSI_NN_TYPE_FLOAT64: ret +=
" 64F";
break;
207 default:
throw std::range_error(
"shapestr: Unsupported tensor type " + std::to_string(attr.dtype.vx_type));
217 std::ostringstream os;
218 std::vector<int64_t> input_node_dims = ti.GetShape();
219 os << input_node_dims.size() <<
"D ";
220 for (int64_t d : input_node_dims) os << d <<
'x';
221 os.seekp(-1, os.cur);
223 switch (ti.GetElementType())
225 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED: os <<
" UNDEFINED";
break;
226 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: os <<
" 32F";
break;
227 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: os <<
" 8U";
break;
228 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: os <<
" 8S";
break;
229 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16: os <<
" 16U";
break;
230 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16: os <<
" 16S";
break;
231 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: os <<
" 32S";
break;
232 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: os <<
" 64S";
break;
233 case ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING: os <<
" STR";
break;
234 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: os <<
" BOOL";
break;
235 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: os <<
" 16F";
break;
236 case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE: os <<
" 64F";
break;
237 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32: os <<
" 32U";
break;
238 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64: os <<
" 64U";
break;
239 case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64: os <<
" 64CPLX";
break;
240 case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128: os <<
" 128CPLX";
break;
241 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: os <<
" 16B";
break;
242 default:
throw std::range_error(
"shapestr: Unsupported tensor type " + std::to_string(ti.GetElementType()));
253 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED:
return VSI_NN_TYPE_NONE;
254 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT:
return VSI_NN_TYPE_FLOAT32;
255 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8:
return VSI_NN_TYPE_UINT8;
256 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8:
return VSI_NN_TYPE_INT8;
257 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16:
return VSI_NN_TYPE_UINT16;
258 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16:
return VSI_NN_TYPE_INT16;
259 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32:
return VSI_NN_TYPE_INT32;
260 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64:
return VSI_NN_TYPE_INT64;
261 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL:
return VSI_NN_TYPE_BOOL8;
262 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16:
return VSI_NN_TYPE_FLOAT16;
263 case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE:
return VSI_NN_TYPE_FLOAT64;
264 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32:
return VSI_NN_TYPE_UINT32;
265 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64:
return VSI_NN_TYPE_UINT64;
266 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
return VSI_NN_TYPE_BFLOAT16;
270 default:
throw std::range_error(
"onnx2vsi: Unsupported tensor type " + std::to_string(t));
277 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
278 attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
281 std::vector<int64_t>
const dims = ti.GetShape();
282 size_t const ds = dims.size();
284 for (
size_t i = 0; i < ds; ++i) attr.size[ds - 1 - i] = dims[i];
287 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_NONE;
320 std::vector<size_t> ret;
322 for (std::string
const & t : tok) ret.emplace_back(std::stoi(t));
331 case kTfLiteFloat32:
return CV_32F;
332 case kTfLiteInt32:
return CV_32S;
333 case kTfLiteUInt8:
return CV_8U;
334 case kTfLiteInt16:
return CV_16S;
335 case kTfLiteInt8:
return CV_8S;
336 case kTfLiteFloat16:
return CV_16F;
337 case kTfLiteFloat64:
return CV_64F;
344 default:
throw std::range_error(std::string(
"tf2cv: Unsupported type ") + TfLiteTypeGetName(t));
353 case VSI_NN_TYPE_UINT8:
return CV_8U;
354 case VSI_NN_TYPE_INT8:
return CV_8S;
355 case VSI_NN_TYPE_BOOL8:
return CV_8U;
356 case VSI_NN_TYPE_UINT16:
return CV_16U;
357 case VSI_NN_TYPE_INT16:
return CV_16S;
358 case VSI_NN_TYPE_FLOAT16:
return CV_16F;
361 case VSI_NN_TYPE_INT32:
return CV_32S;
362 case VSI_NN_TYPE_FLOAT32:
return CV_32F;
365 case VSI_NN_TYPE_FLOAT64:
return CV_64F;
366 default:
throw std::range_error(
"vsi2cv: Unsupported tensor type " + std::to_string(t));
375 case kTfLiteFloat32:
return VSI_NN_TYPE_FLOAT32;
376 case kTfLiteInt32:
return VSI_NN_TYPE_INT32;
377 case kTfLiteUInt8:
return VSI_NN_TYPE_UINT8;
378 case kTfLiteInt16:
return VSI_NN_TYPE_INT16;
379 case kTfLiteInt8:
return VSI_NN_TYPE_INT8;
380 case kTfLiteFloat16:
return VSI_NN_TYPE_FLOAT16;
381 case kTfLiteFloat64:
return VSI_NN_TYPE_FLOAT64;
382 case kTfLiteInt64:
return VSI_NN_TYPE_INT64;
383 case kTfLiteBool:
return VSI_NN_TYPE_BOOL8;
384 case kTfLiteNoType:
return VSI_NN_TYPE_NONE;
388 default:
throw std::range_error(std::string(
"tf2vsi: Unsupported type ") + TfLiteTypeGetName(t));
398 case HAILO_FORMAT_TYPE_AUTO:
return VSI_NN_TYPE_NONE;
break;
399 case HAILO_FORMAT_TYPE_UINT8:
return VSI_NN_TYPE_UINT8;
break;
400 case HAILO_FORMAT_TYPE_UINT16:
return VSI_NN_TYPE_UINT16;
break;
401 case HAILO_FORMAT_TYPE_FLOAT32:
return VSI_NN_TYPE_FLOAT32;
break;
402 default:
throw std::range_error(
"hailo2vsi: Unsupported tensor type " + std::to_string(t));
410 int tx = std::min(width - 1, std::max(0, r.x));
411 int ty = std::min(height - 1, std::max(0, r.y));
412 int bx = std::min(width - 1, std::max(0, r.x + r.width));
413 int by = std::min(height - 1, std::max(0, r.y + r.height));
414 r.x = tx; r.y = ty; r.width = bx - tx; r.height = by - ty;
420 float tx = std::min(width - 1.0F, std::max(0.0F, r.x));
421 float ty = std::min(height - 1.0F, std::max(0.0F, r.y));
422 float bx = std::min(width - 1.0F, std::max(0.0F, r.x + r.width));
423 float by = std::min(height - 1.0F, std::max(0.0F, r.y + r.height));
424 r.x = tx; r.y = ty; r.width = bx - tx; r.height = by - ty;
430 char const *
const specdef =
"[NCHW:|NHWC:|NA:|AUTO:]Type:[NxCxHxW|NxHxWxC|...][:QNT[:fl|:scale:zero]]";
431 std::vector<std::string> spectok =
jevois::split(specs,
",\\s*");
432 std::vector<vsi_nn_tensor_attr_t> ret;
434 for (std::string
const & spec : spectok)
436 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
440 if (tok.size() < 2)
throw std::runtime_error(
"parseTensorSpecs: Malformed tensor spec ["+spec+
"] not "+specdef);
444 if (tok[0] ==
"NCHW") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_NCHW; }
445 else if (tok[0] ==
"NHWC") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC; }
446 else if (tok[0] ==
"NA") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_NA; }
447 else if (tok[0] ==
"AUTO") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO; }
448 else attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
451 if (tok.size() < n+2)
throw std::runtime_error(
"parseTensorSpecs: Malformed tensor spec ["+spec+
"] not "+specdef);
454 if (tok[n] ==
"8U") attr.dtype.vx_type = VSI_NN_TYPE_UINT8;
455 else if (tok[n] ==
"8S") attr.dtype.vx_type = VSI_NN_TYPE_INT8;
456 else if (tok[n] ==
"8B") attr.dtype.vx_type = VSI_NN_TYPE_BOOL8;
457 else if (tok[n] ==
"16U") attr.dtype.vx_type = VSI_NN_TYPE_UINT16;
458 else if (tok[n] ==
"16S") attr.dtype.vx_type = VSI_NN_TYPE_INT16;
459 else if (tok[n] ==
"16F") attr.dtype.vx_type = VSI_NN_TYPE_FLOAT16;
460 else if (tok[n] ==
"16B") attr.dtype.vx_type = VSI_NN_TYPE_BFLOAT16;
461 else if (tok[n] ==
"32U") attr.dtype.vx_type = VSI_NN_TYPE_UINT32;
462 else if (tok[n] ==
"32S") attr.dtype.vx_type = VSI_NN_TYPE_INT32;
463 else if (tok[n] ==
"32F") attr.dtype.vx_type = VSI_NN_TYPE_FLOAT32;
464 else if (tok[n] ==
"64U") attr.dtype.vx_type = VSI_NN_TYPE_UINT64;
465 else if (tok[n] ==
"64S") attr.dtype.vx_type = VSI_NN_TYPE_INT64;
466 else if (tok[n] ==
"64F") attr.dtype.vx_type = VSI_NN_TYPE_FLOAT64;
467 else throw std::range_error(
"parseTensorSpecs: Invalid tensor type [" + tok[n] +
"] in " + spec);
472 attr.dim_num = dims.size();
473 for (
size_t i = 0; i < attr.dim_num; ++i) attr.size[attr.dim_num - 1 - i] = dims[i];
477 if (n == tok.size() || tok[n] ==
"NONE")
479 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_NONE;
481 else if (tok[n] ==
"DFP")
483 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_DFP;
484 if (tok.size() != n+2)
485 throw std::range_error(
"parseTensorSpecs: In "+spec+
", DFP quantization needs :fl (" + specdef +
')');
486 attr.dtype.fl = std::stoi(tok[n+1]);
489 else if (tok[n] ==
"AA" || tok[n] ==
"AS")
491 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC;
492 if (tok.size() != n+3)
493 throw std::range_error(
"parseTensorSpecs: In "+spec+
", AA/AS quantization needs :scale:zero ("+specdef+
')');
494 attr.dtype.scale = std::stof(tok[n+1]);
495 attr.dtype.zero_point = std::stoi(tok[n+2]);
497 else if (tok[n] ==
"APS")
499 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC;
500 throw std::range_error(
"parseTensorSpecs: In " + spec +
", AFFINE_PERCHANNEL_SYMMETRIC quant not yet supported");
502 else throw std::range_error(
"parseTensorSpecs: Invalid quantization type in " + spec);
505 ret.emplace_back(attr);
521 size_t const ndim = attr.dim_num;
522 std::vector<int> cvdims(ndim);
523 for (
size_t i = 0; i < ndim; ++i) cvdims[ndim - 1 - i] = attr.size[i];
530 switch (attr.dtype.fmt)
532 case VSI_NN_DIM_FMT_NHWC:
533 if (attr.dim_num < 3)
throw std::range_error(
"attrsize: need at least 3D, got " +
jevois::dnn::attrstr(attr));
534 return cv::Size(attr.size[1], attr.size[2]);
536 case VSI_NN_DIM_FMT_NCHW:
537 if (attr.dim_num < 2)
throw std::range_error(
"attrsize: need at least 2D, got " +
jevois::dnn::attrstr(attr));
538 return cv::Size(attr.size[0], attr.size[1]);
540 case VSI_NN_DIM_FMT_AUTO:
541 if (attr.dim_num < 2)
return cv::Size(attr.size[0], 1);
542 if (attr.dim_num < 3)
return cv::Size(attr.size[0], attr.size[1]);
544 if (attr.size[0] > attr.size[2])
return cv::Size(attr.size[0], attr.size[1]);
545 else return cv::Size(attr.size[1], attr.size[2]);
548 throw std::range_error(
"attrsize: cannot extract width and height, got " +
jevois::dnn::attrstr(attr));
558 if (attr.dim_num > 2)
559 switch (attr.dtype.fmt)
561 case VSI_NN_DIM_FMT_NCHW: ret =
"NCHW:";
break;
562 case VSI_NN_DIM_FMT_NHWC: ret =
"NHWC:";
break;
567 switch (attr.dtype.vx_type)
569 case VSI_NN_TYPE_UINT8: ret +=
"8U:";
break;
570 case VSI_NN_TYPE_INT8: ret +=
"8S:";
break;
571 case VSI_NN_TYPE_BOOL8: ret +=
"8B:";
break;
572 case VSI_NN_TYPE_UINT16: ret +=
"16U:";
break;
573 case VSI_NN_TYPE_INT16: ret +=
"16S:";
break;
574 case VSI_NN_TYPE_FLOAT16: ret +=
"16F:";
break;
575 case VSI_NN_TYPE_BFLOAT16: ret +=
"16B:";
break;
576 case VSI_NN_TYPE_UINT32: ret +=
"32U:";
break;
577 case VSI_NN_TYPE_INT32: ret +=
"32S:";
break;
578 case VSI_NN_TYPE_FLOAT32: ret +=
"32F:";
break;
579 case VSI_NN_TYPE_UINT64: ret +=
"64U:";
break;
580 case VSI_NN_TYPE_INT64: ret +=
"64S:";
break;
581 case VSI_NN_TYPE_FLOAT64: ret +=
"64F:";
break;
582 default: ret +=
"TYPE_UNKNOWN:";
586 for (uint32_t i = 0; i < attr.dim_num; ++i)
587 ret += std::to_string(attr.size[attr.dim_num - 1 - i]) + ((i<attr.dim_num-1) ?
'x' :
':');
590 switch (attr.dtype.qnt_type)
592 case VSI_NN_QNT_TYPE_NONE: ret +=
"NONE";
break;
593 case VSI_NN_QNT_TYPE_DFP: ret +=
"DFP:" + std::to_string(attr.dtype.fl);
break;
594 case VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC:
595 ret +=
"AA:" + std::to_string(attr.dtype.scale) +
':' + std::to_string(attr.dtype.zero_point);
597 case VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC: ret +=
"APS:unsupported";
break;
598 default: ret +=
"QUANT_UNKNOWN";
607 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
608 attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
611 switch (t->quantization.type)
613 case kTfLiteNoQuantization:
614 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_NONE;
617 case kTfLiteAffineQuantization:
619 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC;
620 attr.dtype.scale = t->params.scale;
621 attr.dtype.zero_point = t->params.zero_point;
625 default:
LFATAL(
"unsupported quantization " << t->quantization.type);
628 TfLiteIntArray
const & dims = *t->dims;
629 attr.dim_num = dims.size;
630 for (
int i = 0; i < dims.size; ++i) attr.size[dims.size - 1 - i] = dims.data[i];
633 if (attr.dim_num == 4)
635 if (attr.size[0] > attr.size[2]) attr.dtype.fmt = VSI_NN_DIM_FMT_NCHW;
636 else attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
646 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
648 attr.dtype.vx_type =
hailo2vsi(vi.format.type);
650 switch (vi.format.order)
652 case HAILO_FORMAT_ORDER_HAILO_NMS:
653 attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
655 attr.size[0] = vi.nms_shape.number_of_classes;
656 attr.size[1] = vi.nms_shape.max_bboxes_per_class * 5;
659 case HAILO_FORMAT_ORDER_NHWC:
660 case HAILO_FORMAT_ORDER_FCR:
661 case HAILO_FORMAT_ORDER_F8CR:
662 attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
664 attr.size[0] = vi.shape.features;
665 attr.size[1] = vi.shape.width;
666 attr.size[2] = vi.shape.height;
670 case HAILO_FORMAT_ORDER_NHW:
671 attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
674 attr.size[1] = vi.shape.width;
675 attr.size[2] = vi.shape.height;
679 case HAILO_FORMAT_ORDER_NC:
680 attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
684 attr.size[2] = vi.shape.features;
688 case HAILO_FORMAT_ORDER_NCHW:
689 attr.dtype.fmt = VSI_NN_DIM_FMT_NCHW;
691 attr.size[0] = vi.shape.features;
692 attr.size[1] = vi.shape.width;
693 attr.size[2] = vi.shape.height;
697 default:
throw std::range_error(
"tensorattr: Unsupported Hailo order " +std::to_string(vi.format.order));
701 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC;
702 attr.dtype.scale = vi.quant_info.qp_scale;
703 attr.dtype.zero_point = int32_t(vi.quant_info.qp_zp);
712 struct ParallelSigmoid :
public cv::ParallelLoopBody
714 ParallelSigmoid(
float * ptr) : p(ptr)
717 virtual void operator()(cv::Range
const & r)
const
727 if (m.type() != CV_32F)
LFATAL(
"Can only apply to CV_32F tensors");
729 cv::parallel_for_(cv::Range(0, m.total()), ParallelSigmoid((
float *)m.data));
733size_t jevois::dnn::softmax(
float const * input,
size_t const n,
size_t const stride,
float const fac,
float * output,
736 if (stride == 0)
LFATAL(
"Cannot work with stride = 0");
739 float largest = -FLT_MAX;
size_t largest_idx = 0;
740 size_t const ns = n * stride;
742 for (
size_t i = 0; i < ns; i += stride)
if (input[i] > largest) { largest = input[i]; largest_idx = i; }
745 for (
size_t i = 0; i < ns; i += stride)
752 for (
size_t i = 0; i < ns; i += stride)
761 if (maxonly) output[largest_idx] /= sum;
762 else for (
size_t i = 0; i < ns; i += stride) output[i] /= sum;
772 size_t const ns = n * stride;
774 float alpha = -FLT_MAX;
775 for (
size_t c = 0; c < ns; c += stride)
777 float score = src[c];
778 if (score > alpha) alpha = score;
781 float denominator = 0;
785 for (
size_t i = 0; i < ns; i += stride)
788 denominator += *dp++;
791 if (denominator == 0.0F)
return 0.0F;
793 for (
size_t i = 0; i < n; ++i)
795 dst[i] /= denominator;
796 dis_sum += i * dst[i];
805 if (blob.channels() != 1)
return false;
807 if (uint32_t(blob.size.dims()) != attr.dim_num)
return false;
809 for (
size_t i = 0; i < attr.dim_num; ++i)
810 if (
int(attr.size[attr.dim_num - 1 - i]) != blob.size[i])
return false;
818 if (m.depth() != CV_32F)
LFATAL(
"Tensor to quantize must be 32F");
822 size_t tot = 1;
for (
int d : adims) tot *= d;
824 if (tot != m.total() * m.channels())
829 switch (attr.dtype.qnt_type)
831 case VSI_NN_QNT_TYPE_NONE:
834 m.convertTo(ret, tt);
838 case VSI_NN_QNT_TYPE_DFP:
844 if (attr.dtype.fl > 7)
LFATAL(
"Invalid DFP fl value " << attr.dtype.fl <<
": must be in [0..7]");
846 m.convertTo(ret, tt, 1 << attr.dtype.fl, 0.0);
851 if (attr.dtype.fl > 15)
LFATAL(
"Invalid DFP fl value " << attr.dtype.fl <<
": must be in [0..15]");
853 m.convertTo(ret, tt, 1 << attr.dtype.fl, 0.0);
861 case VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC:
869 m.convertTo(ret, tt, 1.0 / attr.dtype.scale, attr.dtype.zero_point);
878 case VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC:
879 LFATAL(
"Affine per-channel symmetric not supported yet");
893 switch (attr.dtype.qnt_type)
895 case VSI_NN_QNT_TYPE_NONE:
898 m.convertTo(ret, CV_32F);
902 case VSI_NN_QNT_TYPE_DFP:
905 m.convertTo(ret, CV_32F, 1.0 / (1 << attr.dtype.fl), 0.0);
909 case VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC:
912 double const alpha = attr.dtype.scale;
913 double const beta = - alpha * attr.dtype.zero_point;
914 m.convertTo(ret, CV_32F, alpha, beta);
918 case VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC:
919 LFATAL(
"Affine per-channel symmetric not supported yet");
922 LFATAL(
"Unknown quantization type " <<
int(attr.dtype.qnt_type));
929 cv::MatSize
const & rs = m.size;
930 size_t const ndims = rs.dims();
932 for (
size_t i = 0; i < ndims; ++i)
if (rs[i] == 1) --ret;
else break;
939 if (tensors.empty())
return cv::Mat();
940 if (tensors.size() == 1)
return tensors[0];
942 cv::MatSize
const & ms = tensors[0].size;
943 int const ndims = ms.dims();
944 auto const typ = tensors[0].type();
947 if (axis < - ndims || axis >= ndims)
948 LFATAL(
"Incorrect axis " << axis <<
": must be in [" << -ndims <<
" ... " << ndims - 1 <<
']');
949 if (axis < 0) axis = ndims - axis;
952 size_t newsize = tensors[0].size[axis];
954 for (
size_t i = 1; i < tensors.size(); ++i)
956 if (tensors[i].type() != typ)
960 if (tensors[i].size.dims() != ndims)
961 LFATAL(
"Mismatched number of dimensions: " << ndims <<
" for tensors[0] vs. " <<
962 tensors[i].size.dims() <<
" for tensors[" << i <<
']');
964 newsize += tensors[i].size[axis];
968 for (
int a = 0; a < ndims; ++a)
970 for (
size_t i = 1; i < tensors.size(); ++i)
971 if (tensors[i].size[a] != ms[a])
972 LFATAL(
"Mismatched size for axis " << a <<
": tensors[0] has " << ms[a] <<
" while tensors[" <<
973 i <<
"] has " << tensors[i].size[a]);
976 int newdims[ndims];
for (
int i = 0; i < ndims; ++i) newdims[i] = ms.p[i];
977 newdims[axis] = newsize;
978 cv::Mat ret(ndims, newdims, typ);
979 unsigned char * optr = ret.data;
981 size_t numcopy = 1;
for (
int a = 0; a < axis; ++a) numcopy *= ms[a];
982 size_t elemsize =
jevois::cvBytesPerPix(typ);
for (
int a = axis + 1; a < ndims; ++a) elemsize *= ms[a];
984 for (
size_t n = 0; n < numcopy; ++n)
985 for (
size_t i = 0; i < tensors.size(); ++i)
987 size_t const axsize = tensors[i].size[axis];
988 unsigned char const * sptr = tensors[i].data + n * elemsize * axsize;
989 std::memcpy(optr, sptr, elemsize * axsize);
990 optr += elemsize * axsize;
997std::vector<cv::Mat>
jevois::dnn::split(cv::Mat
const & tensor,
int axis, std::vector<int>
const & sizes)
999 cv::MatSize
const & ms = tensor.size;
1000 int const ndims = ms.dims();
1001 auto const typ = tensor.type();
1002 int const nsplit = sizes.size();
1005 if (axis < - ndims || axis >= ndims)
1006 LFATAL(
"Incorrect axis " << axis <<
": must be in [" << -ndims <<
" ... " << ndims - 1 <<
1008 if (axis < 0) axis = ndims - axis;
1011 std::vector<cv::Mat> ret;
1012 if (nsplit == 0)
return ret;
1015 if (sizes[0] == ms[axis]) { ret.emplace_back(tensor);
return ret; }
1016 else LFATAL(
"Desired new size " << sizes[0] <<
" for axis " << axis <<
" with only one output tensor must match "
1021 unsigned char * optr[nsplit];
size_t copysize[nsplit];
1023 size_t numcopy = 1;
for (
int a = 0; a < axis; ++a) numcopy *= ms[a];
1024 size_t elemsize =
jevois::cvBytesPerPix(typ);
for (
int a = axis + 1; a < ndims; ++a) elemsize *= ms[a];
1027 int newdims[ndims];
for (
int i = 0; i < ndims; ++i) newdims[i] = ms.p[i];
1030 for (
int i = 0; i < nsplit; ++i)
1032 int const s = sizes[i];
1033 newdims[axis] = s; ret.emplace_back(cv::Mat(ndims, newdims, typ));
1034 optr[i] = ret.back().data;
1035 copysize[i] = s * elemsize;
1039 if (sum != ms[axis])
1040 LFATAL(
"Given sizes [" <<
jevois::join(sizes,
", ") <<
"] do not add up to original size of axis " <<
1044 unsigned char const * sptr = tensor.data;
1045 for (
size_t n = 0; n < numcopy; ++n)
1046 for (
int j = 0; j < nsplit; ++j)
1048 size_t const cs = copysize[j];
1049 std::memcpy(optr[j], sptr, cs);
1050 sptr += cs; optr[j] += cs;
#define JEVOIS_SHARE_PATH
Base path for shared files (e.g., neural network weights, etc)
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
float fastexp(float x)
Compute fast exponential using approximation formula.
int tf2cv(TfLiteType t)
Convert from TensorFlow data type to OpenCV.
std::map< int, std::string > getClassLabels(std::string const &arg)
Get class labels from either a list or a file.
int vsi2cv(vsi_nn_type_e t)
Convert from NPU data type to OpenCV.
size_t softmax(float const *input, size_t const n, size_t const stride, float const fac, float *output, bool maxonly)
Apply softmax to a float vector.
vsi_nn_tensor_attr_t tensorattr(TfLiteTensor const *t)
Get tensor shape and type attributes for a TensorFlow Lite tensor.
std::string getLabel(std::map< int, std::string > const &labels, int id, bool namedonly=false)
Get a label from an id.
cv::Mat quantize(cv::Mat const &m, vsi_nn_tensor_attr_t const &attr)
Quantize from float32 to fixed-point according to the quantization spec in attr.
std::map< int, std::string > readLabelsFile(std::string const &fname)
Read a label file.
float sigmoid(float x)
Compute sigmoid using fastexp.
vsi_nn_type_e onnx2vsi(ONNXTensorElementDataType t)
Convert from ONNX-Runtime data type to vsi_nn.
std::vector< cv::Mat > split(cv::Mat const &tensor, int axis, std::vector< int > const &sizes)
Split a tensor into several, along a given axis.
std::vector< vsi_nn_tensor_attr_t > parseTensorSpecs(std::string const &specs)
Parse tensor specification.
void clamp(cv::Rect &r, int width, int height)
Clamp a rectangle to within given image width and height.
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...
float softmax_dfl(float const *src, float *dst, size_t const n, size_t const stride=1)
Compute softmax and return DFL distance.
cv::Mat attrmat(vsi_nn_tensor_attr_t const &attr, void *dataptr=nullptr)
Construct a cv::Mat from attr and possibly data pointer.
size_t effectiveDims(cv::Mat const &m)
Returns the number of non-unit dims in a cv::Mat.
vsi_nn_type_e hailo2vsi(hailo_format_type_t t)
Convert from Hailo data type to vsi_nn.
cv::Mat concatenate(std::vector< cv::Mat > const &tensors, int axis)
Concatenate several tensors into one.
int stringToRGBA(std::string const &label, unsigned char alpha=128)
Compute a color from a label name.
cv::Size attrsize(vsi_nn_tensor_attr_t const &attr)
Get a tensor's (width, height) size in cv::Size format, skipping over other dimensions.
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.
vsi_nn_type_e tf2vsi(TfLiteType t)
Convert from TensorFlow data type to vsi_nn.
void topK(float const *pfProb, float *pfMaxProb, uint32_t *pMaxClass, uint32_t outputCount, uint32_t topNum)
Get top-k entries and their indices.
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.
std::vector< int > attrdims(vsi_nn_tensor_attr_t const &attr)
Get a tensor dims as a vector of int, useful to construct a matching cv::Mat.
std::vector< size_t > strshape(std::string const &str)
Get a vector of size_t from a string containing AxBxC...
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.
unsigned int cvBytesPerPix(unsigned int cvtype)
Return the number of bytes per pixel for a given OpenCV pixel type.
std::string cvtypestr(unsigned int cvtype)
Convert cv::Mat::type() code to to a string (e.g., CV_8UC1, CV_32SC3, etc)
std::string join(std::vector< T > const &tokens, std::string const &delimiter)
Concatenate a vector of tokens into a string.
size_t replaceStringAll(std::string &str, std::string const &from, std::string const &to)
Replace all instances of 'from' with 'to'.
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...