{"id":12368,"date":"2021-06-18T09:00:30","date_gmt":"2021-06-18T13:00:30","guid":{"rendered":"https:\/\/blogs.mathworks.com\/pick\/?p=12368"},"modified":"2021-06-18T09:20:21","modified_gmt":"2021-06-18T13:20:21","slug":"industrial-machinery-anomaly-detection","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/pick\/2021\/06\/18\/industrial-machinery-anomaly-detection\/","title":{"rendered":"Industrial Machinery Anomaly Detection"},"content":{"rendered":"<div xmlns:mwsh=\"http:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <p><i>Rachel is the product manager for predictive maintenance at MathWorks.<\/i><\/p>\r\n   <p>Rachel's pick this week is <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/90752\">Industrial Machinery Anomaly Detection using an Autoencoder<\/a> which she submitted! Today's pick was featured in the <a href=\"https:\/\/www.mathworks.com\/videos\/predictive-maintenance-using-deep-learning-1622015420382.html\">Predictive Maintenance Using Deep Learning<\/a> talk at MATLAB EXPO 2021.\r\n   <\/p>\r\n   <p>How do you know if a machine is operating normally? That's the question this week's pick aims to answer, by using deep learning to detect anomalies in normal vibration data from an industrial machine. Anomaly detection has lots of uses, but it's particularly useful in <a href=\"https:\/\/www.mathworks.com\/discovery\/predictive-maintenance-matlab.html\">Predictive Maintenance<\/a>.\r\n   <\/p>\r\n   <p>This example uses deep learning in the form of a bi-directional LSTM-based autoencoder. That's a mouthful, but it's just training a network to reconstruct \"normal\" operating data. That way, when we feed the algorithm some data that looks different, the reconstruction error will indicate that there's a problem &#8211; maybe the machine needs maintenance. Autoencoders are a good approach to try when all you have for sure is \"normal\" data.\r\n   <\/p>\r\n   <p>The dataset has two parts: data from right <i>before<\/i> maintenance, and data from right <i>after<\/i> maintenance. We can logically assume the data right after maintenance is \"normal\" (that is, if we have a competent maintenance team!) We aren't so sure about the before data.\r\n   <\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/traindata-e1623952471240.png\"> <\/p>\r\n   <p>Here's two sample members of the dataset overlaid on top of each other.<\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/samplemembers.png\"> <\/p>\r\n   <p>Rather than training on raw signals, it often helps to extract features that can better differentiate between the before and after data. Use the <a href=\"https:\/\/www.mathworks.com\/help\/predmaint\/ref\/diagnosticfeaturedesigner-app.html\">Diagnostic Feature Designer<\/a> app to automatically extract and rank features from all the data at once. Then, the app can automatically create a function <tt>generateFeatures<\/tt> to redo all that work programmatically. Neat!\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">trainFeatures = generateFeatures(trainData);<\/pre><p>Here's that biLSTM autoencoder.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">featureDimension = 1;\r\n\r\n<span style=\"color: #228B22\">% Define biLSTM network layers<\/span>\r\nlayers = [ sequenceInputLayer(featureDimension, <span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'in'<\/span>)\r\n    bilstmLayer(16, <span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'bilstm1'<\/span>)\r\n    reluLayer(<span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'relu1'<\/span>)\r\n    bilstmLayer(32, <span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'bilstm2'<\/span>)\r\n    reluLayer(<span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'relu2'<\/span>)\r\n    bilstmLayer(16, <span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'bilstm3'<\/span>)\r\n    reluLayer(<span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'relu3'<\/span>)\r\n    fullyConnectedLayer(featureDimension, <span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'fc'<\/span>)\r\n    regressionLayer(<span style=\"color: #A020F0\">'Name'<\/span>, <span style=\"color: #A020F0\">'out'<\/span>) ];<\/pre><p>An autoencoder works something like this: train a network on normal data. If you then pass it normal data, it'll be able to reconstruct it really well. If you pass it something that doesn't look normal, it won't be able to reconstruct it, and you'll be able to see that in the reconstruction error.\r\n   <\/p>\r\n   <p>Train the network on the top four ranked features from each channel &#8211; from the normal (after maintenance) data only.<\/p>\r\n   <p>By picking the right threshold for reconstruction error, the algorithm identifies anomalies with pretty high accuracy. In this case we had some test data that we knew was anomalous, so we could test the algorithm accuracy explicitly. Pretty good!\r\n   <\/p>\r\n   <p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/anomalyresults2.png\"> <\/p>\r\n   <p>Try out this method on your own data and see what you think <a href=\"http:\/\/blogs.mathworks.com\/pick\/?p=12368#respond\">in the comments<\/a>.\r\n   <\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_2047ce981eb248a2bdec19c2e6b7ecb5() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='2047ce981eb248a2bdec19c2e6b7ecb5 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 2047ce981eb248a2bdec19c2e6b7ecb5';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Rachel Johnson';\r\n        copyright = 'Copyright 2021 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }   \r\n      \r\n-->\r\n<\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><br>\r\n      Published with MATLAB&reg; R2021b<br><\/p>\r\n<\/div>\r\n<!--\r\n2047ce981eb248a2bdec19c2e6b7ecb5 ##### SOURCE BEGIN #####\r\n%% Industrial Machinery Anomaly Detection\r\n% _Rachel is the product manager for predictive maintenance at MathWorks._\r\n%\r\n% Rachel's pick this week is\r\n% <http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/90752 Industrial\r\n% Machinery Anomaly Detection using an Autoencoder> which she developed!\r\n% Today's pick was featured in the\r\n% <https:\/\/www.mathworks.com\/videos\/predictive-maintenance-using-deep-learning-1622015420382.html\r\n% Predictive Maintenance Using Deep Learning> talk at MATLAB EXPO 2021.\r\n%\r\n% How do you know if a machine is operating normally? That's the question\r\n% this week's pick aims to answer, by using deep learning to detect\r\n% anomalies in normal vibration data from an industrial machine. Anomaly\r\n% detection has lots of uses, but it's particularly useful in\r\n% <https:\/\/www.mathworks.com\/discovery\/predictive-maintenance-matlab.html\r\n% Predictive Maintenance>.\r\n%\r\n% This example uses deep learning in the form of a bi-directional\r\n% LSTM-based autoencoder. That's a mouthful, but it's just training a\r\n% network to reconstruct \"normal\" operating data. That way, when we feed\r\n% the algorithm some data that looks different, the reconstruction error\r\n% will indicate that there's a problem \u2013 maybe the machine needs\r\n% maintenance. Autoencoders are a good approach to try when all you have\r\n% for sure is \"normal\" data.\r\n%\r\n% The dataset has two parts: data from right _before_ maintenance, and data\r\n% from right _after_ maintenance. We can logically assume the data right\r\n% after maintenance is \"normal\" (that is, if we have a competent\r\n% maintenance team!) We aren't so sure about the before data.\r\n%\r\n% <<traindata.png>>\r\n%\r\n% Here's two sample members of the dataset overlaid on top of each other.\r\n%\r\n% <<samplemembers.png>>\r\n%\r\n% Rather than training on raw signals, it often helps to extract features\r\n% that can better differentiate between the before and after data. Use the\r\n% <https:\/\/www.mathworks.com\/help\/predmaint\/ref\/diagnosticfeaturedesigner-app.html\r\n% Diagnostic Feature Designer> app to automatically extract and rank\r\n% features from all the data at once. Then, the app can automatically\r\n% create a function generateFeatures to redo all that work\r\n% programmatically. Neat!\r\n\r\ntrainFeatures = generateFeatures(trainData);\r\n%%\r\n% Here's that biLSTM autoencoder.\r\n\r\nfeatureDimension = 1;\r\n\r\n% Define biLSTM network layers\r\nlayers = [ sequenceInputLayer(featureDimension, 'Name', 'in')\r\n    bilstmLayer(16, 'Name', 'bilstm1')\r\n    reluLayer('Name', 'relu1')\r\n    bilstmLayer(32, 'Name', 'bilstm2')\r\n    reluLayer('Name', 'relu2')\r\n    bilstmLayer(16, 'Name', 'bilstm3')\r\n    reluLayer('Name', 'relu3')\r\n    fullyConnectedLayer(featureDimension, 'Name', 'fc')\r\n    regressionLayer('Name', 'out') ];\r\n%%\r\n% An autoencoder works something like this: train a network on normal data.\r\n% If you then pass it normal data, it'll be able to reconstruct it really\r\n% well. If you pass it something that doesn't look normal, it won't be able\r\n% to reconstruct it, and you'll be able to see that in the reconstruction\r\n% error.\r\n%\r\n% Train the network on the top four ranked features from each channel \u2013\r\n% from the normal (after maintenance) data only.\r\n%\r\n% By picking the right threshold for reconstruction error, the algorithm\r\n% identifies anomalies with pretty high accuracy. In this case we had some\r\n% test data that we knew was anomalous, so we could test the algorithm\r\n% accuracy explicitly. Pretty good!\r\n%\r\n% <<anomalyresults2.png>>\r\n%\r\n% Try out this method on your own data and see what you think\r\n% <http:\/\/blogs.mathworks.com\/pick\/?p=12368#respond in the comments>.\r\n%\r\n%\r\n##### SOURCE END ##### 2047ce981eb248a2bdec19c2e6b7ecb5\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/pick\/files\/samplemembers.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>\r\n   Rachel is the product manager for predictive maintenance at MathWorks.\r\n   Rachel's pick this week is Industrial Machinery Anomaly Detection using an Autoencoder which she submitted! Today's... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/pick\/2021\/06\/18\/industrial-machinery-anomaly-detection\/\">read more >><\/a><\/p>","protected":false},"author":36,"featured_media":12377,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/12368"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/users\/36"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/comments?post=12368"}],"version-history":[{"count":9,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/12368\/revisions"}],"predecessor-version":[{"id":12422,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/12368\/revisions\/12422"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media\/12377"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media?parent=12368"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/categories?post=12368"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/tags?post=12368"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}