27 std::ifstream ifs(fname);
28 if (ifs.is_open() ==
false)
LFATAL(
"Failed to open file " << fname);
30 size_t linenum = 1; std::map<int, std::string> ret;
int id = 0;
31 for (std::string line; std::getline(ifs, line); ++linenum)
33 size_t idx1 = line.find_first_not_of(
" \t");
if (idx1 == line.npos)
continue;
34 size_t idx2 = line.find_last_not_of(
" \t\r\n");
if (idx2 == line.npos)
continue;
35 if (line[idx1] ==
'#')
continue;
37 try {
id = std::stoi(line, &idx1); idx1 = line.find_first_not_of(
"0123456789 \t,:", idx1); }
catch (...) { }
39 std::string classname;
42 LERROR(fname <<
':' << linenum <<
": empty class name -- REPLACING BY 'unspecified'");
43 classname =
"unspecified";
45 else classname = line.substr(idx1, idx2 + 1 - idx1);
51 size_t len = classname.length();
52 if (len > 1 && classname[0] ==
'"' && classname[len-1] ==
'"') classname = classname.substr(1, len-2);
62 LINFO(
"Loaded " << ret.size() <<
" class names from " << fname);
70 auto itr = labels.find(
id);
71 if (itr == labels.end())
73 if (namedonly)
return std::string();
74 else return std::to_string(
id);
83 for (
char const c : label) col = c + ((col << 5) - col);
84 col = (col & 0xffffff) | (alpha << 24);
89void jevois::dnn::topK(
float const * pfProb,
float * pfMaxProb, uint32_t * pMaxClass, uint32_t outputCount,
92 memset(pfMaxProb, 0xfe,
sizeof(
float) * topNum);
93 memset(pMaxClass, 0xff,
sizeof(
float) * topNum);
95 for (uint32_t j = 0; j < topNum; ++j)
97 for (uint32_t i = 0; i < outputCount; ++i)
100 for (k = 0; k < topNum; ++k)
if (i == pMaxClass[k])
break;
101 if (k != topNum)
continue;
103 if (pfProb[i] > pfMaxProb[j]) { pfMaxProb[j] = pfProb[i]; pMaxClass[j] = i; }
111 cv::MatSize
const & ms = m.size;
int const nd = ms.dims();
112 std::string ret = std::to_string(nd) +
"D ";
113 for (
int i = 0; i < nd; ++i) ret += std::to_string(ms[i]) + (i < nd-1 ?
"x" :
"");
121 int const nd = int(dims.size());
122 std::string ret = std::to_string(nd) +
"D ";
123 for (
int i = 0; i < nd; ++i) ret += std::to_string(dims[i]) + (i < nd-1 ?
"x" :
"");
131 int const nd = int(dims.size());
132 std::string ret = std::to_string(nd) +
"D ";
133 for (
int i = 0; i < nd; ++i) ret += std::to_string(dims[i]) + (i < nd-1 ?
"x" :
"");
142 TfLiteIntArray
const & dims = *t->dims;
143 std::string ret = std::to_string(dims.size) +
"D ";
144 for (
int i = 0; i < dims.size; ++i) ret += std::to_string(dims.data[i]) + (i < dims.size-1 ?
"x" :
"");
149 case kTfLiteNoType: ret +=
" NoType";
break;
150 case kTfLiteFloat32: ret +=
" 32F";
break;
151 case kTfLiteInt32: ret +=
" 32S";
break;
152 case kTfLiteUInt8: ret +=
" 8U";
break;
153 case kTfLiteInt64: ret +=
" 64S";
break;
154 case kTfLiteString: ret +=
" String";
break;
155 case kTfLiteBool: ret +=
" 8B";
break;
156 case kTfLiteInt16: ret +=
" 16S";
break;
157 case kTfLiteComplex64: ret +=
" 64C";
break;
158 case kTfLiteInt8: ret +=
" 8I";
break;
159 case kTfLiteFloat16: ret +=
" 16F";
break;
160 case kTfLiteFloat64: ret +=
" 64F";
break;
161 case kTfLiteComplex128: ret +=
" 128C";
break;
162 default: ret +=
" UnknownType";
break;
170 std::string ret = std::to_string(attr.dim_num) +
"D ";
171 for (uint32_t i = 0; i < attr.dim_num; ++i)
172 ret += std::to_string(attr.size[attr.dim_num-1-i]) + (i < attr.dim_num-1 ?
"x" :
"");
175 switch (attr.dtype.vx_type)
177 case VSI_NN_TYPE_UINT8: ret +=
" 8U";
break;
178 case VSI_NN_TYPE_INT8: ret +=
" 8S";
break;
179 case VSI_NN_TYPE_BOOL8: ret +=
" 8B";
break;
180 case VSI_NN_TYPE_UINT16: ret +=
" 16U";
break;
181 case VSI_NN_TYPE_INT16: ret +=
" 16S";
break;
182 case VSI_NN_TYPE_FLOAT16: ret +=
" 16F";
break;
183 case VSI_NN_TYPE_BFLOAT16: ret +=
" 16B";
break;
184 case VSI_NN_TYPE_UINT32: ret +=
" 32U";
break;
185 case VSI_NN_TYPE_INT32: ret +=
" 32S";
break;
186 case VSI_NN_TYPE_FLOAT32: ret +=
" 32F";
break;
187 case VSI_NN_TYPE_UINT64: ret +=
" 64U";
break;
188 case VSI_NN_TYPE_INT64: ret +=
" 64S";
break;
189 case VSI_NN_TYPE_FLOAT64: ret +=
" 64F";
break;
190 default:
throw std::range_error(
"shapestr: Unsupported tensor type " + std::to_string(attr.dtype.vx_type));
200 std::ostringstream os;
201 std::vector<int64_t> input_node_dims = ti.GetShape();
202 os << input_node_dims.size() <<
"D ";
203 for (int64_t d : input_node_dims) os << d <<
'x';
204 os.seekp(-1, os.cur);
206 switch (ti.GetElementType())
208 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED: os <<
" UNDEFINED";
break;
209 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: os <<
" 32F";
break;
210 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: os <<
" 8U";
break;
211 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: os <<
" 8S";
break;
212 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16: os <<
" 16U";
break;
213 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16: os <<
" 16S";
break;
214 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: os <<
" 32S";
break;
215 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: os <<
" 64S";
break;
216 case ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING: os <<
" STR";
break;
217 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: os <<
" BOOL";
break;
218 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: os <<
" 16F";
break;
219 case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE: os <<
" 64F";
break;
220 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32: os <<
" 32U";
break;
221 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64: os <<
" 64U";
break;
222 case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64: os <<
" 64CPLX";
break;
223 case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128: os <<
" 128CPLX";
break;
224 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: os <<
" 16B";
break;
225 default:
throw std::range_error(
"shapestr: Unsupported tensor type " + std::to_string(ti.GetElementType()));
236 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED:
return VSI_NN_TYPE_NONE;
237 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT:
return VSI_NN_TYPE_FLOAT32;
238 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8:
return VSI_NN_TYPE_UINT8;
239 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8:
return VSI_NN_TYPE_INT8;
240 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16:
return VSI_NN_TYPE_UINT16;
241 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16:
return VSI_NN_TYPE_INT16;
242 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32:
return VSI_NN_TYPE_INT32;
243 case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64:
return VSI_NN_TYPE_INT64;
244 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL:
return VSI_NN_TYPE_BOOL8;
245 case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16:
return VSI_NN_TYPE_FLOAT16;
246 case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE:
return VSI_NN_TYPE_FLOAT64;
247 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32:
return VSI_NN_TYPE_UINT32;
248 case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64:
return VSI_NN_TYPE_UINT64;
249 case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
return VSI_NN_TYPE_BFLOAT16;
253 default:
throw std::range_error(
"onnx2vsi: Unsupported tensor type " + std::to_string(t));
260 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
261 attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
264 std::vector<int64_t>
const dims = ti.GetShape();
265 size_t const ds = dims.size();
267 for (
size_t i = 0; i < ds; ++i) attr.size[ds - 1 - i] = dims[i];
270 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_NONE;
303 std::vector<size_t> ret;
305 for (std::string
const & t : tok) ret.emplace_back(std::stoi(t));
314 case kTfLiteFloat32:
return CV_32F;
315 case kTfLiteInt32:
return CV_32S;
316 case kTfLiteUInt8:
return CV_8U;
317 case kTfLiteInt16:
return CV_16S;
318 case kTfLiteInt8:
return CV_8S;
319 case kTfLiteFloat16:
return CV_16F;
320 case kTfLiteFloat64:
return CV_64F;
327 default:
throw std::range_error(std::string(
"tf2cv: Unsupported type ") + TfLiteTypeGetName(t));
336 case VSI_NN_TYPE_UINT8:
return CV_8U;
337 case VSI_NN_TYPE_INT8:
return CV_8S;
338 case VSI_NN_TYPE_BOOL8:
return CV_8U;
339 case VSI_NN_TYPE_UINT16:
return CV_16U;
340 case VSI_NN_TYPE_INT16:
return CV_16S;
341 case VSI_NN_TYPE_FLOAT16:
return CV_16F;
344 case VSI_NN_TYPE_INT32:
return CV_32S;
345 case VSI_NN_TYPE_FLOAT32:
return CV_32F;
348 case VSI_NN_TYPE_FLOAT64:
return CV_64F;
349 default:
throw std::range_error(
"vsi2cv: Unsupported tensor type " + std::to_string(t));
358 case kTfLiteFloat32:
return VSI_NN_TYPE_FLOAT32;
359 case kTfLiteInt32:
return VSI_NN_TYPE_INT32;
360 case kTfLiteUInt8:
return VSI_NN_TYPE_UINT8;
361 case kTfLiteInt16:
return VSI_NN_TYPE_INT16;
362 case kTfLiteInt8:
return VSI_NN_TYPE_INT8;
363 case kTfLiteFloat16:
return VSI_NN_TYPE_FLOAT16;
364 case kTfLiteFloat64:
return VSI_NN_TYPE_FLOAT64;
365 case kTfLiteInt64:
return VSI_NN_TYPE_INT64;
366 case kTfLiteBool:
return VSI_NN_TYPE_BOOL8;
367 case kTfLiteNoType:
return VSI_NN_TYPE_NONE;
371 default:
throw std::range_error(std::string(
"tf2vsi: Unsupported type ") + TfLiteTypeGetName(t));
381 case HAILO_FORMAT_TYPE_AUTO:
return VSI_NN_TYPE_NONE;
break;
382 case HAILO_FORMAT_TYPE_UINT8:
return VSI_NN_TYPE_UINT8;
break;
383 case HAILO_FORMAT_TYPE_UINT16:
return VSI_NN_TYPE_UINT16;
break;
384 case HAILO_FORMAT_TYPE_FLOAT32:
return VSI_NN_TYPE_FLOAT32;
break;
385 default:
throw std::range_error(
"hailo2vsi: Unsupported tensor type " + std::to_string(t));
393 int tx = std::min(width - 1, std::max(0, r.x));
394 int ty = std::min(height - 1, std::max(0, r.y));
395 int bx = std::min(width - 1, std::max(0, r.x + r.width));
396 int by = std::min(height - 1, std::max(0, r.y + r.height));
397 r.x = tx; r.y = ty; r.width = bx - tx; r.height = by - ty;
403 float tx = std::min(width - 1.0F, std::max(0.0F, r.x));
404 float ty = std::min(height - 1.0F, std::max(0.0F, r.y));
405 float bx = std::min(width - 1.0F, std::max(0.0F, r.x + r.width));
406 float by = std::min(height - 1.0F, std::max(0.0F, r.y + r.height));
407 r.x = tx; r.y = ty; r.width = bx - tx; r.height = by - ty;
413 char const *
const specdef =
"[NCHW:|NHWC:|NA:|AUTO:]Type:[NxCxHxW|NxHxWxC|...][:QNT[:fl|:scale:zero]]";
414 std::vector<std::string> spectok =
jevois::split(specs,
",\\s*");
415 std::vector<vsi_nn_tensor_attr_t> ret;
417 for (std::string
const & spec : spectok)
419 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
423 if (tok.size() < 2)
throw std::runtime_error(
"parseTensorSpecs: Malformed tensor spec ["+spec+
"] not "+specdef);
427 if (tok[0] ==
"NCHW") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_NCHW; }
428 else if (tok[0] ==
"NHWC") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC; }
429 else if (tok[0] ==
"NA") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_NA; }
430 else if (tok[0] ==
"AUTO") { ++n; attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO; }
431 else attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
434 if (tok.size() < n+2)
throw std::runtime_error(
"parseTensorSpecs: Malformed tensor spec ["+spec+
"] not "+specdef);
437 if (tok[n] ==
"8U") attr.dtype.vx_type = VSI_NN_TYPE_UINT8;
438 else if (tok[n] ==
"8S") attr.dtype.vx_type = VSI_NN_TYPE_INT8;
439 else if (tok[n] ==
"8B") attr.dtype.vx_type = VSI_NN_TYPE_BOOL8;
440 else if (tok[n] ==
"16U") attr.dtype.vx_type = VSI_NN_TYPE_UINT16;
441 else if (tok[n] ==
"16S") attr.dtype.vx_type = VSI_NN_TYPE_INT16;
442 else if (tok[n] ==
"16F") attr.dtype.vx_type = VSI_NN_TYPE_FLOAT16;
443 else if (tok[n] ==
"16B") attr.dtype.vx_type = VSI_NN_TYPE_BFLOAT16;
444 else if (tok[n] ==
"32U") attr.dtype.vx_type = VSI_NN_TYPE_UINT32;
445 else if (tok[n] ==
"32S") attr.dtype.vx_type = VSI_NN_TYPE_INT32;
446 else if (tok[n] ==
"32F") attr.dtype.vx_type = VSI_NN_TYPE_FLOAT32;
447 else if (tok[n] ==
"64U") attr.dtype.vx_type = VSI_NN_TYPE_UINT64;
448 else if (tok[n] ==
"64S") attr.dtype.vx_type = VSI_NN_TYPE_INT64;
449 else if (tok[n] ==
"64F") attr.dtype.vx_type = VSI_NN_TYPE_FLOAT64;
450 else throw std::range_error(
"parseTensorSpecs: Invalid tensor type [" + tok[n] +
"] in " + spec);
455 attr.dim_num = dims.size();
456 for (
size_t i = 0; i < attr.dim_num; ++i) attr.size[attr.dim_num - 1 - i] = dims[i];
460 if (n == tok.size() || tok[n] ==
"NONE")
462 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_NONE;
464 else if (tok[n] ==
"DFP")
466 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_DFP;
467 if (tok.size() != n+2)
468 throw std::range_error(
"parseTensorSpecs: In "+spec+
", DFP quantization needs :fl (" + specdef +
')');
469 attr.dtype.fl = std::stoi(tok[n+1]);
472 else if (tok[n] ==
"AA" || tok[n] ==
"AS")
474 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC;
475 if (tok.size() != n+3)
476 throw std::range_error(
"parseTensorSpecs: In "+spec+
", AA/AS quantization needs :scale:zero ("+specdef+
')');
477 attr.dtype.scale = std::stof(tok[n+1]);
478 attr.dtype.zero_point = std::stoi(tok[n+2]);
480 else if (tok[n] ==
"APS")
482 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC;
483 throw std::range_error(
"parseTensorSpecs: In " + spec +
", AFFINE_PERCHANNEL_SYMMETRIC quant not yet supported");
485 else throw std::range_error(
"parseTensorSpecs: Invalid quantization type in " + spec);
488 ret.emplace_back(attr);
504 size_t const ndim = attr.dim_num;
505 std::vector<int> cvdims(ndim);
506 for (
size_t i = 0; i < ndim; ++i) cvdims[ndim - 1 - i] = attr.size[i];
513 switch (attr.dtype.fmt)
515 case VSI_NN_DIM_FMT_NHWC:
516 if (attr.dim_num < 3)
throw std::range_error(
"attrsize: need at least 3D, got " +
jevois::dnn::attrstr(attr));
517 return cv::Size(attr.size[1], attr.size[2]);
519 case VSI_NN_DIM_FMT_NCHW:
520 if (attr.dim_num < 2)
throw std::range_error(
"attrsize: need at least 2D, got " +
jevois::dnn::attrstr(attr));
521 return cv::Size(attr.size[0], attr.size[1]);
523 case VSI_NN_DIM_FMT_AUTO:
524 if (attr.dim_num < 2)
return cv::Size(attr.size[0], 1);
525 if (attr.dim_num < 3)
return cv::Size(attr.size[0], attr.size[1]);
527 if (attr.size[0] > attr.size[2])
return cv::Size(attr.size[0], attr.size[1]);
528 else return cv::Size(attr.size[1], attr.size[2]);
531 throw std::range_error(
"attrsize: cannot extract width and height, got " +
jevois::dnn::attrstr(attr));
541 if (attr.dim_num > 2)
542 switch (attr.dtype.fmt)
544 case VSI_NN_DIM_FMT_NCHW: ret =
"NCHW:";
break;
545 case VSI_NN_DIM_FMT_NHWC: ret =
"NHWC:";
break;
550 switch (attr.dtype.vx_type)
552 case VSI_NN_TYPE_UINT8: ret +=
"8U:";
break;
553 case VSI_NN_TYPE_INT8: ret +=
"8S:";
break;
554 case VSI_NN_TYPE_BOOL8: ret +=
"8B:";
break;
555 case VSI_NN_TYPE_UINT16: ret +=
"16U:";
break;
556 case VSI_NN_TYPE_INT16: ret +=
"16S:";
break;
557 case VSI_NN_TYPE_FLOAT16: ret +=
"16F:";
break;
558 case VSI_NN_TYPE_BFLOAT16: ret +=
"16B:";
break;
559 case VSI_NN_TYPE_UINT32: ret +=
"32U:";
break;
560 case VSI_NN_TYPE_INT32: ret +=
"32S:";
break;
561 case VSI_NN_TYPE_FLOAT32: ret +=
"32F:";
break;
562 case VSI_NN_TYPE_UINT64: ret +=
"64U:";
break;
563 case VSI_NN_TYPE_INT64: ret +=
"64S:";
break;
564 case VSI_NN_TYPE_FLOAT64: ret +=
"64F:";
break;
565 default: ret +=
"TYPE_UNKNOWN:";
569 for (uint32_t i = 0; i < attr.dim_num; ++i)
570 ret += std::to_string(attr.size[attr.dim_num - 1 - i]) + ((i<attr.dim_num-1) ?
'x' :
':');
573 switch (attr.dtype.qnt_type)
575 case VSI_NN_QNT_TYPE_NONE: ret +=
"NONE";
break;
576 case VSI_NN_QNT_TYPE_DFP: ret +=
"DFP:" + std::to_string(attr.dtype.fl);
break;
577 case VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC:
578 ret +=
"AA:" + std::to_string(attr.dtype.scale) +
':' + std::to_string(attr.dtype.zero_point);
580 case VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC: ret +=
"APS:unsupported";
break;
581 default: ret +=
"QUANT_UNKNOWN";
590 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
591 attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
594 switch (t->quantization.type)
596 case kTfLiteNoQuantization:
597 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_NONE;
600 case kTfLiteAffineQuantization:
602 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC;
603 attr.dtype.scale = t->params.scale;
604 attr.dtype.zero_point = t->params.zero_point;
608 default:
LFATAL(
"unsupported quantization " << t->quantization.type);
611 TfLiteIntArray
const & dims = *t->dims;
612 attr.dim_num = dims.size;
613 for (
int i = 0; i < dims.size; ++i) attr.size[dims.size - 1 - i] = dims.data[i];
616 if (attr.dim_num == 4)
618 if (attr.size[0] > attr.size[2]) attr.dtype.fmt = VSI_NN_DIM_FMT_NCHW;
619 else attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
629 vsi_nn_tensor_attr_t attr; memset(&attr, 0,
sizeof(attr));
631 attr.dtype.vx_type =
hailo2vsi(vi.format.type);
633 switch (vi.format.order)
635 case HAILO_FORMAT_ORDER_HAILO_NMS:
636 attr.dtype.fmt = VSI_NN_DIM_FMT_AUTO;
638 attr.size[0] = vi.nms_shape.number_of_classes;
639 attr.size[1] = vi.nms_shape.max_bboxes_per_class * 5;
642 case HAILO_FORMAT_ORDER_NHWC:
643 case HAILO_FORMAT_ORDER_FCR:
644 case HAILO_FORMAT_ORDER_F8CR:
645 attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
647 attr.size[0] = vi.shape.features;
648 attr.size[1] = vi.shape.width;
649 attr.size[2] = vi.shape.height;
653 case HAILO_FORMAT_ORDER_NHW:
654 attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
657 attr.size[1] = vi.shape.width;
658 attr.size[2] = vi.shape.height;
662 case HAILO_FORMAT_ORDER_NC:
663 attr.dtype.fmt = VSI_NN_DIM_FMT_NHWC;
667 attr.size[2] = vi.shape.features;
671 case HAILO_FORMAT_ORDER_NCHW:
672 attr.dtype.fmt = VSI_NN_DIM_FMT_NCHW;
674 attr.size[0] = vi.shape.features;
675 attr.size[1] = vi.shape.width;
676 attr.size[2] = vi.shape.height;
680 default:
throw std::range_error(
"tensorattr: Unsupported Hailo order " +std::to_string(vi.format.order));
684 attr.dtype.qnt_type = VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC;
685 attr.dtype.scale = vi.quant_info.qp_scale;
686 attr.dtype.zero_point = int32_t(vi.quant_info.qp_zp);
695 struct ParallelSigmoid :
public cv::ParallelLoopBody
697 ParallelSigmoid(
float * ptr) : p(ptr)
700 virtual void operator()(cv::Range
const & r)
const
710 if (m.type() != CV_32F)
LFATAL(
"Can only apply to CV_32F tensors");
712 cv::parallel_for_(cv::Range(0, m.total()), ParallelSigmoid((
float *)m.data));
716size_t jevois::dnn::softmax(
float const * input,
size_t const n,
size_t const stride,
float const fac,
float * output,
719 if (stride == 0)
LFATAL(
"Cannot work with stride = 0");
722 float largest = -FLT_MAX;
size_t largest_idx = 0;
723 size_t const ns = n * stride;
725 for (
size_t i = 0; i < ns; i += stride)
if (input[i] > largest) { largest = input[i]; largest_idx = i; }
728 for (
size_t i = 0; i < ns; i += stride)
735 for (
size_t i = 0; i < ns; i += stride)
744 if (maxonly) output[largest_idx] /= sum;
745 else for (
size_t i = 0; i < ns; i += stride) output[i] /= sum;
755 size_t const ns = n * stride;
757 float alpha = -FLT_MAX;
758 for (
size_t c = 0; c < ns; c += stride)
760 float score = src[c];
761 if (score > alpha) alpha = score;
764 float denominator = 0;
768 for (
size_t i = 0; i < ns; i += stride)
771 denominator += *dp++;
774 if (denominator == 0.0F)
return 0.0F;
776 for (
size_t i = 0; i < n; ++i)
778 dst[i] /= denominator;
779 dis_sum += i * dst[i];
788 if (blob.channels() != 1)
return false;
790 if (uint32_t(blob.size.dims()) != attr.dim_num)
return false;
792 for (
size_t i = 0; i < attr.dim_num; ++i)
793 if (
int(attr.size[attr.dim_num - 1 - i]) != blob.size[i])
return false;
801 if (m.depth() != CV_32F)
LFATAL(
"Tensor to quantize must be 32F");
805 size_t tot = 1;
for (
int d : adims) tot *= d;
807 if (tot != m.total() * m.channels())
812 switch (attr.dtype.qnt_type)
814 case VSI_NN_QNT_TYPE_NONE:
817 m.convertTo(ret, tt);
821 case VSI_NN_QNT_TYPE_DFP:
827 if (attr.dtype.fl > 7)
LFATAL(
"Invalid DFP fl value " << attr.dtype.fl <<
": must be in [0..7]");
829 m.convertTo(ret, tt, 1 << attr.dtype.fl, 0.0);
834 if (attr.dtype.fl > 15)
LFATAL(
"Invalid DFP fl value " << attr.dtype.fl <<
": must be in [0..15]");
836 m.convertTo(ret, tt, 1 << attr.dtype.fl, 0.0);
844 case VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC:
852 m.convertTo(ret, tt, 1.0 / attr.dtype.scale, attr.dtype.zero_point);
861 case VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC:
862 LFATAL(
"Affine per-channel symmetric not supported yet");
876 switch (attr.dtype.qnt_type)
878 case VSI_NN_QNT_TYPE_NONE:
881 m.convertTo(ret, CV_32F);
885 case VSI_NN_QNT_TYPE_DFP:
888 m.convertTo(ret, CV_32F, 1.0 / (1 << attr.dtype.fl), 0.0);
892 case VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC:
895 double const alpha = attr.dtype.scale;
896 double const beta = - alpha * attr.dtype.zero_point;
897 m.convertTo(ret, CV_32F, alpha, beta);
901 case VSI_NN_QNT_TYPE_AFFINE_PERCHANNEL_SYMMETRIC:
902 LFATAL(
"Affine per-channel symmetric not supported yet");
905 LFATAL(
"Unknown quantization type " <<
int(attr.dtype.qnt_type));
912 cv::MatSize
const & rs = m.size;
913 size_t const ndims = rs.dims();
915 for (
size_t i = 0; i < ndims; ++i)
if (rs[i] == 1) --ret;
else break;
922 if (tensors.empty())
return cv::Mat();
923 if (tensors.size() == 1)
return tensors[0];
925 cv::MatSize
const & ms = tensors[0].size;
926 int const ndims = ms.dims();
927 auto const typ = tensors[0].type();
930 if (axis < - ndims || axis >= ndims)
931 LFATAL(
"Incorrect axis " << axis <<
": must be in [" << -ndims <<
" ... " << ndims - 1 <<
']');
932 if (axis < 0) axis = ndims - axis;
935 size_t newsize = tensors[0].size[axis];
937 for (
size_t i = 1; i < tensors.size(); ++i)
939 if (tensors[i].type() != typ)
943 if (tensors[i].size.dims() != ndims)
944 LFATAL(
"Mismatched number of dimensions: " << ndims <<
" for tensors[0] vs. " <<
945 tensors[i].size.dims() <<
" for tensors[" << i <<
']');
947 newsize += tensors[i].size[axis];
951 for (
int a = 0; a < ndims; ++a)
953 for (
size_t i = 1; i < tensors.size(); ++i)
954 if (tensors[i].size[a] != ms[a])
955 LFATAL(
"Mismatched size for axis " << a <<
": tensors[0] has " << ms[a] <<
" while tensors[" <<
956 i <<
"] has " << tensors[i].size[a]);
959 int newdims[ndims];
for (
int i = 0; i < ndims; ++i) newdims[i] = ms.p[i];
960 newdims[axis] = newsize;
961 cv::Mat ret(ndims, newdims, typ);
962 unsigned char * optr = ret.data;
964 size_t numcopy = 1;
for (
int a = 0; a < axis; ++a) numcopy *= ms[a];
965 size_t elemsize =
jevois::cvBytesPerPix(typ);
for (
int a = axis + 1; a < ndims; ++a) elemsize *= ms[a];
967 for (
size_t n = 0; n < numcopy; ++n)
968 for (
size_t i = 0; i < tensors.size(); ++i)
970 size_t const axsize = tensors[i].size[axis];
971 unsigned char const * sptr = tensors[i].data + n * elemsize * axsize;
972 std::memcpy(optr, sptr, elemsize * axsize);
973 optr += elemsize * axsize;
980std::vector<cv::Mat>
jevois::dnn::split(cv::Mat
const & tensor,
int axis, std::vector<int>
const & sizes)
982 cv::MatSize
const & ms = tensor.size;
983 int const ndims = ms.dims();
984 auto const typ = tensor.type();
985 int const nsplit = sizes.size();
988 if (axis < - ndims || axis >= ndims)
989 LFATAL(
"Incorrect axis " << axis <<
": must be in [" << -ndims <<
" ... " << ndims - 1 <<
991 if (axis < 0) axis = ndims - axis;
994 std::vector<cv::Mat> ret;
995 if (nsplit == 0)
return ret;
998 if (sizes[0] == ms[axis]) { ret.emplace_back(tensor);
return ret; }
999 else LFATAL(
"Desired new size " << sizes[0] <<
" for axis " << axis <<
" with only one output tensor must match "
1004 unsigned char * optr[nsplit];
size_t copysize[nsplit];
1006 size_t numcopy = 1;
for (
int a = 0; a < axis; ++a) numcopy *= ms[a];
1007 size_t elemsize =
jevois::cvBytesPerPix(typ);
for (
int a = axis + 1; a < ndims; ++a) elemsize *= ms[a];
1010 int newdims[ndims];
for (
int i = 0; i < ndims; ++i) newdims[i] = ms.p[i];
1013 for (
int i = 0; i < nsplit; ++i)
1015 int const s = sizes[i];
1016 newdims[axis] = s; ret.emplace_back(cv::Mat(ndims, newdims, typ));
1017 optr[i] = ret.back().data;
1018 copysize[i] = s * elemsize;
1022 if (sum != ms[axis])
1023 LFATAL(
"Given sizes [" <<
jevois::join(sizes,
", ") <<
"] do not add up to original size of axis " <<
1027 unsigned char const * sptr = tensor.data;
1028 for (
size_t n = 0; n < numcopy; ++n)
1029 for (
int j = 0; j < nsplit; ++j)
1031 size_t const cs = copysize[j];
1032 std::memcpy(optr[j], sptr, cs);
1033 sptr += cs; optr[j] += cs;
#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.
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::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...