分享点之前的工作,针对高通芯片部署的,主要是流程方面的解读
参考资料: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版本不一致,输入数据通道排布不一致
### 原创文章,转载需要本人同意