3 軸振動データを使用した産業機械での異常検出
この例では、機械学習と深層学習を使用して振動データにおける異常を検出する方法を説明します。例では、産業機械の振動データを使用します。最初に、診断特徴デザイナー アプリを使用して、通常の動作に対応する生の測定値から特徴を抽出します。選択した特徴を使用して、異常検出用の 3 種類のモデル (1 クラス SVM、孤立森、LSTM オートエンコーダー) に学習させます。その後、学習済みの各モデルを使用して、機械が正常に動作しているかどうかを識別します。
データ セット
データ セットには、産業機械からの 3 軸振動測定値が含まれています。データは、定期保守の直前と直後の両方で収集されます。定期保守の後に収集されたデータは、機械の通常の動作状態を表していると見なされます。保守前のデータは、通常状態と異常状態のどちらを表す場合もあります。各軸のデータは別々の列に保存されています。データ セットを保存して解凍し、学習データを読み込みます。
url = 'https://ssd.mathworks.com/supportfiles/predmaint/anomalyDetection3axisVibration/v1/vibrationData.zip'; websave('vibrationData.zip',url); unzip('vibrationData.zip'); load("MachineData.mat") trainData
trainData=40×4 table
ch1 ch2 ch3 label
________________ ________________ ________________ ______
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
{70000×1 double} {70000×1 double} {70000×1 double} Before
⋮
データをより良く理解するために、保守前後のデータを可視化します。アンサンブルの 4 番目のメンバーの振動データをプロットします。2 つの状態のデータが異なって見える点に注意してください。
ensMember = 4; helperPlotVibrationData(trainData, ensMember)
診断特徴デザイナー アプリによる特徴の抽出
生のデータには相関やノイズが多いため、機械学習モデルの学習に生のデータを使用することは、あまり効率的ではありません。診断特徴デザイナーアプリでは、対話的にデータの調査と前処理を行い、時間ドメインと周波数ドメインの特徴を抽出したうえで特徴をランク付けして、どれが故障やその他の異常システムの診断に最も効果的か判定できます。次に関数をエクスポートして、選択した特徴をデータ セットからプログラムにより抽出できます。コマンド プロンプトで「diagnosticFeatureDesigner
」と入力して、"診断特徴デザイナー" を開きます。"診断特徴デザイナー" の使用方法のチュートリアルについては、予知保全アルゴリズムの状態インジケーターの設計を参照してください。
[新規セッション] ボタンをクリックし、trainData
をソースとして選択してから、label
を [状態変数] に設定します。変数 label
は、対応するデータについて機械の状態を特定します。
"診断特徴デザイナー" を使用して特徴について反復し、それらをランク付けできます。アプリによって、生成されたすべての特徴のヒストグラム ビューが作成され、ラベルごとの分布が可視化されます。たとえば、以下のヒストグラムは、ch1 から抽出した各種の特徴の分布を示しています。これらのヒストグラムは、ラベルグループの分離がわかりやすくなるよう、この例で使用するデータ セットよりもはるかに大規模なデータ セットから導出されたものです。使用するデータ セットは比較的小規模であるため、結果は異なります。
各チャネルにつき上位 4 つのランク付けされた特徴を使用します。
ch1: クレスト ファクター、尖度、RMS、標準偏差
ch2: 平均、RMS、歪度、標準偏差
ch3: クレスト ファクター、SINAD、SNR、THD
特徴を生成するための関数を診断特徴デザイナー アプリからエクスポートして、generateFeatures
の名前で保存します。この関数はコマンド ラインから、データ セット全体の各チャネルにつき上位 4 つの関連する特徴を抽出します。
trainFeatures = generateFeatures(trainData); head(trainFeatures)
label ch1_stats/Col1_CrestFactor ch1_stats/Col1_Kurtosis ch1_stats/Col1_RMS ch1_stats/Col1_Std ch2_stats/Col1_Mean ch2_stats/Col1_RMS ch2_stats/Col1_Skewness ch2_stats/Col1_Std ch3_stats/Col1_CrestFactor ch3_stats/Col1_SINAD ch3_stats/Col1_SNR ch3_stats/Col1_THD ______ __________________________ _______________________ __________________ __________________ ___________________ __________________ _______________________ __________________ __________________________ ____________________ __________________ __________________ Before 2.2811 1.8087 2.3074 2.3071 -0.032332 0.64962 4.523 0.64882 11.973 -15.945 -15.886 -2.732 Before 2.3276 1.8379 2.2613 2.261 -0.03331 0.59458 5.548 0.59365 10.284 -15.984 -15.927 -2.7507 Before 2.3276 1.8626 2.2613 2.2612 -0.012052 0.48248 4.3638 0.48233 8.9125 -15.858 -15.798 -2.7104 Before 2.8781 2.1986 1.8288 1.8285 -0.005049 0.34984 2.3324 0.34981 11.795 -16.191 -16.14 -3.0683 Before 2.8911 2.06 1.8205 1.8203 -0.0018988 0.27366 1.7661 0.27365 11.395 -15.947 -15.893 -3.1126 Before 2.8979 2.1204 1.8163 1.8162 -0.0044174 0.3674 2.8969 0.36737 11.685 -15.963 -15.908 -2.9761 Before 2.9494 1.92 1.7846 1.7844 -0.0067284 0.36262 4.1308 0.36256 12.396 -15.999 -15.942 -2.8281 Before 2.5106 1.6774 1.7513 1.7511 -0.0089548 0.32348 3.7691 0.32335 8.8808 -15.79 -15.732 -2.9532
学習用の完全なデータ セットの準備
ここまでに使用してきたデータ セットは、特徴の抽出と選択の過程を説明するために用いた、はるかに大規模なデータ セットの小さなサブセットに過ぎません。使用可能なすべてのデータでアルゴリズムに学習させると、最良のパフォーマンスがもたらされます。そのために、17,642 の信号からなるより大規模なデータ セットから前もって抽出しておいたものと同じ 12 個の特徴を読み込みます。
load("FeatureEntire.mat")
head(featureAll)
label ch1_stats/Col1_CrestFactor ch1_stats/Col1_Kurtosis ch1_stats/Col1_RMS ch1_stats/Col1_Std ch2_stats/Col1_Mean ch2_stats/Col1_RMS ch2_stats/Col1_Skewness ch2_stats/Col1_Std ch3_stats/Col1_CrestFactor ch3_stats/Col1_SINAD ch3_stats/Col1_SNR ch3_stats/Col1_THD ______ __________________________ _______________________ __________________ __________________ ___________________ __________________ _______________________ __________________ __________________________ ____________________ __________________ __________________ Before 2.3683 1.927 2.2225 2.2225 -0.015149 0.62512 4.2931 0.62495 5.6569 -5.4476 -4.9977 -4.4608 Before 2.402 1.9206 2.1807 2.1803 -0.018269 0.56773 3.9985 0.56744 8.7481 -12.532 -12.419 -3.2353 Before 2.4157 1.9523 2.1789 2.1788 -0.0063652 0.45646 2.8886 0.45642 8.3111 -12.977 -12.869 -2.9591 Before 2.4595 1.8205 2.14 2.1401 0.0017307 0.41418 2.0635 0.41418 7.2318 -13.566 -13.468 -2.7944 Before 2.2502 1.8609 2.3391 2.339 -0.0081829 0.3694 3.3498 0.36931 6.8134 -13.33 -13.225 -2.7182 Before 2.4211 2.2479 2.1286 2.1285 0.011139 0.36638 1.8602 0.36621 7.4712 -13.324 -13.226 -3.0313 Before 3.3111 4.0304 1.5896 1.5896 -0.0080759 0.47218 2.1132 0.47211 8.2412 -13.85 -13.758 -2.7822 Before 2.2655 2.0656 2.3233 2.3233 -0.0049447 0.37829 2.4936 0.37827 7.6947 -13.781 -13.683 -2.5601
cvpartition
を使用して、データを学習セットと、独立したテスト セットに分割します。補助関数 helperExtractLabeledData
を使用して、変数 featureTrain
内でラベル 'After
' に対応する特徴をすべて検索します。
rng(0) % set for reproducibility idx = cvpartition(featureAll.label, 'holdout', 0.1); featureTrain = featureAll(idx.training, :); featureTest = featureAll(idx.test, :);
それぞれのモデルでは、通常状態であると見なされる、保守後のデータのみで学習を行います。このデータのみを featureTrain
から抽出します。
trueAnomaliesTest = featureTest.label;
featureNormal = featureTrain(featureTrain.label=='After', :);
1 クラス SVM による異常の検出
サポート ベクター マシンは強力な分類器であり、ここでは通常状態のデータのみで学習するバリアントが使用されています。このモデルは、通常状態のデータから "かけ離れた" 異常の識別に効果的です。関数 fitcsvm
と通常状態のデータを使用して、1 クラス SVM モデルに学習させます。
mdlSVM = fitcsvm(featureNormal, 'label', 'Standardize', true, 'OutlierFraction', 0);
通常状態と異常状態の両方のデータを含むテスト データを使用して、学習済みの SVM モデルを検証します。
featureTestNoLabels = featureTest(:, 2:end); [~,scoreSVM] = predict(mdlSVM,featureTestNoLabels); isanomalySVM = scoreSVM<0; predSVM = categorical(isanomalySVM, [1, 0], ["Anomaly", "Normal"]); trueAnomaliesTest = renamecats(trueAnomaliesTest,["After","Before"], ["Normal","Anomaly"]); figure; confusionchart(trueAnomaliesTest, predSVM, Title="Anomaly Detection with One-class SVM", Normalization="row-normalized");
混同行列から、1 クラス SVM がうまく機能していることがわかります。異常状態のサンプルの 0.3% のみが通常として誤分類され、通常状態のデータの約 0.9% が異常として誤分類されています。
孤立森による異常の検出
孤立森の決定木では、各観測を 1 枚の葉に分離します。サンプルがその葉に至るためにいくつの判定を通過するかは、それを他から分離するのがどの程度困難であったかの尺度です。特定サンプルの木の平均深度は異常のスコアとして使用され、iforest
によって返されます。
通常状態のデータのみで孤立森モデルに学習させます。
[mdlIF,~,scoreTrainIF] = iforest(featureNormal{:,2:13},'ContaminationFraction',0.09);
テスト データを使用して、学習済みの孤立森モデルを検証します。混同チャートを使用して、このモデルのパフォーマンスを可視化します。
[isanomalyIF,scoreTestIF] = isanomaly(mdlIF,featureTestNoLabels.Variables); predIF = categorical(isanomalyIF, [1, 0], ["Anomaly", "Normal"]); figure; confusionchart(trueAnomaliesTest,predIF,Title="Anomaly Detection with Isolation Forest",Normalization="row-normalized");
このデータでは、孤立森は 1 クラス SVM ほどうまく機能しません。機能が低下する理由は、学習データには通常状態のデータのみが含まれており、一方でテスト データには約 30% の異常状態のデータが含まれている点にあります。したがって、学習データとテスト データの両方において、通常状態のデータに対する異常状態のデータの割合が同程度である場合には、孤立森モデルの方が適切な選択となります。
LSTM オートエンコーダー ネットワークによる異常の検出
オートエンコーダーはニューラル ネットワークの一種で、ラベルなしのデータの圧縮表現を学習します。LSTM オートエンコーダーはこのネットワークから派生したもので、シーケンス データの圧縮表現を学習できます。ここでは、通常状態のデータのみを使って LSTM オートエンコーダーに学習させ、この学習済みのネットワークを使用して、通常状態には見えない信号を特定します。
まず、保守後のデータから特徴を抽出します。
featuresAfter = helperExtractLabeledData(featureTrain, ... "After");
LSTM オートエンコーダー ネットワークを構成し、学習オプションを設定します。
featureDimension = 1; % Define biLSTM network layers layers = [ sequenceInputLayer(featureDimension) bilstmLayer(16) reluLayer bilstmLayer(32) reluLayer bilstmLayer(16) reluLayer fullyConnectedLayer(featureDimension)]; % Set Training Options options = trainingOptions('adam', ... 'Plots', 'training-progress', ... 'Metrics', 'rmse', ... 'MiniBatchSize', 500,... 'MaxEpochs',200);
学習オプション パラメーター MaxEpochs
は 200 に設定されます。検証の精度を高めるには、このパラメーターをより大きい数に設定することができます。ただし、ネットワークが過適合になる可能性があります。
trainnet
を使用してモデルを学習させ、損失関数として平均二乗誤差 (mse) を指定します。
net = trainnet(featuresAfter, featuresAfter, layers, "mse", options);
Iteration Epoch TimeElapsed LearnRate TrainingLoss TrainingRMSE _________ _____ ___________ _________ ____________ ____________ 1 1 00:00:09 0.001 33.771 5.8113 50 3 00:00:15 0.001 29.543 5.4353 100 5 00:00:19 0.001 15.904 3.988 150 8 00:00:24 0.001 18.274 4.2748 200 10 00:00:29 0.001 12.052 3.4716 250 13 00:00:33 0.001 15.794 3.9742 300 15 00:00:38 0.001 10.051 3.1703 350 18 00:00:42 0.001 13.84 3.7202 400 20 00:00:47 0.001 8.359 2.8912 450 23 00:00:51 0.001 12.185 3.4907 500 25 00:00:55 0.001 7.1721 2.6781 550 28 00:01:00 0.001 11.018 3.3194 600 30 00:01:04 0.001 6.2384 2.4977 650 33 00:01:08 0.001 10.009 3.1637 700 35 00:01:12 0.001 5.3576 2.3146 750 38 00:01:16 0.001 8.8568 2.976 800 40 00:01:20 0.001 4.5712 2.138 850 43 00:01:24 0.001 8.0863 2.8436 900 45 00:01:28 0.001 4.0192 2.0048 950 48 00:01:32 0.001 7.456 2.7306 1000 50 00:01:36 0.001 3.6334 1.9061 1050 53 00:01:41 0.001 6.9985 2.6455 1100 55 00:01:45 0.001 3.332 1.8254 1150 58 00:01:49 0.001 6.5709 2.5634 1200 60 00:01:53 0.001 3.0456 1.7452 1250 63 00:01:57 0.001 6.2219 2.4944 1300 65 00:02:00 0.001 2.8124 1.677 1350 68 00:02:04 0.001 5.868 2.4224 1400 70 00:02:08 0.001 2.4919 1.5786 1450 73 00:02:12 0.001 5.3488 2.3127 1500 75 00:02:16 0.001 2.161 1.47 1550 78 00:02:20 0.001 4.9866 2.2331 1600 80 00:02:24 0.001 1.9088 1.3816 1650 83 00:02:28 0.001 4.6791 2.1631 1700 85 00:02:32 0.001 1.7001 1.3039 1750 88 00:02:36 0.001 4.4113 2.1003 1800 90 00:02:41 0.001 1.5254 1.2351 1850 93 00:02:45 0.001 4.1853 2.0458 1900 95 00:02:49 0.001 1.3738 1.1721 1950 98 00:02:53 0.001 3.9576 1.9894 2000 100 00:02:57 0.001 1.2387 1.113 2050 103 00:03:01 0.001 3.7698 1.9416 2100 105 00:03:05 0.001 1.123 1.0597 2150 108 00:03:09 0.001 3.6016 1.8978 2200 110 00:03:13 0.001 1.0263 1.0131 2250 113 00:03:17 0.001 3.4534 1.8583 2300 115 00:03:21 0.001 0.94179 0.97046 2350 118 00:03:25 0.001 3.3239 1.8232 2400 120 00:03:29 0.001 0.87847 0.93727 2450 123 00:03:34 0.001 3.2066 1.7907 2500 125 00:03:38 0.001 0.80876 0.89931 2550 128 00:03:42 0.001 3.0997 1.7606 2600 130 00:03:46 0.001 0.74998 0.86601 2650 133 00:03:50 0.001 3.0022 1.7327 2700 135 00:03:54 0.001 0.70011 0.83672 2750 138 00:03:58 0.001 2.9062 1.7047 2800 140 00:04:02 0.001 0.6546 0.80908 2850 143 00:04:05 0.001 2.8237 1.6804 2900 145 00:04:09 0.001 0.6157 0.78466 2950 148 00:04:13 0.001 2.7403 1.6554 3000 150 00:04:18 0.001 0.5843 0.7644 3050 153 00:04:22 0.001 2.665 1.6325 3100 155 00:04:25 0.001 0.54377 0.73741 3150 158 00:04:29 0.001 2.5921 1.61 3200 160 00:04:33 0.001 0.51321 0.71639 3250 163 00:04:37 0.001 2.5235 1.5886 3300 165 00:04:41 0.001 0.49071 0.70051 3350 168 00:04:45 0.001 2.4591 1.5682 3400 170 00:04:49 0.001 0.46161 0.67942 3450 173 00:04:53 0.001 2.3967 1.5481 3500 175 00:04:57 0.001 0.43363 0.65851 3550 178 00:05:01 0.001 2.3392 1.5295 3600 180 00:05:05 0.001 0.41236 0.64215 3650 183 00:05:09 0.001 2.2851 1.5116 3700 185 00:05:13 0.001 0.39331 0.62715 3750 188 00:05:17 0.001 2.234 1.4947 3800 190 00:05:21 0.001 0.37487 0.61227 3850 193 00:05:24 0.001 2.1853 1.4783 3900 195 00:05:28 0.001 0.35768 0.59806 3950 198 00:05:32 0.001 2.1387 1.4624 4000 200 00:05:36 0.001 0.34181 0.58465 Training stopped: Max epochs completed
検証データでのモデル動作と誤差の可視化
異常状態と通常状態からそれぞれ 1 つのサンプルを抽出し、可視化します。以下のプロットでは、12 個の特徴 (X 軸上に表示) それぞれについて、オートエンコーダー モデルの再構成誤差を示しています。このプロットでは、再構成された特徴値は "Decoded" (復号化された) 信号と呼ばれています。このサンプルでは、特徴 10、11、12 が異常入力に対してうまく再構成されず、したがって、誤差が大きくなります。再構成誤差を使用して異常を特定できます。
testNormal = featureTest(1200, 2:end).Variables'; testAnomaly = featureTest(200, 2:end).Variables'; % Predict decoded signal for both decodedNormal = predict(net,testNormal); decodedAnomaly = predict(net,testAnomaly); % Visualize helperVisualizeModelBehavior(testNormal, testAnomaly, decodedNormal, decodedAnomaly)
すべての通常状態のデータと異常状態のデータの特徴を抽出します。学習済みオートエンコーダー モデルを使用して、保守前と保守後の両方のデータについて、選択した 12 個の特徴を予測します。以下のプロットは、12 個の特徴の平方根平均二乗再構成誤差を示したものです。図には、異常状態のデータの再構成誤差が通常状態のデータよりはるかに高いことが示されています。オートエンコーダーは通常状態のデータで学習したため、類似する信号をよりうまく再構成するという結果は予想どおりです。
% Extract data Before maintenance XTestBefore = helperExtractLabeledData(featureTest, "Before"); % Predict output before maintenance and calculate error yHatBefore = minibatchpredict(net, XTestBefore, 'UniformOutput', false); errorBefore = helperCalculateError(XTestBefore, yHatBefore); % Extract data after maintenance XTestAfter = helperExtractLabeledData(featureTest, "After"); % Predict output after maintenance and calculate error yHatAfter = minibatchpredict(net, XTestAfter, 'UniformOutput', false); errorAfter = helperCalculateError(XTestAfter, yHatAfter); helperVisualizeError(errorBefore, errorAfter);
異常の特定
検証データ全体について、再構成誤差を計算します。
XTestAll = helperExtractLabeledData(featureTest, "All"); yHatAll = minibatchpredict(net, XTestAll, 'UniformOutput', false); errorAll = helperCalculateError(XTestAll, yHatAll);
再構成誤差がすべての観測の平均の 0.5 倍となっている点を異常と定義します。このしきい値は前回の実験を通して決定されたものであり、必要に応じて変更することができます。
thresh = 0.5; anomalies = errorAll > thresh*mean(errorAll); helperVisualizeAnomalies(anomalies, errorAll, featureTest);
この例では、3 種類のモデルを使用して異常を検出しています。テスト データの異常検出は、1 クラス SVM が 99.7% と最も高いパフォーマンスを示し、他の 2 つのモデルは 93% 程度の精度でした。モデルの相対的なパフォーマンスは、別の特徴セットを選択した場合や、各モデルに別のハイパーパラメーターを使用した場合に変化する可能性があります。診断特徴デザイナー MATLAB アプリを使用して、さらに特徴選択を試してみましょう。
サポート関数
function E = helperCalculateError(X, Y) % HELPERCALCULATEERROR calculates the rms error value between the % inputs X, Y E = zeros(length(X),1); for i = 1:length(X) E(i,:) = sqrt(sum((Y{i} - X{i}).^2)); end end function helperVisualizeError(errorBefore, errorAfter) % HELPERVISUALIZEERROR creates a plot to visualize the errors on detecting % before and after conditions figure("Color", "W") tiledlayout("flow") nexttile plot(1:length(errorBefore), errorBefore, 'LineWidth',1.5), grid on title(["Before Maintenance", ... sprintf("Mean Error: %.2f\n", mean(errorBefore))]) xlabel("Observations") ylabel("Reconstruction Error") ylim([0 15]) nexttile plot(1:length(errorAfter), errorAfter, 'LineWidth',1.5), grid on, title(["After Maintenance", ... sprintf("Mean Error: %.2f\n", mean(errorAfter))]) xlabel("Observations") ylabel("Reconstruction Error") ylim([0 15]) end function helperVisualizeAnomalies(anomalies, errorAll, featureTest) % HELPERVISUALIZEANOMALIES creates a plot of the detected anomalies anomalyIdx = find(anomalies); anomalyErr = errorAll(anomalies); predAE = categorical(anomalies, [1, 0], ["Anomaly", "Normal"]); trueAE = renamecats(featureTest.label,["Before","After"],["Anomaly","Normal"]); acc = numel(find(trueAE == predAE))/numel(predAE)*100; figure; t = tiledlayout("flow"); title(t, "Test Accuracy: " + round(mean(acc),2) + "%"); nexttile hold on plot(errorAll) plot(anomalyIdx, anomalyErr, 'x') hold off ylabel("Reconstruction Error") xlabel("Observation") legend("Error", "Candidate Anomaly") nexttile confusionchart(trueAE,predAE) end function helperVisualizeModelBehavior(normalData, abnormalData, decodedNorm, decodedAbNorm) %HELPERVISUALIZEMODELBEHAVIOR Visualize model behavior on sample validation data figure("Color", "W") tiledlayout("flow") nexttile() hold on colororder('default') yyaxis left plot(normalData') plot(decodedNorm',":","LineWidth",1.5) hold off title("Normal Input") grid on ylabel("Feature Value") yyaxis right stem(abs(normalData' - decodedNorm')) ylim([0 2]) ylabel("Error") legend(["Input", "Decoded","Error"],"Location","southwest") nexttile() hold on yyaxis left plot(abnormalData) plot(decodedAbNorm',":","LineWidth",1.5) hold off title("Abnormal Input") grid on ylabel("Feature Value") yyaxis right stem(abs(abnormalData' - decodedAbNorm')) ylim([0 2]) ylabel("Error") legend(["Input", "Decoded","Error"],"Location","southwest") end function X = helperExtractLabeledData(featureTable, label) %HELPEREXTRACTLABELEDDATA Extract data from before or after operating %conditions and re-format to support input to autoencoder network % Select data with label After if label == "All" Xtemp = featureTable(:, 2:end).Variables; else tF = featureTable.label == label; Xtemp = featureTable(tF, 2:end).Variables; end % Arrange data into cells X = cell(length(Xtemp),1); for i = 1:length(Xtemp) X{i,:} = Xtemp(i,:)'; end end
参考
cvpartition
| fitcsvm
| iforest
| 診断特徴デザイナー