2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <tfldump/Dump.h>
18 #include <mio_tflite2121/Helper.h>
21 #include "OpPrinter.h"
25 #include <algorithm> // min
26 #include <iomanip> // setfill
31 void dump_buffer(std::ostream &os, const uint8_t *buffer, size_t size, size_t amount)
33 std::ios_base::fmtflags saveflags(os.flags());
36 bool ellipsis = amount > 0 && size > 8;
37 size_t count = ellipsis ? std::min(size, amount) : size;
39 for (size_t i = 0; i < count; i++)
46 os << std::showbase << std::setfill('0') << std::setw(2);
47 os << std::hex << (uint32_t)buffer[i];
59 void dump_vector(std::ostream &os, const std::vector<int32_t> &vs)
71 std::ostream &operator<<(std::ostream &os, const std::vector<int32_t> &vect)
73 tfldump::dump_vector(os, vect);
78 void dump_fbvect(std::ostream &os, const flatbuffers::Vector<T> *fbvect, uint32_t size)
80 for (uint32_t q = 0; q < size; q++)
89 void dump_fbvect(std::ostream &os, const flatbuffers::Vector<uint8_t> *fbvect, uint32_t size)
92 for (uint32_t q = 0; q < size; q++)
96 os << static_cast<uint32_t>(fbvect->Get(q));
100 template <typename T>
101 std::ostream &operator<<(std::ostream &os, const flatbuffers::Vector<T> *fbvect)
103 if (fbvect == nullptr)
106 bool ellipsis = (fbvect->size() > 8);
107 auto limit_size = ellipsis ? 8 : fbvect->size();
111 os << "(" << fbvect->size() << ") ";
114 dump_fbvect(os, fbvect, limit_size);
124 void dump_sub_graph(std::ostream &os, tflread::Reader &reader)
126 auto tensors = reader.tensors();
127 auto operators = reader.operators();
129 // dump operands(tensors)
130 os << "Operands: T(subgraph index : tensor index) TYPE (shape) (shape_signature) "
131 << "B(buffer index) (variable) OperandName" << std::endl;
132 for (uint32_t i = 0; i < tensors->Length(); ++i)
134 // TODO refactor to some better structure
135 auto tensor = tensors->Get(i);
136 std::vector<int32_t> dims = {-1};
139 dims = tflread::as_index_vector(tensor->shape());
141 os << "T(" << reader.subgraph_index() << ":" << i << ") " << mio::tflite::tensor_type(tensor)
143 os << "(" << dims << ") ";
144 if (tensor->shape_signature())
146 std::vector<int32_t> dims_sig = tflread::as_index_vector(tensor->shape_signature());
147 os << "(" << dims_sig << ") ";
149 os << "B(" << tensor->buffer() << ") ";
150 if (tensor->is_variable())
154 os << mio::tflite::tensor_name(tensor) << std::endl;
156 if (auto q_params = tensor->quantization())
158 if ((q_params->min() && q_params->max()) || (q_params->scale() && q_params->zero_point()))
160 std::string strquantiz = " Quantization: ";
161 std::string strqindent(strquantiz.size(), ' ');
166 os << "min(" << q_params->min() << ") ";
167 if (q_params->min()->size() > 1)
168 os << std::endl << strqindent;
172 os << "max(" << q_params->max() << ") ";
173 if (q_params->max()->size() > 1)
174 os << std::endl << strqindent;
176 if (q_params->scale())
178 os << "scale(" << q_params->scale() << ") ";
179 if (q_params->scale()->size() > 1)
180 os << std::endl << strqindent;
182 if (q_params->zero_point())
184 os << "zeropt(" << q_params->zero_point() << ") ";
185 if (q_params->zero_point()->size() > 1)
186 os << std::endl << strqindent;
188 os << "quantized_dimension(" << q_params->quantized_dimension() << ")";
194 if (const auto &s_params = tensor->sparsity())
196 std::string strsparsity = " Sparsity: ";
197 std::string strsindent(strsparsity.size(), ' ');
200 if (s_params->traversal_order())
202 os << "traversal_order(" << s_params->traversal_order() << ") ";
203 os << std::endl << strsindent;
205 if (s_params->block_map())
207 os << "block_map(" << s_params->block_map() << ") ";
208 os << std::endl << strsindent;
210 if (const auto &dim_metadata = s_params->dim_metadata())
213 for (const auto &dm : *dim_metadata)
215 std::string strdm = "dim_metadata[" + std::to_string(idx++) + "]: ";
216 std::string strdm_indent = strsindent + std::string(strdm.size(), ' ');
219 os << "format(" << tflite::EnumNameDimensionType(dm->format()) << ") ";
220 os << std::endl << strdm_indent;
222 os << "dense_size(" << dm->dense_size() << ") ";
223 os << std::endl << strdm_indent;
225 os << "array_segments_type("
226 << tflite::EnumNameSparseIndexVector(dm->array_segments_type()) << ") ";
227 os << std::endl << strdm_indent;
229 os << "array_segments(";
230 switch (dm->array_segments_type())
232 case tflite::SparseIndexVector_NONE:
235 case tflite::SparseIndexVector_Int32Vector:
236 os << dm->array_segments_as_Int32Vector()->values();
238 case tflite::SparseIndexVector_Uint16Vector:
239 os << dm->array_segments_as_Uint16Vector()->values();
241 case tflite::SparseIndexVector_Uint8Vector:
242 os << dm->array_segments_as_Uint8Vector()->values();
245 throw std::runtime_error("Invalid SparseIndexVector type of array_segments");
247 os << ")" << std::endl << strdm_indent;
249 os << "array_indices_type(" << tflite::EnumNameSparseIndexVector(dm->array_indices_type())
251 os << std::endl << strdm_indent;
253 os << "array_indices(";
254 switch (dm->array_indices_type())
256 case tflite::SparseIndexVector_NONE:
259 case tflite::SparseIndexVector_Int32Vector:
260 os << dm->array_indices_as_Int32Vector()->values();
262 case tflite::SparseIndexVector_Uint16Vector:
263 os << dm->array_indices_as_Uint16Vector()->values();
265 case tflite::SparseIndexVector_Uint8Vector:
266 os << dm->array_indices_as_Uint8Vector()->values();
269 throw std::runtime_error("Invalid SparseIndexVector type of array_indices");
271 os << ")" << std::endl << strsindent;
279 os << "Operators: O(subgraph index : operator index) OpCodeName " << std::endl;
280 os << " Option(values) ... <-- depending on OpCode" << std::endl;
281 os << " I T(tensor index) OperandName <-- as input" << std::endl;
282 os << " O T(tensor index) OperandName <-- as output" << std::endl;
283 for (uint32_t i = 0; i < operators->Length(); ++i)
285 const auto op = operators->Get(i);
286 tflite::BuiltinOperator builtincode = reader.builtin_code(op);
288 const std::vector<int32_t> &inputs = tflread::as_index_vector(op->inputs());
289 const std::vector<int32_t> &outputs = tflread::as_index_vector(op->outputs());
290 auto op_name = reader.opcode_name(op);
292 os << "O(" << reader.subgraph_index() << ":" << i << ") " << op_name << " ";
295 if (auto op_prn = OpPrinterRegistry::get().lookup(builtincode))
297 op_prn->options(op, os);
300 for (auto input : inputs)
302 os << " I T(" << reader.subgraph_index() << ":" << input << ") ";
305 auto tensor = tensors->Get(input);
306 os << mio::tflite::tensor_name(tensor);
310 for (auto output : outputs)
312 os << " O T(" << reader.subgraph_index() << ":" << output << ") ";
315 auto tensor = tensors->Get(output);
316 os << mio::tflite::tensor_name(tensor);
323 // dump network inputs/outputs
324 os << "Inputs/Outputs: I(input)/O(output) T(tensor index) OperandName" << std::endl;
326 for (const auto input : reader.inputs())
328 auto tensor = tensors->Get(input);
329 std::string name = mio::tflite::tensor_name(tensor);
330 os << "I T(" << reader.subgraph_index() << ":" << input << ") " << name << std::endl;
333 for (const auto output : reader.outputs())
335 auto tensor = tensors->Get(output);
336 std::string name = mio::tflite::tensor_name(tensor);
337 os << "O T(" << reader.subgraph_index() << ":" << output << ") " << name << std::endl;
343 void dump_model(std::ostream &os, const tflite::Model *model)
345 tflread::Reader reader(model);
347 uint32_t num_subgraph = reader.num_subgraph();
349 // dump model version
350 os << "===================================================================" << std::endl;
351 os << "Model version: " << reader.version() << std::endl;
352 os << " # sub graphs: " << num_subgraph << std::endl;
355 auto opcodes = reader.opcodes();
356 auto buffers = reader.buffers();
357 auto metadata = reader.metadata();
358 auto signaturedefs = reader.signaturedefs();
360 // dump operator_codes
361 os << "Operator Codes: [order] OpCodeName (OpCode Enum)" << std::endl;
362 int32_t opcode_index = 0;
363 for (auto opcode : opcodes)
365 tflite::BuiltinOperator op_code = opcode->builtin_code();
366 tflite::BuiltinOperator dp_code = tflite::BuiltinOperator(opcode->deprecated_builtin_code());
368 auto op_name = mio::tflite::opcode_name(opcode);
369 auto op_version = opcode->version();
371 os << "[" << opcode_index << "] " << op_name << " (code: " << op_code
372 << ", dep_code: " << dp_code << ", version: " << op_version << ")" << std::endl;
379 os << "Buffers: B(index) (length) values, if any" << std::endl;
380 for (uint32_t i = 0; i < buffers->Length(); ++i)
382 const uint8_t *buff_data;
383 size_t size = reader.buffer_info(i, &buff_data);
385 os << "B(" << i << ") (" << size << ") ";
386 if (buff_data != nullptr)
388 dump_buffer(os, buff_data, size, 16);
395 if (metadata != nullptr)
397 os << "metadata : B(index) name" << std::endl;
398 for (uint32_t i = 0; i < metadata->Length(); ++i)
400 os << "B(" << metadata->Get(i)->buffer() << ") " << metadata->Get(i)->name()->c_str()
407 if (signaturedefs != nullptr)
409 os << "SignatureDef" << std::endl;
410 for (uint32_t i = 0; i < signaturedefs->Length(); ++i)
412 auto sign_i = signaturedefs->Get(i);
413 os << "S(" << i << ") signature_key(" << sign_i->signature_key()->c_str() << "), sub_graph("
414 << sign_i->subgraph_index() << ")" << std::endl;
416 auto inputs_i = sign_i->inputs();
417 for (uint32_t t = 0; t < inputs_i->Length(); ++t)
419 auto inputs_i_t = inputs_i->Get(t);
420 os << " I(" << t << ")"
421 << " T(" << sign_i->subgraph_index() << ":" << inputs_i_t->tensor_index() << ") "
422 << inputs_i_t->name()->c_str() << std::endl;
425 auto outputs_i = sign_i->outputs();
426 for (uint32_t t = 0; t < outputs_i->Length(); ++t)
428 auto outputs_i_t = outputs_i->Get(t);
429 os << " O(" << t << ")"
430 << " T(" << sign_i->subgraph_index() << ":" << outputs_i_t->tensor_index() << ") "
431 << outputs_i_t->name()->c_str() << std::endl;
437 for (uint32_t sg = 0; sg < num_subgraph; ++sg)
439 reader.select_subgraph(sg);
441 os << "-------------------------------------------------------------------" << std::endl;
442 os << "Sub-Graph: #" << sg << " " << reader.subgraph_name() << std::endl;
445 dump_sub_graph(os, reader);
448 os << "===================================================================" << std::endl;
451 } // namespace tfldump
453 std::ostream &operator<<(std::ostream &os, const tflite::Model *model)
455 tfldump::dump_model(os, model);