Imported Upstream version 1.25.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 #include <mio_tflite2121/Helper.h>
19
20 #include "Read.h"
21 #include "OpPrinter.h"
22
23 #include <ostream>
24
25 #include <algorithm> // min
26 #include <iomanip>   // setfill
27
28 namespace tfldump
29 {
30
31 void 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
59 void 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
71 std::ostream &operator<<(std::ostream &os, const std::vector<int32_t> &vect)
72 {
73   tfldump::dump_vector(os, vect);
74   return os;
75 }
76
77 template <typename T>
78 void 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
88 template <>
89 void 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
100 template <typename T>
101 std::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
124 void 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->Length(); ++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->Length(); ++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
343 void dump_model(std::ostream &os, const tflite::Model *model)
344 {
345   tflread::Reader reader(model);
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" << std::endl;
380   for (uint32_t i = 0; i < buffers->Length(); ++i)
381   {
382     const uint8_t *buff_data;
383     size_t size = reader.buffer_info(i, &buff_data);
384
385     os << "B(" << i << ") (" << size << ") ";
386     if (buff_data != nullptr)
387     {
388       dump_buffer(os, buff_data, size, 16);
389     }
390     os << std::endl;
391   }
392   os << std::endl;
393
394   // dump metadata
395   if (metadata != nullptr)
396   {
397     os << "metadata : B(index) name" << std::endl;
398     for (uint32_t i = 0; i < metadata->Length(); ++i)
399     {
400       os << "B(" << metadata->Get(i)->buffer() << ") " << metadata->Get(i)->name()->c_str()
401          << std::endl;
402     }
403     os << std::endl;
404   }
405
406   // dump signaturedef
407   if (signaturedefs != nullptr)
408   {
409     os << "SignatureDef" << std::endl;
410     for (uint32_t i = 0; i < signaturedefs->Length(); ++i)
411     {
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;
415
416       auto inputs_i = sign_i->inputs();
417       for (uint32_t t = 0; t < inputs_i->Length(); ++t)
418       {
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;
423       }
424
425       auto outputs_i = sign_i->outputs();
426       for (uint32_t t = 0; t < outputs_i->Length(); ++t)
427       {
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;
432       }
433     }
434     os << std::endl;
435   }
436
437   for (uint32_t sg = 0; sg < num_subgraph; ++sg)
438   {
439     reader.select_subgraph(sg);
440
441     os << "-------------------------------------------------------------------" << std::endl;
442     os << "Sub-Graph: #" << sg << " " << reader.subgraph_name() << std::endl;
443     os << std::endl;
444
445     dump_sub_graph(os, reader);
446   }
447
448   os << "===================================================================" << std::endl;
449 }
450
451 } // namespace tfldump
452
453 std::ostream &operator<<(std::ostream &os, const tflite::Model *model)
454 {
455   tfldump::dump_model(os, model);
456   return os;
457 }