服装设计师必看的网站,百度人工服务在线咨询,杭州手机申请网站登录,网页制作成品网站OpenVINO C# API 常用 API 详解与演示 1 安装OpenVINO C# API2 导入程序集 3 初始化OpenVINO 运行时内核4 加载并获取模型信息4.1 加载模型4.2 获取模型信息 5 编译模型并创建推理请求6 张量Tensor6.1 张量的获取与设置6.2 张量的信息获取与设置 7 加载推理数据7.1 获取输入张量… OpenVINO C# API 常用 API 详解与演示 1 安装OpenVINO C# API2 导入程序集 3 初始化OpenVINO 运行时内核4 加载并获取模型信息4.1 加载模型4.2 获取模型信息 5 编译模型并创建推理请求6 张量Tensor6.1 张量的获取与设置6.2 张量的信息获取与设置 7 加载推理数据7.1 获取输入张量7.2 添加推理数据 8 模型推理9 获取推理结果10 释放分配的内存11 Yolov8分类模型示例12 总结 OpenVINO™ 工具套件可以加快深度学习视觉应用开发速度帮助用户在从边缘到云的各种英特尔平台上更加方便快捷的将 AI 模型部署到生产系统中。OpenVINO™ 2023.1 LTS 版本现已发布可帮助你快速轻松地开发卓越的人工智能应用并跨边缘和云端部署深度学习推理工作负载无论你处于人工智能编程的什么阶段。 C# 是由 C 和 C 衍生出来的一种安全的、稳定的、简单的、优雅的面向对象编程语言它综合了 VB 简单的可视化操作和 C 的高运行效率成为支持成为.NET 开发的首选语言。作为人工智能开发人员如果你希望在 C# 端使用 OpenVINO™ OpenVINO C# API将是你的首选并且制作了 NuGet 程序包实现在 C# 端了一站式安装与使用 OpenVINO™ 。 项目的首发网址OpenVINO™ C# API 详解与演示 | 开发者实战。 OpenVINO C# API在制作时参考了OpenVINO™ C API因此对于之前使用过OpenVINO™ 的人十分友好。下面表格向我们展示了 C# 与 C API的对应关系
ClassC APIC# API说明Core classov::CoreCoreOpenVINO运行时核心实体类Model classov::ModelModel用户自定义模型类CompiledModel classov::CompiledModelCompiledModel已编译的模型类Output classov:: Outputov::NodeOutput节点输出的句柄类Input classov:: Inputov::NodeInput节点输入的句柄类InferRequest classov::InferRequestov::InferRequest以异步或同步方式运行推断请求的类Tensor classov::TensorTensor张量Shape classov::ShapeShape张量的形状类 在本文中将会根据模型部署的一般步骤演示从模型加载到推理的方法函数使用方式并于C API 做对比。
1 安装OpenVINO C# API OpenVINO C# API 支持 NuGet 程序包安装方式这与在C中安装过程相比较为简单并且程序包中包含了最新版的 OpenVINO™ 2023.1 发行版本的 Release可以通 过 NuGet 安装后直接使用。 如果使用Visual Studio 编译该项目则可以通过 NuGet 程序包管理功能直接安装即可
如果通过dotnet命令方式安装通过下面语句进行安装即可
dotnet add package OpenVINO.CSharp.win2 导入程序集 OpenVINO C# API 程序集全部在CSharp命名空间下因此若要使用 OpenVINO C# API需要先引入命名空间
using OpenVinoSharp;3 初始化OpenVINO 运行时内核 Core类代表一个OpenVINO运行时核心实体后续的读取模型、加载模型等方法都需要通过 Core 类进行创建在封装C# API 时为了与 C API 对应也对 Core 类进行了封装并封装了与 C API 中对应的方法
在C#中的初始化方式
Core core new Core();在C中的初始化方式
ov::Core core;4 加载并获取模型信息
4.1 加载模型 OpenVINO™ 2022.1版本更新之后加载下面是所使用的 API 方法
API作用Core.read_model ()将模型从硬盘载入内存并返回Model对象。
在C#中加载模型的方式
Model model core.read_model(model_path);在C中的初始化方式
std::shared_ptrov::Model model core.read_model(model_path);4.2 获取模型信息 通过 Core.read_model ()方法获得的 Model 对象和通过 Core.compile_model ()方法获得的 CompiledModel 对象都支持直接访问属性获取输入与输出层信息。以Model对象获取模型信息为例下面是所使用的 API 方法
API作用Model.get_friendly_name()获取模型的friendly name。Model.input()获取模型的输入层并返回 Input对象。Model.output()获取模型的输出层并返回 Output对象。 Input/Output 主要是封装了模型网络层可以通过下面 API 实现获取模型的详细信息
API作用Output.get_any_name()获取模型网络层的名字。Output.get_element_type()获取模型网络层的数据类型并返回 OvType对象OvType主要封装了网络的基本数据类型。Output.get_shape()获取模型网络层的形状并返回 Shape对象Shape封装了网络层的形状数组。 在 C# 中通过下方代码可以直接获取模型的输入、输入层以及模型的friendly name
string model_name model.get_friendly_name();
Input input model.input();
Output output model.output();然后将模型具体信息打印到控制台页面
Console.WriteLine(Model name: {0}, model_name);
Console.WriteLine(/------- [In] -------/);
Console.WriteLine(Input name: {0}, input.get_any_name());
Console.WriteLine(Input type: {0}, input.get_element_type().to_string());
Console.WriteLine(Input shape: {0}, input.get_shape().to_string());
Console.WriteLine(/------- [Out] -------/);
Console.WriteLine(Output name: {0}, output.get_any_name());
Console.WriteLine(Output type: {0}, output.get_element_type().to_string());
Console.WriteLine(Output shape: {0}, output.get_shape().to_string());获取模型网络层信息如下
Model name: torch_jit
/------- [In] -------/
Input name: data
Input type: float
Input shape: [1,3,224,224]
/------- [Out] -------/
Output name: prob
Output type: float
Output shape: [1,1000]同样的输出信息我们使用 C API 实现如下
std::cout Model name: model-get_friendly_name() std::endl;
ov::Outputov::Node input model-input();
std::cout /------- [In] -------/ std::endl;
std::cout Input name: input.get_any_name() std::endl;
std::cout Input type: input.get_element_type().c_type_string() std::endl;
std::cout Input shape: input.get_shape().to_string() std::endl;
ov::Outputov::Node output model-output();
std::cout /------- [Out] -------/ std::endl;
std::cout Output name: output.get_any_name() std::endl;
std::cout Output type: output.get_element_type().c_type_string() std::endl;
std::cout Output shape: output.get_shape().to_string() std::endl;5 编译模型并创建推理请求 在读取本地模型后调用模型编译方法将模型编译为可以在目标设备上执行的 compile_model 对象并通过该对象创建用于推断已编译模型的推断请求对象。下面是所使用的 API 方法
API作用Core.compile_model()将模型编译为可以在目标设备上执行的 compile_model 对象。CompiledModel.create_infer_request()创建用于推断已编译模型的推断请求对象创建的请求已经分配了输入和输出张量。 在 C# 中编译模型并创建推理请求的方式
CompiledModel compiled_model core.compile_model(model, AUTO);
InferRequest infer_request compiled_model.create_infer_request();使用C API中编译模型并创建推理请求的方式
CompiledModel compiled_model core.compile_model(model, AUTO);
InferRequest infer_request compiled_model.create_infer_request();6 张量Tensor
6.1 张量的获取与设置 在创建推理请求后系统会自动创建和分配输入和输出的张量张量可以通过InferRequest 对象获得并且可以自定义张量并加载到模型指定节点可以根据张量的输入输出序号、名称以及模型节点Node对象获取和设置主要C# API 如下
API作用InferRequest.set_tensor()设置要推断的输入/输出张量。InferRequest.set_input_tensor()设置要推断的输入张量。InferRequest.set_output_tensor()设置要推断的输出张量InferRequest.get_tensor()获取用于推理的输入/输出张量。InferRequest.get_input_tensor()获取用于推理的输入张量。InferRequest.get_output_tensor()获取用于推理的输出张量。
6.2 张量的信息获取与设置 张量中主要包含的信息有张量的形状(Shape)、张量的数据格式(OvType- element.Type)以及张量中的内存数据。可以通过以下API方法操作张量的参数
API作用Tensor.set_shape ()给张量设置一个新的形状。Tensor.get_shape()获取张量的形状。Tensor.get_element_type()获取张量的数据类型。Tensor.get_size()获取张量的数据长度。Tensor.get_byte_size()获取张量的字节大小。Tensor.data()获取张量的内存地址。Tensor.set_data()将指定类型的数据加载到张量内存下。Tensor.get_data()从张量中读取指定类型的数据。 以上方法是对张量的一些基础操作除了set_data、get_data是OpenVINO C# API独有的其他接口都与CAPI一致。
7 加载推理数据
7.1 获取输入张量 对于单输入的模型可以直接通过get_input_tensor()方法获得并调用Tensor的相关方法获取Tensor的相关信息C# 代码如下所示
Tensor input_tensor infer_request.get_input_tensor();
Console.WriteLine(/------- [Input tensor] -------/);
Console.WriteLine(Input tensor type: {0}, input_tensor.get_element_type().to_string());
Console.WriteLine(Input tensor shape: {0}, input_tensor.get_shape().to_string());
Console.WriteLine(Input tensor size: {0}, input_tensor.get_size());获取输出结果为
/------- [Input tensor] -------/
Input tensor type: f32
Input tensor shape: Shape : {1, 3, 224, 224}
Input tensor size: 150528对于上述的同样输出内容我们也可以通过C API 实现C 代码如下
ov::Tensor input_tensor infer_request.get_input_tensor();
std::cout /------- [Input tensor] -------/ std::endl;
std::cout Input tensor type: input_tensor.get_element_type().c_type_string() std::endl;
std::cout Input tensor shape: input_tensor.get_shape().to_string() std::endl;
std::cout Input tensor size: input_tensor.get_size() std::endl;7.2 添加推理数据 这一步主要是将处理好的图片数据加载到Tensor数据内存中OpenVINO的API中提供了访问内存地址的接口可以获取数据内存首地址不过为了更好的加载推理数据我们此处封装了set_data()方法可以实现将处理后的图片数据加载到数据内存上。在C#中的代码为
Mat input_mat new Mat();
Shape input_shape input_tensor.get_shape();
long channels input_shape[1];
long height input_shape[2];
long width input_shape[3];
float[] input_data new float[channels * height * width];
Marshal.Copy(input_mat.Ptr(0), input_data, 0, input_data.Length);
input_tensor.set_data(input_data);下面是在C中实现上述功能的代码
cv::Mat input_mat
float* input_data input_tensor.datafloat();
ov::Shape input_shape input_tensor.get_shape();
size_t channels input_shape[1];
size_t height input_shape[2];
size_t width input_shape[3];
for (size_t c 0; c channels; c) {for (size_t h 0; h height; h) {for (size_t w 0; w width; w) {input_data[c * height * width h * width w] input_mat.atcv::Vecfloat, 3(h, w)[c];}}
}8 模型推理 在加载完推理数据后就可以调用模型推理的API方法推理当前数据主要使用到的API方法为
API作用InferRequest.infer()在同步模式下推断指定的输入。 调用该方法也较为简单只需要调用该API接口即可在C#中的代码为
infer_request.infer();C中的代码与C中一致。
9 获取推理结果 对于单输出的模型可以直接通过get_output_tensor()方法获得并调用Tensor的相关方法获取Tensor的相关信息C# 代码如下所示
Tensor output_tensor infer_request.get_output_tensor();
Console.WriteLine(/------- [Output tensor] -------/);
Console.WriteLine(Output tensor type: {0}, output_tensor.get_element_type().to_string());
Console.WriteLine(Output tensor shape: {0}, output_tensor.get_shape().to_string());
Console.WriteLine(Output tensor size: {0}, output_tensor.get_size());获取输出output_tensor信息为
/------- [Output tensor] -------/
Output tensor type: f32
Output tensor shape: Shape : {1, 1000}
Output tensor size: 1000对于输出Tensor我们只需要读取输出内存上的数据即可此处我们封装了get_data()方法可以直接获取输出内存上的数据在C#中的代码为
float[] result output_tensor.get_datafloat(1000);同样获取推理结果在C中的代码为
const float* output_data output_tensor.dataconst float();
float result[1000];
for (int i 0; i 1000; i) {result[i] *output_data;output_data;
}在获取结果后后续的处理需要根据模型的输出类型做相应的处理。
10 释放分配的内存 由于C#在封装时采用的C API 接口实现的因此在C#中会产生较多的 非托管内存若该对象出现循环重复创建会导致过多的内存未释放导致内存泄漏因此对于临时创建的对象在使用后要即使销毁销毁方式也较为简单只需要调用对象的dispose()方法即可。
output_tensor.dispose();
input_shape.dispose();
infer_request.dispose();
compiled_model.dispose();
input.dispose();
output.dispose();
model.dispose();
core.dispose();11 Yolov8分类模型示例 下面代码展示了Yolov8分类模型使用OpenVINO C# API API方法部署模型的完整代码
using OpenCvSharp;
using OpenCvSharp.Dnn;
using OpenVinoSharp;
using System.Data;
using System.Runtime.InteropServices;
namespace test_openvino_csharp_api
{internal class Program{static void Main(string[] args){string model_path E:\\GitSpace\\ OpenVINO-CSharp-API \\model\\yolov8\\yolov8s-cls.xml;Core core new Core(); // 初始化推理核心Model model core.read_model(model_path); // 读取本地模型CompiledModel compiled_model core.compile_model(model, AUTO); // 便哟模型到指定设备// 获取模型的输入输出信息Console.WriteLine(Model name: {0}, model.get_friendly_name());Input input compiled_model.input();Console.WriteLine(/------- [In] -------/);Console.WriteLine(Input name: {0}, input.get_any_name());Console.WriteLine(Input type: {0}, input.get_element_type().to_string());Console.WriteLine(Input shape: {0}, input.get_shape().to_string());Output output compiled_model.output();Console.WriteLine(/------- [Out] -------/);Console.WriteLine(Output name: {0}, output.get_any_name());Console.WriteLine(Output type: {0}, output.get_element_type().to_string());Console.WriteLine(Output shape: {0}, output.get_shape().to_string());// 创建推理请求InferRequest infer_request compiled_model.create_infer_request();// 获取输入张量Tensor input_tensor infer_request.get_input_tensor();Console.WriteLine(/------- [Input tensor] -------/);Console.WriteLine(Input tensor type: {0}, input_tensor.get_element_type().to_string());Console.WriteLine(Input tensor shape: {0}, input_tensor.get_shape().to_string());Console.WriteLine(Input tensor size: {0}, input_tensor.get_size());// 读取并处理输入数据Mat image Cv2.ImRead(E:\GitSpace\ OpenVINO-CSharp-API \dataset\image\demo_7.jpg);Mat input_mat new Mat();input_mat CvDnn.BlobFromImage(image, 1.0 / 255.0, new Size(224, 224), 0, true, false);// 加载推理数据Shape input_shape input_tensor.get_shape();long channels input_shape[1];long height input_shape[2];long width input_shape[3];float[] input_data new float[channels * height * width];Marshal.Copy(input_mat.Ptr(0), input_data, 0, input_data.Length);input_tensor.set_data(input_data);// 模型推理infer_request.infer(); // 获取输出张量Tensor output_tensor infer_request.get_output_tensor();Console.WriteLine(/------- [Output tensor] -------/);Console.WriteLine(Output tensor type: {0}, output_tensor.get_element_type().to_string());Console.WriteLine(Output tensor shape: {0}, output_tensor.get_shape().to_string());Console.WriteLine(Output tensor size: {0}, output_tensor.get_size());// 获取输出数据float[] result output_tensor.get_datafloat(1000);Listfloat[] new_list new Listfloat[] { };for (int i 0; i result.Length; i){new_list.Add(new float[] { (float)result[i], i });}new_list.Sort((a, b) b[0].CompareTo(a[0]));KeyValuePairint, float[] cls new KeyValuePairint, float[10];for (int i 0; i 10; i){cls[i] new KeyValuePairint, float((int)new_list[i][1], new_list[i][0]);}Console.WriteLine(\n Classification Top 10 result : \n);Console.WriteLine(classid probability);Console.WriteLine(------- -----------);for (int i 0; i 10; i){Console.WriteLine({0} {1}, cls[i].Key.ToString(0), cls[i].Value.ToString(0.000000));}// 销毁非托管内存output_tensor.dispose();input_shape.dispose();infer_request.dispose();compiled_model.dispose();input.dispose();output.dispose();model.dispose();core.dispose();}}
}12 总结 在本文中我们基于模型推理流程演示了OpenVINO C# API使用方法并和OpenVINO CAPI进行了对比展示了OpenVINO C# API与CAPI在使用的区别这也对使用过C API的开发者十分友好上手会十分容易。 在本文中我们只展示了基础的模型推理流程代码也对各个API进行了测试针对其他比较高级的API方法我们后续会继续进行测试其他API方法向各位开发者展示其用法。 总的来说目前OpenVINO C# API已经完全支持在Windows环境下的安装使用欢迎各位开发者安装使用如有相关问题或优化方法也欢迎大家提出意见与指导。