最近折腾了一波心音信号(PCG)分类的小项目,踩了不少坑也攒了点能直接跑的代码,今天掏出来跟大伙唠唠
MATLAB环境下一种基于连续小波变换和GoogLeNet的PCG信号分类算法 算法运行环境为MATLAB r2021b共5种PCG信号即normal, AR,AS,MR,MS五类 算法可迁移至金融时间序列地震信号语音信号声信号生理信号ECG,EEG,EMG等信号说白了就是用机器视觉的路子来做生理信号分类毕竟PCG是一维的时域信号直接丢进CNN不太好使不如先转成时频图再用预训练的GoogLeNet来微调效果比传统的时域特征提取香多了。这次用的是MATLAB R2021b跑的是公开的5类PCG数据集正常心音normal、主动脉瓣狭窄AS、主动脉瓣反流AR、二尖瓣反流MR、二尖瓣狭窄MS总共五类。首先得先把数据集准备好我是把每一类信号单独存在一个文件夹里比如D:/PCG_Dataset/normal下面全是正常心音的mat文件这样加载起来方便。代码就这么写别嫌路径硬编码麻烦改自己的路径就行% 数据集根目录改成你自己的文件夹路径哈 dataRoot D:/PCG_Dataset; % 我们的5类信号标签顺序要和文件夹名一致 classList {normal, AR, AS, MR, MS};这里要吐槽一下一开始我用相对路径结果跑的时候找不到文件后来直接写绝对路径省心多了反正自己用的话改一下就行。接下来是核心步骤把一维的PCG信号转成时频scalogram也就是我们要喂给GoogLeNet的“图片”。为啥用CWT因为心音是非平稳的信号CWT的时频分辨率比STFT灵活能更好地捕捉到心音里的异常成分。这里我用的是Morlet小波亲测对生理信号效果不错代码如下% 假设已经读取了一段PCG信号sig采样频率fs设为2000Hz心音常用采样率 fs 2000; % 选择Morlet小波基 wavName morl; % 计算连续小波变换得到系数矩阵和对应的频率 [cfs, frequencies] cwt(sig, fs, Wavelet, wavName); % 把系数转成对数幅度不然动态范围太大没法当成图像存 logCfs log10(abs(cfs) eps); % 加eps是防止log0报错我第一次跑就踩了这个坑直接炸了 % 归一化到0-1范围方便后续转成图像 logCfs (logCfs - min(logCfs(:))) / (max(logCfs(:)) - min(logCfs(:))); % 转成224x224的尺寸因为GoogLeNet默认输入是224x224的三通道图像 img imresize(logCfs, [224, 224]); % 把单通道的灰度图转成三通道不然GoogLeNet会报错说通道数不对 img repmat(img, [1,1,3]);这里解释一下repmat就是把单通道复制三份当成RGB图省得去改模型的输入层省事。把所有的PCG信号都转成scalogram之后用MATLAB的imageDatastore来加载数据集这个工具真的省事儿不用手动把所有图像塞到一个大矩阵里还能自动按文件夹分标签% 自动按子文件夹读取图像标签就是文件夹名 imds imageDatastore(dataRoot, ... IncludeSubfolders,true, ... LabelSource,foldernames); % 按7:3划分训练集和测试集随机打乱 [imdsTrain, imdsTest] splitEachLabel(imds, 0.7, randomize);这个splitEachLabel真的好用不用自己手动写代码分训练测试还能保证每一类的比例都差不多。接下来就是用预训练的GoogLeNet做迁移学习毕竟我们的数据集不大从头训的话不仅慢还容易过拟合。第一次跑的时候我直接用了原模型的分类层结果报错说分类数不对后来才知道原模型是1000类的ImageNet得改成我们的5类% 加载预训练的GoogLeNet第一次跑会自动下载大概几百MB有点慢 net googlenet; % 提取除了最后两层的所有层最后两层是原模型的全连接和分类层 layers net.Layers(1:end-2); % 添加我们自己的全连接层输出5类 numClasses length(classList); fcLayer fullyConnectedLayer(numClasses, Name, new_fc); softmaxLayer softmaxLayer(Name, new_softmax); classLayer classificationLayer(Name, new_classoutput); % 把新层拼接进去 layers [layers; fcLayer; softmaxLayer; classLayer];这里要注意别直接删最后两层之后就完事一定要加新的全连接层和分类层不然模型输出的还是1000类根本没法用。MATLAB环境下一种基于连续小波变换和GoogLeNet的PCG信号分类算法 算法运行环境为MATLAB r2021b共5种PCG信号即normal, AR,AS,MR,MS五类 算法可迁移至金融时间序列地震信号语音信号声信号生理信号ECG,EEG,EMG等信号训练参数我调了好几次一开始学习率设成1e-3结果训练集准确率涨得飞快测试集根本不涨纯纯过拟合了后来改成1e-4才正常。还有如果有GPU的话一定要开gpu加速不然训一次要俩小时开了之后20分钟搞定options trainingOptions(adam, ... InitialLearnRate,1e-4, ... % 别设太高微调用小学习率 MaxEpochs,15, ... % 一般10-20轮就够了 MiniBatchSize,32, ... ValidationData,imdsTest, ... ValidationFrequency,30, ... % 每30个batch验证一次 Plots,training-progress, ... % 实时画训练曲线 Verbose,1, ... % 打印训练日志 ExecutionEnvironment,gpu); % 有GPU就加上这个没有就删掉训练的时候会弹出一个实时的窗口看训练loss和验证准确率要是验证准确率不再涨了就可以提前stop不用跑完所有epoch省时间。然后直接开训就行% 开始训练记得关掉其他占内存的程序MATLAB吃内存挺狠的 netTransfer trainNetwork(imdsTrain, layers, options);我用的是PhysioNet的公开PCG数据集跑出来的测试集准确率大概在92%左右要是自己的数据集噪音多的话调调小波基、学习率、增加数据增强比如翻转、加高斯噪音都能提上来。训练完之后就可以测试模型效果了比如算准确率和画混淆矩阵% 预测测试集的标签 predLabels classify(netTransfer, imdsTest); % 获取真实标签 trueLabels imdsTest.Labels; % 计算准确率 accuracy mean(predLabels trueLabels); fprintf(测试集分类准确率%.2f%%\n, accuracy*100); % 画混淆矩阵直观看每一类的分类情况 confusionchart(trueLabels, predLabels, Title, PCG信号分类混淆矩阵);这个混淆矩阵真的很有用能看到哪一类最容易分错比如AR和AS有时候会混因为都是主动脉的问题特征比较像。重点来了这个算法其实不止能做PCG信号只要是一维的时序信号都可以套这个流程比如金融时间序列、地震信号、语音、ECG、EEG、EMG这些。举个例子比如金融里的股票价格序列把每天的收盘价序列做CWT转成时频图就能用这个代码改成股票涨跌分类再比如肌电信号EMG用来识别手势我同学用这个流程做过识别准确率也能到90%以上。其实流程都是一模一样的读时序信号→CWT转时频图→resize成224x224三通道→用预训练GoogLeNet微调分类→完事。唯一需要改的就是数据集路径、分类数还有根据信号的特点调一下小波基和采样频率。最后给大伙总结几个踩过的坑小波基别乱选Morlet、Mexican hat这俩对时序信号效果都不错别用太偏的不然特征提取不出来归一化很重要不管是信号还是图像不归一化训练的时候loss直接炸一定要注意模型的输入尺寸GoogLeNet是224x224别忘记resize不然会报错数据集小的话一定要加数据增强比如翻转、加高斯噪音、随机裁剪不然很容易过拟合有GPU一定要开gpu加速血的教训没开的时候训一次要俩小时开了之后飞一样要是大伙有啥问题或者踩了别的坑欢迎在评论区留言唠唠我看到都会回的。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2458990.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!