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