鸽了这么久,正式开工
Author: carbon
email: ecras_y@163.com
参考资料:
https://github.com/tensorflow/tensorflow
https://github.com/snipsco/tensorflow-build
年中6月份的时候被抽到AI项目组,有幸接触目前最火的深度学习神经网络,
从开始到现在,一直坚守在google的tensorflow
目前行业的趋势是在PC或者服务器集群上进行训练,然后将训练好的模型export到mobile设备上,
由mobile设备加载使用这些训练好的模型。
我早几年前做过很多嵌入式的项目,所以将tensorflow移植到mobile嵌入式平台上的任务就落到了我的身上,我也当仁不让,
一撸到底。
目前仅支持交叉编译tensorflow的c和c++模块。
python模块由于链接目标库问题,在mobile设备上也没有训练模型的需求,
兼具性能的考虑,暂时没做python这一块的交叉编译支持。感兴趣的同学可以自己试试看。
测试板子使用树莓派,
树莓派可以跑完整的Linux操作系统,如果需要在树莓派上运行基于python的tensorflow,
需要在树莓派上进行编译,但是可能需要编译几天时间
基于以后可能需要将项目export到其它的嵌入式系统上,需要考虑到通用性
Android的编译比较特殊,直接使用官方的预编译好的组件即可
这里只考虑非Android和iOS的嵌入式平台
tensorflow编译使用bazel进行自动化编译管理,涉及到:
1. 子模块网络下载
2. 预编译期代码生成(generate files)
3. 模块之间依赖判定
4. 代码编译
如果将工程更改为Makefile编译,工作量巨大,难以操作
最好的做法还是使用bazel,加入交叉编译支持
bazel交叉编译官方有一些指导文档,有很好的参考意义
https://github.com/bazelbuild/bazel/wiki/Building-with-a-custom-toolchain
下载源码
使用git命令下载tensorflow源码
git clone git@github.com:tensorflow/tensorflow.git
google在最近发布了tensorflow lite,用于支持mobile设备,
更小的编译目标文件,更好的性能
但是还没有export到最新的tag中,所以这里我们直接基于master分支来操作
git checkout master
git checkout -b cross-compile
文章最后加入对交叉编译tensorflow lite的说明
编译之前需要先修正数据对齐bug
x86和x64平台无对齐问题
但是在某些arm平台上,需要地址对齐,
否则程序会在运行时,访问内存奇数地址或者未对齐地址,导致crash
vim tensorflow/core/lib/gtl/inlined_vector.h +288
将 T* unused_aligner 替换为 uint64_t unused_aligner
强制为8字节对齐
准备交叉编译工具链
这里以树莓派为例
git clone https://github.com/raspberrypi/tools.git
下载完成之后,将工具链路径添加到PATH中
脚本编写
目录结构
.
└── tensorflow
├── armv6-compiler
│ ├── BUILD
│ ├── CROSSTOOL
│ └── cross_toolchain_target_armv6.BUILD
├── build_armv6.sh
├── build_tflite.sh
└── WORKSPACE
1. 修改WORKSPACE文件,添加交叉编译工具链仓库描述
打开WORKSPACE文件,按照bazel的语法在文件末尾添加以下内容
new_local_repository(
name='toolchain_target_armv6',
path='/path/to/toolchain/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf',
build_file = 'armv6-compiler/cross_toolchain_target_armv6.BUILD'
)
参数说明:
交叉编译工具链别名: toolchain_target_armv6
交叉编译工具链路经: /path/to/toolchain/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf
交叉编译工具链描述文件: armv6-compiler/cross_toolchain_target_armv6.BUILD
2. 编写WORKSPACE仓库引用的交叉编译工具链的BUILD描述文件
mkdir armv6-compiler && cd armv6-compiler
touch cross_toolchain_target_armv6.BUILD
vi cross_toolchain_target_armv6.BUILD
具体语法规则参考详见
https://github.com/bazelbuild/bazel/wiki/Building-with-a-custom-toolchain
脚本内容如下:
1 package(default_visibility = ['//visibility:public']) 2 3 filegroup( 4 name = 'gcc', 5 srcs = [ 6 'bin/arm-linux-gnueabihf-gcc', 7 ], 8 ) 9 10 filegroup( 11 name = 'ar', 12 srcs = [ 13 'bin/arm-linux-gnueabihf-ar', 14 ], 15 ) 16 17 filegroup( 18 name = 'ld', 19 srcs = [ 20 'bin/arm-linux-gnueabihf-ld', 21 ], 22 ) 23 24 filegroup( 25 name = 'nm', 26 srcs = [ 27 'bin/arm-linux-gnueabihf-nm', 28 ], 29 ) 30 31 filegroup( 32 name = 'objcopy', 33 srcs = [ 34 'bin/arm-linux-gnueabihf-objcopy', 35 ], 36 ) 37 38 filegroup( 39 name = 'objdump', 40 srcs = [ 41 'bin/arm-linux-gnueabihf-objdump', 42 ], 43 ) 44 45 filegroup( 46 name = 'strip', 47 srcs = [ 48 'bin/arm-linux-gnueabihf-strip', 49 ], 50 ) 51 52 filegroup( 53 name = 'as', 54 srcs = [ 55 'bin/arm-linux-gnueabihf-as', 56 ], 57 ) 58 59 filegroup( 60 name = 'compiler_pieces', 61 srcs = glob([ 62 'arm-linux-gnueabihf/**', 63 'libexec/**', 64 'lib/gcc/arm-linux-gnueabihf/**', 65 'include/**', 66 ]), 67 ) 68 69 filegroup( 70 name = 'compiler_components', 71 srcs = [ 72 ':gcc', 73 ':ar', 74 ':ld', 75 ':nm', 76 ':objcopy', 77 ':objdump', 78 ':strip', 79 ':as', 80 ], 81 )