0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

OpenVINO™ C# API详解与演示

英特尔物联网 来源:英特尔物联网 2023-10-13 16:39 次阅读
OpenVINO工具套件可以加快深度学习视觉应用开发速度,帮助用户在从边缘到云的各种英特尔平台上,更加方便快捷的将AI模型部署到生产系统中。本文的所介绍的 OpenVINO C# API 已支持OpenVINO2023.1.0 版。

C#是由C和C++衍生出来的一种安全的、稳定的、简单的、优雅的面向对象编程语言,它综合了 VB简单的可视化操作和 C++的高运行效率,成为支持成为 .NET 开发的首选语言。作为人工智能开发人员,如果你希望在 C# 中使用OpenVINO,OpenVINO C# API将是你的首选。OpenVINO C# API提供了NuGet程序包,实现在 C# 中一站式安装与使用OpenVINO。

b68269f6-699e-11ee-939d-92fbcf53809c.png

OpenVINO C# API 项目地址(复制到浏览器打开)

https://github.com/guojin-yan/OpenVINO-CSharp-API

OpenVINO C# API 基于 OpenVINOC++ API 研发,下表展示了C#与C++ API的对应关系:

b72277de-699e-11ee-939d-92fbcf53809c.png

本文根据 AI 模型部署的典型步骤,演示 OpenVINO C# API 使用方式,并跟 C++ API 做对比。

01

安装 OpenVINO C# API

OpenVINO C# API支持NuGet程序包安装方式,这与 OpenVINO C++ 库的安装过程相比,更加简单。如果使用 Visual Studio 开发 AI 项目,则可以通过NuGet程序包管理功能直接安装即可,如下图所示:

b7324434-699e-11ee-939d-92fbcf53809c.png

如果通过 dotnet 命令方式安装,通过下面语句进行安装即可:

dotnet add package OpenVINO.CSharp.win

02

导入程序集

OpenVINO C# API程序集全部在 CSharp 命名空间下,因此若要使用OpenVINO C# API,需要先引入命名空间:

using OpenVinoSharp;

03

初始化 OpenVINO运行时

Core 类代表一个 OpenVINO 运行时核心实体,后续的读取模型、加载模型等方法都需要通过Core类进行创建,在封装 C# API时,为了与C++ API对应,也对Core类进行了封装,并封装了与C++ API中对应的方法。

在 C# 中的初始化方式:

Core core = new Core();

在 C++ 中的初始化方式:

ov::Core core;

04

加载并获取模型信息

4.1 加载模型

OpenVINO2022.1 版本更新之后,加载模型是使用下面的API方法:

b755a1d6-699e-11ee-939d-92fbcf53809c.png

在 C# 中加载模型的方式:

Model model = core.read_model(model_path);

在 C++ 中的初始化方式:

std::shared_ptr model = core.read_model(model_path);

4.2 获取模型信息

通过Core.read_model () 方法获得的Model对象和通过Core.compile_model () 方法获得的CompiledModel对象,都支持直接访问属性获取输入与输出层信息。以 Model 对象获取模型信息为例,下面是所使用的API方法:

b76a7a8e-699e-11ee-939d-92fbcf53809c.png

Input/Output主要是封装了模型网络层,可以通过下面API实现获取模型的详细信息:

b7782292-699e-11ee-939d-92fbcf53809c.png

在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::Output 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::Output 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<< "Outputshape:"<< output.get_shape().to_string() << std::endl;

05

编译模型并创建推理请求

在读取本地模型后,调用模型编译方法将模型编译为可以在目标设备上执行的compile_model对象,并通过该对象创建用于推断已编译模型的推断请求对象。下面是所使用的API方法:

b792269c-699e-11ee-939d-92fbcf53809c.png

在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();

06

张量 Tensor

6.1 张量的获取与设置

在创建推理请求后,系统会自动创建和分配输入和输出的张量,张量可以通过 InferRequest对象获得,并且可以自定义张量并加载到模型指定节点;可以根据张量的输入输出序号、名称以及模型节点 Node 对象获取和设置,主要 C# API如下:

b7b7ee72-699e-11ee-939d-92fbcf53809c.png

6.2 张量的信息获取与设置

张量中主要包含的信息有张量的形状 (Shape) 、张量的数据格式 (OvType-> element.Type) 以及张量中的内存数据。可以通过以下 API 方法操作张量的参数

b7d2ca80-699e-11ee-939d-92fbcf53809c.png

以上方法是对张量的一些基础操作,除了 set_data、get_data 是 OpenVINO C# API 独有的,其他接口都与 C++API 一致。

07

加载推理数据

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.data<float>();
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.atfloat, 3>>(h, w)[c];
    }
  }
}

08

模型推理

在加载完推理数据后,就可以调用模型推理的 API 方法推理当前数据,主要使用到的 API 方法为:

b8620d12-699e-11ee-939d-92fbcf53809c.png

调用该方法也较为简单,只需要调用该 API 接口即可,在 C# 中的代码为:

infer_request.infer();

C++ 中的代码与 C++ 中一致。

09

获取推理结果

对于单输出的模型可以直接通过 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_data<float>(1000);

同样获取推理结果,在 C++ 中的代码为:

const float* output_data = output_tensor.data<const 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 datasetimagedemo_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_data<float>(1000);
      List<float[]> new_list = new List<float[]> { };
      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]));


      KeyValuePair<int, float>[] cls = new KeyValuePair<int, float>[10];
      for (int i = 0; i < 10; ++i)
      {
        cls[i] = new KeyValuePair<int, float>((int)new_list[i][1], new_list[i][0]);
      }
      Console.WriteLine("
 Classification Top 10 result : 
");
      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 C++API 进行了对比,展示了 OpenVINO C# API 与 C++API 在使用的区别,这也对使用过 C++ API 的开发者十分友好,上手会十分容易。

在本文中我们只展示了基础的模型推理流程代码,也对各个 API 进行了测试,针对其他比较高级的 API 方法,我们后续会继续进行测试其他 API 方法,向各位开发者展示其用法。

总的来说,目前 OpenVINO C# API 已经完全支持在 Windows 环境下的安装使用,欢迎各位开发者安装使用,如有相关问题或优化方法,也欢迎大家提出意见与指导。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    1481

    浏览量

    61776
  • 编程语言
    +关注

    关注

    10

    文章

    1936

    浏览量

    34573
  • C++
    C++
    +关注

    关注

    21

    文章

    2104

    浏览量

    73469

原文标题:OpenVINO™ C# API 详解与演示 | 开发者实战

文章出处:【微信号:英特尔物联网,微信公众号:英特尔物联网】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    OpenVINO Java API详解演示

    英特尔 发行版 OpenVINO 工具套件基于 oneAPI 而开发,可以加快高性能计算机视觉和深度学习视觉应用开发速度工具套件,适用于从边缘到云的各种英特尔平台上,帮助用户更快地将更准确的真实世界
    的头像 发表于 11-09 17:03 954次阅读
    <b class='flag-5'>OpenVINO</b> Java <b class='flag-5'>API</b><b class='flag-5'>详解</b>与<b class='flag-5'>演示</b>

    如何使用OpenVINO C++ API部署FastSAM模型

    象的位置和边界。本文将介绍如何使用 OpenVINO C++ API 部署 FastSAM 模型,以实现快速高效的语义分割。在前文中我们发表了《基于 OpenVINO Python
    的头像 发表于 11-17 09:53 855次阅读
    如何使用<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C</b>++ <b class='flag-5'>API</b>部署FastSAM模型

    CySmart API C#示例如何正确启动

    if there is a bare bones example in C# code using the CySmart API to setup and talk to the dongle
    发表于 02-25 06:31

    使用OpenVINO运行C++ API创建输入tensor并执行推理遇到的问题求解

    使用 OpenVINO™ 运行时 C++ API 创建输入 tensor 并执行推理: ov::Tensor input_tensor = ov::Tensor(input_type
    发表于 08-15 08:22

    运行任何OpenVINO Python演示和示例时报错怎么解决?

    运行任何OpenVINO™ Python 演示和示例时,会出现错误: FileNotFoundEror:[WinError 2]。
    发表于 08-15 07:21

    c#源码_C# 2008源代码案例下载

    附件为:c#源码_C# 2008源代码案例,共有11个附件文件。 第1章 Visual C#2008与窗体界面 案例1 飘动动画窗体 案例2 透明动画窗体 案例3 利用API函数实现动
    发表于 10-17 10:10 103次下载
    <b class='flag-5'>c#</b>源码_<b class='flag-5'>C#</b> 2008源代码案例下载

    C#平台调用OpenVINO的可行性

    OpenVINO 工具套件是英特尔基于自身现有的硬件平台开发的一种可以加快高性能计算机视觉和深度学习视觉应用开发速度工具套件,支持各种英特尔平台的硬件加速器上进行深度学习,并且允许直接异构执行。支持在Windows与Linux系统,官方支持编程语言为Python与C++语
    的头像 发表于 05-24 09:37 1288次阅读

    OpenVINO工具套件预处理API的概念及使用方法

    OpenVINO 2022.1之前版本不提供OpenVINO Runtime原生的用于数据预处理的API函数1 ,如图1-1所示,开发者必须通过第三方库(例如:OpenCV)来实现数据预处理。
    的头像 发表于 06-09 17:25 2054次阅读

    OpenVINO™的C API 2.0有何新特性?

    你是否准备好在新的一年体验 OpenVINO 工具套件分发版的最新长期支持 (LTS) 版本?
    的头像 发表于 02-24 11:14 515次阅读

    OpenVINOC++ API编写YOLOv8-Seg实例分割模型推理程序

    本文章将介绍使用 OpenVINO 2023.0 C++ API 开发YOLOv8-Seg 实例分割(Instance Segmentation)模型的 AI 推理程序。本文 C++
    的头像 发表于 06-25 16:09 1501次阅读
    用<b class='flag-5'>OpenVINO</b>™ <b class='flag-5'>C</b>++ <b class='flag-5'>API</b>编写YOLOv8-Seg实例分割模型推理程序

    基于OpenVINO Python API部署RT-DETR模型

    RT-DETR 是在 DETR 模型基础上进行改进的,一种基于 DETR 架构的实时端到端检测器,它通过使用一系列新的技术和算法,实现了更高效的训练和推理,我们将在 Python、C++、C# 三个
    的头像 发表于 10-20 11:15 899次阅读
    基于<b class='flag-5'>OpenVINO</b> Python <b class='flag-5'>API</b>部署RT-DETR模型

    基于OpenVINO C++ API部署RT-DETR模型

    应用中,我们为了与当前软件平台集成更多会采用 C++ 平台,因此在本文中,我们将基于 OpenVINO C++ API 向大家展示了不包含后处理的 RT-DETR 模型的部署流程,并向
    的头像 发表于 11-03 14:30 765次阅读
    基于<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C</b>++ <b class='flag-5'>API</b>部署RT-DETR模型

    基于OpenVINO C# API部署RT-DETR模型

    C# 环境下使用该模型应用到工业检测中,因此在本文中,我们将向大家展示使用 OpenVINO Csharp API 部署 RT-DETR 模型,并对比不同编程平台下模型部署的速度。
    的头像 发表于 11-10 16:59 704次阅读
    基于<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C#</b> <b class='flag-5'>API</b>部署RT-DETR模型

    OpenVINO C# API在intel平台部署YOLOv10目标检测模型

    的模型设计策略,从效率和精度两个角度对YOLOs的各个组成部分进行了全面优化,大大降低了计算开销,增强了性能。在本文中,我们将结合OpenVINO C# API使用最新发布的OpenVINO
    的头像 发表于 06-21 09:23 928次阅读
    用<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C#</b> <b class='flag-5'>API</b>在intel平台部署YOLOv10目标检测模型

    使用OpenVINO C# API部署YOLO-World实现实时开放词汇对象检测

    的快速准确识别,并通过AR技术将虚拟元素与真实场景相结合,为用户带来沉浸式的交互体验。在本文中,我们将结合OpenVINO C# API使用最新发布的OpenVINO 2024.0部署
    的头像 发表于 08-30 16:27 537次阅读
    使用<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C#</b> <b class='flag-5'>API</b>部署YOLO-World实现实时开放词汇对象检测