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