alibaba / MNN

MNN is a blazing fast, lightweight deep learning framework, battle-tested by business-critical use cases in Alibaba
http://www.mnn.zone/
8.69k stars 1.66k forks source link

chinese-bert-wwm-ext模型转换成onnx再转换成mnn模型, PC和移动端测试, output全是NaN #2435

Closed XDL-dengxian closed 1 year ago

XDL-dengxian commented 1 year ago
  1. 模型转换方式: ./MNNConvert -f ONNX --modelFile .../model.onnx --MNNModel ~/Desktop/model.mn

  2. model.onnx没有问题: onnx再转化成tflite之后, 输出结果符合预期

  3. PC测试MNN模型方式: ./MNNV2Basic.out .../model.mnn 1 0 0 3x1x32

jxt1234 commented 1 year ago

先用 testMNNFromOnnx.py 测试

XDL-dengxian commented 1 year ago
image image

用testMNNFromOnnx.py测试, 结果正确, 截图如上

XDL-dengxian commented 1 year ago

toUseGPU = hasGPU && useGPU;

// 创建Interpreter m_net = std::shared_ptr(MNN::Interpreter::createFromFile(mnn_path.c_str()));

// 后端配置 m_backend_config.precision = MNN::BackendConfig::PrecisionMode::Precision_Low; m_backend_config.power = MNN::BackendConfig::Power_Normal; m_backend_config.memory = MNN::BackendConfig::Memory_Normal; m_config.backendConfig = &m_backend_config;

// 调度配置 m_config.numThread = 4; if (toUseGPU) { m_config.type = MNN_FORWARD_OPENCL; } m_config.backupType = MNN_FORWARD_CPU;

// 创建session m_session = m_net->createSession(m_config); std::cout << "session created" << std::endl;

// 获取输入tensor m_inTensor = m_net->getSessionInput(m_session, nullptr);

// 获取输出tensor std::string output_tensor_name0 = "output"; MNN::Tensor *outTensor0 = m_net->getSessionOutput(m_session, output_tensor_name0.c_str());

std::string output_tensor_name1 = "1337"; MNN::Tensor *outTensor1 = m_net->getSessionOutput(m_session, output_tensor_name1.c_str());

// 拷贝输入数据 long input[3][1][32] = { {{101, 2802, 2458, 9955, 3846, 6229, 1690, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} }; ::memcpy(m_inTensor->host(), input, 3 1 32 * sizeof(long));

// 运行会话 m_net->runSession(m_session);

// 获取输出数据 std::cout << "session gen output" << std::endl; auto output0 = outTensor0->host(); auto output1 = outTensor1->host(); std::cout << output0[0] << std::endl; std::cout << output1[0] << std::endl;

float output00[1][24]; float output11[1][4000]; ::memcpy(output00, outTensor0->host(), 1 24 sizeof(float)); ::memcpy(output11, outTensor1->host(), 1 4000 sizeof(float));

XDL-dengxian commented 1 year ago
image

但是在Android上output全是NaN (input完全一致), 帮忙看下是否写法有问题, 或者要我自己可以怎么排查?

jxt1234 commented 1 year ago

在开启 ARM82 编译宏后,android 上 precision low 会在支持的机器上运行 fp16 ,不能直接读 output->host ,需要按如下方法(二选一)取值

  1. 推荐:调 ptr = (float*)output->map() ,使用完后调 output->unmap(ptr) 2.建一个 outputHostTensor ,然后 copyToHostTensor ,用 outputHostTensor 里面的 host
XDL-dengxian commented 1 year ago
image

还是一样

jxt1234 commented 1 year ago

long input[3][1][32] = { {{101, 2802, 2458, 9955, 3846, 6229, 1690, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} }; ::memcpy(m_inTensor->host(), input, 3 1 32 * sizeof(long));

这么写不行的,input 需要是个一维数组,不然地址不连续

jxt1234 commented 1 year ago

另外 mnn 中 int64 会换成 int32 处理,需要把 long 改成 int

XDL-dengxian commented 1 year ago

ModuleBasic.out push到手机上测试, 结果正常输出

image
XDL-dengxian commented 1 year ago

多个输入, 当成单个输入来做了, 已经ok

yangy996 commented 1 year ago

大佬,怎么解决的,新版2.7.1Android端预测也是报nan数据