放置在雷达前的物体的不同部分的运动产生微多普勒信号,可用于识别该物体。这个例子使用了一个卷积神经网络(CNN)来根据行人和骑自行车的人的签名来识别他们。
这个例子使用模拟数据训练深度学习网络,然后检查网络在分类两个重叠签名案例时的表现。
基于仿真的综合数据生成用于训练网络的数据是使用来自 Radar ToolboxTM 的反向散射行人和反向散射自行车手生成的。这些函数分别模拟行人和骑自行车者反射的信号的雷达后向散射。Helper 函数 helperBackScatterSignals 生成指定数量的行人、骑自行车者和汽车雷达返回值。由于该示例的目的是对行人和骑自行车的人进行分类,因此该示例仅将汽车特征视为噪声源。为了了解所要解决的分类问题,研究了一种来自行人、自行车和汽车的微多普勒信号的实现方法。(对于每个实现,返回信号的维数为 Nfast-by-Nsllow,Nfast是快速时间样本的数量和Nsllow是慢时间样本的数量)
%%
numPed = 1; % 行人实现次数
numBic = 1; % 自行车实现次数
numCar = 1; % 汽车实现次数
[xPedRec,xBicRec,xCarRec,Tsamp] = helperBackScatterSignals(numPed,numBic,numCar);
辅助函数 helperDopplerSignatures
通过计算雷达回波的短时距傅里叶变换(STFT)来产生微多普勒信号。为了获得微多普勒信号,利用辅助函数对每个信号进行短时傅里叶变换和预处理。
[SPed,T,F] = helperDopplerSignatures(xPedRec,Tsamp);
[SBic,~,~] = helperDopplerSignatures(xBicRec,Tsamp);
[SCar,~,~] = helperDopplerSignatures(xCarRec,Tsamp);
绘制步行者、骑自行车者和汽车实现的时频地图。
%% 绘制步行者、骑自行车者和汽车实现的时频地图。
figure
subplot(1,3,1)
imagesc(T,F,SPed(:,:,1))
ylabel('Frequency (Hz)')
title('Pedestrian')
axis square xy
subplot(1,3,2)
imagesc(T,F,SBic(:,:,1))
xlabel('Time (s)')
title('Bicyclist')
axis square xy
subplot(1,3,3)
imagesc(T,F,SCar(:,:,1))
title('Car')
axis square xy
归一化谱图(STFT 绝对值)表明,这三个物体具有相当不同的特征。具体来说,行人和骑自行车者的声谱图分别具有丰富的微多普勒特征,这些特征是由手臂和腿的摆动以及车轮的转动引起的。相比之下,在这个例子中,汽车被建模为一个点目标与刚体,所以汽车的频谱显示,短期多普勒频移变化很小,表明微多普勒效应很小。
对象的组合:
由于行人和骑自行车者的微多普勒特征不同,将单个实现分类为行人或骑自行车者相对简单。然而,分类多个重叠的行人或自行车,加上高斯噪声或汽车噪声,是困难得多。如果雷达探测区域内同时存在多个目标,那么接收到的雷达信号就是来自所有目标的探测信号的总和。作为一个例子,产生接收雷达信号的行人和自行车与高斯背景噪声。
%% 在接收端配置高斯噪声电平
rx = phased.ReceiverPreamp('Gain',25,'NoiseFigure',10);
xRadarRec = complex(zeros(size(xPedRec)));
for ii = 1:size(xPedRec,3)
xRadarRec(:,:,ii) = rx(xPedRec(:,:,ii) + xBicRec(:,:,ii));
end
然后利用短时傅里叶变换获得接收信号的微多普勒特征。
[S,~,~] = helperDopplerSignatures(xRadarRec,Tsamp);
figure
imagesc(T,F,S(:,:,1)) % Plot the first realization
axis xy
xlabel('Time (s)')
ylabel('Frequency (Hz)')
title('Spectrogram of a Pedestrian and a Bicyclist')
由于行人和骑自行车者的特征在时间和频率上重叠,因此很难区分两个物体。
生成训练数据:
通过使用由具有不同属性的对象的模拟实现组成的数据来训练 CNN,例如,骑自行车的人以不同的速度骑车,行人以不同的速度行走。假设雷达固定在原点,在一个实现中,一个物体或多个物体沿 X 轴和 Y 轴分别均匀分布在[5,45]和[ -10,10]米的矩形区域内。
随机调优的三个对象的其他属性如下:
1)行人
- 高度ーー均匀分布在[1.5,2]米的间距内;
- 方向ーー在[ -180,180]度间隔内均匀分布;
- 速度ーー均匀分布在[0,1.4 h]米/秒的间隔内,其中 h 为高度值;
2)骑单车者
- 方向ーー在[ -180,180]度间隔内均匀分布;
- 速度ーー均匀分布在[1,10]米/秒的间隔内;
- 齿轮传动比ーー均匀分布在[0.5,6]区间内;
- 踩踏板或滑行ーー50% 的可能性踩踏板(滑行意味着骑自行车的人没有踩踏板);
3)汽车
- 速度ーー沿 X、 Y 方向均匀分布在[0,10]米/秒的区间内
卷积网络的输入是微多普勒特征,由以分贝表示并归一化为[0,1]的光谱图组成,如下图所示:
雷达回波来自不同的物体和物体的不同部分。根据配置的不同,一些回波要比其他回波强得多。较强的回波往往掩盖较弱的回波。对数缩放通过使返回强度具有可比性来增强这些特性。幅度归一化有助于 CNN 更快地收敛。
数据集包含以下场景的实现:
- 现场有一个行人
- 现场有一名骑自行车的人
- 现场有一名行人和一名骑自行车的人
- 现场有两个行人
- 两名骑自行车的人出现在现场
数据集下载:
数据包括20,000个行人、20,000个骑自行车的人和12,500个汽车信号,这些信号是使用 helper 函数 helperBackScatterSignals 和 helperdopplerSignature 生成的。信号分为两个数据集: 一个没有汽车噪声样本,一个有汽车噪声样本。
对于第一个数据集(没有汽车噪声) ,将行人和自行车信号合并,添加高斯噪声,并计算微多普勒特征,以生成五个场景中每个场景的5000个特征。
在每个类别中,80% 的签名(即4000个签名)保留给训练数据集,而20% 的签名(即1000个签名)保留给测试数据集。
为了生成第二个数据集(汽车噪声) ,遵循第一个数据集的过程,除了汽车噪声被添加到50% 的签名。在训练和测试数据集中,有和没有汽车噪声的签名的比例是相同的。
下载并解压缩临时目录中的数据,其位置由 MATLAB 的 temdir 命令指定。数据大小为21GB,下载过程可能需要一些时间。如果数据位于与 temdir 不同的文件夹中,请在后面的说明中更改目录名。
%% 数据集下载
dataURL = 'https://ssd.mathworks.com/supportfiles/SPT/data/PedBicCarData.zip';
saveFolder = fullfile(tempdir,'PedBicCarData');
zipFile = fullfile(tempdir,'PedBicCarData.zip');
if ~exist(zipFile,'file')
websave(zipFile,dataURL);
elseif ~exist(saveFolder,'dir')
% Unzip the data
unzip(zipFile,tempdir)
end
注意事项:此处直接使用tempdir路径极大可能报错,我的做法是将tempdir替换为当前脚本路径下文件夹,创建zipFlie ,大概是下面这样:(下载进程可以单击属性栏查看)
%% 数据集下载
dataURL = 'https://ssd.mathworks.com/supportfiles/SPT/data/PedBicCarData.zip';
saveFolder = fullfile("F:\机器学习\deep\zipFile",'PedBicCarData');
zipFile = fullfile("F:\机器学习\deep\zipFile",'PedBicCarData.zip');
if ~exist(zipFile,'file')
websave(zipFile,dataURL);
elseif ~exist(saveFolder,'dir')
% Unzip the data
unzip(zipFile,tempdir)
end
数据档案如下:
- 训练数据集 train DataNoCar 及其标签集 train LabelNoCar。
- 测试数据集 testDataNoCar 及其标签集 testLabelNoCar。
- 训练数据集 train DataCarNoise.mat 及其标签集 train LabelCarNoise.mat。
- 测试数据集 testDataCarNoise.mat 及其标签集 testLabelCarNoise.mat。
- TF.mat 包含微多普勒信号的时间和频率信息。
网络架构 :
创建五个卷积层和一个完全连接层。前四个卷积层之后是批归一化层、整流线性单元(ReLU)激活层和最大池层。在最后一个卷积层中,最大池层被一个平均池层所代替。输出层是 Softmax 激活后的分类层。
批归一化层:https://blog.csdn.net/u014453898/article/details/108172108
整流线性单元激活层:https://zhuanlan.zhihu.com/p/98863801
https://zhuanlan.zhihu.com/p/363345545
layers = [
imageInputLayer([size(S,1),size(S,2),1],'Normalization','none')
%图形输入层,[size(S,1),size(S,2),1]输入数据大小;
%图形输入层,'Normalization',归一化,‘none’:不采取任何归一化措施;
convolution2dLayer(10,16,'Padding','same')
batchNormalizationLayer
reluLayer
maxPooling2dLayer(10,'Stride',2)
convolution2dLayer(5,32,'Padding','same')
batchNormalizationLayer
reluLayer
maxPooling2dLayer(10,'Stride',2)
convolution2dLayer(5,32,'Padding','same')
batchNormalizationLayer
reluLayer
maxPooling2dLayer(10,'Stride',2)
convolution2dLayer(5,32,'Padding','same')
batchNormalizationLayer
reluLayer
maxPooling2dLayer(5,'Stride',2)
convolution2dLayer(5,32,'Padding','same')
batchNormalizationLayer
reluLayer
averagePooling2dLayer(2,'Stride',2)
fullyConnectedLayer(5)
softmaxLayer
classificationLayer]
图像输入层 imageInputLayer 用于指定图像大小,在本例中为 [size(S,1),size(S,2),1]。这些数字对应于高度、宽度和通道大小。数字数据由灰度图像组成,因此通道大小(颜色通道)为 1。对于彩色图像,通道大小为 3,对应于 RGB 值。您不需要打乱数据,因为 trainNetwork 默认会在训练开始时打乱数据。trainNetwork 还可以在训练过程中的每轮训练开始时自动打乱数据。
卷积层 在卷积层中,第一个参数是 filterSize,它是训练函数在沿图像扫描时使用的过滤器的高度和宽度。在此示例中,数字 10表示过滤器大小为 10×10。您可以为过滤器的高度和宽度指定不同大小。第二个参数是过滤器数量 numFilters,它是连接到同一输入区域的神经元数量。此参数决定了特征图的数量。使用 ‘Padding’ 名称-值对组对输入特征图进行填充。对于默认步幅为 1 的卷积层,‘same’ 填充可确保空间输出大小与输入大小相同。您也可以使用 convolution2dLayer 名称-值对组参数定义该层的步幅和学习率。
批量归一化层 批量归一化层对网络中的激活值和梯度传播进行归一化,使网络训练成为更简单的优化问题。在卷积层和非线性部分(例如 ReLU 层)之间使用批量归一化层,来加速网络训练并降低对网络初始化的敏感度。使用 batchNormalizationLayer 创建批量归一化层。
ReLU 层 批量归一化层后接一个非线性激活函数。最常见的激活函数是修正线性单元 (ReLU)。使用 reluLayer 创建 ReLU 层。
最大池化层 卷积层(带激活函数)有时会后跟下采样操作,以减小特征图的空间大小并删除冗余空间信息。通过下采样可以增加更深卷积层中的过滤器数量,而不会增加每层所需的计算量。下采样的一种方法是使用最大池化,可使用 maxPooling2dLayer 创建。最大池化层返回由第一个参数 poolSize 指定的矩形输入区域的最大值。在此示例中,该矩形区域的大小是 [10,10]。‘Stride’ 名称-值对组参数指定训练函数在沿输入扫描时所采用的步长。
全连接层 卷积层和下采样层后跟一个或多个全连接层。顾名思义,全连接层中的神经元将连接到前一层中的所有神经元。该层将先前层在图像中学习的所有特征组合在一起,以识别较大的模式。最后一个全连接层将特征组合在一起来对图像进行分类。因此,最后一个全连接层中的 OutputSize 参数等于目标数据中的类数。在此示例中,输出大小为5,对应于 5个类。使用 fullyConnectedLayer 创建全连接层。
softmax 层 softmax 激活函数对全连接层的输出进行归一化。softmax 层的输出由总和为 1 的多个正数组成,这些数字随后可被分类层用作分类概率。使用 softmaxLayer 函数在最后一个全连接层后创建一个 softmax 层。
分类层 最终层是分类层。该层使用 softmax 激活函数针对每个输入返回的概率,将输入分配到其中一个互斥类并计算损失。要创建分类层,请使用 classificationLayer。
指定优化求解器和超参数
%% 指定优化求解器和超参数,以使用 training ingOptions 训练 CNN。
options = trainingOptions('adam', ...
'ExecutionEnvironment','gpu',...
'MiniBatchSize',128, ...
'MaxEpochs',30, ...
'InitialLearnRate',1e-2, ...
'LearnRateSchedule','piecewise', ...
'LearnRateDropFactor',0.1, ...
'LearnRateDropPeriod',10, ...
'Shuffle','every-epoch', ...
'Verbose',false, ...
'Plots','training-progress');
- solverName:优化函数,可选’sgdm’,‘rmsprop’,‘adam’
- ExecutionEnvironment:名称-值对组参数指定所需的执行环境(可以指定单个 CPU (
'cpu'
)、单个 GPU ('gpu'
)、多个 GPU ('multi-gpu'
),或本地并行池或计算集群 ('parallel'
)) - MiniBatchSize:指定用于每次训练迭代的小批量的大小作为由
MiniBatchSize
和a组成的逗号分隔对正整数。迷你批次是训练集的子集,它是用于评估损失函数的梯度并更新权重。 - InitialLearnRate:初始学习率
- MaxEpochs:最大训练轮数
- LearnRateSchedule:学习率策略,‘none’或者’piecewise’,'none’表示学习率不变,'piecewise’为分段学习率
- LearnRateDropFactor:学习率下降因子,[0,1]之间,降低之后学习率为:当前学习率*下降因子
- LearnRateDropPeriod:学习率下降周期,即几个epoch下降一次学习率
- shuffle:数据洗牌选项,指定为由“洗牌”和下列选项之一组成的逗号分隔对:'once’在训练之前,对训练和验证数据进行一次洗牌。'never’不打乱数据。'every-epoch’在每个训练轮次之前洗牌训练数据,在每个网络验证之前洗牌验证数据。如果小批量大小不能均匀划分训练样本的数量,则训练网络丢弃不适合每个轮次的最终完整小批量的训练数据。为了避免在每个轮次中丢弃相同的数据,将“Shuffle”值设置为“every-epoch”。
- Verbose:是否在命令行窗口显示实时训练进程,0或1,若为1,则在命令行显示当前在干啥了,默认为true
- Plots:是否画出实时训练进程,可选’none’或者’training-progress’,默认为’none’
加载数据集(根据各自环境改变路径即可)
%% 加载数据集
load(fullfile("F:\机器学习\deep\zipFile",'PedBicCarData','trainDataNoCar.mat')) % load training data set
load(fullfile("F:\机器学习\deep\zipFile",'PedBicCarData','testDataNoCar.mat')) % load test data set
load(fullfile("F:\机器学习\deep\zipFile",'PedBicCarData','TF.mat')) % load time and frequency information
helperPlotTrainData(trainDataNoCar,trainLabelNoCar,T,F)
训练你创建的 CNN
trainedNetNoCar = trainNetwork(trainDataNoCar,trainLabelNoCar,layers,options);
使用训练好的网络和分类函数来获得测试数据集 testDataNoCar 的预测标签
predTestLabel = classify(trainedNetNoCar,testDataNoCar);
testAccuracy = mean(predTestLabel == testLabelNoCar);
figure
confusionchart(testLabelNoCar,predTestLabel);
为了分析汽车噪声的影响,利用经过训练的 NetNoCar 网络对含有汽车噪声的数据进行分类,该网络在没有汽车噪声的情况下进行训练。
%加载汽车噪声损坏的测试数据集 testDataCarNoise.mat。
load(fullfile("F:\机器学习\deep\zipFile",'PedBicCarData','testDataCarNoise.mat'));
向网络输入汽车噪声损坏的测试数据集。
predTestLabel = classify(trainedNetNoCar,testDataCarNoise);
testAccuracy = mean(predTestLabel == testLabelCarNoise);
confusionchart(testLabelCarNoise,predTestLabel);
在训练数据集中添加汽车噪声对 CNN 进行再训练,加载汽车噪声损坏的训练数据集 train DataCarNoise.mat。
load(fullfile("F:\机器学习\deep\zipFile",'PedBicCarData','trainDataCarNoise.mat'))
利用汽车噪声污染的训练数据集对网络进行再训练,在30个训练周期内,训练过程达到近90% 的准确率。
trainedNetCarNoise = trainNetwork(trainDataCarNoise,trainLabelCarNoise,layers,options);
predTestLabel = classify(trainedNetCarNoise,testDataCarNoise);
testAccuracy = mean(predTestLabel == testLabelCarNoise);
%% 混淆矩阵显示,经过训练的网络在预测一个行人和两个行人的场景方面表现得更好。
confusionchart(testLabelCarNoise,predTestLabel);
训练效果此处不附图,可自行使用工具箱实现。