2 // Copyright 2016-2018 Intel Corporation.
4 // This software and the related documents are Intel copyrighted materials,
5 // and your use of them is governed by the express license under which they
6 // were provided to you (End User License Agreement for the Intel(R) Software
7 // Development Products (Version May 2017)). Unless the License provides
8 // otherwise, you may not use, modify, copy, publish, distribute, disclose or
9 // transmit this software or the related documents without Intel's prior
10 // written permission.
12 // This software and the related documents are provided as is, with no
13 // express or implied warranties, other than those that are expressly
14 // stated in the License.
17 #include "blob_dump.h"
18 #include "blob_factory.hpp"
19 #include "mkldnn_memory.h"
21 // It's so bad to include by relative path :-(
22 #include "../../thirdparty/mkl-dnn/src/common/memory_desc_wrapper.hpp"
26 using namespace InferenceEngine;
28 namespace MKLDNNPlugin {
30 // IEB file format routine
31 static unsigned char IEB_MAGIC[4] = {'I', 'E', 'B', '0'};
32 static unsigned char NO_SCALES = 0xFF;
35 unsigned char magic[4];
38 unsigned char precision; // 0-8
40 unsigned int dims[7]; // max is 7-D blob
42 unsigned char scaling_axis; // FF - no scaling
43 unsigned char reserved[3];
45 unsigned long data_offset;
46 unsigned long data_size;
47 unsigned long scaling_data_offset;
48 unsigned long scaling_data_size;
51 static IEB_HEADER prepare_header(const TensorDesc& desc) {
54 header.magic[0] = IEB_MAGIC[0];
55 header.magic[1] = IEB_MAGIC[1];
56 header.magic[2] = IEB_MAGIC[2];
57 header.magic[3] = IEB_MAGIC[3];
59 // IEB file format version 0.1
63 header.precision = desc.getPrecision();
65 if (desc.getDims().size() > 7)
66 THROW_IE_EXCEPTION << "Dumper support max 7D blobs";
68 header.ndims = desc.getDims().size();
69 for (int i = 0; i < header.ndims; i++)
70 header.dims[i] = desc.getDims()[i];
72 header.scaling_axis = NO_SCALES;
77 static TensorDesc parse_header(IEB_HEADER &header) {
78 if (header.magic[0] != IEB_MAGIC[0] ||
79 header.magic[1] != IEB_MAGIC[1] ||
80 header.magic[2] != IEB_MAGIC[2] ||
81 header.magic[3] != IEB_MAGIC[3])
82 THROW_IE_EXCEPTION << "Dumper cannot parse file. Wrong format.";
84 if (header.ver[0] != 0 ||
86 THROW_IE_EXCEPTION << "Dumper cannot parse file. Unsupported IEB format version.";
88 Precision prc = Precision(static_cast<Precision::ePrecision>(header.precision));
89 SizeVector dims(header.ndims);
90 for (int i = 0; i < header.ndims; i++)
91 dims[i] = header.dims[i];
93 return TensorDesc {prc, dims, plain_layout(dims)};
97 bool is_plain(Blob::Ptr blob) {
100 auto orig_strides = blob->getTensorDesc().getBlockingDesc().getStrides();
101 auto orig_order = blob->getTensorDesc().getBlockingDesc().getOrder();
102 auto dims = blob->getTensorDesc().getDims();
104 for (int stride = 1, i = dims.size()-1; i >= 0; --i) {
105 if (stride != orig_strides[i] || i != orig_order[i]) res = false;
112 static Blob::Ptr prepare_plain_data(Blob::Ptr blob) {
113 // check if it already plain
114 if (is_plain(blob)) return blob;
116 Blob::Ptr pln_blob = make_plain_blob(blob->precision(), blob->getTensorDesc().getDims());
117 pln_blob->allocate();
120 MKLDNNMemoryDesc mdesc(blob->getTensorDesc());
121 mkldnn::memory::desc desc = mdesc;
122 mkldnn::impl::memory_desc_wrapper blob_wrp(desc.data);
124 int data_size = blob->size();
126 // TODO: make it with blob_copy utility
127 switch (blob->precision()) {
128 case Precision::FP32:
129 case Precision::I32: {
130 int32_t *pln_blob_ptr = pln_blob->buffer().as<int32_t*>();
131 int32_t *blob_ptr = blob->buffer().as<int32_t*>();
132 for (size_t i = 0; i < data_size; i++)
133 pln_blob_ptr[i] = blob_ptr[blob_wrp.off_l(i)];
137 case Precision::U16: {
138 int16_t *pln_blob_ptr = pln_blob->buffer().as<int16_t*>();
139 int16_t *blob_ptr = blob->buffer().as<int16_t *>();
140 for (size_t i = 0; i < data_size; i++)
141 pln_blob_ptr[i] = blob_ptr[blob_wrp.off_l(i)];
145 case Precision::U8: {
146 int8_t *pln_blob_ptr = pln_blob->buffer().as<int8_t*>();
147 int8_t *blob_ptr = blob->buffer().as<int8_t *>();
148 for (size_t i = 0; i < data_size; i++)
149 pln_blob_ptr[i] = blob_ptr[blob_wrp.off_l(i)];
153 THROW_IE_EXCEPTION << "Dumper. Unsupported precision";
159 void BlobDumper::dump(std::ostream &stream) {
161 THROW_IE_EXCEPTION << "Dumper cannot dump empty Blob";
163 if (_blob->buffer().as<float*>() == nullptr)
164 THROW_IE_EXCEPTION << "Dumper cannot dump. Blob is not allocated.";
166 IEB_HEADER header = prepare_header(_blob->getTensorDesc());
167 Blob::Ptr pln_blob = prepare_plain_data(_blob);
169 header.data_offset = sizeof(header);
170 header.data_size = pln_blob->byteSize();
171 header.scaling_data_offset = 0;
172 header.scaling_data_size = 0;
175 header.scaling_axis = 1;
176 header.scaling_data_offset = header.data_offset + header.data_size;
177 header.scaling_data_size = _scales->byteSize();
180 stream.write(reinterpret_cast<char*>(&header), sizeof(header));
181 stream.write(pln_blob->buffer().as<char*>(), pln_blob->byteSize());
184 stream.write(_scales->buffer().as<char*>(), _scales->byteSize());
188 void BlobDumper::dumpAsTxt(std::ostream &stream) {
190 THROW_IE_EXCEPTION << "Dumper cannot dump empty Blob";
192 if (_blob->buffer().as<float*>() == nullptr)
193 THROW_IE_EXCEPTION << "Dumper cannot dump. Blob is not allocated.";
195 SizeVector dims = _blob->getTensorDesc().getDims();
197 // Header like "U8 4D shape: 2 3 224 224 ()
198 stream << _blob->precision().name() << " "
199 << dims.size() << "D "
201 for (size_t d : dims) stream << d << " ";
202 stream << "(" << _blob->size() << ")" <<std::endl;
205 MKLDNNMemoryDesc mdesc(_blob->getTensorDesc());
206 mkldnn::memory::desc desc = mdesc;
207 mkldnn::impl::memory_desc_wrapper blob_wrp(desc.data);
209 int data_size = _blob->size();
210 switch (_blob->precision()) {
211 case Precision::FP32: {
212 auto *blob_ptr = _blob->buffer().as<float*>();
213 for (size_t i = 0; i < data_size; i++)
214 stream << blob_ptr[blob_wrp.off_l(i)] << std::endl;
217 case Precision::I32: {
218 auto *blob_ptr = _blob->buffer().as<int32_t*>();
219 for (size_t i = 0; i < data_size; i++)
220 stream << blob_ptr[blob_wrp.off_l(i)] << std::endl;
223 case Precision::I16: {
224 auto *blob_ptr = _blob->buffer().as<int16_t*>();
225 for (size_t i = 0; i < data_size; i++)
226 stream << static_cast<int>(blob_ptr[blob_wrp.off_l(i)]) << std::endl;
229 case Precision::U16: {
230 auto *blob_ptr = _blob->buffer().as<uint16_t*>();
231 for (size_t i = 0; i < data_size; i++)
232 stream << static_cast<int>(blob_ptr[blob_wrp.off_l(i)]) << std::endl;
235 case Precision::I8: {
236 auto *blob_ptr = _blob->buffer().as<int8_t*>();
237 for (size_t i = 0; i < data_size; i++)
238 stream << static_cast<int>(blob_ptr[blob_wrp.off_l(i)]) << std::endl;
241 case Precision::U8: {
242 auto *blob_ptr = _blob->buffer().as<uint8_t*>();
243 for (size_t i = 0; i < data_size; i++)
244 stream << static_cast<int>(blob_ptr[blob_wrp.off_l(i)]) << std::endl;
248 THROW_IE_EXCEPTION << "Dumper. Unsupported precision";
252 BlobDumper BlobDumper::read(std::istream &stream) {
254 stream.read(reinterpret_cast<char*>(&header), sizeof(header));
256 TensorDesc desc = parse_header(header);
257 Blob::Ptr blob = make_blob_with_precision(desc);
260 stream.seekg(header.data_offset, stream.beg);
261 stream.read(blob->buffer().as<char*>(), header.data_size);
263 BlobDumper res(blob);
265 // Parse scales fields.
266 if (header.scaling_axis != NO_SCALES) {
267 if (header.scaling_axis != 1)
268 THROW_IE_EXCEPTION << "Dumper support scaling only for channel dims.";
270 size_t scl_size = header.scaling_data_size / sizeof(float);
271 auto scl = make_blob_with_precision({Precision::FP32, {scl_size}, C});
274 stream.seekg(header.scaling_data_offset, stream.beg);
275 stream.read(scl->buffer().as<char*>(), header.scaling_data_size);
282 BlobDumper BlobDumper::read(const std::string &file_path) {
284 file.open(file_path);
286 THROW_IE_EXCEPTION << "Dumper cannot open file " << file_path;
288 auto res = read(file);
293 void BlobDumper::dump(const std::string &dump_path) {
294 std::ofstream dump_file;
295 dump_file.open(dump_path);
296 if (!dump_file.is_open())
297 THROW_IE_EXCEPTION << "Dumper cannot create dump file";
303 void BlobDumper::dumpAsTxt(const std::string dump_path) {
304 std::ofstream dump_file;
305 dump_file.open(dump_path);
306 if (!dump_file.is_open())
307 THROW_IE_EXCEPTION << "Dumper cannot create dump file";
309 dumpAsTxt(dump_file);
313 Blob::Ptr BlobDumper::get() {
317 template <typename data_t>
318 static void plain_copy(const Blob::Ptr &from, const Blob::Ptr &scls, Blob::Ptr &to) {
319 auto dims = from->getTensorDesc().getDims();
321 size_t data_size = from->size();
322 size_t outer_size = dims[0];
323 size_t c_size = dims.size() > 1 ? dims[1] : 1;
324 size_t inner_size = dims.size() == 4 ? dims[2]*dims[3] :
325 dims.size() == 3 ? dims[2] : 1;
327 auto to_data = to->buffer().as<float*>();
328 auto from_data = from->buffer().as<data_t*>();
331 auto scls_data = scls->buffer().as<float*>();
333 for (size_t o=0; o < outer_size; o++)
334 for (size_t c=0; c < c_size; c++)
335 for (size_t i=0; i < inner_size; i++)
336 *to_data++ = static_cast<float>(*from_data++) * scls_data[c];
338 for (size_t i=0; i < data_size; i++)
339 *to_data++ = static_cast<float>(*from_data++);
343 Blob::Ptr BlobDumper::getRealValue() {
344 if (_blob->precision() == Precision::FP32 && !_scales)
347 auto res = make_plain_blob(Precision::FP32, _blob->getTensorDesc().getDims());
350 switch (_blob->precision()) {
351 case Precision::U8: plain_copy<uint8_t>(_blob, _scales, res); break;
352 case Precision::FP32: plain_copy<float>(_blob, _scales, res); break;
353 case Precision::I8: plain_copy<int8_t >(_blob, _scales, res); break;
354 default: THROW_IE_EXCEPTION << "Unsupported precesion for getRealValue method.";
361 BlobDumper& BlobDumper::withScales(InferenceEngine::Blob::Ptr scales) {
362 if ( _blob->getTensorDesc().getDims().size() < 2 ||
363 scales->getTensorDesc().getDims().size() != 1 ||
364 scales->getTensorDesc().getDims()[0] != _blob->getTensorDesc().getDims()[1] ||
365 scales->getTensorDesc().getPrecision() != Precision::FP32)
366 THROW_IE_EXCEPTION << "Dumper cannot use passed scales. Blob has incompatible shape.";
372 BlobDumper& BlobDumper::withoutScales() {
378 const InferenceEngine::Blob::Ptr& BlobDumper::getScales() const {
382 } // namespace MKLDNNPlugin