ONE - On-device Neural Engine
Loading...
Searching...
No Matches
entry.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 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
20
21#include <H5Cpp.h>
22
23#include <cassert>
24#include <cmath>
25#include <cstdint>
26#include <iostream>
27#include <set>
28#include <stdexcept>
29#include <string>
30#include <vector>
31
32namespace
33{
34
35enum class ErrorCode
36{
37 CountMismatch,
38 TypeMismatch,
39 ShapeMismatch,
40 ValueMismatch,
41};
42
43template <ErrorCode EC> class ErrorDetail;
44
45// TODO Record the details
46template <> class ErrorDetail<ErrorCode::CountMismatch>
47{
48public:
49 ErrorDetail() = default;
50};
51
52// TODO Record the details
53template <> class ErrorDetail<ErrorCode::TypeMismatch>
54{
55public:
56 ErrorDetail() = default;
57};
58
59// TODO Record the details
60template <> class ErrorDetail<ErrorCode::ShapeMismatch>
61{
62public:
63 ErrorDetail() = default;
64};
65
66// TODO Record the details
67template <> class ErrorDetail<ErrorCode::ValueMismatch>
68{
69public:
70 ErrorDetail() = default;
71};
72
73struct Observer
74{
75 virtual ~Observer() = default;
76
77 virtual void notify(const ErrorDetail<ErrorCode::CountMismatch> &) = 0;
78 virtual void notify(const ErrorDetail<ErrorCode::TypeMismatch> &) = 0;
79 virtual void notify(const ErrorDetail<ErrorCode::ShapeMismatch> &) = 0;
80 virtual void notify(const ErrorDetail<ErrorCode::ValueMismatch> &) = 0;
81};
82
83class Mux final : public Observer
84{
85public:
86 Mux() = default;
87
88public:
89 void attach(Observer *o) { _observers.insert(o); }
90
91private:
92 template <ErrorCode EC> void notify_all(const ErrorDetail<EC> &e)
93 {
94 for (auto o : _observers)
95 {
96 o->notify(e);
97 }
98 }
99
100public:
101 void notify(const ErrorDetail<ErrorCode::CountMismatch> &e) final { notify_all(e); }
102 void notify(const ErrorDetail<ErrorCode::TypeMismatch> &e) final { notify_all(e); }
103 void notify(const ErrorDetail<ErrorCode::ShapeMismatch> &e) final { notify_all(e); }
104 void notify(const ErrorDetail<ErrorCode::ValueMismatch> &e) final { notify_all(e); }
105
106public:
107 std::set<Observer *> _observers;
108};
109
110class ExitcodeTracker final : public Observer
111{
112public:
113 const int &exitcode(void) const { return _exitcode; }
114
115public:
116 void notify(const ErrorDetail<ErrorCode::CountMismatch> &) { _exitcode = 1; }
117 void notify(const ErrorDetail<ErrorCode::TypeMismatch> &) { _exitcode = 1; }
118 void notify(const ErrorDetail<ErrorCode::ShapeMismatch> &) { _exitcode = 1; }
119 void notify(const ErrorDetail<ErrorCode::ValueMismatch> &) { _exitcode = 1; }
120
121public:
122 int _exitcode = 0;
123};
124
125} // namespace
126
127//
128// HDF5 helpers
129//
130namespace
131{
132
133enum class DataType
134{
135 UNKNOWN,
136 FLOAT32,
137 /* TO BE ADDED */
138};
139
140DataType to_internal_dtype(const H5::DataType &dtype)
141{
142 if (dtype == H5::PredType::IEEE_F32BE)
143 {
144 return DataType::FLOAT32;
145 }
146 return DataType::UNKNOWN;
147}
148
150
151TensorShape to_internal_shape(const H5::DataSpace &dataspace)
152{
153 int rank = dataspace.getSimpleExtentNdims();
154
155 std::vector<hsize_t> dims;
156
157 dims.resize(rank, 0);
158
159 dataspace.getSimpleExtentDims(dims.data());
160
161 TensorShape res;
162
163 res.resize(rank);
164 for (int axis = 0; axis < rank; ++axis)
165 {
166 res.dim(axis) = dims[axis];
167 }
168
169 return res;
170}
171
172uint32_t element_count(const H5::DataSpace &dataspace)
173{
174 return nncc::core::ADT::tensor::num_elements(to_internal_shape(dataspace));
175}
176
177std::vector<float> as_float_vector(const H5::DataSet &dataset)
178{
179 std::vector<float> buffer;
180
181 buffer.resize(element_count(dataset.getSpace()));
182 dataset.read(buffer.data(), H5::PredType::NATIVE_FLOAT);
183
184 return buffer;
185}
186
187using LexicalLayout = nncc::core::ADT::tensor::LexicalLayout;
188using TensorIndexEnumerator = nncc::core::ADT::tensor::IndexEnumerator;
189
190} // namespace
191
192// TODO Report the details
193int entry(int argc, char **argv)
194{
195 // The current implementation works only for command-line of the following form:
196 //
197 // i5diff -d 0.001 /path/to/left.h5 /path/to/right.h5
198 //
199 // TODO Support more options
200 assert(argc == 5);
201 assert(std::string(argv[1]) == "-d");
202 assert(std::string(argv[2]) == "0.001");
203
204 H5::H5File lhs{argv[3], H5F_ACC_RDONLY};
205 H5::H5File rhs{argv[4], H5F_ACC_RDONLY};
206
207 ExitcodeTracker exitcode_tracker;
208
209 Mux mux;
210 mux.attach(&exitcode_tracker);
211
212 // Compare values
213 do
214 {
215 // NOTE The name of value group SHOULD BE aligned with nnkit HDF5 actions
216 const std::string value_grpname{"value"};
217
218 H5::Group lhs_value_grp = lhs.openGroup(value_grpname);
219 H5::Group rhs_value_grp = rhs.openGroup(value_grpname);
220
221 // Compare value count
222 int64_t value_count = -1;
223 {
224 uint32_t lhs_value_count = static_cast<uint32_t>(lhs_value_grp.getNumObjs());
225 uint32_t rhs_value_count = static_cast<uint32_t>(rhs_value_grp.getNumObjs());
226
227 if (lhs_value_count != rhs_value_count)
228 {
229 ErrorDetail<ErrorCode::CountMismatch> error{};
230 mux.notify(error);
231 break;
232 }
233
234 value_count = std::max<int64_t>(lhs_value_count, rhs_value_count);
235 }
236 assert(value_count >= 0);
237
238 // Compare each dataset
239 for (int64_t n = 0; n < value_count; ++n)
240 {
241 // NOTE The name of dataset SHOULD BE aligned with nnkit HDF5 actions
242 const std::string dataset_name = std::to_string(n);
243
244 auto lhs_dataset = lhs_value_grp.openDataSet(dataset_name);
245 auto rhs_dataset = rhs_value_grp.openDataSet(dataset_name);
246
247 auto lhs_dtype = to_internal_dtype(lhs_dataset.getDataType());
248 auto rhs_dtype = to_internal_dtype(rhs_dataset.getDataType());
249
250 // TODO Support other data types
251 assert(rhs_dtype == DataType::FLOAT32);
252 assert(lhs_dtype == DataType::FLOAT32);
253
254 if (lhs_dtype != rhs_dtype)
255 {
256 ErrorDetail<ErrorCode::TypeMismatch> error{};
257 mux.notify(error);
258 continue;
259 }
260
261 auto lhs_shape = to_internal_shape(lhs_dataset.getSpace());
262 auto rhs_shape = to_internal_shape(rhs_dataset.getSpace());
263
264 if (!(lhs_shape == rhs_shape))
265 {
266 ErrorDetail<ErrorCode::ShapeMismatch> error{};
267 mux.notify(error);
268 continue;
269 }
270
271 assert(lhs_shape == rhs_shape);
272 assert(lhs_dtype == rhs_dtype);
273 const auto &shape = lhs_shape;
274 const auto &dtype = lhs_dtype;
275
276 switch (dtype)
277 {
278 case DataType::FLOAT32:
279 {
280 auto lhs_vector = as_float_vector(lhs_dataset);
281 auto rhs_vector = as_float_vector(rhs_dataset);
282
283 assert(lhs_vector.size() == rhs_vector.size());
284
285 LexicalLayout layout;
286
287 for (TensorIndexEnumerator e{shape}; e.valid(); e.advance())
288 {
289 const auto &ind = e.current();
290 auto lhs_value = lhs_vector.at(layout.offset(shape, ind));
291 auto rhs_value = rhs_vector.at(layout.offset(shape, ind));
292
293 // TODO Abstract equality criterion
294 if (std::abs(lhs_value - rhs_value) >= 0.001f)
295 {
296 ErrorDetail<ErrorCode::ValueMismatch> error{};
297 mux.notify(error);
298 continue;
299 }
300 }
301
302 break;
303 }
304 default:
305 throw std::runtime_error{"Not supported, yet"};
306 };
307 }
308 } while (false);
309
310 // TODO Compare names (if requested)
311
312 return exitcode_tracker.exitcode();
313}
uint32_t & dim(uint32_t axis)
Definition Shape.cpp:42
Shape & resize(uint32_t size)
Definition Shape.cpp:36
int entry(int argc, char **argv)
Dump IR for given arguments.
Definition entry.cpp:193
::nncc::core::ADT::tensor::Shape TensorShape
Definition TensorShape.h:25
uint32_t element_count(const loco::TensorShape *tensor_shape)
Return the number of elements in a tensor of given shape.
DataType
"scalar" value type
Definition DataType.h:27
uint64_t num_elements(const Shape &)
Definition Shape.cpp:51
std::string value_grpname(void)
Return the name of "value group".
Definition Common.cpp:34