美文网首页
TVM编译遇到的那些坑

TVM编译遇到的那些坑

作者: 耗子JF | 来源:发表于2022-04-14 11:45 被阅读0次

    由于工作需要,初次接触TVM,工作用的电脑是windows系统的,要从头搭建整个编译环境,嗯,真的硬核从头,从安装ubuntu子系统开始,中间遇坑无数,死磕各种报错很久,终于经过苦难的半个月折磨顺利按官方文档完成了tvm库到android_rpc客户端的编译工作!撒花完结!

    目前找到的比较友好的大佬文档:
    用TVM在Android上部署模型
    tvm系列-Android TVM RPC
    TVM系列 - 终于在手机成功部署Auto-TVM

    源码是在2022年4月初下载的最新代码,高于V0.8版本,懒人包:
    tvm/build目录覆盖:TVM share-lib build 目录完全内容下载
    tvm/jvm目录覆盖:TVM jvmpkg 编译完成包下载
    tvm/apps/android_rpc/app/src/main/libs目录覆盖:tvm android_rpc so完整库
    tvm/apps/android_rpc/app/src/libs目录覆盖:tvm4j-core-0.0.1-SNAPSHOT.jar

    宝宝心里苦啊,不知道是不是大佬们玩linux环境比较溜,基本上编译都是一笔带过环境问题,主角光环加身既视感,嗯,就像看小说里的那句“很多年过去了,男主神功大成”一毛一样!

    废话不多说,我们开始爬坑之路:

    安装windows10自带unbuntu子系统:
    公司破电脑权限问题只能绕过微软应用商店,用shell装ubuntu16.4的系统,正常用应用商店应该是装18.4(推荐)或者20.4系统,最好18.4的,因为网上很多环境下载这个版本支持比较全,20.4实在没心情去折腾了,有兴趣的自己去搞一下试试,应该也差不多……吧?

    新系统先跑一下下面这个命令,官方给的环境,16.4默认好些个版本都太低,cmake,gcc python3都低于官方要求版本,需要单独升级一下

    sudo apt-get update
    sudo apt-get install -y python3 python3-dev python3-setuptools gcc libtinfo-dev zlib1g-dev build-essential cmake libedit-dev libxml2-dev
    

    step 1:TVM4J Installation Guide

    官方文档(下载,环境配置,编译)
    基本上先按文档走一遍,那么大部分环境就算OK了:

    1.tvm源码下载地址

    git clone --recursive https://github.com/apache/tvm tvm
    

    For windows users who use github tools, you can open the git shell, and type the following command.

    git submodule init
    git submodule update
    

    上面是官方原文建议,但是个人建议还是老老实实用ubuntu下敲命令下载吧,因为这里也会有点点坑,看人品,别问,问就是遇到过,对于像我这种触及到知识盲区的新入坑人员来说还是太深了:源码内 tvm/3rdparty/目录下会有子工程,直接git clone tvm这部分代码是不会下载的,要么按上面submodule操作自动下载,要么就手动点进github子模块链接下载,推荐手动点进去下载,因为这里也有坑

    各个子系统git地址:
    tvm/3rdparty/cutlass: https://github.com/NVIDIA/cutlass.git
    tvm/3rdparty/dlpack: https://github.com/dmlc/dlpack.git
    tvm/3rdparty/dmlc-core: https://github.com/dmlc/dmlc-core.git
    tvm/3rdparty/libbacktrace: https://github.com/tlc-pack/libbacktrace.git
    tvm/3rdparty/rang: https://github.com/agauniyal/rang.git
    tvm/3rdparty/vta-hw:https://github.com/apache/tvm-vta.git

    好了,源码下载完了,按官方文档更新下编译环境:

    Requirements

    • JDK 1.6+. Oracle JDK and OpenJDK are well tested.
      我的版本是openJDK8
    • Maven 3 for build.
      我的版本是maven3.3.9
    • LLVM (TVM4J need LLVM support. Please refer to build-the-shared-library for how to enable LLVM support.) LLVM一定要安装,推荐LLVM6.0版本(ubuntu16.4 apt支持的最高版本,手动安装太麻烦了),当然LLVM7应该也可以(这个是ubuntu18.4apt支持的最低版本,LLVM10也OK,官方推荐),如果config.mk不把LLVM打开容易遇到报错不通过编译,嗯,有一定概率,玄学玄学

    android_rpc工程依赖tvm4j的jar包,因此首先需要编译生成tvm4j包,编译的环境要求为:

    • A recent c++ compiler supporting C++ 14 (g++-5 or higher) :
      我使用的是gcc g++ 7.5的版本(5.4的版本也能过),unbuntu16.4自带版本太低,需要手动升级一下,ubuntu18.4默认就是7的版本起步省心啊!
    • CMake 3.10 or higher:
      我使用的是3.22.3以及3.23.xx版本都能过,ubuntu16.4 apt库的版本过低要手动升级
    • We highly recommend to build with LLVM to enable all the features.
      Python is also required. Avoid using Python 3.9.X+ which is not supported. 3.7.X+ and 3.8.X+ should be well supported however:
      这个后续部署服务联调会用,但是前面阶段编译TVM用不到还,尽量按要求来吧

    编译开始:

    • First, check the cmake in your system. If you do not have cmake, you can obtain the latest version from official website
      我的cmake版本3.22.3(3.23.xx也可以,家里电脑用的最新的没问题)
    • First create a build directory, copy the cmake/config.cmake to the directory.
      在TVM目录创建一个build文件夹,复制cmake/config.cmake到build目录
    mkdir build
    cp cmake/config.cmake build
    

    打开config.cmake找到下面这些参数,修改为打开

    set(USE_GRAPH_EXECUTOR ON) 
    set(USE_PROFILER ON)
    

    有需要的话可以开启debug:

    set(USE_RELAY_DEBUG ON)
    

    //命令行需要执行一下这一句命令

    export TVM_LOG_DEBUG="ir/transform.cc=1;relay/ir/transform.cc=1"
    

    打开LLVM功能

    set(USE_LLVM /path/to/your/llvm/bin/llvm-config) 
    #我的实际路径是:set(USE_LLVM /usr/lib/llvm-6.0/bin/llvm-config)
    

    然后切换到build目录进行编译:

    cd build
    cmake ..
    make -j4
    

    顺利的话,我们应该能喝一喝茶或者咖啡等待编译完成拿到我们需要的so库:
    TVM share-lib build 目录完全内容下载
    实在搞不出来又急着用,可以直接下这个包,整个build完整编译文件都在里面,包括要用到的libtvm.so和libtvm_runtime.so文件,解压覆盖就可以用

    但是!有问题很正常,容易采坑的地方:

    如果遇到问题,首先先对照一下编译环境是不是OK,回过头去耐心对照一下我上面加粗标注的那些环境版本,起码上面那些版本我趟过雷了,编译是没问题的,这个编译很磨人的地方就在这里,如果你环境对不上可能就会报各种莫名其妙的错误:


    • 1.一定要ubuntu子系统内下载,不要windows下面下载,否则会莫名其妙遇到编码问题,比如里面加一个^M啊这种啥的,编译的时候会报错:
      unrecognized command line xxx
      ...3rdparty/libbacktrace/configure: Syntax error: newline unexpected (expecting ")")
      等类似错误,因为编译的时候会先运行各个子模块的configure进行验证,大概率这个地方会报语法错误,但是如果普通文本工具打开看是看不到这些编码的,如果你遇到查看configure内容明明语法没问题,但是死活告诉你语法有错,编译不过
      解决方法:如果是这个错误,大概率就是下载的源码被污染了,可以通过命令:vim -b xxxx 来查看是否有奇怪编码,如果有乱码,那就重新在unbuntu里下一遍吧,如果只是单个配置文件出问题了,可以用这个命令清除整理一下:sed -i 's/\r//g' xxxx.sh 然后再用vim -b查看,非法字符就消失了,上面的configure可以通过运行 sh configure --help 验证是否正常,如果执行了清除非法字符的命令,应该是会正常运行,并提示configure文件内可用参数的相关help信息的

    • 2.就是前面下载说明的地方说的,要手动下载tvm/3rdparty目录下各个子模块编码放到对应的文件夹里去,否则编译的时候会报错:各种找不到文件之类的,目录指向tvm/3rdparty下面,那么就是这个问题了

    • 3.编译遇到tvm/3rdparty下某些重复定义错误,对就是kDLHexagon,kDLWebGPU这些重复定义,指向的是c_runtime_api.h 以及dlpack.h
      编译build so库的时候,给你的错误提醒是这样的:

    In file included from /mnt/d/ubuntu/tvm/include/tvm/runtime/object.h:26:0,
                     from /mnt/d/ubuntu/tvm/src/support/libinfo.cc:19:
    /mnt/d/ubuntu/tvm/include/tvm/runtime/c_runtime_api.h:89:16: error: redeclaration of ‘kDLHexagon’
       kDLHexagon = 14,
                    ^~
    In file included from /mnt/d/ubuntu/tvm/include/tvm/runtime/c_runtime_api.h:72:0,
                     from /mnt/d/ubuntu/tvm/include/tvm/runtime/object.h:26,
                     from /mnt/d/ubuntu/tvm/src/support/libinfo.cc:19:
    /mnt/d/ubuntu/tvm/3rdparty/dlpack/include/dlpack/dlpack.h:64:3: note: previous declaration ‘DLDeviceType kDLHexagon’
       kDLHexagon = 15,
       ^~~~~~~~~~
    In file included from /mnt/d/ubuntu/tvm/include/tvm/runtime/object.h:26:0,
                     from /mnt/d/ubuntu/tvm/src/support/libinfo.cc:19:
    /mnt/d/ubuntu/tvm/include/tvm/runtime/c_runtime_api.h:90:15: error: redeclaration of ‘kDLWebGPU’
       kDLWebGPU = 15
                   ^~
    In file included from /mnt/d/ubuntu/tvm/include/tvm/runtime/c_runtime_api.h:72:0,
                     from /mnt/d/ubuntu/tvm/include/tvm/runtime/object.h:26,
                     from /mnt/d/ubuntu/tvm/src/support/libinfo.cc:19:
    /mnt/d/ubuntu/tvm/3rdparty/dlpack/include/dlpack/dlpack.h:65:3: note: previous declaration ‘DLDeviceType kDLWebGPU’
       kDLWebGPU = 16
       ^~~~~~~~~
    ^CCMakeFiles/tvm_runtime_objs.dir/build.make:89: recipe for target 'CMakeFiles/tvm_runtime_objs.dir/src/runtime/c_runtime_api.cc.o' failed
    

    同时这个问题还会导致android so 的jni编译脚本无法通过,报错与kDLWebGPU,kDLHexagon重复定义有关,这个就是子模块自动下载可能带来的问题:git submodule update拉取的代码是⽗项⽬中记录的那个submodule版本,但不⼀定是submoudle远程仓库⾥最新的版本,实际上最新的版本dlpack.h相关重复定义字段已经删除了,泪流满面,因为大佬的文章都是一笔带过,所以坚信源码没问题没问题没问题!浪费了大量时间有木有有木有!!

    踩过坑以后,我们对于TVM相关share-lib so库的编译工作就算完成了,我们可以继续按流程往下走,编译jar库,在上面编译通过的基础上,环境问题的坑基本我们都补好了,就不太可能出啥问题了,直接就能顺利编译过了:

    First please refer to Installation Guide and build runtime shared library from the C++ codes (libtvm_runtime.so for Linux and libtvm_runtime.dylib for OSX).
    Then you can compile tvm4j by

    #source-shell tvm目录运行shell脚本
    make jvmpkg
    

    (Optional) run unit test by 这个其实不跑也没关系……吧?

    #source-shell tvm目录运行shell脚本
    sh tests/scripts/task_java_unittest.sh
    

    After it is compiled and packaged, you can install tvm4j in your local maven repository,

    #source-shell tvm目录运行shell脚本
    make jvminstall
    

    顺利完成tvm4j jar库的编译,我们可以在tvm/jvm/core/target里找到编译成功的jar库
    tvm4j-core-0.0.1-SNAPSHOT.jar 这个jar包我们在后面的android 编译的时候需要用到,附上编译好的jvm目录,懒人可以直接覆盖tvm/jvm文件夹跳过编译过程:
    TVM jvmpkg 编译完成包下载
    文件包括所有编译出的文件,包括tvm4j-core-0.0.1-SNAPSHOT.jar,以及后续要用的编译文件

    Step2. Android TVM RPC

    You will need JDK(我的版本是openJDK8,尽量安装这个版本,因为我在论坛查找各种问题的issue的时候看到有人因为jdk版本问题无法正确编译的), Android NDK(务必使用NDK 16 rb版本我测试过10e, 12b, 23b统统卡死在ndk-build编译JNI那一步,no zuo no die!!!) and an Android device to use this.

    Build APK

    We use Gradle (请使用相对高一些的版本,推荐gradle 6 或者 7 这两个都试过,没问题,有人在官方论坛说的,gradle版本低了无法正常编译,不信可以试试嗷)to build. Please follow the installation instruction for your operating system.

    Before you build the Android application, please refer to TVM4J Installation Guide and install tvm4j-core to your local maven repository. You can find tvm4j dependency declare in app/build.gradle. Modify it if it is necessary.

    我们前面编辑出来jar包了,所以用简单点的方法,直接换成本地libs的jar引用方式吧,maven库的方式是在有点麻烦,附上懒人包(其中jar包也可以在jvm那个包里的jvm/core/target下面找到),使用so懒人包的时候,记得把buildJni注释掉:

    tasks.withType(JavaCompile) {
        //像这样,注释掉,很重要!!!
        //compileTask -> compileTask.dependsOn buildJni
    }
    

    这样就不用走buildJni去重复编译so库了,否则会直接就删掉我们懒人包的so重新编译了:
    tvm/apps/android_rpc/app/src/main/libs目录覆盖:tvm android_rpc so完整库
    tvm/apps/android_rpc/app/src/libs目录覆盖:tvm4j-core-0.0.1-SNAPSHOT.jar

    dependencies {
       implementation fileTree(dir: 'libs', include: ['*.jar'])
        androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        implementation 'com.android.support:appcompat-v7:26.0.1'
        implementation 'com.android.support.constraint:constraint-layout:1.0.2'
        implementation 'com.android.support:design:26.0.1'
        //划重点,这里替换成我们编译出来的jar包放到工程目录src/libs里
        implementation files('src/libs/tvm4j-core-0.0.1-SNAPSHOT.jar')
        //implementation 'org.apache.tvm:tvm4j-core:0.0.1-SNAPSHOT'
        testImplementation 'junit:junit:4.12'
    }
    
    

    Now use Gradle to compile JNI, resolve Java dependencies and build the Android application together with tvm4j. Run following script to generate the apk file.
    如果一切正常,我们就能得到编译出来的的apk用于连接服务器测试了,如果要加入opencl库的APK请参考官方文档进行设置打包,好了,暂时更新到这里,后面继续测试连接服务器运算以及opencl库启用踩坑!

    坑来了

    NDK在这里,版本很重要我测试过(android-ndk-r10e,android-ndk-r12b,android-ndk-r16b,android-ndk-r23b),太高的版本(android-ndk-r23b)会报错,各种错,一个是找不到tools-chain里面的编译器工具错误,因为新版已经把这些工具包去掉了,只有llvm,renderscript文件夹,后续用到的Cross Compile也会需要,高版本是没法正常使用的:

    cd /opt/android-ndk/build/tools/
    //高版本NDK这条命令没法正常执行
    ./make-standalone-toolchain.sh --platform=android-24 --use-llvm --arch=arm64 --install-dir=/opt/android-toolchain-arm64
    

    更新了编译机制,就算你从低版本复制对应的chain包进去,依然会有其他错误,错误是没有具体提醒的,具体姿势是这样的:

    make: Entering directory '/mnt/d/ubuntu/tvm/apps/android_rpc/app/src/main/jni'
    [armeabi-v7a] Compile++ arm  : tvm4j_runtime_packed <= org_apache_tvm_native_c_api.cc
    clang: error: no input files
    
    //gradle执行脚本的话会报这个错误
    Process 'command 'sh'' finished with non-zero exit value 2
    

    NDK版本太低的版本(10e,12b)会报错误,而且ubuntu16.4默认的clang是3.8的版本,最好手动更新下默认clang版本,同理还有gcc 和 g++版本一定要检查(我用的是gcc g++ 7.5),否者会遇到下面错误,这两个错误主要能在jni 对应的Application.mk配置里找到对应的命令行,但本质上就是编译版本对不上的问题:

    //错误1( gcc最好升级到7)
    arm-linux-androideabi-g++: error: unrecognized command line option '-std=c++14'
    //错误2
    cc1plus: error: argument to '-O' should be a non-negative integer, 'g', 's' or 'fast'
    

    然后正确的NDK版本,如果遇到之前编译so的时候没有处理tvm/3rdparty下面dlpack库同步问题,会有这样的的错误:

    In file included from /mnt/d/ubuntu/tvm/apps/android_rpc/app/src/main/jni/org_apache_tvm_native_c_api.cc:25:
    In file included from /mnt/d/ubuntu/tvm/apps/android_rpc/app/src/main/jni/tvm_runtime.h:36:
    In file included from /mnt/d/ubuntu/tvm/apps/android_rpc/app/src/main/jni/../../../../../../include/../src/runtime/c_runtime_api.cc:25:
    In file included from /mnt/d/ubuntu/tvm/apps/android_rpc/app/src/main/jni/../../../../../../include/tvm/runtime/c_backend_api.h:31:
    /mnt/d/ubuntu/tvm/apps/android_rpc/app/src/main/jni/../../../../../../include/tvm/runtime/c_runtime_api.h:90:3: error:
          redefinition of enumerator 'kDLWebGPU'
      kDLWebGPU = 15
      ^
    /mnt/d/ubuntu/tvm/apps/android_rpc/app/src/main/jni/../../../../../../3rdparty/dlpack/include/dlpack/dlpack.h:65:3: note:
          previous definition is here
      kDLWebGPU = 16
    

    另外,我在参考有大佬文档的时候,说自己运行gradle clean build 进行打包的时候会报错,但是我后面把各种坑踩完以后,倒是没遇到这个问题,这里提供一种担心gradle版本过高(反正我用最新的gradle 7没遇到),可能引起错误的规避方法,使用gradlew脚本进行指定版本编译,操作如下:

    //先切换到android_rpc根目录,执行下面命令,会自动生成gradlew脚本
    //且会自动下载对应的gradle插件包,避免版本不匹配的问题
    //我这里设置的4.4版本,工程里3.1版本下不下来
    gradle wrapper --gradle-version 4.4
    //执行完毕以后就生成好gradlew脚本文件了,执行工程编译
    ./gradlew clean build
    

    相关文章

      网友评论

          本文标题:TVM编译遇到的那些坑

          本文链接:https://www.haomeiwen.com/subject/svktertx.html