Сгенерируйте синтетические сигналы Используя условный GAN

В этом примере показано, как сгенерировать сигналы насоса синтетического продукта с помощью условной порождающей соперничающей сети.

Порождающие соперничающие сети (GANs) могут использоваться, чтобы произвести синтетические данные, которые напоминают действительный ввод данных к сетям. GANs полезны, когда симуляции являются в вычислительном отношении дорогими, или эксперименты являются дорогостоящими. Условное выражение GANs (CGANs) может использовать метки данных во время учебного процесса, чтобы сгенерировать данные, принадлежащие определенным категориям.

Эти обработки в качестве примера симулировали сигналы, полученные моделью Simulink™ насоса как "действительные" данные, которые играют роль обучающего набора данных для CGAN. CGAN использует 1D сверточные сети и обучен с помощью пользовательского учебного цикла и массива глубокого обучения. Кроме того, этот пример использует анализ главных компонентов (PCA), чтобы визуально сравнить характеристики сгенерированных и действительных сигналов.

CGAN для синтеза сигнала

CGANs состоят из двух сетей, которые обучаются вместе как противники:

  1. Сеть Generator —, Учитывая метку и случайный массив, как введено, эта сеть генерирует данные с той же структурой как наблюдения обучающих данных, соответствующие той же метке. Цель генератора состоит в том, чтобы сгенерировать маркированные данные, которые различитель классифицирует как "действительные".

  2. Сеть Discriminator — Данный пакеты маркированных данных, содержащих наблюдения от обоих обучающих данных и сгенерированные данные из генератора, эта сеть пытается классифицировать наблюдения как "действительные" или "сгенерированные". Цель различителя не состоит в том, чтобы "дурачить" генератор когда данный пакеты и действительных и сгенерированных маркированных данных.

Идеально, эти стратегии приводят к генератору, который генерирует убедительно реалистические данные, соответствующие входным меткам и различителю, который изучил характеристику сильных черт обучающих данных для каждой метки.

Загрузка данных

Симулированные данные сгенерированы моделью Simulink насоса, представленной в Мультиклассовом обнаружении неисправностей с использованием смоделированных данных (Predictive Maintenance Toolbox) пример. Модель Simulink сконфигурирована, чтобы смоделировать три типа отказов: цилиндрические утечки, блокированные входы и увеличенное трение подшипника. Набор данных содержит 1 575 сигналов потока выхода насоса, из которых 760 здоровые сигналы, и 815 имеют одиночный отказ, комбинации двух отказов или комбинации трех отказов. Каждый сигнал имеет 1 201 выборку сигнала с частотой дискретизации 1 000 Гц.

Загрузите и разархивируйте данные в своей временной директории, местоположение которой задано 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.

Задайте сеть генератора

Задайте следующую 2D входную сеть, которая генерирует сигналы потока, учитывая 1 1 100 массивами случайных значений и соответствующих меток.

Сеть:

  • Проекты и изменяют 1 1 100 массивами шума к 4 1 1 024 массивами пользовательским слоем.

  • Преобразует категориальные метки во встраивание векторов и изменяет их к 4 массивами 1 на 1.

  • Конкатенации результатов двух входных параметров по измерению канала. Выход является 4 1 1 025 массивами.

  • Сверхдискретизировал полученные массивы к 1 201 массивами 1 на 1 с помощью серии 1D транспонированных слоев свертки со слоев ReLU и нормализацией партии.

Чтобы спроектировать и изменить шумовой вход, используйте пользовательский слой projectAndReshapeLayer, присоединенный к этому примеру как вспомогательный файл. projectAndReshapeLayer объект увеличивает масштаб вход с помощью полносвязного слоя и изменяет выход к заданному размеру.

Чтобы ввести метки в сеть, используйте imageInputLayer возразите и задайте размер 1 на 1. Чтобы встроить и изменить вход метки, используйте пользовательский слой embedAndReshapeLayer, присоединенный к этому примеру как вспомогательный файл. 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);

Задайте сеть различителя

Задайте следующую 2D входную сеть, которая классифицирует действительный, и сгенерированный 1201 1 сигнализирует, учитывая набор сигналов и их соответствующих меток.

Эта сеть:

  • Берет 1201 сигналами 1 на 1, как введено.

  • Преобразует категориальные метки во встраивание векторов и изменяет их к 1201 массивами 1 на 1.

  • Конкатенации результатов двух входных параметров по измерению канала. Выход является 1201 1 1 025 массивами.

  • Downsample полученные массивы к скалярным баллам предсказания, которые являются 1 массивами 1 на 1, с помощью серии 1D слоев свертки с текучими слоями 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;

Установите среду выполнения запускать CGANs на центральном процессоре. Чтобы запустить CGANs на графическом процессоре, установите executionEnvironment к "gpu"или выберите опцию "Run on GPU" в Live Editor. Используя графический процессор требует Parallel Computing Toolbox™. Чтобы видеть, который поддерживаются графические процессоры, смотрите Поддержку графического процессора Релизом (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, метки, параметрические усилители); %#ok
else
    % Use pretrained CGAN (default)
    загрузка (fullfile (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');

Укажите, что первые 1 000 случайных массивов здоровы, и остальные являются дефектными.

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.

Извлечение признаков

Объедините исходный действительный сигнал и сгенерированные сигналы в одной матрице данных. Используйте функцию помощника extractFeatures извлекать функцию включая общую статистику сигнала, такую как среднее значение и отклонение, а также спектральные характеристики.

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 часов, чтобы сгенерировать 2 000 сигналов потока насоса. Эта длительность может уменьшаться приблизительно до 1,7 часов с восемью параллельными рабочими, если у вас есть Parallel Computing Toolbox™.

CGAN занимает 1,5 часа, чтобы обучаться и 70 секунд, чтобы сгенерировать то же самое значение синтетических данных с Титаном NVIDIA V графических процессоров.