AI與.NET技術(shù)實現(xiàn)圖像分類模型的部署與調(diào)用的詳細(xì)步驟
引言
人工智能(AI)技術(shù)的迅猛發(fā)展推動了各行各業(yè)的數(shù)字化轉(zhuǎn)型。圖像分類,作為計算機視覺領(lǐng)域的核心技術(shù)之一,能夠讓機器自動識別圖像中的物體、場景或特征,已廣泛應(yīng)用于醫(yī)療診斷、安防監(jiān)控、自動駕駛和電子商務(wù)等領(lǐng)域。
與此同時,.NET 平臺憑借其高效性、跨平臺能力和強大的 C# 編程語言支持,成為開發(fā)者構(gòu)建企業(yè)級應(yīng)用的首選技術(shù)棧。將 AI 圖像分類模型與 .NET 技術(shù)結(jié)合,不僅能充分發(fā)揮兩者的優(yōu)勢,還能為開發(fā)者提供一種高效、直觀的實現(xiàn)方式。
本文將詳細(xì)介紹如何在 .NET 環(huán)境下使用 C# 部署和調(diào)用 AI 圖像分類模型。我們將從環(huán)境搭建、模型選擇,到模型調(diào)用,再到實際應(yīng)用場景,逐步展開講解,并提供豐富的代碼示例和實踐指導(dǎo),幫助開發(fā)者快速上手并應(yīng)用到實際項目中。
準(zhǔn)備工作
在開始實現(xiàn)圖像分類之前,我們需要準(zhǔn)備必要的開發(fā)環(huán)境和工具。以下是所需的軟件和庫:
- Visual Studio:Visual Studio 2022。
- .NET SDK:安裝 .NET 6.0 或更高版本,確保支持最新的功能和性能優(yōu)化。
- ML.NET:微軟提供的開源機器學(xué)習(xí)框架,專為 .NET 開發(fā)者設(shè)計,支持模型訓(xùn)練和推理。
- 模型文件:我們將使用預(yù)訓(xùn)練的圖像分類模型 tensorflow_inception_graph.pb。
安裝步驟
創(chuàng)建項目并添加依賴:在命令行中運行以下命令,創(chuàng)建一個控制臺應(yīng)用程序并安裝必要的 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
完成以上步驟后,你的環(huán)境就準(zhǔn)備好了。接下來,我們將選擇一個合適的圖像分類模型。
圖像分類模型的選擇
圖像分類模型是基于監(jiān)督學(xué)習(xí)的神經(jīng)網(wǎng)絡(luò),其目標(biāo)是將輸入圖像分配到預(yù)定義的類別中。在選擇模型時,我們需要考慮模型的性能、計算復(fù)雜度和適用場景。以下是幾種常見的圖像分類模型:
- 卷積神經(jīng)網(wǎng)絡(luò)(CNN):如 LeNet、AlexNet 和 VGGNet,適合基本的圖像分類任務(wù),但層數(shù)較深時可能面臨梯度消失問題。
- 殘差網(wǎng)絡(luò)(ResNet):通過引入殘差連接(skip connections),解決了深層網(wǎng)絡(luò)的訓(xùn)練難題,適用于高精度分類任務(wù)。
- EfficientNet:通過平衡網(wǎng)絡(luò)深度、寬度和分辨率,提供高效的性能,適合資源受限的場景。
模型訓(xùn)練與導(dǎo)出
考慮到時間和資源成本,我們將直接使用預(yù)訓(xùn)練的 tensorflow_inception_graph.pb 模型。如果你有自定義需求,可以使用以下步驟訓(xùn)練并導(dǎo)出模型:
- 數(shù)據(jù)準(zhǔn)備:收集并標(biāo)注圖像數(shù)據(jù)集,分為訓(xùn)練集和驗證集。
- 訓(xùn)練模型:使用 TensorFlow 或 PyTorch 等框架訓(xùn)練模型。
- 導(dǎo)出模型:利用框架提供的導(dǎo)出工具導(dǎo)出模型。
在本文中,我們選擇 tensorflow_inception_graph.pb 作為示例模型,這是一種由Google開發(fā)的高性能卷積神經(jīng)網(wǎng)絡(luò)(CNN)架構(gòu)。
該模塊通過并行使用不同大小的卷積核(如1x1、3x3、5x5)和池化層,提取圖像的多尺度特征。這種設(shè)計提高了模型在圖像分類任務(wù)中的表現(xiàn),同時保持了計算效率。支持 1000 個類別的分類,且可以輕松集成到 .NET 中。
大家可以直接點擊 tensorflow_inception_graph.pb 下載(文章最后也有下載方式)預(yù)訓(xùn)練的模型文件和分類文件,并將其放入項目目錄中。
也可以到github上下載(文章最后也有下載方式),里面的內(nèi)容相對來說也更豐富些。

在 .NET 中調(diào)用模型
現(xiàn)在,我們進(jìn)入核心部分:在 .NET 中調(diào)用 tensorflow_inception_graph.pb。以下是逐步實現(xiàn)的過程。
1. 創(chuàng)建 .NET 項目
使用命令行創(chuàng)建一個控制臺應(yīng)用,項目基本結(jié)構(gòu)如下:
ImageClassificationDemo/ ├── ImageClassificationDemo.csproj ├── Program.cs ├── assets/inputs/inception/tensorflow_inception_graph.pb ├── assets/inputs/inception/imagenet_comp_graph_label_strings.txt
2. 定義輸入和輸出數(shù)據(jù)結(jié)構(gòu)
如果在運行的時候報錯說找不到模型或者label文件,可以進(jìn)行如下操作:

輸入類中定義數(shù)據(jù)的結(jié)構(gòu)如下,后續(xù)會使用 TextLoader 加載數(shù)據(jù)時引用該類型。此處的類名為 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; }
}需要強調(diào)的是,ImageNetData 類中的標(biāo)簽在使用 TensorFlow 模型進(jìn)行評分時并沒有真正使用。而是在測試預(yù)測時使用它,這樣就可以將每個樣本數(shù)據(jù)的實際標(biāo)簽與 TensorFlow 模型提供的預(yù)測標(biāo)簽進(jìn)行比較。
輸出類的結(jié)構(gòu)如下:
public class ImageNetPrediction
{
[ColumnName(TFModelScorer.InceptionSettings.outputTensorName)]
public float[] PredictedLabels;
}Inception 模型還需要幾個傳入的默認(rèn)參數(shù):
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 管道
在處理深度神經(jīng)網(wǎng)絡(luò)時,必須使圖像適應(yīng)網(wǎng)絡(luò)期望的格式。這就是圖像被調(diào)整大小然后轉(zhuǎn)換的原因(主要是像素值在所有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));運行代碼后,模型將被成功加載到內(nèi)存中,接下來我們可以調(diào)用它進(jìn)行圖像分類。
通常情況下,這里經(jīng)常報的錯就是輸入/輸出節(jié)點的名稱不正確,你可以通過 Netron (https://netron.app/)工具查看輸入/輸出節(jié)點的名稱。
因為這兩個節(jié)點的名稱后面會在 estimator 的定義中使用:在 inception 網(wǎng)絡(luò)的情況下,輸入張量命名為 ‘input’,輸出命名為 ‘softmax2’。
下圖是通過 Netron 讀取的 tensorflow_inception_graph.pb 模型分析圖:


4. 提取預(yù)測結(jié)果
填充 estimator 管道
ITransformer model = pipeline.Fit(data); var predictionEngine = mlContext.Model.CreatePredictionEngine<ImageNetData, ImageNetPrediction>(model);
當(dāng)獲得預(yù)測結(jié)果后,我們會在屬性中得到一個浮點數(shù)數(shù)組。數(shù)組中的每個位置都會分配到一個標(biāo)簽。
例如,如果模型有5個不同的標(biāo)簽,則數(shù)組將為length = 5。數(shù)組中的每個位置都表示標(biāo)簽在該位置的概率;所有數(shù)組值(概率)的和等于1。
然后,您需要選擇最大的值(概率),并檢查配給了該位置的那個以填充 estimator 管道標(biāo)簽。
調(diào)用模型進(jìn)行圖像分類
接下來我們需要編寫代碼來加載圖像、進(jìn)行預(yù)測并解析結(jié)果。
1. 準(zhǔn)備素材與分類文件
定義圖像文件夾目錄和圖像分類目錄。以下代碼加載并預(yù)處理圖像:
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. 解析輸出結(jié)果
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 方法中調(diào)用,完整代碼如下:
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();
}運行程序后,你將看到類似以下的輸出:

其他實現(xiàn)方式
在實際應(yīng)用中,我們也可以使用ONNX模型,此處不做額外敘述。由于模型的性能和效率至關(guān)重要,只是提供一些優(yōu)化建議:
- 模型量化:使用 ONNX Runtime 的量化工具,將模型從浮點數(shù)(FP32)轉(zhuǎn)換為整數(shù)(INT8),減少模型大小和推理時間。
- 硬件加速:結(jié)合 ONNX Runtime 的 GPU 支持,利用 CUDA 或 DirectML 加速推理。
- 批處理:如果需要處理多張圖像,可以將輸入組織為批次(batch),提高吞吐量。例如:
var inputs = new List<ImageInput> { input1, input2, input3 };
var batchPrediction = mlContext.Data.LoadFromEnumerable(inputs);
var predictions = model.Transform(batchPrediction);- 緩存機制:對于頻繁使用的模型,保持預(yù)測引擎的單例實例,避免重復(fù)加載。
通過這些優(yōu)化,模型可以在 .NET 環(huán)境中實現(xiàn)更高的性能,滿足實時應(yīng)用的需求。
實際應(yīng)用場景
圖像分類模型在 .NET 應(yīng)用中有廣泛的用途,以下是幾個典型場景:
醫(yī)療影像分析
在醫(yī)療系統(tǒng)中,部署圖像分類模型可以輔助醫(yī)生識別 X 光片或 MRI 圖像中的異常。例如,檢測肺部結(jié)節(jié)或腫瘤。
智能安防
在監(jiān)控系統(tǒng)中,模型可以實時識別可疑物體或行為,如檢測闖入者或遺留物品。
電子商務(wù)
在商品管理系統(tǒng)中,自動分類上傳的商品圖像,提升搜索和推薦的準(zhǔn)確性。
挑戰(zhàn)與解決方案
- 數(shù)據(jù)隱私:通過加密傳輸和本地推理保護(hù)用戶數(shù)據(jù)。
- 模型更新:定期從云端下載新模型,并使用版本控制管理。
- 計算資源:在資源受限的設(shè)備上,使用輕量化模型(如 MobileNet)。
結(jié)論
本文詳細(xì)介紹了如何在 .NET 環(huán)境下使用 C# 部署和調(diào)用 AI 圖像分類模型。從環(huán)境搭建到模型選擇、部署與調(diào)用,再到性能優(yōu)化和應(yīng)用場景,我們提供了一套完整的實踐指南。通過 ML.NET 和預(yù)測模式的支持,開發(fā)者可以輕松地將強大的 AI 能力集成到 .NET 應(yīng)用中。
隨著 AI 技術(shù)的不斷進(jìn)步和 .NET 平臺的持續(xù)發(fā)展,二者的結(jié)合將為開發(fā)者帶來更多可能性。無論是構(gòu)建智能桌面應(yīng)用、Web 服務(wù)還是跨平臺解決方案,圖像分類模型都能為項目增添創(chuàng)新價值。希望本文能為你的 AI 之旅提供啟發(fā)和幫助!
參考資料
- 素材下載地址: 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
到此這篇關(guān)于AI與.NET技術(shù)實現(xiàn)圖像分類模型的部署與調(diào)用的詳細(xì)步驟的文章就介紹到這了,更多相關(guān).net 圖像分類模型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
.NET Core中RabbitMQ使用死信隊列的實現(xiàn)
本文主要介紹了.NET Core中RabbitMQ使用死信隊列的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Community Server專題二:體系結(jié)構(gòu)
Community Server專題二:體系結(jié)構(gòu)...2007-03-03
js獲取.aspx頁面里面的服務(wù)器控件和.ascx中的服務(wù)器控件值
用js獲取.ascx控件中服務(wù)器控件值時首先要得到服務(wù)器控件的ClientID再加上.ascx頁面里面的服務(wù)器空間ID并用"_"連接2009-02-02
c# 讀取文件內(nèi)容存放到int數(shù)組 array.txt
c# 讀取文本的內(nèi)容,并且將內(nèi)容保存到int數(shù)組中,大家可以學(xué)習(xí)到c#一些數(shù)組跟讀取內(nèi)容的函數(shù)。2009-04-04
ASP.NET(C#)實現(xiàn)一次性動態(tài)上傳多張圖片的代碼(多個文件)
我們就要讓這些文件上傳框動態(tài)添加,下面我以我做的一個圖庫管理中的上傳圖片的功能為例2011-10-10
C# javaScript函數(shù)的相互調(diào)用
如何在JavaScript訪問C#函數(shù),如何在C#中訪問JavaScript的已有變量等實現(xiàn)方法2008-12-12
Aspnetpager對GridView分頁并順利導(dǎo)出Excel
這篇文章主要介紹了Aspnetpager對GridView分頁并順利導(dǎo)出Excel的相關(guān)資料,需要的朋友可以參考下2016-04-04
如何在一個.NET?Core項目中使用RabbitMQ進(jìn)行即時消息管理
本文提供了在.NETCore項目中使用RabbitMQ進(jìn)行即時消息管理的詳細(xì)操作指南,包括安裝Erlang和RabbitMQ,配置RabbitMQ,以及在.NETCore項目中編寫代碼和調(diào)試,操作步驟詳盡,感興趣的朋友一起看看吧2024-09-09
在asp.net中獲取當(dāng)前頁面的URL的方法(推薦)
下面小編就為大家?guī)硪黄赼sp.net中獲取當(dāng)前頁面的URL的方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09

