Этот пример показывает, как сгенерировать синтетические сигналы насоса с помощью условной генеративной состязательной сети.
Генеративные состязательные сети (GANs) могут использоваться, чтобы получить синтетические данные, которые напоминают реальный вход данных в сети. GAN применяются, когда симуляции являются вычислительно дорогими или эксперименты являются дорогостоящими. Условные GAN (CGAN) могут использовать метки данных в процессе обучения для генерации данных, относящихся к конкретным категориям.
Этот пример обрабатывает моделируемые сигналы, полученные моделью Simulink™ насоса, как «действительные» данные, которые играют роль набора обучающих данных для CGAN. CGAN использует 1-D сверточных сетей и обучается с помощью пользовательского цикла обучения и глубокого обучения массива. Кроме сложения, этот пример использует анализ основных компонентов (PCA), чтобы визуально сравнить характеристики сгенерированных и реальных сигналов.
CGAN состоят из двух сетей, которые обучаются вместе как противники:
Сеть генератора - учитывая метку и случайный массив как вход, эта сеть генерирует данные с той же структурой, что и наблюдения обучающих данных, соответствующие той же метке. Цель генератора состоит в том, чтобы сгенерировать маркированные данные, которые дискриминатор классифицирует как «реальные».
Сеть дискриминатора - Учитывая пакеты маркированных данных, содержащих наблюдения как от обучающих данных, так и от сгенерированных данных от генератора, эта сеть пытается классифицировать наблюдения как «реальные» или «сгенерированные». Цель дискриминатора состоит в том, чтобы не быть «обманутым» генератором, когда данные пакеты как реальных, так и сгенерированных маркированных данных.
В идеале эти стратегии приводят к генератору, который генерирует убедительно реалистичные данные, соответствующие входным меткам, и дискриминатору, который выучил сильные функции, характерные для обучающих данных для каждой метки.
Моделируемые данные генерируются моделью Simulink насоса, представленной в примере Мультиклассовое Обнаружение Неисправностей с Использованием Смоделированных Данных (Predictive Maintenance Toolbox). Модель Simulink сконфигурирована, чтобы смоделировать три типа отказов: утечки в гидроцилиндре, заблокированные входные отверстия и увеличенное трение подшипника. Набор данных содержит 1575 выходных сигналов потока насоса, из которых 760 являются исправными сигналами, а 815 имеют один отказ, комбинации двух отказов или комбинации трех отказов. Каждый сигнал имеет 1201 выборок сигнала со скоростью дискретизации 1000 Гц.
Загрузите и разархивируйте данные во временной директории, местоположение которого задано MATLAB ® tempdir
команда. Если у вас есть данные, отличные от заданных tempdir
измените имя директории в следующем коде.
% Download the data dataURL = 'https://ssd.mathworks.com/supportfiles/SPT/data/PumpSignalGAN.zip'; saveFolder = fullfile(tempdir,'PumpSignalGAN'); zipFile = fullfile(tempdir,'PumpSignalGAN.zip'); if ~exist(saveFolder,'dir') websave(zipFile,dataURL); end % Unzip the data unzip(zipFile,saveFolder)
zip- файла содержит набор обучающих данных и предварительно обученный CGAN:
simulatedDataset
- Имитированные сигналы и соответствующие им категориальные метки
GANModel
- Генератор и дискриминатор, обученный на моделируемых данных
Загрузите обучающий набор обучающих данных и стандартизируйте сигналы, чтобы иметь нулевое среднее и единичное отклонение.
load(fullfile(saveFolder,'simulatedDataset.mat')) % load data set meanFlow = mean(flow,2); flowNormalized = flow-meanFlow; stdFlow = std(flowNormalized(:)); flowNormalized = flowNormalized/stdFlow;
Исправные сигналы помечаются как 1, а неисправные сигналы - как 2.
Определите следующую сеть с двумя входами, которая генерирует сигналы потока, данные массивы случайных значений 1 на 1 на 100 и соответствующих меток.
Сеть:
Проекты и изменяют массивы шума 1 на 1 на 100 к 4 на 1 1 024 массивами таможенным слоем.
Преобразовывает категорические метки во вложение векторов и изменяет их к массивы 4 на 1 на 1.
Конкатенирует результаты из двух входов по размерности канала. Выходные выходы: массив 4 на 1 на 1025.
Сверхдискретизировал получающиеся массивы к 1201 массивами 1 на 1, используя серию перемещенных слоев скручивания 1-D со слоев ReLU и нормализацией партии.
Чтобы проецировать и изменить форму входного сигнала шума, используйте пользовательский слой projectAndReshapeLayer
, присоединенный к этому примеру как вспомогательный файл. The projectAndReshapeLayer
объект увеличивает масштаб входа с помощью полносвязного слоя и изменяет форму выхода на заданный размер.
Чтобы ввести метки в сеть, используйте imageInputLayer
и задайте размер 1 на 1. Для встраивания и изменения формы входов меток используйте пользовательский слой embedAndReshapeLayer
, присоединенный к этому примеру как вспомогательный файл. The embedAndReshapeLayer
объект преобразует категориальную метку в одноканальный массив заданного размера с помощью встраивания и полносвязной операции. Для категориальных входов используйте размерность вложения 100.
% Generator Network numFilters = 64; numLatentInputs = 100; projectionSize = [4 1 1024]; numClasses = 2; embeddingDimension = 100; layersGenerator = [ imageInputLayer([1 1 numLatentInputs],'Normalization','none','Name','in') projectAndReshapeLayer(projectionSize,numLatentInputs,'proj'); concatenationLayer(3,2,'Name','cat'); transposedConv2dLayer([5 1],8*numFilters,'Name','tconv1') batchNormalizationLayer('Name','bn1','Epsilon',5e-5) reluLayer('Name','relu1') transposedConv2dLayer([10 1],4*numFilters,'Stride',4,'Cropping',[1 0],'Name','tconv2') batchNormalizationLayer('Name','bn2','Epsilon',5e-5) reluLayer('Name','relu2') transposedConv2dLayer([12 1],2*numFilters,'Stride',4,'Cropping',[1 0],'Name','tconv3') batchNormalizationLayer('Name','bn3','Epsilon',5e-5) reluLayer('Name','relu3') transposedConv2dLayer([5 1],numFilters,'Stride',4,'Cropping',[1 0],'Name','tconv4') batchNormalizationLayer('Name','bn4','Epsilon',5e-5) reluLayer('Name','relu4') transposedConv2dLayer([7 1],1,'Stride',2,'Cropping',[1 0],'Name','tconv5') ]; lgraphGenerator = layerGraph(layersGenerator); layers = [ imageInputLayer([1 1],'Name','labels','Normalization','none') embedAndReshapeLayer(projectionSize(1:2),embeddingDimension,numClasses,'emb')]; lgraphGenerator = addLayers(lgraphGenerator,layers); lgraphGenerator = connectLayers(lgraphGenerator,'emb','cat/in2');
Постройте график структуры сети для генератора.
plot(lgraphGenerator)
Чтобы обучить сеть с помощью пользовательского цикла обучения и включить автоматическую дифференциацию, преобразуйте график слоев в dlnetwork
объект.
dlnetGenerator = dlnetwork(lgraphGenerator);
Задайте следующую сеть с двумя входами, которая классифицирует реальные и сгенерированные сигналы 1201 на 1 с учетом набора сигналов и соответствующих им меток.
Эта сеть:
Занимает 1201 сигналами 1 на 1, как введено.
Преобразовывает категорические метки во вложение векторов и изменяет их к 1201 массивами 1 на 1.
Конкатенирует результаты из двух входов по размерности канала. Выходные выходы: массив 1201 на 1 на 1025.
Субдискретизирует получающиеся массивы к скалярным счетам предсказания, которые являются массивами 1 на 1 на 1, используя серию 1-D слоев скручивания с прохудившимися слоями ReLU со шкалой 0,2.
% Discriminator Network scale = 0.2; inputSize = [1201 1 1]; layersDiscriminator = [ imageInputLayer(inputSize,'Normalization','none','Name','in') concatenationLayer(3,2,'Name','cat') convolution2dLayer([17 1],8*numFilters,'Stride',2,'Padding',[1 0],'Name','conv1') leakyReluLayer(scale,'Name','lrelu1') convolution2dLayer([16 1],4*numFilters,'Stride',4,'Padding',[1 0],'Name','conv2') leakyReluLayer(scale,'Name','lrelu2') convolution2dLayer([16 1],2*numFilters,'Stride',4,'Padding',[1 0],'Name','conv3') leakyReluLayer(scale,'Name','lrelu3') convolution2dLayer([8 1],numFilters,'Stride',4,'Padding',[1 0],'Name','conv4') leakyReluLayer(scale,'Name','lrelu4') convolution2dLayer([8 1],1,'Name','conv5')]; lgraphDiscriminator = layerGraph(layersDiscriminator); layers = [ imageInputLayer([1 1],'Name','labels','Normalization','none') embedAndReshapeLayer(inputSize,embeddingDimension,numClasses,'emb')]; lgraphDiscriminator = addLayers(lgraphDiscriminator,layers); lgraphDiscriminator = connectLayers(lgraphDiscriminator,'emb','cat/in2');
Постройте график структуры сети для дискриминатора.
plot(lgraphDiscriminator)
Чтобы обучить сеть с помощью пользовательского цикла обучения и включить автоматическую дифференциацию, преобразуйте график слоев в dlnetwork
объект.
dlnetDiscriminator = dlnetwork(lgraphDiscriminator);
Обучите модель CGAN с помощью пользовательского цикла обучения. Закольцовывайте обучающие данные и обновляйте сетевые параметры при каждой итерации. Чтобы контролировать процесс обучения, отобразите сгенерированные исправные и неисправные сигналы с помощью двух фиксированных массивов случайных значений для ввода в генератор, а также график счетов двух сетей.
Для каждой эпохи перетасуйте обучающие данные и закольцовывайте мини-пакеты данных.
Для каждого мини-пакета:
Сгенерируйте dlarray
объект, содержащий массив случайных значений для сети генератора.
Для обучения графический процессор преобразуйте данные в gpuArray
(Parallel Computing Toolbox) объект.
Оцените градиенты модели с помощью dlfeval
и вспомогательную функцию modelGradients
.
Обновляйте параметры сети с помощью adamupdate
функция.
Функция помощника modelGradients
принимает за вход сети генератора и дискриминатора, мини-пакет входных данных и массив случайных значений и возвращает градиенты потерь относительно настраиваемых параметров в сетях и счетов двух сетей. Функция потерь определяется в вспомогательной функции ganLoss
.
Установите параметры обучения.
params.numLatentInputs = numLatentInputs;
params.numClasses = numClasses;
params.sizeData = [inputSize length(labels)];
params.numEpochs = 1000;
params.miniBatchSize = 256;
% Specify the options for Adam optimizer
params.learnRate = 0.0002;
params.gradientDecayFactor = 0.5;
params.squaredGradientDecayFactor = 0.999;
Установите окружение выполнения, чтобы запустить CGAN на центральном процессоре. Чтобы запустить CGAN на графическом процессоре, установите executionEnvironment
в "gpu
"или выберите параметр" Выполнить на графическом процессоре "в Live Editor. Для использования графический процессор требуется Parallel Computing Toolbox™. Информацию о том, какие графические процессоры поддерживаются, см. в разделе Поддержка GPU Release (Parallel Computing Toolbox).
executionEnvironment = "cpu";
params.executionEnvironment = executionEnvironment;
Пропустите процесс обучения, загрузив предварительно обученную сеть. Чтобы обучить сеть на вашем компьютере, установите trainNow
на true
или выберите «Train CGAN now» опции в Live Editor.
trainNow = false; if trainNow % Train the CGAN [dlnetGenerator, dlnetDiscriminator] = trainGAN ( dlnetGenerator,... dlnetDiscriminator, flowNormalized, метки, params);%#ok else % Use pretrained CGAN (default) load (полный файл (tempdir,'PumpSignalGAN','GANModel.mat')) % load data set end
Обучающий график ниже показывает пример счетам сетей генератора и дискриминатора. Дополнительные сведения о том, как интерпретировать счета сети, см. в разделах Мониторинг процесса обучения GAN и Идентификация распространенных типах отказа. В этом примере счетов как генератора, так и дискриминатора сходятся близко к 0,5, указывая, что производительность обучения хороша.
Создайте dlarray
объект, содержащий партию 2 000 массивов случайных значений 1 на 1 на 100, чтобы ввести в сеть генератора. Сбросьте генератор случайных чисел для воспроизводимых результатов.
rng default numTests = 2000; ZNew = randn(1,1,numLatentInputs,numTests,'single'); dlZNew = dlarray(ZNew,'SSCB');
Укажите, что первые 1000 случайных массивов исправны, а остальные неисправны.
TNew = ones(1,1,1,numTests,'single'); TNew(1,1,1,numTests/2+1:end) = single(2); dlTNew = dlarray(TNew,'SSCB');
Чтобы сгенерировать сигналы с помощью графический процессор, преобразуйте данные в gpuArray
объекты.
if executionEnvironment == "gpu" dlZNew = gpuArray(dlZNew); dlTNew = gpuArray(dlTNew); end
Используйте predict
функция на генераторе с партией массивов случайных значений 1 на 1 на 100 и меток, чтобы сгенерировать синтетические сигналы и вернуться шаг стандартизации, который Вы выполнили на оригинальных сигналах потока.
dlXGeneratedNew = predict(dlnetGenerator,dlZNew,dlTNew)*stdFlow+meanFlow;
В отличие от изображений и аудиосигналов, общие сигналы имеют характеристики, которые затрудняют их разнесение восприятия человеком. Чтобы сравнить реальные и сгенерированные сигналы или исправные и неисправные сигналы, можно применить анализ основных компонентов (PCA) к статистическим функциям реальных сигналов, а затем спроектировать функции сгенерированных сигналов к тому же подпространству PCA.
Объедините исходный действительный сигнал и сгенерированные сигналы в одну матрицу данных. Используйте функцию helper extractFeature
для извлечения функции, включающей общую статистику сигналов, таких как среднее и отклонение, а также спектральные характеристики.
idxGenerated = 1:numTests; idxReal = numTests+1:numTests+size(flow,2); XGeneratedNew = squeeze(extractdata(gather(dlXGeneratedNew))); x = [XGeneratedNew single(flow)]; features = zeros(size(x,2),14,'like',x); for ii = 1:size(x,2) features(ii,:) = extractFeatures(x(:,ii)); end
Каждая строка features
соответствует функциям одного сигнала.
Измените метки для сгенерированных здоровых и неисправных сигналов, а также реальных здоровых и неисправных сигналов.
L = [squeeze(TNew)+2;labels.'];
Теперь у меток есть следующие определения:
1 - Сгенерированные исправные сигналы
2 - Сгенерированные неисправные сигналы
3 - Реальные исправные сигналы
4 - Реальные неисправные сигналы
Выполните PCA на функциях реальных сигналов и проецируйте функции сгенерированных сигналов на тот же подпространство PCA. W
- коэффициент и Y
- счет.
% PCA via svd
featuresReal = features(idxReal,:);
mu = mean(featuresReal,1);
[~,S,W] = svd(featuresReal-mu);
S = diag(S);
Y = (features-mu)*W;
Из сингулярного вектора S
первые три сингулярных значений составляют 99% энергии в S
. Можно визуализировать функции сигнала, используя первые три основных компонента.
sum(S(1:3))/sum(S)
ans = single
0.9923
Постройте график функций всех сигналов с помощью первых трех основных компонентов. В подпространстве PCA распределение сгенерированных сигналов подобно распределению действительных сигналов.
idxHealthyR = L==1; idxFaultR = L==2; idxHealthyG = L==3; idxFaultG = L==4; pp = Y(:,1:3); figure scatter3(pp(idxHealthyR,1),pp(idxHealthyR,2),pp(idxHealthyR,3),'o') xlabel('1st Principal Component') ylabel('2nd Principal Component') zlabel('3rd Principal Component') hold on scatter3(pp(idxFaultR,1),pp(idxFaultR,2),pp(idxFaultR,3),'d') scatter3(pp(idxHealthyG,1),pp(idxHealthyG,2),pp(idxHealthyG,3),'s') scatter3(pp(idxFaultG,1),pp(idxFaultG,2),pp(idxFaultG,3),'+') view(-10,20) legend('Real healthy','Real faulty','Generated healthy','Generated faulty', ... 'Location','Best') hold off
Чтобы лучше захватить различие между реальными сигналами и сгенерированными сигналами, постройте график подпространства с помощью первых двух главных компонентов.
view(2)
Исправные и неисправные сигналы лежат в одной и той же области подпространства PCA независимо от того, являются ли они реальными или сгенерированными, что демонстрирует, что сгенерированные сигналы имеют признаки, сходные с функциями реальных сигналов.
Чтобы дополнительно проиллюстрировать эффективность CGAN, обучите классификатор SVM на основе сгенерированных сигналов и затем предсказайте, является ли реальный сигнал исправным или неисправным.
Установите сгенерированные сигналы в качестве набора обучающих данных, а реальные - в качестве набора тестовых данных. Измените числовые метки на векторы символов.
LABELS = {'Healthy','Faulty'}; strL = LABELS([squeeze(TNew);labels.']).'; dataTrain = features(idxGenerated,:); dataTest = features(idxReal,:); labelTrain = strL(idxGenerated); labelTest = strL(idxReal); predictors = dataTrain; response = labelTrain; cvp = cvpartition(size(predictors,1),'KFold',5);
Обучите классификатор SVM с помощью сгенерированных сигналов.
SVMClassifier = fitcsvm( ... predictors(cvp.training(1),:), ... response(cvp.training(1)),'KernelFunction','polynomial', ... 'PolynomialOrder',2, ... 'KernelScale','auto', ... 'BoxConstraint',1, ... 'ClassNames',LABELS, ... 'Standardize',true);
Используйте обученный классификатор, чтобы получить предсказанные метки для действительных сигналов. Классификатор достигает точности предсказания выше 90%.
actualValue = labelTest; predictedValue = predict(SVMClassifier,dataTest); predictAccuracy = mean(cellfun(@strcmp,actualValue,predictedValue))
predictAccuracy = 0.9460
Используйте матрицу неточностей, чтобы просмотреть подробную информацию о эффективности предсказания для каждой категории. Матрица неточностей показывает, что в каждой категории классификатор, обученный на основе сгенерированных сигналов, достигает высокой степени точности.
figure confusionchart(actualValue,predictedValue)
Сравните спектральные характеристики действительных и сгенерированных сигналов. Из-за недетерминированного поведения обучения графический процессор, если вы сами обучаете модель CGAN, ваши результаты могут отличаться от результатов в этом примере.
Скорость мотора насоса составляет 950 об/мин, или 15,833 Гц, и, поскольку насос имеет три цилиндра, ожидается, что поток будет иметь фундаментальную частоту в 3 раза 15,833 Гц, или 47,5 Гц, и гармоники при множителях 47,5 Гц. Постройте график спектра для одного случая реальных и сгенерированных здоровых сигналов. Из графика сгенерированный сигнал исправности имеет относительно высокие значения степени 47,5 Гц и 2 раза 47,5 Гц, что в точности совпадает с реальным сигналом работоспособности.
Fs = 1000; pspectrum([x(:,1) x(:,2006)],Fs) set(gca,'XScale','log') legend('Generated healthy','Real healthy')
Если отказы существуют, резонансы будут происходить при скорости двигателя насоса, 15,833 Гц, и его гармонике. Постройте график спектров для одного случая действительных и сгенерированных неисправных сигналов. Сгенерированный сигнал имеет относительно высокие значения степени около 15,833 Гц и его гармоники, что подобно реальному дефектному сигналу.
pspectrum([x(:,1011) x(:,2100)],Fs) set(gca,'XScale','log') legend('Generated faulty','Real faulty')
Постройте спектры для другого случая реальных и сгенерированных неисправных сигналов. Спектральные характеристики сгенерированных дефектных сигналов не очень хорошо совпадают с теоретическим анализом и отличаются от реального дефектного сигнала. CGAN все еще может быть улучшен путем настройки структуры сети или гиперпараметров.
pspectrum([x(:,1001) x(:,2600)],Fs) set(gca,'XScale','log') legend('Generated faulty','Real faulty')
Симуляция Simulink занимает около 14 часов, чтобы сгенерировать 2000 сигналы потока насоса. Это длительность может быть сокращено примерно до 1,7 часов с восемью параллельными рабочими, если у вас есть Parallel Computing Toolbox™.
CGAN занимает 1,5 часов, чтобы обучить и 70 секунды, чтобы сгенерировать такое же количество синтетических данных с графическим процессором NVIDIA Titan V.