点击上方“Python爬虫与数据挖掘”,进行关注

回复“书籍”即可获赠Python从入门到进阶共10本电子书

青山隐隐水迢迢, 秋尽江南草未凋。

大家好,我是「K同学啊 」!

好像有一段时间没有更新了,这段事情真的太多了,自己也有一点点小偷懒,但是我还在坚持哈,等开学了更新频率可能就会稳定下来。

唠嗑结束,进入正题,前段时间帮别人做了一个3D分类的活,想着怎么也得整理出一篇博客给大家吧,于是乎就有了这篇文章。这篇文章讲解的项目相对早期的项目有如下改进:

  • 1.设置的动态学习率

  • 2.加入的早停策略

  • 3.模型的保存时间更加“智能”

  • 4.在数据加载这块也有明显的优化

我的环境:

  • 语言环境:Python3.6.5

  • 编译器:jupyter notebook

  • 深度学习环境:TensorFlow2.4.1

  • 显卡(GPU):NVIDIA GeForce RTX 3080

  • 数据链接: https://pan.baidu.com/s/1_8T3PthALINkqsu7yquODw 提取码: ueka

来自专栏:《深度学习100例》

CT 扫描 3D 图像分类

  • 创作时间:2021年8月23日下午

  • 任务描述:训练一个 3D 卷积神经网络来预测肺炎的存在。

一、前期工作

1. 介绍

本案例将展示通过构建 3D 卷积神经网络 (CNN) 来预测计算机断层扫描 (CT) 中病毒性肺炎是否存在。2D 的 CNN 通常用于处理 RGB 图像(3 个通道)。3D 的 CNN 仅仅是 3D 等价物,我们可以将 3D 图像简单理解成 2D 图像的叠加。3D 的 CNN 可以理解成是学习立体数据的强大模型。

import os,zipfile
import numpy as np
from tensorflow import keras
from tensorflow.keras import layersimport tensorflow as tf
gpus = tf.config.list_physical_devices("GPU")if gpus:tf.config.experimental.set_memory_growth(gpus[0], True)  #设置GPU显存用量按需使用tf.config.set_visible_devices([gpus[0]],"GPU")# 打印显卡信息,确认GPU可用
print(gpus)
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

2. 加载和预处理数据

数据文件是 Nifti,扩展名为 .nii。我使用nibabel 包来读取文件,你可以通过 pip install nibabel 来安装 nibabel 包。

数据预处理步骤:

  1. 首先将体积旋转 90 度,确保方向是固定的

  2. 将 HU 值缩放到 0 和 1 之间。

  3. 调整宽度、高度和深度。

我定义了几个辅助函数来完成处理数据,这些功能将在构建训练和验证数据集时使用。

import nibabel as nib
from scipy import ndimagedef read_nifti_file(filepath):# 读取文件scan = nib.load(filepath)# 获取数据scan = scan.get_fdata()return scandef normalize(volume):"""归一化"""min = -1000max = 400volume[volume < min] = minvolume[volume > max] = maxvolume = (volume - min) / (max - min)volume = volume.astype("float32")return volumedef resize_volume(img):"""修改图像大小"""# Set the desired depthdesired_depth = 64desired_width = 128desired_height = 128# Get current depthcurrent_depth = img.shape[-1]current_width = img.shape[0]current_height = img.shape[1]# Compute depth factordepth = current_depth / desired_depthwidth = current_width / desired_widthheight = current_height / desired_heightdepth_factor = 1 / depthwidth_factor = 1 / widthheight_factor = 1 / height# 旋转img = ndimage.rotate(img, 90, reshape=False)# 数据调整img = ndimage.zoom(img, (width_factor, height_factor, depth_factor), order=1)return imgdef process_scan(path):# 读取文件volume = read_nifti_file(path)# 归一化volume = normalize(volume)# 调整尺寸 width, height and depthvolume = resize_volume(volume)return volume

读取CT扫描文件的路径

# “CT-0”文件夹中是正常肺组织的CT扫描
normal_scan_paths = [os.path.join(os.getcwd(), "MosMedData/CT-0", x)for x in os.listdir("MosMedData/CT-0")
]# “CT-23”文件夹中是患有肺炎的人的CT扫描
abnormal_scan_paths = [os.path.join(os.getcwd(), "MosMedData/CT-23", x)for x in os.listdir("MosMedData/CT-23")
]print("CT scans with normal lung tissue: " + str(len(normal_scan_paths)))
print("CT scans with abnormal lung tissue: " + str(len(abnormal_scan_paths)))
CT scans with normal lung tissue: 100
CT scans with abnormal lung tissue: 100
# 读取数据并进行预处理
abnormal_scans = np.array([process_scan(path) for path in abnormal_scan_paths])
normal_scans = np.array([process_scan(path) for path in normal_scan_paths])# 标签数字化
abnormal_labels = np.array([1 for _ in range(len(abnormal_scans))])
normal_labels = np.array([0 for _ in range(len(normal_scans))])

二、构建训练和验证集

从类目录中读取扫描并分配标签。对扫描进行下采样以具有 128x128x64 的形状。将原始 HU 值重新调整到 0 到 1 的范围内。最后,将数据集拆分为训练和验证子集。

# 按照7:3的比例划分训练集、验证集
x_train = np.concatenate((abnormal_scans[:70], normal_scans[:70]), axis=0)
y_train = np.concatenate((abnormal_labels[:70], normal_labels[:70]), axis=0)
x_val = np.concatenate((abnormal_scans[70:], normal_scans[70:]), axis=0)
y_val = np.concatenate((abnormal_labels[70:], normal_labels[70:]), axis=0)
print("Number of samples in train and validation are %d and %d."% (x_train.shape[0], x_val.shape[0])
)
Number of samples in train and validation are 140 and 60.

三、数据增强

CT扫描也通过在训练期间在随机角度旋转来增强数据。由于数据存储在Rank-3的形状(样本,高度,宽度,深度)中,因此我们在轴4处添加大小1的尺寸,以便能够对数据执行3D卷积。因此,新形状(样品,高度,宽度,深度,1)。在那里有不同类型的预处理和增强技术,这个例子显示了一些简单的开始。

import random
from scipy import ndimage@tf.function
def rotate(volume):"""不同程度上进行旋转"""def scipy_rotate(volume):# 定义一些旋转角度angles = [-20, -10, -5, 5, 10, 20]# 随机选择一个角度angle = random.choice(angles)volume = ndimage.rotate(volume, angle, reshape=False)volume[volume < 0] = 0volume[volume > 1] = 1return volumeaugmented_volume = tf.numpy_function(scipy_rotate, [volume], tf.float32)return augmented_volumedef train_preprocessing(volume, label):volume = rotate(volume)volume = tf.expand_dims(volume, axis=3)return volume, labeldef validation_preprocessing(volume, label):volume = tf.expand_dims(volume, axis=3)return volume, label

在定义训练和验证数据加载器的同时,训练数据将进行不同角度的随机旋转。训练和验证数据都已重新调整为具有 0 到 1 之间的值。

# 定义数据加载器
train_loader = tf.data.Dataset.from_tensor_slices((x_train, y_train))
validation_loader = tf.data.Dataset.from_tensor_slices((x_val, y_val))batch_size = 2train_dataset = (train_loader.shuffle(len(x_train)).map(train_preprocessing).batch(batch_size).prefetch(2)
)validation_dataset = (validation_loader.shuffle(len(x_val)).map(validation_preprocessing).batch(batch_size).prefetch(2)
)

四、数据可视化

import matplotlib.pyplot as pltdata = train_dataset.take(1)
images, labels = list(data)[0]
images = images.numpy()
image = images[0]
print("Dimension of the CT scan is:", image.shape)
plt.imshow(np.squeeze(image[:, :, 30]), cmap="gray")
Dimension of the CT scan is: (128, 128, 64, 1)

def plot_slices(num_rows, num_columns, width, height, data):"""Plot a montage of 20 CT slices"""data = np.rot90(np.array(data))data = np.transpose(data)data = np.reshape(data, (num_rows, num_columns, width, height))rows_data, columns_data = data.shape[0], data.shape[1]heights = [slc[0].shape[0] for slc in data]widths = [slc.shape[1] for slc in data[0]]fig_width = 12.0fig_height = fig_width * sum(heights) / sum(widths)f, axarr = plt.subplots(rows_data,columns_data,figsize=(fig_width, fig_height),gridspec_kw={"height_ratios": heights},)for i in range(rows_data):for j in range(columns_data):axarr[i, j].imshow(data[i][j], cmap="gray")axarr[i, j].axis("off")plt.subplots_adjust(wspace=0, hspace=0, left=0, right=1, bottom=0, top=1)plt.show()# Visualize montage of slices.
# 4 rows and 10 columns for 100 slices of the CT scan.
plot_slices(4, 10, 128, 128, image[:, :, :40])

五、构建3D卷积神经网络模型

为了使模型更容易理解,我将其构建成块。

def get_model(width=128, height=128, depth=64):"""构建 3D 卷积神经网络模型"""inputs = keras.Input((width, height, depth, 1))x = layers.Conv3D(filters=64, kernel_size=3, activation="relu")(inputs)x = layers.MaxPool3D(pool_size=2)(x)x = layers.BatchNormalization()(x)x = layers.Conv3D(filters=64, kernel_size=3, activation="relu")(x)x = layers.MaxPool3D(pool_size=2)(x)x = layers.BatchNormalization()(x)x = layers.Conv3D(filters=128, kernel_size=3, activation="relu")(x)x = layers.MaxPool3D(pool_size=2)(x)x = layers.BatchNormalization()(x)x = layers.Conv3D(filters=256, kernel_size=3, activation="relu")(x)x = layers.MaxPool3D(pool_size=2)(x)x = layers.BatchNormalization()(x)x = layers.GlobalAveragePooling3D()(x)x = layers.Dense(units=512, activation="relu")(x)x = layers.Dropout(0.3)(x)outputs = layers.Dense(units=1, activation="sigmoid")(x)# 定义模型model = keras.Model(inputs, outputs, name="3dcnn")return model# 构建模型
model = get_model(width=128, height=128, depth=64)
model.summary()
Model: "3dcnn"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         [(None, 128, 128, 64, 1)] 0
_________________________________________________________________
conv3d (Conv3D)              (None, 126, 126, 62, 64)  1792
_________________________________________________________________
max_pooling3d (MaxPooling3D) (None, 63, 63, 31, 64)    0
_________________________________________________________________
batch_normalization (BatchNo (None, 63, 63, 31, 64)    256
_________________________________________________________________
conv3d_1 (Conv3D)            (None, 61, 61, 29, 64)    110656
_________________________________________________________________
max_pooling3d_1 (MaxPooling3 (None, 30, 30, 14, 64)    0
_________________________________________________________________
batch_normalization_1 (Batch (None, 30, 30, 14, 64)    256
_________________________________________________________________
conv3d_2 (Conv3D)            (None, 28, 28, 12, 128)   221312
_________________________________________________________________
max_pooling3d_2 (MaxPooling3 (None, 14, 14, 6, 128)    0
_________________________________________________________________
batch_normalization_2 (Batch (None, 14, 14, 6, 128)    512
_________________________________________________________________
conv3d_3 (Conv3D)            (None, 12, 12, 4, 256)    884992
_________________________________________________________________
max_pooling3d_3 (MaxPooling3 (None, 6, 6, 2, 256)      0
_________________________________________________________________
batch_normalization_3 (Batch (None, 6, 6, 2, 256)      1024
_________________________________________________________________
global_average_pooling3d (Gl (None, 256)               0
_________________________________________________________________
dense (Dense)                (None, 512)               131584
_________________________________________________________________
dropout (Dropout)            (None, 512)               0
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 513
=================================================================
Total params: 1,352,897
Trainable params: 1,351,873
Non-trainable params: 1,024
_________________________________________________________________

六、训练模型

# 设置动态学习率
initial_learning_rate = 1e-4
lr_schedule = keras.optimizers.schedules.ExponentialDecay(initial_learning_rate, decay_steps=30, decay_rate=0.96, staircase=True
)
# 编译
model.compile(loss="binary_crossentropy",optimizer=keras.optimizers.Adam(learning_rate=lr_schedule),metrics=["acc"],
)
# 保存模型
checkpoint_cb = keras.callbacks.ModelCheckpoint("3d_image_classification.h5", save_best_only=True
)
# 定义早停策略
early_stopping_cb = keras.callbacks.EarlyStopping(monitor="val_acc", patience=15)epochs = 100
model.fit(train_dataset,validation_data=validation_dataset,epochs=epochs,shuffle=True,verbose=2,callbacks=[checkpoint_cb, early_stopping_cb],
)
Epoch 1/100
70/70 - 18s - loss: 0.7115 - acc: 0.5143 - val_loss: 0.8686 - val_acc: 0.5000
Epoch 2/100
70/70 - 15s - loss: 0.6595 - acc: 0.6643 - val_loss: 0.8958 - val_acc: 0.5000
Epoch 3/100
70/70 - 15s - loss: 0.6623 - acc: 0.6214 - val_loss: 0.8238 - val_acc: 0.5000
Epoch 4/100
......
70/70 - 15s - loss: 0.5098 - acc: 0.7571 - val_loss: 0.5803 - val_acc: 0.6667
Epoch 43/100
70/70 - 15s - loss: 0.5083 - acc: 0.7857 - val_loss: 0.6009 - val_acc: 0.6333
Epoch 44/100
70/70 - 15s - loss: 0.5276 - acc: 0.7429 - val_loss: 0.5300 - val_acc: 0.7000
Epoch 45/100
70/70 - 15s - loss: 0.5158 - acc: 0.7500 - val_loss: 0.5504 - val_acc: 0.6833
Epoch 46/100
70/70 - 15s - loss: 0.4648 - acc: 0.8357 - val_loss: 0.5724 - val_acc: 0.6833<tensorflow.python.keras.callbacks.History at 0x1becc8326d8>

注意:由于样本数量非常少(只有 200 个),而且我没有指定随机种子。因此,你可以预期结果可能会有显着差异。

七、可视化模型性能

fig, ax = plt.subplots(1, 2, figsize=(20, 3))
ax = ax.ravel()for i, metric in enumerate(["acc", "loss"]):ax[i].plot(model.history.history[metric])ax[i].plot(model.history.history["val_" + metric])ax[i].set_title("Model {}".format(metric))ax[i].set_xlabel("epochs")ax[i].set_ylabel(metric)ax[i].legend(["train", "val"])

八、对单次 CT 扫描进行预测

# 加载模型
model.load_weights("3d_image_classification.h5")
prediction = model.predict(np.expand_dims(x_val[0], axis=0))[0]
scores = [1 - prediction[0], prediction[0]]class_names = ["normal", "abnormal"]
for score, name in zip(scores, class_names):print("This model is %.2f percent confident that CT scan is %s"% ((100 * score), name))
This model is 27.88 percent confident that CT scan is normal
This model is 72.12 percent confident that CT scan is abnormal

注:本文参考了官方代码,并对里面的一些内容做了改动。

------------------- End -------------------

往期精彩文章推荐:

  • 手把手教你用Python改造一款外星人入侵小游戏

  • 手把手教你用Python网络爬虫+自动化来创建一位属于你自己的虚拟女票(附源码)

  • Python也能操作MongoDB数据库

  • Python也能操作Mysql数据库

欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持

想加入Python学习群请在后台回复【入群

万水千山总是情,点个【在看】行不行

/今日留言主题/

随便说一两句吧~

用Python打造一款3D医疗影像识别系统相关推荐

  1. 元宵节就要到了,手把手教你用Python打造一款3D花灯

    点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 独有宦游人,偏惊物候新. 1 前言 ...

  2. 深度学习100例-卷积神经网络(CNN)3D医疗影像识别 | 第23天

    大家好,我是「K同学啊 」! 好像有一段时间没有更新了,这段事情真的太多了,自己也有一点点小偷懒,但是我还在坚持哈,等开学了更新频率可能就会稳定下来. 唠嗑结束,进入正题,前段时间帮别人做了一个3D分 ...

  3. 荟聚NeurIPS顶会模型、智能标注10倍速神器、人像分割SOTA方案、3D医疗影像分割利器,PaddleSeg重磅升级!

    导读 图像分割是计算机视觉三大任务之一,基于深度学习的图像分割技术也发挥日益重要的作用,广泛应用于智慧医疗.工业质检.自动驾驶.遥感.智能办公等行业. 然而在实际业务中,图像分割依旧面临诸多挑战,比如 ...

  4. 腾讯优图开源业界首个3D医疗影像大数据预训练模型

    整理 | Jane出品 | AI科技大本营(ID:rgznai100) 近日,腾讯优图首个医疗AI深度学习预训练模型 MedicalNet 正式对外开源.这也是全球第一个提供多种 3D 医疗影像专用预 ...

  5. 腾讯开源首个医疗AI项目,业内首个3D医疗影像大数据预训练模型

    乾明 发自 凹非寺  量子位 报道 | 公众号 QbitAI 腾讯AI,开源又有新动作. 旗下顶级AI实验室腾讯优图,对外开源了腾讯首个医疗AI项目--深度学习预训练模型MedicalNet. 这一项 ...

  6. 腾讯开源首个医疗AI项目,业内首个3D医疗影像大数据预训

    腾讯AI,开源又有新动作. 旗下顶级AI实验室腾讯优图,对外开源了腾讯首个医疗AI项目--深度学习预训练模型MedicalNet. 这一项目,专为3D医疗影像在深度学习上的应用开发,也是业内首个同方向 ...

  7. 全球首个!腾讯优图开源3D医疗影像大数据预训练模型

    点击我爱计算机视觉标星,更快获取CVML新技术 本文转载自腾讯优图. 近日,腾讯优图首个医疗AI深度学习预训练模型MedicalNet正式对外开源.这也是全球第一个提供多种3D医疗影像专用预训练模型的 ...

  8. 一种基于深度学习的增值税发票影像识别系统

    一种基于深度学习的增值税发票影像识别系统-专利技术交底书 缩略语和关键术语定义 1.卷积神经网络(Convolutional Neural Networks, CNN)是一类包含卷积计算且具有深度结构 ...

  9. 中安财报影像识别系统V2.0,为您摘下“紧箍咒

    中安财报影像识别系统V2.0,为您摘下"紧箍咒 财务报表包含资产负债表.现金流表.利润表,是公司进行信贷审批.财务审计时的主要依据.财务报表核查,对于银行卡信贷审批.企业信用审核等行业的工作 ...

最新文章

  1. PHP Webservice的发布与调用
  2. 经典面试题:给两个序列如何构造一棵二叉树
  3. 先来先服务算法代码_一致性哈希算法编写
  4. java反射成员变量_java反射之成员变量的反射
  5. 如何解决Android studio已分享到github的项目但是git->commit directory提交不上去
  6. 盲盒(随机概率 + 最大公约数)
  7. 第三讲 关系映射反演原则
  8. dateutils 工具类_五金工具泡壳封边机
  9. super(XXXX,self).__init__()在类中的作用
  10. 运维自动化之5 - 基于LVS实现4层负载均衡应用
  11. python mock接口返回数据(转载)
  12. 黑马程序员——C语言基础教程笔记
  13. c语言 键盘扫描码 c-free,FreeBarcode条形码制作工具
  14. 安信可 Telink_825x 环境搭建
  15. 十七、HBase更新数据
  16. Android隐藏状态栏实现沉浸式体验
  17. php压缩文件下载后损坏,php下载压缩文件
  18. 小白看了也能搭建物联网项目——物联网开发板——QD-mini板
  19. 解决webSocket中使用@Autowired注入为空的办法
  20. Pentest BOX安装和使用

热门文章

  1. 灰点相机SDK研究(壹)-使用Python多线程读取灰点相机图像
  2. 2.3 黑群晖驱动:开启nvme缓存、将nvme缓存作为存储盘 教程
  3. postgis函数汇总
  4. 白板体现计算机什么方面应用,白板汉字论文,关于电子白板在小学低年级识字写字教学中的运用相关参考文献资料-免费论文范文...
  5. thinkphp网站提示缓存文件写入失败
  6. 在小程序中使用dayjs
  7. 关于s19赛季服务器维修,S19赛季已开服,版本重点调整需知熟,想要跟上游戏节奏必了解...
  8. 根据hash值找到bt种子的磁力下载链…
  9. 简历信息提取二:PaddleNLP完成简历信息抽取
  10. Ubuntu 电驴下载软件 - mldonkey