深度学习在心电图信号分割中的应用

近期,在网络上关注到一个影响力人物Andrew Ng发表的一篇研究论文,这篇论文提出了一种先进的心脏病检测方法。心脏病?机器学习从心电图(ECG)中诊断比心脏病专家还要准确!这个想法让非常感兴趣,于是深入研究了所有相关的材料,以理解背后的原始创意。

简而言之,论文表示他们使用了深度学习技术,这是一种近年来一直备受关注的技术,用于提取专家用来识别疾病患者的模式。经过训练后,这个算法变得如此擅长这项任务,以至于声称它甚至超过了经验丰富的医生。这个想法影响了,让意识到即使是这样的小角色,也能对这些研究人员所取得的重大进展产生影响!

本文将聚焦于心电图信号中的音频分割问题,以及如何利用深度学习来解决这项任务。将首先讨论一般意义上的分割问题,然后展示可以用来解决问题的方法。还将讨论“心脏声音”是什么,然后展示心脏声音分割的实现。

注意:本文假设对音频数据分析有基本的了解。如果想复习这些概念,可以阅读文章《使用深度学习进行音频数据分析入门》和《深度学习基础》。

什么是分割问题(一般意义上)?

在深入探讨心脏声音分割之前,让先回顾一下分割问题的含义。分割字面上意味着根据一组定义好的特征将一个特定对象分成部分(或段落)。这个对象可以是任何东西——从具体的事物如图像的一帧或音频信号,到抽象的对象如市场或消费者。

可能会问,为什么要分割对象?答案很简单——如果将一个对象分解,它就变得更容易从中提取信息。例如,在客户管理中,处理平均值永远不会揭示可操作的洞察,直到将其分解成段落。正如文章中提到的,这是基于年龄对信用卡使用进行客户分割的一个例子。

监督分割方法

现在已经了解了分割问题,让了解解决分割问题的方法。对于音频数据分析来说,分割是一个重要的预处理步骤。这是因为可以将嘈杂且冗长的音频信号分割成短的同质段落,这些段落是用于进一步处理的方便的短音频序列。现在要解决一个分割问题,可以直接使用无监督方法,或者将其转换为监督问题,然后根据其类别进行分组。

为了更直观地解释这一点,让以图像分割任务为例。假设有一张田野中的猫的图片,如下所示。想要将图片分成块——以便一个单独的对象可以从其他对象中被单独识别出来。可以用两种方式做到这一点:

方法1:从图像的每个像素开始,找出彼此接近且颜色大致相似的像素。可以将这些像素聚类在一起,形成一个更大的对象图像。在下面的示例中,猫主要是灰白色。因此,找到像素并从图像中分割出猫会更容易。这是一种无监督的分割方法。

方法2:通过给模型提供属于图像的类别的明确示例来训练模型——特别是猫、树木和天空。然后让模型预测图像中哪些地方存在哪些类别。这是一种监督的分割方法。

尽管这两种方法都有其优缺点,但选择从哪种方法开始将取决于获取训练示例进行监督方法的难度。

理解问题——“心脏声音”是什么意思?

让不要浪费时间,直接跳到实际问题上,并尝试解决它。引用挑战页面本身的说法,根据世界卫生组织的数据,心血管疾病(CVDs)是全球死亡的首要原因:每年死于CVDs的人数比死于任何其他原因的人数都多。2004年,估计有1710万人死于CVDs,占全球死亡人数的29%。在这些死亡中,估计有720万人死于冠状动脉心脏病。因此,任何能够帮助检测心脏病迹象的方法都可能对世界健康产生重大影响。这个挑战就是要产生这样的方法。

挑战的任务是找到一种方法,可以在音频数据中定位特定于心脏的声音(即技术上称为S1和S2的“lub”和“dub”),然后根据这些声音对音频文件进行分割。在分割声音后,挑战然后要求产生一种方法,可以将心跳分类为正常和病态类别。为了本文的目的,将只承担挑战的第一个任务,即分割心脏音频。

为了给一个实际的预览,这就是心脏的声音:

# 导入模块 %pylab inline import librosa import numpy as np import pandas as pd from librosa import display # 读取csv文件 temp = pd.read_csv('../misc/Atraining_normal_seg.csv') temp.head() # 绘制样本心跳 data, sampling_rate = librosa.load('../misc/Atraining_normal/201102081321.wav', sr=44100) display.waveplot(data, sr=sampling_rate) # 可以看到心跳的周期,先是高强度的声音,然后是低强度的声音。

对于问题,需要从原始文件中创建训练数据。下面的代码通过遍历所有原始文件,并提取音频的一部分及其相应的标签来实现这一点:

data_x = [] data_y = [] for j in range(temp.shape[0]): for i in range(1, temp.shape[1] - 1): try: data, sampling_rate = librosa.load('../misc/Atraining_normal/' + temp.iloc[j, 0].split('.')[0] + '.wav', sr=44100) temp_data = data[int(temp.iloc[j, i]):int(temp.iloc[j, i+1])] temp_label = temp.iloc[:, i].name.split('.')[0] data_x.append(temp_data) data_y.append(temp_label) except: pass

当创建这些数据时,需要进行一些预处理。首先是使所有提取的样本具有相同的形状,其次是对数据进行归一化,第三是为深度学习模型创建适当的X和Y。

from keras.preprocessing.sequence import pad_sequences # 第1步 data_x = pad_sequences(data_x, maxlen=20000, dtype='float', padding='post', truncating='post', value=0.) # 第2步 data_x = data_x / np.max(data_x) # 第3步 data_x = data_x[:,:,np.newaxis] data_y = pd.Series(data_y) data_y.value_counts() data_y = data_y.map({'S1':0, 'S2':1}).values

现在让构建深度学习模型。将构建一个CNN模型,因为CNN已被证明是理解序列和分类的最先进的架构。

from keras.layers import InputLayer, Conv1D, Dense, Flatten, MaxPool1D from keras.models import Sequential model = Sequential() model.add(InputLayer(input_shape=data_x.shape[1:])) model.add(Conv1D(filters=50, kernel_size=10, activation='relu')) model.add(MaxPool1D(strides=8)) model.add(Conv1D(filters=50, kernel_size=10, activation='relu')) model.add(MaxPool1D(strides=8)) model.add(Flatten()) model.add(Dense(units=1, activation='softmax')) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

模型将具有这种架构。下一步是在转换后的数据集上训练模型。

# 训练模型 model.fit(data_x, data_y, batch_size=32, epochs=1)

在这里只限制训练1个周期。但可以增加这个周期以使模型表现更好。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485