AI時代的網站與手機App建置與開發Part24 - ML.NET與圖片異常偵測
· 摘要
將異常偵測應用在圖片資料能夠替代人工進行產品的瑕疵檢視, 例如檢視食物是否腐敗, 外型破裂, 研判X光片的內容是否異常, 或是判斷商品的包裝是否破損等等, 對於24小時不間斷的生產線能夠提供重要的品管支援.
在本篇文章中, 我們將使用Microsoft ML.NET支援的ResNet50預訓練模型(Pre-Trained Model)執行圖片的異常偵測, 期能利用AI模型支援24小時不間斷的自動化作業.
· 準備訓練資料
首先請啟動瀏覽器, 瀏覽至Cloud and Non-Cloud Images(Anomaly Detection, 下載訓練圖片資料集(下載網址: https://www.kaggle.com/datasets/ashoksrinivas/cloud-anomaly-detection-images?resource=download).
圖1所示即為下載得到的圖片資料集的部分內容:
請將訓練圖片加入到Visual Studio專案中名稱為images資料夾中, 並到[屬性]視窗將所有的訓練圖片的[複製到輸出目錄]屬性的內容值設定為:有更新時才複製.
· 準備預訓練模型
請啟動瀏覽器, 瀏覽至ONNX Model Zoo, 下載支援圖片辨識的預訓練模型(下載網址: GitHub -
onnx/models: A collection of pre-trained, state-of-the-art models in the ONNX
format), 請下載名稱為resnet50-v2-7.onnx的預訓練模型.
請將下載妥的預訓練模型加入到Visual Studio專案中名稱為PreTrainedModel資料夾中, 並到[屬性]視窗將預訓練模型檔案的[複製到輸出目錄]屬性的內容值設定為:有更新時才複製.
· 使用ML.NET偵測圖片內容異常
首先我們要定義描述訓練圖片資料的ImageData類別和描述圖片特徵向量的ImageFeatures類別.
· 定義描述訓練圖片資料的ImageData類別
// 描述訓練圖片資訊的類別
public class ImageData
{
public string data { get; set; } // 記載訓練圖片檔案名稱的屬性
}
· 定義描述圖片特徵向量的ImageFeatures類別
// 描述訓練圖片特徵向量的類別
public class ImageFeatures
{
// 指定輸出特徵向量的名稱(必須符合所使用的圖片辨識模型搭配)
[ColumnName("resnetv24_dense0_fwd")]
public float[] Features { get; set; } // 記載訓練圖片特徵向量的屬性
}
· 實作圖片異常偵測
//計算異常臨界值的函式
double CalculateAnomalyThreshold(List<float[]> features)
{
double totalDistance = 0;
int count = features.Count;
foreach (var feature in features)
{
totalDistance += CalculateDistanceToCenter( feature,
features); //加總距離中心點的距離
}
return totalDistance / count * 1.5;
//以平均距離的1.5倍為臨界值
}
//計算圖片的特徵向量距離中心點的距離
double CalculateDistanceToCenter(
float[] feature, List<float[]> features)
{
int
length = feature.Length;
var centroid = new float[length];
foreach (var f in features)
// 加總圖片特徵向量的內容值
{
for (int i = 0; i < length; i++)
entroid[i]
+= f[i];
}
for (int i = 0; i < length; i++)
// 計算圖片特徵向量的平均值
centroid[i]
/= features.Count;
double distance=0; //計算並傳回圖片的Euclidean distance(歐幾里德距離)
for (int i = 0; i < length; i++)
distance += Math.Pow(feature[i] - centroid[i], 2);
return Math.Sqrt(distance);
}
// 載入訓練圖片集
IEnumerable<ImageData>
LoadImageData(string folder)
{
foreach (var file in Directory.GetFiles( folder, "*.jpg")) // 讀取放置訓練圖片的資料夾中所有的JPG圖片檔案
{
yield return new ImageData { data
= file }; // 將圖片的資料建立成ImageData類別的物件
}
}
// 執行圖片異常偵測
private void btnTrain_Click(object sender, EventArgs e)
{
string imagesFolder = "images"; // 指定放置訓練圖片的資料夾名稱
string modelPath = "PreTrainedModel/resnet50-v2-7.onnx"; // 指定欲使用的預訓練模型
var mlContext = new MLContext(); // 建立MLContext類別的物件
var imageData = LoadImageData(imagesFolder).ToArray();//載入訓練圖片
var data = mlContext.Data.LoadFromEnumerable( imageData); // 準備成IDataView格式的訓練資料 var pipeline = mlContext.Transforms.LoadImages("data", "",
nameof(ImageData.data)) // 將圖片準備成預訓練模型指定的大小
.Append(mlContext.Transforms.ResizeImages("data", 224, 224))
.Append(mlContext.Transforms.ExtractPixels("data"))
.Append(mlContext.Transforms.ApplyOnnxModel(
modelFile: modelPath,
outputColumnNames: new[] { "resnetv24_dense0_fwd" },
inputColumnNames: new[] { "data" }));
var model = pipeline.Fit(data); // 使用指定的預訓練模型執行訓練
var transformedData =
model.Transform(data); // 計算每一張訓練圖片的特徵向量
// 將訓練圖片的特徵向量準備成List集合
var featuresList = new List<float[]>();
foreach (var features in mlContext.Data.CreateEnumerable<
ImageFeatures>(transformedData,
reuseRowObject: false))
{
featuresList.Add(features.Features);
}
var threshold = CalculateAnomalyThreshold(
featuresList); //計算異常的臨界值
int i = 0;
foreach(var feature in featuresList)//標示特徵大於臨界值的圖片為異常
{
var distance = CalculateDistanceToCenter(
feature, featuresList);
bool isAnomaly = distance > threshold;
Trace.WriteLine($"Image: {imageData[i++].data},
Anomaly: {isAnomaly}, Distance:
{distance}");
}
}
執行上述的程式碼會顯示對每一個訓練圖片的內容預測的結果, 其中的Anomaly內容值為True代表圖片的內容被判定為異常, 而Anomaly內容值為False代表圖片的內容被判定為正常, 如圖2所示:
圖2: 判定圖片內容是否異常的結果
範例下載:



留言
張貼留言