费尽心血训练好的深度学习模型如何给别人展示?只在服务器上运行demo怎么吸引别人的目光?怎么才能让自己的成果落地?这篇文章带你进入模型部署的大门。
0 前言
模型部署的步骤:
- 训练一个深度学习模型;
- 使用不同的推理框架对模型进行推理转换;
- 在应用平台运行转换好的模型。
步骤看起来比较简单,但是牵扯的到的知识还是比较多。在实际应用过程中,我们使用的模型通常不会太简单,因为要确保模型的精度。但是,实际应用场景往往需要模型速度与精度能达到一个较好的平衡。因此这就需要在算法(剪枝,压缩等)与底层(手写加速算作)去优化模型。但是,我们现在可以站在巨人的肩膀上去眺望世界,因此,该文章会给大家介绍一些常用的开源推理框架,大家一起参考学习。毕竟大牛团队做出来的好用一些。。。
1 ONNX、NCNN、OpenVINO、 TensorRT、Mediapipe模型部署那家强?
1.1 ONNX
简介:
开放神经网络交换ONNX(Open Neural Network Exchange)是一套表示深度神经网络模型的开放格式,由微软和Facebook于2017推出,然后迅速得到了各大厂商和框架的支持。通过短短几年的发展,已经成为表示深度学习模型的实际标准,并且通过ONNX-ML,可以支持传统非神经网络机器学习模型,大有一统整个AI模型交换标准。ONNX定义了一组与环境和平台无关的标准格式,为AI模型的互操作性提供了基础,使AI模型可以在不同框架和环境下交互使用。硬件和软件厂商可以基于ONNX标准优化模型性能,让所有兼容ONNX标准的框架受益,简单来说,ONNX就是模型转换的中间人。
使用场景:
无论你使用什么样的训练框架来训练模型(比如TensorFlow/Pytorch/OneFlow/Paddle),你都可以在训练后将这些框架的模型统一转为ONNX存储。ONNX文件不仅存储了神经网络模型的权重,还存储了模型的结构信息、网络中各层的输入输出等一些信息。目前,ONNX主要关注在模型预测方面(inferring),将转换后的ONNX模型,转换成我们需要使用不同框架部署的类型,可以很容易的部署在兼容ONNX的运行环境中。
使用方法:
[代码示例]在 ONNX 模型上运行形状推理:https://github.com/onnx/onnx
import onnx from onnx import helper, shape_inference from onnx import TensorProto # 预处理:创建一个包含两个节点的模型,Y是未知的 node1 = helper.make_node("Transpose", ["X"], ["Y"], perm=[1, 0, 2]) node2 = helper.make_node("Trans pose", ["Y"], ["Z"], perm=[1, 0, 2]) graph = helper.make_graph( [node1, node2], "two-transposes", [helper.make_tensor_value_info("X", TensorProto.FLOAT, (2, 3, 4))], [helper.make_tensor_value_info("Z", TensorProto.FLOAT, (2, 3, 4))], ) original_model = helper.make_model(graph, producer_name="onnx-examples") # 检查模型并打印Y的信息 onnx.checker.check_model(original_model) print(f"Before shape inference, the shape info of Y is:\n{original_model.graph.value_info}") # 在模型上进行推理 inferred_model = shape_inference.infer_shapes(original_model) # 检查模型并打印Y的信息 onnx.checker.check_model(inferred_model) print(f"After shape inference, the shape info of Y is:\n{inferred_model.graph.value_info}")
1.2 NCNN
简介:
ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架,也是腾讯优图实验室成立以来的第一个开源项目。ncnn 从设计之初深刻考虑手机端的部署和使用,无第三方依赖,跨平台,手机端 CPU 的速度快于目前所有已知的开源框架。基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能 App。ncnn 目前已在腾讯多款应用中使用,如 QQ、Qzone、微信、天天P图等。
使用场景:
从NCNN的发展矩阵可以看出,NCNN覆盖了几乎所有常用的系统平台,尤其是在移动平台上的适用性更好,在Linux、Windows和Android、以及iOS、macOS平台上都可以使用GPU来部署模型。
框架特点:
- 支持卷积神经网络,支持多输入和多分支结构,可计算部分分支
- 无任何第三方库依赖,不依赖 BLAS/NNPACK 等计算框架
- 纯 C++ 实现,跨平台,支持 Android / iOS 等
- ARM Neon 汇编级良心优化,计算速度极快
- 精细的内存管理和数据结构设计,内存占用极低
- 支持多核并行计算加速,ARM big.LITTLE CPU 调度优化
- 支持基于全新低消耗的 Vulkan API GPU 加速
- 可扩展的模型设计,支持 8bit 量化和半精度浮点存储,可导入 caffe/pytorch/mxnet/onnx/darknet/keras/tensorflow(mlir) 模型
- 支持直接内存零拷贝引用加载网络模型
- 可注册自定义层实现并扩展
使用方法:
[代码示例]输入数据并推理输出:https://github.com/Tencent/ncnn/wiki
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include "net.h" int main() { // opencv读取输入图片 cv::Mat img = cv::imread("image.ppm", CV_LOAD_IMAGE_GRAYSCALE); int w = img.cols; int h = img.rows; // 减均值以及缩放操作,最后输入数据的值域为[-1,1] ncnn::Mat in = ncnn::Mat::from_pixels_resize(img.data, ncnn::Mat::PIXEL_GRAY, w, h, 60, 60); float mean[1] = { 128.f }; float norm[1] = { 1/128.f }; in.substract_mean_normalize(mean, norm); // 构建NCNN的net,并加载转换好的模型 ncnn::Net net; net.load_param("model.param"); net.load_model("model.bin"); // 创建网络提取器,设置网络输入,线程数,light模式等等 ncnn::Extractor ex = net.create_extractor(); ex.set_light_mode(true); ex.set_num_threads(4); ex.input("data", in); // 调用extract接口,完成网络推理,获得输出结果 ncnn::Mat feat; ex.extract("output", feat); return 0;
1.3 OpenVINO
简介:
OpenVINO是一种可以加快高性能计算机视觉和深度学习视觉应用开发速度的工具套件,支持各种英特尔平台的硬件加速器上进行深度学习,并且允许直接异构执行。OpenVINO™工具包是用于快速开发应用程序和解决方案的综合工具包,可解决各种任务,包括模拟人类视觉,自动语音识别,自然语言处理,推荐系统等。该工具包基于最新一代的人工神经网络,包括卷积神经网络(CNN),循环和基于注意力的网络,可在英特尔®硬件上扩展计算机视觉和非视觉工作负载,从而最大限度地提高性能。它通过从边缘到云的高性能,人工智能和深度学习推理来加速应用程序。
使用场景:
框架特点:
OpenVINO在模型部署前,首先会对模型进行优化,模型优化器会对模型的拓扑结构进行优化,去掉不需要的层,对相同的运算进行融合、合并以加快运算效率,减少内存拷贝;FP16、INT8量化也可以在保证精度损失很小的前提下减小模型体积,提高模型的性能。在部署方面,OpenVIVO的开发也是相对比较简单的,提供了C、C++和python3种语言编程接口。它最大的优势呢,其实还是在Intel的不同硬件平台上进行部署的时候,移植会很方便。推理引擎对不同的硬件提供统一的接口,底层实现直接调用硬件指令集的加速库,应用程序开发人员不需要关心底层的硬件实现,即可在不同的硬件平台上加速模型推理。
- 在边缘启用基于CNN的深度学习推理
- 支持通过英特尔®Movidius™VPU在英特尔®CPU,英特尔®集成显卡,英特尔®神经计算棒2和英特尔®视觉加速器设计之间进行异构执行
- 通过易于使用的计算机视觉功能库和预先优化的内核加快上市时间
- 包括对计算机视觉标准(包括OpenCV *和OpenCL™)的优化调用
使用方法:
[代码示例]在应用程序中实现典型的 OpenVINO™ 运行推理:https://docs.openvino.ai/latest/openvino_docs_OV_UG_Integrate_OV_with_your_application.html
#include <openvino/openvino.hpp> // 1.创建 OpenVINO™ 核心以管理可用设备和读取模型对象 ov::Core core; // 2.为特定设备编译模型 ov::CompiledModel compiled_model = core.compile_model("model.onnx", "AUTO"); // 3.创建推理请求 ov::InferRequest infer_request = compiled_model.create_infer_request(); // 4.设置输入 // 获取模型的输入端口 auto input_port = compiled_model.input(); // 从外部存储器创建张量 ov::Tensor input_tensor(input_port.get_element_type(), input_port.get_shape(), memory_ptr); // 为模型设置一个输入张量 infer_request.set_input_tensor(input_tensor); // 5.开始推理 infer_request.start_async(); infer_request.wait(); // 6.处理推理结果 // 通过tensor_name获取输出张量 auto output = infer_request.get_tensor("tensor_name"); const float \*output_buffer = output.data<const float>(); // output_buffer[] - 访问输出张量数据 // 7.释放分配的对象(仅适用于C) ov_shape_free(&input_shape); ov_tensor_free(output_tensor); ov_output_const_port_free(input_port); ov_tensor_free(tensor); ov_infer_request_free(infer_request); ov_compiled_model_free(compiled_model); ov_model_free(model); ov_core_free(core);
// 为项目创建结构 project/ ├── CMakeLists.txt - CMake file to build ├── ... - Additional folders like includes/ └── src/ - source folder └── main.cpp build/ - build directory ...
// 创建 Cmake 脚本 cmake_minimum_required(VERSION 3.10) set(CMAKE_CXX_STANDARD 11) find_package(OpenVINO REQUIRED) add_executable(${TARGET_NAME} src/main.cpp) target_link_libraries(${TARGET_NAME} PRIVATE openvino::runtime)
// 构建项目 cd build/ cmake ../project cmake --build .
原文首发微信公众号【自动驾驶之心】:一个专注自动驾驶与AI的社区(https://mp.weixin.qq.com/s/NK-0tfm_5KxmOfFHpK5mBA)