1 赛题背景

本赛题原型为ISBI2019PALM眼科大赛。 近视已成为全球公共卫生负担。在近视患者中,约35%为高度近视。近视导致眼轴长度的延长,可能引起视网膜和脉络膜的病理改变。随着近视屈光度的增加,高度近视将发展为病理性近视,其特点是病理改变的形成:
(1)后极,包括镶嵌型眼底、后葡萄肿、视网膜脉络膜变性等;
(2)视盘,包括乳头旁萎缩、倾斜等;
(3)近视性黄斑,包括漆裂、福氏斑、CNV等。

病理性近视对患者造成不可逆的视力损害。因此,早期诊断和定期随访非常重要。

视网膜由黄斑向鼻侧约3mm处有一直径约1.5mm、境界清楚的淡红色圆盘状结构,称为视神经盘,简称视盘。视盘是眼底图像的一个重要特征,对其进行准确、快速地定位与分割对利用眼底图像进行疾病辅助诊断具有重要意义。


2 赛题介绍

PALM眼底视盘检测与分割常规赛的重点是研究和发展与患者眼底照片结构分割相关的算法。该常规赛的目标是评估和比较在一个常见的视网膜眼底图像数据集上分割视盘的自动算法。该任务目的是对眼底图像的视盘进行检测,若存在视盘结构,需从眼底图像中分割出视盘区域;若无视盘结构,分割结果直接置全背景。


【数据说明】

本次常规赛提供的金标准由中山大学中山眼科中心的7名眼科医生手工进行视盘像素级标注,之后由另一位高级专家将它们融合为最终的标注结果。存储为 BMP 图像,与对应的眼底图像大小相同,标签为 0 代表视盘(黑色区域);标签为 255 代表其他(白色区域)。

  • 训练数据集

文件名称:Train:Train文件夹里有 fundus_images 文件夹和 Disc_Masks 文件夹。

  1. fundus_images文件夹内包含800张眼底彩照,分辨率为1444×1444,或2124×2056。命名形如H0001.jpg、N0001.jpg、P0001.jpg和V0001.jpg。
  2. Disc_Masks文件夹内包含fundus_images里眼底彩照的视盘分割金标准,大小与对应的眼底彩照一致。命名前缀和对应的fundus_images文件夹里的图像命名一致,后缀为bmp。
  • 测试数据集

文件名称:PALM-Testing400-Images:包含400张眼底彩照,命名形如T0001.jpg。


3 技术方案

通过【赛题介绍】可知,本赛题为医学图像——眼底彩照图像中的语义分割 2 分类任务,尝试使用 PaddleSeg - API 版本实现数据变换、读取、训练和预测全流程。在此之前,先进行数据清洗转换成套件标准格式,使用 [PaddleX] 进行数据划分。

PaddleX: 飞桨全流程开发工具,集飞桨核心框架、模型库、工具及组件等深度学习开发所需全部能力于一身,打通深度学习开发全流程。PaddleX同时提供简明易懂的Python API,及一键下载安装的图形化开发客户端。用户可根据实际生产需求选择相应的开发方式,获得飞桨全流程开发的最佳体验。

PaddleSeg: 基于飞桨 PaddlePaddle 开发的端到端图像分割开发套件,涵盖了高精度和轻量级等不同方向的大量高质量分割模型。通过模块化的设计,提供了配置化驱动和API调用两种应用方式,帮助开发者更便捷地完成从训练到部署的全流程图像分割应用。

3.1 安装开发套件

其中PaddleX用于命令行下的数据划分,其他部分用PaddleSeg实现。

!pip install paddlex
!pip install paddleseg

3.2 导入依赖模块

import warnings
warnings.filterwarnings('ignore')import paddle
import paddleseg
from paddleseg import transforms as Timport os
import shutil
import globimport numpy as np
import pandas as pdimport cv2
import imghdr
from PIL import Image

3.3 数据获取与清洗

  • PaddleX 要求目录结构是PascalVOC结构的目录,方便进行数据划分。
  • 我们将对源数据目录重定义至如下格式:data/dataset/Train/{JPEGImages, Annotations}

这里是对官方数据进行下载,然后对相应的目录重命名,达到上述目录结构。

!wget https://bj.bcebos.com/v1/dataset-bj/%E5%8C%BB%E7%96%97%E6%AF%94%E8%B5%9B/%E5%B8%B8%E8%A7%84%E8%B5%9B%EF%BC%9APALM%E7%9C%BC%E5%BA%95%E5%BD%A9%E7%85%A7%E8%A7%86%E7%9B%98%E6%8E%A2%E6%B5%8B%E4%B8%8E%E5%88%86%E5%89%B2.zip -O data/dataset.zip
!unzip -oq data/dataset.zip -d data!rm -r data/__MACOSX
!mv data/常规赛:PALM眼底彩照视盘探测与分割 data/dataset!mv data/dataset/Train/fundus_image data/dataset/Train/JPEGImages
!mv data/dataset/Train/Disc_Masks data/dataset/Train/Annotations
!mv data/dataset/PALM-Testing400-Images data/dataset/Test

以上单元格运行完成后,得到如下目录结构。

!tree data/dataset -d
data/dataset
├── Test
└── Train├── Annotations└── JPEGImages4 directories
  • 数据清洗:原图和标注图的模式分别为 RGB(真彩色、三通道, JPG) 和 L(8位灰度图, PNG),并且尺寸(size)需要一致;
  • 另外,标注图的数值应该是从0开始递增的,所以对 0-255 标签映射到 1-0 标签。
image_path_list = glob.glob('data/dataset/Train/JPEGImages/*.jpg')for i in range(len(image_path_list)):image_path = image_path_list[i]image_name = str(image_path.split('/')[-1]).split('.')[0]label_path = os.path.join('data/dataset/Train/Annotations', f'{image_name}.bmp')try:assert imghdr.what(image_path) and imghdr.what(label_path)except:print(image_path, label_path)image = Image.open(image_path).convert('RGB')label = Image.open(label_path).convert('L')if image.size != label.size:image = image.resize(label.size, Image.ANTIALIAS)image.save(image_path)label = np.array(label, dtype='uint8')label = np.uint8((label == 0) * 1)cv2.imwrite(label_path.split('.')[0]+'.png', label)os.remove(label_path)

3.4 数据划分

  • 20%用于验证,0%用于测试(测试集为 data/dataset/Test/*.jpg),则80%用于训练。
!paddlex --split_dataset --format SEG\--dataset_dir data/dataset/Train\--val_value 0.2\--test_value 0

以上,得到 data/dataset/Train/{train_list.txt, val_list.txt, labels.txt} 三个文件。

笔者的得到的划分情况在 work/{train_list.txt, val_list.txt}

3.5 数据变换与读取

为了训练时 GPU 内存的固定,加快训练速度,这里将图像 Resize 到 512x512,另外做了 [-25, 25]°的随机旋转和垂直翻转,最后将图像归一化到 [-1, 1]。

train_transforms = [T.RandomRotation(max_rotation=25),T.Resize(target_size=(512, 512), interp='AREA'),T.RandomVerticalFlip(0.5),T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
]eval_transforms = [T.Resize(target_size=(512, 512), interp='AREA'),T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
]

定义训练数据和验证数据的读取器(paddleseg.datasets.Dataset 为自定义数据集),配置相应的参数。

train_dataset = paddleseg.datasets.Dataset(mode='train',num_classes=2,dataset_root='data/dataset/Train',train_path='work/train_list.txt',transforms=train_transforms)val_dataset = paddleseg.datasets.Dataset(mode='val',num_classes=2,dataset_root='data/dataset/Train',    val_path='work/val_list.txt',transforms=eval_transforms)

3.6 模型与超参数

先定义模型,配置FCN的backbone及相应的pretrain (IMAGENET+CITYSCAPES)。

其中的预训练权重来源为:https://github.com/paddlepaddle/PaddleSeg/tree/release/2.3/configs/fcn 。

backbone = paddleseg.models.backbones.HRNet_W18(pretrained='https://bj.bcebos.com/paddleseg/dygraph/hrnet_w18_ssld.tar.gz'
)model = paddleseg.models.FCN(num_classes=2,backbone=backbone,backbone_indices=(-1,),pretrained='https://bj.bcebos.com/paddleseg/dygraph/cityscapes/fcn_hrnetw18_cityscapes_1024x512_80k/model.pdparams')

构建自定义 Momentum 优化器,采用Warmup + Cosine-decay 学习率衰减策略,模型更新 10k 次参数,L2正则化系数 0.0001。

iters = 10000
train_batch_size = 4
learning_rate = 0.01decayed_lr = paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=learning_rate,T_max=iters)decayed_lr = paddle.optimizer.lr.LinearWarmup(learning_rate=decayed_lr,warmup_steps=1000,start_lr=0.0,end_lr=learning_rate)optimizer = paddle.optimizer.Momentum(learning_rate=decayed_lr,momentum=0.9,weight_decay=paddle.regularizer.L2Decay(1e-4),parameters=model.parameters())

定义损失函数,这里采用加权的 CE 和 DiceLoss。

from paddleseg.models import MixedLoss, CrossEntropyLoss, DiceLosslosses = {'types': [MixedLoss([CrossEntropyLoss(), DiceLoss()], [0.8, 0.2]),],'coef': [1]
}

开始训练:

  • 训练集和验证集;
  • 模型、优化器、损失函数;
  • 每步的批大小和总步数;
  • 配置训练过程,保存模型间隔步长,日志打印间隔步长,线程数,模型保存文件夹路径,默认最多保存 5 个。

输入终端命令 watch -n 0 nvidia-smi:得到内存使用情况为 4246MiB / 16160MiB。

from paddleseg.core import traintrain(train_dataset=train_dataset,val_dataset=val_dataset,model=model,optimizer=optimizer,losses=losses,iters=iters,batch_size=train_batch_size,save_interval=500,log_iters=50,num_workers=0,save_dir='output/FCN_HRNetW18_512x512_B8_CE.8+D.2_10k',use_vdl=True)

训练结束得到保存下来的模型权重文件 *.pdparams

4 评估与预测

这里是评估和预测的两个接口。

from paddleseg.core import evaluate
from paddleseg.core import predict

首先初始化训练时的模型架构 FCN+HRNetW18,之后载入训练好的参数(work/model.pdparams)。

model = paddleseg.models.FCN(num_classes=2,backbone=paddleseg.models.backbones.HRNet_W18(),backbone_indices=(-1,))params_path = 'work/model.pdparams'
model_state_dict = paddle.load(params_path)
model.set_dict(model_state_dict)

模型增强评估:包含水平翻转和垂直翻转。

evaluate(model,val_dataset,aug_eval=True,flip_horizontal=True,flip_vertical=True)

单张图片的预测结果可视化(这里要注意加上 T.Compose)。

image_list = ['data/dataset/Test/T0002.jpg']predict(model=model,model_path=params_path,transforms=T.Compose(eval_transforms),image_list=image_list,save_dir='one_predict')

PaddleSeg 预测得到两种类型图片,一种是叠加图(added_prediction),另一种是 3 通道伪彩色图像(pseudo_prediction)。

import matplotlib.pyplot as plt
%matplotlib inlineadded_prediction = cv2.imread('one_predict/added_prediction/T0002.jpg')
pseudo_prediction = cv2.imread('one_predict/pseudo_color_prediction/T0002.png')
gray_prediction = cv2.imread('one_predict/pseudo_color_prediction/T0002.png', cv2.IMREAD_GRAYSCALE)plt.figure(figsize=(8, 8))
plt.subplot(221)
plt.title('added_prediction')
plt.imshow(added_prediction[:, :, [2, 1, 0]])
plt.subplot(222)
plt.title('pseudo_color_prediction')
plt.imshow(pseudo_prediction[:, :, [2, 1, 0]])
plt.subplot(223)
plt.title('pseudo_color_prediction gray')
plt.imshow(gray_prediction, cmap='gray')
plt.tight_layout()
plt.show()

np.unique(gray_prediction, return_counts=True)
(array([38, 75], dtype=uint8), array([4309420,   57524]))

考虑如何生成比赛的提交文件(黑色区域 0 代表视盘,白色区域 255 代表其他):

  • 观察伪彩色图片的灰度图,可以知道灰度图的数值(黑色区域 38 - 白色区域 75)需要分别转换成(0 - 255)。

预测所有测试集图片,即将测试集图片路径都放入上方的 image_list 中即可。

image_list = glob.glob('data/dataset/Test/*.jpg')predict(model=model,model_path=params_path,transforms=T.Compose(eval_transforms),image_list=image_list,save_dir='test_predict')

对预测结果图像中的伪彩色图像进行数值映射,将图像另存为 work/Disc_Segmentation/*.png

if not os.path.exists('work/Disc_Segmentation'):os.makedirs('work/Disc_Segmentation')label_path_list = glob.glob('test_predict/pseudo_color_prediction/*.png')for path in label_path_list:img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)img = np.uint8((img == 38) * 255)cv2.imwrite(f"work/Disc_Segmentation/{path.split('/')[-1]}", img)

压缩文件夹,生成提交文件。

%cd work/
!zip -rq Disc_Segmentation.zip Disc_Segmentation
t8((img == 38) * 255)cv2.imwrite(f"work/Disc_Segmentation/{path.split('/')[-1]}", img)

压缩文件夹,生成提交文件。

%cd work/
!zip -rq Disc_Segmentation.zip Disc_Segmentation
%cd ../

5 项目总结

本项目使用 PaddleSeg-API 搭建 FCN 模型,以具有 CITYSCPES 预训练权重的 HRNet18 作为 Backbone,利用随机旋转、随机垂直翻转的数据增强,配置 Dice Loss + CE 混合损失函数和 Warmup + Cosine decay 的训练策略,完成了眼底视盘检测与分割赛题,提交分数可达到 0.96701。

改进方向

  • 训练数据的预处理、训练时的数据增强方法;
  • 模型和超参数的配置与调优;

我的 AI Studio 主页

[常规赛] PALM眼底彩照视盘探测与分割 - 10月第1名方案相关推荐

  1. [常规赛] PALM眼底彩照视盘探测与分割 - 9月第1名方案

    赛题链接:常规赛:PALM眼底彩照视盘探测与分割 赛题简介:ISBI2019 PALM眼科挑战赛赛题再现,提供800张眼底彩照训练数据集, 要求选手训练模型完成眼底视盘结构的探测和分割任务. 赛题背景 ...

  2. 常规赛:PALM眼底彩照视盘探测与分割202105-202205全时段第一名(得分0.97387)方案

    本来该比赛博主卷到写上一篇博文0.97123是不打算在卷了的,事情的起因也很简单博主4月底参加这个比赛的时候提交了结果,成绩0.96689很一般.不料,到了月底有人(202105-202204月份的全 ...

  3. 常规赛:PALM眼底彩照视盘探测与分割202105-202205全时段第二名(得分0.97123)方案

    这只是百度的aistudio平台的一个常规赛(可以一直刷榜的比赛,每月计算一次排名),虽然在整个时段是榜2,但只是一个普通的语义分割比赛,参数人数不过百.有意参赛刷榜的的朋友可以访问以下链接 常规赛: ...

  4. 飞桨常规赛:PALM眼底彩照中黄斑中央凹定位-9月第1名方案

    飞桨常规赛:PALM眼底彩照中黄斑中央凹定位-9月第1名方案 (1)比赛介绍 赛题介绍 榜首个人主页,戳此处查看 PALM黄斑定位常规赛的重点是研究和发展与患者眼底照片黄斑结构定位相关的算法.该常规赛 ...

  5. 飞桨常规赛:PALM眼底彩照中黄斑中央凹定位-11月第1名方案

    飞桨常规赛:PALM眼底彩照中黄斑中央凹定位-11月第1名方案 (1)比赛介绍 赛题介绍 榜首个人主页,戳此处查看 PALM黄斑定位常规赛的重点是研究和发展与患者眼底照片黄斑结构定位相关的算法.该常规 ...

  6. 飞桨常规赛:PALM病理性近视病灶检测与分割 - 10月第1名方案

    常规赛:PALM病理性近视病灶检测与分割 具体介绍 赛题介绍 PALM病理性近视病灶检测与分割常规赛的重点是研究和发展与病理性近视诊断和患者眼底照片病变分割相关的算法.该常规赛的目标是评估和比较在一个 ...

  7. 飞桨常规赛:PALM眼底彩照中黄斑中央凹定位

    飞桨常规赛:PALM眼底彩照中黄斑中央凹定位 aistudio地址: https://aistudio.baidu.com/aistudio/projectdetail/2190500?contrib ...

  8. 飞桨常规赛:黄斑中央凹定位(GAMMA挑战赛任务二) - 11月第3名方案

    飞桨常规赛:黄斑中央凹定位(GAMMA挑战赛任务二) 11月第3名方案--鸣沙山下.伽利略 比赛地址:https://aistudio.baidu.com/aistudio/competition/d ...

  9. 2018 AI Challenger全球AI挑战赛‘眼底水肿病变区域自动分割’赛道比赛总结

    2018 AI Challenger全球AI挑战赛'眼底水肿病变区域自动分割'赛道比赛总结 苏州的十月,无论是天气还是桂香都觉得让人无所适从,忙碌的低年级学生一阵风似的从身边经过,恍惚才觉得,这是我最 ...

最新文章

  1. ai条码插件免安装_ai条码插件2款下载|Barcode Toolbox插件+Barcode条码插件下载 - 偶要下载站...
  2. 【密码学】一万字带您走进密码学的世界(下)
  3. 【数据结构与算法】之深入解析“等差数列划分II”的求解思路与算法示例
  4. centos akonadi mysql,MySQL数据库之在CentOS7上安装MySQL5.7
  5. 信息学奥赛一本通(1400:统计单词数)
  6. 截屏状态监听 - iOS
  7. 计算机控制炉温实验,计算机控制(炉温控制)实验报告-20210412070439.docx-原创力文档...
  8. php : 收集整理的非常有用的函数
  9. java map格式化_字符串模板格式化输出map 值
  10. wpe修改充值_WPE修改基础第四课:封包分析教程
  11. C# 从入门到精通 学习笔记2 第3章 方法和作用域
  12. (全角→半角)把文字从PDF复制到Word,发现很宽但又不是多出空格?
  13. bex5执行oracle语句,BeX5
  14. 个人开发者基于可编程Web的产品尝试:QCon会前采访FaWave作者李华煜
  15. 互联网公司如何管理研发团队
  16. 基于SSM实现汽车配件商城系统
  17. 【自然语言处理】中文开源工具汇总(7种)
  18. kali修改用户名与密码
  19. htpc派_您应该为HTPC使用PCI,USB或基于网络的电视调谐器吗?
  20. 埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 E-小Y吃苹果

热门文章

  1. predis 连接redis哨兵模式
  2. 微博The Networker Society社交网络联盟正式成立
  3. docker buildx 构建arm64架构镜像
  4. 线性表(顺序存储结构)C语言
  5. 电商竞逐景区大数据 前景值得期待
  6. 湖北三本计算机排名2015,湖北省三本大学排名
  7. 当ORACLE处于数据库垄断时,会不会出现店大欺客
  8. MariaDB-点滴
  9. centos7安装tinyproxy代理服务器
  10. UEFI Framework - 1 [ EFI Architecture Overview ]