在实际场景中,深度学习模型通常通过 PyTorch、TensorFlow 等框架来完成,直接通过这些模型来进行推理效率并不高,特别是对延时要求严格的线上场景。由此,经过工业界和学术界数年的探索,模型部署有了一条流行的流水线:

这一条流水线解决了模型部署中的两大难点:使用对接深度学习框架和推理引擎的中间表示,开发者不必担心如何在新环境中运行各个复杂的框架;通过中间表示的网络结构优化和推理引擎对运算的底层优化,模型的运算效率大幅提升。

在本文中,我们尝试以 ONNX 模型作为中介将 PyTorch 模型转换为 NCNN 模型

一、将 PyTorch 模型转换为 ONNX 模型

1.1 配置环境

配置 PyTorch 环境的过程可以参考官方网站

安装 ONNX Runtime 和 ONNX Smiplifier:

pip install onnxruntime
pip install onnx-simplifier

1.2 转换模型

在准备好相关环境后,使用以下 Python 代码即可将 PyTorch 模型转换为 ONNX 模型:

import torch.onnx
import torch
import timm


dummy_input = torch.randn(1, 3, 299, 299)

model = timm.create_model('inception_v3', num_classes=1000, pretrained=True)
model.eval()

torch.onnx.export(model,                     # model being run
                  dummy_input,               # model input (or a tuple for multiple inputs)
                  "./out/inception_v3.onnx", # where to save the model (can be a file or file-like object)
                  export_params=True,        # store the trained parameter weights inside the model file

                  do_constant_folding=True,  # whether to execute constant folding for optimization
                  input_names = ['input'],   # the model's input names
                  output_names = ['output'], # the model's output names
                 )

为了避免出现运行失败的情况,在将 ONNX 模型转换为 NCNN 模型前,我们需要简化ONNX 模型:

onnxsim ./out/inception_v3.onnx ./out/inception_v3-sim.onnx

1.3 验证模型

在转换后,需要对比 PyTorch 模型和转换后得到的 ONNX 模型的推理结果是否一致,以验证转换是否成功,可以使用以下代码:

import torch
import onnxruntime
import numpy as np
import cv2
import timm

#test image
img_path = "59204d6bb0c234eb.png"
img = cv2.imread(img_path)
img = cv2.resize(img, (299, 299))
img = np.transpose(img, (2, 0, 1)).astype(np.float32)
img = torch.from_numpy(img)
img = img.unsqueeze(0)

# pytorch test
model = timm.create_model('inception_v3', num_classes=1000, pretrained=True)
model.eval()

# pytorch test
output = model(img)
val, cls = torch.max(output.data, 1)
print("[PyTorch]--->predicted class:", cls.item())
print("[PyTorch]--->predicted value:", val.item())

# onnx test
sess = onnxruntime.InferenceSession("./out/inception_v3-sim.onnx")
x = "input"
y = ["output"]
output = sess.run(y, {x : img.numpy()})
cls = np.argmax(output[0][0], axis=0)
val = output[0][0][cls]
print("[ONNX]--->predicted class:", cls)
print("[ONNX]--->predicted value:", val)

可见,PyTorch 模型和 ONNX 模型的推理结果一致,说明转换成功:

二、将 ONNX 模型转换为 NCNN 模型

拉取 NCNN 代码:

git clone https://github.com/Tencent/ncnn.git

安装相关依赖:

sudo apt update
sudo apt install build-essential git cmake libprotobuf-dev protobuf-compiler libvulkan-dev vulkan-utils libopencv-dev

编译 Vulkan 后端:

wget https://sdk.lunarg.com/sdk/download/1.2.182.0/linux/vulkansdk-linux-x86_64-1.2.182.0.tar.gz
tar xvf vulkansdk-linux-x86_64-1.2.182.0.tar.gz
export VULKAN_SDK=$(pwd)/1.2.182.0/x86_64

拉取 NCNN 子模块:

cd ncnn
git submodule update --init

编译 NCNN:

mkdir -p build-x86
cd build-x86
cmake -DCMAKE_BUILD_TYPE=Release -DNCNN_VULKAN=ON -DNCNN_SYSTEM_GLSLANG=ON -DNCNN_BUILD_EXAMPLES=ON ..
make -j$(nproc)

如果使用cmake命令时提示:CMake 3.14.0 or higher is required. You are running version 3.10.2,则需要升级cmake,可以执行以下命令:

sudo apt remove cmake  # 删除旧版本的cmake

sudo apt-get install build-essential libssl-dev
wget https://github.com/Kitware/CMake/releases/download/v3.20.0/cmake-3.20.0.tar.gz
tar -zxvf cmake-3.20.0.tar.gz
cd cmake-3.20.0
./bootstrap
make
sudo make install

cmake --version 

编译结束之后会在 ./build-x86/tools/onnx/下得到 onnx2ncnn可执行文件,即将 ONNX 模型转换为 NCNN 模型的转换工具。将上面得到的 inception_v3-sim.onnx拷贝至该目录,执行命令:

cd tools/onnx/
./onnx2ncnn inception_v3-sim.onnx inception_v3.param inception_v3.bin

即可转换得到 NCNN 模型。

参考资料

[1] pytorch->onnx->ncnn模型移植

[2] pytorch转ncnn及其测试

[3] V831上部署resnet18分类网络

[4] onnx2ncnn并在pc端调用ncnn模型

另外,本文只是最基本的部署教程,如果涉及到复杂操作(例如自定义 ONNX 中没有的算子),建议阅读由 MMDeploy 提供的文档:操作概述第一章:模型部署简介等。

最后修改:2023 年 07 月 29 日
如果觉得我的文章对你有用,请随意赞赏