Радарная классификация целей Используя машинное обучение и глубокое обучение

То В этом примере показано, как классифицировать радар, возвращается с обоими подходами машинного и глубокого обучения. Подход машинного обучения использует извлечение признаков рассеивания вейвлета вместе с машиной опорных векторов. Кроме того, два подхода глубокого обучения проиллюстрированы: использование передачи обучения SqueezeNet и рекуррентная нейронная сеть Долгой краткосрочной памяти (LSTM). Обратите внимание на то, что набор данных, используемый в этом примере, не требует усовершенствованных методов, но рабочий процесс описан, потому что методы могут быть расширены к более сложным задачам.

Введение

Целевая классификация является важной функцией в современных радиолокационных системах. Этот пример использует машинное и глубокое обучение, чтобы классифицировать радарное эхо от цилиндра и конуса. Несмотря на то, что этот пример использует синтезируемые выборки I/Q, рабочий процесс применим к действительному радару, возвращается.

Синтез RCS

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

Следующий код симулирует шаблон RCS цилиндра с радиусом 1 метра и высотой 10 метров. Рабочая частота радара составляет 850 МГц.

c = 3e8;
fc = 850e6;
[cylrcs,az,el] = rcscylinder(1,1,10,c,fc);
helperTargetRCSPatternPlot(az,el,cylrcs);

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

cyltgt = phased.BackscatterRadarTarget('PropagationSpeed',c,...
    'OperatingFrequency',fc,'AzimuthAngles',az,'ElevationAngles',el,'RCSPattern',cylrcs);

Следующий график показывает, как симулировать 100, возвращается из цилиндра в зависимости от времени. Это принято, что цилиндр под движениями движение, которое вызывает маленькие колебания вокруг вида скуки, в результате угол обзора, изменяется от одной выборки до следующего.

rng default;
N = 100;
az = 2*randn(1,N);                  
el = 2*randn(1,N);
cylrtn = cyltgt(ones(1,N),[az;el]);  


plot(mag2db(abs(cylrtn)));
xlabel('Time Index')
ylabel('Target Return (dB)');
title('Target Return for Cylinder');

Возврат конуса может быть сгенерирован так же. Чтобы создать набор обучающих данных, вышеупомянутый процесс повторяется для 5 произвольно выбранных цилиндрических радиусов. Кроме того, для каждого радиуса, 10 профилей движения симулированы путем варьирования инцидентного угла после 10 случайным образом сгенерированных кривых синусоиды вокруг опорного направления. В каждом профиле движения существует 701 выборка, таким образом, существуют 701 50 выборки. Процесс повторяется для цилиндрической цели, которая приводит к 701 100 матрица обучающих данных с 50 цилиндрами и 50 коническими профилями. В наборе тестов мы используем 25 цилиндров и 25 конических профилей, чтобы создать 701 50 набор обучающих данных. Из-за долгого времени вычисления обучающие данные предварительно вычислены и загружены ниже.

load('RCSClassificationReturnsTraining');
load('RCSClassificationReturnsTest');

Как пример, следующий график показывает возврат для одного из профилей движения от каждой формы. Графики показывают, как изменение значений в зависимости от времени и для инцидентных углов азимута и для цели возвращается.

subplot(2,2,1)
plot(cylinderAspectAngle(1,:))
ylim([-90 90])
grid on
title('Cylinder Aspect Angle vs. Time'); xlabel('Time Index'); ylabel('Aspect Angle (degrees)');
subplot(2,2,3)
plot(RCSReturns.Cylinder_1); ylim([-50 50]);
grid on
title('Cylinder Return'); xlabel('Time Index'); ylabel('Target Return (dB)');
subplot(2,2,2)
plot(coneAspectAngle(1,:)); ylim([-90 90]); grid on;
title('Cone Aspect Angle vs. Time'); xlabel('Time Index'); ylabel('Aspect Angle (degrees)');
subplot(2,2,4);
plot(RCSReturns.Cone_1); ylim([-50 50]); grid on;
title('Cone Return'); xlabel('Time Index'); ylabel('Target Return (dB)');

Рассеивание вейвлета

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

Основные параметры, чтобы задать в разложении рассеивания времени вейвлета являются шкалой независимого от времени, количество вейвлета преобразовывает, и количество вейвлетов на октаву в каждом из наборов фильтров вейвлета. Во многих приложениях каскад двух наборов фильтров достаточен, чтобы достигнуть хорошей производительности. В этом примере мы создаем разложение рассеивания времени вейвлета с наборами фильтров по умолчанию: 8 вейвлетов на октаву в первом наборе фильтров и 1 вейвлет на октаву во втором наборе фильтров. Шкала инвариантности установлена в 701 выборку, длину данных.

sf = waveletScattering('SignalLength',701,'InvarianceScale',701);

Затем мы получаем рассеивающиеся преобразования и наборов обучающих данных и наборов тестов.

sTrain = sf.featureMatrix(RCSReturns{:,:},'transform','log');
sTest = sf.featureMatrix(RCSReturnsTest{:,:},'transform','log');

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

TrainFeatures = squeeze(mean(sTrain,2))';
TestFeatures = squeeze(mean(sTest,2))';

Создайте метки для обучения и изучения

TrainLabels = repelem(categorical({'Cylinder','Cone'}),[50 50])';
TestLabels = repelem(categorical({'Cylinder','Cone'}),[25 25])';

Обучение модели

Подбирайте модель машины опорных векторов с квадратичным ядром к рассеивающимся функциям и получите точность перекрестной проверки.

template = templateSVM('KernelFunction', 'polynomial', ...
    'PolynomialOrder', 2, ...
    'KernelScale', 'auto', ...
    'BoxConstraint', 1, ...
    'Standardize', true);
classificationSVM = fitcecoc(...
    TrainFeatures, ...
    TrainLabels, ...
    'Learners', template, ...
    'Coding', 'onevsone', ...
    'ClassNames', categorical({'Cylinder','Cone'}));
partitionedModel = crossval(classificationSVM, 'KFold', 5);
[validationPredictions, validationScores] = kfoldPredict(partitionedModel);
validationAccuracy = (1 - kfoldLoss(partitionedModel, 'LossFun', 'ClassifError'))*100
validationAccuracy = 100

Целевая классификация

Используя обученный SVM, классифицируйте рассеивающиеся функции, полученные из набора тестов.

predLabels = predict(classificationSVM,TestFeatures);
accuracy = sum(predLabels == TestLabels )/numel(TestLabels)*100
accuracy = 100

Постройте матрицу беспорядка.

figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]);
ccDCNN = confusionchart(TestLabels,predLabels);
ccDCNN.Title = 'Confusion Chart';
ccDCNN.ColumnSummary = 'column-normalized';
ccDCNN.RowSummary = 'row-normalized';

Для наборов более комплексных данных рабочий процесс глубокого обучения может улучшать производительность.

Передача обучения с CNN

SqueezeNet является глубокой сверточной нейронной сетью (CNN), обученной изображениям в 1 000 классов, как используется в Крупном масштабе ImageNet визуальной проблеме распознавания (ILSVRC). В этом примере мы снова используем предварительно обученный SqueezeNet, чтобы классифицировать радар, возвращает принадлежность одному из двух классов.

Загрузите SqueezeNet.

snet = squeezenet;
snet.Layers
ans = 
  68x1 Layer array with layers:

     1   'data'                              Image Input              227x227x3 images with 'zerocenter' normalization
     2   'conv1'                             Convolution              64 3x3x3 convolutions with stride [2  2] and padding [0  0  0  0]
     3   'relu_conv1'                        ReLU                     ReLU
     4   'pool1'                             Max Pooling              3x3 max pooling with stride [2  2] and padding [0  0  0  0]
     5   'fire2-squeeze1x1'                  Convolution              16 1x1x64 convolutions with stride [1  1] and padding [0  0  0  0]
     6   'fire2-relu_squeeze1x1'             ReLU                     ReLU
     7   'fire2-expand1x1'                   Convolution              64 1x1x16 convolutions with stride [1  1] and padding [0  0  0  0]
     8   'fire2-relu_expand1x1'              ReLU                     ReLU
     9   'fire2-expand3x3'                   Convolution              64 3x3x16 convolutions with stride [1  1] and padding [1  1  1  1]
    10   'fire2-relu_expand3x3'              ReLU                     ReLU
    11   'fire2-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    12   'fire3-squeeze1x1'                  Convolution              16 1x1x128 convolutions with stride [1  1] and padding [0  0  0  0]
    13   'fire3-relu_squeeze1x1'             ReLU                     ReLU
    14   'fire3-expand1x1'                   Convolution              64 1x1x16 convolutions with stride [1  1] and padding [0  0  0  0]
    15   'fire3-relu_expand1x1'              ReLU                     ReLU
    16   'fire3-expand3x3'                   Convolution              64 3x3x16 convolutions with stride [1  1] and padding [1  1  1  1]
    17   'fire3-relu_expand3x3'              ReLU                     ReLU
    18   'fire3-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    19   'pool3'                             Max Pooling              3x3 max pooling with stride [2  2] and padding [0  1  0  1]
    20   'fire4-squeeze1x1'                  Convolution              32 1x1x128 convolutions with stride [1  1] and padding [0  0  0  0]
    21   'fire4-relu_squeeze1x1'             ReLU                     ReLU
    22   'fire4-expand1x1'                   Convolution              128 1x1x32 convolutions with stride [1  1] and padding [0  0  0  0]
    23   'fire4-relu_expand1x1'              ReLU                     ReLU
    24   'fire4-expand3x3'                   Convolution              128 3x3x32 convolutions with stride [1  1] and padding [1  1  1  1]
    25   'fire4-relu_expand3x3'              ReLU                     ReLU
    26   'fire4-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    27   'fire5-squeeze1x1'                  Convolution              32 1x1x256 convolutions with stride [1  1] and padding [0  0  0  0]
    28   'fire5-relu_squeeze1x1'             ReLU                     ReLU
    29   'fire5-expand1x1'                   Convolution              128 1x1x32 convolutions with stride [1  1] and padding [0  0  0  0]
    30   'fire5-relu_expand1x1'              ReLU                     ReLU
    31   'fire5-expand3x3'                   Convolution              128 3x3x32 convolutions with stride [1  1] and padding [1  1  1  1]
    32   'fire5-relu_expand3x3'              ReLU                     ReLU
    33   'fire5-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    34   'pool5'                             Max Pooling              3x3 max pooling with stride [2  2] and padding [0  1  0  1]
    35   'fire6-squeeze1x1'                  Convolution              48 1x1x256 convolutions with stride [1  1] and padding [0  0  0  0]
    36   'fire6-relu_squeeze1x1'             ReLU                     ReLU
    37   'fire6-expand1x1'                   Convolution              192 1x1x48 convolutions with stride [1  1] and padding [0  0  0  0]
    38   'fire6-relu_expand1x1'              ReLU                     ReLU
    39   'fire6-expand3x3'                   Convolution              192 3x3x48 convolutions with stride [1  1] and padding [1  1  1  1]
    40   'fire6-relu_expand3x3'              ReLU                     ReLU
    41   'fire6-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    42   'fire7-squeeze1x1'                  Convolution              48 1x1x384 convolutions with stride [1  1] and padding [0  0  0  0]
    43   'fire7-relu_squeeze1x1'             ReLU                     ReLU
    44   'fire7-expand1x1'                   Convolution              192 1x1x48 convolutions with stride [1  1] and padding [0  0  0  0]
    45   'fire7-relu_expand1x1'              ReLU                     ReLU
    46   'fire7-expand3x3'                   Convolution              192 3x3x48 convolutions with stride [1  1] and padding [1  1  1  1]
    47   'fire7-relu_expand3x3'              ReLU                     ReLU
    48   'fire7-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    49   'fire8-squeeze1x1'                  Convolution              64 1x1x384 convolutions with stride [1  1] and padding [0  0  0  0]
    50   'fire8-relu_squeeze1x1'             ReLU                     ReLU
    51   'fire8-expand1x1'                   Convolution              256 1x1x64 convolutions with stride [1  1] and padding [0  0  0  0]
    52   'fire8-relu_expand1x1'              ReLU                     ReLU
    53   'fire8-expand3x3'                   Convolution              256 3x3x64 convolutions with stride [1  1] and padding [1  1  1  1]
    54   'fire8-relu_expand3x3'              ReLU                     ReLU
    55   'fire8-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    56   'fire9-squeeze1x1'                  Convolution              64 1x1x512 convolutions with stride [1  1] and padding [0  0  0  0]
    57   'fire9-relu_squeeze1x1'             ReLU                     ReLU
    58   'fire9-expand1x1'                   Convolution              256 1x1x64 convolutions with stride [1  1] and padding [0  0  0  0]
    59   'fire9-relu_expand1x1'              ReLU                     ReLU
    60   'fire9-expand3x3'                   Convolution              256 3x3x64 convolutions with stride [1  1] and padding [1  1  1  1]
    61   'fire9-relu_expand3x3'              ReLU                     ReLU
    62   'fire9-concat'                      Depth concatenation      Depth concatenation of 2 inputs
    63   'drop9'                             Dropout                  50% dropout
    64   'conv10'                            Convolution              1000 1x1x512 convolutions with stride [1  1] and padding [0  0  0  0]
    65   'relu_conv10'                       ReLU                     ReLU
    66   'pool10'                            Global Average Pooling   Global average pooling
    67   'prob'                              Softmax                  softmax
    68   'ClassificationLayer_predictions'   Classification Output    crossentropyex with 'tench' and 999 other classes

Вы видите, что SqueezeNet состоит из 68 слоев. Как весь DCNNs, SqueezeNet располагает каскадом сверточные операторы, сопровождаемые нелинейностью и объединением или усреднением. SqueezeNet ожидает вход изображений размера 227 227 3, который вы видите со следующим кодом.

snet.Layers(1)
ans = 
  ImageInputLayer with properties:

                      Name: 'data'
                 InputSize: [227 227 3]

   Hyperparameters
          DataAugmentation: 'none'
             Normalization: 'zerocenter'
    NormalizationDimension: 'auto'
                      Mean: [1×1×3 single]

Кроме того, SqueezeNet сконфигурирован к распознанным 1 000 различных классов, которые вы видите со следующим кодом.

snet.Layers(68)
ans = 
  ClassificationOutputLayer with properties:

            Name: 'ClassificationLayer_predictions'
         Classes: [1000×1 categorical]
      OutputSize: 1000

   Hyperparameters
    LossFunction: 'crossentropyex'

В последующем разделе мы изменим избранные слои SqueezeNet для того, чтобы применить его к нашей проблеме классификации.

Непрерывный вейвлет преобразовывает

SqueezeNet спроектирован, чтобы отличить различия в изображениях и классифицировать результаты. Поэтому для того, чтобы использовать SqueezeNet, чтобы классифицировать радар, возвращается, мы должны преобразовать 1D радар, возвращают временные ряды в изображение. Распространенный способ сделать это должно использовать представление частоты времени (TFR). Существует много вариантов для представления частоты времени сигнала и какой является самым соответствующим, зависит от характеристик сигнала. Чтобы определить, какой TFR может подходить для этой проблемы, случайным образом выберите и постройте некоторых, радар возвращается из каждого класса.

rng default;
idxCylinder = randperm(50,2);
idxCone = randperm(50,2)+50;

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

cwt(RCSReturns{:,idxCylinder(1)},'VoicesPerOctave',8)

CWT одновременно получает и медленно различный (низкая частота) колебания и переходные процессы. Контрастируйте CWT цилиндра возвращаются с одним из конической цели.

cwt(RCSReturns{:,idxCone(2)},'VoicesPerOctave',8);

Из-за очевидной важности переходных процессов в определении, происходит ли целевой возврат из цилиндра или конической цели, мы выбираем CWT как идеальный TFR, чтобы использовать. После получения CWT для каждого целевого возврата мы заставляем изображения из CWT каждого радара возвратиться. Эти изображения изменены, чтобы быть совместимыми с входным слоем SqueezeNet, и мы усиливаем SqueezeNet, чтобы классифицировать получившиеся изображения.

Отобразите подготовку

Функция помощника, helpergenWaveletTFImg, получает CWT для каждого радара, возвращаются, изменяет CWT, чтобы быть совместимым с SqueezeNet и пишет CWT как jpeg файл. Запускать helpergenWaveletTFImg, выберите parentDir где у вас есть разрешение записи. Этот пример использует tempdir, но можно использовать любую папку на машине, где у вас есть разрешение записи. Функция помощника создает Training и Test установите папки под parentDir а также создание Cylinder и Cone подпапки под обоими Training и Test. Эти папки заполняются с изображениями jpeg, которые будут использоваться в качестве входных параметров к SqueezeNet.

parentDir = tempdir;
helpergenWaveletTFImg(parentDir,RCSReturns,RCSReturnsTest)
Generating Time-Frequency Representations...Please Wait
   Creating Cylinder Time-Frequency Representations ... Done
   Creating Cone Time-Frequency Representations ... Done
   Creating Cylinder Time-Frequency Representations ... Done
   Creating Cone Time-Frequency Representations ... Done

Теперь используйте imageDataStore управлять доступом к файлу от папок для того, чтобы обучить SqueezeNet. Создайте хранилища данных и для обучения и для тестовых данных.

trainingData= imageDatastore(fullfile(parentDir,'Training'), 'IncludeSubfolders', true,...
    'LabelSource', 'foldernames');
testData = imageDatastore(fullfile(parentDir,'Test'),'IncludeSubfolders',true,...
    'LabelSource','foldernames');

Для того, чтобы использовать SqueezeNet с этой бинарной проблемой классификации, мы должны изменить пару слоев. Во-первых, мы изменяем последний learnable слой в SqueezeNet (слой 64), чтобы иметь то же количество сверток 1 на 1 как наше новое количество классов, 2.

lgraphSqueeze = layerGraph(snet);
convLayer = lgraphSqueeze.Layers(64);
numClasses = numel(categories(trainingData.Labels));
newLearnableLayer = convolution2dLayer(1,numClasses, ...
        'Name','binaryconv', ...
        'WeightLearnRateFactor',10, ...
        'BiasLearnRateFactor',10);
lgraphSqueeze = replaceLayer(lgraphSqueeze,convLayer.Name,newLearnableLayer);
classLayer = lgraphSqueeze.Layers(end);
newClassLayer = classificationLayer('Name','binary');
lgraphSqueeze = replaceLayer(lgraphSqueeze,classLayer.Name,newClassLayer);

Наконец, установите опции для переквалификации SqueezeNet. Установите начальную букву, изучают уровень 1e-4, определяют максимальный номер эпох к 15 и мини-пакетного размера к 10. Используйте стохастический градиентный спуск с импульсом.

ilr = 1e-4;
mxEpochs = 15;
mbSize =10;
opts = trainingOptions('sgdm', 'InitialLearnRate', ilr, ...
    'MaxEpochs',mxEpochs , 'MiniBatchSize',mbSize, ...
    'Plots', 'training-progress','ExecutionEnvironment','cpu');

Обучите сеть. Если у вас есть совместимый графический процессор, trainNetwork автоматически использует графический процессор, и обучение должно завершиться меньше чем через одну минуту. Если у вас нет совместимого графического процессора, trainNetwork использует центральный процессор, и обучение должно занять приблизительно пять минут. Учебные времена действительно варьируются на основе многих факторов. В этом случае обучение происходит на CPU путем установки ExecutionEnvironment параметр к cpu.

CWTnet = trainNetwork(trainingData,lgraphSqueeze,opts);
Initializing input data normalization.
|========================================================================================|
|  Epoch  |  Iteration  |  Time Elapsed  |  Mini-batch  |  Mini-batch  |  Base Learning  |
|         |             |   (hh:mm:ss)   |   Accuracy   |     Loss     |      Rate       |
|========================================================================================|
|       1 |           1 |       00:00:01 |       60.00% |       2.6639 |      1.0000e-04 |
|       5 |          50 |       00:00:42 |      100.00% |       0.0001 |      1.0000e-04 |
|      10 |         100 |       00:01:20 |      100.00% |       0.0002 |      1.0000e-04 |
|      15 |         150 |       00:01:58 |      100.00% |   2.2276e-05 |      1.0000e-04 |
|========================================================================================|

Используйте обучивший сеть, чтобы предсказать, что цель возвращается в протянутом наборе тестов.

predictedLabels = classify(CWTnet,testData,'ExecutionEnvironment','cpu');
accuracy = sum(predictedLabels == testData.Labels)/50*100
accuracy = 100

Постройте график беспорядка наряду с точностью и отзывом. В этом случае 100% тестовых выборок классифицируются правильно.

figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]);
ccDCNN = confusionchart(testData.Labels,predictedLabels);
ccDCNN.Title = 'Confusion Chart';
ccDCNN.ColumnSummary = 'column-normalized';
ccDCNN.RowSummary = 'row-normalized';

LSTM

В итоговом разделе этого примера описан рабочий процесс LSTM. Сначала слои LSTM заданы:

LSTMlayers = [ ...
    sequenceInputLayer(1)
    bilstmLayer(100,'OutputMode','last')
    fullyConnectedLayer(2)
    softmaxLayer
    classificationLayer
    ];
options = trainingOptions('adam', ...
    'MaxEpochs',30, ...
    'MiniBatchSize', 150, ...
    'InitialLearnRate', 0.01, ...
    'GradientThreshold', 1, ...
    'plots','training-progress', ...
    'Verbose',false,'ExecutionEnvironment','cpu');
trainLabels = repelem(categorical({'cylinder','cone'}),[50 50]);
trainLabels = trainLabels(:);
trainData = num2cell(table2array(RCSReturns)',2);
testData = num2cell(table2array(RCSReturnsTest)',2);
testLabels = repelem(categorical({'cylinder','cone'}),[25 25]);
testLabels = testLabels(:);
RNNnet = trainNetwork(trainData,trainLabels,LSTMlayers,options);

Точность для этой системы также построена.

predictedLabels = classify(RNNnet,testData,'ExecutionEnvironment','cpu');
accuracy = sum(predictedLabels == testLabels)/50*100
accuracy = 100

Заключение

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

С этим набором данных мы были также получены, чтобы достигнуть подобной точности, только подав необработанные данные в LSTM. В более сложных наборах данных необработанные данные могут быть слишком по сути переменными для модели, чтобы узнать об устойчивых функциях из необработанных данных, и вам, вероятно, придется обратиться к извлечению признаков до использования LSTM.