7.8. BM1684(X)_to_BM1688(CV186AH)兼容性文档

该文档面向有一定SOPHONSDK使用经验的用户,它还需丰富和完善,如果您发现了新的问题或有改进建议,可以反馈给我们的工作人员。

7.8.1. 获取BM1688/CV186AH SOPHONSDK

BM1688/CV186AH的SOPHONSDK与BM1684/BM1684X的SOPHONSDK不是同一套,所以需要另外从官网获取。下载后使用工具解压,可以得到各个模块的安装包、示例程序,SDK目录结构如下:

文件夹名

备注

sophon-img

SoC模式安装包等

sophon_media

支持SOPHON设备硬件加速的多媒体库

tpu-mlir

TPU编译器工具链

tpu-perf

模型性能和精度验证工具包

sophon-stream

基于pipeline的高性能推理框架

sophon-demo

针对单模型或者场景的综合例程

sophon-sail

对底层接口进行C++/Python API封装的接口库

isp-tools

ISP各个模块的参数调节工具

doc

各个模块的文档资料合集

7.8.2. 准备BM1688/CV186AH的bmodel

重新编译能在BM1688/CV186AH上运行的bmodel,需要使用能够支持BM1688/CV186AH的tpu-mlir。

一般来说,有以下几个步骤:

  1. 准备一台x86 ubuntu,相应的规格参数,取决于需要编译的模型大小,建议运行内存32GB以上,这样足够编译绝大多数模型。

  2. 运行如下命令,搭建tpu-mlir环境:

    # 拉取latest版本docker,目前对应tpuc_dev:v3.2,如果您的环境已经有这个image了,也需要重新执行以下命令。
    docker pull sophgo/tpuc_dev:latest
    
    # 这里将本级目录映射到docker内的/workspace目录,用户需要根据实际情况将demo的目录映射到docker里面
    # myname只是举个名字的例子, 请指定成自己想要的容器的名字
    docker run --privileged --name myname -v $PWD:/workspace -it sophgo/tpuc_dev:latest
    
    # 此时已经进入docker,并在/workspace目录下
    
    # 通过pip下载tpu_mlir,如果下不下来,可以使用清华源加速。
    pip install tpu_mlir
    
    # TPU-MLIR在对不同框架模型处理时所需的依赖不同。对于onnx或torch生成的模型文件,使用类似下面命令安装额外的依赖环境:
    pip install tpu_mlir[onnx]
    pip install tpu_mlir[torch]
    
    # 目前支持五种配置: onnx, torch, tensorflow, caffe, paddle。可使用一条命令安装多个配置,也可直接安装全部依赖环境:
    pip install tpu_mlir[onnx,torch]
    pip install tpu_mlir[all]
    
  3. 编译模型:

    只要将以前的编译命令或脚本中model_deploy.py部分的 --processor ,参数值更改成bm1688/cv186x,其他的部分都不用改动,运行之后就可以获取能在BM1688/CV186AH上运行的bmodel。

  4. 编译BM1688双核模型:

    BM1688由两个相同的核组成,支持一个模型的数据切分到两个核上面跑,tpu-mlir model_deploy.py为BM1688新增了 --num_core 参数,如果您想要一个模型跑两个核,可以在model_deploy.py中新增 --num_core 2 参数,这样就编译出来的模型,会由两个核来执行。

  5. 量化注意事项:

    以前的calibration_table和qtable均是可以复用的,如果在mlir编译bmodel的过程中出现类似算子不支持的报错,或者量化出来的模型精度不好,再重新生成calibration_table或qtable。

7.8.3. 准备编译依赖的SDK

如果您使用C++编程,您仍然需要获取sophon-img目录下的libsophon_soc_${x.y.z}/_aarch64.tar.gz和sophon_media目录下的sophon-media-soc_${x.y.z}/_aarch64.tar.gz发布包,作为交叉编译依赖的头文件和库文件。

如果以前有手动链接 bmion/bmjpulite/bmjpuapi/bmvpulite/bmvpuapi/bmvideo/bmvppapi 等库,可以直接去掉,这些库其实并没有暴露接口给用户,它们是供底层调用的。

和BM1684/BM1684X有一点不同的是,目前sophon_media中提供的库还依赖libisp模块,如果您使用BM1688/CV186AH的GeminiSDK1.3以上版本,您还需要做这些操作:

从sdk中获取sophon-img/bsp-debs/目录下的sophon-soc-libisp_${x.y.z}_arm64.deb,然后运行如下命令:

dpkg -x sophon-soc-libisp_${x.y.z}_arm64.deb sophon-libisp
cp -rf sophon-libisp/opt/sophon/sophon-soc-libisp_${x.y.z}/lib ${soc-sdk} #将libisp的库添加到已有的依赖库中。

如果您使用Python编程,那只需要重新编译sophon-sail的.whl安装包,编译流程与之前相同,参考sophon-sail开发指南即可。BM1688 SoC上自带libsophon和sophon_media的runtime。

7.8.4. SDK版本≥1.7 兼容性适配

BM1688/CV186AH SOPHONSDK 1.7及以上版本,对兼容性问题做了进一步的优化,只需要保证您的代码引入了以下头文件即可。

#include <bmcv_api.h>

7.8.4.1. 头文件改动

  1. bmcv_api.h已废弃,兼容性解决办法如下:

    #if !(BMCV_VERSION_MAJOR > 1)
    #include <bmcv_api.h>
    #endif
    

7.8.4.2. bmcv改动

  1. 函数参数变为指针:

    DECL_EXPORT bm_status_t bm_image_destroy(bm_image image)
    

    变为

    DECL_EXPORT bm_status_t bm_image_destroy(bm_image *image)
    

    兼容性解决办法如下:

    1. 在公共头文件中添加如下代码:

    #if BMCV_VERSION_MAJOR > 1
        static inline bm_status_t bm_image_destroy(bm_image& image){
        return bm_image_destroy(&image);
        }
    #endif
    
  2. 函数名称变化:

    bm_image_dev_mem_alloc
    

    变为

    bm_image_alloc_dev_mem
    

    兼容性解决办法:

    1. 在公共头文件中封装一个相同功能的旧接口。

  3. 接口名称修正:

    bm_image_dettach_contiguous_mem
    

    修正为

    bm_image_detach_contiguous_mem
    

    兼容性解决办法:

    1. 在公共头文件中封装一个相同功能的旧接口。

  4. 结构体名称修正

    bmcv_padding_atrr_t
    

    修正为

    bmcv_padding_attr_t
    

    兼容性解决办法:

    1. 在公共头文件中添加 typedef bmcv_padding_attr_t bmcv_padding_atrr_t;

  5. 接口废弃:

    bmcv_image_crop
    

    兼容性解决办法:

    1. 使用bmcv_image_vpp_convert来代替。

    2. 或者在公共头文件使用bmcv_image_vpp_convert封装一个bmcv_image_crop接口。

  6. 数据类型废弃:

    DATA_TYPE_EXT_4N_BYTE_SIGNED
    DATA_TYPE_EXT_4N_BYTE
    

    兼容性解决办法:

    1. 4N数据类型在以前的SDK中也很少使用,不建议再使用4N数据类型,改用1N数据类型。

  7. 内存布局改动导致的接口功能改动:

    bm_image_alloc_dev_mem(heap_id = 2)
    bm_image_alloc_dev_mem_heap_mask(heap_mask = 1 << 2)
    bm_image_alloc_contiguous_mem_heap_mask(heap_mask = 1 << 2)
    

    BM1688/CV186AH上只有两个heap,原来放在heap2的内存需要挪到heap1,否则分配失败。如上接口的heap_id/heap_mask参数需要改为:

    bm_image_alloc_dev_mem(heap_id = 1)
    bm_image_alloc_dev_mem_heap_mask(heap_mask = 1 << 1)
    bm_image_alloc_contiguous_mem_heap_mask(heap_mask = 1 << 1)
    
  8. 暂未支持的接口:

    bmcv_base64_enc()
    bmcv_base64_dec()
    bmcv_faiss_indexflatIP()
    bmcv_nms()
    bmcv_nms_ext()
    bmcv_fft_1d_create_plan()
    bmcv_fft_2d_create_plan()
    bmcv_fft_execute()
    bmcv_fft_execute_real_input()
    bmcv_fft_destroy_plan()
    

7.8.4.3. ffmpeg改动

ffmpeg版本从4.1升级到了6.0,由此引入了一些ffmpeg本身的改动,如下:

  1. 接口废弃:

    av_register_all
    

    兼容性解决办法:

    1. 去掉

    2. 或者封装一个av_register_all。

    avcodec_decode_video2
    avcodec_encode_video2
    

    兼容性解决办法:

    1. 按照ffmpeg文档,改成avcodec_send_packet和avcodec_receive_frame的形式。

    2. 可以自己封装一个avcodec_decode_video2,参考https://github.com/sophgo/sophon-demo/blob/release/include/ff_decode.hpp

    3. 可以自己封装一个avcodec_encode_video2,参考sophon-sail src/internal.h

  2. 结构体或函数类型变为const:

    struct AVOutputFormat *oformat;
    AVInputFormat* av_find_input_format
    AVCodec* avcodec_find_decoder
    AVOutputFormat* av_guess_format
    AVCodec* avcodec_find_decoder_by_name
    AVCodec* avcodec_find_decoder_by_name
    

    变为

    const struct AVOutputFormat *oformat
    const AVInputFormat* av_find_input_format
    const AVCodec* avcodec_find_decoder
    const AVOutputFormat* av_guess_format
    const AVCodec* avcodec_find_decoder_by_name
    const AVCodec* avcodec_find_decoder_by_name
    

    兼容性解决办法:

    1. 使用const_cast去掉const修饰符。

  3. 结构体成员变量变化:

    AVStream->codec
    

    变为

    AVStream->codecpar
    

    兼容性解决办法:

    1. avcodec_parameters_to_context重新获取上下文,avcodec_parameters_from_context把上下文内容重新拷贝到流中。

7.8.4.4. bmlib改动

  1. 新增接口:

    DECL_EXPORT bm_status_t bm_thread_sync_from_core(bm_handle_t handle, int core_id);
    

    功能描述:

    可以指定只sync某个核,在每个核各跑一个模型时会用到。

  2. 内存布局改动导致的接口功能改动:

    bm_malloc_device_byte_heap(heap_id = 2)
    bm_malloc_device_byte_heap_mask(heap_mask = 1 << 2)
    

    BM1688/CV186AH上只有两个heap,原来放在heap2的内存需要挪到heap1,否则分配失败。如上接口的heap_id/heap_mask参数需要改为:

    bm_malloc_device_byte_heap(heap_id = 1)
    bm_malloc_device_byte_heap_mask(heap_mask = 1 << 1)
    

7.8.4.5. bmrt改动

  1. 新增接口:

    DECL_EXPORT bool bmrt_launch_tensor_multi_cores(void *p_bmrt,
                                                    const char *net_name,
                                                    const bm_tensor_t input_tensors[],
                                                    int input_num,
                                                    bm_tensor_t output_tensors[],
                                                    int output_num,
                                                    bool user_mem,
                                                    bool user_stmode,
                                                    const int *core_list,
                                                    int core_num);
    

    功能描述:

    该接口可以将单核模型指定在不同的核上运行,具体请查看SOPHONSDK的bmruntime接口文档或源码。

7.8.5. 准备BM1688/CV186AH运行环境

BM1688/CV186AH的刷机步骤和BM1684/BM1684X相同,具体可以看相关的产品使用手册,在 获取BM1688/CV186AH SOPHONSDK 章节下载的SDK中,sophon-img/sdcard.tgz文件就是刷机包。

准备好运行环境之后,就可以将编译好的程序拷贝到BM1688/CV186AH SoC上执行了。

7.8.6. 其他注意事项

  1. bmrt、bmcv相关的操作,最好把各自分配的内存隔离开,bmrt需要用到的内存放在heap0(也就是npu heap),bmcv需要用到的内存则放在heap1(也就是vpp heap)。

  2. 由于BM1688的内存减小,ddr是全interleave的,没有带宽分配问题,因此不再预留vpu heap,多媒体模块共用vpp heap。

  3. bm1688的sdk目前只把ddr划分成npu、vpp两个heap,查看方法改为:

    sudo cat /sys/kernel/debug/ion/cvi_vpp_heap_dump/summary
    sudo cat /sys/kernel/debug/ion/cvi_npu_heap_dump/summary
    
  4. 内存布局修改工具:SoC模式内存修改工具

    可以兼容BM1688/CV186AH Gemini v1.5以上SDK,vpu heap需要设置为0。