• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2021 Huawei Technologies Co., Ltd
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 "coder/generator/component/const_blocks/calib_output.h"
18 
19 namespace mindspore::lite::micro {
20 
21 const char *calib_header = R"RAW(
22 /**
23  * Copyright 2021 Huawei Technologies Co., Ltd
24  *
25  * Licensed under the Apache License, Version 2.0 (the "License");
26  * you may not use this file except in compliance with the License.
27  * You may obtain a copy of the License at
28  *
29  * http://www.apache.org/licenses/LICENSE-2.0
30  *
31  * Unless required by applicable law or agreed to in writing, software
32  * distributed under the License is distributed on an "AS IS" BASIS,
33  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34  * See the License for the specific language governing permissions and
35  * limitations under the License.
36  */
37 
38 #ifndef MINDSPORE_LITE_MICRO_CALIB_OUTPUT_H_
39 #define MINDSPORE_LITE_MICRO_CALIB_OUTPUT_H_
40 
41 #include "include/lite_utils.h"
42 #include "include/ms_tensor.h"
43 #include "include/errorcode.h"
44 
45 namespace mindspore {
46 namespace lite {
47 
48 class CalibTensor {
49  public:
50   CalibTensor(String name, size_t elements_num) : tensor_name_(name), elements_num_(elements_num) {}
51   ~CalibTensor() {
52     free(data_);
53     data_ = nullptr;
54   }
55   String tensor_name() const { return tensor_name_; }
56   int ElementsNum() const { return elements_num_; }
57   float *MutableData() {
58     if (data_ == nullptr) {
59       if (elements_num_ == 0 || elements_num_ > INT16_MAX) {
60         return nullptr;
61       }
62       data_ = static_cast<float *>(malloc(elements_num_ * sizeof(float)));
63     }
64     return data_;
65   }
66 
67  private:
68   String tensor_name_;
69   int elements_num_{0};
70   float *data_{nullptr};
71 };
72 
73 class Calibrator {
74  public:
75   Calibrator() = default;
76   ~Calibrator() {
77     for (auto &calib : calib_outputs_) {
78       delete calib;
79       calib = nullptr;
80     }
81     calib_outputs_.clear();
82   }
83   int ReadCalibData(const char *calib_data_path);
84   int CompareOutputs(const Vector<tensor::MSTensor *> &outputs) const;
85 
86  private:
87   Vector<CalibTensor *> calib_outputs_;
88 };
89 
90 }  // namespace lite
91 }  // namespace mindspore
92 
93 #endif  // MINDSPORE_LITE_MICRO_CALIB_OUTPUT_H_
94 )RAW";
95 
96 const char *calib_source = R"RAW(
97 /**
98  * Copyright 2021 Huawei Technologies Co., Ltd
99  *
100  * Licensed under the Apache License, Version 2.0 (the "License");
101  * you may not use this file except in compliance with the License.
102  * You may obtain a copy of the License at
103  *
104  * http://www.apache.org/licenses/LICENSE-2.0
105  *
106  * Unless required by applicable law or agreed to in writing, software
107  * distributed under the License is distributed on an "AS IS" BASIS,
108  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
109  * See the License for the specific language governing permissions and
110  * limitations under the License.
111  */
112 
113 #include "calib_output.h"
114 #include <fstream>
115 #include <sstream>
116 #include <iostream>
117 #include <stdio.h>
118 #include <cmath>
119 
120 namespace mindspore {
121 namespace lite {
122 constexpr float kToleranceVal = 0.0001;
123 
124 #define MS_ERROR_IF_NULL(ptr)            \
125   do {                                   \
126     if ((ptr) == nullptr) {              \
127       return mindspore::lite::RET_ERROR; \
128     }                                    \
129   } while (0)
130 
131 int Calibrator::ReadCalibData(const char *calib_data_path) {
132   std::ifstream in_file(calib_data_path);
133   if (!in_file.good()) {
134     printf("file is not exist, %s\n", calib_data_path);
135     return RET_ERROR;
136   }
137   if (!in_file.is_open()) {
138     printf("open file failed, %s\n", calib_data_path);
139     in_file.close();
140     return RET_ERROR;
141   }
142   while (!in_file.eof()) {
143     std::string line;
144     getline(in_file, line);
145     if (line.empty()) {
146       continue;
147     }
148     std::stringstream name_line(line);
149     std::string tensor_name;
150     size_t dim = 0;
151     name_line >> tensor_name >> dim;
152     size_t elements = 1;
153     for (size_t i = 0; i < dim; i++) {
154       size_t tmp_dim;
155       name_line >> tmp_dim;
156       elements *= tmp_dim;
157     }
158     getline(in_file, line);
159     std::stringstream data_line(line);
160     String name(tensor_name.c_str());
161     CalibTensor *output = new (std::nothrow) CalibTensor(name, elements);
162     MS_ERROR_IF_NULL(output);
163     float *data = output->MutableData();
164     MS_ERROR_IF_NULL(data);
165     for (size_t i = 0; i < elements; i++) {
166       data_line >> data[i];
167     }
168     calib_outputs_.push_back(output);
169   }
170   in_file.close();
171   return RET_OK;
172 }
173 
174 template <typename T>
175 float CompareData(const T *output, const float *calib, size_t elements_num) {
176   float error = 0.;
177   if (output == nullptr || calib == nullptr) {
178     printf("output or calib is nullptr\n");
179     return error;
180   }
181   for (size_t i = 0; i < elements_num; ++i) {
182     if (std::isnan(output[i]) || std::isinf(output[i]) || std::isnan(calib[i]) || std::isinf(calib[i])) {
183       printf("error, output data is nan or inf\n");
184       return error;
185     }
186     error += std::abs(output[i] - calib[i]);
187   }
188   return error;
189 }
190 
191 int Calibrator::CompareOutputs(const Vector<tensor::MSTensor *> &outputs) const {
192   if (outputs.size() != calib_outputs_.size()) {
193     printf("error, outputs and calibs size is mismatch\n");
194     return RET_ERROR;
195   }
196   float total_error = 0;
197   size_t outputs_num = outputs.size();
198   for (size_t i = 0; i < outputs_num; ++i) {
199     tensor::MSTensor *output = outputs[i];
200     MS_ERROR_IF_NULL(output);
201     CalibTensor *calib = calib_outputs_[i];
202     MS_ERROR_IF_NULL(calib);
203     if (output->tensor_name() != calib->tensor_name()) {
204       printf("warning, output tensor name is not equal to calib\n");
205     }
206     if (output->ElementsNum() != calib->ElementsNum()) {
207       printf("error, output elements num is not equal to calib\n");
208       return RET_ERROR;
209     }
210     switch (output->data_type()) {
211       case TypeId::kNumberTypeFloat:
212       case TypeId::kNumberTypeFloat32: {
213         total_error += CompareData(static_cast<float *>(output->data()), calib->MutableData(), output->ElementsNum());
214         break;
215       }
216       case TypeId::kNumberTypeInt8: {
217         total_error += CompareData(static_cast<int8_t *>(output->data()), calib->MutableData(), output->ElementsNum());
218         break;
219       }
220       case TypeId::kNumberTypeUInt8: {
221         total_error += CompareData(static_cast<uint8_t *>(output->data()), calib->MutableData(), output->ElementsNum());
222         break;
223       }
224       case TypeId::kNumberTypeUInt:
225       case TypeId::kNumberTypeUInt32: {
226         total_error += CompareData(static_cast<int32_t *>(output->data()), calib->MutableData(), output->ElementsNum());
227         break;
228       }
229       default: {
230         printf("unsupported tensor data type\n");
231       }
232     }
233   }
234   if (total_error > kToleranceVal) {
235     printf("compare outputs failed, total error: %f\n", total_error);
236     return RET_ERROR;
237   }
238   printf("compare outputs success, total error: %f\n", total_error);
239   return RET_OK;
240 }
241 }  // namespace lite
242 }  // namespace mindspore
243 )RAW";
244 
245 }  // namespace mindspore::lite::micro
246