1. 毕业设计(论文)开题报告
当前的医学图像分析需求。在临床实践中,医生常常需要从大量的医学图像中识别出病变组织,以便进行准确的诊断和治疗方案选择。然而,人工检测病变组织存在一定的局限性,如易受疲劳、经验等因素影响,可能存在误诊或漏诊的情况。因此,我旨在通过研究先进的图像识别技术、机器学习和深度学习模型,开发一种能够准确、高效地检测胃肠息肉的自动化系统。 2.国内外现状
深度学习在国外的发展十分迅速。Yuan等人将旋转不变性和图像相似度引入算法,提出了用于内窥镜图像识别的RLLR-SENSENet网络;Fang等人将边缘信息引入算法,将网络分为区域提取和边缘提取2大分支,通过分支网络信息交互进行肠息肉信息的提取,但由于肠息肉成像差异息肉类型多样等导致检测结果假阳性高在算法优化方面:Fang等人将边缘信息引入算法,将网络分为区域提取和边缘提取2大分支,通过分支网络信息交互进行肠息肉信息的提取,但由于肠息肉成像差异大、息肉类型多样等导致检测结果假阳性高研究人员提出了许多新的优化算法,如自适应学习率算法、正则化算法、优化器算法等,这些算法可以提高深度学习模型的训练速度和精度。
李龙岩展开了利用深度学习算法对结肠息肉图像分割算法的研究。针对目前结肠息肉的分割难点,设计了改进 HarDNet-MSEG 算法对结肠息肉进行分割,提高了结肠息肉图像分割模型的分割速度和分割精度,减少了模型的参数量。肖鹏从轻量化网络的角度出发,将卷积神经网络与 Vision Transformer 的优势相结合,提出了 MVT 轻量化分割网络,并Swin-transformer 引入其中,提出了 Swin-MVT 轻量化分割网络,在保证结肠镜息肉图像分割效果的基础上,该方法成功实现了参数量和计算量的降低. 3.研究意义 本课题的研究具有重要的现实意义和科学价值。首先,胃肠息肉是一种常见的消化道疾病,早期诊断和治疗对于预防消化道癌症具有重要意义。通过本课题的研究,我们能够提高胃肠息肉的检测准确性和敏感性,降低漏诊和误诊的风险,为临床医生提供更可靠的支持和辅助。其次,本课题的研究成果不仅可以应用于胃肠息肉的检测,还可以为其他医学图像分析领域提供借鉴和参考,推动医学图像技术的发展和应用。此外,本课题的研究还可以为人工智能技术在医学领域的应用提供新的思路和方法,具有广泛的应用前景和深远的社会效益。 | ||
二、研究内容 1.学术构想与思路 1.主要内容 本研究精心选用了U-net模型作为设计的核心。众所周知,目前市面上已涌现出众多自动化检测息肉的技术,它们均源于人类对息肉特征的精细手工描绘。然而,在图像检测和医学图像处理等诸多领域,深度学习技术已经大放异彩,其性能显著超越了传统方法。通过将卷积神经网络融入结肠镜图像的识别任务之中,CNN模型已能更加出色地应对肠镜息肉图像的多样化挑战。尽管如此,鉴于训练数据集的有限规模和网络结构的复杂性,卷积神经网络仍存局限性。在视觉识别的诸多场景中,特别是医学图像的处理过程中,理想的输出应当是具备精确定位的信息,也就是说,为图像中的每一个像素点赋予恰当的类别标签,而不仅限于对整幅图像进行分类标注。鉴于此,本文着眼于对U-net模型进行精炼改良(如图一所示), 旨在显著提升结肠镜图像中息肉检测的精确度,并借助结肠表面的凸起特征进一步增强图像分割的效果。对U-net网络的优化分为两大策略:(1)加入通道注意力机制;(2)加入网络注意力机制。接下来,将分别对这三种网络模型进行实验,并运行以得出结果,最终通过对比实验数据,以辨识哪一模型的准确率最为卓越。本课题主要分为四个部分。
为了确保数据的准确性,本课题使用了开源数据集LIMUC中的上千张肠镜图像,将其按照八比二的比例划分为训练数据和测试数据。
首先,从多个来源收集包含胃肠息肉的图像数据集。然后,对数据进行预处理,包括图像标准化、去噪、裁剪等操作,以使图像数据更加规范化和易于分析。
根据内外结肠息肉分割的相关研究现状,目前的方法主要依赖人工设计的特征进行分割,而算法的准确度很大程度上依赖于这些特征。针对镜内息肉边界模糊和小目标难以定位等问题,本课题提出了对U-net模型进行改进以进行多特征识别。具体方法包括: ①加入通道注意力机制(图二):通道注意力自适应的校准每个通道的权重,这被看作是一个对象的选择过程,从而决定要注意什么。 ②加入通道注意力机制(图三):寻找图像最主要部分进行处理
可视化可以用tensorboard对训练进行可视化,并用pillow库来进行图像的处理展示 2.拟解决的关键问题 问题 通过对U-net的结肠息肉图像分割模型进行训练。发现U-net存在很大的误检现象。并且对息肉的边界分割比较粗糙。 2.拟采取的研究方法、技术路线、实施方案及可行性分析 1.研究方法 本文研究方法,是基于学校课程为基础,外加中国知网的对深度学习中的图像识别系统文献和b站某些教学视频。本课题进行检测息肉检测,用U-net网络模型与改进后的U-net网络模型来进行检测。针对镜内息肉边界的难区分以及小目标难以定位等问题,利用对U-net模型的改进来进行息肉多特征识别。1.要将U-net模型最后一层来增加准确率,可以引入注意力机制具体来说,可以在解码器的倒数第二层和完成上采样的解码器倒数第一层之间添加注意力模块。卷积下采样的过程中加入了通道注意力和空间注意力。然后将俩种数据结果进行对比,得出那个准确率更高。
(1)数据收集和预处理:首先,需要从多个来源收集包含胃肠息肉的图像数据集。然后,将进行数据预处理,包括图像标准化、去噪、裁剪等操作,以便使图像数据更加规范化和易于分析。同时,还将进行数据增强操作,如旋转、缩放、翻转等,以增加训练数据的多样性,这里将使用大量的图像别技术和算法,并将数据分为训练数据和测试数据。 (2)特征提取:先使用U-NET模型来提取图像中的特征,并利用深度学习技术来自动提取更丰富的特征。将加入U-NET模型来提取图像中的特征,以便用于模型训练。同时,我们还将对特征进行优化和调整,以适应不同的图像类型和处理需求。 (3)网络模型:用U-Net的整个结构主要分为两个部分组成,一个是U型结构里面的编码器和解码器,编码器很主要作用来识别,捕获输入的图像中的上下文语义信息。解码器主要是顾名思义是利用编码后的高层语义信息和通过跳跃链接传递过来的细节特征,一起解码为训练的语义标签。 (4)模型验证和测试:使用独立的验证集和测试集来评估模型的性能,并根据反馈进行模型调整。我们将分别使用验证集和测试集来评估模型的性能和泛化能力,并根据反馈进行相应的调整和优化。同时,还将对模型进行实时测试和评估,以确保其能够在实时或接近实时的速度下运行,并满足临床应用的需求。 (5)对比实验:将实验结果进行对比,得出那个改进方法得出的准确率最高。 (6)数据可视化:用tensorboard帮助我们可视化网络修炼过程中的个种参数,调整网络模型,网络参数
3.可行性分析 从应用可行性角度来看,医生常常需要从大量的医学图像中识别出病变组织,以便进行准确的诊断和治疗方案选择。然而,人工检测病变组织存在一定的局限性。肠镜图像息肉检测可以帮助医生更好的,高效地检测胃肠息肉的自动化系统 从技术可行性角度来看,随着人工智能高度发展,本检测的系统可以采用机器学习算法、openCV(Python OpenCV图像处理和图像识别技术:图像处理的各种运算,包括图像点运算、形态学处理、图像锐化、图像增强、图像平滑等,研究图像识别、图像分割、图像分类、图像特效处理以及图像处理相关技术更好的检测图像的特征和识别。 从经济可行性角度来看,测试系统由于其开发框架大多是开源的,和使用的软件等都是免费,除了数据原可能需要购买,除了需要花费大量的时间外,并无其他消费。所以本系统运行成本低,使用方便,在经济上是可行的。 | ||
三、研究计划及进度安排 | ||
起止时间 | 主要内容 | 预期目标 |
2023年11月11日-2023年12月24日 2023年12月25日-2024年2月7日 2024年2月8日-2024年4月6日 2024年4月7日-2024年4月22日 2024年4月23日-2024年5月6日 2024年5月7日-2024年5月30日 | 在查阅文献、广泛调研后,确定本课题的总体设计方案与结构 进一步整理分析文献资料,完成实验设计工作 通过设计思路的整理、完成实验方案和优化相关结果。初步完成毕业设计相关内容,写出论文初稿 完成论文终稿 将论文及相关材料汇总提交 进行论文答辩及后续的材料完善工作 | 完成开题报告 拟定写作提纲 顺利通过中期检查 完成论文重复率的自查 准备答辩PPT 完成答辩及后续修改工作 |
四、主要参考文献(宋体五号,行距固定值20磅,格式参考正文参考文献格式) [1]许增宝, 苏树智, 胡天良. 高效多注意力融合的U-Net结直肠息肉图像分割算法[J]. 湖北民族大学学报(自然科学版), 2023, 41(03): 353-359. [2]程立英, 刘祖琛, 谷利茹等. 基于深度学习的结肠息肉检测算法 [J]. 沈阳师范大学学报(自然科学版), 2023, 41(03): 274-279. [3]符道朋.基于深度学习的结肠息肉分割方法研究[D].南昌大学,2023.41(03):356-441. [4]Xiaoke L, Honghuan C, Wenbing J. DRI-Net: segmentation of polyp in colonoscopy images using dense residual-inception network[J]. Frontiers in Physiology, 2023, 14: 1290820-1290820. [5]基于医疗影像大数据中心的异常图像标注及机器学习系统, 横向项目, 2019.9.11- -2021.03.20. [6 ] AHN S B, HAN D S, BAE J H, et al. The miss rate forcolorectal adenoma determined by quality-adjusted, back-to-backcolonoscopies[J]. Gut Liver, 2012, 6(1): 64-70
[9] 赵立新,邢润哲,白银光,等. 深度学习在目标检测的研究综述[J]. 科学技术与工程,2021,21( 30) : 12787-12795. [10] 王旭阳. 基于深度学习的食道癌图像检测技术的研究[D].兰州: 兰州大学,2017. 15(2):201-260 [11]Hu J,Shen L,Sun G. Squeeze-and-excitation networks[C]/ /Proceedings of the IEEE Conference on Computer Vision and Pat-tern Recognition. New York: IEEE,2018: 7132-7141. [12]岳龙旺,魏青彪,程豪,等. 无环境阻力的尖端生长型软体机器人研究综述[J].科学技术与工程,2022,22 ( 6 ) :2159-2169. [13]MISAWA M, KUDO S E, MORI Y, et al. Current status and futureperspective on artificial intelligence for lower endoscopy[J]. DigEndosc, 2021, 33(2): 273-284. [14] Lim J. S., Astrid M., Yoon H. J., et al. Small object detection using context andattention[C]//2021 International Conference on Artificial Intelligence in Information andCommunication (ICAIIC). IEEE, 2021: 181-186 [15]金洪杨,董晓淦,魏青彪,刘景达,岳龙旺.面向胃息肉检测的深度学习神经网络优化[J].河南工业大学,河南牧业经济学院能源与智能工程学院.2023,23(15):150-23 | ||
指导教师意见 指导教师签字: 年 月 日 | ||
开题报告评审小组意见 评审小组负责人签字: 年 月 日 |
2. 基础框架与库介绍
- 安装
Python3.7以上或者Anaconda镜像
下载地址:Anaconda | The Operating System for AI
Pycharm专业版
Windows10环境
TensorFlow2.0以上版本
MATLAB2.6以上版本
本设计数据集下载网址:下载 - Grand Challenge (grand-challenge.org)https://chaos.grand-challenge.org/Download/
- 详细设计与代码
- TensorFlow简介
官网下载与学习:关于TensorFlow | TensorFlow中文官网
安装与教程:TensorFlow教程 - TensorFlow 教程 | BootWiki.com
TensorFlow是一个面向所有开发人员的开源机器学习框架。它用于实现机器学习和深度学习应用程序。为了开发和研究有关人工智能,Google团队创建了TensorFlow。TensorFlow是使用Python编程语言设计的,因此它是一个易于理解的框架。
- 关于Keras
Keras是一个非常方便的深度学习框架,它以TensorFlow或Theano为后端。用它可以快速地搭建深度网络,灵活地选取训练参数来进行网路训练。总之就是:灵活+快速!!!
3.U-Net网络详解
在图像分割任务特别是医学图像分割中,U-Net[1]无疑是最成功的方法之一,该方法在2015年MICCAI会议上提出,目前已达到四千多次引用。其采用的编码器(下采样)-解码器(上采样)结构和跳跃连接是一种非常经典的设计方法。U-Net最初是一个用于二维图像分割的卷积神经网络。这个结构就是先对图片进行卷积和池化,在Unet论文中是池化4次,比方说一开始的图片是224x224的,那么就会变成112x112,56x56,28x28,14x14四个不同尺寸的特征。然后我们对14x14的特征图做上采样或者反卷积,得到28x28的特征图,这个28x28的特征图与之前的28x28的特征图进行通道伤的拼接concat,然后再对拼接之后的特征图做卷积和上采样,得到56x56的特征图,再与之前的56x56的特征拼接,卷积,再上采样,经过四次上采样可以得到一个与输入图像尺寸相同的224x224的预测结果。
集体内容参考文章:https://zhuanlan.zhihu.com/p/93527125
- 问题分析
在医学诊断中,一般通过CT影像来确定肠镜息肉的位置、大小和判断是否发生转移癌变具有重要的意义。按照你的论文设计要求:
1、实现基于机器学习的图像处理算法;
2、实现基于机器学习的胃部肿瘤区域分割;
3、图形化展示胃部肿瘤2D分割。
我们要做的就是从已有的胃CT影像中分割出肿瘤的区域,肿瘤的区域掩模图是由专业医生描绘标注出来的,下面我们来看一组图
![]() | ![]() |
用于训练的CT影像图 | 由医生绘制的肿瘤区域 |
- 尽可能准确地分割出肿瘤区域;
- 无肿瘤的胃部CT影像,网络分割结果应为全黑;
- 评价指标为准确率百分比、Dice系数和损失函数;
利用深度学习解决问题具有较为固定的流程,具体可以概括为:
- 数据预处理:包括数据集准备、数据归一化、数据裁剪等等操作;
- 构建网络:根据具体问题的需要构建合适的网络,本文构建的网络是UNet;
- 编译网络:选择训练网络的优化器、学习率、损失函数和评价函数等等;
- 训练网络:设置batch_size,epoch,是否乱序训练,验证集分割比例等等;
- 测试网络:编写测试函数,查看网络分割效果并计算相关评价指标等等。
- 图片数据处理过程
U-Net肿瘤分割算法可以分解为多个步骤,数据预处理模块的工作包括:
胃部CT影像图片读取 -> 图片有效区域裁剪 -> 图像归一化 -> 分离训练集(train)和测试集(test) -> 保存数据和实验结果。
监督学习性深度学习需要大量的数据,所以胃癌CT影像图片数据需要很大的数据量。
- 数据集介绍
Train文件夹下面:我使用100位胃癌症肿瘤患者的CT影像文件夹,每位患者大概有30张左右的CT影像图,原本影像是dcm格式的,为了读取使用数据操作方便,统一将它读取后保存为".png"格式。其中,label文件夹保存了相对应的CT影像掩膜图图片。
特别注意的是:胃部肿瘤只发生在连接胃部的肠道或胃的内部内部,所以实际需要处理的区域并不需要整张胃部图片,适当的裁剪CT影像图可以提高U-net机器学习网络训练速度;
例如:
以U-Net网络为基本框架设计深层次的胃癌病理切片分割算法模型Deeper U-Net(DU-Net)。采用区域重叠分割法将数据分割成若干小块图片,然后利用预先训练好的U-Net网络模型对分割的小图片进行初次分割,重新合成新样本。采用重复学习的方法使用新样本进行多次重复训练。
- 因为,train训练文件夹下面的CT影像图数量不一样,所以我们首先要进行该文件夹下面的文件夹读取操作,然后再进行图片读取操作。
- 接下来就是遍历完所有的CT影像图,然后保存在列表x_train[ ]中。
- 分离训练集和测试
因为肿瘤分布具有连续性,所以为了避免局部特征过于集中,这里对数据集进行乱序操作,之后再按9:1分配训练集和测试集。
构建U_Net网络(你最好看看论原稿,很详细介绍原理)
训练结果:
- 从上图中结果可以看出,验证集(不参与训练)的loss总是比训练集的要大,即肿瘤分割效果总比训练集的差,这说明了我们评价网络要用未训练的数据进行测试,网络本身是通过不断地拟合训练集来达到训练效果的,所以用训练集的数据测试意义不大。验证集的Dice系数达到了80%以上,这是一个比较高的值,说明网络训练效果不错。在370多张测试集中,分割的肿瘤平均Dice系数达到了83.26%;这个结果表示网络分割的肿瘤区域与医生的掩膜极为相似。
- 训练结果如下:
D:\Develop_Code\py_workplace\Scripts\python.exe D:/Develop_Code/py_work/肿瘤图像2D分割系统/UNet/train.py
2024-03-17 10:31:39.024379: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'cudart64_101.dll'; dlerror: cudart64_101.dll not found
2024-03-17 10:31:39.024873: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
D:\Develop_Code\py_workplace\lib\site-packages\OpenSSL\crypto.py:8: CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography and will be removed in a future release.
from cryptography import utils, x509
2024-03-17 10:31:43.839245: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'nvcuda.dll'; dlerror: nvcuda.dll not found
2024-03-17 10:31:43.839325: W tensorflow/stream_executor/cuda/cuda_driver.cc:312] failed call to cuInit: UNKNOWN ERROR (303)
2024-03-17 10:31:43.844384: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: ZHAO
2024-03-17 10:31:43.844490: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: ZHAO
2024-03-17 10:31:43.844947: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN)to use the following CPU instructions in performance-critical operations: AVX2
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2024-03-17 10:31:43.864763: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x23a0e307b40 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2024-03-17 10:31:43.864903: I tensorflow/compiler/xla/service/service.cc:176] StreamExecutor device (0): Host, Default Version
Model: "functional_1"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_1 (InputLayer) [(None, 416, 416, 3) 0
__________________________________________________________________________________________________
conv2d (Conv2D) (None, 416, 416, 64) 1792 input_1[0][0]
__________________________________________________________________________________________________
activation (Activation) (None, 416, 416, 64) 0 conv2d[0][0]
__________________________________________________________________________________________________
conv2d_1 (Conv2D) (None, 416, 416, 64) 36928 activation[0][0]
__________________________________________________________________________________________________
batch_normalization (BatchNorma (None, 416, 416, 64) 256 conv2d_1[0][0]
__________________________________________________________________________________________________
activation_1 (Activation) (None, 416, 416, 64) 0 batch_normalization[0][0]
__________________________________________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 208, 208, 64) 0 activation_1[0][0]
__________________________________________________________________________________________________
conv2d_2 (Conv2D) (None, 208, 208, 128 73856 max_pooling2d[0][0]
__________________________________________________________________________________________________
activation_2 (Activation) (None, 208, 208, 128 0 conv2d_2[0][0]
__________________________________________________________________________________________________
conv2d_3 (Conv2D) (None, 208, 208, 128 147584 activation_2[0][0]
__________________________________________________________________________________________________
batch_normalization_1 (BatchNor (None, 208, 208, 128 512 conv2d_3[0][0]
__________________________________________________________________________________________________
activation_3 (Activation) (None, 208, 208, 128 0 batch_normalization_1[0][0]
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D) (None, 104, 104, 128 0 activation_3[0][0]
__________________________________________________________________________________________________
conv2d_4 (Conv2D) (None, 104, 104, 256 295168 max_pooling2d_1[0][0]
__________________________________________________________________________________________________
activation_4 (Activation) (None, 104, 104, 256 0 conv2d_4[0][0]
__________________________________________________________________________________________________
conv2d_5 (Conv2D) (None, 104, 104, 256 590080 activation_4[0][0]
__________________________________________________________________________________________________
batch_normalization_2 (BatchNor (None, 104, 104, 256 1024 conv2d_5[0][0]
__________________________________________________________________________________________________
activation_5 (Activation) (None, 104, 104, 256 0 batch_normalization_2[0][0]
__________________________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D) (None, 52, 52, 256) 0 activation_5[0][0]
__________________________________________________________________________________________________
conv2d_6 (Conv2D) (None, 52, 52, 512) 1180160 max_pooling2d_2[0][0]
__________________________________________________________________________________________________
activation_6 (Activation) (None, 52, 52, 512) 0 conv2d_6[0][0]
__________________________________________________________________________________________________
conv2d_7 (Conv2D) (None, 52, 52, 512) 2359808 activation_6[0][0]
__________________________________________________________________________________________________
batch_normalization_3 (BatchNor (None, 52, 52, 512) 2048 conv2d_7[0][0]
__________________________________________________________________________________________________
activation_7 (Activation) (None, 52, 52, 512) 0 batch_normalization_3[0][0]
__________________________________________________________________________________________________
max_pooling2d_3 (MaxPooling2D) (None, 26, 26, 512) 0 activation_7[0][0]
__________________________________________________________________________________________________
conv2d_8 (Conv2D) (None, 26, 26, 1024) 4719616 max_pooling2d_3[0][0]
__________________________________________________________________________________________________
activation_8 (Activation) (None, 26, 26, 1024) 0 conv2d_8[0][0]
__________________________________________________________________________________________________
conv2d_9 (Conv2D) (None, 26, 26, 1024) 9438208 activation_8[0][0]
__________________________________________________________________________________________________
batch_normalization_4 (BatchNor (None, 26, 26, 1024) 4096 conv2d_9[0][0]
__________________________________________________________________________________________________
activation_9 (Activation) (None, 26, 26, 1024) 0 batch_normalization_4[0][0]
__________________________________________________________________________________________________
conv2d_transpose (Conv2DTranspo (None, 52, 52, 512) 2097664 activation_9[0][0]
__________________________________________________________________________________________________
concatenate (Concatenate) (None, 52, 52, 1024) 0 conv2d_transpose[0][0]
conv2d_7[0][0]
__________________________________________________________________________________________________
conv2d_10 (Conv2D) (None, 52, 52, 512) 4719104 concatenate[0][0]
__________________________________________________________________________________________________
activation_10 (Activation) (None, 52, 52, 512) 0 conv2d_10[0][0]
__________________________________________________________________________________________________
conv2d_11 (Conv2D) (None, 52, 52, 512) 2359808 activation_10[0][0]
__________________________________________________________________________________________________
batch_normalization_5 (BatchNor (None, 52, 52, 512) 2048 conv2d_11[0][0]
__________________________________________________________________________________________________
activation_11 (Activation) (None, 52, 52, 512) 0 batch_normalization_5[0][0]
__________________________________________________________________________________________________
conv2d_transpose_1 (Conv2DTrans (None, 104, 104, 256 524544 activation_11[0][0]
__________________________________________________________________________________________________
concatenate_1 (Concatenate) (None, 104, 104, 512 0 conv2d_transpose_1[0][0]
conv2d_5[0][0]
__________________________________________________________________________________________________
conv2d_12 (Conv2D) (None, 104, 104, 256 1179904 concatenate_1[0][0]
__________________________________________________________________________________________________
activation_12 (Activation) (None, 104, 104, 256 0 conv2d_12[0][0]
__________________________________________________________________________________________________
conv2d_13 (Conv2D) (None, 104, 104, 256 590080 activation_12[0][0]
__________________________________________________________________________________________________
batch_normalization_6 (BatchNor (None, 104, 104, 256 1024 conv2d_13[0][0]
__________________________________________________________________________________________________
activation_13 (Activation) (None, 104, 104, 256 0 batch_normalization_6[0][0]
__________________________________________________________________________________________________
conv2d_transpose_2 (Conv2DTrans (None, 208, 208, 128 131200 activation_13[0][0]
__________________________________________________________________________________________________
concatenate_2 (Concatenate) (None, 208, 208, 256 0 conv2d_transpose_2[0][0]
conv2d_3[0][0]
__________________________________________________________________________________________________
conv2d_14 (Conv2D) (None, 208, 208, 128 295040 concatenate_2[0][0]
__________________________________________________________________________________________________
activation_14 (Activation) (None, 208, 208, 128 0 conv2d_14[0][0]
__________________________________________________________________________________________________
conv2d_15 (Conv2D) (None, 208, 208, 128 147584 activation_14[0][0]
__________________________________________________________________________________________________
batch_normalization_7 (BatchNor (None, 208, 208, 128 512 conv2d_15[0][0]
__________________________________________________________________________________________________
activation_15 (Activation) (None, 208, 208, 128 0 batch_normalization_7[0][0]
__________________________________________________________________________________________________
conv2d_transpose_3 (Conv2DTrans (None, 416, 416, 64) 32832 activation_15[0][0]
__________________________________________________________________________________________________
concatenate_3 (Concatenate) (None, 416, 416, 128 0 conv2d_transpose_3[0][0]
conv2d_1[0][0]
__________________________________________________________________________________________________
conv2d_16 (Conv2D) (None, 416, 416, 64) 73792 concatenate_3[0][0]
__________________________________________________________________________________________________
activation_16 (Activation) (None, 416, 416, 64) 0 conv2d_16[0][0]
__________________________________________________________________________________________________
conv2d_17 (Conv2D) (None, 416, 416, 64) 36928 activation_16[0][0]
__________________________________________________________________________________________________
batch_normalization_8 (BatchNor (None, 416, 416, 64) 256 conv2d_17[0][0]
__________________________________________________________________________________________________
activation_17 (Activation) (None, 416, 416, 64) 0 batch_normalization_8[0][0]
__________________________________________________________________________________________________
conv2d_18 (Conv2D) (None, 416, 416, 1) 65 activation_17[0][0]
==================================================================================================
Total params: 31,043,521
Trainable params: 31,037,633
Non-trainable params: 5,888
__________________________________________________________________________________________________
Found 500 images belonging to 1 classes.
WARNING:tensorflow:`period` argument is deprecated. Please use `save_freq` to specify the frequency in number of batches seen.
Found 500 images belonging to 1 classes.
Epoch 1/30
62/62 [==============================] - ETA: 0s - loss: -0.3943 - binary_accuracy: 0.6860 - iou: 0.2504 - dice_coef: 0.3943 Found 20 images belonging to 1 classes.
Found 20 images belonging to 1 classes.
62/62 [==============================] - 1826s 29s/step - loss: -0.3943 - binary_accuracy: 0.6860 - iou: 0.2504 - dice_coef: 0.3943 - val_loss: -0.3333 - val_binary_accuracy: 0.3998 - val_iou: 0.2007 - val_dice_coef: 0.3333
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 2/30
62/62 [==============================] - 1735s 28s/step - loss: -0.4082 - binary_accuracy: 0.7051 - iou: 0.2607 - dice_coef: 0.4094 - val_loss: -0.3250 - val_binary_accuracy: 0.4054 - val_iou: 0.1962 - val_dice_coef: 0.3250
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 3/30
62/62 [==============================] - ETA: 0s - loss: -0.4114 - binary_accuracy: 0.7175 - iou: 0.2637 - dice_coef: 0.4122
Epoch 00003: ReduceLROnPlateau reducing learning rate to 0.00010000000474974513.
62/62 [==============================] - 3768s 61s/step - loss: -0.4114 - binary_accuracy: 0.7175 - iou: 0.2637 - dice_coef: 0.4122 - val_loss: -0.2951 - val_binary_accuracy: 0.3749 - val_iou: 0.1734 - val_dice_coef: 0.2951
Epoch 4/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - 1783s 29s/step - loss: -0.4203 - binary_accuracy: 0.7100 - iou: 0.2698 - dice_coef: 0.4191 - val_loss: -0.3541 - val_binary_accuracy: 0.5925 - val_iou: 0.2153 - val_dice_coef: 0.3541
Epoch 5/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - 1786s 29s/step - loss: -0.4109 - binary_accuracy: 0.7152 - iou: 0.2616 - dice_coef: 0.4086 - val_loss: -0.3441 - val_binary_accuracy: 0.6837 - val_iou: 0.2105 - val_dice_coef: 0.3441
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 6/30
62/62 [==============================] - 1588s 26s/step - loss: -0.4226 - binary_accuracy: 0.7199 - iou: 0.2717 - dice_coef: 0.4229 - val_loss: -0.4424 - val_binary_accuracy: 0.8088 - val_iou: 0.2859 - val_dice_coef: 0.4424
Epoch 7/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - 1606s 26s/step - loss: -0.4074 - binary_accuracy: 0.7209 - iou: 0.2621 - dice_coef: 0.4076 - val_loss: -0.3553 - val_binary_accuracy: 0.8082 - val_iou: 0.2329 - val_dice_coef: 0.3553
Epoch 8/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4202 - binary_accuracy: 0.7348 - iou: 0.2716 - dice_coef: 0.4221
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 00008: ReduceLROnPlateau reducing learning rate to 1.0000000474974514e-05.
62/62 [==============================] - 2510s 40s/step - loss: -0.4202 - binary_accuracy: 0.7348 - iou: 0.2716 - dice_coef: 0.4221 - val_loss: -0.0602 - val_binary_accuracy: 0.8644 - val_iou: 0.0315 - val_dice_coef: 0.0602
Epoch 9/30
62/62 [==============================] - 1646s 27s/step - loss: -0.4314 - binary_accuracy: 0.7389 - iou: 0.2810 - dice_coef: 0.4328 - val_loss: -0.3680 - val_binary_accuracy: 0.8087 - val_iou: 0.2290 - val_dice_coef: 0.3680
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 10/30
62/62 [==============================] - ETA: 0s - loss: -0.4202 - binary_accuracy: 0.7344 - iou: 0.2700 - dice_coef: 0.4211
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 00010: ReduceLROnPlateau reducing learning rate to 1.0000000656873453e-06.
62/62 [==============================] - 1599s 26s/step - loss: -0.4202 - binary_accuracy: 0.7344 - iou: 0.2700 - dice_coef: 0.4211 - val_loss: -0.3822 - val_binary_accuracy: 0.7898 - val_iou: 0.2374 - val_dice_coef: 0.3822
Epoch 11/30
62/62 [==============================] - 1607s 26s/step - loss: -0.4302 - binary_accuracy: 0.7369 - iou: 0.2785 - dice_coef: 0.4298 - val_loss: -0.3810 - val_binary_accuracy: 0.7359 - val_iou: 0.2405 - val_dice_coef: 0.3810
Epoch 12/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4204 - binary_accuracy: 0.7370 - iou: 0.2726 - dice_coef: 0.4215
Epoch 00012: ReduceLROnPlateau reducing learning rate to 1.0000001111620805e-07.
62/62 [==============================] - 1592s 26s/step - loss: -0.4204 - binary_accuracy: 0.7370 - iou: 0.2726 - dice_coef: 0.4215 - val_loss: -0.3914 - val_binary_accuracy: 0.7291 - val_iou: 0.2473 - val_dice_coef: 0.3914
Epoch 13/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - 1583s 26s/step - loss: -0.4252 - binary_accuracy: 0.7357 - iou: 0.2732 - dice_coef: 0.4240 - val_loss: -0.3599 - val_binary_accuracy: 0.6845 - val_iou: 0.2195 - val_dice_coef: 0.3599
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 14/30
62/62 [==============================] - 1597s 26s/step - loss: -0.4269 - binary_accuracy: 0.7364 - iou: 0.2771 - dice_coef: 0.4278 - val_loss: -0.4441 - val_binary_accuracy: 0.7372 - val_iou: 0.2858 - val_dice_coef: 0.4441
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 15/30
62/62 [==============================] - 1502s 24s/step - loss: -0.4211 - binary_accuracy: 0.7362 - iou: 0.2712 - dice_coef: 0.4204 - val_loss: -0.3049 - val_binary_accuracy: 0.6860 - val_iou: 0.1836 - val_dice_coef: 0.3049
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 16/30
62/62 [==============================] - ETA: 0s - loss: -0.4158 - binary_accuracy: 0.7324 - iou: 0.2682 - dice_coef: 0.4164 WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 00016: ReduceLROnPlateau reducing learning rate to 1.000000082740371e-08.
62/62 [==============================] - 1567s 25s/step - loss: -0.4158 - binary_accuracy: 0.7324 - iou: 0.2682 - dice_coef: 0.4164 - val_loss: -0.3883 - val_binary_accuracy: 0.7140 - val_iou: 0.2458 - val_dice_coef: 0.3883
Epoch 17/30
62/62 [==============================] - 1526s 25s/step - loss: -0.4272 - binary_accuracy: 0.7386 - iou: 0.2766 - dice_coef: 0.4285 - val_loss: -0.3697 - val_binary_accuracy: 0.6880 - val_iou: 0.2269 - val_dice_coef: 0.3697
Epoch 18/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4166 - binary_accuracy: 0.7325 - iou: 0.2698 - dice_coef: 0.4178 WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 00018: ReduceLROnPlateau reducing learning rate to 1.000000082740371e-09.
62/62 [==============================] - 1586s 26s/step - loss: -0.4166 - binary_accuracy: 0.7325 - iou: 0.2698 - dice_coef: 0.4178 - val_loss: -0.3423 - val_binary_accuracy: 0.7106 - val_iou: 0.2071 - val_dice_coef: 0.3423
Epoch 19/30
62/62 [==============================] - 1578s 25s/step - loss: -0.4326 - binary_accuracy: 0.7398 - iou: 0.2825 - dice_coef: 0.4339 - val_loss: -0.3860 - val_binary_accuracy: 0.7167 - val_iou: 0.2413 - val_dice_coef: 0.3860
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 20/30
62/62 [==============================] - ETA: 0s - loss: -0.4320 - binary_accuracy: 0.7390 - iou: 0.2780 - dice_coef: 0.4306
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 00020: ReduceLROnPlateau reducing learning rate to 1.000000082740371e-10.
62/62 [==============================] - 1511s 24s/step - loss: -0.4320 - binary_accuracy: 0.7390 - iou: 0.2780 - dice_coef: 0.4306 - val_loss: -0.3341 - val_binary_accuracy: 0.6669 - val_iou: 0.2007 - val_dice_coef: 0.3341
Epoch 21/30
62/62 [==============================] - 1549s 25s/step - loss: -0.4051 - binary_accuracy: 0.7318 - iou: 0.2579 - dice_coef: 0.4051 - val_loss: -0.3497 - val_binary_accuracy: 0.6951 - val_iou: 0.2155 - val_dice_coef: 0.3497
Epoch 22/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4587 - binary_accuracy: 0.7454 - iou: 0.3029 - dice_coef: 0.4588 WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 00022: ReduceLROnPlateau reducing learning rate to 1.000000082740371e-11.
62/62 [==============================] - 1523s 25s/step - loss: -0.4587 - binary_accuracy: 0.7454 - iou: 0.3029 - dice_coef: 0.4588 - val_loss: -0.3359 - val_binary_accuracy: 0.6807 - val_iou: 0.2048 - val_dice_coef: 0.3359
Epoch 23/30
62/62 [==============================] - 1492s 24s/step - loss: -0.4100 - binary_accuracy: 0.7315 - iou: 0.2619 - dice_coef: 0.4102 - val_loss: -0.3637 - val_binary_accuracy: 0.7108 - val_iou: 0.2225 - val_dice_coef: 0.3637
Epoch 24/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4214 - binary_accuracy: 0.7367 - iou: 0.2725 - dice_coef: 0.4223
Epoch 00024: ReduceLROnPlateau reducing learning rate to 1.000000082740371e-12.
62/62 [==============================] - 1492s 24s/step - loss: -0.4214 - binary_accuracy: 0.7367 - iou: 0.2725 - dice_coef: 0.4223 - val_loss: -0.3597 - val_binary_accuracy: 0.6645 - val_iou: 0.2194 - val_dice_coef: 0.3597
Epoch 25/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - 1933s 31s/step - loss: -0.4315 - binary_accuracy: 0.7382 - iou: 0.2798 - dice_coef: 0.4325 - val_loss: -0.3518 - val_binary_accuracy: 0.6729 - val_iou: 0.2147 - val_dice_coef: 0.3518
Epoch 26/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4243 - binary_accuracy: 0.7384 - iou: 0.2736 - dice_coef: 0.4248
Epoch 00026: ReduceLROnPlateau reducing learning rate to 1.0000001044244145e-13.
62/62 [==============================] - 1509s 24s/step - loss: -0.4243 - binary_accuracy: 0.7384 - iou: 0.2736 - dice_coef: 0.4248 - val_loss: -0.3747 - val_binary_accuracy: 0.7099 - val_iou: 0.2307 - val_dice_coef: 0.3747
Epoch 27/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - 1505s 24s/step - loss: -0.4252 - binary_accuracy: 0.7377 - iou: 0.2758 - dice_coef: 0.4264 - val_loss: -0.3812 - val_binary_accuracy: 0.7058 - val_iou: 0.2356 - val_dice_coef: 0.3812
Epoch 28/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4214 - binary_accuracy: 0.7326 - iou: 0.2710 - dice_coef: 0.4209
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Epoch 00028: ReduceLROnPlateau reducing learning rate to 1.0000001179769417e-14.
62/62 [==============================] - 31958s 515s/step - loss: -0.4214 - binary_accuracy: 0.7326 - iou: 0.2710 - dice_coef: 0.4209 - val_loss: -0.3343 - val_binary_accuracy: 0.6906 - val_iou: 0.2039 - val_dice_coef: 0.3343
Epoch 29/30
62/62 [==============================] - 1778s 29s/step - loss: -0.4319 - binary_accuracy: 0.7402 - iou: 0.2812 - dice_coef: 0.4323 - val_loss: -0.2847 - val_binary_accuracy: 0.6877 - val_iou: 0.1667 - val_dice_coef: 0.2847
Epoch 30/30
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
62/62 [==============================] - ETA: 0s - loss: -0.4250 - binary_accuracy: 0.7357 - iou: 0.2738 - dice_coef: 0.4234
Epoch 00030: ReduceLROnPlateau reducing learning rate to 1.0000001518582595e-15.
62/62 [==============================] - 1632s 26s/step - loss: -0.4250 - binary_accuracy: 0.7357 - iou: 0.2738 - dice_coef: 0.4234 - val_loss: -0.3566 - val_binary_accuracy: 0.6712 - val_iou: 0.2194 - val_dice_coef: 0.3566
WARNING:tensorflow:Can save best model only with val_acc available, skipping.
Process finished with exit code 0
训练结果保存在\evaluation文件夹下的:show文件夹中
原始数据
第一张是网络U_Net的输入,第二张是网络的输出,第三张是医生提供的掩膜图。上面的测试评价都是对为训练的测试集进行的,也再次说明了网络训练得非常成功。肿瘤分割与肿瘤区域判断几乎达到97%以上的精度。
训练时间很漫长,自己多留点耐心,项目中我已经做过训练,可以直接运行预测即可:
3. 核心代码
import os
from model import unet
import tensorflow as tf
from tensorflow.keras.callbacks import ReduceLROnPlateau
from tensorflow.keras import backend as K
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import ModelCheckpoint
#图片大小
im_width = 416
im_height = 416
BATCH_SIZE = 8
train_files = './data/train/'
val_files = './data/val/'
if not os.path.exists("save_weights"):
os.makedirs("save_weights")
train_num = len(os.listdir(os.path.join(train_files,'image')))
val_num = len(os.listdir(os.path.join(val_files,'image')))
# 定义数据生成器函数
def data_generator(data_path, batch_size, aug_dict,
image_color_mode="rgb",
mask_color_mode="grayscale",
image_save_prefix="image",
mask_save_prefix="mask",
save_to_dir=None,
target_size=(im_width, im_height),
seed=1):
image_datagen = ImageDataGenerator(**aug_dict)
mask_datagen = ImageDataGenerator(**aug_dict)
image_generator = image_datagen.flow_from_directory(
data_path,
classes=['image'],
class_mode=None,
color_mode=image_color_mode,
target_size=target_size,
batch_size=batch_size,
save_to_dir=save_to_dir,
save_prefix=image_save_prefix,
seed=seed)
mask_generator = mask_datagen.flow_from_directory(
data_path,
classes=['label'],
class_mode=None,
color_mode=mask_color_mode,
target_size=target_size,
batch_size=batch_size,
save_to_dir=save_to_dir,
save_prefix=mask_save_prefix,
seed=seed)
train_gen = zip(image_generator, mask_generator)
for (img, mask) in train_gen:
img, mask = adjust_data(img, mask)
yield (img, mask)
# 处理数据函数
def adjust_data(img, mask):
img = img / 255
mask = mask / 255
mask[mask > 0.5] = 1
mask[mask <= 0.5] = 0
return (img, mask)
smooth = 100
# 定义Dice系数
def dice_coef(y_true, y_pred):
y_truef = K.flatten(y_true)
y_predf = K.flatten(y_pred)
And = K.sum(y_truef * y_predf)
return ((2 * And + smooth) / (K.sum(y_truef) + K.sum(y_predf) + smooth))
# 定义损失函数
def dice_coef_loss(y_true, y_pred):
return -dice_coef(y_true, y_pred)
# 定义iou函数
def iou(y_true, y_pred):
intersection = K.sum(y_true * y_pred)
sum_ = K.sum(y_true + y_pred)
jac = (intersection + smooth) / (sum_ - intersection + smooth)
return jac
def jac_distance(y_true, y_pred):
y_truef = K.flatten(y_true)
y_predf = K.flatten(y_pred)
return - iou(y_true, y_pred)
model = unet()
# 打印模型参数
model.summary()
#训练集图片做数据增强
train_generator_args = dict(rotation_range=0.2,
width_shift_range=0.05,
height_shift_range=0.05,
shear_range=0.05,
zoom_range=0.05,
horizontal_flip=True,
fill_mode='nearest')
#生成训练数据
train_gen = data_generator(train_files, BATCH_SIZE,
train_generator_args,
target_size=(im_height, im_width))
#生成验证数据
val_gen = data_generator(val_files, BATCH_SIZE,
dict(),
target_size=(im_height, im_width))
checkpoint = ModelCheckpoint(
filepath='./save_weights/myUnet.h5',
monitor='val_acc',
save_weights_only=False,
save_best_only=True,
mode='auto',
period=1
)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=2, verbose=1)
#编译模型
model.compile(optimizer=tf.keras.optimizers.Adam(1e-3), loss=dice_coef_loss, metrics=["binary_accuracy", iou, dice_coef])
history = model.fit(train_gen,
steps_per_epoch= train_num // BATCH_SIZE,
epochs=30,
validation_data = val_gen,
validation_steps= val_num // BATCH_SIZE,
callbacks=[checkpoint,reduce_lr])
model.save_weights('./save_weights/myUnet.h5')
代码2:
import os
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from glob import glob
from PIL import Image
from tensorflow.keras import backend as K
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.layers import concatenate
from tensorflow.keras.layers import BatchNormalization, Activation, Conv2DTranspose
from tensorflow.keras.layers import Input, Dropout, Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
class U_Net():
def __init__(self):
# 设置图片基本参数
self.height = 256
self.width = 256
self.channels = 1
self.shape = (self.height, self.width, self.channels)
# 优化器
optimizer = Adam(0.002, 0.5)
# u_net
self.unet = self.build_unet() # 创建网络变量
self.unet.compile(loss='mse',
optimizer=optimizer,
metrics=[self.metric_fun])
self.unet.summary()
def build_unet(self, n_filters=16, dropout=0.1, batchnorm=True, padding='same'):
# 定义一个多次使用的卷积块
def conv2d_block(input_tensor, n_filters=16, kernel_size=3, batchnorm=True, padding='same'):
# the first layer
x = Conv2D(n_filters, kernel_size, padding=padding)(
input_tensor)
if batchnorm:
x = BatchNormalization()(x)
x = Activation('relu')(x)
# the second layer
x = Conv2D(n_filters, kernel_size, padding=padding)(x)
if batchnorm:
x = BatchNormalization()(x)
X = Activation('relu')(x)
return X
# 构建一个输入
img = Input(shape=self.shape)
# contracting path
c1 = conv2d_block(img, n_filters=n_filters * 1, kernel_size=3, batchnorm=batchnorm, padding=padding)
p1 = MaxPooling2D((2, 2))(c1)
p1 = Dropout(dropout * 0.5)(p1)
c2 = conv2d_block(p1, n_filters=n_filters * 2, kernel_size=3, batchnorm=batchnorm, padding=padding)
p2 = MaxPooling2D((2, 2))(c2)
p2 = Dropout(dropout)(p2)
c3 = conv2d_block(p2, n_filters=n_filters * 4, kernel_size=3, batchnorm=batchnorm, padding=padding)
p3 = MaxPooling2D((2, 2))(c3)
p3 = Dropout(dropout)(p3)
c4 = conv2d_block(p3, n_filters=n_filters * 8, kernel_size=3, batchnorm=batchnorm, padding=padding)
p4 = MaxPooling2D((2, 2))(c4)
p4 = Dropout(dropout)(p4)
c5 = conv2d_block(p4, n_filters=n_filters * 16, kernel_size=3, batchnorm=batchnorm, padding=padding)
# extending path
u6 = Conv2DTranspose(n_filters * 8, (3, 3), strides=(2, 2), padding='same')(c5)
u6 = concatenate([u6, c4])
u6 = Dropout(dropout)(u6)
c6 = conv2d_block(u6, n_filters=n_filters * 8, kernel_size=3, batchnorm=batchnorm, padding=padding)
u7 = Conv2DTranspose(n_filters * 4, (3, 3), strides=(2, 2), padding='same')(c6)
u7 = concatenate([u7, c3])
u7 = Dropout(dropout)(u7)
c7 = conv2d_block(u7, n_filters=n_filters * 4, kernel_size=3, batchnorm=batchnorm, padding=padding)
u8 = Conv2DTranspose(n_filters * 2, (3, 3), strides=(2, 2), padding='same')(c7)
u8 = concatenate([u8, c2])
u8 = Dropout(dropout)(u8)
c8 = conv2d_block(u8, n_filters=n_filters * 2, kernel_size=3, batchnorm=batchnorm, padding=padding)
u9 = Conv2DTranspose(n_filters * 1, (3, 3), strides=(2, 2), padding='same')(c8)
u9 = concatenate([u9, c1])
u9 = Dropout(dropout)(u9)
c9 = conv2d_block(u9, n_filters=n_filters * 1, kernel_size=3, batchnorm=batchnorm, padding=padding)
output = Conv2D(1, (1, 1), activation='sigmoid')(c9)
return Model(img, output)
def metric_fun(self, y_true, y_pred):
fz = tf.reduce_sum(2 * y_true * tf.cast(tf.greater(y_pred, 0.1), tf.float32)) + 1e-8
fm = tf.reduce_sum(y_true + tf.cast(tf.greater(y_pred, 0.1), tf.float32)) + 1e-8
return fz / fm
def load_data(self):
x_train = [] # 定义一个空列表,用于保存数据集
x_label = []
for file in glob('./train/*'): # 获取文件夹名称
for filename in glob(file + '/*'): # 获取文件夹中的文件
img = np.array(Image.open(filename), dtype='float32') / 255
x_train.append(img[256:, 128:384])
for file in glob('./label/*'):
for filename in glob(file + '/*'):
img = np.array(Image.open(filename), dtype='float32') / 255
x_label.append(img[256:, 128:384])
x_train = np.expand_dims(np.array(x_train), axis=3) # 扩展维度,增加第4维
x_label = np.expand_dims(np.array(x_label), axis=3) # 变为网络需要的输入维度(num, 256, 256, 1)
np.random.seed(116) # 设置相同的随机种子,确保数据匹配
np.random.shuffle(x_train) # 对第一维度进行乱序
np.random.seed(116)
np.random.shuffle(x_label)
# 图片有三千张左右,按9:1进行分配
return x_train[:2700, :, :], x_label[:2700, :, :], x_train[2700:, :, :], x_label[2700:, :, :]
def train(self, epochs=101, batch_size=32):
os.makedirs('./weights', exist_ok=True)
# 获得数据
x_train, x_label, y_train, y_label = self.load_data()
# 加载已经训练的模型
self.unet.load_weights(r"./best_model.h5")
# 设置训练的checkpoint
callbacks = [EarlyStopping(patience=100, verbose=2),
ReduceLROnPlateau(factor=0.5, patience=20, min_lr=0.00005, verbose=2),
ModelCheckpoint('./weights/best_model.h5', verbose=2, save_best_only=True)]
# 进行训练
results = self.unet.fit(x_train, x_label, batch_size=batch_size, epochs=epochs, verbose=2,
callbacks=callbacks, validation_split=0.1, shuffle=True)
# 绘制损失曲线
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
loss = results.history['loss']
val_loss = results.history['val_loss']
metric = results.history['metric_fun']
val_metric = results.history['val_metric_fun']
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
x = np.linspace(0, len(loss), len(loss)) # 创建横坐标
plt.subplot(121), plt.plot(x, loss, x, val_loss)
plt.title("损失曲线"), plt.legend(['loss', 'val_loss'])
plt.xlabel("Epochs"), plt.ylabel("loss")
plt.subplot(122), plt.plot(x, metric, x, val_metric)
plt.title("标准曲线"), plt.legend(['metric', 'val_metric'])
plt.xlabel("Epochs"), plt.ylabel("Dice")
plt.show() # 会弹出显示框,关闭之后继续运行
fig.savefig('./evaluation/else/', bbox_inches='tight', pad_inches=0.1) # 保存绘制曲线的图片
plt.close()
def test(self, batch_size=1):
os.makedirs('./evaluation/test_result', exist_ok=True)
self.unet.load_weights(r"weights/best_model.h5")
# 获得数据
x_train, x_label, y_train, y_label = self.load_data()
test_num = y_train.shape[0]
index, step = 0, 0
self.unet.evaluate(y_train, y_label)
n = 0.0
while index < test_num:
print('schedule: %d/%d' % (index, test_num))
step += 1 # 记录训练批数
mask = self.unet.predict(x_train[index:index + batch_size]) > 0.1
mask_true = x_label[index, :, :, 0]
if (np.sum(mask) > 0) == (np.sum(mask_true) > 0):
n += 1
mask = Image.fromarray(np.uint8(mask[0, :, :, 0] * 255))
mask.save('./evaluation/test_result/' + str(step) + '.png')
mask_true = Image.fromarray(np.uint8(mask_true * 255))
mask_true.save('./evaluation/test_result/' + str(step) + 'true.png')
index += batch_size
acc = n / test_num * 100
print('测试数据的准确率为: %.2f%%' % acc)
def test1(self, batch_size=1):
self.unet.load_weights(r"weights/best_model.h5")
# 获得数据
x_train, x_label, y_train, y_label = self.load_data()
test_num = y_train.shape[0]
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
for epoch in range(5):
rand_index = []
while len(rand_index) < 3:
np.random.seed()
temp = np.random.randint(0, test_num, 1)
if np.sum(x_label[temp]) > 0: # 确保产生有结肠镜息肉的编号
rand_index.append(temp)
rand_index = np.array(rand_index).squeeze()
fig, ax = plt.subplots(3, 3, figsize=(18, 18))
for i, index in enumerate(rand_index):
mask = self.unet.predict(x_train[index:index + 1]) > 0.1
ax[i][0].imshow(x_train[index].squeeze(), cmap='gray')
ax[i][0].set_title('network input', fontsize=20)
# 计算dice系数
fz = 2 * np.sum(mask.squeeze() * x_label[index].squeeze())
fm = np.sum(mask.squeeze()) + np.sum(x_label[index].squeeze())
dice = fz / fm
ax[i][1].imshow(mask.squeeze())
ax[i][1].set_title('网络输出结果(%.4f)' % dice, fontsize=20) # 设置title
ax[i][2].imshow(x_label[index].squeeze())
ax[i][2].set_title('息肉掩膜标记', fontsize=20)
fig.savefig('./evaluation/show/%d_%d_%d.png' % (rand_index[0], rand_index[1], rand_index[2]),
bbox_inches='tight', pad_inches=0.1) # 保存绘制的图片
print('finished epoch: %d' % epoch)
plt.close()
if __name__ == '__main__':
unet = U_Net()
#unet.train() # 开始训练网络 训练时间2H很久,所以注销
unet.test() # 评价测试集并检测测试集结肠镜息肉分割结果
unet.test1() # 随机显示
3. 系统测试:
所有训练图和常规图皆可测试----
4. 联系讨论
微信 | |
![]() | ![]() |
5. 参考论文:
UNet++: A Nested U-Net Architecture for Medical Image Segmentation