diff options
Diffstat (limited to 'compiler/tfldump/src/Dump.cpp')
-rw-r--r-- | compiler/tfldump/src/Dump.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/compiler/tfldump/src/Dump.cpp b/compiler/tfldump/src/Dump.cpp new file mode 100644 index 000000000..e6b84251a --- /dev/null +++ b/compiler/tfldump/src/Dump.cpp @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <tfldump/Dump.h> + +#include "Read.h" +#include "OpPrinter.h" + +#include <ostream> + +#include <algorithm> // min +#include <iomanip> // setfill + +namespace tfldump +{ + +void dump_buffer(std::ostream &os, const uint8_t *buffer, size_t size, size_t amount) +{ + std::ios_base::fmtflags saveflags(os.flags()); + + bool second = false; + bool ellipsis = amount > 0 && size > 4; + size_t count = ellipsis ? std::min(size, amount) : size; + + for (size_t i = 0; i < count; i++) + { + if (second) + { + os << " "; + } + + os << std::showbase << std::setfill('0') << std::setw(2); + os << std::hex << (uint32_t)buffer[i]; + + second = true; + } + if (ellipsis) + { + os << " ..."; + } + + os.flags(saveflags); +} + +void dump_vector(std::ostream &os, const std::vector<int32_t> &vs) +{ + uint32_t seq = 0; + for (auto &v : vs) + { + if (seq) + os << ", "; + os << v; + seq++; + } +} + +std::ostream &operator<<(std::ostream &os, const std::vector<int32_t> &vect) +{ + tfldump::dump_vector(os, vect); + return os; +} + +template <typename T> void dump_fbvect(std::ostream &os, const flatbuffers::Vector<T> *fbvect) +{ + if (fbvect == nullptr) + return; + + bool ellipsis = (fbvect->size() > 4); + auto limit_size = ellipsis ? 4 : fbvect->size(); + + if (ellipsis) + { + os << "(" << fbvect->size() << ") "; + } + for (uint32_t q = 0; q < limit_size; q++) + { + if (q) + os << ", "; + os << fbvect->Get(q); + } + if (ellipsis) + { + os << " ... "; + } +} + +template <typename T> +std::ostream &operator<<(std::ostream &os, const flatbuffers::Vector<T> *fbvect) +{ + dump_fbvect(os, fbvect); + return os; +} + +void dump_sub_graph(std::ostream &os, tflread::Reader &reader) +{ + auto tensors = reader.tensors(); + auto operators = reader.operators(); + + // dump operands(tensors) + os << "Operands: T(subgraph index : tensor index) TYPE (shape) B(buffer index) OperandName" + << std::endl; + for (uint32_t i = 0; i < tensors->Length(); ++i) + { + // TODO refactor to some better structure + auto tensor = tensors->Get(i); + std::vector<int32_t> dims = {-1}; + + if (tensor->shape()) + dims = tflread::as_index_vector(tensor->shape()); + + os << "T(" << reader.subgraph_index() << ":" << i << ") " << tflread::tensor_type(tensor) + << " "; + os << "(" << dims << ") "; + os << "B(" << tensor->buffer() << ") "; + os << tflread::tensor_name(tensor) << std::endl; + + if (auto q_params = tensor->quantization()) + { + if ((q_params->min() && q_params->max()) || (q_params->scale() && q_params->zero_point())) + { + std::string strquantiz = " Quantization: "; + std::string strqindent(strquantiz.size(), ' '); + os << strquantiz; + + if (q_params->min()) + { + os << "min(" << q_params->min() << ") "; + if (q_params->min()->size() > 1) + os << std::endl << strqindent; + } + if (q_params->max()) + { + os << "max(" << q_params->max() << ") "; + if (q_params->max()->size() > 1) + os << std::endl << strqindent; + } + if (q_params->scale()) + { + os << "scale(" << q_params->scale() << ") "; + if (q_params->scale()->size() > 1) + os << std::endl << strqindent; + } + if (q_params->zero_point()) + os << "zeropt(" << q_params->zero_point() << ") "; + + os << std::endl; + } + } + } + os << std::endl; + + // dump operators + os << "Operators: O(subgraph index : operator index) OpCodeName " << std::endl; + os << " Option(values) ... <-- depending on OpCode" << std::endl; + os << " I T(tensor index) OperandName <-- as input" << std::endl; + os << " O T(tensor index) OperandName <-- as output" << std::endl; + for (uint32_t i = 0; i < operators->Length(); ++i) + { + const auto op = operators->Get(i); + tflite::BuiltinOperator builtincode = reader.builtin_code(op); + + const std::vector<int32_t> &inputs = tflread::as_index_vector(op->inputs()); + const std::vector<int32_t> &outputs = tflread::as_index_vector(op->outputs()); + auto op_name = reader.opcode_name(op); + + os << "O(" << reader.subgraph_index() << ":" << i << ") " << op_name << " "; + os << std::endl; + + if (auto op_prn = OpPrinterRegistry::get().lookup(builtincode)) + { + op_prn->options(op, os); + } + + for (auto input : inputs) + { + os << " I T(" << input << ") "; + if (input >= 0) + { + auto tensor = tensors->Get(input); + os << tflread::tensor_name(tensor); + } + os << std::endl; + } + for (auto output : outputs) + { + os << " O T(" << output << ") "; + if (output >= 0) + { + auto tensor = tensors->Get(output); + os << tflread::tensor_name(tensor); + } + os << std::endl; + } + } + os << std::endl; + + // dump network inputs/outputs + os << "Inputs/Outputs: I(input)/O(output) T(tensor index) OperandName" << std::endl; + + for (const auto input : reader.inputs()) + { + auto tensor = tensors->Get(input); + std::string name = tflread::tensor_name(tensor); + os << "I T(" << input << ") " << name << std::endl; + } + + for (const auto output : reader.outputs()) + { + auto tensor = tensors->Get(output); + std::string name = tflread::tensor_name(tensor); + os << "O T(" << output << ") " << name << std::endl; + } + + os << std::endl; +} + +void dump_model(std::ostream &os, const tflite::Model *model) +{ + tflread::Reader reader(model); + + uint32_t num_subgraph = reader.num_subgraph(); + + // dump model version + os << "===================================================================" << std::endl; + os << "Model version: " << reader.version() << std::endl; + os << " # sub graphs: " << num_subgraph << std::endl; + os << std::endl; + + auto opcodes = reader.opcodes(); + auto buffers = reader.buffers(); + + // dump operator_codes + os << "Operator Codes: [order] OpCodeName (OpCode Enum)" << std::endl; + int32_t opcode_index = 0; + for (auto opcode : opcodes) + { + tflite::BuiltinOperator op_code = opcode->builtin_code(); + auto op_name = tflread::opcode_name(opcode); + auto op_version = opcode->version(); + + os << "[" << opcode_index << "] " << op_name << " (code: " << op_code + << ", version: " << op_version << ")" << std::endl; + + opcode_index++; + } + os << std::endl; + + // dump buffer + os << "Buffers: B(index) (length) values, if any" << std::endl; + for (uint32_t i = 0; i < buffers->Length(); ++i) + { + const uint8_t *buff_data; + size_t size = reader.buffer_info(i, &buff_data); + + os << "B(" << i << ") (" << size << ") "; + if (buff_data != nullptr) + { + dump_buffer(os, buff_data, size, 16); + } + os << std::endl; + } + os << std::endl; + + for (uint32_t sg = 0; sg < num_subgraph; ++sg) + { + reader.select_subgraph(sg); + + os << "-------------------------------------------------------------------" << std::endl; + os << "Sub-Graph: #" << sg << " " << reader.subgraph_name() << std::endl; + os << std::endl; + + dump_sub_graph(os, reader); + } + + os << "===================================================================" << std::endl; +} + +} // namespace tfldump + +std::ostream &operator<<(std::ostream &os, const tflite::Model *model) +{ + tfldump::dump_model(os, model); + return os; +} |