Andrew Y. Ng式ResNet在MIT-BIH上的Inter-Patient分类实现(2)

数据处理

       目前大部分的文章均是基于心拍的分类。这样做在理论上本身没什么问题,因为数据库中的标签就是针对每个心拍给出的。但是在具体操作中,心拍的定位要么直接使用了数据库中的人工位置标记,这样在实际应用中等同于加入人工干预,自动化程度不够;要么使用一些经典的QRS波检测算法,如Pan-Tompkins算法,而这样的定位方式依赖于QRS检测算法的准确度。鉴于目前QRS波检测算法动辄99%以上的准确率,这个准确度依赖乍一听似乎也不是大问题。但根据我个人的经验,不同的QRS波算法在同等准确度情况下的定位结果会存在一定的差异,例如有的QRS定位点偏左,有的则偏右,这就导致哪怕是处理相同的数据,最终的定位结果会存在明显的偏差,截取心拍的波形表现也会有不同,这也就进一步导致后面网络的学习过程对QRS定位算法也会产生依赖,两个模块间会产生一定程度的耦合。

因此这里采用直接信号切片的方式,每个片段长5s。难道说这种方式就没有缺点了吗?非也。倘若一个切片中出现多种类型心拍的话,那标签应该怎么打呢?这一点就值得商榷了。这里我们采取这样的一种规则来缓解一下这个问题:

  1. 一个切片中所有心拍为正常时,该切片为正常;
  2. 一个切片中同时存在正常和异常心拍,该切片为异常;
  3. 一个切片中同时存在多类异常心拍,以切片中最多的异常类型为该切片类型;
  4. 一个切片中的存在多类且相同数目的异常心拍,以最先出现的异常类型为该切片类型。

这只是一种可能的解决方案,并非黄金规则。总体来看,个人还是认为切片方式利大于弊,截取的信息更完整,且不依赖于特定QRS检测算法,流程上也变得简单和一般化。

数据集划分方面,在MIT-BIH数据库中采用了如下的划分方式:

       训练集DS1:

101,106,108,109,112,114,115,116,118,119,122,124,201,203,205,207,208,209,215,220,223,230.

       测试集DS2:

100,103,105,111,113,117,121,123,200,202,210,212,213,214,219,221,222,228,231,232,233,234.

       这种方式是在论文中应用最广泛的inter-patient划分方式。所谓inter-patient,就是训练集和测试集来自不同的个体,个体差异性被充分考虑,是最贴近现实的一种评估方式,不清楚的可参考我之前的博客:https://blog.csdn.net/qq_15746879/article/details/80487543。类别划分遵循AAMI标准,共5类,N,V(VEB),S(SVEB),F,Q。这5大类是由各种小类集合而成,具体可参见下图:

来自文献:Luz E J S, Schwartz W R, Cámara-Chávez G, et al. ECG-based heartbeat classification for arrhythmia detection: A survey[J]. Computer methods and programs in biomedicine, 2016, 127: 144-164.

       数据集上的基本设定就说完了。接下来摆在面前的问题就是数据集本身的严重类别不平衡,尤其是训练集的不平衡极有可能会导致网络学习无效甚至不收敛,这一点是机器学习领域中的常识。根据我们以上的设定,在训练集中5类样本数分别为N:5907,V:1633,S:344,F:54,Q:4。得益于我们上述的切片方式,这里可以通过片段间的互相重叠来缓解类别不平衡所带来的影响,即样本量少的类别相邻切片间多重叠一些,能采集的样本就多一些。相比简单的过采样得到完全一致的新样本,这样的方式得到的新样本与原样本之间还能存在一定差异,理论上质量更好。以不重叠情况下最多的类别为基准,其余类别切片重叠长度可由以下公式估算:

其中,ol表示要重叠的长度,round表示四舍五入,L表示每个切片的长度,n表示当前类别的样本数目,N表示数目最多类别的样本数。需要注意的是,这样计算出来的重叠长度仅供参考,有时候并不能给出一个很好的结果。例如,完全按照这个公式的结果在DS1中处理过后,V,S,F类基本达到了与N类的平衡,但Q类的数目达到了8000多,重叠有些偏大;将计算出来的ol减去1,这样Q类数目也有3000+,又有些偏小。不过这里还是采取后面的方式。DS2作为测试集不做重叠处理。

       以上过程均在Matlab中实现,代码可见github项目中的check_nums_overlaps.m,get_category_segs.m,get_segs.m。由于下一步要转移到Python平台进行网络的搭建,所以将以上代码保存下的.mat文件转化为.npy文件,代码可见mat2npy.py。

       对于截取好的切片,还要再进行小波变换滤波[Martis R J, Acharya U R, Min L C. ECG beat classification using PCA, LDA, ICA and discrete wavelet transform [J].Biomedical Signal Processing and Control, 2013, 8(5): 437-448]和z-score标准化。另外,网络中存在多次的2倍下采样,而我们的5s片段在数据库360 Hz采样率的情况下长为1800,3次下采样后便不能整除,因此这里将所有片段再次重采样为1280点,等效256 Hz采样率。这个采样率也是足够的,原文中所采用的信号采样率也只有200 Hz。这些过程的函数代码实现可见github工程的mit_utils.py。

       现成的截取好的数据也可以直接下载:

.npy文件 链接:https://pan.baidu.com/s/1Rz9hmauG8tWg_dtdYXKDuQ  提取码:5qjh

.mat文件 链接:https://pan.baidu.com/s/1NFJtTMl5my3wUrCp_eoO-w  提取码:m199

解压后可使用,注意路径。

       下一部分讲网络。

 

Github:https://github.com/Aiwiscal/MIT_Scheme

喜欢请点赞和github给star哦~~~~

  • 19
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
好的,我可以为您提供代码实现。在这里,我将使用Keras中的ResNet50预训练模型,并使用Fashion-MNIST数据集对十种服装进行分类。首先,我们需要安装一些必要的库: ``` !pip install tensorflow !pip install keras !pip install matplotlib ``` 接下来,我们将加载数据集并进行预处理: ```python import numpy as np import keras from keras.datasets import fashion_mnist from keras.preprocessing.image import ImageDataGenerator # 数据集路径 (x_train, y_train), (x_test, y_test) = fashion_mnist.load_data() # 将图像转换为RGB格 x_train = np.repeat(x_train[..., np.newaxis], 3, -1) x_test = np.repeat(x_test[..., np.newaxis], 3, -1) # 批量大小 batch_size = 32 # 数据增强 train_datagen = ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) # 没有数据增强的验证数据生成器 val_datagen = ImageDataGenerator(rescale=1./255) # 训练集生成器 train_generator = train_datagen.flow( x_train, keras.utils.to_categorical(y_train), batch_size=batch_size) # 验证集生成器 val_generator = val_datagen.flow( x_test, keras.utils.to_categorical(y_test), batch_size=batch_size) ``` 接下来,我们将加载ResNet50模型,并对其进行微调,以适应我们的数据集: ```python from keras.applications.resnet50 import ResNet50 from keras.layers import Dense, GlobalAveragePooling2D from keras.models import Model # 加载ResNet50模型,不包括顶层(全连接层) base_model = ResNet50(weights='imagenet', include_top=False) # 添加全局平均池化层 x = base_model.output x = GlobalAveragePooling2D()(x) # 添加全连接层,输出为十个类别 predictions = Dense(10, activation='softmax')(x) # 构建我们需要训练的完整模型 model = Model(inputs=base_model.input, outputs=predictions) # 冻结ResNet50的所有层,以便在训练过程中不更新它们的权重 for layer in base_model.layers: layer.trainable = False ``` 现在,我们可以开始训练模型了: ```python from keras.optimizers import SGD # 编译模型,指定损失函数、优化器和评价指标 model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.001), metrics=['accuracy']) # 训练模型 history = model.fit_generator( train_generator, steps_per_epoch=x_train.shape[0] // batch_size, epochs=10, validation_data=val_generator, validation_steps=x_test.shape[0] // batch_size) ``` 最后,我们可以使用matplotlib库绘制训练和验证的准确率和损失曲线: ```python import matplotlib.pyplot as plt # 绘制训练和验证的准确率曲线 plt.plot(history.history['accuracy']) plt.plot(history.history['val_accuracy']) plt.title('Model accuracy') plt.ylabel('Accuracy') plt.xlabel('Epoch') plt.legend(['Train', 'Val'], loc='upper left') plt.show() # 绘制训练和验证的损失曲线 plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('Model loss') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(['Train', 'Val'], loc='upper left') plt.show() ``` 现在您应该可以使用这些代码实现您的需求了。
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值