基于Tensorflow深度学习的ECG身份识别方法(一)
基于Tensorflow深度学习的ECG身份识别方法(二)
基于Tensorflow深度学习的ECG身份识别方法(三)
一、前言
这段时间工作是有些忙,没什么时间更新。但是想着还是年前把这个写完吧,挤挤时间还是有的。其实话说回来,博客写的这些吧,只能算是兴趣爱好,仅此记录一下所得。
好了,步入正题,上一篇把数据处理好了,本篇就介绍下我训练用的神经网络以及一些参数的选择。
二、CNN简介(来自网络)
卷积神经网络(CNN)是一类包含卷积计算且具有深度结构的前馈神经网络,是深度学习的代表算法之一。卷积神经网络具有表征学习能力,能够按其阶层结构对输入信息进行平移不变分类,因此也被称为“平移不变人工神经网络”。卷积神经网络仿造生物的视知觉机制构建,可以进行监督学习和非监督学习,其隐含层内的卷积核参数共享和层间连接的稀疏性使得卷积神经网络能够以较小的计算量对格点化特征。其结构包括输入层、隐藏层、输出层,其中隐藏层可包含卷积层、池化层、全连接层。
三、代码部分
照例先贴代码,代码部分很简单,使用的是 Tensorflow2.0 的 Keras。通过简单的模型堆叠搭建神经网络。
class_num = 48 #将最后的的结果分为48类
#将数据转换为张量,并改变输入形状
x_train = tf.convert_to_tensor(train_x, dtype=tf.float32)
y_train = tf.convert_to_tensor(train_y, dtype=tf.float32)
x_train = tf.reshape(x_train, (x_train.shape[0], -1, 1))
test_x = tf.convert_to_tensor(test_x, dtype=tf.float32)
test_x = tf.reshape(test_x, (test_x.shape[0], -1, 1))
test_y = tf.convert_to_tensor(test_y, dtype=tf.float32)
# 搭建一维cnn网络,keras简单的模型堆叠
model_m = keras.Sequential()
model_m.add(tf.keras.layers.Conv1D(100, 10, activation='relu', input_shape=(360, 1)))
model_m.add(tf.keras.layers.Conv1D(100, 10, activation='relu'))
model_m.add(tf.keras.layers.AveragePooling1D(3))
model_m.add(tf.keras.layers.Conv1D(160, 10, activation='relu'))
model_m.add(tf.keras.layers.Conv1D(160, 10, activation='relu'))
model_m.add(tf.keras.layers.AveragePooling1D(3))
model_m.add(tf.keras.layers.Conv1D(160, 10, activation='relu'))
model_m.add(tf.keras.layers.Conv1D(160, 10, activation='relu'))
model_m.add(tf.keras.layers.GlobalAveragePooling1D())
model_m.add(tf.keras.layers.Dropout(0.5))
model_m.add(tf.keras.layers.Dense(class_num, activation='softmax'))
print(model_m.summary())
model_m.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 大致看下训练所需时间
start_time = time.time()
model_m.fit(x_train, y_train, batch_size=400, epochs=60)
end_time = time.time()
print('Running time is %d minutes.' % ((end_time - start_time) / 60))
# 评估模型
test_loss, test_acc = model_m.evaluate(test_x, test_y)
print('\nTest accurac:', test_acc, 'Test loss:', test_loss)
# 保存模型,下次使用可直接load,不用再训练
model_m.save('ecg_model_file')
四、神经网络结构
由于 ECG 信号是一维数据序列,所以我使用的是用一维 CNN 来进行 ECG 身份识别算法的训练(但其实处理时间序列数据用 LSTM 会更好)。网络共有 12 层,包括 1 一个输入层、1 个输出层和 10 个隐藏层,隐藏层中包括 6 个卷积层,3 个池化层和 1 一个全连接层。每两个卷积层后面跟着一个池化层进行二次特征提取,输入 ECG 信号经过卷积和池化后特征图越来越小,但是特征图数量越来越多,意味着提取特征种类也越来越多。神经网络结构如下图所示:
各层的输入输出形状以及参数的个数如下所示:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv1d (Conv1D) (None, 351, 100) 1100
_________________________________________________________________
conv1d_1 (Conv1D) (None, 342, 100) 100100
_________________________________________________________________
average_pooling1d (AveragePo (None, 114, 100) 0
_________________________________________________________________
conv1d_2 (Conv1D) (None, 105, 160) 160160
_________________________________________________________________
conv1d_3 (Conv1D) (None, 96, 160) 256160
_________________________________________________________________
average_pooling1d_1 (Average (None, 32, 160) 0
_________________________________________________________________
conv1d_4 (Conv1D) (None, 23, 160) 256160
_________________________________________________________________
conv1d_5 (Conv1D) (None, 14, 160) 256160
_________________________________________________________________
global_average_pooling1d (Gl (None, 160) 0
_________________________________________________________________
dropout (Dropout) (None, 160) 0
_________________________________________________________________
dense (Dense) (None, 48) 7728
=================================================================
Total params: 1,037,568
Trainable params: 1,037,568
Non-trainable params: 0
_________________________________________________________________
关于输入输出张量以及参数个数的计算: 卷 积 层 输 出 张 量 形 状 = ( 输 入 数 据 大 小 − 卷 积 核 大 小 + 1 ) × 卷 积 核 数 量 (1) 卷积层输出张量形状 =(输入数据大小 - 卷积核大小 + 1)× 卷积核数量{\tag1} 卷积层输出张量形状=(输入数据大小−卷积核大小+1)×卷积核数量(1) 参 数 个 数 = 卷 积 核 数 量 × ( 卷 积 核 大 小 × 输 入 数 据 组 数 + 1 ) (2) 参数个数 = 卷积核数量 × (卷积核大小 × 输入数据组数 + 1){\tag2} 参数个数=卷积核数量×(卷积核大小×输入数据组数+1)(2)
- 第一层卷积层输入形状为
360×1
,卷积核大小为10
,数量为100
,所以第一层卷积层输出形状为: ( 360 − 10 + 1 ) × 100 = 351 × 100 (360 - 10 + 1) × 100 = 351 × 100 (360−10+1)×100=351×100
参数个数为: 100 × ( 10 × 1 + 1 ) = 1100 100 \times (10 \times 1 + 1) = 1100 100×(10×1+1)=1100- 第二层卷积层输入形状为
351×100
,输出形状为:
( 351 − 10 + 1 ) × 100 = 342 × 100 (351 - 10 + 1) × 100 = 342 \times 100 (351−10+1)×100=342×100
参数个数为: 100 × ( 10 × 100 + 1 ) = 100100 100 \times (10 \times 100 + 1) = 100100 100×(10×100+1)=100100- 第一层平均池化层的输入形状为
342 x 100
,输出形状为: 342 ÷ 3 × 100 = 114 × 100 342 \div3 \times100 = 114 \times 100 342÷3×100=114×100
··· ···
五、神经网络参数
- 激活函数:
- 卷积层所采用的激活函数为
relu
函数,其函数图形如下图其具有仿生物学、更加有效率的梯度下降以及反向传播和简化计算过程等优势,能更好的对ECG信号特征进行提取,将其映射到非线性空间。- 全连接层所采用的激活函数是
softmax
函数。在机器学习尤其是深度学习中,softmax是个非常常用而且比较重要的函数,尤其在多分类的场景中使用广泛。他把一些输入映射为0-1之间的实数,并且归一化保证和为1,因此多分类的概率之和也刚好为1。
- 损失函数:
- 选取损失函数为分类交叉熵函数categorical_crossentropy,其损失函数表达式为:
l o s s = − ∑ i = 1 n y ^ i 1 log ( y i 1 ) + y ^ i 2 log ( y i 2 ) + ⋯ + y ^ i m log ( y i m ) loss = -\sum^{n}_{i=1}{\hat{y}_{i1}\log(y_{i1}) +\hat{y}_{i2}\log(y_{i2}) + \cdots+\hat{y}_{im}\log(y_{im})} loss=−i=1∑ny^i1log(yi1)+y^i2log(yi2)+⋯+y^imlog(yim)其中n是样本数,m是分类数。该损失函数适用于多分类问题,并使用softmax作为输出层的激活函数的情况。
- 优化器:
- 优化器选择Adam优化器,其是基于随机梯度下降(SGD)的高级演化版本,其计算效率高、能够自适应调整学习率。
六、结语
关于 ECG 身份识别这部分就到此结束了,也是我接触深度学习第一个手动做出来的小实验,其实很多概念理解的也不是很到位,文中或有错误之处,望各位不吝赐教。最后祝大家生活愉快,未来可期。