xref: /third_party/mindspore/test/utils/common.cpp (revision be168c0d)
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