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