百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类

liebian365 2025-03-23 20:57 5 浏览 0 评论

引言

人工智能(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 classImageNetData
{
[LoadColumn(0)]
publicstring ImagePath;

[LoadColumn(1)]
publicstring Label;

public static IEnumerable 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] } );
}
}

publicclassImageNetDataProbability : ImageNetData
{
publicstring PredictedLabel;
publicfloat Probability { get; set; }
}

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

输出类的结构如下:

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

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

public struct ImageNetSettings
{
publicconstint imageHeight = 224;
publicconstint imageWidth = 224;
publicconstfloat mean = 117;
publicconstbool 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(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 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(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(model);

return predictionEngine;
}

3. 解析输出结果

protected IEnumerable PredictDataUsingModel(string testLocation, 
string imagesFolder,
string labelsLocation,
PredictionEngine 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();
yieldreturn 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 { 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 之旅提供启发和帮助!


合集链接

  • AI与.NET技术实操系列(一): 开篇
  • AI与.NET技术实操系列(二):开始使用 ML.NET
  • AI与.NET技术实操系列(三):在.NET中使用大语言模型(LLMs)
  • AI与.NET技术实操系列(四):使用Semantic Kernel和DeepSeek构建AI应用
  • AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现

参考资料

  • 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

相关推荐

深度解密epoll 如何工作的?(epoll基本处理流程)

epoll...

大乐透第19082期:头奖开出7注1000万分落六地 奖池41亿元

2019年7月17日晚开奖的体彩超级大乐透第19082期开奖号码为:前区06、18、20、21、31,后区03、04。本期大乐透前区号码五区比为1:0:3:0:1,二区和四区号码没有给出。当期前区和值...

【开奖】4月27日周六:福彩、体彩(2021年4月27日体彩开奖结果)

4月27日开奖福彩3D第2019110期:61222选5第2019110期:0812202122排列3第19110期:303排列5第19110期:30305大乐透第19047期:0304...

“红狒狒”落户哈尔滨铁路局(哈尔滨铁路红肠)

这几天,“红人”“红狒狒”在牡丹江机务段可引起了不小的轰动,众粉丝争相与其拍照留念,在该段人气爆棚!“红狒狒”到底何许人也?“红狒狒”,中文名:和谐3D型电力机车;绰号:红狒狒、番茄;制造商:大连机...

2D、3D、2.5D,做游戏还是搞噱头?玩家都晕了

前言游戏类型就像某种潮流,一种流行罢,另一种接棒成为主流。前两年的新作大多以“开放世界”为标签,在追求纯沙盒的过程中打造出一些细致的分类,比如说“类GTA沙盒”。诚然,纯碎的沙盒游戏并不多见,业内只有...

《战神4》PC版宣传片发布 GTX 1070即可60帧畅玩

在今年10月的时候索尼PlayStation官方正式宣布圣莫尼卡2018年的《战神4》将于2022年1月14日推出PC版本,官方在今天公布了一段PC版宣传片,并且公开了游戏的配置需求。下面让我们一起来...

男星深情好丈夫形象崩塌,半夜搂美女坐大腿,举止亲密

近日,于晓光被拍到深夜在酒吧玩,结束后与一名女子一起上车离开。上车后,女子直接坐在了他腿上,他也顺势搂着美女,美女满脸笑容地坐在他腿上玩手机离开。可能有人会好奇,于晓光是谁呢?于晓光是韩国艺人秋瓷炫的...

d3d12dll丢失怎么修复?d3d12dll加载失败怎么解决?

  d3d12.dll丢失怎么修复?d3d12.dll加载失败怎么解决?很多朋友想要运行游戏的时候都会遇到这个问题,这种情况该怎么办呢?今天系统之家小编给朋友们讲讲具体的解决方法,操作其实还蛮简单的。...

许多玩家反馈《生化4RE》PC一直崩溃 无法进入游戏

今日(3月24日),卡普空《生化危机4:重制版》正式发售,然而有部分PC玩家遇到了游戏崩溃等问题。很多玩家在贴吧发帖称游戏遇到了严重的崩溃问题,且经常反复,报错代码普遍为FatalD3Derror...

微软正式推出适用于WSL Linux的D3D12 GPU视频加速技术

今天,微软正式向WindowsSubsystemforLinux(WSL)用户发布了Direct3D12GPU视频加速支持。在微软通过WSL允许在Linux下使用Open...

《怪物猎人:崛起》曙光系统报错“Fatal d3d error”的解决办法

《怪物猎人:崛起》曙光系统报错“Fatald3derror”的解决办法不少小伙伴反应《怪物猎人:崛起》DLC曙光预载以后打不开游戏,出现了Fatald3derror类似的错误代码,这类问题的解...

Mac+双屏,前端程序员的专业配置 - Loctek 乐歌 D3D 双屏电脑显示器支架

做FE也有一段日子了,电脑屏幕每天在设计稿、浏览器、IDE、即时通讯工具、Terminal、邮箱之间切换。虽然mac的工作区带来了很多灵活,但是依然略显不足。于是入手支架,把公司配的电脑和显示器发挥起...

RPC 的原理和简单使用(rpc详解)

RPC的概念RPC,RemoteProcedureCall,翻译成中文就是远程过程调用,是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数。在调用的...

大厂开源的golang微服务rpc框架 — kitex

提前rpc估计所有的开发同学都知道,不知道的也无所谓,毕竟我也好几年没用了,今天带大家在复习一下。RPC(RemoteProcedureCall):远程过程调用,...

干货!一文掌握Protobuf所有语言所有用法,快收藏

说实话,Protobuf这个库,让人相见时难别亦难,东风无力百花残,每次等到要用它的时候,总感觉还没有完全掌握它的用法,而实际上等去百度或者谷歌的时候,教程都是多么的凌乱不堪。学会它,最直接关系到的,...

取消回复欢迎 发表评论: