Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理

Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理

概述:本文主要讲述把MobileNet转成华为Altas服务器离线推理om模型的过程,本人在转换过程中也遇到过比较多的坑,这里把我的经验记录下来,希望大家可以少走点弯路,如果大家觉得此教程有用,记得订阅点赞加分享哦.

1. 下载官方的样例

ATC MobileNet在ascend的ModelZoo已经有相关的样例,我们先通过下面的地址去下载样例,在下面地址点击立即下载即可.

https://www.hiascend.com/zh/software/modelzoo/detail/1/a2951ef07c40424a9b0e39237466e383

下载并解压,里面有官方提供的通过ImageNet训练出来的模型,如下,
Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理_第1张图片

2. 安装相关的依赖

我们需要为环境安装相对应的依赖,我们这里是使用ARM架构的Altas服务器,我解决完依赖问题时候,对应的Python环境包如下所示:

asttokens==2.0.4
astunparse==1.6.3
attrs==20.3.0
auto-tune @ file:///root/selfgz270731700/fwkacllib/lib64/auto_tune-0.1.0-py3-none-any.whl
certifi==2020.12.5
cffi==1.14.4
chardet==4.0.0
click==7.1.2
Cython==0.29.21
decorator==4.4.2
easydict==1.9
Flask==1.1.2
flatbuffers==1.12
geffnet @ file:///home/jxl/guochan/dxaisix/geffnet-1.0.2-py3-none-any.whl
grpcio==1.35.0
grpcio-tools==1.35.0
gunicorn @ file:///home/jxl/guochan/dxaisix/gunicorn-20.0.4-py2.py3-none-any.whl
hccl @ file:///root/selfgz270731700/fwkacllib/lib64/hccl-0.1.0-py3-none-any.whl
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.2
joblib==0.17.0
MarkupSafe==1.1.1
mindspore-ascend @ file:///tmp/mindspore_ascend-1.1.1-cp37-cp37m-linux_aarch64.whl
mpmath==1.1.0
numpy @ file:///home/jxl/guochan/whl/numpy-1.21.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
onnx @ file:///home/jxl/guochan/dxaisix/onnx-1.10.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
onnxconverter-common==1.7.0
onnxruntime @ file:///home/jxl/guochan/dxaisix/onnxruntime-1.10.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
packaging==20.9
pathlib2==2.3.5
Pillow==8.1.0
protobuf==3.14.0
psutil==5.8.0
pycparser==2.20
pyparsing==2.4.7
PyYAML==5.4.1
requests==2.25.1
schedule-search @ file:///root/selfgz270731700/fwkacllib/lib64/schedule_search-0.1.0-py3-none-any.whl
scikit-learn==0.23.2
scipy==1.6.0
six==1.15.0
skl2onnx @ file:///home/jxl/guochan/dxaisix/skl2onnx-1.10.3-py2.py3-none-any.whl
sympy==1.4
te @ file:///root/selfgz270731700/fwkacllib/lib64/te-0.4.0-py3-none-any.whl
tensorflow-aarch64==1.2
threadpoolctl==2.1.0
topi @ file:///root/selfgz270731700/fwkacllib/lib64/topi-0.4.0-py3-none-any.whl
torch @ file:///home/jxl/guochan/dxaisix/torch-1.10.0-cp37-cp37m-manylinux2014_aarch64.whl
torchvision @ file:///home/jxl/guochan/whl/torchvision-0.10.0-cp37-cp37m-manylinux2014_aarch64.whl
typing-extensions==3.7.4.3
urllib3==1.26.3
Werkzeug==1.0.1

3. 准备相关的转换文件

我们把官方无用的pth模型(Pytorch输出),和om模型删除,并换上自己训练好准备转换的模型,这里我把模型统一放在models目录下面,如下所示:
Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理_第2张图片

对于上图中,其他的文件解释如下:

atlas_utils(现在改名为acllite):

Pyacl调用组件包,可以通过下面地址下载:

https://gitee.com/ascend/samples/tree/master/python/common

nc

存放我们这个实例中的测试图片

tools

存放我们这个实例中的自定义预处理文件

mobilenetv3.py文件

存放我们定义的mobilenetv3文件

至此,前期文件准备已经完成

4. pth模型转onnx模型并测试

更改MobileNetV3_pth2onnx.py,使其模型导入为自定义的模型,其中需要修改的部分如下,下图蓝色部分,这里需要传入正确的class_num,另外如果inputsize不是224*224的话,需要改32行的input,这里是默认input所以暂时不用修改.
Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理_第3张图片
通过下面的命令调用MobileNetV3_pth2onnx.py把pth模型转换成onnx模型,转换完成以后,models文件夹下面就会多一个mobilenetv3-81-best.onnx模型

python3 MobileNetV3_pth2onnx.py ./models/mobilenetv3-81-best.pth ./models/mobilenetv3-81-best.onnx

测试onnx模型

新建predict_onnx.py文件,使用转换前一样的预处理函数,用onnxrutime去调用onnx模型进行前向运算,查看输出结果和原来的是否一致

import os
import cv2
from torchvision import transforms
from tools import my_transforms
from tools.utils import BaseTransform
import onnxruntime   # to inference ONNX models, we use the ONNX Runtime


train_size = (256, 256)
net_size = (224, 224)
rgb_means = (0.42819217, 0.4287907, 0.42214316)
rgb_std = (0.26126036, 0.24752016, 0.24400638)


def predict_onnx(img_path):
    img_src = cv2.imread(img_path)
    transformer = transforms.Compose([
        my_transforms.Resize(train_size),
        my_transforms.CenterCrop(net_size),
        BaseTransform(net_size, rgb_means, rgb_std)])
    img_src = transformer(img_src)
    img_src = img_src.unsqueeze(0)
    input_data = img_src.numpy()

    print("input_data shape {}".format(input_data.shape))
    session = onnxruntime.InferenceSession('./models/mobilenetv3-81-best.onnx', None)
    raw_result = session.run([], {'image': input_data})
    return raw_result


if __name__ == '__main__':
    img_list = os.listdir("./nc")
    for img_name in img_list:
        print("predict: {}".format(img_name))
        result = predict_onnx("./nc/{}".format(img_name))
        print(result)

这里的输出结果,如下所示,与转换之前的结果是一致的
Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理_第4张图片

5. 把onnx模型转换成Pyacl所使用的om格式模型并测试使用

5.1 配置环境变量

下面需要用到模型转换工具ATC,以及PYACL离线推理包,需要先配置环境变量,过程如下,其中ascendtools的安装环境需要自己更改,本实例是安装在/usr/local/Ascend/ascend-toolkit/latest

配置ATC环境变量

export PATH=/usr/local/Ascend/ascend-toolkit/latest/atc/ccec_compiler/bin:/usr/local/Ascend/ascend-toolkit/latest/atc/bin:$PATH
export ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/arm64-linux/opp
export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/

配置PYACL环境变量

export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/arm64-linux/pyACL/python/site-packages/acl:$PYTHONPATH
export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/arm64-linux/acllib/lib64:$LD_LIBRARY_PATH

5.2 onnx模型转om模型

接下来把onnx模型转换成om模型,运行下面的命令即可,运行成功后,模型

atc --framework=5 \
    --model=./models/mobilenetv3-81-best.onnx \
    --input_format=NCHW \
    --input_shape="image:1,3,224,224" \
    --output=./models/mobilenetv3-81-best \
    --log=debug \
    --soc_version=Ascend910

运行结果:
Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理_第5张图片

5.3 使用PYACL测试om模型

新建predict_pyacl.py文件,与onnx一样,参照原模型去写预处理代码,并使用pyacl的api调用离线模型

from atlas_utils.acl_model import Model
from atlas_utils.acl_resource import AclResource
from torchvision import transforms
import os
import acl
import cv2
from tools import my_transforms
from tools.utils import BaseTransform


acl_resource = AclResource()
acl_resource.init()
model = Model("models/mobilenetv3-81-best.om")
dims, ret = acl.mdl.get_input_dims(model._model_desc, 0)
_, _, height, width = tuple(dims["dims"])
print("model input: {}".format(tuple(dims["dims"])))


train_size = (256, 256)
net_size = (224, 224)
rgb_means = (0.42819217, 0.4287907, 0.42214316)
rgb_std = (0.26126036, 0.24752016, 0.24400638)


def predict_acl(img_path):
    """
    Program execution with picture directory parameters
    """
    """
    模仿img_preprocess.py编写
    """
    img_src = cv2.imread(img_path)

    transformer = transforms.Compose([
        my_transforms.Resize(train_size),
        my_transforms.CenterCrop(net_size),
        BaseTransform(net_size, rgb_means, rgb_std)])

    img_src = transformer(img_src)
    img_src = img_src.unsqueeze(0)
    input_data = img_src.numpy()

    ptr, input_data = acl.util.numpy_contiguous_to_ptr(input_data)

    print("input_data shape {}".format(input_data.shape))
    result = model.execute([input_data, ])
    return result


if __name__ == '__main__':
    img_list = os.listdir("./nc")
    for img_name in img_list:
        print("predict: {}".format(img_name))
        result = predict_acl("./nc/{}".format(img_name))
        print(result)

运行并测试代码,输出如下结果:
Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理_第6张图片
可见输出的结果和onnx模型是一致的,证明转换成功了,

5.4 注意

这里有一个天坑,本人花了很长时间才确认的,如果自定义预处理中,输出的numpy数组在内存不是连续存储的,会出现下面的warning

/home/jxl/guochan/guochan_src_code/mobilenetv3/atlas_utils/acl_model.py:142: Warning: The input ndarray is discontiguous. Please use acl.util.numpy_contiguous_to_ptr instead.
  ptr = acl.util.numpy_to_ptr(input_data)

ATTENTION

这个warning是不能忽略的,否则,输出的不肯能是我们想要的结果.我们先通过下面语句去看是否连续

input_data.flags

输出:
Pytorch版本MobileNetV3转ONNX然后转om模型使用Pyacl离线推理_第7张图片
发现和上面的warning一致,储存是不连续的,所以我们需要用到下面语句,把他转成连续存储的numpy数组:

ptr, input_data = acl.util.numpy_contiguous_to_ptr(input_data)

ALL DONE!
本期的教程就到这里啦,谢谢大家的关注哦,如果大家觉得有用,记得点赞和分享哦.

你可能感兴趣的:(pytorch,python,人工智能)