CNN分类-卷积神经网络(Convolutional Neural Network)
源代码
CNN分类的用途介绍
什么是卷积神经网络(CNN)?
卷积神经网络(Convolutional Neural Network,简称CNN)是一种深度学习模型,特别擅长处理具有网格结构的数据,如图像。CNN通过卷积层、池化层和全连接层等结构,能够自动提取数据中的空间特征,广泛应用于计算机视觉和图像处理领域。
CNN的主要用途和应用场景
-
图像分类
- 应用示例:识别和分类图像中的物体,如猫、狗、车辆等。
- 解释:通过学习图像中的特征,CNN能够将图像准确分类到不同的类别中。
-
目标检测
- 应用示例:在图像中定位并识别多个物体,如自动驾驶中的行人和车辆检测。
- 解释:CNN能够识别图像中不同物体的位置和类别,实现精确的目标检测。
-
图像分割
- 应用示例:将图像分割成不同的区域,如医学影像中的器官分割。
- 解释:CNN通过像素级的分类,实现对图像的精细分割。
-
人脸识别
- 应用示例:识别和验证个人身份,如手机解锁、安防监控。
- 解释:CNN能够提取人脸特征,实现高准确度的人脸识别和验证。
-
图像生成
- 应用示例:生成逼真的图像,如生成对抗网络(GAN)中的图像合成。
- 解释:CNN能够学习图像的分布特征,生成高质量的新图像。
-
视频分析
- 应用示例:视频内容识别、行为分析、异常检测。
- 解释:CNN结合时间序列分析,能够处理和分析视频中的动态信息。
-
医疗影像分析
- 应用示例:自动检测癌症、分析X光片和MRI图像。
- 解释:CNN能够辅助医生快速、准确地分析医疗影像,提升诊断效率和准确性。
-
自动驾驶
- 应用示例:环境感知、路径规划、障碍物检测。
- 解释:CNN用于处理车辆周围的视觉信息,实现自动驾驶系统的感知与决策。
CNN的优势
- 自动特征提取:无需手工设计特征,CNN能够自动学习和提取数据中的有用特征。
- 空间不变性:通过卷积和池化操作,CNN具有一定的平移不变性,能够识别不同位置的物体。
- 参数共享:卷积核在整个输入数据上共享参数,减少了模型的参数数量,提升了训练效率。
- 深层结构:多层的网络结构能够捕捉数据中的复杂模式和高层次特征。
CNN的局限性
- 计算资源需求高:深层CNN需要大量的计算资源和内存,训练时间较长。
- 对旋转和尺度变化敏感:虽然CNN具有一定的平移不变性,但对旋转和尺度变化仍然敏感。
- 需要大量标注数据:训练高性能的CNN通常需要大量的标注数据,获取和标注数据成本较高。
- 过拟合风险:深层模型容易在小数据集上过拟合,需要有效的正则化和数据增强技术。
总结
卷积神经网络(CNN)作为深度学习领域的核心模型,在图像处理、计算机视觉、医疗诊断、自动驾驶等多个领域展现出强大的性能。通过其独特的结构和自动特征提取能力,CNN能够高效、准确地处理和分析复杂的视觉数据。然而,随着技术的发展,如何优化CNN的结构、提升其泛化能力、减少计算资源消耗,仍然是研究和应用中的重要课题。
带有详细中文注释的Matlab代码
%% 初始化
clear % 清除工作区中的所有变量
close all % 关闭所有打开的图形窗口
clc % 清除命令窗口的内容
warning off % 关闭警告信息
%% 读取数据
res = xlsread('数据集.xlsx'); % 从Excel文件中读取数据,存储在变量res中
%% 分析数据
num_class = length(unique(res(:, end))); % 计算类别数,假设最后一列为类别标签
num_dim = size(res, 2) - 1; % 计算特征维度(总列数减去类别列)
num_res = size(res, 1); % 计算样本总数,每一行代表一个样本
num_size = 0.7; % 设置训练集占数据集的比例为70%
res = res(randperm(num_res), :); % 随机打乱数据集顺序(提高模型泛化能力)
% 如果不需要打乱数据,可以注释掉上行代码
flag_conusion = 1; % 标志位为1,启用混淆矩阵绘制(要求Matlab 2018及以上版本)
%% 设置变量存储数据
P_train = []; % 初始化训练集输入特征
P_test = []; % 初始化测试集输入特征
T_train = []; % 初始化训练集目标输出
T_test = []; % 初始化测试集目标输出
%% 划分数据集
for i = 1 : num_class
mid_res = res((res(:, end) == i), :); % 提取当前类别的所有样本
mid_size = size(mid_res, 1); % 当前类别的样本数量
mid_tiran = round(num_size * mid_size); % 计算当前类别的训练样本数量(四舍五入)
% 将当前类别的训练样本添加到训练集
P_train = [P_train; mid_res(1: mid_tiran, 1: end - 1)]; % 训练集输入特征(除最后一列)
T_train = [T_train; mid_res(1: mid_tiran, end)]; % 训练集目标输出(最后一列)
% 将当前类别的测试样本添加到测试集
P_test = [P_test; mid_res(mid_tiran + 1: end, 1: end - 1)]; % 测试集输入特征
T_test = [T_test; mid_res(mid_tiran + 1: end, end)]; % 测试集目标输出
end
%% 数据转置
P_train = P_train'; % 转置训练集输入特征,使每列代表一个样本
P_test = P_test'; % 转置测试集输入特征
T_train = T_train'; % 转置训练集目标输出
T_test = T_test'; % 转置测试集目标输出
%% 得到训练集和测试样本个数
M = size(P_train, 2); % 训练集样本数量
N = size(P_test , 2); % 测试集样本数量
%% 数据归一化
[P_train, ps_input] = mapminmax(P_train, 0, 1); % 将训练集输入特征归一化到[0,1]范围
P_test = mapminmax('apply', P_test, ps_input); % 使用相同的归一化参数处理测试集输入特征
t_train = categorical(T_train)'; % 将训练集目标输出转换为分类类型,并转置
t_test = categorical(T_test )'; % 将测试集目标输出转换为分类类型,并转置
%% 数据平铺
% 将数据平铺成1维数据是一种处理方式
% 也可以平铺成2维数据,以及3维数据,需要修改对应模型结构
% 但是应该始终和输入层数据结构保持一致
p_train = double(reshape(P_train, num_dim, 1, 1, M)); % 将训练集数据重塑为4D张量,适应CNN输入
p_test = double(reshape(P_test , num_dim, 1, 1, N)); % 将测试集数据重塑为4D张量,适应CNN输入
%% 构造网络结构
layers = [
imageInputLayer([num_dim, 1, 1]) % 输入层,输入尺寸为[num_dim, 1, 1]
convolution2dLayer([2, 1], 16, 'Padding', 'same') % 卷积层,卷积核大小为2x1,生成16个卷积核,填充方式为'same'
batchNormalizationLayer % 批归一化层,加速训练和稳定网络
reluLayer % ReLU激活层,引入非线性
maxPooling2dLayer([2, 1], 'Stride', [2, 1]) % 最大池化层,池化窗口大小为2x1,步长为[2, 1]
convolution2dLayer([2, 1], 32, 'Padding', 'same') % 卷积层,卷积核大小为2x1,生成32个卷积核,填充方式为'same'
batchNormalizationLayer % 批归一化层
reluLayer % ReLU激活层
fullyConnectedLayer(num_class) % 全连接层,输出神经元数量等于类别数
softmaxLayer % Softmax层,将输出转换为概率分布
classificationLayer]; % 分类层,计算分类损失
%% 参数设置
options = trainingOptions('adam', ... % 使用Adam优化器
'MaxEpochs', 500, ... % 最大训练次数为500
'InitialLearnRate', 1e-3, ... % 初始学习率为0.001
'L2Regularization', 1e-4, ... % L2正则化参数,防止过拟合
'LearnRateSchedule', 'piecewise', ... % 学习率调度方式为分段
'LearnRateDropFactor', 0.1, ... % 学习率下降因子为0.1
'LearnRateDropPeriod', 400, ... % 每经过400个epoch,学习率下降
'Shuffle', 'every-epoch', ... % 每个epoch后打乱数据集
'ValidationPatience', Inf, ... % 关闭验证
'Plots', 'training-progress', ... % 绘制训练过程图
'Verbose', false); % 关闭详细训练信息输出
%% 训练模型
net = trainNetwork(p_train, t_train, layers, options); % 使用训练集数据和定义的网络结构训练CNN模型
%% 预测模型
t_sim1 = predict(net, p_train); % 使用训练集数据进行预测,得到预测概率
t_sim2 = predict(net, p_test ); % 使用测试集数据进行预测,得到预测概率
%% 反归一化
% 注意:由于使用的是分类层,predict函数输出的是类别概率,因此无需反归一化
% 这里使用vec2ind可能不适用于categorical类型,可以直接转换为类别索引
T_sim1 = vec2ind(t_sim1'); % 将训练集预测概率转换为类别索引
T_sim2 = vec2ind(t_sim2'); % 将测试集预测概率转换为类别索引
%% 性能评价
error1 = sum((T_sim1 == T_train)) / M * 100 ; % 计算训练集准确率
error2 = sum((T_sim2 == T_test )) / N * 100 ; % 计算测试集准确率
%% 绘制网络分析图
analyzeNetwork(layers) % 绘制网络结构图,便于理解网络层级和参数
%% 绘图
figure
plot(1: M, T_train, 'r-*', 1: M, T_sim1, 'b-o', 'LineWidth', 1) % 绘制训练集真实值与预测值对比图
legend('真实值', '预测值')
xlabel('预测样本')
ylabel('预测结果')
title({'训练集预测结果对比'; ['准确率=' num2str(error1) '%']}) % 设置图形标题,显示准确率
grid on % 显示网格
figure
plot(1: N, T_test, 'r-*', 1: N, T_sim2, 'b-o', 'LineWidth', 1) % 绘制测试集真实值与预测值对比图
legend('真实值', '预测值')
xlabel('预测样本')
ylabel('预测结果')
title({'测试集预测结果对比'; ['准确率=' num2str(error2) '%']}) % 设置图形标题,显示准确率
grid on % 显示网格
%% 混淆矩阵
if flag_conusion == 1
figure
cm_train = confusionchart(T_train, T_sim1); % 绘制训练集混淆矩阵
cm_train.Title = '训练集混淆矩阵';
cm_train.ColumnSummary = 'column-normalized'; % 列归一化显示
cm_train.RowSummary = 'row-normalized'; % 行归一化显示
figure
cm_test = confusionchart(T_test, T_sim2); % 绘制测试集混淆矩阵
cm_test.Title = '测试集混淆矩阵';
cm_test.ColumnSummary = 'column-normalized'; % 列归一化显示
cm_test.RowSummary = 'row-normalized'; % 行归一化显示
end
代码详细说明与注释
1. 初始化部分
clear
close all
clc
warning off
- 功能:清理工作环境,确保代码在干净的环境中运行。
clear
:清除所有变量,释放内存。close all
:关闭所有打开的图形窗口。clc
:清空命令窗口内容。warning off
:关闭所有警告信息,避免干扰输出。
2. 读取数据
res = xlsread('数据集.xlsx');
- 功能:从Excel文件中读取数据。
- 假设数据集位于“数据集.xlsx”文件中,每一行代表一个样本,最后一列为类别标签。
3. 分析数据
num_class = length(unique(res(:, end)));
num_dim = size(res, 2) - 1;
num_res = size(res, 1);
num_size = 0.7;
res = res(randperm(num_res), :);
flag_conusion = 1;
- 功能:
- 计算类别数(
num_class
),即数据集中不同类别的数量。 - 计算特征维度(
num_dim
),即数据集中除去类别标签的特征数量。 - 计算样本总数(
num_res
)。 - 设置训练集占数据集的比例为70%(
num_size
)。 - 随机打乱数据集顺序,增加模型的泛化能力。
- 设置标志位
flag_conusion
为1,表示启用混淆矩阵绘制。
- 计算类别数(
4. 设置变量存储数据
P_train = []; P_test = [];
T_train = []; T_test = [];
- 功能:初始化训练集和测试集的输入特征(
P_train
、P_test
)及目标输出(T_train
、T_test
)。
5. 划分数据集
for i = 1 : num_class
mid_res = res((res(:, end) == i), :);
mid_size = size(mid_res, 1);
mid_tiran = round(num_size * mid_size);
P_train = [P_train; mid_res(1: mid_tiran, 1: end - 1)];
T_train = [T_train; mid_res(1: mid_tiran, end)];
P_test = [P_test; mid_res(mid_tiran + 1: end, 1: end - 1)];
T_test = [T_test; mid_res(mid_tiran + 1: end, end)];
end
- 功能:
- 按类别循环,将每个类别的数据按比例划分为训练集和测试集。
- 训练集输入特征和目标输出分别存储在
P_train
和T_train
中。 - 测试集输入特征和目标输出分别存储在
P_test
和T_test
中。
6. 数据转置
P_train = P_train';
P_test = P_test';
T_train = T_train';
T_test = T_test';
- 功能:将数据转置,使每列代表一个样本,符合Matlab神经网络工具箱的输入要求。
7. 得到训练集和测试样本个数
M = size(P_train, 2);
N = size(P_test , 2);
- 功能:获取训练集(
M
)和测试集(N
)的样本数量。
8. 数据归一化
[P_train, ps_input] = mapminmax(P_train, 0, 1);
P_test = mapminmax('apply', P_test, ps_input);
t_train = categorical(T_train)';
t_test = categorical(T_test )';
- 功能:
- 使用
mapminmax
函数将输入特征归一化到[0,1]范围,提升训练效果。 - 使用相同的归一化参数处理测试集输入特征。
- 将类别标签转换为分类类型(
categorical
),并转置,适应分类任务的要求。
- 使用
9. 数据平铺
% 将数据平铺成1维数据是一种处理方式
% 也可以平铺成2维数据,以及3维数据,需要修改对应模型结构
% 但是应该始终和输入层数据结构保持一致
p_train = double(reshape(P_train, num_dim, 1, 1, M));
p_test = double(reshape(P_test , num_dim, 1, 1, N));
- 功能:
- 将训练集和测试集的数据重塑为4D张量,适应CNN的输入要求。
- 这里将数据平铺成1维数据,形成[num_dim, 1, 1, M]和[num_dim, 1, 1, N]的形状。
10. 构造网络结构
layers = [
imageInputLayer([num_dim, 1, 1]) % 输入层,输入尺寸为[num_dim, 1, 1]
convolution2dLayer([2, 1], 16, 'Padding', 'same') % 卷积层,卷积核大小为2x1,生成16个卷积核,填充方式为'same'
batchNormalizationLayer % 批归一化层,加速训练和稳定网络
reluLayer % ReLU激活层,引入非线性
maxPooling2dLayer([2, 1], 'Stride', [2, 1]) % 最大池化层,池化窗口大小为2x1,步长为[2, 1]
convolution2dLayer([2, 1], 32, 'Padding', 'same') % 卷积层,卷积核大小为2x1,生成32个卷积核,填充方式为'same'
batchNormalizationLayer % 批归一化层
reluLayer % ReLU激活层
fullyConnectedLayer(num_class) % 全连接层,输出神经元数量等于类别数
softmaxLayer % Softmax层,将输出转换为概率分布
classificationLayer]; % 分类层,计算分类损失
- 功能:定义卷积神经网络的各个层级结构。
- imageInputLayer:定义输入层,输入尺寸为[num_dim, 1, 1],适用于1维数据。
- convolution2dLayer:定义卷积层,卷积核大小为2x1,生成16个和32个卷积核,使用’same’填充保持输出尺寸。
- batchNormalizationLayer:批归一化层,帮助加速训练和稳定网络。
- reluLayer:ReLU激活层,引入非线性,提高模型表达能力。
- maxPooling2dLayer:最大池化层,池化窗口大小为2x1,步长为[2, 1],减少特征图尺寸。
- fullyConnectedLayer:全连接层,输出神经元数量等于类别数,用于最终分类。
- softmaxLayer:Softmax层,将全连接层的输出转换为概率分布。
- classificationLayer:分类层,计算分类损失并进行反向传播。
11. 参数设置
options = trainingOptions('adam', ... % 使用Adam优化器
'MaxEpochs', 500, ... % 最大训练次数为500
'InitialLearnRate', 1e-3, ... % 初始学习率为0.001
'L2Regularization', 1e-4, ... % L2正则化参数,防止过拟合
'LearnRateSchedule', 'piecewise', ... % 学习率调度方式为分段
'LearnRateDropFactor', 0.1, ... % 学习率下降因子为0.1
'LearnRateDropPeriod', 400, ... % 每经过400个epoch,学习率下降
'Shuffle', 'every-epoch', ... % 每个epoch后打乱数据集
'ValidationPatience', Inf, ... % 关闭验证
'Plots', 'training-progress', ... % 绘制训练过程图
'Verbose', false); % 关闭详细训练信息输出
- 功能:设置训练选项,定义训练过程中的参数和行为。
- ‘adam’:选择Adam优化器,加速收敛。
- ‘MaxEpochs’:设置最大训练次数为500。
- ‘InitialLearnRate’:设置初始学习率为0.001。
- ‘L2Regularization’:设置L2正则化参数为1e-4,防止模型过拟合。
- ‘LearnRateSchedule’:设置学习率调度方式为分段。
- ‘LearnRateDropFactor’:学习率下降因子为0.1。
- ‘LearnRateDropPeriod’:每经过400个epoch,学习率下降。
- ‘Shuffle’:每个epoch后打乱数据集,提升模型泛化能力。
- ‘ValidationPatience’:关闭验证,不进行早停策略。
- ‘Plots’:绘制训练过程图,实时监控训练进展。
- ‘Verbose’:关闭详细训练信息输出,减少控制台信息量。
12. 训练模型
net = trainNetwork(p_train, t_train, layers, options);
- 功能:使用训练集数据和定义的网络结构训练CNN模型。
p_train
:训练集输入数据。t_train
:训练集目标输出。layers
:定义的网络层级结构。options
:训练选项参数。
13. 预测模型
t_sim1 = predict(net, p_train);
t_sim2 = predict(net, p_test );
- 功能:
- 使用训练好的CNN模型对训练集和测试集进行预测,得到预测概率。
t_sim1
:训练集的预测概率。t_sim2
:测试集的预测概率。
14. 反归一化
% 注意:由于使用的是分类层,predict函数输出的是类别概率,因此无需反归一化
% 这里使用vec2ind可能不适用于categorical类型,可以直接转换为类别索引
T_sim1 = vec2ind(t_sim1'); % 将训练集预测概率转换为类别索引
T_sim2 = vec2ind(t_sim2'); % 将测试集预测概率转换为类别索引
- 功能:将预测概率转换为类别索引。
vec2ind
:将概率向量转换为类别索引,取概率最大的类别作为预测结果。- 注意:由于
predict
输出的是概率分布,需确保转换方法与输出格式匹配。
15. 性能评价
error1 = sum((T_sim1 == T_train)) / M * 100 ; % 计算训练集准确率
error2 = sum((T_sim2 == T_test )) / N * 100 ; % 计算测试集准确率
- 功能:
- 计算训练集和测试集的分类准确率(百分比)。
error1
:训练集准确率。error2
:测试集准确率。
16. 绘制网络分析图
analyzeNetwork(layers)
- 功能:绘制网络结构图,便于理解网络层级和参数设置。
17. 绘图
figure
plot(1: M, T_train, 'r-*', 1: M, T_sim1, 'b-o', 'LineWidth', 1) % 绘制训练集真实值与预测值对比图
legend('真实值', '预测值')
xlabel('预测样本')
ylabel('预测结果')
title({'训练集预测结果对比'; ['准确率=' num2str(error1) '%']}) % 设置图形标题,显示准确率
grid on % 显示网格
figure
plot(1: N, T_test, 'r-*', 1: N, T_sim2, 'b-o', 'LineWidth', 1) % 绘制测试集真实值与预测值对比图
legend('真实值', '预测值')
xlabel('预测样本')
ylabel('预测结果')
title({'测试集预测结果对比'; ['准确率=' num2str(error2) '%']}) % 设置图形标题,显示准确率
grid on % 显示网格
- 功能:
- 绘制训练集和测试集的真实值与预测值对比图,直观展示分类效果。
- 在图形标题中显示分类准确率。
legend
:添加图例,区分真实值和预测值。xlabel
、ylabel
:设置X轴和Y轴标签。title
:设置图形标题,显示准确率。grid on
:显示网格,便于观察数据趋势。
18. 混淆矩阵
if flag_conusion == 1
figure
cm_train = confusionchart(T_train, T_sim1); % 绘制训练集混淆矩阵
cm_train.Title = '训练集混淆矩阵';
cm_train.ColumnSummary = 'column-normalized'; % 列归一化显示
cm_train.RowSummary = 'row-normalized'; % 行归一化显示
figure
cm_test = confusionchart(T_test, T_sim2); % 绘制测试集混淆矩阵
cm_test.Title = '测试集混淆矩阵';
cm_test.ColumnSummary = 'column-normalized'; % 列归一化显示
cm_test.RowSummary = 'row-normalized'; % 行归一化显示
end
- 功能:
- 如果
flag_conusion
为1,则绘制训练集和测试集的混淆矩阵。 - 混淆矩阵有助于评估分类器在不同类别上的表现,特别是对不平衡数据集的分类效果。
confusionchart
:创建混淆矩阵图表,显示真实类别与预测类别之间的关系。ColumnSummary
、RowSummary
:设置混淆矩阵的列和行的归一化显示,便于比较分类器在不同类别上的表现。
- 如果
总结
通过上述代码,您可以使用Matlab实现一个基于卷积神经网络(CNN)的分类模型。详细的中文注释帮助您理解每一步的具体操作和实现逻辑。该CNN模型适用于各种分类任务,特别是在处理具有空间特征的数据(如图像)时表现出色。根据具体需求,您可以调整网络结构、卷积核大小、神经元数量和训练参数,以优化模型性能和适应不同的应用场景。