引言

人工智能(AI)技术的迅猛发展推动了各行各业的数字化转型。图像分类,作为计算机视觉领域的核心技术之一,能够让机器自动识别图像中的物体、场景或特征,已广泛应用于医疗诊断、安防监控、自动驾驶和电子商务等领域。

与此同时,.NET 平台凭借其高效性、跨平台能力和强大的 C# 编程语言支持,成为开发者构建企业级应用的首选技术栈。将 AI 图像分类模型与 .NET 技术结合,不仅能充分发挥两者的优势,还能为开发者提供一种高效、直观的实现方式。

本文将详细介绍如何在 .NET 环境下使用 C# 部署和调用 AI 图像分类模型。我们将从环境搭建、模型选择,到模型调用,再到实际应用场景,逐步展开讲解,并提供丰富的代码示例和实践指导,帮助开发者快速上手并应用到实际项目中。


准备工作

在开始实现图像分类之前,我们需要准备必要的开发环境和工具。以下是所需的软件和库:

  • Visual Studio:Visual Studio 2022。
  • .NET SDK:安装 .NET 6.0 或更高版本,确保支持最新的功能和性能优化。
  • ML.NET:微软提供的开源机器学习框架,专为 .NET 开发者设计,支持模型训练和推理。
  • 模型文件:我们将使用预训练的图像分类模型 tensorflow_inception_graph.pb。

安装步骤

创建项目并添加依赖:在命令行中运行以下命令,创建一个控制台应用程序并安装必要的 NuGet 包:

dotnet new console -n ImageClassificationDemo
cd ImageClassificationDemo
dotnet add package Microsoft.ML
dotnet add package Microsoft.ML.ImageAnalytics
dotnet add package Microsoft.ML.TensorFlow
dotnet add package SciSharp.TensorFlow.Redist

完成以上步骤后,你的环境就准备好了。接下来,我们将选择一个合适的图像分类模型。


图像分类模型的选择

图像分类模型是基于监督学习的神经网络,其目标是将输入图像分配到预定义的类别中。在选择模型时,我们需要考虑模型的性能、计算复杂度和适用场景。以下是几种常见的图像分类模型:

  • 卷积神经网络(CNN):如 LeNet、AlexNet 和 VGGNet,适合基本的图像分类任务,但层数较深时可能面临梯度消失问题。
  • 残差网络(ResNet):通过引入残差连接(skip connections),解决了深层网络的训练难题,适用于高精度分类任务。
  • EfficientNet:通过平衡网络深度、宽度和分辨率,提供高效的性能,适合资源受限的场景。

模型训练与导出

考虑到时间和资源成本,我们将直接使用预训练的 tensorflow_inception_graph.pb 模型。如果你有自定义需求,可以使用以下步骤训练并导出模型:

  1. 数据准备:收集并标注图像数据集,分为训练集和验证集。
  2. 训练模型:使用 TensorFlow 或 PyTorch 等框架训练模型。
  3. 导出模型:利用框架提供的导出工具导出模型。

在本文中,我们选择 tensorflow_inception_graph.pb 作为示例模型,这是一种由Google开发的高性能卷积神经网络(CNN)架构。

该模块通过并行使用不同大小的卷积核(如1x1、3x3、5x5)和池化层,提取图像的多尺度特征。这种设计提高了模型在图像分类任务中的表现,同时保持了计算效率。支持 1000 个类别的分类,且可以轻松集成到 .NET 中。

大家可以直接点击 tensorflow_inception_graph.pb 下载(文章最后也有下载方式)预训练的模型文件和分类文件,并将其放入项目目录中。

也可以到github上下载(文章最后也有下载方式),里面的内容相对来说也更丰富些。


在 .NET 中调用模型

现在,我们进入核心部分:在 .NET 中调用 tensorflow_inception_graph.pb。以下是逐步实现的过程。

1. 创建 .NET 项目

使用命令行创建一个控制台应用,项目基本结构如下:

ImageClassificationDemo/
├── ImageClassificationDemo.csproj
├── Program.cs
├── assets/inputs/inception/tensorflow_inception_graph.pb
├── assets/inputs/inception/imagenet_comp_graph_label_strings.txt

2. 定义输入和输出数据结构

如果在运行的时候报错说找不到模型或者label文件,可以进行如下操作:

输入类中定义数据的结构如下,后续会使用 TextLoader 加载数据时引用该类型。此处的类名为 ImageNetData

    public class ImageNetData{[LoadColumn(0)]public string ImagePath;[LoadColumn(1)]public string Label;public static IEnumerable<ImageNetData> ReadFromCsv(string file, string folder){return File.ReadAllLines(file).Select(x => x.Split('\t')).Select(x => new ImageNetData { ImagePath = Path.Combine(folder, x[0]), Label = x[1] } );}}public class ImageNetDataProbability : ImageNetData{public string PredictedLabel;public float Probability { get; set; }}

需要强调的是,ImageNetData 类中的标签在使用 TensorFlow 模型进行评分时并没有真正使用。而是在测试预测时使用它,这样就可以将每个样本数据的实际标签与 TensorFlow 模型提供的预测标签进行比较。

输出类的结构如下:

public class ImageNetPrediction
{[ColumnName(TFModelScorer.InceptionSettings.outputTensorName)]public float[] PredictedLabels;
}

Inception 模型还需要几个传入的默认参数:

public struct ImageNetSettings
{public const int imageHeight = 224;public const int imageWidth = 224;public const float mean = 117;public const bool channelsLast = true;
}      

3. 定义 estimator 管道

在处理深度神经网络时,必须使图像适应网络期望的格式。这就是图像被调整大小然后转换的原因(主要是像素值在所有R,G,B通道上被归一化)。

var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "input", imageFolder: imagesFolder, inputColumnName: nameof(ImageNetData.ImagePath)).Append(mlContext.Transforms.ResizeImages(outputColumnName: "input", imageWidth: ImageNetSettings.imageWidth, imageHeight: ImageNetSettings.imageHeight, inputColumnName: "input")).Append(mlContext.Transforms.ExtractPixels(outputColumnName: "input", interleavePixelColors: ImageNetSettings.channelsLast, offsetImage: ImageNetSettings.mean)).Append(mlContext.Model.LoadTensorFlowModel(modelLocation).ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2" }, inputColumnNames: new[] { "input" },addBatchDimensionInput:true));

运行代码后,模型将被成功加载到内存中,接下来我们可以调用它进行图像分类。

通常情况下,这里经常报的错就是输入/输出节点的名称不正确,你可以通过 Netron (https://netron.app/)工具查看输入/输出节点的名称。

因为这两个节点的名称后面会在 estimator 的定义中使用:在 inception 网络的情况下,输入张量命名为 ‘input’,输出命名为 ‘softmax2’。

下图是通过 Netron 读取的 tensorflow_inception_graph.pb 模型分析图:

输入张量名

输出张量名

4. 提取预测结果

填充 estimator 管道

ITransformer model = pipeline.Fit(data);
var predictionEngine = mlContext.Model.CreatePredictionEngine<ImageNetData, ImageNetPrediction>(model);

当获得预测结果后,我们会在属性中得到一个浮点数数组。数组中的每个位置都会分配到一个标签。

例如,如果模型有5个不同的标签,则数组将为length = 5。数组中的每个位置都表示标签在该位置的概率;所有数组值(概率)的和等于1。

然后,您需要选择最大的值(概率),并检查配给了该位置的那个以填充 estimator 管道标签。


调用模型进行图像分类

接下来我们需要编写代码来加载图像、进行预测并解析结果。

1. 准备素材与分类文件

定义图像文件夹目录和图像分类目录。以下代码加载并预处理图像:

string assetsRelativePath = @"../../../assets";
string assetsPath = GetAbsolutePath(assetsRelativePath);string tagsTsv = Path.Combine(assetsPath, "inputs", "images", "tags.tsv");
string imagesFolder = Path.Combine(assetsPath, "inputs", "images");
string inceptionPb = Path.Combine(assetsPath, "inputs", "inception", "tensorflow_inception_graph.pb");
string labelsTxt = Path.Combine(assetsPath, "inputs", "inception", "imagenet_comp_graph_label_strings.txt");

2. 加载模型

private PredictionEngine<ImageNetData, ImageNetPrediction> LoadModel(string dataLocation, string imagesFolder, string modelLocation)
{ConsoleWriteHeader("Read model");Console.WriteLine($"Model location: {modelLocation}");Console.WriteLine($"Images folder: {imagesFolder}");Console.WriteLine($"Training file: {dataLocation}");Console.WriteLine($"Default parameters: image size=({ImageNetSettings.imageWidth},{ImageNetSettings.imageHeight}), image mean: {ImageNetSettings.mean}");var data = mlContext.Data.LoadFromTextFile<ImageNetData>(dataLocation, hasHeader: true);var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "input", imageFolder: imagesFolder, inputColumnName: nameof(ImageNetData.ImagePath)).Append(mlContext.Transforms.ResizeImages(outputColumnName: "input", imageWidth: ImageNetSettings.imageWidth, imageHeight: ImageNetSettings.imageHeight, inputColumnName: "input")).Append(mlContext.Transforms.ExtractPixels(outputColumnName: "input", interleavePixelColors: ImageNetSettings.channelsLast, offsetImage: ImageNetSettings.mean)).Append(mlContext.Model.LoadTensorFlowModel(modelLocation).ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2" },inputColumnNames: new[] { "input" }, addBatchDimensionInput:true));ITransformer model = pipeline.Fit(data);var predictionEngine = mlContext.Model.CreatePredictionEngine<ImageNetData, ImageNetPrediction>(model);return predictionEngine;
}

3. 解析输出结果

protected IEnumerable<ImageNetData> PredictDataUsingModel(string testLocation, string imagesFolder, string labelsLocation, PredictionEngine<ImageNetData, ImageNetPrediction> model)
{ConsoleWriteHeader("Classify images");Console.WriteLine($"Images folder: {imagesFolder}");Console.WriteLine($"Training file: {testLocation}");Console.WriteLine($"Labels file: {labelsLocation}");var labels = ReadLabels(labelsLocation);var testData = ImageNetData.ReadFromCsv(testLocation, imagesFolder);foreach (var sample in testData){var probs = model.Predict(sample).PredictedLabels;var imageData = new ImageNetDataProbability(){ImagePath = sample.ImagePath,Label = sample.Label};(imageData.PredictedLabel, imageData.Probability) = GetBestLabel(labels, probs);imageData.ConsoleWrite();yield return imageData;}
}

Main 方法中调用,完整代码如下:

static void Main(string[] args)
{string assetsRelativePath = @"../../../assets";string assetsPath = GetAbsolutePath(assetsRelativePath);string tagsTsv = Path.Combine(assetsPath, "inputs", "images", "tags.tsv");string imagesFolder = Path.Combine(assetsPath, "inputs", "images");string inceptionPb = Path.Combine(assetsPath, "inputs", "inception", "tensorflow_inception_graph.pb");string labelsTxt = Path.Combine(assetsPath, "inputs", "inception", "imagenet_comp_graph_label_strings.txt");try{TFModelScorer modelScorer = new TFModelScorer(tagsTsv, imagesFolder, inceptionPb, labelsTxt);modelScorer.Score();}catch (Exception ex){ConsoleHelpers.ConsoleWriteException(ex.ToString());}ConsoleHelpers.ConsolePressAnyKey();
}

运行程序后,你将看到类似以下的输出:


其他实现方式

在实际应用中,我们也可以使用ONNX模型,此处不做额外叙述。由于模型的性能和效率至关重要,只是提供一些优化建议:

  1. 模型量化:使用 ONNX Runtime 的量化工具,将模型从浮点数(FP32)转换为整数(INT8),减少模型大小和推理时间。
  2. 硬件加速:结合 ONNX Runtime 的 GPU 支持,利用 CUDA 或 DirectML 加速推理。
  3. 批处理:如果需要处理多张图像,可以将输入组织为批次(batch),提高吞吐量。例如:
var inputs = new List<ImageInput> { input1, input2, input3 };
var batchPrediction = mlContext.Data.LoadFromEnumerable(inputs);
var predictions = model.Transform(batchPrediction);
  1. 缓存机制:对于频繁使用的模型,保持预测引擎的单例实例,避免重复加载。

通过这些优化,模型可以在 .NET 环境中实现更高的性能,满足实时应用的需求。


实际应用场景

图像分类模型在 .NET 应用中有广泛的用途,以下是几个典型场景:

  1. 医疗影像分析
    在医疗系统中,部署图像分类模型可以辅助医生识别 X 光片或 MRI 图像中的异常。例如,检测肺部结节或肿瘤。

  2. 智能安防
    在监控系统中,模型可以实时识别可疑物体或行为,如检测闯入者或遗留物品。

  3. 电子商务
    在商品管理系统中,自动分类上传的商品图像,提升搜索和推荐的准确性。

挑战与解决方案

  • 数据隐私:通过加密传输和本地推理保护用户数据。
  • 模型更新:定期从云端下载新模型,并使用版本控制管理。
  • 计算资源:在资源受限的设备上,使用轻量化模型(如 MobileNet)。

结论

本文详细介绍了如何在 .NET 环境下使用 C# 部署和调用 AI 图像分类模型。从环境搭建到模型选择、部署与调用,再到性能优化和应用场景,我们提供了一套完整的实践指南。通过 ML.NET 和预测模式的支持,开发者可以轻松地将强大的 AI 能力集成到 .NET 应用中。

随着 AI 技术的不断进步和 .NET 平台的持续发展,二者的结合将为开发者带来更多可能性。无论是构建智能桌面应用、Web 服务还是跨平台解决方案,图像分类模型都能为项目增添创新价值。希望本文能为你的 AI 之旅提供启发和帮助!


参考资料

  • 素材下载地址: https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip
  • Netron工具地址: https://netron.app/
  • 224x224图像素材: https://www.kaggle.com/datasets/abhinavnayak/catsvdogs-transformed/data
  • tensorflow教程及模型文件和label文件: https://github.com/martinwicke/tensorflow-tutorial
  • Image Classification - Scoring sample: https://github.com/dotnet/machinelearning-samples/blob/main/samples/csharp/getting-started/DeepLearning_ImageClassification_TensorFlow/README.md
  • ML.NET 官方文档: https://dotnet.microsoft.com/apps/machinelearning-ai/ml-dotnet
  • ONNX Model Zoo: https://github.com/onnx/models

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/80930.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/80930.shtml
英文地址,请注明出处:http://en.pswp.cn/web/80930.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cause: org.apache.ibatis.ognl.OgnlException: sqlSegment

17:12:47.358 [http-nio-11080-exec-2] ERROR c.c.f.w.e.GlobalExceptionHandler - [handleRuntimeException,100] - 请求地址/xx/xxx/xxx/xxx/xxx/8bbe5b132a7a4d9bb28cedfeac94d69f,发生未知异常. org.mybatis.spring.MyBatisSystemException: nested exception is org.apach…

jmeter登录接口生成一批token并写入csv文件

背景&#xff1a;大部分项目真实的业务接口都是需要token鉴权的&#xff0c;想对一批核心业务接口进行并发压测&#xff0c;必然要先生成一批token给这些接口并发循环调用。 基本的思路是这样的&#xff1a;一批手机号csv文件 -》登录接口循环读取csv文件并生成token -》每次…

技术篇-2.3.Golang应用场景及开发工具安装

Golang 虽然语法简洁&#xff0c;上手也较快&#xff0c;但其在高并发、微服务和云原生领域的优势明显&#xff0c;要真正精通并灵活运用仍需积累大量实践经验。与 Java 借助重量级框架不同&#xff0c;Go 倾向于使用标准库和轻量级第三方包来构建高性能、低延迟的系统。 1.1应…

Java面试问题基础篇

面向对象 面向对象编程&#xff1a;拿东西过来做对应的事情 特征&#xff1a; 封装&#xff1a;对象代表什么&#xff0c;就要封装对应的数据&#xff0c;并提供数据对应的行为 继承&#xff1a;Java中提供一个关键字extends&#xff0c;用这个关键字可以让一个类和另一个类…

SpringBoot的前世今生

1. Spring Spring 特性&#xff1a;IOC、AOP、DI&#xff0c; Spring&#xff1a;解决对象耦合的问题&#xff0c;在 applicationContext.xml 中申明 bean&#xff0c;Spring在启动时会解析xml文件进行装载&#xff0c;当需要用对象时直接从容器中拿取bean。 Spring万能胶&a…

微信小程序自行diy选择器有效果图

效果图 实现思路 主要运用到小程序自带视图容器《swiper》 运用到的属性《vertical》《display-multiple-items》《current》《animationfinish》 滑动方向变为纵向 vertical&#xff1a;true 显示的滑块数量 display-multiple-items&#xff1a;5 当前所在滑块的 index curr…

【实用教程】如何快速搭建一套私有的埋点系统?

这篇教程将基于开源项目-ClkLog&#xff0c;教大家快速搭建一套自有的埋点系统&#xff0c;从0开始完成数据采集、分析与展示&#xff0c;全流程掌控用户行为数据。 ClkLog是一款支持私有化部署的全开源用户行为数据采集与分析系统&#xff0c;兼容Web、App、小程序多端埋点&am…

falsk模型-flask_sqlalchemy增删改查

1、增、删、改 增 home_bp.route(/useradd) def user_add():users []for i in range(10,20):user User()user.name 冰冰 str(i)user.age 20iusers.append(user)try:db.session.add_all(users)db.session.commit()return jsonify({code:1,info:success})except Exception…

【专题】机器学习期末复习资料

机器学习期末复习资料&#xff08;题库&#xff09; 链接&#xff1a;https://blog.csdn.net/Pqf18064375973/article/details/148105494?sharetypeblogdetail&sharerId148105494&sharereferPC&sharesourcePqf18064375973&sharefrommp_from_link 【测试】 Art…

SpringCloud Alibaba微服务-- Sentinel的使用(笔记)

雪崩问题&#xff1a; 小问题引发大问题&#xff0c;小服务出现故障&#xff0c;处理不当&#xff0c;可能导致整个微服务宕机。 假如商品服务出故障&#xff0c;购物车调用该服务&#xff0c;则可能出现处理时间过长&#xff0c;如果一秒几十个请求&#xff0c;那么处理时间过…

5:OpenCV—图像亮度、对比度变换

1.更改图像和视频的亮度 更改亮度 更改图像的亮度是常用的点操作。在此操作中&#xff0c;图像中每个像素的值应增加/减少一个常数。要更改视频的亮度&#xff0c;应对视频中的每一帧执行相同的操作。 如果要增加图像的亮度&#xff0c;则必须为图像中的每个像素添加一些正常…

【工作流】Fastgpt配置豆包模型-火山引擎

V4.9.7 Fastgpt现在不通过oneapi 来配置模型和渠道了&#xff0c; 可以直接在页面进行设置 首先在账号- 模型提供商里面 填入豆包的信息&#xff1a; 渠道名随便填&#xff0c;厂商选豆包&#xff0c; 然后选3个模型&#xff0c;如图所示 如果没有填入模型映射的话是没办法 …

2025年系统架构师---综合知识卷

1.进程是一个具有独立功能的程序关于某数据集合的一次运行活动,是系统进行资源分配和调度的基本单位(线程包含于进程之中,可并发,是系统进行运算调度的最小单位)。一个进程是通过其物理实体被感知的,进程的物理实体又称为进程的静态描述,通常由三部分组成,分别是程序、…

LangChain4j入门AI(六)整合提示词(Prompt)

前言 提示词&#xff08;Prompt&#xff09;是用户输入给AI模型的一段文字或指令&#xff0c;用于引导模型生成特定类型的内容。通过提示词&#xff0c;用户可以告诉AI“做什么”、 “如何做”以及“输出格式”&#xff0c;从而在满足需求的同时最大程度减少无关信息的生成。有…

如何使用 Docker Compose 部署 Immich

如何使用 Docker Compose 部署 Immich Immich 是一个开源的自建照片和视频备份解决方案&#xff0c;通过 Docker 部署可以快速构建一个稳定的自主管理系统。本文将带你一步步完成使用 Docker Compose 部署 Immich 的过程&#xff0c;帮助你在生产环境中实现高效的媒体管理。 1…

Mac远程连接Windows电脑教程

在 Mac 上通过微软官方远程桌面工具&#xff08;Windows App&#xff09;连接局域网内的 Windows 电脑&#xff0c;需按照以下步骤操作&#xff1a; 一、准备工作 确认 Windows 版本支持远程连接 Windows 专业版/企业版/教育版 支持远程桌面功能。家庭版不支持&#xff0c;需使…

从0到1打造AI Copilot:用SpringBoot + ChatGPT API实现智能开发助手

本文将从0到1系统性地讲解如何基于SpringBoot与OpenAI ChatGPT API打造一款智能开发助手&#xff08;AI Copilot&#xff09;。文章首先介绍AI Copilot的背景与价值&#xff0c;接着深入架构设计与环境准备&#xff0c;然后通过详尽的代码示例演示SpringBoot项目的搭建、依赖配…

Crawl4AI:高效的AI数据抓取工具

在大数据时代&#xff0c;抓取并处理大量数据是进行人工智能&#xff08;AI&#xff09;研究与开发的基础。而网络爬虫是获取网页数据的重要工具。今天&#xff0c;我想介绍一个功能强大的爬虫框架——Crawl4AI&#xff0c;它为数据抓取和机器学习任务提供了无缝的支持。Crawl4…

从单链表 list 中删除第 i 个元素--Python

从单链表 list 中删除第 i 个元素 一、问题引入二、解题步骤1.思维导图2.解题步骤 三、代码实现四、个人总结 一、问题引入 请编写程序&#xff0c;将 n 个整数顺次插入一个初始为空的单链表的表头。随后对任意给定的位序 i&#xff0c;删除链表中第 i 个结点。注意&#xff1…

git学习与使用(远程仓库、分支、工作流)

文章目录 前言简介git的工作流程git的安装配置git环境&#xff1a;git config --globalgit的基本使用新建目录初始化仓库&#xff08;repository&#xff09;添加到暂存区新增/修改/删除 文件状态会改变 提交到仓库查看提交&#xff08;commit&#xff09;的历史记录git其他命令…