1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "common.h" 17#include <numeric> 18#include <inttypes.h> 19#include <securec.h> 20 21/* 22 * getDimInfo: get dim info from data file(int64_t) 23 * param: 24 * fp: the testing datafile object 25 * 26 * return : 27 * dim_info: array to store the info of the dim in datafile, like 28 * [4,3,3,6,3,162(3*3*6*3)],4 is dim size,3,3,6,3 is the dim shape data_size: 29 * the size of the testing data including the data file 30 * */ 31void getDimInfo(FILE *fp, std::vector<int64_t>* dim_info) { 32 const int MAX_HEAD_SIZE = 50; 33 uint32_t *dim_buffer = reinterpret_cast<uint32_t *>(malloc(MAX_HEAD_SIZE * sizeof(uint32_t))); 34 size_t ret = fread(dim_buffer, sizeof(uint32_t), MAX_HEAD_SIZE, fp); 35 if (ret == 0) { 36 free(dim_buffer); 37 return; 38 } 39 dim_info->push_back(*dim_buffer); // get dim size 40 41 // get data shape to compute the datasize 42 uint64_t data_size = 1; 43 uint32_t i = 1; 44 for (; i <= dim_info->at(0); i++) { 45 dim_info->push_back(*(dim_buffer + i)); 46 data_size *= *(dim_buffer + i); 47 } 48 dim_info->push_back(data_size); 49 50 free(dim_buffer); 51} 52 53/* 54 * readTestDataFile: read test date from hisi .t datafile(int64_t) 55 * param: 56 * infile: the path of hisi .t datafile 57 * return: 58 * dim_info: array to store the info of the dim in datafile, like [4,3,3,6,3],4 59 * is dim size,3,3,6,3 is the dim shape 60 * */ 61void *readTestDataFile(std::string infile, std::vector<int64_t>* dim_info1) { 62 printf("\n [common.cpp] Loading data from: %s\n", infile.c_str()); 63 64 FILE *fp; 65 fp = fopen(infile.c_str(), "r"); 66 if (fp == nullptr) { 67 printf("ERROR: cant't open file %s\n", infile.c_str()); 68 return nullptr; 69 } else { 70 std::vector<int64_t> dim_info; 71 std::vector<int64_t>* ptr_dim_info = &dim_info; 72 getDimInfo(fp, ptr_dim_info); 73 uint64_t data_size = ptr_dim_info->at(ptr_dim_info->size() - 1); 74 fclose(fp); 75 76 fp = fopen(infile.c_str(), "r"); 77 if (fp == nullptr) { 78 printf("ERROR: cant't open file %s\n", infile.c_str()); 79 return nullptr; 80 } 81 uint32_t *memory = reinterpret_cast<uint32_t *>(malloc((dim_info[0] + 1) * sizeof(uint32_t))); 82 83 size_t ret = fread(memory, sizeof(uint32_t), (dim_info[0] + 1), fp); 84 if (ret == 0) { 85 free(memory); 86 fclose(fp); 87 return nullptr; 88 } 89 uint32_t *data = reinterpret_cast<uint32_t *>(malloc((data_size) * sizeof(uint32_t))); 90 size_t ret2 = fread(data, sizeof(uint32_t), data_size, fp); 91 if (ret2 == 0) { 92 free(data); 93 fclose(fp); 94 return nullptr; 95 } 96 free(memory); 97 fclose(fp); 98 99 for (int i = 0; i < dim_info[0]; i++) { 100 dim_info1->push_back(dim_info[i + 1]); 101 } 102 103 printf("\n [common.cpp] Read test data file Over, get dimInfo as: ("); 104 int count = dim_info1->size(); 105 for (int i = 0; i < count; i++) { 106 printf("%" PRId64, dim_info1->at(i)); 107 } 108 printf(")\n"); 109 return data; 110 } 111} 112 113/* 114 * allclose 115 * param: 116 * a:compared file a 117 * b:compared file b 118 * count: the count size which will compare 119 * rtol: 120 * atol: 121 * return: 122 * true or false 123 * */ 124bool allclose(float *a, float *b, uint64_t count, float rtol = 1e-05, 125 float atol = 1e-08, bool isquant = false) { 126 uint32_t i = 0; 127 128 // add fail loop print 129 uint32_t fail_count = 0; 130 float tol = 0; 131 float tol1 = 0; 132 float tol2 = 0; 133 bool nan_occur_in_accuray = false; 134 135 float sum = 0.0f; 136 static float sum_all; 137 static float maximum = 0; 138 static float minimum = 0; 139 static uint64_t c = 0; 140 141 if (a == nullptr || b == nullptr) { 142 return false; 143 } 144 145 for (; i < count; ++i) { 146 sum = sum + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i])); 147 sum_all = sum_all + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i])); 148 maximum = std::max(maximum, fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i]))); 149 minimum = std::min(minimum, fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i]))); 150 if (isnan(a[i]) || isinf(a[i])) { 151 fail_count = fail_count + 1; 152 nan_occur_in_accuray = true; 153 if (fail_count < 100) { 154 printf(" i = %2u: %+f | %+f\n", i, a[i], b[i]); 155 } 156 } else if (fabs(a[i] - b[i]) > (atol + rtol * fabs(b[i]))) { 157 tol = tol + fabs(a[i] - b[i]) / (fabs(b[i]) + 1); 158 tol1 = tol1 + fabs(a[i] - b[i]); 159 tol2 = tol2 + fabs(a[i] - b[i]) / fabs(b[i]); 160 fail_count = fail_count + 1; 161 if (fail_count < 100) { 162 printf(" i = %2u: %+f | %+f\n", i, a[i], b[i]); 163 } 164 } 165 166 if (i == count - 1) { 167 printf(" ......\n"); 168 printf("\n *** Total fail_count: %u\n", fail_count); 169 if (fail_count != 0) { 170 printf("\n fabs(a[i] - b[i])/(fabs(b[i])+1) : %f\n", 171 tol / fail_count); 172 printf("\n fabs(a[i] - b[i]) : %f\n", tol1 / fail_count); 173 printf("\n fabs(a[i] - b[i])/fabs(b[i]) : %f\n", tol2 / fail_count); 174 } 175 c = c + count; 176 printf("\n avg : %f\n", sum / count); 177 printf("\n min : %f\n", minimum); 178 printf("\n max : %f\n", maximum); 179 printf("\n avg_all : %f\n", sum_all / c); 180 printf("\n"); 181 std::fstream file; 182 file.open("cout.csv", std::ios::app); 183 184 file << "," 185 << "1," 186 << "0," << maximum; 187 if (fail_count == 0) { 188 file << "," << sum_all / c; 189 } else { 190 file << "," << tol / fail_count; 191 } 192 file.close(); 193 } 194 } 195 if (nan_occur_in_accuray) { 196 printf("\n[common.cpp] eval output include some NAN/INF\n"); 197 return false; 198 } 199 200 if (fail_count > 0) { 201 printf("\n *** These data compare failed: atol = %f, rtol = %f\n", atol, 202 rtol); 203 printf("\n"); 204 if (isquant) { 205 if (tol / fail_count < 0.04) { 206 return true; 207 } 208 } 209 return false; 210 } 211 return true; 212} 213 214bool allclose_int8(uint8_t *a, uint8_t *b, uint64_t count, float rtol = 1e-05, 215 float atol = 1e-08, bool isquant = false) { 216 uint32_t i = 0; 217 // add fail loop print 218 uint32_t fail_count = 0; 219 float tol = 0; 220 float tol1 = 0; 221 float tol2 = 0; 222 bool nan_occur_in_accuray = false; 223 224 float sum = 0.0f; 225 static float sum_all; 226 static float maximum = 0; 227 static float minimum = 0; 228 static uint64_t c = 0; 229 // add fail loop print 230 231 if (a == nullptr || b == nullptr) { 232 return false; 233 } 234 235 for (; i < count; ++i) { 236 sum = sum + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i])); 237 sum_all = sum_all + fabs(a[i] - b[i]) / (atol + rtol * fabs(b[i])); 238 maximum = std::max(static_cast<double>(maximum), 239 static_cast<double>(fabs(a[i] - b[i])) / (atol + rtol * fabs(b[i]))); 240 minimum = std::min(static_cast<double>(minimum), 241 static_cast<double>(fabs(a[i] - b[i])) / (atol + rtol * fabs(b[i]))); 242 if (isnan(a[i]) || isinf(a[i])) { 243 fail_count = fail_count + 1; 244 nan_occur_in_accuray = true; 245 if (fail_count < 100) { 246 printf(" i = %2u: %+f | %+f\n", i, static_cast<float>(a[i]), static_cast<float>(b[i])); 247 } 248 } else if (fabs(a[i] - b[i]) > 0) { 249 tol = tol + fabs(a[i] - b[i]) / (fabs(b[i]) + 1); 250 tol1 = tol1 + fabs(a[i] - b[i]); 251 tol2 = tol2 + fabs(a[i] - b[i]) / fabs(b[i]); 252 fail_count = fail_count + 1; 253 printf("%2d", static_cast<int>(fabs(a[i] - b[i]))); 254 printf(" i = %2u: %2d | %2d\n", i, a[i], b[i]); 255 } 256 if (i == count - 1) { 257 printf(" ……\n"); 258 printf("\n *** Total fail_count: %u\n", fail_count); 259 if (fail_count != 0) { 260 printf("\n fabs(a[i] - b[i])/(fabs(b[i])+1) : %f\n", 261 tol / fail_count); 262 printf("\n fabs(a[i] - b[i]) : %f\n", tol1 / fail_count); 263 printf("\n fabs(a[i] - b[i])/fabs(b[i]) : %f\n", tol2 / fail_count); 264 } 265 266 c = c + count; 267 printf("\n avg : %f\n", sum / count); 268 printf("\n min : %f\n", minimum); 269 270 printf("\n max : %f\n", maximum); 271 printf("\n avg_all : %f\n", sum_all / c); 272 printf("\n"); 273 std::fstream file; 274 file.open("cout.csv", std::ios::app); 275 276 file << "," 277 << "1," 278 << "0," << maximum; 279 if (fail_count == 0) { 280 file << "," << sum_all / c; 281 } else { 282 file << "," << tol / fail_count; 283 } 284 file.close(); 285 } 286 } 287 if (nan_occur_in_accuray) { 288 printf("\n[common.cpp] eval output include some NAN/INF\n"); 289 return false; 290 } 291 if (fail_count > 0) { 292 printf("\n *** These data compare failed: atol = %f, rtol = %f\n", atol, 293 rtol); 294 printf("\n"); 295 if (isquant) { 296 if (tol / fail_count < 0.04) { 297 return true; 298 } 299 } 300 return false; 301 } 302 return true; 303} 304 305/* 306 * compFp32WithTData: compare the data with the data in hisi .t file 307 * param: 308 * actualOutputData: the result of ge 309 * expectedDataFile: the path of hisi .t result file 310 * rtol: 311 * atol: 312 * return: 313 * true of false 314 * */ 315bool compFp32WithTData(float *actualOutputData, const std::string& expectedDataFile, 316 float rtol = 1e-05, float atol = 1e-08, 317 bool isquant = false) { 318 std::vector<int64_t> dim_info; 319 std::vector<int64_t>* ptr_dim_info = &dim_info; 320 float *expectedOutputData = 321 reinterpret_cast<float *>(readTestDataFile(expectedDataFile, ptr_dim_info)); 322 uint32_t i = 0; 323 uint64_t data_size = 1; 324 data_size = accumulate(dim_info.begin(), dim_info.end(), 1, std::multiplies<uint64_t>()); 325 326 // print caffe/tf output: 327 printf("[common.cpp] expected output data:"); 328 for (; i < data_size && i < 10; i++) { 329 printf("%4f ", expectedOutputData[i]); 330 } 331 printf("\n"); 332 if (isquant) { 333 bool ret = allclose(actualOutputData, expectedOutputData, data_size, rtol, atol, 334 true); 335 free(expectedOutputData); 336 return ret; 337 } 338 bool ret = allclose(actualOutputData, expectedOutputData, data_size, rtol, atol); 339 free(expectedOutputData); 340 return ret; 341} 342 343bool compUint8WithTData(uint8_t *actualOutputData, const std::string& expectedDataFile, 344 float rtol = 1e-05, float atol = 1e-08, 345 bool isquant = false) { 346 std::vector<int64_t> dim_info; 347 std::vector<int64_t>* ptr_dim_info = &dim_info; 348 auto dataFile = readTestDataFile(expectedDataFile, ptr_dim_info); 349 if(dataFile == nullptr){ 350 return false; 351 } 352 uint8_t *expectedOutputData = 353 reinterpret_cast<uint8_t *>(dataFile); 354 uint32_t i = 0; 355 uint64_t data_size = 1; 356 data_size = accumulate(dim_info.begin(), dim_info.end(), 1, std::multiplies<uint64_t>()); 357 358 // print caffe/tf output: 359 printf("\n [common.cpp] expected output data:\n"); 360 for (; i < data_size && i < 10; i++) { 361 printf("%4hhu ", static_cast<unsigned char>(expectedOutputData[i])); 362 } 363 printf("\n"); 364 if (isquant) { 365 bool ret = allclose_int8(actualOutputData, expectedOutputData, data_size, rtol, 366 atol, true); 367 free(expectedOutputData); 368 return ret; 369 } 370 bool ret = allclose_int8(actualOutputData, expectedOutputData, data_size, rtol, 371 atol); 372 free(expectedOutputData); 373 return ret; 374} 375 376/* 377 * ReadFile: read file of model 378 * param: 379 * file: file location 380 * size: file size 381 * return: 382 * buf of file 383 * */ 384char *ReadFile(const char *file, size_t* size) { 385 printf("[common.cpp] Loading data from: %s\n", file); 386 387 std::ifstream ifs(file); 388 if (!ifs.good()) { 389 return nullptr; 390 } 391 392 if (!ifs.is_open()) { 393 ifs.close(); 394 return nullptr; 395 } 396 397 ifs.seekg(0, std::ios::end); 398 *size = ifs.tellg(); 399 400 char *buf = new char[*size]; 401 if (buf == nullptr) { 402 ifs.close(); 403 return nullptr; 404 } 405 406 ifs.seekg(0, std::ios::beg); 407 ifs.read(buf, *size); 408 ifs.close(); 409 printf("[common.cpp]Read Binary Data Over, get tensorSize as: %" PRId64 ".\n", static_cast<int64_t>(*size)); 410 411 return buf; 412} 413 414void PackNCHWToNHWCFp32(const char *src, char *dst, int batch, int plane, int channel) { 415 for (int n = 0; n < batch; n++) { 416 for (int c = 0; c < channel; c++) { 417 for (int hw = 0; hw < plane; hw++) { 418 int nhwc_index = n * channel * plane + hw * channel + c; 419 int nchw_index = n * channel * plane + c * plane + hw; 420 dst[nhwc_index * 4] = src[nchw_index * 4]; 421 dst[nhwc_index * 4 + 1] = src[nchw_index * 4 + 1]; 422 dst[nhwc_index * 4 + 2] = src[nchw_index * 4 + 2]; 423 dst[nhwc_index * 4 + 3] = src[nchw_index * 4 + 3]; 424 } 425 } 426 } 427 return; 428} 429 430char **TransStrVectorToCharArrays(const std::vector<std::string> &s) { 431 char **charArr = static_cast<char **>(malloc(s.size() * sizeof(char *))); 432 for (size_t i = 0; i < s.size(); i++) { 433 charArr[i] = static_cast<char *>(malloc((s[i].size() + 1))); 434 errno_t ret = memcpy_s(charArr[i], s[i].size(), s[i].c_str(), s[i].size()); 435 if (ret != EOK) { 436 printf("memcpy_s failed, ret: %d\n", ret); 437 } 438 *(charArr[i] + s[i].size()) = '\0'; 439 } 440 return charArr; 441} 442 443std::vector<std::string> TransCharArraysToStrVector(char **c, const size_t &num) { 444 std::vector<std::string> str; 445 for (size_t i = 0; i < num; i++) { 446 str.push_back(std::string(c[i])); 447 } 448 return str; 449} 450