23 #include <edgetpu_c.h>
25 #include <tensorflow/lite/builtin_op_data.h>
26 #include <tensorflow/lite/kernels/register.h>
27 #include <tensorflow/lite/kernels/internal/tensor_ctypes.h>
30 int jevois::dnn::NetworkTPU::ErrorReporter::Report(
char const * format, va_list args)
32 static char buf[2048];
33 int ret = vsnprintf(buf, 2048, format, args);
34 itsErrors.push_back(buf);
46 dataroot::freeze(doit);
49 dequant::freeze(doit);
50 intensors::freeze(doit);
51 outtensors::freeze(doit);
58 if (ready() ==
false)
LFATAL(
"Network is not ready");
65 std::vector<vsi_nn_tensor_attr_t> ret;
66 auto const & input_indices = itsInterpreter->inputs();
68 for (
size_t i = 0; i < input_indices.size(); ++i)
70 TfLiteTensor
const * itensor = itsInterpreter->tensor(input_indices[i]);
71 if (itensor ==
nullptr)
LFATAL(
"Network has Null input tensor " << i);
81 if (ready() ==
false)
LFATAL(
"Network is not ready");
88 std::vector<vsi_nn_tensor_attr_t> ret;
89 auto const & output_indices = itsInterpreter->outputs();
91 for (
size_t i = 0; i < output_indices.size(); ++i)
93 TfLiteTensor
const * otensor = itsInterpreter->tensor(output_indices[i]);
94 if (otensor ==
nullptr)
LFATAL(
"Network has Null output tensor " << i);
105 itsInterpreter.reset();
107 itsErrorReporter.itsErrors.clear();
114 itsModel = tflite::FlatBufferModel::BuildFromFile(m.c_str(), &itsErrorReporter);
115 if (!itsModel)
LFATAL(
"Failed to load model from file " << m);
117 tflite::ops::builtin::BuiltinOpResolver resolver;
118 tflite::InterpreterBuilder(*itsModel, resolver)(&itsInterpreter);
121 std::unique_ptr<edgetpu_device, decltype(&edgetpu_free_devices)>
122 devices(edgetpu_list_devices(&num_devices), &edgetpu_free_devices);
124 if (num_devices == 0)
LFATAL(
"No connected TPU found");
126 if (tn >= num_devices)
LFATAL(
"Cannot use TPU " << tn <<
" because only " << num_devices <<
" TPUs detected.");
128 auto const & device = devices.get()[tn];
130 ModifyGraphWithDelegate(std::unique_ptr<TfLiteDelegate, decltype(&edgetpu_free_delegate)>
131 (edgetpu_create_delegate(device.type, device.path,
nullptr, 0), &edgetpu_free_delegate));
133 itsInterpreter->SetNumThreads(1);
135 if (itsInterpreter->AllocateTensors() != kTfLiteOk)
LFATAL(
"Failed to allocate tensors");
137 for (
size_t i = 0; i < itsInterpreter->inputs().size(); ++i)
138 LINFO(
"Input tensor " << i <<
": " << itsInterpreter->GetInputName(i));
139 for (
size_t i = 0; i < itsInterpreter->outputs().size(); ++i)
140 LINFO(
"Output tensor " << i <<
": " << itsInterpreter->GetOutputName(i));
142 int t_size = itsInterpreter->tensors_size();
143 for (
int i = 0; i < t_size; ++i)
144 if (itsInterpreter->tensor(i)->name)
145 LINFO(
"Layer " << i <<
": " << itsInterpreter->tensor(i)->name <<
", "
147 << itsInterpreter->tensor(i)->bytes <<
" bytes, scale: "
148 << itsInterpreter->tensor(i)->params.scale <<
", zero: "
149 << itsInterpreter->tensor(i)->params.zero_point);
152 for (
size_t i = 0; i < itsInterpreter->inputs().size(); ++i)
153 LINFO(
"input " << i <<
" is layer " << itsInterpreter->inputs()[i]);
154 for (
size_t i = 0; i < itsInterpreter->outputs().size(); ++i)
155 LINFO(
"output " << i <<
" is layer " << itsInterpreter->outputs()[i]);
157 catch (std::exception
const & e)
159 std::string err =
"\n";
160 for (std::string
const & s : itsErrorReporter.itsErrors) err +=
"ERR " + s +
"\n";
162 throw std::runtime_error(err);
168 std::vector<std::string> & info)
170 if ( ! itsInterpreter)
LFATAL(
"Internal inconsistency");
172 if (blobs.size() != itsInterpreter->inputs().size())
173 LFATAL(
"Received " << blobs.size() <<
" input tensors, but network wants " << itsInterpreter->inputs().size());
175 auto const & input_indices = itsInterpreter->inputs();
176 for (
size_t b = 0; b < blobs.size(); ++b)
178 cv::Mat
const & cvin = blobs[b];
179 auto * itensor = itsInterpreter->tensor(input_indices[b]);
180 if (itensor ==
nullptr)
LFATAL(
"Network has Null input tensor " << b);
183 TfLiteIntArray
const & tfindims = *itensor->dims;
184 cv::MatSize
const & cvindims = cvin.size;
185 for (
int i = 0; i < tfindims.size; ++i)
186 if (tfindims.data[i] != cvindims[i])
191 size_t const cvsiz = cvin.total() * cvin.elemSize();
192 size_t const tfsiz = itensor->bytes;
193 if (cvsiz != tfsiz)
LFATAL(
"Input " << b <<
" size mismatch: blob has " << cvsiz <<
194 " but network wants " << tfsiz <<
" bytes. Maybe type is wrong in intensors?");
197 uint8_t * input = tflite::GetTensorData<uint8_t>(itensor);
198 if (input ==
nullptr)
LFATAL(
"Input tensor " << b <<
" is null in network");
199 std::memcpy(input, cvin.data, cvsiz);
200 info.emplace_back(
"- Input tensors ok");
204 if (itsInterpreter->Invoke() != kTfLiteOk)
LFATAL(
"Failed to invoke interpreter");
205 info.emplace_back(
"- Network forward pass ok");
208 auto const & output_indices = itsInterpreter->outputs();
209 std::vector<cv::Mat> outs;
211 for (
size_t o = 0;
o < output_indices.size(); ++
o)
213 auto const * otensor = itsInterpreter->tensor(output_indices[
o]);
214 if (otensor ==
nullptr)
LFATAL(
"Network produced Null output tensor " <<
o);
217 TfLiteIntArray
const & tfdims = *otensor->dims;
218 std::vector<int> cvdims;
size_t sz = 1;
219 for (
int i = 0; i < tfdims.size; ++i) { cvdims.emplace_back(tfdims.data[i]); sz *= tfdims.data[i]; }
222 TfLiteType
const ot = otensor->type;
223 std::string
const otname = TfLiteTypeGetName(ot);
233 uint8_t
const * output = tflite::GetTensorData<uint8_t>(otensor);
234 if (output ==
nullptr)
LFATAL(
"Network produced Null output tensor data " <<
o);
235 cv::Mat
const cvi(cvdims, CV_8U, (
void *)output);
236 cv::Mat cvout; cvi.convertTo(cvout, CV_32F);
237 cvout -= otensor->params.zero_point;
238 cvout *= otensor->params.scale;
239 info.emplace_back(
"- Dequantized " + otname +
" output tensor " +
std::to_string(
o) +
" to FLOAT32");
240 outs.emplace_back(cvout);
258 cv::Mat cvout(cvdims, CV_32S);
259 int * cvoutdata = (
int *)cvout.data;
260 int64_t
const * output = tflite::GetTensorData<int64_t>(otensor);
261 if (output ==
nullptr)
LFATAL(
"Network produced Null output tensor data " <<
o);
262 for (
size_t i = 0; i < sz; ++i) *cvoutdata++ =
int(*output++);
263 info.emplace_back(
"- Converted " + otname +
" output tensor " +
std::to_string(
o) +
" to INT32");
264 outs.emplace_back(cvout);
278 cv::Mat cvout(cvdims, cvtype);
279 uint8_t
const * output = tflite::GetTensorData<uint8_t>(otensor);
280 if (output ==
nullptr)
LFATAL(
"Network produced Null output tensor data " <<
o);
282 info.emplace_back(
"- Copied " + otname +
" output tensor " +
std::to_string(
o));
283 outs.emplace_back(cvout);
288 LFATAL(
"Output tensor " << otensor->name <<
" has unsupported type: " << otname);
296 if ((jevois::frameNum() % 50) == 0)
299 info.emplace_back(
jevois::sformat(
"- TPU%zu temp %dC", tn, temp / 1000));