2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
31 void print_comma_sepearted(std::ostream &os, const flatbuffers::Vector<T> *vec)
35 for (auto iter = vec->begin(); iter != vec->end(); iter++)
37 if (iter != vec->begin())
43 void print_buffer(std::ostream &os, uint32_t buff_idx, const flatbuffers::Vector<uint8_t> *data_ptr,
44 const circle::TensorType &type)
46 if (data_ptr == nullptr)
49 os << " └── buffer" << std::endl;
50 os << " ├── index : " << buff_idx << std::endl;
51 size_t buff_size = data_ptr->size();
52 os << " ├── size : " << buff_size << std::endl;
56 case circle::TensorType_UINT8:
58 const uint8_t *buff_data_ui8 = reinterpret_cast<const uint8_t *>(data_ptr->data());
59 for (uint32_t idx = 0; idx < buff_size / sizeof(uint8_t); idx++)
61 os << static_cast<const uint32_t>(buff_data_ui8[idx]) << ", ";
65 case circle::TensorType_INT32:
67 const int32_t *buff_data_i32 = reinterpret_cast<const int32_t *>(data_ptr->data());
68 for (uint32_t idx = 0; idx < buff_size / sizeof(int32_t); idx++)
70 os << buff_data_i32[idx] << ", ";
74 case circle::TensorType_INT64:
76 const int64_t *buff_data_i64 = reinterpret_cast<const int64_t *>(data_ptr->data());
77 for (uint32_t idx = 0; idx < buff_size / sizeof(int64_t); idx++)
79 os << buff_data_i64[idx] << ", ";
83 case circle::TensorType_FLOAT32:
85 const float *buff_data_f32 = reinterpret_cast<const float *>(data_ptr->data());
86 for (uint32_t idx = 0; idx < buff_size / sizeof(float); idx++)
88 os << buff_data_f32[idx] << ", ";
93 throw std::runtime_error("NYI tensor type : " + std::to_string(type));
100 namespace circletensordump
103 void DumpTensors::run(std::ostream &os, const circle::Model *model, const std::string &)
105 circletensordump::Reader reader(model);
106 uint32_t num_subgraph = reader.num_subgraph();
107 auto buffers = reader.buffers();
109 for (uint32_t subgraph_idx = 0; subgraph_idx < num_subgraph; subgraph_idx++)
111 reader.select_subgraph(subgraph_idx);
113 auto tensors = reader.tensors();
114 for (const auto &tensor : *tensors)
116 os << std::string(70, '-') << std::endl;
117 os << "[" << tensor->name()->str() << "]" << std::endl;
118 auto buff_idx = tensor->buffer();
119 auto buff_data_ptr = reader.buffers()->Get(buff_idx)->data();
120 auto quant_param = tensor->quantization();
121 std::string print_format = (!buff_data_ptr && !quant_param) ? "└──" : "├──";
124 auto shape = tensor->shape();
125 os << " " + print_format + " shape : (";
126 ::print_comma_sepearted(os, shape);
127 os << ")" << std::endl;
129 // quantization paramters
132 std::string print_format1 = buff_data_ptr ? "├──" : "└──";
133 std::string print_format2 = buff_data_ptr ? "│" : " ";
134 os << " " + print_format1 + " quantization" << std::endl;
135 auto min = quant_param->min();
136 auto max = quant_param->max();
137 auto scale = quant_param->scale();
138 auto zero_point = quant_param->zero_point();
139 auto quantized_dimension = quant_param->quantized_dimension();
141 os << " " + print_format2 + " ├── min : ";
142 ::print_comma_sepearted(os, min);
144 os << " " + print_format2 + " ├── max : ";
145 ::print_comma_sepearted(os, max);
147 os << " " + print_format2 + " ├── scale : ";
148 ::print_comma_sepearted(os, scale);
150 os << " " + print_format2 + " ├── zero_point : ";
151 ::print_comma_sepearted(os, zero_point);
153 os << " " + print_format2 + " └── quantized_dimension : " << quantized_dimension;
158 print_buffer(os, buff_idx, buff_data_ptr, tensor->type());
164 } // namespace circletensordump
169 // HDF5 forbids the inclusion of '/' in the name.
170 std::string mangle(const std::string &name)
172 std::string ret{name};
173 std::replace(ret.begin(), ret.end(), '/', '_');
177 H5::PredType hdf5_dtype_cast(const circle::TensorType &circle_type)
181 case circle::TensorType_UINT8:
183 return H5::PredType::NATIVE_UINT8;
185 case circle::TensorType_INT32:
187 return H5::PredType::NATIVE_INT32;
189 case circle::TensorType_INT64:
191 return H5::PredType::NATIVE_INT64;
193 case circle::TensorType_FLOAT32:
195 return H5::PredType::NATIVE_FLOAT;
198 throw std::runtime_error("NYI tensor type : " + std::to_string(circle_type));
203 * In order to create a dataspace, its rank and dimensions are required as hsize_t type.
204 * This function converts flatbuffers::Vector<T> to std::vector<hsize_t>.
206 * If "dims" parameter is passed, the parameter will be converted. However, if
207 * not passed(nullptr), data is considered as a rank 1 vector.
209 template <typename T>
210 std::vector<hsize_t> hdf5_dims_cast(const flatbuffers::Vector<T> *data,
211 const flatbuffers::Vector<int32_t> *dims = nullptr)
213 std::vector<hsize_t> ret;
219 ret.at(0) = data->size();
223 const uint32_t rank = dims->size();
225 for (uint32_t d = 0; d < rank; d++)
227 ret.at(d) = dims->Get(d);
235 * This function writes vector data to given hdf5 file like below.
239 * ㄴDATASET "dataset_name"
243 template <typename T>
244 void write_vector_data_to_hdf5(H5::H5File &file, std::string &group_name, std::string dataset_name,
245 const H5::PredType &type, const flatbuffers::Vector<T> *data,
246 std::vector<hsize_t> dims)
250 auto dataspace = std::make_unique<H5::DataSpace>(dims.size(), dims.data());
251 auto dataset = std::make_unique<H5::DataSet>(
252 file.createDataSet(group_name + "/" + dataset_name, type, *dataspace));
253 dataset->write(data->data(), type);
256 /// @brief This function writes scalar data to given hdf5 file
257 template <typename T>
258 void write_scalar_data_to_hdf5(H5::H5File &file, std::string &group_name, std::string dataset_name,
259 const H5::PredType &type, T data)
261 auto dataspace = std::make_unique<H5::DataSpace>(H5S_SCALAR);
262 auto dataset = std::make_unique<H5::DataSet>(
263 file.createDataSet(group_name + "/" + dataset_name, type, *dataspace));
264 dataset->write(&data, type);
269 namespace circletensordump
273 * HDF5 layout is like below
276 * ㄴGROUP "tensor name"
277 * ㄴDATASET "weights" : Shape (x, y, ...), type(uint8, int16)
278 * ㄴDATASET "min" : Shape (n)
279 * ㄴDATASET "max" : Shape (n)
280 * ㄴDATASET "scale" : Shape (m)
281 * ㄴDATASET "zero_point" : Shape (m)
283 * NOTE All Dataset is optional. It means that if tensor doesn't have the data, it won't be created
287 void DumpTensorsToHdf5::run(std::ostream &os, const circle::Model *model,
288 const std::string &output_path)
290 // loads a circle model
291 circletensordump::Reader reader(model);
292 uint32_t num_subgraph = reader.num_subgraph();
294 // create a hdf5 file
295 H5::H5File file{output_path, H5F_ACC_TRUNC};
297 for (uint32_t subgraph_idx = 0; subgraph_idx < num_subgraph; subgraph_idx++)
299 reader.select_subgraph(subgraph_idx);
301 auto tensors = reader.tensors();
302 for (const auto &tensor : *tensors)
304 // create a group for each tensor whose name is its tensor name
305 std::string group_name = ::mangle(tensor->name()->c_str());
306 std::unique_ptr<H5::Group> tensor_group =
307 std::make_unique<H5::Group>(file.createGroup(group_name));
309 // write a buffer data
310 uint32_t buff_idx = tensor->buffer();
311 auto buff_data_ptr = reader.buffers()->Get(buff_idx)->data();
314 ::write_vector_data_to_hdf5(file, group_name, "weights", ::hdf5_dtype_cast(tensor->type()),
316 ::hdf5_dims_cast(buff_data_ptr, tensor->shape()));
319 // write quantization parameters
320 auto quant_param = tensor->quantization();
323 auto min = quant_param->min();
324 ::write_vector_data_to_hdf5(file, group_name, "min", H5::PredType::NATIVE_FLOAT, min,
325 ::hdf5_dims_cast(min));
326 auto max = quant_param->max();
327 ::write_vector_data_to_hdf5(file, group_name, "max", H5::PredType::NATIVE_FLOAT, max,
328 ::hdf5_dims_cast(max));
329 auto scale = quant_param->scale();
330 ::write_vector_data_to_hdf5(file, group_name, "scale", H5::PredType::NATIVE_FLOAT, scale,
331 ::hdf5_dims_cast(scale));
332 auto zero_point = quant_param->zero_point();
333 ::write_vector_data_to_hdf5(file, group_name, "zero_point", H5::PredType::NATIVE_INT64,
334 zero_point, ::hdf5_dims_cast(zero_point));
335 auto quantized_dimension = quant_param->quantized_dimension();
336 ::write_scalar_data_to_hdf5(file, group_name, "quantized_dimension",
337 H5::PredType::NATIVE_INT32, quantized_dimension);
343 } // namespace circletensordump