ONE - On-device Neural Engine
Loading...
Searching...
No Matches
Dump.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include <tfldump/Dump.h>
19
20#include "Read.h"
21#include "OpPrinter.h"
22
23#include <ostream>
24
25#include <algorithm> // min
26#include <iomanip> // setfill
27
28namespace tfldump
29{
30
31void dump_buffer(std::ostream &os, const uint8_t *buffer, size_t size, size_t amount)
32{
33 std::ios_base::fmtflags saveflags(os.flags());
34
35 bool second = false;
36 bool ellipsis = amount > 0 && size > 8;
37 size_t count = ellipsis ? std::min(size, amount) : size;
38
39 for (size_t i = 0; i < count; i++)
40 {
41 if (second)
42 {
43 os << " ";
44 }
45
46 os << std::showbase << std::setfill('0') << std::setw(2);
47 os << std::hex << (uint32_t)buffer[i];
48
49 second = true;
50 }
51 if (ellipsis)
52 {
53 os << " ...";
54 }
55
56 os.flags(saveflags);
57}
58
59void dump_vector(std::ostream &os, const std::vector<int32_t> &vs)
60{
61 uint32_t seq = 0;
62 for (auto &v : vs)
63 {
64 if (seq)
65 os << ", ";
66 os << v;
67 seq++;
68 }
69}
70
71std::ostream &operator<<(std::ostream &os, const std::vector<int32_t> &vect)
72{
73 tfldump::dump_vector(os, vect);
74 return os;
75}
76
77template <typename T>
78void dump_fbvect(std::ostream &os, const flatbuffers::Vector<T> *fbvect, uint32_t size)
79{
80 for (uint32_t q = 0; q < size; q++)
81 {
82 if (q)
83 os << ", ";
84 os << fbvect->Get(q);
85 }
86}
87
88template <>
89void dump_fbvect(std::ostream &os, const flatbuffers::Vector<uint8_t> *fbvect, uint32_t size)
90{
91 assert(fbvect);
92 for (uint32_t q = 0; q < size; q++)
93 {
94 if (q)
95 os << ", ";
96 os << static_cast<uint32_t>(fbvect->Get(q));
97 }
98}
99
100template <typename T>
101std::ostream &operator<<(std::ostream &os, const flatbuffers::Vector<T> *fbvect)
102{
103 if (fbvect == nullptr)
104 return os;
105
106 bool ellipsis = (fbvect->size() > 8);
107 auto limit_size = ellipsis ? 8 : fbvect->size();
108
109 if (ellipsis)
110 {
111 os << "(" << fbvect->size() << ") ";
112 }
113
114 dump_fbvect(os, fbvect, limit_size);
115
116 if (ellipsis)
117 {
118 os << " ... ";
119 }
120
121 return os;
122}
123
124void dump_sub_graph(std::ostream &os, tflread::Reader &reader)
125{
126 auto tensors = reader.tensors();
127 auto operators = reader.operators();
128
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->size(); ++i)
133 {
134 // TODO refactor to some better structure
135 auto tensor = tensors->Get(i);
136 std::vector<int32_t> dims = {-1};
137
138 if (tensor->shape())
139 dims = tflread::as_index_vector(tensor->shape());
140
141 os << "T(" << reader.subgraph_index() << ":" << i << ") " << mio::tflite::tensor_type(tensor)
142 << " ";
143 os << "(" << dims << ") ";
144 if (tensor->shape_signature())
145 {
146 std::vector<int32_t> dims_sig = tflread::as_index_vector(tensor->shape_signature());
147 os << "(" << dims_sig << ") ";
148 }
149 os << "B(" << tensor->buffer() << ") ";
150 if (tensor->is_variable())
151 {
152 os << "(variable) ";
153 }
154 os << mio::tflite::tensor_name(tensor) << std::endl;
155
156 if (auto q_params = tensor->quantization())
157 {
158 if ((q_params->min() && q_params->max()) || (q_params->scale() && q_params->zero_point()))
159 {
160 std::string strquantiz = " Quantization: ";
161 std::string strqindent(strquantiz.size(), ' ');
162 os << strquantiz;
163
164 if (q_params->min())
165 {
166 os << "min(" << q_params->min() << ") ";
167 if (q_params->min()->size() > 1)
168 os << std::endl << strqindent;
169 }
170 if (q_params->max())
171 {
172 os << "max(" << q_params->max() << ") ";
173 if (q_params->max()->size() > 1)
174 os << std::endl << strqindent;
175 }
176 if (q_params->scale())
177 {
178 os << "scale(" << q_params->scale() << ") ";
179 if (q_params->scale()->size() > 1)
180 os << std::endl << strqindent;
181 }
182 if (q_params->zero_point())
183 {
184 os << "zeropt(" << q_params->zero_point() << ") ";
185 if (q_params->zero_point()->size() > 1)
186 os << std::endl << strqindent;
187 }
188 os << "quantized_dimension(" << q_params->quantized_dimension() << ")";
189
190 os << std::endl;
191 }
192 }
193
194 if (const auto &s_params = tensor->sparsity())
195 {
196 std::string strsparsity = " Sparsity: ";
197 std::string strsindent(strsparsity.size(), ' ');
198 os << strsparsity;
199
200 if (s_params->traversal_order())
201 {
202 os << "traversal_order(" << s_params->traversal_order() << ") ";
203 os << std::endl << strsindent;
204 }
205 if (s_params->block_map())
206 {
207 os << "block_map(" << s_params->block_map() << ") ";
208 os << std::endl << strsindent;
209 }
210 if (const auto &dim_metadata = s_params->dim_metadata())
211 {
212 uint32_t idx = 0;
213 for (const auto &dm : *dim_metadata)
214 {
215 std::string strdm = "dim_metadata[" + std::to_string(idx++) + "]: ";
216 std::string strdm_indent = strsindent + std::string(strdm.size(), ' ');
217 os << strdm;
218
219 os << "format(" << tflite::EnumNameDimensionType(dm->format()) << ") ";
220 os << std::endl << strdm_indent;
221
222 os << "dense_size(" << dm->dense_size() << ") ";
223 os << std::endl << strdm_indent;
224
225 os << "array_segments_type("
226 << tflite::EnumNameSparseIndexVector(dm->array_segments_type()) << ") ";
227 os << std::endl << strdm_indent;
228
229 os << "array_segments(";
230 switch (dm->array_segments_type())
231 {
232 case tflite::SparseIndexVector_NONE:
233 // DO NOTHING
234 break;
235 case tflite::SparseIndexVector_Int32Vector:
236 os << dm->array_segments_as_Int32Vector()->values();
237 break;
238 case tflite::SparseIndexVector_Uint16Vector:
239 os << dm->array_segments_as_Uint16Vector()->values();
240 break;
241 case tflite::SparseIndexVector_Uint8Vector:
242 os << dm->array_segments_as_Uint8Vector()->values();
243 break;
244 default:
245 throw std::runtime_error("Invalid SparseIndexVector type of array_segments");
246 }
247 os << ")" << std::endl << strdm_indent;
248
249 os << "array_indices_type(" << tflite::EnumNameSparseIndexVector(dm->array_indices_type())
250 << ") ";
251 os << std::endl << strdm_indent;
252
253 os << "array_indices(";
254 switch (dm->array_indices_type())
255 {
256 case tflite::SparseIndexVector_NONE:
257 // DO NOTHING
258 break;
259 case tflite::SparseIndexVector_Int32Vector:
260 os << dm->array_indices_as_Int32Vector()->values();
261 break;
262 case tflite::SparseIndexVector_Uint16Vector:
263 os << dm->array_indices_as_Uint16Vector()->values();
264 break;
265 case tflite::SparseIndexVector_Uint8Vector:
266 os << dm->array_indices_as_Uint8Vector()->values();
267 break;
268 default:
269 throw std::runtime_error("Invalid SparseIndexVector type of array_indices");
270 }
271 os << ")" << std::endl << strsindent;
272 }
273 }
274 }
275 os << std::endl;
276 }
277
278 // dump operators
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->size(); ++i)
284 {
285 const auto op = operators->Get(i);
286 tflite::BuiltinOperator builtincode = reader.builtin_code(op);
287
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);
291
292 os << "O(" << reader.subgraph_index() << ":" << i << ") " << op_name << " ";
293 os << std::endl;
294
295 if (auto op_prn = OpPrinterRegistry::get().lookup(builtincode))
296 {
297 op_prn->options(op, os);
298 }
299
300 for (auto input : inputs)
301 {
302 os << " I T(" << reader.subgraph_index() << ":" << input << ") ";
303 if (input >= 0)
304 {
305 auto tensor = tensors->Get(input);
306 os << mio::tflite::tensor_name(tensor);
307 }
308 os << std::endl;
309 }
310 for (auto output : outputs)
311 {
312 os << " O T(" << reader.subgraph_index() << ":" << output << ") ";
313 if (output >= 0)
314 {
315 auto tensor = tensors->Get(output);
316 os << mio::tflite::tensor_name(tensor);
317 }
318 os << std::endl;
319 }
320 }
321 os << std::endl;
322
323 // dump network inputs/outputs
324 os << "Inputs/Outputs: I(input)/O(output) T(tensor index) OperandName" << std::endl;
325
326 for (const auto input : reader.inputs())
327 {
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;
331 }
332
333 for (const auto output : reader.outputs())
334 {
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;
338 }
339
340 os << std::endl;
341}
342
343void dump_model(std::ostream &os, const tflite::Model *model, const std::vector<char> *rawdata)
344{
345 tflread::Reader reader(model, rawdata);
346
347 uint32_t num_subgraph = reader.num_subgraph();
348
349 // dump model version
350 os << "===================================================================" << std::endl;
351 os << "Model version: " << reader.version() << std::endl;
352 os << " # sub graphs: " << num_subgraph << std::endl;
353 os << std::endl;
354
355 auto opcodes = reader.opcodes();
356 auto buffers = reader.buffers();
357 auto metadata = reader.metadata();
358 auto signaturedefs = reader.signaturedefs();
359
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)
364 {
365 tflite::BuiltinOperator op_code = opcode->builtin_code();
366 tflite::BuiltinOperator dp_code = tflite::BuiltinOperator(opcode->deprecated_builtin_code());
367
368 auto op_name = mio::tflite::opcode_name(opcode);
369 auto op_version = opcode->version();
370
371 os << "[" << opcode_index << "] " << op_name << " (code: " << op_code
372 << ", dep_code: " << dp_code << ", version: " << op_version << ")" << std::endl;
373
374 opcode_index++;
375 }
376 os << std::endl;
377
378 // dump buffer
379 os << "Buffers: B(index) (length) values, if any; (length *) for ext_offset" << std::endl;
380 for (uint32_t i = 0; i < buffers->size(); ++i)
381 {
382 bool ext_offset = false;
383 const uint8_t *buff_data;
384 size_t size = reader.buffer_info(i, &buff_data, ext_offset);
385
386 os << "B(" << i << ") (" << size;
387 if (ext_offset)
388 os << " *";
389 os << ") ";
390 if (buff_data != nullptr)
391 {
392 dump_buffer(os, buff_data, size, 16);
393 }
394 os << std::endl;
395 }
396 os << std::endl;
397
398 // dump metadata
399 if (metadata != nullptr)
400 {
401 os << "metadata : B(index) name" << std::endl;
402 for (uint32_t i = 0; i < metadata->size(); ++i)
403 {
404 os << "B(" << metadata->Get(i)->buffer() << ") " << metadata->Get(i)->name()->c_str()
405 << std::endl;
406 }
407 os << std::endl;
408 }
409
410 // dump signaturedef
411 if (signaturedefs != nullptr)
412 {
413 os << "SignatureDef" << std::endl;
414 for (uint32_t i = 0; i < signaturedefs->size(); ++i)
415 {
416 auto sign_i = signaturedefs->Get(i);
417 os << "S(" << i << ") signature_key(" << sign_i->signature_key()->c_str() << "), sub_graph("
418 << sign_i->subgraph_index() << ")" << std::endl;
419
420 auto inputs_i = sign_i->inputs();
421 for (uint32_t t = 0; t < inputs_i->size(); ++t)
422 {
423 auto inputs_i_t = inputs_i->Get(t);
424 os << " I(" << t << ")"
425 << " T(" << sign_i->subgraph_index() << ":" << inputs_i_t->tensor_index() << ") "
426 << inputs_i_t->name()->c_str() << std::endl;
427 }
428
429 auto outputs_i = sign_i->outputs();
430 for (uint32_t t = 0; t < outputs_i->size(); ++t)
431 {
432 auto outputs_i_t = outputs_i->Get(t);
433 os << " O(" << t << ")"
434 << " T(" << sign_i->subgraph_index() << ":" << outputs_i_t->tensor_index() << ") "
435 << outputs_i_t->name()->c_str() << std::endl;
436 }
437 }
438 os << std::endl;
439 }
440
441 for (uint32_t sg = 0; sg < num_subgraph; ++sg)
442 {
443 reader.select_subgraph(sg);
444
445 os << "-------------------------------------------------------------------" << std::endl;
446 os << "Sub-Graph: #" << sg << " " << reader.subgraph_name() << std::endl;
447 os << std::endl;
448
449 dump_sub_graph(os, reader);
450 }
451
452 os << "===================================================================" << std::endl;
453}
454
455} // namespace tfldump
456
457std::ostream &operator<<(std::ostream &os, const tfldump::ModelEx &modelex)
458{
459 tfldump::dump_model(os, modelex.model, modelex.rawdata);
460 return os;
461}
std::ostream & operator<<(std::ostream &os, const circledump::ModelEx &modelex)
Definition Dump.cpp:467
return_type Get(uoffset_t i) const
uoffset_t size() const
static OpPrinterRegistry & get()
Definition OpPrinter.h:49
Loads TF lite file and provides helpers to access attributes.
Definition Read.h:43
uint32_t num_subgraph() const
Definition Read.h:70
const TFliteOperators_t * operators()
Definition Read.h:64
const std::vector< const tflite::OperatorCode * > & opcodes()
Definition Read.h:61
tflite::BuiltinOperator builtin_code(const tflite::Operator *op) const
Definition Read.cpp:123
const std::vector< int32_t > & inputs() const
Definition Read.h:65
size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data)
Definition Read.cpp:60
const TFliteBuffers_t * buffers()
Definition Read.h:62
uint32_t subgraph_index(void) const
Definition Read.h:80
const std::vector< int32_t > & outputs() const
Definition Read.h:66
bool select_subgraph(uint32_t subgraph)
Definition Read.cpp:148
const TFliteSignatureDef_t * signaturedefs() const
Definition Read.h:68
uint32_t version() const
Definition Read.h:59
const TFliteTensors_t * tensors()
Definition Read.h:63
const std::string & subgraph_name(void) const
Definition Read.h:79
std::string opcode_name(const tflite::Operator *op) const
Definition Read.cpp:132
const TFliteMetadata_t * metadata() const
Definition Read.h:67
std::string opcode_name(const ::tflite::OperatorCode *opcode)
Definition Helper.cpp:61
const char * tensor_type(const ::tflite::Tensor *tensor)
Definition Helper.cpp:87
const char * tensor_name(const ::tflite::Tensor *tensor)
Definition Helper.cpp:92
Definition Dump.h:25
void dump_fbvect(std::ostream &os, const flatbuffers::Vector< T > *fbvect, uint32_t size)
Definition Dump.cpp:78
void dump_sub_graph(std::ostream &os, tflread::Reader &reader)
Definition Dump.cpp:124
void dump_vector(std::ostream &os, const std::vector< int32_t > &vs)
Definition Dump.cpp:59
void dump_model(std::ostream &os, const ModelEx &model)
std::ostream & operator<<(std::ostream &os, const std::vector< int32_t > &vect)
Definition Dump.cpp:71
void dump_buffer(std::ostream &os, const uint8_t *buffer, size_t size, size_t amount)
Definition Dump.cpp:31
std::vector< T > as_index_vector(const flatbuffers::Vector< T > *flat_array)
Definition Read.h:29
int32_t size[5]
Definition Slice.cpp:35
const std::vector< char > * rawdata
Definition Dump.h:30
const tflite::Model * model
Definition Dump.h:29