如何用MATLAB搭建ResNet网络(复现论文)
文章目录
- 前言
- 基础工具
- 网络搭建
- ResNet网络代码
- 完整代码
- 总结
- 参考文献
前言
之前暑假实习了3个月,后来又赶上开学一堆事,现在终于有时间记录一下学习经历。新的学期开始了,要继续努力。
因为最近要做一个无人机航迹分类的项目,所以找了很多论文,但是不知道具体用起来效果如何,所以想用Matlab复现一下,这里主要是复现的其中的ResNet。
论文:基于CNN的雷达航迹分类方法
基础工具
Matlab深度网络设计器
打开工具箱后,左侧是网络的模块,在搭建网络的时候只需要拖拽这些模块就能组成网络的主体,右侧的属性用来调节网络模块的参数,例如卷积核,步长等等。
网络搭建
从论文的图中我们可以得到网络的结构如下,但是其中用的是一维卷积,所以我们选取的是Convd_1d
按照论文中的网络结构所示,我们搭建出了网络的主体架构,但值得注意的是,在第一次相加那里,输入的数据是5维的特征向量,但是经过卷积的向量维度是64,那么在这里该如何处理呢,为了让2者顺利相加,在这里我采用的是全连接层把5维扩展到64维,但是具体能不能这么做还有待进一步验证,因为网上的相关资料比较少,所以在这里先挖一个坑。
网络搭建好之后,先点击分析,看看网络的参数有没有问题
如果没有报错的话直接点击左上角的生成代码就好了,工具箱会生成一个mlx脚本,脚本如下。
ResNet网络代码
创建层次图
创建层次图变量以包含网络层。
lgraph = layerGraph();
添加层分支
将网络分支添加到层次图中。每个分支均为一个线性层组。
tempLayers = sequenceInputLayer(5,"Name","sequence");
lgraph = addLayers(lgraph,tempLayers);
tempLayers = fullyConnectedLayer(64,"Name","fc");
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
convolution1dLayer(3,64,"Name","conv1d_1","Padding","same")
batchNormalizationLayer("Name","batchnorm_1")
reluLayer("Name","relu_1")
convolution1dLayer(3,64,"Name","conv1d_2","Padding","same")
batchNormalizationLayer("Name","batchnorm_2")
reluLayer("Name","relu_2")
convolution1dLayer(3,64,"Name","conv1d_3","Padding","same")
batchNormalizationLayer("Name","batchnorm_3")
reluLayer("Name","relu_3")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
additionLayer(2,"Name","addition_1")
reluLayer("Name","relu_10")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
convolution1dLayer(3,128,"Name","conv1d_4","Padding","same")
batchNormalizationLayer("Name","batchnorm_4")
reluLayer("Name","relu_4")
convolution1dLayer(3,128,"Name","conv1d_5","Padding","same")
batchNormalizationLayer("Name","batchnorm_5")
reluLayer("Name","relu_5")
convolution1dLayer(3,128,"Name","conv1d_6","Padding","same")
batchNormalizationLayer("Name","batchnorm_6")
reluLayer("Name","relu_6")
convolution1dLayer(1,64,"Name","conv1d_10","Padding","same")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
additionLayer(2,"Name","addition_2")
reluLayer("Name","relu_11")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
convolution1dLayer(3,128,"Name","conv1d_7","Padding","same")
batchNormalizationLayer("Name","batchnorm_7")
reluLayer("Name","relu_7")
convolution1dLayer(3,128,"Name","conv1d_8","Padding","same")
batchNormalizationLayer("Name","batchnorm_8")
reluLayer("Name","relu_8")
convolution1dLayer(3,128,"Name","conv1d_9","Padding","same")
batchNormalizationLayer("Name","batchnorm_9")
reluLayer("Name","relu_9")
convolution1dLayer(1,64,"Name","conv1d_11","Padding","same")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
additionLayer(2,"Name","addition_3")
reluLayer("Name","relu_12")
globalAveragePooling1dLayer("Name","gapool1d")
fullyConnectedLayer(2,"Name","fc_final") % 将输出调整为2类
softmaxLayer("Name","softmax")
classificationLayer("Name","classoutput")];
lgraph = addLayers(lgraph,tempLayers);
% 清理辅助变量
clear tempLayers;
连接层分支
连接网络的所有分支以创建网络图。
lgraph = connectLayers(lgraph,"sequence","fc");
lgraph = connectLayers(lgraph,"sequence","conv1d_1");
lgraph = connectLayers(lgraph,"fc","addition_1/in1");
lgraph = connectLayers(lgraph,"relu_3","addition_1/in2");
lgraph = connectLayers(lgraph,"relu_10","conv1d_4");
lgraph = connectLayers(lgraph,"relu_10","addition_2/in1");
lgraph = connectLayers(lgraph,"conv1d_10","addition_2/in2");
lgraph = connectLayers(lgraph,"relu_11","conv1d_7");
lgraph = connectLayers(lgraph,"relu_11","addition_3/in1");
lgraph = connectLayers(lgraph,"conv1d_11","addition_3/in2");
这就是网络的整体架构,但是因为真实的数据还没有,所以还需要生成数据,因为论文的要求,生成的是5维特征向量组,为了计算方便,就选取了5x1000的矩阵代表无人机和飞鸟的特征向量。
完整代码如下
完整代码
clear;
clc;
% Step 1: 生成5x1000的矩阵数据
numSamples = 1000;
numFeatures = 5; % 原始每个样本的特征数为5
sequenceLength = 1000;
% 类别 1:生成5x1000的矩阵代表标签 1
X1 = randn(numFeatures, numSamples); % 模拟5x1000数据,类别1
% 类别 2:生成5x1000的矩阵代表标签 2
X2 = randn(numFeatures, numSamples); % 模拟5x1000数据,类别2
% 合并数据
X = [X1, X2]; % 5x2000的矩阵,总共有2000个样本
labels = [ones(1, numSamples), 2 * ones(1, numSamples)]; % 类别标签 1 和 2
% Step 2: 数据预处理
XTrain = num2cell(X, 1); % 将数据转换为元胞数组,每个元胞代表一个5x1的特征向量
YTrain = categorical(labels'); % 将标签转化为分类格式
% Step 3: 将数据分为90%训练集和10%验证集
idx = randperm(2 * numSamples);
numTrain = round(0.9 * numel(labels));
XTrainSet = XTrain(idx(1:numTrain)); % 选择90%的数据作为训练集
YTrainSet = YTrain(idx(1:numTrain));
XValidationSet = XTrain(idx(numTrain+1:end)); % 剩余10%作为验证集
YValidationSet = YTrain(idx(numTrain+1:end));
% Step 4: 定义网络结构
lgraph = layerGraph();
tempLayers = sequenceInputLayer(5,"Name","sequence");
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
convolution1dLayer(1,64,"Name","conv_projection","Padding","same")
batchNormalizationLayer("Name","batchnorm_projection")
reluLayer("Name","relu_projection")
convolution1dLayer(3,64,"Name","conv1d_1","Padding","same")
batchNormalizationLayer("Name","batchnorm_1")
reluLayer("Name","relu_1")
convolution1dLayer(3,64,"Name","conv1d_2","Padding","same")
batchNormalizationLayer("Name","batchnorm_2")
reluLayer("Name","relu_2")
convolution1dLayer(3,64,"Name","conv1d_3","Padding","same")
batchNormalizationLayer("Name","batchnorm_3")
reluLayer("Name","relu_3")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = fullyConnectedLayer(64,"Name","fc_2");
lgraph = addLayers(lgraph,tempLayers);
tempLayers = additionLayer(2,"Name","addition_1");
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
convolution1dLayer(3,128,"Name","conv1d_4","Padding","same")
batchNormalizationLayer("Name","batchnorm_4")
reluLayer("Name","relu_4")
convolution1dLayer(3,128,"Name","conv1d_5","Padding","same")
batchNormalizationLayer("Name","batchnorm_5")
reluLayer("Name","relu_5")
convolution1dLayer(3,128,"Name","conv1d_6","Padding","same")
batchNormalizationLayer("Name","batchnorm_6")
reluLayer("Name","relu_6")
convolution1dLayer(1,64,"Name","conv1d_10","Padding","same")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = additionLayer(2,"Name","addition_2");
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
convolution1dLayer(3,128,"Name","conv1d_7","Padding","same")
batchNormalizationLayer("Name","batchnorm_7")
reluLayer("Name","relu_7")
convolution1dLayer(3,128,"Name","conv1d_8","Padding","same")
batchNormalizationLayer("Name","batchnorm_8")
reluLayer("Name","relu_8")
convolution1dLayer(3,128,"Name","conv1d_9","Padding","same")
batchNormalizationLayer("Name","batchnorm_9")
reluLayer("Name","relu_9")
convolution1dLayer(1,64,"Name","conv1d_11","Padding","same")];
lgraph = addLayers(lgraph,tempLayers);
tempLayers = [
additionLayer(2,"Name","addition_3")
globalAveragePooling1dLayer("Name","gapool1d")
fullyConnectedLayer(2,"Name","fc_1")
softmaxLayer("Name","softmax")
classificationLayer("Name","classoutput")];
lgraph = addLayers(lgraph,tempLayers);
% 清理辅助变量
clear tempLayers;
% Step 5: 设置网络连接
lgraph = connectLayers(lgraph,"sequence","conv_projection");
lgraph = connectLayers(lgraph,"sequence","fc_2");
lgraph = connectLayers(lgraph,"fc_2","addition_1/in1");
lgraph = connectLayers(lgraph,"relu_3","addition_1/in2");
lgraph = connectLayers(lgraph,"addition_1","conv1d_4");
lgraph = connectLayers(lgraph,"addition_1","addition_2/in1");
lgraph = connectLayers(lgraph,"conv1d_10","addition_2/in2");
lgraph = connectLayers(lgraph,"addition_2","conv1d_7");
lgraph = connectLayers(lgraph,"addition_2","addition_3/in1");
lgraph = connectLayers(lgraph,"conv1d_11","addition_3/in2");
% Step 6: 设置训练选项
options = trainingOptions('adam', ...
'MaxEpochs', 600, ...
'MiniBatchSize', 32, ...
'InitialLearnRate', 1e-5, ...
'L2Regularization', 1e-6, ...
'ValidationData', {XValidationSet, YValidationSet}, ...
'ValidationFrequency', 30, ...
'Shuffle', 'every-epoch', ...
'Plots', 'training-progress', ...
'Verbose', false);
% Step 7: 训练网络
net = trainNetwork(XTrainSet, YTrainSet, lgraph, options);
% Step 8: 测试网络
YPred = classify(net, XTrain);
accuracy = sum(YPred == YTrain) / numel(YTrain);
disp(['Training Accuracy: ', num2str(accuracy * 100), '%']);
用的随机矩阵进行训练,所以结果也是在预料之中了
总结
在复现的过程中,遇到最多的问题就是网络结构运算之间的大小对不上,如果出现了报错,第一时间就应该去检查一下网络之间传递的参数是否合理。
参考文献
[1] 汪浩,窦贤豪,田开严,等.基于CNN的雷达航迹分类方法[J].舰船电子对抗,2023,46(05):70-74.DOI:10.16426/j.cnki.jcdzdk.2023.05.014.