AI時代的網站與手機App建置與開發Part25 - ML.NET與聲音異常偵測

 ·       摘要

將異常偵測應用在聲音資料能夠預警機器運作的失誤, 例如預警馬逹, 幫浦, 閥門開關, 齒輪, 滑軌, 或是風扇的運作是否異常, 或是預警汽機車, 輪船, 甚至飛機的引擎狀態等等, 對於24小時不間斷的生產線能夠提供重要的營運支援.


: 機械運作聲音異常預警示意圖

在本篇文章中, 我們將使用Microsoft ML.NET搭配Librosa聲音處理程式庫執行聲音的異常偵測, 期能利用AI模型支援24小時不間斷的營運作業.

·       準備訓練資料

首先請啟動瀏覽器, 瀏覽至MIMII DUE: Sound Dataset for Malfunctioning Industrial Machine Investigation and Inspection with Domain Shifts due to Changes in Operational and Environmental Conditions, 下載訓練聲音資料集(下載網址: https://zenodo.org/records/4740355).

本篇文章將會從上述的下載網址下載幫浦(Pump)運作的聲音檔案, 然後將其中的10個正常的幫浦運作聲音檔案加入到名稱為NormalSounds的資料夾中, 再將其中的10個異常的幫浦運作聲音檔案加入到名稱為AbnormalSounds的資料夾中(讀者可以視需要加入更多的聲音檔案, 以提升訓練的機器學習模型的準確度), 做好之後, 請到[屬性]視窗將所有的聲音檔案的[複製到輸出目錄]屬性的內容值設定為:有更新時才複製.

·       實作取得聲音檔案特徵向量的Python程式

import librosa

import pandas as pd

import numpy as np

import os

# 讀取資料夾中的聲音檔案, 並將檔案的檔案名稱建立成字串陣列後傳回

def get_filenames_in_folder(folder_path):

    filenames = []

    for filename in os.listdir(folder_path):  # 取得資料夾中的所有內容

        if os.path.isfile(os.path.join(                                                  folder_path, filename)):     # 如果是檔案

            filenames.append(filename)        # 將檔案名稱加入到陣列

    return filenames

# 使用MFCC(Mel Frequency Cepstral Coefficients)演算法取得聲音的特徵向量

def extract_features(foldername, file_path):

    audio, sample_rate = librosa.load(

f"{foldername}/{file_path}", sr=None) # 讀取聲音檔案

mfccs = librosa.feature.mfcc(y=audio, sr=sample_rate,

n_mfcc=13)    # 取得聲音的特徵

    mfccs_mean = np.mean(mfccs, axis=1)             # 計算平均值

    return mfccs_mean                               # 傳回平均值

# 取得NormalSounds資料夾中正常的聲音檔案, 將檔案名稱建立成字串陣列

folder_path = 'NormalSounds'  

normal_audio_files = get_filenames_in_folder(folder_path)

print(normal_audio_files)

 

# 取得正常聲音檔案的特徵向量

features = [extract_features(folder_path, f)                                    for f in normal_audio_files]

dfNormal = pd.DataFrame(features)         # 將特徵向量建立成DataFrame  

# DataFrame加入名稱為Label的欄位, 並將欄位內容值設定為0(正常)

dfNormal['Label'] = 0    

 

# 取得AbnormalSounds資料夾中異常的聲音檔案, 將檔案名稱建立成字串陣列

folder_path = 'AbnormalSounds'

abnormal_audio_files = get_filenames_in_folder(folder_path)

print(abnormal_audio_files)

 

# 取得異常聲音檔案的特徵向量

features = [extract_features(folder_path, f)

 for f in abnormal_audio_files]

dfAbnormal = pd.DataFrame(features)         # 將特徵向量建立成DataFrame

# DataFrame加入名稱為Label的欄位, 並將欄位內容值設定為1(異常)

dfAbnormal['Label'] = 1                    

 

df = pd.concat([dfNormal, dfAbnormal],

ignore_index=True)   # 串連dfNormal, dfAbnormal兩個DataFrame

df.to_csv("audio_features.csv",

index=False)         # DataFrame的內容寫成純文字文件供訓練使用

執行上述的Python程式, 會擷取當做訓練資料的聲音檔案的特徵向量, 並儲存成名稱為audio_features.csv的文件, ML.NET訓練時使用.

1所示即為名稱為audio_features.csv的文件的部分內容:

1: 名稱為audio_features.csv的文件的部分內容

請名稱為audio_features.csv的文件加入到Visual Studio專案中, 並到[屬性]視窗將[複製到輸出目錄]屬性的內容值設定為:有更新時才複製.

·       使用ML.NET偵測聲音內容異常

首先我們要定義描述訓練圖片資料的ImageData類別和描述圖片特徵向量的ImageFeatures類別.

·       定義聲音特徵向量的AudioFeature類別

// 描述聲音特徵向量的類別

public class AudioFeature

{

    [LoadColumn(0, 12)]      // 載入0~12, 13個欄位的特徵向量的內容值

    [VectorType(13)]

    public float[] Features { get; set; }

    [LoadColumn(13)]                        // 載入Label檔案的內容值

    public float Label { get; set; }

}

·       定義描述圖片特徵向量的ImageFeatures類別

// 描述預測結果的類別

public class AnomalyPrediction

{

    [ColumnName("PredictedLabel")]

    public bool Prediction { get; set; }

}

·       實作聲音異常偵測

private void btnDetect_Click(object sender, EventArgs e)

{

    var mlContext = new MLContext();       // 建立MLContext類別的物件

    var dataPath = "audio_features.csv";   // 存放聲音特徵向量的檔案名稱

    IDataView data = mlContext.Data.LoadFromTextFile<AudioFeature>(

        path: dataPath, hasHeader: true,

separatorChar: ',');           // 載入存放聲音特徵向量的檔案的內容

    // 指定特徵向量的內容為訓練資料(Features)

    var pipeline = mlContext.Transforms.Concatenate("Features",

nameof(AudioFeature.Features))

        .Append(mlContext.Transforms.NormalizeMinMax(

"Features"))   // 將特徵向量的內容值轉換成0~1之間的數字

        .Append(mlContext.AnomalyDetection.Trainers.RandomizedPca(

            featureColumnName: "Features",

rank: 2));         // 使用RandomizedPca演算法進行訓練

    var model = pipeline.Fit(data);               // 執行訓練

    var transformedData = model.Transform(data);  // 取得訓練結果

    var metrics = mlContext.AnomalyDetection.Evaluate(

transformedData, labelColumnName: "Label");   // 評估訓練結果

// 顯示Area Under the ROC Curve (AUC-ROC)

Trace.WriteLine($"Area Under ROC: {metrics.AreaUnderRocCurve}");

    // 顯示Detection Rate At False Positive Count

Trace.WriteLine($@"Detection Rate at False Positive Count:

                    {metrics.DetectionRateAtFalsePositiveCount}");    

var predictionEngine =

mlContext.Model.CreatePredictionEngine

<AudioFeature, AnomalyPrediction>(model);  // 建立預測引擎

    // 使用訓練資料的最後一筆當做測試資料

    var newSample = new AudioFeature

    {

        Features = mlContext.Data.CreateEnumerable<AudioFeature>(

data, reuseRowObject: false).Last().Features

    };

    var prediction = predictionEngine.Predict(newSample); // 執行預測

    Trace.WriteLine(

$"Is Anomaly? {prediction.Prediction}"); // 顯示預測結果

}

執行上述的程式碼會顯示判定聲音檔案是否異常預測結果, 如圖2所示:

2: 判定測試的聲音檔案是否異常的結果

·       預測結果說明

1.    Area Under ROC:

ROCReceiver Operating Characteristic的縮寫, 代表二元分類演算法(binary classification)的品質.

ROC曲線是以TPR(正常資料被正確檢出的比例)Y, FPR(異常資料未被正確檢出的比例)X軸畫出來的曲線, Area Under ROC(AUC)值判讀如下:

  • 如果AUC = 1: 完美的模型, 能夠正確檢測出正常和異常的資料
  • 如果AUC = 0.5: 沒有比亂猜更好的模型, 即沒有檢測能力的模型
  • 如果AUC < 0.5: 比亂猜更差的模型

2.    Detection Rate at a Specific False Positive Count

Detection Rate at False Positive Count也是一個用來評估二元分類演算法品質的常用指標. 常異常資料未被正確檢測出代價高昂, 或是不能容許時, 會檢視異常資料未被正確檢測出的數量或比例固定在某個值(容許底限), 正常資料被正確檢出的比例

範例下載:

https://github.com/CraigIII/SoundAnomalyDetection.git

留言

這個網誌中的熱門文章

AI時代的網站與手機App建置與開發Part27 - ML.NET與物件偵測

AI時代的網站與手機App建置與開發Part24 - ML.NET與圖片異常偵測

AI時代的網站與手機App建置與開發Part28 - 使用YOLO模型進行物件偵測