文档

利用长短期记忆网络对心电信号进行分类

这个例子展示了如何使用深度学习和信号处理对来自PhysioNet 2017挑战赛的心跳心电图(ECG)数据进行分类。特别地,这个例子使用了长短期记忆(LSTM)网络和时频分析。

介绍

心电图记录一个人在一段时间内心脏的电活动。医生用心电图目测病人的心跳是正常还是不规则。

心房颤动(AFib)是一种不规则的心跳,发生在心脏的上腔(心房)与下腔(心室)不协调时。

本例使用来自PhysioNet 2017挑战赛[1],[2],[3]的ECG数据,该数据可在https://physionet.org/challenge/2017/。数据由一组以300hz采样的心电信号组成,并由一组专家分为四个不同的类别:正常(N), AFib (a),其他节奏(O)和噪声记录(~)。这个例子展示了如何使用深度学习自动化分类过程。该程序探索了一种二元分类器,可以区分正常的ECG信号和显示房颤迹象的信号。

这个例子使用了长短期记忆(LSTM)网络,这是一种循环神经网络(RNN),非常适合研究序列和时间序列数据。LSTM网络可以学习序列时间步长之间的长期依赖关系。LSTM层(lstmLayer)可以查看正向的时间序列,而双向LSTM层(bilstmLayer)可以看到向前和向后两个方向的时间序列。本例使用双向LSTM层。

为了加速训练过程,请在带有GPU的机器上运行此示例。如果您的机器具有GPU和并行计算工具箱™,那么MATLAB®将自动使用GPU进行训练;否则,使用CPU。

加载和检查数据

运行ReadPhysionetData脚本,从物理网网站下载数据,并生成mat文件(PhysionetData.mat),其中包含适当格式的心电信号。下载数据可能需要几分钟。

ReadPhysionetData负载PhysionetData

加载操作向工作区添加两个变量:信号标签信号是储存心电信号的细胞阵列。标签是一个分类数组,它包含信号的相应接地真值标签。

信号(1:5)
ans =5×1单元阵列{1×9000 double} {1×9000 double} {1×18000 double} {1×9000 double} {1×18000 double}
标签(1:5)
ans =5×1分类数组N N N a a

使用总结函数查看有738个AFib信号和5050个Normal信号。

总结(标签)
A 738 n 5050

生成信号长度的直方图。注意,大多数信号都有9000个采样长。

L = cellfun(@length,Signals);h =直方图(L);xticks (0:3000:18000);xticklabels (0:3000:18000);标题(“信号长度”)包含(“长度”) ylabel (“数”

可视化每个类的一个信号片段。心房颤动的心跳是不规则的,而正常的心跳是有规律的。心房颤动的心跳信号通常也没有P波,而P波在正常心跳信号的QRS复合体之前脉冲。正常信号的图显示P波和QRS复合体。

normal =信号{1};aFib =信号{4};Subplot (2,1,1) plot(normal) title(“正常的节奏”) xlim([4000,5200]) ylabel(“振幅(mV)”)文本(4330、150、“P”“HorizontalAlignment”“中心”)文本(4370、850、“QRS”“HorizontalAlignment”“中心”) subplot(2,1,2) plot(aFib) title(心房纤维性颤动的) xlabel([4000,5200])“样本”) ylabel (“振幅(mV)”

准备培训数据

在训练期间,trainNetwork函数将数据分割成小批量。然后,该函数填充或截断同一小批中的信号,使它们都具有相同的长度。过多的填充或截断可能会对网络的性能产生负面影响,因为网络可能会根据添加或删除的信息错误地解释信号。

若要避免过度填充或截断,请应用segmentSignals功能对心电信号,所以他们都是9000个样本长。该函数忽略采样数少于9000的信号。如果一个信号有超过9000个采样,segmentSignals将其分解为尽可能多的9000个样本片段,并忽略剩余的样本。例如,一个18500个样本的信号变成两个9000个样本的信号,剩下的500个样本被忽略。

[Signals,Labels] = segmentSignals(Signals,Labels);

查看的前五个元素信号数组来验证每个条目现在有9000个样本长。

信号(1:5)
ans =5×1单元阵列{1×9000 double} {1×9000 double} {1×9000 double} {1×9000 double} {1×9000 double}

使用原始信号数据训练分类器

要设计分类器,请使用前一节中生成的原始信号。将信号分成训练集来训练分类器,测试集来测试分类器在新数据上的准确性。

使用总结函数显示有718个AFib信号和4937个Normal信号,比例为1:7。

总结(标签)
A 718 n 4937

因为87.3%的信号是正常的,分类器会学习到,只要把所有的信号都分类为正常,就可以达到很高的准确率。为了避免这种偏差,可以通过在数据集中复制AFib信号来增加AFib数据,以便有相同数量的正常和AFib信号。这种重复,通常被称为过采样,是深度学习中使用的一种数据增强形式。

根据他们的等级把信号分开。

afibX =信号(标签)=“一个”);afibY =标签(标签==“一个”);normalX =信号(标签)=“N”);normalY = Labels(标签==“N”);

下一步,使用dividerand将每一类的目标随机分成训练集和测试集。

[trainIndA,~,testIndA] = dividerand(718,0.9,0.0,0.1);[trainIndN,~,testIndN] = dividerand(4937,0.9,0.0,0.1);XTrainA = afibX(trainIndA);YTrainA = afibY(trainIndA);XTrainN = normalX(trainIndN);YTrainN = normalY(trainIndN);XTestA = afibX(testIndA);YTestA = afibY(testIndA);XTestN = normalX(testIndN);YTestN = normalY(testIndN);

现在有646个AFib信号和4443个Normal信号用于训练。为了实现每个类中相同数量的信号,首先使用4438 Normal信号,然后使用repmat将前634个AFib信号重复7次。

用于测试,有72个AFib信号和494个Normal信号。使用第一个490 Normal信号,然后使用repmat将前70个AFib信号重复7次。默认情况下,神经网络在训练前随机洗牌数据,以确保相邻信号不都具有相同的标签。

XTrain = [repmat(XTrainA(1:634),7,1);XTrainN (1:4438)];YTrain = [repmat(YTrainA(1:634),7,1);YTrainN (1:4438)];XTest = [repmat(XTestA(1:70), 1,1);XTestN (1:490)];YTest = [repmat(YTestA(1:70), 1,1);YTestN (1:490);];

Normal和AFib信号之间的分布现在在训练集和测试集中都是均匀平衡的。

总结(YTrain)
A 4438 n 4438
总结(欧美)
A 490 n 490

定义LSTM网络架构

LSTM网络可以学习序列数据时间步长之间的长期依赖关系。本例使用双向LSTM层bilstmLayer,因为它从向前和向后两个方向看序列。

因为每个输入信号都有一个维度,所以将输入大小指定为大小为1的序列。指定一个输出大小为100的双向LSTM层,输出序列的最后一个元素。该命令指示双向LSTM层将输入时间序列映射为100个特征,然后为全连接层准备输出。最后,通过包括大小为2的完全连接层、softmax层和分类层来指定两个类。

图层= [sequenceInputLayer (1) bilstmLayer (100“OutputMode”“最后一次”(2) softmaxLayer classificationLayer
层= 5x1层阵列层:1“序列输入1维序列输入2”BiLSTM BiLSTM有100个隐藏单元3“完全连接2”完全连接层4“Softmax Softmax 5”分类输出crossentropyx

接下来,指定分类器的训练选项。设置“MaxEpochs”到10,允许网络通过10次训练数据。一个“MiniBatchSize”Of 150指示神经网络一次看150个训练信号。一个“InitialLearnRate”0.01有助于加快训练过程。指定一个“SequenceLength”将信号分解成更小的部分,这样机器就不会因为一次查看过多的数据而耗尽内存。设置”GradientThreshold’到1,通过防止梯度过大来稳定训练过程。指定“阴谋”作为“训练进步”生成随迭代次数增加而显示训练进度的图形。集“详细”抑制与图表中显示的数据相对应的表输出。如果你想看这张表,请设置“详细”真正的

本例使用自适应矩估计(ADAM)求解器。与默认的随机动量梯度下降(SGDM)求解器相比,ADAM在lstm等递归神经网络(rnn)上表现更好。

options = trainingOptions(“亚当”“MaxEpochs”10“MiniBatchSize”, 150,“InitialLearnRate”, 0.01,“SequenceLength”, 1000,“GradientThreshold”, 1“ExecutionEnvironment”“汽车”“阴谋”“训练进步”“详细”、假);

训练LSTM网络

使用指定的训练选项和层结构训练LSTM网络trainNetwork。由于训练集很大,训练过程可能需要几分钟。

net = trainNetwork(XTrain,YTrain,layers,options);

训练进度图的最上面的子图表示训练精度,即每个mini-batch上的分类精度。当训练进展顺利时,这个值通常会增加到100%。下面的子图显示了训练损失,这是每个mini-batch上的交叉熵损失。当训练进展顺利时,这个值通常会减小到零。

如果训练不是收敛的,则图可能在值之间振荡,而没有向上或向下的趋势。这种振荡意味着训练精度没有提高,训练损失没有减少。这种情况可能发生在训练开始时,或者在训练精度得到初步提高后,图可能趋于平稳。在许多情况下,改变训练选项可以帮助网络实现收敛。减少MiniBatchSize或减少InitialLearnRate可能会导致更长的训练时间,但它可以帮助网络更好地学习。

分类器的训练准确率在50%到60%之间波动,在10个epoch结束时,它已经花费了几分钟的训练时间。

可视化训练和测试的准确性

计算训练精度,它表示分类器对其所训练的信号的精度。首先,对训练数据进行分类。

trainPred =分类(net,XTrain,“SequenceLength”, 1000);

在分类问题中,混淆矩阵用于可视化分类器在一组已知真实值的数据上的性能。目标类是信号的真值标签,输出类是网络分配给信号的标签。轴标签表示类标签,AFib (A)和Normal (N)。

使用confusionchart命令,用于计算测试数据预测的总体分类精度。指定“RowSummary”作为“row-normalized”在行摘要中显示真阳性率和假阳性率。同时,指定“ColumnSummary”作为“column-normalized”在列摘要中显示正预测值和错误发现率。

LSTMAccuracy = sum(trainPred == YTrain)/numel(YTrain)*100
LSTMAccuracy = 61.2100
图ccLSTM = confusionchart(YTrain,trainPred);ccLSTM。Title =“LSTM混淆图”;ccLSTM。ColumnSummary =“column-normalized”;ccLSTM。RowSummary =“row-normalized”

混淆矩阵显示,81.7%的地真AFib信号被正确分类为AFib, 31.1%的地真Normal信号被正确分类为Normal。此外,归类为AFib的信号中有54.2%实际上是AFib,归类为Normal的信号中有63.0%实际上是Normal。总体训练准确率为56.4%。

现在用同一网络对测试数据进行分类。

testPred =分类(net,XTest,“SequenceLength”, 1000);

计算测试精度并将分类性能可视化为混淆矩阵。

LSTMAccuracy = sum(testPred == YTest)/ nummel (YTest)*100
LSTMAccuracy = 61.4286
图ccLSTM = confusionchart(YTest,testPred);ccLSTM。Title =“LSTM混淆图”;ccLSTM。ColumnSummary =“column-normalized”;ccLSTM。RowSummary =“row-normalized”

这个混淆矩阵类似于训练混淆矩阵。总体检测精度为55.8%。

利用特征提取提高性能

从数据中提取特征有助于提高分类器的训练和测试精度。为了决定提取哪些特征,本例采用了一种计算时频图像(如频谱图)的方法,并使用它们来训练卷积神经网络(cnn)。

可视化每种信号的频谱图。

Fs = 300;图次要情节(2,1,1);pspectrum(正常,fs,的谱图“TimeResolution”, 0.5)标题(“正常信号”次要情节(2,1,2);pspectrum (aFib fs,的谱图“TimeResolution”, 0.5)标题(“AFib信号”

由于本例使用LSTM而不是CNN,因此转换方法以适用于一维信号是很重要的。时频矩从谱图中提取信息。每个矩都可以作为一维特征输入到LSTM中。

探索时域中的两个TF矩:

  • 瞬时频率(instfreq

  • 谱熵(pentropy

instfreq函数估计信号的随时间变化的频率作为功率谱图的第一矩。该函数利用短时傅里叶变换在时间窗口上计算频谱图。在本例中,该函数使用255个时间窗口。函数的时间输出对应于时间窗口的中心。

可视化每种信号的瞬时频率。

[instFreqA,tA] = instfreq(afb,fs);[instFreqN,tN] = instfreq(normal,fs);图次要情节(2,1,1);情节(tN, instFreqN)标题(“正常信号”)包含(“时间(s)”) ylabel (瞬时频率的次要情节(2,1,2);instFreqA情节(tA)标题(“AFib信号”)包含(“时间(s)”) ylabel (瞬时频率的

使用cellfun要应用instfreq函数到训练集和测试集的每个单元。

instfreqTrain = cellfun(@(x)instfreq(x,fs)',XTrain,“UniformOutput”、假);instfreqTest = cellfun(@(x)instfreq(x,fs)',XTest,“UniformOutput”、假);

谱熵测量的是信号的谱有多平坦。具有尖尖频谱的信号,就像正弦波的总和,具有较低的频谱熵。频谱平坦的信号,就像白噪声一样,具有很高的频谱熵。的pentropy函数估计基于功率谱图的谱熵。在瞬时频率估计的情况下,pentropy使用255个时间窗来计算谱图。函数的时间输出对应于时间窗口的中心。

可视化每种类型信号的谱熵。

[pentropyA,tA2] = pentropy(afb,fs);[pentropyN,tN2] = pentropy(normal,fs);图subplot(2,1,1) plot(tN2,pentropyN) title(“正常信号”) ylabel (“谱熵”) subplot(2,1,2) plot(tA2,pentropyA) title(“AFib信号”)包含(“时间(s)”) ylabel (“谱熵”

使用cellfun要应用pentropy函数到训练集和测试集的每个单元。

pentropyTrain = cellfun(@(x)pentropy(x,fs)',XTrain,“UniformOutput”、假);pentropyTest = cellfun(@(x)pentropy(x,fs)',XTest,“UniformOutput”、假);

连接特征,使新的训练集和测试集中的每个单元具有两个维度或两个特征。

XTrain2 = cellfun(@(x,y)[x;y],instfreqTrain,pentropyTrain,“UniformOutput”、假);XTest2 = cellfun(@(x,y)[x;y],instfreqTest,pentropyTest,“UniformOutput”、假);

可视化新输入的格式。每个细胞不再包含一个9000个样本长的信号;现在它包含两个255个样本长的特征。

XTrain2 (1:5)
ans =5×1单元阵列{2×255 double} {2×255 double} {2×255 double} {2×255 double} {2×255 double}

标准化数据

瞬时频率和谱熵的含义几乎相差一个数量级。此外,瞬时频率均值可能过高,使LSTM无法有效学习。当网络拟合具有大均值和大范围值的数据时,大的输入可能会减慢网络的学习和收敛速度[6]。

意思是(instFreqN)
Ans = 5.5615
意思是(pentropyN)
Ans = 0.6326

使用训练集均值和标准差对训练集和测试集进行标准化。标准化,或z评分,是一种在训练期间提高网络性能的流行方法。

XV = [XTrain2{:}];mu = mean(XV,2);sg = std(XV,[],2);XTrainSD = XTrain2;XTrainSD = cellfun(@(x)(x-mu)./sg,XTrainSD,“UniformOutput”、假);XTestSD = XTest2;XTestSD = cellfun(@(x)(x-mu)./sg,XTestSD,“UniformOutput”、假);

显示标准化瞬时频率和谱熵的均值。

instFreqNSD = XTrainSD{1}(1,:);pentropyNSD = XTrainSD{1}(2,:);意思是(instFreqNSD)
Ans = -0.3210
意思是(pentropyNSD)
Ans = -0.2416

修改LSTM网络结构

既然每个信号都有两个维度,就有必要通过指定输入序列大小为2来修改网络架构。指定一个输出大小为100的双向LSTM层,输出序列的最后一个元素。通过包括大小为2的完全连接层、softmax层和分类层来指定两个类。

图层= [sequenceInputLayer (2) bilstmLayer (100“OutputMode”“最后一次”(2) softmaxLayer classificationLayer
层= 5x1层阵列层:1“序列输入2维序列输入2”BiLSTM BiLSTM有100个隐藏单元3“完全连接2”完全连接层4“Softmax Softmax 5”分类输出crossentropyx

指定培训选项。设置最大epoch数为30,允许网络通过训练数据30次。

options = trainingOptions(“亚当”“MaxEpochs”30岁的“MiniBatchSize”, 150,“InitialLearnRate”, 0.01,“GradientThreshold”, 1“ExecutionEnvironment”“汽车”“阴谋”“训练进步”“详细”、假);

利用时频特征训练LSTM网络

使用指定的训练选项和层结构训练LSTM网络trainNetwork

net2 = trainNetwork(XTrainSD,YTrain,layers,options);

训练精度有很大的提高,现在超过90%。交叉熵损失趋向于0。此外,训练所需的时间减少了,因为TF矩比原始序列短。

可视化训练和测试的准确性

使用更新后的LSTM网络对训练数据进行分类。将分类性能可视化为一个混淆矩阵。

trainPred2 =分类(net2,XTrainSD);LSTMAccuracy = sum(trainPred2 == YTrain)/numel(YTrain)*100
LSTMAccuracy = 83.5174
图ccLSTM = confusionchart(YTrain,trainPred2);ccLSTM。Title =“LSTM混淆图”;ccLSTM。ColumnSummary =“column-normalized”;ccLSTM。RowSummary =“row-normalized”

用更新后的网络对测试数据进行分类。绘制混淆矩阵来检验测试的准确性。

testPred2 =分类(net2,XTestSD);LSTMAccuracy = sum(testPred2 == YTest)/ nummel (YTest)*100
LSTMAccuracy = 82.5510
图ccLSTM = confusionchart(YTest,testPred2);ccLSTM。Title =“LSTM混淆图”;ccLSTM。ColumnSummary =“column-normalized”;ccLSTM。RowSummary =“row-normalized”

结论

这个例子展示了如何使用LSTM网络构建一个分类器来检测心电信号中的心房颤动。该程序使用过采样来避免在主要由健康患者组成的人群中检测异常情况时发生的分类偏差。使用原始信号数据训练LSTM网络会导致较差的分类精度。对每个信号使用两个时-频-矩特征来训练网络,可以显著提高分类性能,同时减少训练时间。

参考文献

[1]短单导联心电图记录AF分类:PhysioNet/计算心脏病学挑战赛,2017。https://physionet.org/challenge/2017/

[2] Clifford, Gari,刘成玉,Benjamin Moody, Li-wei H. Lehman, Ikaro Silva, Li Qiao Li, Alistair Johnson, Roger G. Mark。“短单导联心电图记录的房颤分类:2017年心脏病学挑战中的PhysioNet计算”。心脏病学计算(雷恩:IEEE)。2017年第44卷,第1-4页。

[3] Goldberger, a.l., l.a.n. Amaral, l.g lass, j.m. Hausdorff, p.c. Ivanov, r.g. Mark, j.e. Mietus, g.b. Moody, c.k。和h.e. Stanley。PhysioBank, PhysioToolkit和PhysioNet:复杂生理信号新研究资源的组成部分。循环。第101卷第23期,2000年6月13日,第e215-e220页。http://circ.ahajournals.org/content/101/23/e215.full

[4] Pons, Jordi, Thomas Lidy和Xavier Serra。“实验音乐驱动的卷积神经网络”。第十四届基于内容的多媒体索引国际研讨会。2016年6月。

b[5]王,D。“深度学习重塑了助听器,”IEEE频谱,第54卷第3期,2017年3月,第32-37页。doi: 10.1109 / MSPEC.2017.7864754。

[6]布朗利,杰森。如何在Python中扩展长短期记忆网络的数据。2017年7月7日。https://machinelearningmastery.com/how-to-scale-data-for-long-short-term-memory-networks-in-python/。

另请参阅

功能

相关的话题