简介:这份资源面向具备一定MATLAB基础、希望将深度学习应用于地球物理信号处理的学习者与研究人员,核心是用卷积神经网络完成地震等级预测任务。压缩包共33个文件,以30个m脚本为主,辅以2个mat数据文件和1个xlsx表格,整体约370KB,涵盖网络定义、参数初始化、前向与反向传播、梯度数值校验、数据预处理与超参数组合搜索等模块,结构完整、便于逐层拆解学习。已有351人学习下载,说明该方向具备一定关注度。读者可借此掌握从地震时间序列的标准化、降噪、时频分析到CNN特征提取与分类的完整链路,理解卷积层、池化层、全连接层与激活函数的协作方式,并借助梯度检查与随机种子设定保证实验可复现。对于想用MATLAB深度学习工具箱开展地震信号分析与风险等级评估的读者,这是一份可直接运行、便于二次调参的实践参考。
1. 地震等级预测遇上 MATLAB CNN:这套 30 多个文件的源码包到底能跑出什么
地震等级预测这件事,传统做法大多停留在统计回归和经验公式上,特征靠人挑,阈值靠人调,换一批台站数据就得重来一遍。这套基于 MATLAB 编程的卷积神经网络 CNN 地震等级预测源码包,走的是另一条路:把地震信号当成可学习的特征图,用卷积核自动提取波形里的局部模式,再通过全连接层做等级分类。整个包解压后是 30 多个 .m 文件加一个 datan.mat 数据文件和一个 net_cnn.mat 预训练网络,没有花哨的工程封装,全是裸函数调用,适合想看清 CNN 每一层到底在算什么的人。
它解决的核心问题是:给你一套能跑通的前向传播、反向传播、梯度检查、数据预处理和可视化流程,让你在 MATLAB 里从零搭出一个可训练、可验证的 CNN,而不是调一个黑匣子工具箱。适合两类人:一是做地震信号分析、想引入深度学习但不想被 Python 生态绑住的研究生和工程师;二是想通过读源码理解 CNN 底层实现、不满足于trainNetwork一行命令的开发者。前提是你机器上得有 MATLAB,且对矩阵运算和函数句柄不陌生。
2. 拆开卷积.rar:从 main.m 入口到 cnnsetup.m 初始化的调用链
2.1 文件清单与模块职责划分
拿到这个包,第一件事不是急着跑 main.m,而是先把文件按职责分堆。我一般会按下面这张表过一遍,心里有数了再动手,不然报错时连该看哪个文件都不知道。
| 文件 | 职责 | 调用关系 |
|---|---|---|
| main.m | 项目入口,串联数据加载、网络构建、训练、预测 | 调用 cnnsetup、cnntrain、cnnff |
| CNN.m | 网络定义与训练过程封装 | 被 main 调用 |
| cnnsetup.m | 初始化滤波器大小、步长、填充、层数 | 被 main 调用 |
| cnnff.m | 前向传播,逐层计算激活值 | 被 cnntrain、cnntest 调用 |
| cnnbp.m | 反向传播,计算梯度并更新权重 | 被 cnntrain 调用 |
| cnntrain.m | 训练主循环,控制迭代次数与学习率 | 调用 cnnff、cnnbp |
| cnnapplygrads.m | 将梯度应用到权重 | 被 cnntrain 调用 |
| cnnnumgradcheck.m | 数值梯度检查,验证反向传播正确性 | 独立调用 |
| cnnnumgradcheck.m | 数值梯度校验 | 调试用 |
| datan.mat | 地震信号数据 | 被 main 加载 |
| net_cnn.mat | 预训练网络参数 | 可加载做推理 |
| expand.m | 数据增强或维度扩展 | 预处理阶段 |
| normalize.m / zscore.m | 标准化与零均值化 | 预处理阶段 |
| whiten.m | 白化处理 | 预处理阶段 |
| patches2im.m / im2patches.m | 图像块与图像互转 | 卷积实现辅助 |
| makeLMfilters.m | 生成滤波器组 | 初始化阶段 |
| visualize.m | 权重与特征图可视化 | 训练后分析 |
| allcomb.m | 超参数组合生成 | 网格搜索 |
| randp.m / rnd.m | 随机数控制 | 可复现性 |
| sigm.m / sigmrnd.m / tanh_opt.m | 激活函数 | 前向传播 |
| fliplrf.m / flipall.m / flipudf.m | 翻转操作 | 卷积/池化辅助 |
| isOctave.m / myOctaveVersion.m | 环境检测 | 兼容性 |
| flicker.m | 可能用于数据抖动 | 预处理 |
| randcorr.m | 随机相关矩阵 | 数据生成 |
这张表不是让你背,而是让你在遇到Undefined function时能快速定位。比如报错说cnnff未定义,那大概率是路径没加全,而不是文件缺失。
2.2 从 main.m 入手理清执行顺序
main.m 是整个项目的入口,我习惯先把它读一遍,把里面调用的函数按顺序标出来。典型的结构是这样的:
% main.m 典型结构(基于包内文件推断) load('datan.mat'); % 加载地震信号数据 data = normalize(data); % 标准化,消除量纲影响 data = zscore(data); % 零均值化,加速收敛 % 可选:data = whiten(data); % 白化,降低特征冗余 cnn = cnnsetup([输入维度, 卷积层配置, 全连接层配置]); % 初始化网络 cnn = cnntrain(cnn, data, labels, opts); % 训练 pred = cnntest(cnn, testData); % 预测 visualize(cnn); % 可视化权重这段代码的逻辑很直白:先加载数据,做两步预处理,然后初始化网络结构,接着训练,最后预测和可视化。参数说明上,cnnsetup的输入是一个向量,描述每层的类型和尺寸;cnntrain的opts通常包含学习率、批量大小、迭代次数。如果你拿到的是net_cnn.mat已经训练好的网络,可以跳过cnntrain,直接load后调cnntest。
提示:第一次跑不要直接上全量数据,先把
datan.mat里的样本数砍到几十条,确认整条链路能通,再放全量。这样调试成本低得多。
2.3 cnnsetup.m 里的参数到底怎么设
cnnsetup是网络结构的定义处,也是新手最容易翻车的地方。它通常接收一个描述各层尺寸的向量,比如[28 28 6 2 12 2 100 10]这种形式,分别代表输入图像尺寸、卷积核数量、下采样比例、全连接层神经元数、输出类别数。具体到这份源码,你需要打开cnnsetup.m看它怎么解析这个向量。
常见做法是:输入层尺寸要和你的地震信号切片大小一致。如果datan.mat里每个样本是 1×N 的时间序列,你可能需要先用expand.m或im2patches.m把它转成二维或三维形式,才能喂给卷积层。卷积核数量从 6 或 12 起步,太多容易过拟合,太少提取不出特征。下采样比例一般取 2,即每 2×2 区域取一个值。全连接层神经元数 100 左右是常见起点,输出层等于地震等级类别数。
% cnnsetup.m 中常见的参数解析逻辑 inputSize = layerSizes(1); % 输入维度 numFilters = layerSizes(2); % 卷积核数量 poolSize = layerSizes(3); % 池化窗口大小 hiddenSize = layerSizes(4); % 全连接层神经元数 numClasses = layerSizes(5); % 输出类别数参数改动的原则是:先固定其他,只调一个。比如先调卷积核数量,从 6 到 12 到 24,看验证集准确率怎么变。不要一次性把学习率、批量大小、卷积核数量全改了,那样出了好结果你也不知道是哪个参数起了作用。
3. 前向传播与反向传播:cnnff.m 和 cnnbp.m 的矩阵维度对齐
3.1 cnnff.m 逐层计算与激活函数选择
cnnff做的是前向传播,从输入层开始,逐层做卷积、激活、池化,直到输出层。这份源码里激活函数有sigm.m、sigmrnd.m、tanh_opt.m三个可选。sigm是标准 Sigmoid,输出在 0 到 1 之间;tanh_opt是优化过的双曲正切,输出在 -1 到 1 之间,通常收敛更快。我一般会先用tanh_opt,如果训练后期梯度消失严重,再换回sigm试试。
% cnnff.m 核心逻辑示意 for l = 2 : numLayers if strcmp(layerType{l}, 'conv') z = convn(a{l-1}, W{l}, 'valid') + b{l}; % 卷积加偏置 a{l} = tanh_opt(z); % 激活 elseif strcmp(layerType{l}, 'pool') a{l} = pool(a{l-1}, poolSize); % 池化 elseif strcmp(layerType{l}, 'fc') z = W{l} * a{l-1} + b{l}; % 全连接 a{l} = tanh_opt(z); end end这段代码的关键在于矩阵维度必须对齐。convn的'valid'模式会让输出尺寸缩小,如果你在cnnsetup里算错了下一层的输入维度,这里就会报Matrix dimensions must agree。解决办法是在cnnsetup里逐层推算尺寸,或者先用一个极小样本跑一遍cnnff,看每一层a{l}的 size 是否合理。
3.2 cnnbp.m 梯度计算与 cnnapplygrads.m 更新
反向传播是训练的核心,cnnbp负责从输出层往回算误差,cnnapplygrads负责把算出来的梯度乘上学习率更新到权重上。这两步分开写的好处是你可以单独检查梯度,而不影响权重。
% cnnbp.m 核心逻辑示意 delta{numLayers} = (a{numLayers} - labels) .* dactivation(z{numLayers}); for l = numLayers-1 : -1 : 2 if strcmp(layerType{l}, 'conv') delta{l} = backpropConv(delta{l+1}, W{l+1}, a{l}); elseif strcmp(layerType{l}, 'pool') delta{l} = backpropPool(delta{l+1}, poolSize); elseif strcmp(layerType{l}, 'fc') delta{l} = (W{l+1}' * delta{l+1}) .* dactivation(z{l}); end end % 计算权重梯度 for l = 2 : numLayers dW{l} = delta{l} * a{l-1}' / batchSize; db{l} = sum(delta{l}, 2) / batchSize; endcnnapplygrads则简单得多:
% cnnapplygrads.m for l = 2 : numLayers W{l} = W{l} - learningRate * dW{l}; b{l} = b{l} - learningRate * db{l}; end学习率learningRate是这里最敏感的参数。太大直接发散,损失变成 NaN;太小收敛慢到你以为代码卡死了。常见起点是 0.01 或 0.001,配合批量大小 10 到 50 一起调。
3.3 cnnnumgradcheck.m 数值梯度检查怎么用
cnnnumgradcheck是这套源码里最值得单独拿出来说的文件。它的作用是用数值方法近似计算梯度,和你反向传播算出来的梯度对比,如果相对误差在 1e-4 到 1e-6 之间,说明cnnbp写对了。用法通常是构造一个极小的网络和几条随机数据,跑一遍检查。
% 数值梯度检查调用示例 cnn = cnnsetup([8 8 3 2 10 5]); % 极小网络 data = randn(8, 8, 1, 5); % 5 个样本 labels = randi(5, 1, 5); % 5 类标签 cnnnumgradcheck(cnn, data, labels); % 输出相对误差如果误差大于 1e-4,优先检查cnnbp里激活函数的导数有没有写错,尤其是tanh_opt的导数是不是1 - tanh(x)^2。这个检查跑一次可能要几十秒,但能帮你省下几个小时盲目调参的时间。
4. 数据预处理与训练配置:normalize、zscore、whiten 的先后顺序
4.1 地震信号标准化:normalize 和 zscore 的区别
normalize.m和zscore.m都做标准化,但方式不同。normalize通常是把数据缩放到 [0,1] 或 [-1,1] 区间,zscore是减均值除标准差,得到零均值单位方差。对于地震信号,我一般先zscore再normalize,因为地震波形幅度差异大,先零均值化能消除直流分量,再缩放到固定区间能让激活函数工作在敏感区。
% 预处理顺序建议 data = zscore(data); % 零均值化,消除直流偏移 data = normalize(data); % 缩放到 [-1, 1] % data = whiten(data); % 可选:白化,进一步降低冗余whiten.m做的是白化,让特征之间相关性降低。但白化对地震信号不一定总是有益,因为地震波形本身就有空间相关性,过度白化可能把有用信息也去掉。我的习惯是先不加白化跑一版,看验证集表现,如果过拟合明显再加。
4.2 训练超参数:学习率、批量大小、迭代次数
训练超参数在cnntrain.m里设置,常见的是学习率、批量大小、迭代次数三个。学习率控制步长,批量大小控制每次更新用的样本数,迭代次数控制总训练轮数。
| 参数 | 常见范围 | 影响 | 调整建议 |
|---|---|---|---|
| 学习率 | 0.001 ~ 0.1 | 太大发散,太小收敛慢 | 从 0.01 开始,观察损失曲线 |
| 批量大小 | 10 ~ 100 | 太小噪声大,太大内存吃紧 | 从 20 开始,显存/内存够就加大 |
| 迭代次数 | 100 ~ 1000 | 太少欠拟合,太多过拟合 | 看验证集损失何时回升 |
% cnntrain.m 中的超参数设置 opts.alpha = 0.01; % 学习率 opts.batchsize = 20; % 批量大小 opts.numepochs = 200; % 迭代次数 cnn = cnntrain(cnn, data, labels, opts);调参顺序建议:先固定批量大小和迭代次数,只调学习率,找到损失下降最快的值;然后固定学习率,调批量大小;最后调迭代次数,看验证集什么时候开始过拟合。
4.3 allcomb.m 做超参数网格搜索
allcomb.m生成所有参数组合,配合循环就能做网格搜索。比如你想试学习率 [0.001, 0.01, 0.1] 和批量大小 [10, 20, 50] 的九种组合:
alphas = [0.001, 0.01, 0.1]; batchsizes = [10, 20, 50]; combos = allcomb(alphas, batchsizes); for i = 1 : size(combos, 1) opts.alpha = combos(i, 1); opts.batchsize = combos(i, 2); cnn = cnntrain(cnnsetup(...), data, labels, opts); acc(i) = cnntest(cnn, valData, valLabels); end [bestAcc, idx] = max(acc);这个做法在小数据集上可行,但地震信号数据量一大,九次训练可能跑一整天。我的经验是先用粗网格定位大致范围,再用细网格在附近搜。
5. 避坑与排查:维度不匹配、梯度爆炸、过拟合的现场记录
5.1 现象:Matrix dimensions must agree
原因:cnnsetup里算的下一层输入维度和cnnff实际传进去的不一致。常见于卷积层'valid'模式输出尺寸缩小后没更新下一层配置。
解决:在cnnsetup里逐层打印尺寸,或者在cnnff里加assert检查。我一般会在cnnsetup末尾加一行disp(size(a{l})),跑一次看每层尺寸对不对。
5.2 现象:损失变成 NaN
原因:学习率太大,梯度爆炸。地震信号如果没做标准化,幅度差异大,更容易触发。
解决:先把学习率降到 0.001 甚至 0.0001,确认损失能正常下降后再逐步加大。同时检查normalize和zscore有没有漏做。
5.3 现象:训练集准确率高但验证集低
原因:过拟合。网络容量太大,或者训练数据太少。
解决:减少卷积核数量或全连接层神经元数,加whiten降冗余,或者用expand.m做数据增强。如果datan.mat里样本本来就少,考虑交叉验证而不是固定划分。
5.4 现象:cnnnumgradcheck 误差大于 1e-4
原因:cnnbp里激活函数导数写错,或者池化层的反向传播没对上。
解决:逐层检查导数公式。tanh_opt的导数是1 - tanh(x).^2,sigm的导数是sigm(x).*(1-sigm(x))。池化层反向传播要把误差分配到前向传播时取最大值的那个位置。
5.5 现象:训练速度极慢
原因:批量大小太小,或者循环里反复load数据。
解决:把数据一次性加载到内存,批量大小调到 50 以上。如果还是慢,检查cnnff里有没有不必要的for循环,能用矩阵运算的地方尽量向量化。
6. 进阶技巧:用 visualize.m 看卷积核学到了什么,以及预训练网络 net_cnn.mat 的复用
visualize.m是这套源码里容易被忽略但价值很高的文件。它能把卷积核的权重画成图像,让你直观看到网络到底在学什么。如果卷积核看起来像随机噪声,说明训练没收敛或者学习率不对;如果能看到明显的条纹或斑点,说明网络在提取地震波形的局部特征。
% visualize.m 调用示例 load('net_cnn.mat'); % 加载预训练网络 visualize(cnn.W{2}); % 可视化第一层卷积核我一般会在训练结束后跑一次visualize,把第一层卷积核画出来。如果 6 个卷积核里有 3 个以上长得差不多,说明卷积核数量可能多了,可以减半再试。如果全是噪声,回去检查学习率和预处理。
net_cnn.mat是预训练好的网络参数,可以直接加载做推理,跳过训练。用法是:
load('net_cnn.mat'); % 加载 net 变量 pred = cnntest(cnn, newData); % 对新数据预测但要注意,net_cnn.mat是在特定数据分布上训练的,如果你的地震信号来自不同台站或不同量级,直接复用可能不准。我的习惯是先用它做一版基线,然后用自己的数据微调最后几层。
还有一个技巧是结合allcomb.m和cnnnumgradcheck.m做自动化验证:每次改完cnnbp或cnnsetup,先跑一遍梯度检查,确认反向传播没问题,再跑训练。这样能把调试时间从几小时压到几分钟。
从那以后我每次动 CNN 的反向传播代码,都强制先跑一遍cnnnumgradcheck,确认相对误差在 1e-6 以下才继续。这个习惯帮我省下了无数次“训练不收敛但不知道哪里错”的后悔药。希望帮到你。
本文还有配套的精品资源,点击获取