ONNX Runtime入门示例:在C#中使用ResNet50v2进行图像识别
ONNX Runtime简介
ONNX Runtime 是一个跨平台的推理和训练机器学习加速器。ONNX 运行时推理可以实现更快的客户体验和更低的成本,支持来自深度学习框架(如 PyTorch 和 TensorFlow/Keras)以及经典机器学习库(如 scikit-learn、LightGBM、XGBoost 等)的模型。 ONNX 运行时与不同的硬件、驱动程序和操作系统兼容,并通过利用硬件加速器(如果适用)以及图形优化和转换来提供最佳性能。

ResNet50v2简介
ResNet50v2 是一种深度卷积神经网络架构,是 ResNet(Residual Network,残差网络)系列的一部分。ResNet 是由何凯明等人在 2015 年提出的,它通过引入残差块(Residual Block)解决了深度神经网络训练过程中梯度消失和梯度爆炸的问题,使得构建非常深的网络成为可能。ResNet50v2 被广泛应用于各种计算机视觉任务,如图像分类、目标检测、图像分割等。由于其深度和强大的特征学习能力,ResNet50v2 在众多基准测试中表现出色,是许多研究和应用中的首选模型之一。
示例
这个示例代码在
fork一份,克隆到本地,在本地打开这个项目,项目结构如下所示:

依赖的包除了OnnxRuntime还有ImageSharp。
ImageSharp简介
ImageSharp 是一个新的、功能齐全、完全托管的跨平台 2D 图形库。ImageSharp 旨在简化图像处理,为您带来一个非常强大而又非常简单的 API。
ImageSharp 从头开始设计,具有灵活性和可扩展性。该库为常见的图像处理操作提供了 API 端点,并为开发其他操作提供了构建块。
ImageSharp 针对 .NET 8 构建,可用于设备、云和嵌入式/IoT 方案。

下载 ResNet50 v2 ONNX 模型,下载地址在:
读取路径
首先,源代码中是通过程序参数读取模型的路径和要测试的图像的路径,也可以直接赋值:
// Read paths
//string modelFilePath = args[0];
//string imageFilePath = args[1];
string modelFilePath = @"你的路径\Microsoft.ML.OnnxRuntime.ResNet50v2Sample\resnet50-v2-7.onnx";
string imageFilePath = @"你的路径\Microsoft.ML.OnnxRuntime.ResNet50v2Sample\狮子.jpg";
读取图像
接下来,我们将使用跨平台图像库 ImageSharp 读取图像:
// Read image
using Image<Rgb24> image = Image.Load<Rgb24>(imageFilePath);
调整图像大小
接下来,我们将图像大小调整为模型期望的适当大小;224 像素 x 224 像素:
using Stream imageStream = new MemoryStream();
image.Mutate(x =>
{
x.Resize(new ResizeOptions
{
Size = new Size(224, 224),
Mode = ResizeMode.Crop
});
});
image.Save(imageStream, format);
预处理图像
接下来,我们将根据模型的要求对图像进行预处理,具体要求见:
https://github.com/onnx/models/tree/main/validated/vision/classification/resnet#preprocessing
// We use DenseTensor for multi-dimensional access to populate the image data
var mean = new[] { 0.485f, 0.456f, 0.406f };
var stddev = new[] { 0.229f, 0.224f, 0.225f };
DenseTensor<float> processedImage = new(new[] { 1, 3, 224, 224 });
image.ProcessPixelRows(accessor =>
{
for (int y = 0; y < accessor.Height; y++)
{
Span<Rgb24> pixelSpan = accessor.GetRowSpan(y);
for (int x = 0; x < accessor.Width; x++)
{
processedImage[0, 0, y, x] = ((pixelSpan[x].R / 255f) - mean[0]) / stddev[0];
processedImage[0, 1, y, x] = ((pixelSpan[x].G / 255f) - mean[1]) / stddev[1];
processedImage[0, 2, y, x] = ((pixelSpan[x].B / 255f) - mean[2]) / stddev[2];
}
}
});
在这里,我们正在创建一个所需大小 (batch-size, channels, height, width) 的张量,访问像素值,对其进行预处理,最后将它们分配给适当指示的张量。
设置输入
接下来,我们将创建模型的输入:
using var inputOrtValue = OrtValue.CreateTensorValueFromMemory(OrtMemoryInfo.DefaultInstance,
processedImage.Buffer, new long[] { 1, 3, 224, 224 });
var inputs = new Dictionary<string, OrtValue>
{
{ "data", inputOrtValue }
}
要检查 ONNX 模型的输入节点名称,您可以使用 Netron 可视化模型并查看输入/输出名称。在本例中,此模型具有 data 作为输入节点名称。
运行推理
接下来,我们将创建一个推理会话并通过它运行输入:
using var session = new InferenceSession(modelFilePath);
using var runOptions = new RunOptions();
using IDisposableReadOnlyCollection<OrtValue> results = session.Run(runOptions, inputs, session.OutputNames);
后处理输出
接下来,我们需要对输出进行后处理以获得 softmax 向量,因为这不是由模型本身处理的:
var output = results[0].GetTensorDataAsSpan<float>().ToArray();
float sum = output.Sum(x => (float)Math.Exp(x));
IEnumerable<float> softmax = output.Select(x => (float)Math.Exp(x) / sum);
其他型号可能会在输出之前应用 Softmax 节点,在这种情况下,您不需要此步骤。同样,您可以使用 Netron 查看模型输出。
提取前10个预测结果
IEnumerable<Prediction> top10 = softmax.Select((x, i) => new Prediction { Label = LabelMap.Labels[i], Confidence = x })
.OrderByDescending(x => x.Confidence)
.Take(10);
打印结果
Console.WriteLine("Top 10 predictions for ResNet50 v2...");
Console.WriteLine("--------------------------------------------------------------");
foreach (var t in top10)
{
Console.WriteLine($"Label: {t.Label}, Confidence: {t.Confidence}");
}
本例的示例图片是一只狮子,如下所示:

查看预测结果:

在LabelMap类中可以查看该模型可以识别的物体:

例如cock是公鸡的意思,我们可以现场找一张公鸡的图片,查看效果。
找到的一张公鸡图片如下所示:

修改测试图片为这种图片,再次运行,结果如下所示:

成功识别出了公鸡。
总结
以上就完成了ONNX Runtime的入门示例,可以根据兴趣与需求尝试使用其他的模型。
参考
1、Image recognition with ResNet50v2 in C# | onnxruntime
4、SixLabors/ImageSharp: A modern, cross-platform, 2D Graphics library for .NET (github.com)
ONNX Runtime入门示例:在C#中使用ResNet50v2进行图像识别的更多相关文章
- Optimum + ONNX Runtime: 更容易、更快地训练你的 Hugging Face 模型
介绍 基于语言.视觉和语音的 Transformer 模型越来越大,以支持终端用户复杂的多模态用例.增加模型大小直接影响训练这些模型所需的资源,并随着模型大小的增加而扩展它们.Hugging Face ...
- [WCF编程]1.WCF入门示例
一.WCF是什么? Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,整合了原有的windows通讯的 .net Remotin ...
- Spring MVC 入门示例讲解
在本例中,我们将使用Spring MVC框架构建一个入门级web应用程序.Spring MVC 是Spring框架最重要的的模块之一.它以强大的Spring IoC容器为基础,并充分利用容器的特性来简 ...
- Linq to NHibernate入门示例
Linq to NHibernate入门示例 NHibernate相关: 09-08-25连贯NHibernate正式发布1.0候选版 09-08-17NHibernate中一对一关联的延迟加载 09 ...
- Spring MVC 入门示例讲解 - howtodoinjava
在本例中,我们将使用Spring MVC框架构建一个入门级web应用程序.Spring MVC 是Spring框架最重要的的模块之一.它以强大的Spring IoC容器为基础,并充分利用容器的特性来简 ...
- 微软推出了Cloud Native Application Bundles和开源ONNX Runtime
微软的Microsoft Connect(); 2018年的开发者大会 对Azure和IoT Edge服务进行了大量更新; Windows Presentation Foundation,Window ...
- Maven入门示例(3):自动部署至外部Tomcat
Maven入门示例(3):自动部署至外部Tomcat 博客分类: maven 2012原创 Maven入门示例(3):自动部署至外部Tomcat 上一篇,介绍了如何创建Maven项目以及如何在内 ...
- 1.【转】spring MVC入门示例(hello world demo)
1. Spring MVC介绍 Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于 ...
- 【java开发系列】—— spring简单入门示例
1 JDK安装 2 Struts2简单入门示例 前言 作为入门级的记录帖,没有过多的技术含量,简单的搭建配置框架而已.这次讲到spring,这个应该是SSH中的重量级框架,它主要包含两个内容:控制反转 ...
- Couchbase之个人描述及入门示例
本文不打算抄袭官方或者引用他人对Couchbase的各种描述,仅仅是自己对它的一点理解(错误之处,敬请指出),并附上一个入门示例. ASP.NET Web项目(其他web开发平台也一样)应用规模小的时 ...
随机推荐
- 一、Doris演进史
Apache Doris -- 为分析而生 Doris发展历程: Doris发展比较重要的关键节点与事件 #2008 - Doris1 :「筑巢引凤」的重要基石 早年,百度最主要的收入来源是广告.广告 ...
- 利用python爬取某壳的房产数据
以无锡的某壳为例进行数据爬取,现在房子的价格起伏很快,买房是人生一个大事,了解本地的房价走势来判断是否应该入手. (建议是近2年不买,本人在21年高位抛了一套房,基本是通过贝壳数据判断房价已经到顶,希 ...
- JS基础--JavaScript实例集锦(初学)
1.子节点childNodes: <!DOCTYPE html> <html> <head> <title>childNodes</title&g ...
- Django 安全性与防御性编程:如何保护 Django Web 应用
title: Django 安全性与防御性编程:如何保护 Django Web 应用 date: 2024/5/13 20:26:58 updated: 2024/5/13 20:26:58 cate ...
- C 语言编程 — 函数
目录 文章目录 目录 前文列表 函数 函数的声明 函数的定义 函数的形参与实参 值传递 引用传递 可变长形参列表 函数的调用 函数的指针 回调函数 递归函数 数的阶乘 斐波那契数列 构造函数(Cons ...
- 使用docker 5分钟搭建一个博客(mysql+WordPress)
目录 一.系统环境 二.前言 三.搭建博客 3.1 创建wordpress和mysql容器 3.2 在wordpress界面设置个人博客信息 3.3 WordPress容器创建命令的简化版本 一.系统 ...
- supersocket实际应用之你画我猜游戏(一)
supersocket这款组件,让不懂tcp/ip的人都能开发出网络应用.我们不必在开发与自己主要应用不相关的代码了,主要精力都能放在设计业务逻辑上面了. 现在使用现成又完备的组件,真是大大的提高了开 ...
- 异构数据源同步之数据同步 → datax 再改造,开始触及源码
开心一刻 其实追女生,没那么复杂 只要你花心思,花时间,陪她聊天,带她吃好吃的,耍好玩的,买好看的 慢慢你就会发现什么叫做 打水漂 不说了,我要去陪她看电影了 前情回顾 异构数据源同步之数据同步 → ...
- [N1盒子] Armbian安装Docker+Portainer汉化面板支持小钢炮汉化+中英文切换方法
1.下载汉化包,解压后备用链接:https://pan.baidu.com/s/1BLXMSmJFcgESeNMhQL26Mg&shfl=sharepset提取码:6vjr 以下安装,国内建议 ...
- ALL IN AI | 第六届金蝶云·苍穹追光者开发大赛正式启动报名!
2024年5月,第六届金蝶云·苍穹追光者开发大赛x第十三届"中国软件杯"金蝶赛道正式启动报名! 当下,人工智能正以其空前的速度.广度和深度,引领着新一轮科技革命和产业变革,重塑着经 ...