文献笔记——ECG分类器(Inter- and intra- patient ECG heartbeat classification)
文献笔记
Date | Version | Comments |
---|---|---|
2019/11/1 | V0.1 | Init |
2019/12/7 | V0.2 | 添加LSTM部分 |
参考:
- 论文及其引用:Inter- and intra- patient ECG heartbeat classification for arrhythmia detection: a sequence to sequence deep learning approach
@Article{Mousavi2018,author = {Sajad Mousavi and Fatemeh Afghah and U. Rajendra Acharya},title = {Inter- and intra- patient ECG heartbeat classification for arrhythmia detection: a sequence to sequence deep learning approach},date = {2018-12-09},eprint = {http://arxiv.org/abs/1812.07421v2},eprintclass = {q-bio.QM},eprinttype = {arXiv},keywords = {q-bio.QM, eess.SP, physics.med-ph},
}
- 源代码:https://github.com/SajadMo/ECG-Heartbeat-Classification-seq2seq-model
WFDB安装
作者的WFDB工具是安装在Matlab中的。直接打开Matlab,切换到需要安装的目录下,在Matlab中使用一下代码就可以直接安装1,下载过程可能比较慢,但是文件不大,大概就只有8M:
[old_path]=which('rdsamp');if(~isempty(old_path)) rmpath(old_path(1:end-8)); end
wfdb_url='http://physionet.org/physiotools/matlab/wfdb-app-matlab/wfdb-app-toolbox-0-10-0.zip';
[filestr,status] = urlwrite(wfdb_url,'wfdb-app-toolbox-0-10-0.zip');
unzip('wfdb-app-toolbox-0-10-0.zip');
cd mcode
addpath(pwd);savepath
url最后的.zip文件含有版本信息,可以切换文件名,下载不同的版本。下载安装成功后,使用wfdbdemo
如果出现图片,表示安装成功。需要下载安装最新版本,不然可能出现下载错误的问题。应该是网站的文件位置发生了变化,可能会出现如下的错误问题:
java.io.FileNotFoundException: http://physionet.org/physiobank/database/pbi/mitdb
数据下载
安装WFDB成功以后,下载数据,需要打开文件:./data preprocessing_Matlab/download_MITBIHDB.m
,把里面的两个配置信息改了,就可以下载了,下载过程可能需要一点时间。
path_to_exes = 'D:\MATLAB_ECG_TOOL\mcode\nativelibs\windows\bin';
path_to_save_records = 'E:\03personal\DeepLearning\ECG-Heartbeat-seq2seq\data';
path_to_exes
是安装WFDB的目录,我的安装在了D:\MATLAB_ECG_TOOL
就写成上面那样,后面是固定的,注意:安装路径不要出现空格,否则会出现命令行语法识别的问题。path_to_save_records
是需要把数据下载的目标地址,这里就设置为了代码项目目录中的data文件夹中。
另外,如果自行在网站上下载数据,下载的数据是二进制文件,不能使用作者的数据处理方式进行,需要自行预处理。
数据预处理
下载好数据后,分别运行./data preprocessing_Matlab/seq2seq_mitbih_AAMI.m
和./data preprocessing_Matlab/seq2seq_mitbih_AAMI_DS1DS2.m
进行信号的预处理。
在运行时候,我的机器上,normalize函数不认识,按照作者论文中描述,需要将数据归一化到0~1的范围内,所以把signal = normalize(signal);
替换为signal = (mapminmax(signal)+1)/2;
,其中mapminmax(s)
会把数据转化为[-1,1]
的范围,做算数运算转化为[0,1]
即可。还有throw("No label! :(")
中的双引号,需要改为单引号throw('No label! :(')
。
模型
首先作者的模型有几个小问题,有好些地方的seq_seq_annot_DS1DS2.py
的255-256行的代码,由于索引值必须要为整数,所以需要改为:
data = _data[:int((len(_data) / max_time)) * max_time, :]_labels = _labels[:int((len(_data) / max_time)) * max_time]
build_network
函数的第一行也是:
_inputs = tf.reshape(inputs, [-1, n_channels, int(input_depth / n_channels)])
325-326行:
X_train = X_train[:int((X_train.shape[0] / max_time)) * max_time, :]y_train = y_train[:int((X_train.shape[0] / max_time)) * max_time]
seq_seq_annot_aami.py
中类似的地方也需要改。这样,代码是能跑起来了。随便跑了一会儿,效果还行。
数据不平衡问题
由于MIT-BIH数据库中虽然由较多的分类,但是大部分的心拍数据还是正常的(N
),标记为S
和F
的实际上较少,这样的数据直接训练模型肯定存在问题的。数据不不平衡的问题是通过Synthetic Minority Over-sampling Technique(SMOTE)
实现的,论文参考2。这个论文很早了,是2002年的,事实上在,处理中,也并没有太复杂。使用pip
安装imblearn库,就可以进行数据的SMOTE处理。nums[1]是不需要扩增的数据,n_oversampling是参数,需要增加到这么多,程序中取的10000。处理前,F 802, N 90502, S 2777, V 7219
,处理后,F 10000, N 72438, S 10000, V 9992
。这样数据就平衡很多了。
from imblearn.over_sampling import SMOTE
......ratio = {0: n_oversampling, 1: nums[1], 2: n_oversampling, 3: n_oversampling}sm = SMOTE(random_state=12, ratio=ratio)X_train, y_train = sm.fit_sample(X_train, y_train)
......
Inter-patient和Intra-patient
在讨论ECG信号时候,通常都会有Inter-patient和Intra-patient的概念。
Inter-patient: 对不同病人的数据进行特征提取并分类;
Intra-patient: 直接对所有数据进行随机分配,一部分为训练集,一部分为测试集。
其实在实际上Inter-patient更加符合使用意义,但是现在大部分论文还是Intra-patient(尤其中文),这样分类的精度高,看起来论文结果好,但是不符合实际使用情况。对于MIT-BIH的ECG信号来说,有AAMI推荐的一种Inter-patient的分组方式3。
DS1 = {101, 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}
DS1用于了训练模型,DS2用于了测试模型。
预处理与模型
样本的标记比较多,对相似的分类进行了分组。 然后根据标记的标签,讲数据分割为一段一段的信号,为了方便进行输入,分段的信号被resize成为了280点的长度。基本上来说,预处理没有改变任何信号的特点,没有额外引入滤波等的特性。
模型的结构如下图:
CNN部分是如下的3层结构。输入的280x1的数据被resize为了10x28,这点不是非常理解,这样的话,ECG明显的特征点都丢失了。
layer | size | 激活函数 |
---|---|---|
CNN1 | 2x1,32 | ReLU |
MAXPOOL1 | 2x1,stride 1 | - |
CNN2 | 2x1,64 | ReLU |
MAXPOOL2 | 2x1,stride 1 | - |
CNN3 | 2x1,128 | rectifier |
MAXPOOL3 | 2x1,stride 1 | - |
每次的seq长度即为一次送入模型的长度(程序中maxtime=10),CNN的输出作为Encoder的输入。encoder是使用的LSTM结构,同时,他是一种bidirectional recurrent neural network(BiRNN)
的网络结构,并非最简单的LSTM结构,实现信息的向前和向后传播。decoder是用于生成判断的target,由于解码器的 y < i > = x < i + 1 > , i > 0 y^{<i>}=x^{<i+1>},i>0 y<i>=x<i+1>,i>0,这样 x < 0 > x^{<0>} x<0>没有输入,所以在label中,在每次做输入时候,在训练集第一个label前面,额外插入了一个<GO>
这个标签,作为 x < 0 > x^{<0>} x<0>。
建模的python代码:
_input=tf.reshape(inputs,[n_channels,input_depth // n_channels]) # 将输入数据resize(280x1 -> 10x28)
conv1=tf.layers.conv1d(inputs=_input,filters=32,kernel_size=2,strides=1,padding='same',activation=tf.nn.relu) #CNN1
max_pool_1 = tf.layers.max_pooling1d(inputs=conv1, pool_size=2, strides=2, padding='same') # POOL1
conv2 = tf.layers.conv1d(inputs=max_pool_1, filters=64, kernel_size=2, strides=1,padding='same', activation=tf.nn.relu)
max_pool_2 = tf.layers.max_pooling1d(inputs=conv2, pool_size=2, strides=2, padding='same')
conv3 = tf.layers.conv1d(inputs=max_pool_2, filters=128, kernel_size=2, strides=1,padding='same', activation=tf.nn.relu)shape = conv3.get_shape().as_list() #conv3的输出shape
data_input_embed = tf.reshape(conv3, (-1, max_time, shape[1] * shape[2])) # 将conv3输出转化为向量
模型细节:
论文中给出是300 epochs, RMSProp方法更新权重矩阵,batch_size=20,learning_rate=0.001。实际训练时候,100 epochs, batch_size=512效果也挺好的。
评价参数
在生物信号中常用的评判参数有敏感性SEN
,阳性预测值PPV
,特异性SPEC
,准确率Acc
,之前一直没有太理解:
S E N = T P T P + F N (敏感性) SEN=\frac{TP}{TP+FN}\tag{敏感性} SEN=TP+FNTP(敏感性) P P V = T P T P + F P (阳性预测值) PPV=\frac{TP}{TP+FP}\tag{阳性预测值} PPV=TP+FPTP(阳性预测值) S P E C = T N T N + F P (特异性) SPEC=\frac{TN}{TN+FP}\tag{特异性} SPEC=TN+FPTN(特异性) A c c = T P + T N T P + T N + F P + F N (准确率) Acc=\frac{TP+TN}{TP+TN+FP+FN}\tag{准确率} Acc=TP+TN+FP+FNTP+TN(准确率)
敏感性SEN
表示所有的阳性标签里面的正确率。以有毒/无毒为例来说,TP表示输出有毒并正确的数量,FN表示输出为无毒并且错误的(也就是事实上有毒)。所以SEN
表示了所有有毒样本中的正确率。
阳性预测值PPV
表示预测的所有阳性标签是真的的概率。还是TP表示输出有毒并正确的数量,FP表示输出有毒,但是错了。PPV
就是输出的有毒的正确的概率。
特异性SPEC
表示所有的阴性标签里面的正确率。TN表示输出无毒并正确的数量,FP表示输出有毒但错误(事实上无毒),SPEC
就表示所有输出为无毒样本的正确率。
准确率Acc
就简单了,所有样本中的正确率。
LSTM
LSTM部分
embed_size = 10# Embedding layersoutput_embedding = tf.Variable(tf.random_uniform((len(char2numY), embed_size), -1.0, 1.0), name='dec_embedding')data_output_embed = tf.nn.embedding_lookup(output_embedding, dec_inputs)with tf.variable_scope("encoding") as encoding_scope:if not bidirectional:# Regular approach with LSTM unitslstm_enc = tf.contrib.rnn.LSTMCell(num_units)_, last_state = tf.nn.dynamic_rnn(lstm_enc, inputs=data_input_embed, dtype=tf.float32)else:# Using a bidirectional LSTM architecture insteadenc_fw_cell = tf.contrib.rnn.LSTMCell(num_units)enc_bw_cell = tf.contrib.rnn.LSTMCell(num_units)((enc_fw_out, enc_bw_out), (enc_fw_final, enc_bw_final)) = tf.nn.bidirectional_dynamic_rnn(cell_fw=enc_fw_cell,cell_bw=enc_bw_cell,inputs=data_input_embed,dtype=tf.float32)enc_fin_c = tf.concat((enc_fw_final.c, enc_bw_final.c), 1)enc_fin_h = tf.concat((enc_fw_final.h, enc_bw_final.h), 1)last_state = tf.contrib.rnn.LSTMStateTuple(c=enc_fin_c, h=enc_fin_h)with tf.variable_scope("decoding") as decoding_scope:if not bidirectional:lstm_dec = tf.contrib.rnn.LSTMCell(num_units)else:lstm_dec = tf.contrib.rnn.LSTMCell(2 * num_units)dec_outputs, _ = tf.nn.dynamic_rnn(lstm_dec, inputs=data_output_embed, initial_state=last_state)logits = tf.layers.dense(dec_outputs, units=len(char2numY), use_bias=True)
https://blog.csdn.net/qq_37663564/article/details/80602059 ↩︎
https://arxiv.org/pdf/1106.1813.pdf ↩︎
ANSI-AAMI, “Testing and reporting performance results of cardiac rhythm and st segment measurement algorithms,” American National Standards Institute, Inc. (ANSI), Association for the Advancement of Medical Instrumentation (AAMI), ANSI/AAMI/ISO, 1998-2008. ↩︎
文献笔记——ECG分类器(Inter- and intra- patient ECG heartbeat classification)相关推荐
- (2018-2021年)Uncertainty 相关SOTA文献笔记整理
Uncertainty 文献笔记 ACL Word-Level Uncertainty Estimation for Black-Box Text Classifiers using RNNs Uns ...
- 【读文献笔记】图神经网络加速结构综述
[读文献笔记]图神经网络加速结构综述 前言 一.图神经网络来源 1.图神经网络用途 2.图神经网络特点 3.图神经网络主要阶段 4.图神经网络加速面临的挑战 5.本笔记内容包含内容 二.图与图神经网络 ...
- VVC/VTM:帧间预测——Combined inter and intra prediction (CIIP)
Combined inter and intra prediction (CIIP) CIIP,顾名思义,就是说对编码块进行帧间预测Pred_inter和帧内预测Pred_intra,将两个预测块加权 ...
- 文献笔记--相关:无线通信、安全加密隐私
文献笔记 相关:无线通信.安全加密隐私 Marshal Zheng 2019-05,2019-06 文章目录 文献笔记 绿色通信协同认知无线电网络中二级用户的能源效率策略 保护智能家居免受互联网交通分 ...
- 文献笔记 —— GIDS: GAN based Intrusion Detection System for In-Vehicle Network
文献笔记 -- GIDS: GAN based Intrusion Detection System for In-Vehicle Network(GIDS: 基于GAN的车载网络入侵检测系统) 这篇 ...
- 文献笔记:Benchmarking graph neural networks for materials chemistry
文献笔记:Benchmarking graph neural networks for materials chemistry 摘要 Introduction RESULTS DISCUSSION M ...
- 【文献笔记】【精读】Deep Learning-Based Communication Over the Air
文章地址:Deep Learning-Based Communication Over the Air 建议在看这篇blog前先看这篇:[文献笔记][精读]An Introduction to Dee ...
- ECG分析:基于深度学习的ECG心律失常分类入门(1)
ECG分析:基于深度学习的ECG心律失常分类入门(1) 写作动机 由于受突发疫情的影响,开学时间推迟了(在此特向奋斗在前线的各行各业的工作者们致以崇高的敬意!).前天晚上刚好看到一篇新出的论文,跟自己 ...
- ECG ×AI: 机器/深度学习的ECG应用入门(4)
传统机器学习:特征工程+分类器 1.引言 经过前面的工作,我们已经解决了数据来源和识别对象问题.那么接下来,我们就要进行机器/深度学习算法的应用了.由于本人写这些博文的目的不在于讲解机器/深度学习理论 ...
最新文章
- Bootstrap 4 正式发布,却可能生不逢时
- JavaSE_NIO_ByteBuffer
- 数据从程序中传入到form中
- CSS清除行内元素之间的HTML空白
- 项目交接文档_项目管理反思
- 优Tech分享|YouTube推荐系统算法梳理
- c语言程序设计单元小测,C语言程序设计单元小测2.doc
- ant.design pro 登录模块分析
- bp神经网络matlab代码_基于Matlab的BP神经网络识别26个英文字母
- redis集群环境搭建入门
- centos7 减少/home分区空间,扩大/ 的空间
- 主成分分析 SPSS、python实例分析
- 基于STM32制作万能遥控器---1
- Git 之 多人协同开发工作流
- 响铃:丁磊造“网易美学”,是社区进化,还是包抄内容创业
- [译]-100行代码从零实现 Facebook 的 Recoil 库
- 安卓中关于图片的类型
- 键盘RK61-win10蓝牙
- centos下申请阿里云泛域名证书并自动更新
- python电话号码对应的字符组合_Python3 两种方式查找字符串里的电话号码