卷积神经网络-3D医疗影像识别

文章目录

  • 一、前言
  • 二、前期工作
      • 1. 介绍
      • 2. 加载和预处理数据
    • 二、构建训练和验证集
    • 三、数据增强
    • 四、数据可视化
    • 五、构建3D卷积神经网络模型
    • 六、训练模型
    • 七、可视化模型性能
    • 八、对单次 CT 扫描进行预测

一、前言

我的环境:

  • 语言环境:Python3.6.5
  • 编译器:jupyter notebook
  • 深度学习环境:TensorFlow2.4.1

往期精彩内容:

  • 卷积神经网络(CNN)实现mnist手写数字识别
  • 卷积神经网络(CNN)多种图片分类的实现
  • 卷积神经网络(CNN)衣服图像分类的实现
  • 卷积神经网络(CNN)鲜花识别
  • 卷积神经网络(CNN)天气识别
  • 卷积神经网络(VGG-16)识别海贼王草帽一伙
  • 卷积神经网络(ResNet-50)鸟类识别
  • 卷积神经网络(AlexNet)鸟类识别
  • 卷积神经网络(CNN)识别验证码

来自专栏:机器学习与深度学习算法推荐

二、前期工作

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 layers

import 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)

2. 加载和预处理数据

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

数据预处理步骤:

  1. 首先将体积旋转 90 度,确保方向是固定的
  2. 将 HU 值缩放到 0 和 1 之间。
  3. 调整宽度、高度和深度。

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

import nibabel as nib
from scipy import ndimage

def read_nifti_file(filepath):
    # 读取文件
    scan = nib.load(filepath)
    # 获取数据
    scan = scan.get_fdata()
    return scan

def normalize(volume):
    """归一化"""
    min = -1000
    max = 400
    volume[volume < min] = min
    volume[volume > max] = max
    volume = (volume - min) / (max - min)
    volume = volume.astype("float32")
    return volume

def resize_volume(img):
    """修改图像大小"""
    # Set the desired depth
    desired_depth = 64
    desired_width = 128
    desired_height = 128
    # Get current depth
    current_depth = img.shape[-1]
    current_width = img.shape[0]
    current_height = img.shape[1]
    # Compute depth factor
    depth = current_depth / desired_depth
    width = current_width / desired_width
    height = current_height / desired_height
    depth_factor = 1 / depth
    width_factor = 1 / width
    height_factor = 1 / height
    # 旋转
    img = ndimage.rotate(img, 90, reshape=False)
    # 数据调整
    img = ndimage.zoom(img, (width_factor, height_factor, depth_factor), order=1)
    return img

def process_scan(path):
    # 读取文件
    volume = read_nifti_file(path)
    # 归一化
    volume = normalize(volume)
    # 调整尺寸 width, height and depth
    volume = 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] = 0
        volume[volume > 1] = 1
        return volume

    augmented_volume = tf.numpy_function(scipy_rotate, [volume], tf.float32)
    return augmented_volume

def train_preprocessing(volume, label):
    volume = rotate(volume)
    volume = tf.expand_dims(volume, axis=3)
    return volume, label

def 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 = 2

train_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 plt

data = 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.0
    fig_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()

六、训练模型

# 设置动态学习率
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],
)

七、可视化模型性能

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/211961.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mongodb安装及其使用

1.Linux系统上安装Mongodb 在usr/local文件夹下创建mongo文件夹 下载mongodb包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-6.0.5.tgz解压mongodb tar -zxvf mongodb-linux-x86_64-rhel70-6.0.5.tgz更改文件夹的名字 mv mongodb-linux-x86_64-rh…

竞赛选题 题目:基于深度学习的手势识别实现

文章目录 1 前言2 项目背景3 任务描述4 环境搭配5 项目实现5.1 准备数据5.2 构建网络5.3 开始训练5.4 模型评估 6 识别效果7 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的手势识别实现 该项目较为新颖&#xff0c;适合作为竞赛课题…

1.3 Linux文件系统

一、Linux文件系统结构 Linux下都是文件&#xff0c;所以没有Windows一样的盘&#xff0c;有的只有文件夹。 cd /    // 进入根目录 ls     // 查看根目录"/"下的文件及文件夹 /bin    &#xff1a;存储了很多系统命令&#xff0c; /usr/sbin 也存储了…

数据库表的管理

表的基本概念 表是包含数据库中所有数据的数据库对象。数据在表中的组织方式与在电子表格中相似&#xff0c;都是 按行和列的格式组织的。每行代表一条唯一的记录&#xff0c;每列代表记录中的一个字段。例如&#xff0c;在包含公 司员工信息的表中&#xff0c;每行代表一名员工…

Python zip函数及用法与lambda表达式及用法

Python zip函数及用法 zip() 函数可以把两个列表“压缩”成一个 zip 对象&#xff08;可迭代对象&#xff09;&#xff0c;这样就可以使用一个循环并行遍历两个列表。为了测试 zip() 函数的功能&#xff0c;我们可以先在交互式解释器中“试验”一下该函数的功能。 >>&g…

群晖Video Station 添加海报墙-新方法

海报墙 一般我们找到的都是mp4、mkv等格式的视频资源&#xff0c;而没有像上图这样的海报资源&#xff0c;那要怎样实现海报墙呢&#xff1f; 按照以前的方法&#xff0c;是可以通过The Movie Database的API Key来搜刮电影海报信息&#xff0c;但是现在这个方法不行了 现在介绍…

力扣66. 加一

文章目录 力扣66. 加一示例代码实现总结收获 力扣66. 加一 示例 代码实现 class Solution {public int[] plusOne(int[] digits) {int ndigits.length;for(int in-1;i>0;i--){if(digits[i]!9){digits[i];for(int ji1;j<n;j){digits[j]0;}return digits;}}int[] resnew i…

使用String.valueOf()的坑

说明&#xff1a;记录一次使用String.valueOf()的坑&#xff0c;以下是一段有问题的代码&#xff1a; String count String.valueOf(listData.get(0).get(0).get("count");if (StringUtils.isBlank(count) || "0".equals(count)) {result.setResult(page)…

剑指 Offer(第2版)面试题 14:剪绳子

剑指 Offer&#xff08;第2版&#xff09;面试题 14&#xff1a;剪绳子 剑指 Offer&#xff08;第2版&#xff09;面试题 14&#xff1a;剪绳子解法1&#xff1a;动态规划解法2&#xff1a;数学 剑指 Offer&#xff08;第2版&#xff09;面试题 14&#xff1a;剪绳子 题目来源…

组合模式-C++实现

组合模式是一种结构型设计模式&#xff0c;它允许我们将对象组织成树状结构&#xff0c;并以递归的方式处理它们。该模式通过将单个对象和组合对象统一对待&#xff0c;使得客户端可以以一致的方式处理对象集合。 组合模式中有两种角色&#xff1a;组合和组件。组件就是叶子节…

状态类算法复杂排序输出

对于目标检测任务中对某一类的检测结果进行输出的时候&#xff0c;一般都是无序的&#xff0c;很明显这样子很难满足的我们的需求&#xff0c;我们更喜欢他是这样子输出的&#xff1a; &#x1f447; 我们可以看到——”按顺序输出结果“中的字段是完美的和上面图片中的识别结…

Redis 安装部署

文章目录 1、前言2、安装部署2.1、单机模式2.1.1、通过 yum 安装&#xff08;不推荐&#xff0c;版本老旧&#xff09;2.1.1、通过源码编译安装&#xff08;推荐&#xff09; 2.2、主从模式2.3、哨兵模式2.4、集群模式2.5、其他命令2.6、其他操作系统 3、使用3.1、Java 代码 —…

吉他初学者学习网站搭建系列(4)——如何查询和弦图

文章目录 背景实现ChordDbvexchords 背景 作为吉他初学者&#xff0c;如何根据和弦名快速查到和弦图是一个必不可少的功能。以往也许你会去翻和弦的书籍查询&#xff0c;像查新华字典那样&#xff0c;但是有了互联网后我们不必那样&#xff0c;只需要在网页上输入和弦名&#…

react之ReactRouter的使用

react之ReactRouter的使用 一、环境搭建二、抽象路由模块三、路由导航3.1 声明式导航3.2 编程式导航 四、导航传参4.1 searchParams 传参4.2 params 传参 五 、嵌套路由配置六、默认二级路由七、404页面配置八、俩种路由模式 一、环境搭建 1.创建项目安装依赖 npx create-rea…

2024年美国大学生数学建模竞赛(MCM/ICM)论文写作方法指导

一、前言 谈笑有鸿儒&#xff0c;往来无白丁。鸟宿池边树&#xff0c;僧敲月下门。士为知己者死&#xff0c;女为悦己者容。吴楚东南坼&#xff0c;乾坤日夜浮。剪不断&#xff0c;理还乱&#xff0c;是离愁&#xff0c;别是一番滋味在心头。 重要提示&#xff1a;优秀论文的解…

Matlab 加权均值质心计算(WMN)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 思路很简单,即将之前的均值中心,引入相关的权重函数(通常与距离有关),以此为每个点进行赋权,最后即可得到一个加权均值中心: 二、实现代码 %% ********<

[二分查找]LeetCode2009 :使数组连续的最少操作数

本文涉及的基础知识点 二分查找算法合集 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个整数数组 nums 。每一次操作中&#xff0c;你可以将 nums 中 任意 一个元素替换成 任意 整数。 如果 nums 满足以下条件&#xff0c;那么它是 连续的 …

ChatGPT 上线一周年

一年前&#xff0c;ChatGPT 正式上线&#xff0c;这无疑是个革命性的时刻&#xff0c;仅仅 6 周&#xff0c;ChatGPT 用户量达到 1 个亿。 这一年元宇宙作为概念垃圾彻底进入下水道&#xff0c;而 ChatGPT 和 AI 则席卷全球。 仅仅这一年&#xff0c;依托于 ChatGPT&#xff…

SmartSoftHelp8,数据库事务测试工具

SQL数据库事务测试工具 SQL数据库事务回滚测试工具 下载地址&#xff1a; https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg?pwd8888

二分查找:LeetCode2035:将数组分成两个数组并最小化数组和的差

本文涉及的基础知识点 二分查找算法合集 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个长度为 2 * n 的整数数组。你需要将 nums 分成 两个 长度为 n 的数组&#xff0c;分别求出两个数组的和&#xff0c;并 最小化 两个数组和之 差的绝对…