问题描述
需求是要在imx6ull上跑起来tensorflow lite神经网络模型,进阶目标是可以在QT中编写tensorflow lite应用
环境
- 操作环境:VMware中的Ubuntu
- 部署环境:linux on imx6ull(正点原子出厂系统)
基本步骤总结
- 交叉编译出TensorFlow lite针对imx6ull的库
- 将编译好的lite库放在开发板上,Ubuntu中也要保留,且尽量在一样的位置,方便引用
- 在qt开发时,将lite库进行引用,将qt软件编译完成后放置到开发板上
- 其中的模型就是tflite,这个可以在Python端产生和转换
解决步骤
- 安装交叉编译工具
- 这一步在正点原子的环境中已经配置过了,没有配置过的同学可以看参考链接
- 下载Tensorflow库,并编译其中的微处理器tensorflow lite库
- 下载Tensorflow库
- 解压后编译其中的微处理器tensorflow lite库
- 进去tensorflow总目录执行脚本下载依赖
- 在低版本的tenrsoflow上可以使用下面的语句
./tensorflow/lite/tools/make/download_dependencies.sh - 在高版本的tensorflow上,根据文件夹中的README.md,可知之前的文档已启用,需要使用新的方式进行编译,根据提示进入网站后,可以看到提供了两种方式,Bazel与cmake,由于要用QT并且已经配好了cmake,这里选择cmake的方式
- 由于配置cmake过程中发现由于Tensorflow版本更新,配置需要的过程很复杂,而在仔细梳理部署步骤后,这一步完全可以编译之后发布到ARM,不是必须使用自己已经配置好的环境,因此使用Docker,并且使用官方更推荐的Bazel
- 使用cmake编译微处理器tensorflow lite库
- 检查目标处理器的适配性
cat /proc/cpuinfo - 查看imx6ull返回的信息,可知应该选择Build for ARMv7 NEON enabled一项,可以根据这里的来配置cmake
- 根据下面的Run CMake进行编译,编译过程参考,其中cmake时提示一些包没办法下载,强烈建议手动下载并放到指定的位置上(这里建议参考使用clash for linux,代理后无需手动操作)
- 配置好后成功进行configuration
- 之后需要进行编译
cmake --build . -j8 - 编译过程中报错
arm-linux-gnueabihf-g++: error: unrecognized command line option ‘-mavx512f’ ,经查是gcc版本太低,换一个版本进行编译 - 这里更换的版本是gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf
- 更换更高版本gcc后有不明原因的报错,没有报错信息,观察到每次报错会卡死,提高虚拟机的核心数,重新进行编译,问题消失。
- 顺便将label_image编译出来,进行测试
cmake --build . -j -t label_image - 编译成功后放到开发板运行报错
version GLIBCXX_3.4.22 not found - 是开发板libstdc++.so.6版本的问题,更新版本
- 下载一个更新的版本,我是在Ubuntu里进行了搜索,发现有支持3.4.22的libstdc,所以就将Ubuntu里的移动到了开发板上
sudo find / -name "libstdc++.so.6*" (搜索系统里的libstdc)rm -rf libstdc++.so.6 (在目录下删除原来的软连接)ln -s libstdc++.so.6.0.23 libstdc++.so.6 (生成新的软连接) - 问题成功解决
- 下载model与label,放到同一个文件夹下进行测试
- 尝试自己编译一下minimal,方便后续编写自己的程序
- 成功编译,调用mobilenet_v1_1.0_224.tflite
- 下面跳转到使用QT编写程序的阶段
-
- 安装与配置docker
- 在 Ubuntu | 上安装 Docker 引擎Docker 文档
- 配置国内源
- 拉取TensorFlow devel docker 镜像
docker pull tensorflow/tensorflow:devel - 启动镜像
docker run -d -it --name tflite tensorflow/tensorflow:devel - 进入镜像控制台
- 使用Bazel构建ARM 二进制文件
- 进入/tensorflow_src/目录下执行以下指令
bazel build --config=elinux_armhf -c opt //tensorflow/lite:libtensorflowlite.so - 在执行这个指令的时候会需要链接外网下载一部分文件,连不上的话会报错。搜索终端代理会有人推荐proxychains,实测配起来很麻烦,建议使用clash for linux,配置相对简单。如果过程中下载失败的话可能网速还是太慢,断连了,可以重新执行指令。
- 编译成功后,编译好的结果在bazel-bin/tensorflow/lite/libtensorflowlite.so
- 将编译好的动态库so文件从docker中取出
docker cp tflite:tensorflow_src/bazel-bin/tensorflow/lite/libtensorflowlite.so ./ - 将libtensorflowlite.so放到开发板上的文件系统/usr/lib下
- 动态库编译好后需要在ubuntu上配置其他的静态库,主要就是将我们熟悉的.h文件提取出来放到一个include中进行调用,可以在tensorflow_src/tensorflow中使用下面的语句将所有需要的h文件打包为一个tar包,方便我们提取出来
find ./lite -name "*.h" | tar -cf headers.tar -T - - 编译官方demo测试
- 编译官方demo
bazel build --config=elinux_armhf -c opt //tensorflow/lite/examples/label_image:label_image bazel build --config=elinux_armhf -c opt //tensorflow/lite/tools/benchmark:benchmark_model - 编译报错,暂且不编
-
- 新建QT工程
- 在QT的引用中添加库的位置(项目右键->添加库->外部库)
- 这里遇到了编译时FlatBuffers报错的问题,是版本的原因,API有所改变,降低版本即可。
- 基于minimal的文件进行修改,首先添加tensorflow的头文件进行测试,发现此时可以正常将头文件进行编译了
- 基于minimal的文件与label_image的模型和测试数据进行部署测试
- 第一次到这一步是使用Docker+Bazel的方式,到这里.so文件报错,经查询是因为Docker中的系统glibc的版本与ubuntu和开发板的版本不对应
- 尝试更换Docker容器中glibc的版本
- 此降级操作有风险,重新尝试cmake路线之后产生了可用的程序,这一条路没有继续走了,有兴趣的同学可以继续尝试
- 这一步添加了使用的方法后构建报错一百多个,经排查是由于那个600多MB的静态库还有许多的依赖没有包含,需要我们意义手动添加
- 手动添加后发现还是有报错,是关于std::的,当前怀疑是由于编译lite库使用的工具链与QT中配置的工具链不同
- 适用于微控制器的 TensorFlow Lite
参考文献
|