【源创会预告】1024 程序员节(的前两天),相约开源中国办公室,我们一起聊 AI!>>>
为.NET打开新大门:OpenVINO.NET开源项目全新发布
在AI的应用越来越广泛的今天,优化深度学习模型并进行推理部署已经成为了一门必要的技术。Intel开发的OpenVINO工具包(Open Visual Inference and Neural network Optimization)就是这样一款强大的工具。作为一个开源的工具包,OpenVINO为开发者提供了强大的深度学习模型优化和推理功能,支持跨不同的Intel硬件平台进行部署,包括CPU, 集成GPU, Intel Movidius VPU, 和FPGAs。该工具包的初衷就是实现一处编码后,能在任何地方部署的机器学习推理的解决方案。
然而在与深度学习模型推理打交道的过程中,我逐渐发现原本我基于百度飞桨paddlepaddle开发过的PaddleSharp项目在CPU推理OCR性能方面,同样的模型,OpenVINO的性能更胜一筹。于是我开始关注OpenVINO,发现它的C API对于.NET世界来说并没有一个合适且高质量的封装。市面上的一部分封装可能只是为了满足特定项目的需求,功能不够完善;有些虽然功能完善但命名规范可能不符合.NET社区规范;有些在错误处理和性能方面存在问题,或者无法做到跨平台,这与OpenVINO的跨平台性矛盾。.NET世界亟需一个更高质量的OpenVINO封装,而我感觉我有能力去努努力。因此,我在今年的节前立下了flag——国庆期间大干一票,开始了OpenVINO.NET的开源之旅。
如何使用
NuGet包简介
使用OpenVINO.NET
,最简单的方法不是克隆我的Github库(但欢迎star),而是使用我发布的NuGet包,一般它需要配合OpenCVSharp4
一起使用,因此你通常可以安装下面4个NuGet:
- Sdcb.OpenVINO
- Sdcb.OpenVINO.runtime.win-x64
- OpenCvSharp4
- OpenCvSharp4.runtime.win
和OpenCvSharp4
一样,我发布的包也包含.NET PInvoke包和平台动态链接库包,如上Sdcb.OpenVINO
为.NET PInvoke包,Sdcb.OpenVINO.runtime.win-x64
为兼容Windows平台的动态链接库包,里面包含了一些dll。
如果是基于Linux
,我专门发布了一个镜像用于减轻部署压力:sdflysha/openvino-base
,这个镜像基于.NET 7 SDK的Ubuntu 22.04版本,包含了OpenCvSharp 4.8的运行时和所有OpenVINO
的运行时依赖,要使用这个镜像,需将.NET项目第一行的FROM mcr.microsoft.com/dotnet/runtime
改为FROM sdflysha/openvino-base
,使用时当然也需要安装ubuntu 22.04
平台的动态链接库包:Sdcb.OpenVINO.runtime.ubuntu.22.04-x64
。
实际上我发布了8种不同平台的NuGet包,这是所有我此项目新发布的NuGet包列表:
包名 | 版本号 | 简介 |
---|---|---|
Sdcb.OpenVINO | .NET PInvoke | |
Sdcb.OpenVINO.runtime.centos.7-x64 | CentOS 7 x64 | |
Sdcb.OpenVINO.runtime.debian.9-arm | Debian 9 ARM | |
Sdcb.OpenVINO.runtime.debian.9-arm64 | Debian 9 ARM64 | |
Sdcb.OpenVINO.runtime.rhel.8-x64 | RHEL 8 x64 | |
Sdcb.OpenVINO.runtime.ubuntu.18.04-x64 | Ubuntu 18.04 x64 | |
Sdcb.OpenVINO.runtime.ubuntu.20.04-x64 | Ubuntu 20.04 x64 | |
Sdcb.OpenVINO.runtime.ubuntu.22.04-x64 | Ubuntu 22.04 x64 | |
Sdcb.OpenVINO.runtime.win-x64 | Windows x64 |
有兴趣的朋友一定会想,发布并维护这么多包做起来一定很麻烦。其实还好,感谢我此前PaddleSharp项目的经验(那个项目也维护了一屏幕的包),我基于官网的filetree.json做了一些解析,它可以一键自动下载并生成上面这些NuGet包,有兴趣的朋友可以看看我Github中Sdcb.OpenVINO.NuGetBuilder这个项目了解我是如何解析并自动创建NuGet包的。
API设计
和我此前做过的PaddleSharp, Sdcb.LibRaw, Sdcb.Arithmetic, Sdcb.FFmpeg等开源项目相似,我这个项目也秉持下面这些原则:
- 完全支持低级C API,也就是说如果你更享受原汁原味的C API的感觉——或者像我一样不想失去对低层的掌控,使用OpenVINO.NET可以满足这一期望;
- 同时也为所有的低级API提供了便利好用的高层API;
- 高层API符合
C#
的命名规范,完全利用了C#
的优秀特性,做好了异常错误处理; - 高层API使用了
C#
世界有利于性能优化的特性,如ReadOnlySpan<T>
,比如恰当使用值类型; - 所有的高层API都提供了完善了XML注释,并经过了详尽的单元测试;
- 此外我还控制了我携带的“私货”——没必要做成公有的API一律做成
internal
或private
,且不污染常用类型的扩展方法
目前这个项目已经基本稳定,基于这些API
,我测试发现它和C
/C++
推理性能几乎并无差异,PaddleOCR
推理时,性能可以比PaddleSharp
项目快得多,且得益于C#
的优秀语言特性,使用起来会非常的省心。
设计FAQ:
- Q: 为何
OpenVINO.NET
没有直接引用OpenCvSharp4
?- A: 我个人很喜欢
OpenCvSharp4
,开源协议很友好,但一来OpenCvSharp4
官方支持的平台不够多,且有些人可能更喜欢Emgu.CV
或ImageSharp
,尽量不做绑架为好
- A: 我个人很喜欢
- Q: C API有158个函数接口、26个接口体,也写了详尽的
XML
注释,是怎么在短时间内高质量地做到的?- A: 我是自动生成的,我使用了CppSharp项目,CppSharp将C API的头文件内容转换为抽象语法树(AST),然后我将这些AST转换为XML注释详尽的
C#
代码。其实我已经不是第一次将CppSharp应用到开源项目中,有兴趣的朋友可以看我Github Sdcb.OpenVINO.AutoGen这个项目了解实现的细节。
- A: 我是自动生成的,我使用了CppSharp项目,CppSharp将C API的头文件内容转换为抽象语法树(AST),然后我将这些AST转换为XML注释详尽的
为想了解如何使用的朋友,我还写了基于yolov8
的检测和分类的推理示例,OpenVINO
官方的人脸检测示例以及我为它原生设计和迁移的PaddleOCR
项目。另外我还想畅谈一下项目的设计思路和未来的发展方向。
4个示例
人脸检测 - 基于OpenVINO官网提供的face-detection-0200模型
我这个示例中使用的是OpenVINO官网提供的face-detection-0200
模型,官网提供了介绍页面:https://docs.openvino.ai/2023.1/omz_models_model_face_detection_0200.html。
详尽的示例代码可以从我创建的mini-openvino-facedetection这个Github仓库找到,运行时,它会将摄像头中定位人脸位置并框出来,效果图如下:
如图,人脸识别效果正常,上面也标注了每帧推理耗时(约2.14ms)。
我使用的是AMD R7 5800X进行的CPU推理,其实代码也支持Intel的GPU。将DeviceOptions
的第一个参数从"CPU"
(默认值)改为"GPU"
即可,但我只有集成显卡,测试发现虽然能正常工作,且CPU使用率降低了且GPU使用率上升了,但GPU
推理时间比CPU
还更慢。
物体识别 - 基于yolov8模型的物体分类
在上一个例子中,我们已经看到了如何使用OpenVINO.NET进行人脸检测。接下来,我们再来看一下如何使用物体识别模型进行物体分类。
这个示例使用的是yolov8官网下载的YOLOv8n
模型,这个模型支持80种物体的检测。下载后格式为.pt
文件,表示pytorch
模型,需使用yolo export model=yolov8n.pt format=openvino
命令(yolo通过pip安装ultralytics包得到)将其导出为openvino
格式的模型,openvino
模型包含一个xml
和一个bin
文件。
详尽的示例代码可以从我创建的另一个仓库:sdcb-openvino-yolov8-det中找到,仓库我我已经将模型转换好了。运行时,代码会读取摄像头的每一帧,并将检测到的物体位置框出来,效果图如下:
如图,检测出了3个物体,画面中的人、手机和水杯,总耗时约30ms。
物体分类 - 基于yolov8的分类模型
yolov8模型提供了1000种不同的预定义分类,和上面的模型一样,需要从yolov8官网下载并转换,只想快速尝鲜的朋友可以直接打开我写的另一个Github示例:sdcb-openvino-yolov8-cls
运行时,代码会读取一张图片,然后尝试推测出该图片最像1000种分类中的哪一种,在我的代码示例中,输入图片为hen.jpg:
输出如下:
class id=hen, score=0.59
preprocess time: 0.00ms
infer time: 1.65ms
postprocess time: 0.49ms
Total time: 2.14ms
推理得到最有可能的分类是hen(母鸡),信心值为0.59,总耗时2.14ms。
PaddleOCR - 混合3种模型
PaddleOCR是百度飞桨发布了一款性能、精度都较好的开源模型。
和PaddleSharp项目一样,我给OpenVINO.NET项目也内置了PaddleOCR的便利化项目,且API设计和PaddleSharp几乎完全一样,熟悉PaddleSharp的朋友应该可以很轻松地迁移到OpenVINO.NET,我专门为PaddleOCR提供发布了下面2个NuGet包:
包名 | 版本号 📌 | 描述 |
---|---|---|
Sdcb.OpenVINO.PaddleOCR | OCR主包 | |
Sdcb.OpenVINO.PaddleOCR.Models.Online | 包含需在线下载的模型包 |
加上上面那4个包,运行基于OpenVINO.NET的PaddleOCR需要下载下面这6个包:
- Sdcb.OpenVINO
- Sdcb.OpenVINO.runtime.win-x64
- OpenCvSharp4
- OpenCvSharp4.runtime.win
- Sdcb.OpenVINO.PaddleOCR
- Sdcb.OpenVINO.PaddleOCR.Models.Online
最小代码示例如下:
using OpenCvSharp;
using Sdcb.OpenVINO.PaddleOCR.Models.Online;
using Sdcb.OpenVINO.PaddleOCR.Models;
using Sdcb.OpenVINO.PaddleOCR;
using System.Diagnostics;
using System;
FullOcrModel model = await OnlineFullModels.ChineseV3.DownloadAsync();
using Mat src = Cv2.ImDecode(await new HttpClient().GetByteArrayAsync("https://io.starworks.cc:88/paddlesharp/ocr/samples/xdr5450.webp"), ImreadModes.Color);
using (PaddleOcrAll all = new(model)
{
AllowRotateDetection = true,
Enable180Classification = true,
})
{
// Load local file by following code:
// using (Mat src2 = Cv2.ImRead(@"C:test.jpg"))
Stopwatch sw = Stopwatch.StartNew();
PaddleOcrResult result = all.Run(src);
Console.WriteLine($"elapsed={sw.ElapsedMilliseconds} ms");
Console.WriteLine("Detected all texts: n" + result.Text);
foreach (PaddleOcrResultRegion region in result.Regions)
{
Console.WriteLine($"Text: {region.Text}, Score: {region.Score}, RectCenter: {region.Rect.Center}, RectSize: {region.Rect.Size}, Angle: {region.Rect.Angle}");
}
}
运行效果如下:
elapsed=246 ms
Detected all texts:
高速4X4160MHz数据流
5GHz频段流数多一倍
速度快一倍3
AX5400无线规格的路由器,
5GHz频段采用高速4X4160MHz数据流,
相比市面上主流的AX3000路由器(2X2数据流)
5GHz频段流数多一倍,速度快一倍。
...
耗时为246ms,根据我的测试,实际上第二次运行OpenVINO可以降低到140ms左右,同样的代码PaddleSharp耗时约452ms(PaddleSharp使用MKLDNN,仅测试首次运行),显然使用我的新开源项目OpenVINO.NET更快。
上面完整的可运行代码,可以从我的Github另一个仓库mini-openvino-paddleocr
结语
本文中,我向大家介绍了如何使用我新发布的OpenVINO.NET,并提供了数个生动的示例来演示如何将OpenVINO.NET用于深度学习模型的推理任务。虽然我只展示了四个应用示例,其实它们都可以被看作为学习OpenVINO.NET使用的良好起点。
通过这四个示例,读者可以轻松理解OpenVINO.NET的工作原理,在此基础上扩展将其用于其它模型的推理是加深理解和实践的不二选择。我专注于.NET开源项目,并不断地为全球.NET开发者提供更多的可能性,我尤其期待看到大家将OpenVINO.NET用于自身项目之中。
我相信开源的力量以及它为我们提供的无尽可能性。因此,我将OpenVINO.NET作为开源项目,希望它能帮助所有在寻找高效,便捷的深度学习推理工具的.NET开发者。如果你发现这个项目有用,或者正在使用它,我非常欢迎你能去我的项目主页上给我一个star🌟,这对我将会是巨大的鼓励!你们的使用经验和星标都是我继续进行.NET开源项目工作的动力!
我还创建了一个.NET骚操作技术交流QQ群:495782587,欢迎对.NET“骚”操作感兴趣的朋友加入一起探讨。
最后,如果你对我的业余开源工作感兴趣,并希望获取更多有关我.NET开源项目的信息,也可以关注我的微信公众号:【DotNet骚操作】
让我们一起探索.NET的无尽可能性。期待.NET世界未来的更多精彩!