R2:RNN-心脏病预测

一、实验目的:

  1. 本地读取并加载数据。
  2. 了解循环神经网络(RNN)的构建过程
  3. 测试集accuracy到达87%

拔高:测试集accuracy到达89%

二、实验环境:

  • 语言环境:python 3.8
  • 编译器:Jupyter notebook
  • 深度学习环境:TensorFlow

代码流程图:
Inception v3论文:**Rethinking the Inception Architecture for Computer Vision**

三、循环神经网络(RNN)

**循环神经网络(Recurrent Neural Network,RNN)**是一种具有记忆功能的神经网络,主要用于处理序列数据。

RNN 的独特之处在于它的循环结构,能够将上一时刻的信息传递到当前时刻,从而实现对序列数据的动态处理。它包含一个循环单元,这个单元在不同的时间步重复使用,使得网络能够记住过去的信息并影响当前的输出,我们可以认为RNN有一些“记忆”能力。理论上RNN能够利用任意长序列的信息,但是实际中它能记忆的长度是有限的。

随着技术的发展,出现了许多改进的 RNN 变体,如长短期记忆网络(LSTM)门控循环单元(GRU),它们在一定程度上缓解了传统 RNN 的问题,提高了对序列数据的处理能力。

传统神经网络的结构比较简单:输入层 – 隐藏层 – 输出层。

RNN 跟传统神经网络最大的区别在于每次都会将前一次的输出结果,带到下一次的隐藏层中,一起训练。如下图所示:

在这里插入图片描述

这里用一个具体的案例来看看 RNN 是如何工作的:用户说了一句“what time is it?”,我们的神经网络会先将这句话分为五个基本单元(四个单词+一个问号)

在这里插入图片描述

然后,按照顺序将五个基本单元输入RNN网络,先将 “what”作为RNN的输入,得到输出o1
在这里插入图片描述
随后,按照顺序将“time”输入到RNN网络,得到输出o2。

这个过程我们可以看到,输入 “time” 的时候,前面“what” 的输出也会对02的输出产生了影响(隐藏层中有一半是黑色的)。
在这里插入图片描述
以此类推,我们可以看到,前面所有的输入产生的结果都对后续的输出产生了影响(可以看到圆形中包含了前面所有的颜色)
在这里插入图片描述
当神经网络判断意图的时候,只需要最后一层的输出o5,如下图所示:
在这里插入图片描述

四、前期准备

1. 设置GPU

import tensorflow as tf

gpus = tf.config.list_physical_devices("GPU")

if gpus:
    gpu0 = gpus[0]                                        #如果有多个GPU,仅使用第0个GPU
    tf.config.experimental.set_memory_growth(gpu0, True)  #设置GPU显存用量按需使用
    tf.config.set_visible_devices([gpu0],"GPU")
    
gpus
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

2. 导入数据

每个数据的标签含义:

  • age:年龄
  • sex:性别
  • cp:胸痛类型 (4 values)
  • trestbps:静息血压
  • chol:血清胆固醇 (mg/dl)
  • fbs:空腹血糖 > 120 mg/dl
  • restecg:静息心电图结果 (值 0,1 ,2)
  • thalach:达到的最大心率
  • exang:运动诱发的心绞痛
  • oldpeak:相对于静止状态,运动引起的ST段压低
  • slope:运动峰值 ST 段的斜率
  • ca:荧光透视着色的主要血管数量 (0-3)
  • thal:0 = 正常;1 = 固定缺陷;2 = 可逆转的缺陷
  • target:0 = 心脏病发作的几率较小 1 = 心脏病发作的几率更大
import pandas as pd
import numpy as np

df = pd.read_csv("/heart.csv")
df

请添加图片描述

3. 检查数据

在进行数据预处理之前我们还需要对我们的数据进行检查,确保每一个标签内的数据没有空值。

# 检查是否有空值
df.isnull().sum()
age         0
sex         0
cp          0
trestbps    0
chol        0
fbs         0
restecg     0
thalach     0
exang       0
oldpeak     0
slope       0
ca          0
thal        0
target      0
dtype: int64

五、数据预处理

1. 划分训练集与测试集

🍺 测试集与验证集的关系:

  1. 验证集并没有参与训练过程梯度下降过程的,狭义上来讲是没有参与模型的参数训练更新的。
  2. 但是广义上来讲,验证集存在的意义确实参与了一个“人工调参”的过程,我们根据每一个epoch训练之后模型在valid data上的表现来决定是否需要训练进行early stop,或者根据这个过程模型的性能变化来调整模型的超参数,如学习率,batch_size等等。
  3. 我们也可以认为,验证集也参与了训练,但是并没有使得模型去overfit验证集。
from sklearn.preprocessing import StandardScaler 
from sklearn.model_selection import train_test_split


X = df.iloc[:,:-1] 
y = df.iloc[:,-1] 

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.1, random_state = 1)

X_train.shape, y_train.shape 
((272, 13), (272,))

2. 数据标准化

这里我们用到了 StandardScaler函数,它的作用是去均值和方差归一化。且是针对每一个特征维度来做的,而不是针对样本。

# 将每一列特征标准化为标准正态分布,注意,标准化是针对每一列而言的
sc      = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test  = sc.transform(X_test)

X_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)
X_test  = X_test.reshape(X_test.shape[0], X_test.shape[1], 1)

六、构建RNN模型

这里我们构建模型要用到tf.keras.layers.SimpleRNN()函数,这个函数的模型如下:

tf.keras.layers.SimpleRNN(
    units,
    activation='tanh',
    use_bias=True,
    kernel_initializer='glorot_uniform',
    recurrent_initializer='orthogonal',
    bias_initializer='zeros',
    kernel_regularizer=None,
    recurrent_regularizer=None,
    bias_regularizer=None,
    activity_regularizer=None,
    kernel_constraint=None,
    recurrent_constraint=None,
    bias_constraint=None,
    dropout=0.0,
    recurrent_dropout=0.0,
    return_sequences=False,
    return_state=False,
    go_backwards=False,
    stateful=False,
    unroll=False,
    **kwargs
)

函数参数的官方介绍:
在这里插入图片描述

import tensorflow
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,LSTM,SimpleRNN

model = Sequential()
model.add(SimpleRNN(128, input_shape= (13,1),return_sequences=True,activation='relu'))
model.add(SimpleRNN(64,return_sequences=True, activation='relu'))
model.add(SimpleRNN(32, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.summary()

请添加图片描述

七、编译模型

原教案代码中 metrics=“accuracy” 报错,函数期望接收的是可迭代对象(如列表、元组等),改为 metrics=[‘accuracy’] 后解决问题。

opt = tf.keras.optimizers.Adam(learning_rate=1e-4)

model.compile(loss='binary_crossentropy',
       optimizer=opt,
       metrics=['accuracy'])

八、训练模型

epochs = 100

history = model.fit(X_train, y_train, 
                    epochs=epochs, 
                    batch_size=128, 
                    validation_data=(X_test, y_test),
                    verbose=1)

请添加图片描述

九、模型评估

import matplotlib.pyplot as plt

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(14, 4))
plt.subplot(1, 2, 1)

plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

请添加图片描述

scores = model.evaluate(X_test, y_test, verbose=0)
print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
compile_metrics: 87.10%

十、总结

从上图结果中我们可以看出:

左图:训练与验证准确率
训练集的准确率(蓝色线):随着训练次数增加,呈现出平稳上升趋势,最终接近0.92左右,说明模型在训练数据上的拟合效果逐渐变好。
验证集的准确率(橙色线):一开始随着训练迭代次数增加,验证准确率也在提升,但在约20次迭代后,准确率趋于平稳,甚至有一些波动,特别在50次之后,表现出明显的下降和上升不稳定现象。

右图:训练与验证损失
训练集损失(蓝色线):损失随着迭代次数逐渐下降,这表明模型在训练集上不断优化,误差减少。
验证集损失(橙色线):最开始也在下降,但在大约20次迭代后开始变得平缓,甚至有轻微的波动。这与验证集准确率下降的现象一致,暗示模型在验证集上的表现没有持续改进。

问题
验证集准确率的波动与下降:尽管训练集的表现不断提升,验证集的表现却在特定迭代后停滞或波动,表明模型可能存在过拟合。训练集上模型表现越来越好,但它无法有效泛化到验证集数据。
验证集损失的波动:验证集损失在下降到一定程度后不再继续下降,甚至开始轻微波动,这进一步表明模型在面对新数据时的泛化能力不足。

改进方法

  1. 增加数据量:收集更多的心脏病相关数据,包括不同类型的病例和特征,以提高模型的泛化能力。更多的数据可以让模型学习到更广泛的模式,减少过拟合的风险。
  2. 数据增强:增加数据的多样性,多模态?这样可以让模型学习到不同角度和形态下的心脏病特征,提高其鲁棒性。
  3. 正则化方法
    • L1 和 L2(权重衰减) 正则化:在模型的损失函数中添加正则项,限制模型参数的大小来减少模型的复杂度,从而防止过拟合。
    • Dropout:在训练过程中随机丢弃一些神经元,增加模型的泛化能力。
  4. Early Stopping:监控验证集的损失或准确率,当验证集的表现不再提升时,提前终止训练,防止模型过度拟合训练数据。
  5. 调整模型结构:尝试不同的模型结构,如使用别的 RNN 变体或结合其他类型的神经网络,以找到更适合心脏病预测任务的模型。

我的研究更多的是关注人工智能+影像组学,以下是一些结合RNN的简单思路和原理:

  • CNN+RNN用于动态医学影像分析
    动态医学影像(如心脏超声、功能性MRI)包含时间序列信息,需要同时考虑空间和时间特征。
    ✅CNN用于特征提取:使用卷积神经网络(CNN)从每一帧图像中提取空间特征。这些特征可以是解剖结构、病灶特征等。
    ✅RNN用于时间序列分析:将CNN提取的特征序列输入到循环神经网络(RNN)中(如LSTM或GRU),以捕捉时间动态变化。这有助于分析心脏运动、血流动态等。
  • 多模态影像融合分析
    ✅ CNN用于单模态特征提取:为每种影像模态(如CT、MRI、PET)设计专门的CNN模型,提取特定模态的特征。
    ✅ 特征融合策略:使用全连接层或自注意机制将不同模态的特征进行融合,构建一个统一的特征表示。
    ✅ RNN或Transformer用于决策:在融合特征的基础上,使用RNN或Transformer进行最终的分类或回归任务
  • AI驱动的个性化治疗方案
    ✅ CNN用于影像特征提取:从患者的影像数据中提取潜在的病理特征。
    ✅ RNN用于序列数据分析:分析患者的时间序列数据(如治疗历史、病程进展)。
    ✅ 融合多源数据:将影像特征与基因组信息、电子健康记录(EHR)结合,使用多模态融合技术进行综合分析。
    .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值