// // testModelWithDescribe.cpp // MNN // // Created by MNN on 2019/01/22. // Copyright © 2018, Alibaba Group Holding Limited // #define MNN_OPEN_TIME_TRACE #include #include #include #include #include #include #include #include #include "core/Backend.hpp" #include "ConfigFile.hpp" #include #include #include "core/Macro.h" #include #include "core/TensorUtils.hpp" #include #include #include #include #define NONE "\e[0m" #define RED "\e[0;31m" #define GREEN "\e[0;32m" #define L_GREEN "\e[1;32m" #define BLUE "\e[0;34m" #define L_BLUE "\e[1;34m" #define BOLD "\e[1m" using namespace MNN::Express; template inline T stringConvert(const char* number) { std::istringstream os(number); T v; os >> v; return v; } int loadData(const std::string name, void* ptr, int size, halide_type_t dtype) { std::ifstream stream(name.c_str()); if (stream.fail()) { return -1; } switch (dtype.code) { case halide_type_float: { auto data = static_cast(ptr); for (int i = 0; i < size; ++i) { double temp = 0.0f; stream >> temp; data[i] = temp; } } break; case halide_type_int: { MNN_ASSERT(dtype.bits == 32); auto data = static_cast(ptr); for (int i = 0; i < size; ++i) { int temp = 0; stream >> temp; data[i] = temp; } } break; case halide_type_uint: { MNN_ASSERT(dtype.bits == 8); auto data = static_cast(ptr); for (int i = 0; i < size; ++i) { int temp = 0; stream >> temp; data[i] = temp; } } break; default: { stream.close(); return -1; } } stream.close(); return 0; } MNN::Tensor* createTensor(const MNN::Tensor* shape, const std::string name) { auto result = new MNN::Tensor(shape, shape->getDimensionType()); result->buffer().type = shape->buffer().type; if (!loadData(name, result->host(), result->elementSize(), result->getType())) { return result; } delete result; return NULL; } VARP createVar(const std::string name, INTS shape, halide_type_t dtype) { int size = 1; for (int dim : shape) { size *= dim; } std::unique_ptr data(new char[size * dtype.bytes()]); loadData(name, data.get(), size, dtype); return _Const(data.get(), shape, NHWC, dtype); } template bool compareVar(VARP var, std::string name) { auto targetValue = createVar(name, var->getInfo()->dim, var->getInfo()->type); auto absMax = _ReduceMax(_Abs(targetValue), {}); absMax = _Maximum(absMax, _Scalar(0)); auto diff = _Abs(targetValue - var); auto diffAbsMax = _ReduceMax(diff); auto absMaxV = absMax->readMap()[0]; auto diffAbsMaxV = diffAbsMax->readMap()[0]; // The implemention of isnan in VS2017 isn't accept integer type, so cast all type to double #ifdef _MSC_VER #define ALI_ISNAN(x) std::isnan(static_cast(x)) #else #define ALI_ISNAN(x) std::isnan(x) #endif if (absMaxV * 0.01f < diffAbsMaxV || ALI_ISNAN(absMaxV)) { std::cout << "TESTERROR " << name << " value error : absMaxV:" << absMaxV << " - DiffMax:" << diffAbsMaxV << std::endl; return false; } return true; } void log_result(bool correct) { if (correct) { #if defined(_MSC_VER) std::cout << "Correct!" << std::endl; #else std::cout << GREEN << BOLD << "Correct!" << NONE << std::endl; #endif } } int main(int argc, const char* argv[]) { // modelName is xxx/xxx/temp.bin ===> xxx/xxx is the root path const char* modelName = argv[1]; std::string modelDir = argv[2]; modelDir = modelDir.substr(0, modelDir.find("config.txt")); std::cout << "model dir: " << modelDir << std::endl; // read args auto type = MNN_FORWARD_CPU; if (argc > 3) { type = (MNNForwardType)stringConvert(argv[3]); } auto tolerance = 0.1f; if (argc > 4) { tolerance = stringConvert(argv[4]); } auto precision = MNN::BackendConfig::Precision_High; if (argc > 5) { precision = (MNN::BackendConfig::PrecisionMode)(stringConvert(argv[5])); } // input config ConfigFile config(argv[2]); auto numOfInputs = config.Read("input_size"); auto numOfOuputs = config.Read("output_size"); auto inputNames = splitNames(numOfInputs, config.Read("input_names")); auto inputDims = splitDims(numOfInputs, config.Read("input_dims")); auto expectNames = splitNames(numOfOuputs, config.Read("output_names")); bool controlFlow = config.KeyExists("control_flow") && config.Read("control_flow"); auto dataType = halide_type_of(); if (config.KeyExists("data_type")) { auto dtype = config.Read("data_type"); if (dtype == "float") { dataType = halide_type_of(); } else if (dtype == "int32_t") { dataType = halide_type_of(); } else if (dtype == "uint8_t") { dataType = halide_type_of(); } } // create net & session #if defined(_MSC_VER) MNN_PRINT("Testing Model ====> %s\n", modelName); #else MNN_PRINT(GREEN "Testing Model ====> %s\n" NONE, modelName); #endif if (controlFlow) { std::shared_ptr model(Module::load(inputNames, expectNames, modelName)); std::vector inputs; for (int i = 0; i < numOfInputs; i++) { auto inputName = modelDir + inputNames[i] + ".txt"; inputs.push_back(createVar(inputName, inputDims[i], dataType)); } auto outputs = model->onForward(inputs); bool correct = true; for (int i = 0; i < numOfOuputs; i++) { auto dtype = outputs[i]->getInfo()->type; auto outputName = modelDir + expectNames[i] + ".txt"; if (dtype == halide_type_of()) { correct = compareVar(outputs[i], outputName); } else if (dtype == halide_type_of()) { correct = compareVar(outputs[i], outputName); } else { correct = compareVar(outputs[i], outputName); } if (!correct) { break; } } log_result(correct); } else { auto net = std::shared_ptr(MNN::Interpreter::createFromFile(modelName)); MNN::ScheduleConfig schedule; schedule.type = type; MNN::BackendConfig backendConfig; backendConfig.precision = precision; schedule.backendConfig = &backendConfig; auto session = net->createSession(schedule); // resize for (int i = 0; i < numOfInputs; ++i) { auto inputTensor = net->getSessionInput(session, inputNames[i].c_str()); net->resizeTensor(inputTensor, inputDims[i]); } net->resizeSession(session); auto checkFunction = [&]() { // [second] set input-tensor data for (int i = 0; i < numOfInputs; ++i) { auto inputTensor = net->getSessionInput(session, inputNames[i].c_str()); auto inputName = modelDir + inputNames[i] + ".txt"; std::cout << "The " << i << " input: " << inputName << std::endl; auto givenTensor = createTensor(inputTensor, inputName); if (!givenTensor) { #if defined(_MSC_VER) std::cout << "Failed to open " << inputName << std::endl; #else std::cout << RED << "Failed to open " << inputName << NONE << std::endl; #endif break; } inputTensor->copyFromHostTensor(givenTensor); delete givenTensor; } // inference net->runSession(session); // get ouput-tensor and compare data bool correct = true; for (int i = 0; i < numOfOuputs; ++i) { auto outputTensor = net->getSessionOutput(session, expectNames[i].c_str()); MNN::Tensor* expectTensor = nullptr; std::string expectName; // First Check outputname.txt { std::ostringstream iStrOs; iStrOs << expectNames[i]; expectName = modelDir + iStrOs.str() + ".txt"; expectTensor = createTensor(outputTensor, expectName); } if (!expectTensor) { // Second check number outputs std::ostringstream iStrOs; iStrOs << i; expectName = modelDir + iStrOs.str() + ".txt"; expectTensor = createTensor(outputTensor, expectName); } if (!expectTensor) { #if defined(_MSC_VER) std::cout << "Failed to open " << expectName << std::endl; #else std::cout << RED << "Failed to open " << expectName << NONE << std::endl; #endif break; } if (!MNN::TensorUtils::compareTensors(outputTensor, expectTensor, tolerance, true)) { correct = false; break; } delete expectTensor; } return correct; }; auto correct = checkFunction(); if (!correct) { return 0; } else { std::cout << "First Time Pass"<