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 if (q_params->details_type() == circle::QuantizationDetails_MXQuantization)
195 {
196 const auto &mx_params = q_params->details_as_MXQuantization();
197 std::string strquantiz = " MX Quantization: ";
198 os << strquantiz;
199 os << "axis (" << mx_params->axis() << ")" << std::endl;
200
201 os << std::endl;
202 }
203 }
204
205 if (const auto &s_params = tensor->sparsity())
206 {
207 std::string strsparsity = " Sparsity: ";
208 std::string strsindent(strsparsity.size(), ' ');
209 os << strsparsity;
210
211 if (s_params->traversal_order())
212 {
213 os << "traversal_order(" << s_params->traversal_order() << ") ";
214 os << std::endl << strsindent;
215 }
216 if (s_params->block_map())
217 {
218 os << "block_map(" << s_params->block_map() << ") ";
219 os << std::endl << strsindent;
220 }
221 if (const auto &dim_metadata = s_params->dim_metadata())
222 {
223 uint32_t idx = 0;
224 for (const auto &dm : *dim_metadata)
225 {
226 std::string strdm = "dim_metadata[" + std::to_string(idx++) + "]: ";
227 std::string strdm_indent = strsindent + std::string(strdm.size(), ' ');
228 os << strdm;
229
230 os << "format(" << circle::EnumNameDimensionType(dm->format()) << ") ";
231 os << std::endl << strdm_indent;
232
233 os << "dense_size(" << dm->dense_size() << ") ";
234 os << std::endl << strdm_indent;
235
236 os << "array_segments_type("
237 << circle::EnumNameSparseIndexVector(dm->array_segments_type()) << ") ";
238 os << std::endl << strdm_indent;
239
240 os << "array_segments(";
241 switch (dm->array_segments_type())
242 {
243 case circle::SparseIndexVector_NONE:
244 // DO NOTHING
245 break;
246 case circle::SparseIndexVector_Int32Vector:
247 os << dm->array_segments_as_Int32Vector()->values();
248 break;
249 case circle::SparseIndexVector_Uint16Vector:
250 os << dm->array_segments_as_Uint16Vector()->values();
251 break;
252 case circle::SparseIndexVector_Uint8Vector:
253 os << dm->array_segments_as_Uint8Vector()->values();
254 break;
255 default:
256 throw std::runtime_error("Invalid SparseIndexVector type of array_segments");
257 }
258 os << ")" << std::endl << strdm_indent;
259
260 os << "array_indices_type(" << circle::EnumNameSparseIndexVector(dm->array_indices_type())
261 << ") ";
262 os << std::endl << strdm_indent;
263
264 os << "array_indices(";
265 switch (dm->array_indices_type())
266 {
267 case circle::SparseIndexVector_NONE:
268 // DO NOTHING
269 break;
270 case circle::SparseIndexVector_Int32Vector:
271 os << dm->array_indices_as_Int32Vector()->values();
272 break;
273 case circle::SparseIndexVector_Uint16Vector:
274 os << dm->array_indices_as_Uint16Vector()->values();
275 break;
276 case circle::SparseIndexVector_Uint8Vector:
277 os << dm->array_indices_as_Uint8Vector()->values();
278 break;
279 default:
280 throw std::runtime_error("Invalid SparseIndexVector type of array_indices");
281 }
282 os << ")" << std::endl << strsindent;
283 }
284 }
285 }
286 os << std::endl;
287 }
288
289 // dump operators
290 os << "Operators: O(subgraph index : operator index) OpCodeName " << std::endl;
291 os << " Option(values) ... <-- depending on OpCode" << std::endl;
292 os << " I T(tensor index) OperandName <-- as input" << std::endl;
293 os << " O T(tensor index) OperandName <-- as output" << std::endl;
294 for (uint32_t i = 0; i < operators->size(); ++i)
295 {
296 const auto op = operators->Get(i);
297 circle::BuiltinOperator builtincode = reader.builtin_code(op);
298
299 const std::vector<int32_t> &inputs = mio::circle::as_index_vector(op->inputs());
300 const std::vector<int32_t> &outputs = mio::circle::as_index_vector(op->outputs());
301 auto op_name = reader.opcode_name(op);
302
303 os << "O(" << reader.subgraph_index() << ":" << i << ") " << op_name << " ";
304 os << std::endl;
305
306 if (auto op_prn = OpPrinterRegistry::get().lookup(builtincode))
307 {
308 op_prn->options(op, os);
309 }
310
311 for (auto input : inputs)
312 {
313 os << " I T(" << reader.subgraph_index() << ":" << input << ") ";
314 if (input >= 0)
315 {
316 auto tensor = tensors->Get(input);
317 os << mio::circle::tensor_name(tensor);
318 }
319 os << std::endl;
320 }
321 for (auto output : outputs)
322 {
323 os << " O T(" << reader.subgraph_index() << ":" << output << ") ";
324 if (output >= 0)
325 {
326 auto tensor = tensors->Get(output);
327 os << mio::circle::tensor_name(tensor);
328 }
329 os << std::endl;
330 }
331 }
332 os << std::endl;
333
334 // dump network inputs/outputs
335 os << "Inputs/Outputs: I(input)/O(output) T(tensor index) OperandName" << std::endl;
336
337 for (const auto input : reader.inputs())
338 {
339 auto tensor = tensors->Get(input);
340 std::string name = mio::circle::tensor_name(tensor);
341 os << "I T(" << reader.subgraph_index() << ":" << input << ") " << name << std::endl;
342 }
343
344 for (const auto output : reader.outputs())
345 {
346 auto tensor = tensors->Get(output);
347 std::string name = mio::circle::tensor_name(tensor);
348 os << "O T(" << reader.subgraph_index() << ":" << output << ") " << name << std::endl;
349 }
350
351 os << std::endl;
352}
353
354void dump_model(std::ostream &os, const circle::Model *model, const std::vector<char> *rawdata)
355{
356 mio::circle::Reader reader(model, rawdata);
357
358 uint32_t num_subgraph = reader.num_subgraph();
359
360 // dump model version
361 os << "===================================================================" << std::endl;
362 os << "Model version: " << reader.version() << std::endl;
363 os << " # sub graphs: " << num_subgraph << std::endl;
364 os << std::endl;
365
366 auto opcodes = reader.opcodes();
367 auto buffers = reader.buffers();
368 auto metadata = reader.metadata();
369 auto signaturedefs = reader.signature_defs();
370
371 // dump operator_codes
372 os << "Operator Codes: [order] OpCodeName (OpCode Enum)" << std::endl;
373 int32_t opcode_index = 0;
374 for (auto opcode : opcodes)
375 {
376 circle::BuiltinOperator op_code = opcode->builtin_code();
377 // cast to int32_t to print as number or int8_t will print as ascii code
378 int32_t dp_code = static_cast<int32_t>(opcode->deprecated_builtin_code());
379
380 auto op_name = mio::circle::opcode_name(opcode);
381 auto op_version = opcode->version();
382
383 os << "[" << opcode_index << "] " << op_name << " (code: " << op_code
384 << ", dep_code: " << dp_code << ", version: " << op_version << ")" << std::endl;
385
386 opcode_index++;
387 }
388 os << std::endl;
389
390 // dump buffer
391 os << "Buffers: B(index) (length) values, if any; (length *) for ext_offset" << std::endl;
392 for (uint32_t i = 0; i < buffers->size(); ++i)
393 {
394 bool ext_offset = false;
395 const uint8_t *buff_data;
396 size_t size = reader.buffer_info(i, &buff_data, ext_offset);
397
398 os << "B(" << i << ") (" << size;
399 if (ext_offset)
400 os << " *";
401 os << ") ";
402 if (buff_data != nullptr)
403 {
404 dump_buffer(os, buff_data, size, 16);
405 }
406 os << std::endl;
407 }
408 os << std::endl;
409
410 // dump metadata
411 if (metadata != nullptr)
412 {
413 os << "metadata : B(index) name" << std::endl;
414 for (uint32_t i = 0; i < metadata->size(); ++i)
415 {
416 const auto buff_id = metadata->Get(i)->buffer();
417 const auto metadata_name = metadata->Get(i)->name()->str();
418 os << "B(" << buff_id << ") " << metadata_name << std::endl;
419
420 const uint8_t *buff_data;
421 reader.buffer_info(buff_id, &buff_data);
422 if (auto meta_prn = MetadataPrinterRegistry::get().lookup(metadata_name))
423 {
424 meta_prn->print(buff_data, os);
425 }
426 }
427 os << std::endl;
428 }
429
430 // dump signaturedef
431 if (signaturedefs != nullptr)
432 {
433 os << "SignatureDef" << std::endl;
434 for (uint32_t i = 0; i < signaturedefs->size(); ++i)
435 {
436 auto sign_i = signaturedefs->Get(i);
437 os << "S(" << i << ") signature_key(" << sign_i->signature_key()->c_str() << "), sub_graph("
438 << sign_i->subgraph_index() << ")" << std::endl;
439
440 auto inputs_i = sign_i->inputs();
441 for (uint32_t t = 0; t < inputs_i->size(); ++t)
442 {
443 auto inputs_i_t = inputs_i->Get(t);
444 os << " I(" << t << ")"
445 << " T(" << sign_i->subgraph_index() << ":" << inputs_i_t->tensor_index() << ") "
446 << inputs_i_t->name()->c_str() << std::endl;
447 }
448
449 auto outputs_i = sign_i->outputs();
450 for (uint32_t t = 0; t < outputs_i->size(); ++t)
451 {
452 auto outputs_i_t = outputs_i->Get(t);
453 os << " O(" << t << ")"
454 << " T(" << sign_i->subgraph_index() << ":" << outputs_i_t->tensor_index() << ") "
455 << outputs_i_t->name()->c_str() << std::endl;
456 }
457 }
458 os << std::endl;
459 }
460
461 for (uint32_t sg = 0; sg < num_subgraph; ++sg)
462 {
463 reader.select_subgraph(sg);
464
465 os << "-------------------------------------------------------------------" << std::endl;
466 os << "Sub-Graph: #" << sg << " " << reader.subgraph_name() << std::endl;
467 os << std::endl;
468
469 dump_sub_graph(os, reader);
470 }
471
472 os << "===================================================================" << std::endl;
473}
474
475} // namespace circledump
476
477std::ostream &operator<<(std::ostream &os, const circledump::ModelEx &modelex)
478{
479 circledump::dump_model(os, modelex.model, modelex.rawdata);
480 return os;
481}
std::ostream & operator<<(std::ostream &os, const circledump::ModelEx &modelex)
Definition Dump.cpp:477
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