docs/faq.md
cmake 3.10+ gcc 4.9+ protobuf 3.0+
更新 gcc 之后请重新 cmake 一下
*** building flatc ***
CMake Error: Could not find CMAKE_ROOT !!!
这说明你的 CMake 没有正确安装,请尝试
sudo apt install extra-cmake-modules
或
export CMAKE_ROOT=/path/to/where_cmake_installed
更改 schema 之后,需要重新运行 schema/generate.sh
触发问题操作
报错信息类似:
Could NOT find Protobuf (missing: Protobuf_INCLUDE_DIR)
Unrecognized syntax identifier "proto3". This parser only recognizes "proto2".
有两种解决方案
cmake 加上选项 -DMNN_BUILD_PROTOBUFFER=ON ,使用 MNN 自带的 protobuf 编译 采用这种方案时,如果之前有编译残留,有可能出现原先生成的 protobuf 相关头文件与 MNN 自带的 protobuf 库不兼容的问题(编译出错),清空当前编译目录,重新编译即可。
参考 Protobuf's Installation Instructions 安装. 如果您电脑上安装了多份 protobuffer ,他们之前可能产生冲突(protoc 与链接的 libprotobuf 不一致),可尝试如下方式解决:
which protoc
# comment the output path in .bashrc if it do NOT direct to the correct protoc.
source .bashrc
sudo ldconfig
或
# uninstall
sudo apt-get remove libprotobuf-dev
sudo apt-get remove protobuf-compiler
sudo apt-get remove python-protobuf
sudo rm -rf /usr/local/bin/protoc
sudo rm -rf /usr/bin/protoc
sudo rm -rf /usr/local/include/google
sudo rm -rf /usr/local/include/protobuf*
sudo rm -rf /usr/include/google
sudo rm -rf /usr/include/protobuf*
# install
sudo apt-get update
sudo ldconfig
sudo apt-get install libprotobuf* protobuf-compiler python-protobuf
MNN 一般以动态库形式使用,里面有大量自注册函数,如果需要以静态库形式使用 MNN ,需要根据您所用的编译器,增加完全链接的编译选项:
此处报错是 Binary 算子的形状计算出错。
opConverter ==> MNN Converter NOT_SUPPORTED_OP: [ ANY_OP_NAME ]
说明存在 MNN 不支持转换的算子,可以考虑如下解决方案:
先使用MNN中的模型一致性验证脚本进行测试,确定不是调用方法或其他错误,使用方法
此功能只支持压缩模型数据,在运行时仍然先解压到float32运算。如果希望使用 fp16 加速,打开 MNN_ARM82 并在加载模型时设置 precision = low
可以通过动态量化功能,加载仅权重量化的模型,降低内存占用和提升性能
MNN_LOW_MEMORY 编译宏编译 MNN (支持动态量化功能)临时解决方案:升级 numpy 版本到 1.20.0 或以上
MNN 内部对 CV 相关算子采用 NC4HW4 布局,计算 elementSize 时,channel 会上对齐到 4 返回,此内存布局允许实现的硬件自行确定内存排列方式,具体方式不对用户可见,但用户可以通过如下代码,输入或获取自己指定的NCHW / NHWC 内存布局的 Tensor / VARP。
auto srcTensor = net->getSessionInput(session, "data");
auto srcTensorHost = new Tensor(srcTensor, Tensor::TENSORFLOW);
// ... set srcTensorHost data
srcTensor->copyFromHostTensor(srcTensorHost);
delete srcTensorHost;
// ... set other inputs, if exist
net->runSession(session);
auto dstTensor = net->getSessionOutput(session, "prob");
auto dstTensorHost = new Tensor(dstTensor, Tensor::TENSORFLOW);
dstTensor->copyToHostTensor(dstTensorHost);
// ... use dstTensorHost data
delete dstTensorHost;
Module* net = Module::load("net.mnn", {"data"}, {"prob"});
VARP input = _Input({1, 224, 224, 3}, NHWC);
float* inputPtr = input->writeMap<float>();
// ... set srcTensor data
auto info = net->getInfo();
input = _Convert(input, info->inputs[0].order);
output = net->onForward({input});
output = _Convert(output, NHWC);
const float* outputPtr = output->readMap<float>();
// ... use outputPtr
resizeTensor和resizeSession;可以打开source/shape/SizeComputer.cpp中的宏// #define MNN_DEBUG_TENSOR_SIZE定义,然后执行模型推理;打开宏之后可以看到每一层的形状信息,可以逐层进行DebugAndroid 系统有两类打印日志的方式: printf 和 logcat. 默认 MNN 的编译脚本使用 printf,这样方便在命令行中调试。集成到 App 上时,用 cmake -DMNN_USE_LOGCAT=ON 将打印日志的方式改成 logcat 即可用 adb logcat 查看
MNN opencl 后端默认采用 dlopen 的方式动态打开设备的 opencl 驱动,相应位置若找不到您设备上的驱动,请修改 OpenCLWrapper.cpp
TensorArray 和控制流支持需要借助 MNN-Express , 请参考 demo/exec/transformerDemo.cpp 的接口使用
默认情况下, MNN 只支持用户访问网络输入输出节点的数据,如果需要取中间结果,参考如下方式:
Linux系统上的简单解决方案: cmake .. -DMNN_USE_SYSTEM_LIB=true -DMNN_SEP_BUILD=false
Windows 系统上参考 MNN 静态库的使用,需要加静态库全链接选项
为了设备兼容性,MNN Vulkan / OpenCL 默认采用自己搜索路径 dlopen 的方式,不直接依赖系统驱动。您也可以设置 MNN_USE_SYSTEM_LIB = ON , 让 MNN 直接依赖系统驱动
OpenCL / Vulkan 采用静态变量自注册的方式往 MNN 主库注册后端. 在 Linux 系统上默认采用懒加载,由于没有直接依赖 MNN_CL.so / MNN_Vulkan.so ,不会初始化静态变量,导致 opencl / vulkan 后端使用时找不到. 可以按如下方式之一解决:
由于Android新版本增强了权限控制,有可能遇到加载OpenCL库失败的问题,可以修改 AndroidManifest.xml 对应栏,加入OpenCL相关 so 的权限需求
<application>
...
<uses-native-library android:name="libOpenCL.so"
android:required="true"/>
...
</>
用 valgrind 工具检查时会报 MNN Register 相关的内存泄露,这个属于一次性的初始化内存,后续也不会增加,可视为误报
Metal 后端使用的是OC对象,需要用OC的自动回收机制来清除内存,可在使用代码中把相关mnn的API调用放到autorealse中以自动回收内存
@autoreleasepool {
/* MNN 相关调用代码 */
}
GPU 后端调用 copy 的时间包含两个部分
对 GPU 后端而言,在数据被要求对用户可见(比如复制 output tensor 数据出来)之前,是允许异步执行的。 在数据被用户要求可见之时,会等待相应的异步操作完成。 因此有可能 复制 output tensor 的过程包括了等待 GPU 算子异步执行完成,导致看上去缓慢。
有如下原因:
相当一部分移动端设备 (如 pre-iPhone 8), GPU 算力不足,加以内存带宽的限制,本身不如 CPU.
比如 Apple 由 Imagination 切换到自己的 GPU in iPhone 8, 导致 GPU 性能下降(不如 iphone 7) ,相对地, CPU 是提升的.
存在 GPU 不支持的算子,这些算子会切换到 CPU 执行,相应的输入输出需要 CPU - GPU 之间的内存拷贝,产生额外耗时
模型本身计算量小或者不易并行,发挥不了 GPU 并行计算的优势.
GPU 被其他程序占用,或者系统限制了 GPU 频率
这个需要从浮点和量化两个方面说明
加密与破解是攻防的较量,端侧加密很难做到绝对安全。 可以通过构造独有的模型格式来增加反向的难度,按照以下步骤操作可以得到独特的模型格式:
cp -r schema/default schema/privateschema/private/*.fbs下的文件,对参数顺序,枚举类顺序进行重新排序;比如:可以重新调整MNN.fbs中OpType的顺序;重新调整CaffeOp.fbs中Convolution2DCommon成员变量的顺序;schema/generate.sh重新生成flatbuffers头文件;MNN库文件, Convert等所有工具;MNN库文件进行部署;# 产出 op.txt
./GetMNNInfo x0.mnn
# 追加 op.txt
./GetMNNInfo x1.mnn
./GetMNNInfo x2.mnn
......
cd ${MNN_ROOT}
python3 tools/script/prue_mnn_ops.py op.txt .
# 执行完成后会发现 source/backend/cpu/CPUOPRegister.cpp , source/geometry/GeometryOPRegister.cpp 等注册函数被修改了,说明生效