资讯动态

MATLAB深度学习入门:从数据预处理到CNN搭建与迁移学习全流程

发布时间:2026/10/15 20:11:11 来源:尧图企业网站定制
先说结论如果你已经有一门主力语言比如日常做数据处理用的是MATLAB或者你只是想先搞懂深度学习的基本原理、动手跑通一个完整流程那MATLAB绝对值得你花两周左右认真走一遍。这篇文章记录的是我自己从零开始用MATLAB完成一次“深度学习入门之旅”的全过程包括环境准备、数据预处理、卷积网络搭建、训练监控、模型评估以及最后的迁移学习小实验。适合完全没接触过深度学习的新手也适合那些在Python框架里看了好多教程、但始终觉得“差点意思”的半入门同学。我当初纠结了很久深度学习教程十篇有九篇都在讲Python剩下的几篇也在劝人装环境、配依赖。可我的日常工作流基本都在MATLAB里矩阵操作、数据可视化、信号处理全在这一套工具里完成让我为一个教程去搭一套Python环境不是不行而是会额外分散注意力。后来我决定换个思路——直接在MATLAB里把深度学习的流程跑通。这个决定回头来看是对的因为MATLAB的深度学习工具箱把很多底层细节封装得非常好能让我把有限的精力放在理解“网络结构”和“训练逻辑”上而不是和编译环境斗智斗勇。1. 为什么选MATLAB走深度学习入门1.1 我踩过的第一个选择题坦白说最初我几乎要被劝退。朋友推荐的大多数学习资料都是基于某个开源框架写代码一开始就是“安装依赖”“下载CUDA”“配置环境变量”然后半天过去环境还没跑通。对于我这种已经有一门熟练工具的人来说这种起步方式非常难受。这就要说到MATLAB一个特别重要的定位它不是一个专门为深度学习设计的框架而是一个科学计算环境深度学习只是它众多工具箱里的一个。这个定位决定了它的入门思路和开源框架完全不同。在MATLAB里做深度学习你更像是在“用工程工具完成一个AI任务”而不是“先学会一套编程范式再搭建一个模型”。我当时给自己列了一个简单的对比开源框架路线学Python基础 - 学某个深度学习框架语法 - 折腾环境 - 才能开始理解模型本身。MATLAB路线直接打开图像分类示例 - 看懂函数 - 替换成自己的数据 - 跑通 - 再回头看理论。最后选了第二条路。事实证明这条路让我在两周内就建立起了对深度学习的整体认识包括数据流、损失函数、训练过程这些原来觉得很抽象的概念都在具体的图表和曲线里变得非常直观。1.2 MATLAB深度学习工具箱到底适合谁我的体验是MATLAB深度学习工具最适合三类人。第一类是像我这样本来就有MATLAB使用习惯的工程师和科研人员。不需要切换主语言工具箱的API风格和普通MATLAB函数非常接近学习成本极低。第二类是希望在短时间内理解深度学习完整工作流的初学者。因为MATLAB的示例和相关文档做得非常细致自带配套的公共数据集基本没人能在不给代码的情况下跑偏这对建立信心非常重要。第三类是需要在代码里加入信号处理或传统数值计算逻辑的人。深度学习模型在MATLAB里可以直接调用矩阵计算、滤波、傅里叶变换等函数来配合做数据预处理这套体系的成熟度是绝大多数开源框架比不了的。当然它也有明显的局限后面我会专门说但就“入门”这件事而言它的低门槛特性确实让人少踩了非常多冤枉路。2. 环境准备与数据获取先让“原料”到位2.1 工具箱安装与版本坑我在安装时遇到过一个很典型的问题在功能栏里搜“Deep Learning Toolbox”点了安装结果弹出提示说要同时装一个“Parallel Computing Toolbox”我当时一度以为装错了后来才知道MATLAB的深度学习工具箱在做训练时默认走并行计算那一套接口虽然不装也能在CPU上跑但装了它才能更好利用多核和GPU资源。提示最好确认一下自己的MATLAB版本不能太老某几个老版本对深度网络训练的支持非常有限升级一下工具箱通常就能解决大部分兼容问题。我的建议是下载那些体积比较大的工具箱时先确认磁盘空间至少预留十几个G。我记得自己第一次没注意安装到一半提醒磁盘空间不足还要重新清理、重新装非常浪费时间。如果你有GPU还要提前装好对应的显卡驱动MATLAB文档里有明确的设备兼容列表这个别凭感觉来。2.2 手写数字数据集从哪里来、怎么读入门用的标准数据集是手写数字图像集这是深度学习领域的“Hello World”每个样本是一张28x28的灰度图对应0到9中的一个数字。MATLAB的深度学习示例直接集成了这个数据集一行代码就能完成下载和加载非常省心。不过我更推荐自己手动下载一次并整理成文件夹结构因为实际项目中你拿到的数据大概率不会是一键下载的。你需要理解一个核心概念在MATLAB里处理图像分类问题最常用的数据入口是imageDatastore。这个函数会自动扫描指定文件夹下的所有图片并根据子文件夹的名字自动生成标签。我当时把公共数据分别放在两个目录训练集文件夹每个数字一个子文件夹共10个子文件夹。验证集/测试集文件夹同样结构但是我单独留出来的。读取训练集的代码是这个样子的imdsTrain imageDatastore(fullfile(dataRoot, train), ... IncludeSubfolders, true, ... LabelSource, foldernames);IncludeSubfolders参数意味着递归读取所有子文件夹里的图片LabelSource指定“foldernames”也就是用子文件夹的名字作为类别标签。我一开始漏了这个参数结果imdsTrain.Labels全是空的后来对着文档检查才发现这个参数直接影响标签是否被正确生成。标签生成后最好看一眼分布情况countEachLabel(imdsTrain)这个函数会输出每个类别的样本数。我第一次跑出结果时发现每个数字的样本数基本一样说明这个数据集是均衡的。实际项目中如果某个类别的图片特别多、另一个类别特别少模型很容易偏向数量多的类别这时候要么做数据增强补少样本类别要么考虑加权损失函数。在入门阶段均衡数据能帮你少操很多心。2.3 拆分验证集与测试集准备数据时还有个特别容易搞混的点验证集和测试集不是一回事。验证集是在训练过程中用于监控模型表现、判断是否过拟合的数据测试集则是在训练结束后用来模拟“模型没见过的新数据”去评估最终泛化能力的数据。imageDatastore提供了一种很方便的拆分方式[imdsTrain, imdsVal, imdsTest] splitEachLabel(imdsAll, 0.7, 0.15, 0.15, randomized);这里的意思是每个类别内部随机按7:1.5:1.5的比例切三份。randomized参数很关键加了它才会在拆分前随机打乱数据否则直接按顺序切分很可能导致同一个类别的样本全部集中到某个子集里。注意验证集和测试集一旦切出来在整个实验周期内就不要再动了。我后来犯过一个低级错误为了多拿点训练数据把验证集也并回去重新切结果每次训练结果都不一样还以为是模型问题。3. 数据预处理不是所有图片都能直接喂进网络3.1 图像尺寸统一深度学习网络不是“什么尺寸都能吃”的输入层需要固定的输入尺寸。例如我后面搭建的网络输入是[28 28 1]代表高28像素、宽28像素、1个通道的灰度图。如果图片尺寸不统一训练会直接报错。augmentedImageDatastore是处理这个问题的主力augimdsTrain augmentedImageDatastore([28 28], imdsTrain); augimdsVal augmentedImageDatastore([28 28], imdsVal); augimdsTest augmentedImageDatastore([28 28], imdsTest);它会自动把输入图片的尺寸调整到28x28并且在读取时有一个“按需变换”的机制也就是每次迭代读取图片时才进行处理不需要把所有图片一次性全部加载到内存里。这个设计对大数据集非常友好不会一上来就把内存吃满。3.2 归一化问题像素值必须缩到合理范围刚接触时容易忽略一个细节原始图片的像素值范围是0到255而很多网络设计时默认输入数据的数值范围是0到1或者是以0为中心的某种分布。如果直接喂0到255的原始像素值梯度计算很容易不稳定训练Loss可能出现NaN。如果是自己搭建简单网络可以在数据加载后除以255也可以利用imageInputLayer的Normalization参数来实现。imageInputLayer([28 28 1], Normalization, rescale-zero-one)这样输入层会在数据进入网络之前自动完成像素归一化。我后来在自建网络和迁移学习里都用了这个参数省了不少事。实践中最让我印象深刻的是一次尝试中我忘了归一化训练Loss在前几步就直接飘到了几千然后变成NaN最后花了半天时间排查才发现根源。3.3 数据增强把“熟人”变“新人”在训练数据量不够多或者模型明显过拟合的时候数据增强非常实用。augmentedImageDatastore支持在读取图片时同步做随机平移、旋转、缩放、翻转等操作相当于每轮迭代看到的图片都不完全一样能有效提升模型的泛化能力。我试着加了平移和翻转imageAugmenter imageDataAugmenter( ... RandXTranslation, [-3 3], ... RandYTranslation, [-3 3], ... RandXReflection, true); augimdsTrain augmentedImageDatastore([28 28], imdsTrain, ... DataAugmentation, imageAugmenter);这里注意验证集和测试集绝对不能加数据增强。因为验证集的作用是反映模型在“真实数据分布”上的表现如果你也对验证集做随机变换那每次验证的结果都会波动完全失去监控意义。我在网上看到不少人犯过这个错误需要特别警惕。数据增强也不是越多越好。过度增强会让模型的训练难度变得极大甚至收敛不了。合理的策略是先不加增强跑一版基线确认出现过拟合迹象后再逐步增加增强强度。4. 搭建第一个卷积网络从“层”理解深度学习4.1 网络层的堆积刚开始学神经网络时总有人告诉我说“网络就是一层层叠起来”但我始终没法直观理解“层”到底在干什么。后来在MATLAB里一行一行写layers变量时那种“堆积层”的感觉非常强烈。层与层之间像流水线一样前一层输出的特征图就是后一层的输入最后输出一个概率分布用来判断图片属于哪个类别。我搭建的入门卷积网络是这样的layers [ imageInputLayer([28 28 1], Normalization, rescale-zero-one) convolution2dLayer(3, 8, Padding, same) batchNormalizationLayer reluLayer maxPooling2dLayer(2, Stride, 2) convolution2dLayer(3, 16, Padding, same) batchNormalizationLayer reluLayer maxPooling2dLayer(2, Stride, 2) convolution2dLayer(3, 32, Padding, same) batchNormalizationLayer reluLayer fullyConnectedLayer(10) softmaxLayer classificationLayer];我用的是3x3卷积核因为小卷积核配合多层堆叠是现在最常用的设计思路既能减少参数量又能获得足够大的感受野。Padding,same保证卷积输出尺寸和输入尺寸一致这样特征图的长宽不会被不断压缩每两个卷积层之后接一个最大池化层把特征图的尺寸减半逐步提取更高层次的语义信息。关于卷积层的参数convolution2dLayer(3, 8)这里的3是卷积核大小8是输出通道数也就是这一层会提取多少个不同的特征图。第一层输出8个通道第二层16个第三层32个这种逐层增加通道数的做法是为了让网络在高层能够组合出更丰富的模式。4.2 为什么需要批归一化和ReLUbatchNormalizationLayer的作用是让每一层的输入分布保持在比较稳定的范围内。以前没有这个层时网络层数一深训练就容易出问题前面层的参数稍微一变后面层的输入分布就会产生较大的波动收敛很慢。加了它之后整个网络的训练稳定性会大幅提升。reluLayer则是把线性输出转换为非线性否则层叠得再多数学上跟一层也没什么区别。ReLU就是一个很简单的规则负数清零正数保留原值。我刚开始觉得这太简单了后来才理解就是这种简单的非线性让卷积网络具备了拟合非常复杂函数的能力。4.3 全连接层与分类层到最后特征图被展平送入fullyConnectedLayer(10)也就是输出10个数值对应0到9十个类别。这个数值经过softmaxLayer变成概率分布总和为1。最后classificationLayer负责计算损失值驱动反向传播更新权重。第一次自己搭完网络时我心里其实完全没底但MATLAB提供了一个特别好的工具analyzeNetwork。它会把整个网络的结构画出来每一层的名称、输出尺寸、参数量都显示得清清楚楚。我用它检查网络发现第一层输入是28x28x1经过三层卷积池化后变成4x4x32展平后就是4*4*32512个特征最后接全连接输出10类整个数据流动的过程一目了然。经验每次修改完网络结构都先跑一遍analyzeNetwork再训练能省掉大量“维数不匹配”的报错时间。5. 训练配置跑起来之前必须搞懂的参数5.1 trainingOptions参数表训练一个网络不仅仅是调用trainNetwork那么简单。在此之前需要先配置一堆训练参数其中最核心的几个我整理在一个表里参数名作用我的入门设置说明solver优化算法sgdm带动量的随机梯度下降收敛稳定InitialLearnRate初始学习率0.01控制每次梯度更新的步长MaxEpochs训练轮数10每个样本看10遍MiniBatchSize每个批次样本数128一次迭代用128张图ValidationData验证集验证用增强数据用于训练中实时监控ValidationFrequency每多少次迭代验证一次30太频繁会拖慢训练Plots是否显示训练图training-progress能看到实时曲线Verbose命令行是否打印false命令行打印太多刷屏实际配置代码是options trainingOptions(sgdm, ... InitialLearnRate, 0.01, ... MaxEpochs, 10, ... MiniBatchSize, 128, ... ValidationData, augimdsVal, ... ValidationFrequency, 30, ... Shuffle, every-epoch, ... Plots, training-progress, ... Verbose, false);Shuffle参数的意思是在每个轮次开始前打乱训练数据顺序防止模型学习到数据顺序里的虚假规律。5.2 训练过程监控窗口到底看什么第一次点下“运行训练”按钮后屏幕上会弹出一个训练进度窗口里面有两条曲线一条是训练集的损失另一条是验证集的准确率。这些曲线的读取方式非常直观训练损失下降说明网络正在学习。验证准确率上升说明学到的东西是泛化的。训练损失非常低、验证准确率却止步不前这就是典型的过拟合。训练损失一开始就高或者波动剧烈这多半是学习率过大。我第一次跑通时看到训练损失从2.3一路掉到0.05验证准确率最终达到98%以上那种“原来训练过程是这样的”的震撼感现在还记得特别清楚。这里面有一个细节值得说训练损失是每轮迭代都在更新的而验证准确率是按ValidationFrequency间隔才计算一次所以验证曲线看起来会有一个台阶式的上升这不是BUG是采样频率不一致。5.3 我的第一次训练记录那次我用了最大轮数10轮一个批次128张图整个训练集大概有几千张图算下来每轮大概几十次迭代。在CPU上跑全程大约几分钟。如果不用Plots,training-progress参数整个训练过程就像在黑箱里进行我只能看到最后的结果这非常不利于理解过程。把训练过程可视化出来还有一个好处当你想调整任何参数时能立刻看到调整的效果形成一种“实验-观察-改进”的正循环这对培养训练直觉特别重要。6. 模型评估准确率之外还能看到什么6.1 算准确率并保留完整输出训练完成后模型对象里保存了学到的所有参数。用它对新数据进行预测只需要一行代码YPred classify(net, augimdsTest); YTest imdsTest.Labels; accuracy mean(YPred YTest);这里classify会返回每个测试样本对应的预测类别YPred YTest会生成一个逻辑数组mean就是正确率。我那次测试集准确率大约在98%左右在一开始已经很有成就感了。但准确率只是第一印象。深度学习中准确率本身会掩盖很多细节比如某个类别识别得好、某个类别经常混淆。这就需要用混淆矩阵来看。6.2 混淆矩阵一眼看出网络“哪里笨”figure confusionchart(YTest, YPred);confusionchart画出的矩阵是一个10x10的表格横轴是预测标签纵轴是真值标签。对角线上的数字是每个类别的正确预测数非对角线上的数字则是犯错次数。比如我在看结果时发现数字“4”和“9”之间有过一些混淆原因是这两个手写体形状非常相似特别是某些人的写法中顶部几乎一模一样。矩阵中某一类被另一类系统性误判时往往说明特征或数据本身相似度高处理办法通常是增加这类样本量或者增强这部分特征的表达能力。6.3 随机挑错题可视化预测样本只看数字还不够直观。我后来加了几行代码随机选了几十张测试图片把图片本身和预测结果一起画出来然后单独列出预测错误的样本。这些错误样本让你直观地看到网络为什么会错——有些图片本身写得潦草有些模糊到人眼都难判断。这个过程极大缓解了我对模型“错误”的焦虑有些情况下人去分类可能也会错不是网络笨而是数据本身就存在不确定性。可视化代码如下idx find(YPred ~ YTest); figure for i 1:min(9, numel(idx)) subplot(3,3,i); imshow(imdsTest.Files{idx(i)}); title(sprintf(真值: %s, 预测: %s, ... char(YTest(idx(i))), char(YPred(idx(i))))); end这让我意识到一个重要的理念在真实项目中分类问题本质上是概率问题模型给出的只是“概率最大的选择”而不是“绝对正确的答案”。7. 踩坑记录那些让我浪费过时间的问题7.1 内存不足miniBatchSize是罪魁祸首我第一次尝试加载较大的彩色图像数据集时遇到Out of Memory的报错。当时的处理方式是直接用一个大数组把所有图片读入内存然后一次性喂给网络这显然是非常不合适的。深度学习中数据通常是分批读取的ministBatchSize决定了每次读取多少张图片。如果设的很大内存占用自然就高。解决办法非常简单调小miniBatchSize在我用的版本里图像数据增强读取器本身就设计成按批读取配合调小批次内存问题很快就消失了。这款经验延伸到任何数据集如果内存不足第一反应不应该是换机器、加内存条而是先看看能不能减少批量大小或者用流式读取方式。7.2 多次训练结果不一样随机性影响有段时间我发现每次重新训练最终准确率都有点波动。原因在于优化算法和网络初始化本身就是随机的而且数据增强也是随机的。如果想让结果可复现需要设置一个固定的随机种子rng(0);在训练前设置这个能确保每次生成的初始权重和数据打乱顺序一致。这个技巧在做对比实验时几乎等于必需品。7.3 学习率过大导致Loss变成NaN这是我遇到过最“吓人”的报错——训练进行到一半整个Loss曲线突然变成NaN。排查后定位到是学习率过大。学习率本质上决定了每一步参数更新“迈多大步子”步子太大直接在损失函数曲面上越过了合理的低谷一路滚下悬崖数值结果就变成NaN。我当时把0.01的学习率改到0.1试了一次结果前几步就崩了后来改成0.001训练过程明显更平滑。这个教训让我养成一个习惯遇到训练发散永远先把学习率调低一个数量级再试这是最省时间的排查思路。7.4 类别不平衡带来的偏差有一次我自己构造了一个二分类小数据集类别A的数量是类别B的十倍。训练结束后准确率有93%但仔细看混淆矩阵B类别几乎全被预测成了A。这就是样本不平衡导致模型“偷懒”去学占比大的类别的典型现象。处理办法是给少数类加权损失或对少数类做重复采样和数据增强。这个坑让我意识到准确率很高不一定说明模型真的有实用性必须结合矩阵和各类别指标一起看。8. 迁移学习零基础站在巨人肩膀上8.1 为什么迁移学习在MATLAB里特别顺手入门流程走完后我开始尝试用预训练网络解决新问题这就是迁移学习。因为深度学习模型的训练非常耗费算力预训练网络相当于别人已经在大规模数据上训练好了一个“通用特征提取器”你只需把它学会的特征拿过来替换掉最后的分类部分就可以用少量数据训练出新任务的模型。MATLAB里加载一个预训练模型非常直接net vgg16;这个网络已经在千万级图像数据集上预训练过它会自动下载模型文件保存在本地。之后可以用analyzeNetwork(net)查看网络整体结构。8.2 只替换最后几层预训练网络最后一层通常是一个与原来训练集类别数一致的全连接层。我在做某个自定义分类任务时只有5个类别所以需要把最后一层改成5路输出。这里要注意不同预训练网络的结构差异很大有些最后几层名字是fc8有些是loss3-classifier替换前必须先用analyzeNetwork确认当前网络的结构细节。我当时的做法是先把网络结构转换成可编辑的layerGraph对象lgraph layerGraph(net); newFC fullyConnectedLayer(5, Name, fc_new); lgraph replaceLayer(lgraph, fc8, newFC);替换全连接层后还需要更新最后一层的分类层类别数用new_classificationLayer替换原分类层。这里最容易犯的错误是只替换了全连接层、忘了替换分类层训练直接报错。所以我后来给自己定了一个检查流程每做一次网络结构修改第一件事永远是analyzeNetwork(lgraph)确认输出层信息是否正确。8.3 冻结前层与加速微调迁移学习通常有两种策略只训练替换后的新层或者让整个网络都参与微调。前一种策略适合数据量非常少的情况后一种适合数据量中等或较大且希望获得更好性能的情况。在MATLAB里可以先提取出网络层然后对不需要训练的那部分层设置学习率倍数为0layers lgraph.Layers; for i 1:numel(layers) if ~ismember(layers(i).Name, {fc_new,new_classification}) layers(i).WeightLearnRateFactor 0; layers(i).BiasLearnRateFactor 0; end end lgraphFinal layerGraph(layers);这样冻结后训练时只会更新新加入的那两层的参数训练速度极快即使数据量不大也能很快收敛。那次我只用了很少的图片大概训练了几个轮次准确率就直接超过了九成这给当时刚入门的我带来了很强的正向鼓励。9. 个人记录总结与实用建议这一段更像是我走完整趟后的“复盘”与建议希望能对准备走同样路的人有帮助。9.1 什么情况下MATLAB更合适我个人在实践中感受到的MATLAB深度学习优势主要有这几点环境自动化程度高不需要手工处理依赖关系对新手非常友好。文档与示例体系极为完善官方自带大量可直接运行的例子而且经常配有“解释为什么”的说明。网络可视化能力突出analyzeNetwork、训练进度窗口、混淆矩阵图表都能帮助构建直观认知。与其他工程能力的协同好能让深度学习处理和信号分析等需求结合。尤其是在做“教学演示”或“快速验证想法”时MATLAB的效率非常高。你说用开源框架是不是也可以当然可以但入门阶段本来就需要降低认知负担。9.2 MATLAB的短板我不避讳但我也不会推荐所有人一直只用MATLAB做深度学习有一些短板是客观存在的。部署不如开源生态灵活。虽然MATLAB支持代码生成和各类终端部署但和主流的轻量化模型部署工具链相比灵活性有差距。大型社区开源资源相对少。网络模型和神经网络结构很多前沿成果第一时间发布的源码可能不在MATLAB里。商业软件版本间兼容性有时让人头疼。不同版本之间的工具箱行为可能有差异对长期项目管理有影响。我的建议是入门和原理验证用MATLAB完全够用后续如果需要落地部署或者对接很多前沿技术可以考虑再花时间切换到其他框架到那时你已经理解了深度学习的核心逻辑切换成本会低很多。9.3 五条经验之谈最后分享几条我在这趟入门之旅里最有体感的经验。先用小数据、小网络把完整流程跑通一次再逐步扩大规模和复杂度。不要一上来就在大模型上硬跑。所有实验都记录参数与输出结果哪怕只是简单写在注释里。这个习惯能让你在回看之前的实验时有迹可循。学习率是深度学习中最值得调的超参数任何训练异常优先怀疑学习率。验证集和测试集一定要“独立”不要让它们以任何方式参与训练。不要急于追求准确率。先理解数据如何流入网络、损失如何更新权重、验证曲线如何反映泛化能力之后再谈调参技巧。我走完这趟MATLAB深度学习入门之旅最大的收获并不是做出了一个多复杂的模型而是终于把以前那些抽象概念——卷积、池化、批量归一化、学习率、过拟合、迁移学习——一个一个变成了眼前可以被观察和触摸的东西。实际上这种“亲手跑通完整流程”的体验比看再多的理论教程都来得重要。如果你也正纠结该从哪里起步不妨就按这个路径用两周时间把流程走完你再来判断这条路是不是值得。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑