snpe流程扫盲

分享点之前的工作,针对高通芯片部署的,主要是流程方面的解读

参考资料:Snapdragon Neural Processing Engine SDK: Tools

模型转换:

        snpe支持从pytorch和onnx格式转为dlc

        a. pytorch --> onnx

        在模型转换之前最好将torch转onnx以便debug,参考以下代码将torch转onnx

注:我这里代码都是手打的不严谨,思路应该没问题

import torch

###单输入
inputV = torch.rand(N,C,H,W,requires_grad=False)
input_names = ['input']
output_names = ['output']
model = your_model().eval()
torch.onnx.export(model,
        inputV,
        'model.onxx',
        input_names = input_names,
        output_names = output_names,
        verbose=True)

### 如果是多输入 
### forward需要定义为
class model():
    def __init__():
    
          ....
    def forward(inputA,inputB):

inputA = torch.rand()...
torch.onnx.export(model,
        (inputA,inputB),
        'model.onnx',
        opset_version = 11,  ### 这里要根绝snpe对不同网络的支持版本,对应调整onnx的版本
        do_constant_folding=True,
        input_names= input_names,
        output_nams = output_names,
        verbose=True)

 需要注意:

        1、pytorch模型需要在eval()状态下存储,再进行转换

        2、模型里不要包含,从tensor类型转换为numpy类型或者python的list类型的操作,会报错

b.onnx-->onnx-sim

经过上述步骤得到onnx模型之后,建议使用onnx-simplifier来简化模型结构,减少后续风险

onnxsim input_onnx_model output_onnx_model

c.onnx-->dlc

在安装onnx之后,使用以下命令来得到对应的dlc转换接口:ONNXDIR为python虚拟环境中onnx包的位置

参考以下代码来获得安装位置

import onnx
print(onnx.__file__)
cd $snpe_path/bin
source envesetup.sh -o $onnx_dir

接下来就可以使用snpe-onnx-to-dlc 进行从onnx到dlc的模型转换

snpe-onnx-to-dlc --input_network yourmodel.onnx --output_path yourmodel.dlc

一些个人经验:

 1、现在snpe不支持conv3d,conv1d, pool3d 这些层在模型转换期间会有对应的报错,你可以使用app:Netron来可视化onnx,来定位对应的报错位置,conv1d目前可以采用conv2d来替换,使用时需要对输入输入做对应的unsqueeze和squzze的维度转换。具体支持的算子可以参考:
Snapdragon Neural Processing Engine SDK: Supported Network Layers

我这里举个例子

class conv1d(nn.Module):
    def __init__(self):
        super(conv1d,self).__init__():
        self.net = nn.Sequential(
                nn.Conv1d(512,256,5,stride=1,padding=2),
                nn.BatchNorm1d(256),
                nn.RelU(),
                 )
    def forward(self,x):
        out = self.net(x)
        return out

class conv2d(nn.Module):
    def __init__(self):
        super(conv2d,self).__init__():
        self.net = nn.Sequential(
                nn.Conv1d(512,256,kernel_size=(1,5),stride=1,padding=(0,2)),
                nn.BatchNorm2d(256),
                nn.RelU(),
                 )
    def forward(self,x):
        out = self.net(x)
        return out

2.在模型转换过程中,warining是不能忽略的,比如Reduce_mean只能接受4维输入,且只能在最后一维做mean,这些warning回到是dlc的推理出错

3、模型转换的snpe版本和模型推理的snpe版本要保持一直,否则会导致精度不对齐

4、onnx和torch模型都会做tensor维度的自动推导,比如下方的代码在onnxruntime和torch推理都不会报错

>>> import torch
>>> a = torch.tensor([[1,2,3],[4,5,6]])
>>> a.shape
torch.Size([2, 3])
>>> b = torch.tensor([1,1,1])
>>> b.shape
torch.Size([3])
>>> c = a + b
>>> c
tensor([[2, 3, 4],
        [5, 6, 7]])
>>>

但是有这种代码的模型dlc无法推理,需要保持tensor的形状一致

前处理

        官方给出我前处理是在python脚本中完成的

        Snapdragon Neural Processing Engine SDK: Running a ONNX Model with SNPE SDK

 具体来说,会在PIL.Image读图之后,进行图像的裁剪归一化等步骤,再将图片转为numpy.raw数据存下来

以VGG为例

        运行得到输入图片raw格式和包含输入路径的rawlist.txt

python snpe/models/VGG/scripts/create_VGG_raws.py -i $input_path -d $output_path

在端到端推理的c++工程中,需要注意以下几点

1、PIL.Image读取的图片是以HWC+RGB的格式进行排布的,而opencv2的cv::Mat是以 HWC+BGR的方式排列的,前处理的这个部分要对齐

2、由于jpg和jpeg等格式的图像会进行压缩,导致PIL.Image和opencv2读取的图片数据稍有不同,不同的数据在输出上会有gap,可以使用png格式的图片作为统一输入

3、snpe模型推理默认为fp32数据,如果没有自定义的修改,要确保图像输入数据也是fp32

PS:

        官方给出的工程是Makefile编译,在这个上面插入opencv会有些困难,改为cmake可以参考我下面的(X86)

免责声明:我部分的字母可能打错。。该有的东西都有的

cmake_minimum_required(VERSION 3.0)

project(snpe)

SET(CMAKE_SYSTEM_VERSION 700)

SET(CMAKE_CXX_STANDARD 11)

SET(SNPE_ROOT /home/snpe-1.66.03729/)

SET(CMAKE_CXX_FLAGS ''-std=c++11 -std=gnu+11 -fPIC -Wno-write-strings -march=x86)

SET(CMAKE_BUILD_TYPE ''Release")

SET(PROJECT_DIR $(CMAKE_CURRENT_SOURCE_DIR))

###  头文件

INCLUDE_DIRECTORIES(''/snpe/samples/NativeCpp/SampleCode/jni")

INCLUDE_DIRECTORIES(''$(SNPE_ROOT/include/zdl')

LINK_DIRECTORIES(''$(SNPE_ROOT)/lib/x86_64-linux-clang'')

SET(OPENCV_LIB 把你要的opencv库都列在这里)

SET(COMMON_LIB SNPE)

FILE(GLOB SRC_FILES /snpe/examples/NativeCpp/SampleCode/jni/*.cpp)

SET(LIBS $(OPENCV_LIB) $(SRC_FILES))

add_executable(snpe-demo $(SRC_FILES))

target_link_libraries(snpe-demo $(LIBS))

 模型推理:

官方给出的dlc推理方式有两种,性能一致,使用方法略有不同

1、snpe-net-run 不需要配置环境变量,直接运行,将预测结果存在raw文件中

2、snpe-sample 由于是一个c++工程,包含了推理精度,推理环境,自定义插件等多种设置,根据不同芯片架构使用不同的<makefile for the target>

cd $SNPE_ROOT/examples/NativeCpp/SampleCode
make -f <makefile for target>

snpe-sample推理需要加上绝对路径或配置环境变量

后处理:
        在分类VGG中,后处理主要包括argsort和softmax两个步骤,可以参考

/snpe/models/VGG/scripts/show_vgg_classifications.py

写在最后,

根据经验,模型不对齐的主要原因为,onnx版本不一致,转dlc版本不一致,输入数据通道排布不一致

### 原创文章,转载需要本人同意

SNPE Docker是一个包含Snapdragon Neural Processing Engine SDK、Caffe和ADB的Docker镜像。你可以使用以下步骤来构建和运行SNPE Docker镜像: **步骤1:构建Docker镜像** 使用以下命令构建Docker镜像: ``` docker build -t snpe . ``` **步骤2:运行Docker容器** 使用以下命令来运行Docker容器: ``` docker run -it --privileged -v ~/Git/snpe-1.13.0:/root/snpe -v... ``` 在这个命令中,你需要根据你自己的需求来设置相关的选项和挂载卷。 **步骤3:安装SNPE环境** 根据需求,你可以使用Docker镜像中的SNPE环境。根据你的需求,你可以通过以下步骤来安装SNPE环境: 1. 登录到Docker仓库: ``` docker login cr.d.xiaomi.net -u org_46522 -p 46370020336295373ad3815abd6db118 ``` 2. 拉取SNPE镜像: ``` docker pull cr.d.xiaomi.net/ailab-vision-doc/snpe_dev:18.04 ``` 3. 开启一个后台Docker容器: ``` docker run -it --privileged -d --name snpe-1.50 -v /dev/bus/usb:/dev/bus/usb -v /home/:/home/ --net=host cr.d.xiaomi.net/ailab-vision-doc/snpe_dev:18.04 ``` **步骤4:使用SNPE** 在启动的容器中,你可以使用以下命令来使用SNPE: 1. 启动一个容器: ``` # 查看之前已经启动的容器 docker container ls -a # 61744239ab70是容器的ID docker container start 61744239ab70 # 开启一个Docker终端 docker exec -it 61744239ab7 /bin/bash ``` 2. 如果在Docker镜像中没有对应版本的SNPE目录,你可以从SNPE官网下载对应版本的SNPE,并将其拷贝到`/root/snpe/`目录中。 3. 使用SNPE进行模型转换和量化。具体的步骤可以参考官方文档或者SNPE的使用指南。 希望以上信息能够帮助到你。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值