常规赛:PALM病理性近视病灶检测与分割

具体介绍

赛题介绍

PALM病理性近视病灶检测与分割常规赛的重点是研究和发展与病理性近视诊断和患者眼底照片病变分割相关的算法。该常规赛的目标是评估和比较在一个常见的视网膜眼底图像数据集上检测病理性近视的自动算法。具体任务为:检测眼底图像是否出现视网膜萎缩病变和脱离病变,若有,需要实现病变区域的分割。点击前往比赛界面

数据简介

PALM病理性近视病灶检测与分割常规赛由中山大学中山眼科中心提供800张带萎缩和脱离病变分割标注的眼底彩照供选手训练模型,另提供400张带标注数据供平台进行模型测试。

数据说明

数据集中每个眼底彩照上都标注了与病理性近视相关的2种典型病变:斑片状视网膜萎缩(包括乳头周围萎缩)和视网膜脱离。像素级的病灶标注首先由中山大学中山眼科中心的7名眼科医生分别手动进行,最后由另一位高级专家将7位医生的标注结果融合为一个标注金标准,并存储为BMP图像。分割图像大小与对应的眼底图像大小相同,标签如下:
  萎缩病变分割金标准:萎缩区域:0;背景:255;
  脱离病变分割金标准:脱离区域:0;背景:255。
  训练数据集
    文件名称:Train
    Train里有两个文件夹,一个是fundus_images,一个是Lesion_Masks。
      fundus_images文件夹内包含800张眼底彩照,分辨率为1444×1444,或2124×2056。命名形如H0001.jpg、N0001.jpg、P0001.jpg和V0001.jpg。
      Lesion_Masks文件夹内包含两个文件夹:Atrophy和Detachment,其中,Atrophy文件夹包含fundus_images里眼底彩照的萎缩病变区域分割金标准,大小与对应的眼底彩照一致。命名前缀与对应眼底图像一致,后缀为bmp。同理,Detachment文件夹包含fundus_images里眼底彩照的脱离病变区域分割金标准,大小与对应的眼底彩照一致,命名前缀与对应眼底图像一致,后缀为bmp。请注意,若Lesion_Masks中无某张眼底图像的病灶分割结果,说明该图像中不包含对应的病灶区域。
  测试数据集
    文件名称:PALM-Testing400-Images.zip
    压缩包里包含400张眼底彩照,命名形如T0001.jpg。

简要总结

给定一组图片与两种分割任务在这组图片上的分割结果,要求训练对应的模型,对测试集分别给出这两种分割任务的分割结果

项目说明

0.86278result.zip对应了我的最高得分结果。

Detcsvfile/ResNet101_vd_ssld_10_6_3_6_0.83333_0.73032.csv对应了某次分类模型的运行结果,如没有特殊需求,请勿删除本csv文件,后面调用时会用到。

点击前往浏览测试记录 如果你对于如何从一个结果慢慢调整到一个比较好的结果的过程比较感兴趣的话,欢迎前往我的另外一个项目,这个项目和本项目几乎一致,但没有进行整理,里面纯粹是我的个人运行记录和总结,可能看起来比较乱(直接点击链接在网页上会因为表格长度超出看不到总结的文字,可以复制粘贴或者在运行界面查看)。但是也许你可以从中了解到一个并非大佬的人的逐渐修改项目调优的过程。如果你认为这个测试记录是有价值的,便于你看懂的,欢迎你在之后项目中也公开自己的寻优过程促进大家的交流和思考~

方案设计思路

大思路

对于通常的分割任务,只需要设计分割模型进行处理。对于这一任务,给定的训练数据中,有大量的样本不需要被分割(即分割结果为全白);对于预测样本,也有大量样本不需要被分割。因此,对于这个任务,有必要先构造分类模型,区分出样本是否有必要被分割,然后再构造分割模型进行分割。

小细节

对于Atrophy,大量样本都是需要被分割的,所以最终预测的时候,可以先分类,再分割;训练的时候,常规构造分类模型的训练,也可以将全部数据丢给分割模型进行训练。
对于Detachment,大量样本都是不需要分割的,所以最终预测的时候,必须先分类,再分割;训练的时候,分类的模型的构造要注重数据的平衡仅应使用应当被分割的样本训练分割模型。

版本说明(!非常重要!)

大家打开就能看到的版本,应当对应了我的最高得分的版本

这个版本中使用了非常丰富非常规操作,比如截取了他人的训练结果代替自己的部分运行结果,勾心斗角地计算预测集中需要Detachment的样本的数量,蓄意构造分类效果不是那么好的分类器,然后进行集成以提高最后得分。这些特殊的操作将在对应部分进行解释说明。

总之,这个版本并不适合新手去跑通分类+分割的模型框架,因此我生成了版本1,虽然没有详细的描述,但是大致遵循了 定义分类训练函数 - 定义分割训练函数 - 定义分类分割预测函数 - Atr训练分类分割&预测 - Det训练分类分割&预测 - 打包结果 ,应该不是特别难看懂,封包应该做的比较实在,看着函数名捋一遍应该对于新手来说不算太费劲。

特别鸣谢与说明

  1. 感谢yyyokay的项目给不喜欢配置化训练的我提供了学习PaddleSeg调用式训练的机会。
  2. 感谢Niki_173在飞桨常规赛:PALM病理性近视病灶检测与分割 2021 6月第3名方案中保存下来了分割结果。因为我使用Unet进行Atr分割的结果不是特别好,所以我尝试参考之前的大佬们训练时使用的EMAnet,也许是我程序写的有问题,调用式使用EMAnet总是报错。因此,我直接从飞桨常规赛:PALM病理性近视病灶检测与分割 2021 6月第3名方案中下载分割结果,并将其中的Atr分割结果替代我自己训练的Unet网络在Atr部分的分割结果。该结果命名为Niki_1732021.8result.zip在本项目中使用。

具体方案内容

一些准备工作

数据准备

# 下载数据与解压数据
import os
import urlliburl='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%97%85%E7%90%86%E6%80%A7%E8%BF%91%E8%A7%86%E7%97%85%E7%81%B6%E6%A3%80%E6%B5%8B%E4%B8%8E%E5%88%86%E5%89%B2.zip'if not os.path.exists('./work/Train_and_test.zip'):print("Downloading start!")urllib.request.urlretrieve(url, "./work/Train_and_test.zip")  print("Downloading end!")
else:print("Already Downloading")! unzip -oq ./work/Train_and_test.zip -d ./work
! unzip -oq /home/aistudio/Niki_1732021.8result.zip -d work/Niki_173

准备库

!pip install "numpy<=1.19.5" -i https://mirror.baidu.com/pypi/simple
!pip install "paddlex==2.0.0" -i https://mirror.baidu.com/pypi/simple
!pip install paddleseg
#导入常用的库
import os
import random
import numpy as np
from random import shuffle
import cv2
import paddle
from PIL import Image
import shutil
import re
from paddle.vision.transforms import functional as F
import os.path
import paddleseg.transforms as T
from paddleseg.datasets import OpticDiscSeg,Dataset
import paddleseg.models
from paddleseg.models import UNet
from paddleseg.models import OCRNet
from paddleseg.models.losses import CrossEntropyLoss,DiceLoss, MixedLoss
from paddleseg.core import train
from paddleseg.core import evaluate
from paddleseg.core import predict
from PIL import Image
import paddlex as pdx
import paddleseg as pds

准备函数

分类函数

PaddleX的分类训练是依赖于对应的txt文件的,因此本部分主要由以下几个自定义函数组成:

  1. list2txtfile 将list写入指定文件
  2. get_train_val_file 划分list,构造训练集和验证集,不同的divide_type有不同的效果,可以促进det部分的训练样本平衡。
  3. generate_cls_file 重要函数,用户直接调用这个函数生成对应的训练集txt,验证集txt
  4. generate_cls_model 重要函数,用户直接调用这个函数生成对应的分类模型
# this code is created for cls-problems
def list2txtfile(mylist,mydir):with open(mydir,'w') as f:for item in mylist:f.write(item)def get_train_val_file(mylist,cut_percent=0.2,divide_type=0):random.shuffle(mylist)if divide_type==0:cut_point=int(len(mylist)*cut_percent)train=mylist[cut_point:]val=mylist[:cut_point]elif divide_type==1:# 保持类别的等比划分list0=[item for item in mylist if item[-2]=='0']list1=[item for item in mylist if item[-2]=='1']cut_point0=int(len(list0)*cut_percent)cut_point1=int(len(list1)*cut_percent)train=list0[cut_point0:]+list1[cut_point1:]val=list0[:cut_point0]+list1[:cut_point1]random.shuffle(train)random.shuffle(val)elif divide_type==2:# 保持类别的等比划分,并且通过减少数据的方式抑制不平衡问题list0=[item for item in mylist if item[-2]=='0']list1=[item for item in mylist if item[-2]=='1']list1=list1*int(64*2/len(list1))list0=list0[:(64*6-len(list1))]cut_point0=int(len(list0)*cut_percent)cut_point1=int(len(list1)*cut_percent)train=list0[cut_point0:]+list1[cut_point1:]val=list0[:cut_point0]+list1[:cut_point1]random.shuffle(train)random.shuffle(val)elif divide_type==3:# 保持类别的等比划分,并且通过增加数据的方式抑制不平衡问题list0=[item for item in mylist if item[-2]=='0']list1=[item for item in mylist if item[-2]=='1']list1=list1*int(len(list0)/len(list1))random.shuffle(list0)random.shuffle(list1)cut_point0=int(len(list0)*cut_percent)cut_point1=int(len(list1)*cut_percent)train=list0[cut_point0:]+list1[cut_point1:]val=list0[:cut_point0]+list1[:cut_point1]random.shuffle(train)random.shuffle(val)return train,valdef generate_cls_file(img_dir,lab_dir,out_dir,divide_type=0):# img_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/fundus_image'# lab_dir=work/常规赛:PALM病理性近视病灶检测与分割/Train/Lesion_Masks/Atrophy# out_dir=work/os.makedirs(out_dir+'/cls/', exist_ok=True)train_dir=out_dir+'/cls/train.txt'eval_dir=out_dir+'/cls/eval.txt'label_dir=out_dir+'/cls/label.txt'img_names=[item.split('.')[0] for item in os.listdir(img_dir)]lab_names=[item.split('.')[0] for item in os.listdir(lab_dir)]cls_list=[]for item in img_names:if item in lab_names:cls_list.append(img_dir+'/'+item+'.jpg 1\n')else:cls_list.append(img_dir+'/'+item+'.jpg 0\n')list2txtfile(cls_list,out_dir+'/cls/ori_train_list.txt')train,val=get_train_val_file(cls_list,divide_type=divide_type)list2txtfile(train,out_dir+'/cls/train.txt')list2txtfile(val,out_dir+'/cls/eval.txt')list2txtfile(['0\n1\n'],out_dir+'/cls/label.txt')return train_dir,eval_dir,label_dirdef generate_cls_model(train_dir,eval_dir,label_dir,out_dir,root_dir='/home/aistudio',num_epochs=100):train_transforms = pdx.transforms.Compose([#T.Resize([500,600], interp='LINEAR', keep_ratio=False),pdx.transforms.RandomCrop(crop_size=224), pdx.transforms.RandomHorizontalFlip(), pdx.transforms.Normalize()])eval_transforms = pdx.transforms.Compose([#T.Resize([500,600], interp='LINEAR', keep_ratio=False),pdx.transforms.ResizeByShort(short_size=256), pdx.transforms.CenterCrop(crop_size=224), pdx.transforms.Normalize()])train_dataset = pdx.datasets.ImageNet(data_dir=root_dir,file_list=train_dir,label_list=label_dir,transforms=train_transforms,shuffle=True)eval_dataset = pdx.datasets.ImageNet(data_dir=root_dir,file_list=eval_dir,label_list=label_dir,transforms=eval_transforms)num_classes = len(train_dataset.labels)model = pdx.cls.ResNet101_vd_ssld(num_classes=num_classes)model.train(num_epochs=num_epochs,train_dataset=train_dataset,train_batch_size=64,eval_dataset=eval_dataset,# lr_decay_epochs=[4, 6, 8],save_interval_epochs=int(num_epochs/5),learning_rate=0.025,save_dir=out_dir+'/cls/model',use_vdl=False)

分割函数

PaddleX的分类训练是依赖于对应的txt文件的,因此本部分主要由以下几个自定义函数组成:

  1. generate_det_file 重要函数,用户直接调用这个函数生成对应的训练集txt,验证集txt
  2. generate_det_model 重要函数,用户直接调用这个函数生成对应的分割模型
  • 分类函数里的get_train_val_file,list2txtfile在generate_det_file,generate_det_model里还会继续调用的
# this code is create for det-problems, some functions from the previous block are re-used
def generate_det_file(img_dir,lab_dir,out_dir):# img_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/fundus_image'# lab_dir=work/常规赛:PALM病理性近视病灶检测与分割/Train/Lesion_Masks/Atrophy# out_dir=work/os.makedirs(out_dir+'/det/png/', exist_ok=True)train_dir=out_dir+'/det/train.txt'eval_dir=out_dir+'/det/eval.txt'img_names=[item.split('.')[0] for item in os.listdir(img_dir)]lab_names=[item.split('.')[0] for item in os.listdir(lab_dir)]det_list=[]for item in lab_names:im=Image.open(lab_dir+'/'+item+'.bmp')im=(np.array(im)/255).astype('uint8')im = Image.fromarray(im)im.save(out_dir+'/det/png/'+item+'.png')det_list.append(img_dir+'/'+item+'.jpg '+out_dir+'/det/png/'+item+'.png'+'\n')list2txtfile(det_list,out_dir+'/det/ori_train_list.txt')train,val=get_train_val_file(det_list)list2txtfile(train,out_dir+'/det/train.txt')list2txtfile(det_list,out_dir+'/det/eval.txt')#list2txtfile(val,out_dir+'/det/eval.txt')return train_dir,eval_dirdef generate_det_model(train_dir,eval_dir,out_dir,root_dir='/home/aistudio',iters=2000):train_transforms = [pds.transforms.ResizeStepScaling(min_scale_factor=0.5,max_scale_factor=2.0,scale_step_size=0.25),pds.transforms.Resize(target_size=(800,800)),pds.transforms.Normalize()  # 图像标准化]val_transforms = [pds.transforms.Resize(target_size=(800,800)),pds.transforms.Normalize()]# 构建训练集train_dataset = pds.datasets.Dataset(dataset_root=root_dir,train_path=train_dir,transforms=train_transforms,num_classes=2,mode='train')#验证集val_dataset = pds.datasets.Dataset(dataset_root=root_dir,val_path=eval_dir,transforms=val_transforms,num_classes=2,mode='val')model = pds.models.UNet(num_classes=2)base_lr =0.001#自动调整学习率lr =paddle.optimizer.lr.CosineAnnealingDecay(base_lr, T_max=(iters // 3), last_epoch=0.5)u_optimizer = paddle.optimizer.Adam(lr, parameters=model.parameters())mixtureLosses = [pds.models.losses.CrossEntropyLoss(),pds.models.losses.DiceLoss() ]mixtureCoef = [1.0,0.0]losses = {}losses['types'] = [pds.models.losses.MixedLoss(mixtureLosses, mixtureCoef)]losses['coef'] = [1]pds.core.train(model = model,train_dataset=train_dataset,val_dataset=val_dataset,optimizer=u_optimizer,save_dir=out_dir+'/det/model',iters=iters,  batch_size=8, save_interval=int(iters/5),log_iters=40,num_workers=2,losses=losses,use_vdl=False)

分类-分割预测

本部分主要由以下函数组成:

  1. myremovedirs 清空对应目录,保持空气清新生成的结果不会和之前的结果重合
  2. generate_white_pic 对于不需要分割的图片,直接按照图片尺寸生成全白像素图片作为分割结果
  3. predict_img 根据对应的模型进行分类和分割,将分类结果中不需要分割的生成全白图片,需要分割的生成对应的分割结果
# this code is created for cls and det predictions
def myremovedirs(mydir):if not os.path.exists(mydir): returntry: # 删除文件os.remove(mydir)except: # 文件删除失败可能为目录try:os.removedirs(mydir)except: # 可能不是空目录for item in os.listdir(mydir):myremovedirs(mydir+'/'+item)os.removedirs(mydir)def generate_white_pic(white_list,result_dir):for item in white_list:im=Image.open(item)row=np.array(im).shape[0]col=np.array(im).shape[1]im=(np.ones([row,col],dtype='int64')*255).astype('uint8')im = Image.fromarray(im)im.save(result_dir+'/'+item.split('/')[-1].split('.')[0]+'.png')def predict_img(test_dir,out_dir,result_dir,cls_model_dir=""):if cls_model_dir=="":cls_model_dir=out_dir+'/cls/model/best_model'# 清空目录myremovedirs(out_dir+'/pseudo_color_prediction')os.makedirs(result_dir, exist_ok=True)test_list=[]white_list=[]cls_model = pdx.load_model(cls_model_dir)for item in os.listdir(test_dir):fig_name=item.split('.')[0]tmp=cls_model.predict(test_dir+'/'+item)[0]['category']if tmp=='1':test_list.append(test_dir+'/'+fig_name+'.jpg')else:white_list.append(test_dir+'/'+fig_name+'.jpg')print('empty img are '+str(len(white_list))+", unempty img are "+str(len(test_list)))generate_white_pic(white_list,result_dir)transforms = pds.transforms.Compose([pds.transforms.Resize(target_size=(800, 800)),pds.transforms.Normalize()])model = pds.models.UNet(num_classes=2)predict(model,model_path = out_dir+'/det/model/best_model/model.pdparams',transforms=transforms,image_list=test_list,save_dir=out_dir,)for img in os.listdir(out_dir+'/pseudo_color_prediction'):img_dir=out_dir+'/pseudo_color_prediction/'+imgim=Image.open(img_dir)im=Image.fromarray(np.array(im)*255)im.save(result_dir+'/'+img)

基于Niki_1732021.8result.zip的Atrophy分类-分割预测

predict_img2 根据分类模型,将不需要分割的生成对应的全白图片,根据需要分割的图片编号,提取Niki_1732021.8result.zip中对应的分割结果。这一函数主要用于Atr的分类-分割预测。

def predict_img2(test_dir,out_dir,result_dir,cls_model_dir="",predicted_dir="work/Niki_173/Lesion_Segmentation/Atrophy"):if cls_model_dir=="":cls_model_dir=out_dir+'/cls/model/best_model'# 清空目录myremovedirs(out_dir+'/pseudo_color_prediction')os.makedirs(result_dir, exist_ok=True)test_list=[]white_list=[]cls_model = pdx.load_model(cls_model_dir)for item in os.listdir(test_dir):fig_name=item.split('.')[0]tmp=cls_model.predict(test_dir+'/'+item)[0]['category']if tmp=='1':test_list.append(test_dir+'/'+fig_name+'.jpg')else:white_list.append(test_dir+'/'+fig_name+'.jpg')print('empty img are '+str(len(white_list))+", unempty img are "+str(len(test_list)))generate_white_pic(white_list,result_dir)test_names=[img.split('/')[-1].split('.')[0] for img in test_list]for img in os.listdir(predicted_dir):if img.split('.')[0] in test_names:img_dir=predicted_dir+'/'+imgim=Image.open(img_dir)im.save(result_dir+'/'+img)

Atrophy分类&分割

Atrophy分类

img_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/fundus_image'
lab_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/Lesion_Masks/Atrophy'
out_dir='work/Atrophy'
root_dir='/home/aistudio'train_dir,eval_dir,label_dir=generate_cls_file(img_dir,lab_dir,out_dir)
generate_cls_model(train_dir,eval_dir,label_dir,out_dir,root_dir=root_dir,num_epochs=100)

Atrophy分割

img_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/fundus_image'
lab_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/Lesion_Masks/Atrophy'
out_dir='work/Atrophy'
root_dir='/home/aistudio'train_dir,eval_dir=generate_det_file(img_dir,lab_dir,out_dir)
# 由于分割的数据集准备太花时间,所以直接通过参数配置调用即可
train_dir='work/Atrophy/det/train.txt'
eval_dir='work/Atrophy/det/eval.txt'
out_dir='work/Atrophy'
root_dir='/home/aistudio'generate_det_model(train_dir,eval_dir,out_dir,root_dir=root_dir,iters=2000)

Atrophy预测

out_dir='work/Atrophy'
test_dir='work/常规赛:PALM病理性近视病灶检测与分割/PALM-Testing400-Images'
result_dir='Lesion_Segmentation/Atrophy'
# predict_img(test_dir,out_dir,result_dir)
predict_img2(test_dir,out_dir,result_dir)

Detachment分割&分割

Detachment分类

img_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/fundus_image'
lab_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/Lesion_Masks/Detachment'
out_dir='work/Detachment'
root_dir='/home/aistudio'train_dir,eval_dir,label_dir=generate_cls_file(img_dir,lab_dir,out_dir,divide_type=3)
generate_cls_model(train_dir,eval_dir,label_dir,out_dir,root_dir=root_dir,num_epochs=10)

Detachment分割

img_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/fundus_image'
lab_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/Lesion_Masks/Detachment'
out_dir='work/Detachment'
root_dir='/home/aistudio'train_dir,eval_dir=generate_det_file(img_dir,lab_dir,out_dir)
generate_det_model(train_dir,eval_dir,out_dir,root_dir=root_dir,iters=200)

Detachment预测

out_dir='work/Detachment'
test_dir='work/常规赛:PALM病理性近视病灶检测与分割/PALM-Testing400-Images'
result_dir='Lesion_Segmentation/Detachment'
# cls_model_dir="work/Detachment/cls/model/epoch_4"
cls_model_dir=""
predict_img(test_dir,out_dir,result_dir,cls_model_dir=cls_model_dir)

打包

! zip -q -r result.zip Lesion_Segmentation

集成提分

看到这里是不是觉得很惊喜,很意外?上面的内容可以让得分有一点不一样了,但是压根不能让最后的得分达到目标值!因为分类器的存在,所有F1值都提升了!但是因为部分正例没有预测到,也就没有被分割,所以Dice得分又下降了!你很有可能得到的结果是这样的:

Score Atrophy_F1 Atrophy_DICE Detachment_F1 Detachment_DICE
0.69962 0.94037 0.69938 0.61538 0.59552
0.7444 0.95369 0.81221 0.45455 0.73032

终究起来这是因为我们还需要对Det部分进行特别地优化处理!

Det数据的分析

首先,我们需要对Det部分有一个良好地认识,比如先认识一下得分中的F1。如果我们不做分割,得分中的F1就会保持在0.03的水平,这时候recall=1,求解pre可以得到大约为0.015,一共400个样本,测试集共6个正例。有了这个信息,我们可以很轻松知道自己分类结果中究竟包含几个正例了。并且可以注意到,此时Dice得分很高,有0.85,所以只需要预测包含所有正例,做分割即可保证分割后Dice得分是满足目标的。

然后,我们可以反推一下,自己的容错率是多少。即了解一下自己的分类结果中的FP最多是多少,大致可以知道3个FP成为了容错上限。

现在,我们就可以快乐地构造分类器,进行集成了。

一些函数

# 特别章节,用于保存csv文件,方便后期投票学习,这里返回df方便了解究竟哪些样本被分为正例
def get_det_cls_csv(test_dir,cls_model_dir,csv_dir):os.makedirs('Detcsvfile', exist_ok=True)if cls_model_dir=="":cls_model_dir=out_dir+'/cls/model/best_model'cls_model = pdx.load_model(cls_model_dir)cls_list=[]for item in os.listdir(test_dir):fig_name=item.split('.')[0]tmp=cls_model.predict(test_dir+'/'+item)[0]['category']cls_list.append([fig_name,tmp])df=pd.DataFrame(cls_list,columns=['img','type'])df=df.sort_values(by='img')df.to_csv('Detcsvfile/'+csv_dir+'.csv',index=None,header=None)return df# 和前面的内容相比,这里更替了一下transform
def generate_cls_model2(train_dir,eval_dir,label_dir,out_dir,root_dir='/home/aistudio',num_epochs=100):train_transforms = pdx.transforms.Compose([#T.Resize([500,600], interp='LINEAR', keep_ratio=False),pdx.transforms.Resize([800,800]),pdx.transforms.RandomHorizontalFlip(), pdx.transforms.Normalize()])eval_transforms = pdx.transforms.Compose([#T.Resize([500,600], interp='LINEAR', keep_ratio=False),pdx.transforms.Resize([800,800]),pdx.transforms.Normalize()])train_dataset = pdx.datasets.ImageNet(data_dir=root_dir,file_list=train_dir,label_list=label_dir,transforms=train_transforms,shuffle=True)eval_dataset = pdx.datasets.ImageNet(data_dir=root_dir,file_list=eval_dir,label_list=label_dir,transforms=eval_transforms)num_classes = len(train_dataset.labels)model = pdx.cls.ResNet101_vd_ssld(num_classes=num_classes)model.train(num_epochs=num_epochs,train_dataset=train_dataset,train_batch_size=16,eval_dataset=eval_dataset,# lr_decay_epochs=[4, 6, 8],save_interval_epochs=4, # int(num_epochs/5),learning_rate=0.025,save_dir=out_dir+'/cls/model',use_vdl=False)# 这里构造一个一票通过制的分类结果集成
# ResNet101_vd_ssld_10_6_3_6_0.83333_0.73032.csv是divide_type=3,epoch=6的训练结果,6个正例
def predict_img3(test_dir,out_dir,result_dir,cls_model_dir=""):if cls_model_dir=="":cls_model_dir=out_dir+'/cls/model/best_model'# 清空目录myremovedirs(out_dir+'/pseudo_color_prediction')os.makedirs(result_dir, exist_ok=True)test_list=[]white_list=[]df=pd.read_csv('Detcsvfile/ResNet101_vd_ssld_10_6_3_6_0.83333_0.73032.csv',header=None)df=df[df[1]==1]check_list=np.array(df[0]).tolist()count=0cls_model = pdx.load_model(cls_model_dir)for item in os.listdir(test_dir):fig_name=item.split('.')[0]tmp=cls_model.predict(test_dir+'/'+item)[0]['category']if tmp=='1': count=count+1if tmp=='1' or fig_name in check_list:test_list.append(test_dir+'/'+fig_name+'.jpg')else:white_list.append(test_dir+'/'+fig_name+'.jpg')print('empty img are '+str(len(white_list))+", unempty img are "+str(len(test_list))+', real unempyt img are '+str(count))generate_white_pic(white_list,result_dir)transforms = pds.transforms.Compose([pds.transforms.Resize(target_size=(800, 800)),pds.transforms.Normalize()])model = pds.models.UNet(num_classes=2)predict(model,model_path = out_dir+'/det/model/best_model/model.pdparams',transforms=transforms,image_list=test_list,save_dir=out_dir,)for img in os.listdir(out_dir+'/pseudo_color_prediction'):img_dir=out_dir+'/pseudo_color_prediction/'+imgim=Image.open(img_dir)im=Image.fromarray(np.array(im)*255)im.save(result_dir+'/'+img)

训练分类器

img_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/fundus_image'
lab_dir='work/常规赛:PALM病理性近视病灶检测与分割/Train/Lesion_Masks/Detachment'
out_dir='work/Detachment'
root_dir='/home/aistudio'train_dir,eval_dir,label_dir=generate_cls_file(img_dir,lab_dir,out_dir,divide_type=3)
generate_cls_model2(train_dir,eval_dir,label_dir,out_dir,root_dir=root_dir,num_epochs=100)

预测

out_dir='work/Detachment'
test_dir='work/常规赛:PALM病理性近视病灶检测与分割/PALM-Testing400-Images'
result_dir='Lesion_Segmentation/Detachment'
cls_model_dir="work/Detachment/cls/model/epoch_100"
# cls_model_dir=""
asks/Detachment'
out_dir='work/Detachment'
root_dir='/home/aistudio'train_dir,eval_dir,label_dir=generate_cls_file(img_dir,lab_dir,out_dir,divide_type=3)
generate_cls_model2(train_dir,eval_dir,label_dir,out_dir,root_dir=root_dir,num_epochs=100)

预测

out_dir='work/Detachment'
test_dir='work/常规赛:PALM病理性近视病灶检测与分割/PALM-Testing400-Images'
result_dir='Lesion_Segmentation/Detachment'
cls_model_dir="work/Detachment/cls/model/epoch_100"
# cls_model_dir=""
predict_img3(test_dir,out_dir,result_dir,cls_model_dir=cls_model_dir)

打包

这次打包之后就可以获得目标的结果了!

! zip -q -r result.zip Lesion_Segmentation

一些结语

我也曾想过要不要整理一下,按照Atr-Det的顺序写,但是决定还是按照 通用分类分割 - 特别处理 顺序写了。一方面是Unet分割模型在后期的集成部分没有重新训练,另一方面可能这种方式跟容易让大家理解我的思考顺序。

回首自己跑出这个结果,觉得Paddle系列用的还是很开心的,轻松地用一些自己不是那么熟悉的内容,可以愉快地完成一些有意思的事情,但是使用过程中还是有很多迷茫,比如如何调参啥啥啥,模型如何使用啥啥啥,经常碰壁。甚至还想过说,把分类分割模型混在一起根据,同时训练,但是自己毕竟半路出家,也忙着毕业,就没整这些花里胡哨的操作。希望未来Paddle可以更好用。

请点击此处查看本环境基本用法.

Please click here for more detailed instructions.

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

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

    1 赛题背景 本赛题原型为ISBI2019PALM眼科大赛. 近视已成为全球公共卫生负担.在近视患者中,约35%为高度近视.近视导致眼轴长度的延长,可能引起视网膜和脉络膜的病理改变.随着近视屈光度的增 ...

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

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

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

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

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

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

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

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

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

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

  7. 智能交通组合拳--飞桨实现车辆类别/车牌/车速检测、跨境头跟踪、车流密度检测、逆行检测

    智能交通组合拳–飞桨实现车辆类别/车牌/车速检测.跨境头跟踪.车流密度检测.逆行检测 总体简介 这个项目的代码和文件全部都已经上传到百度aistudio上,有需要的伙伴的可以搜索下面的链接找到,那里已 ...

  8. PaddleOCR实践之飞桨常规赛:中文场景文字识别

    简介 本项目是参加飞桨常规赛:中文场景文字识别(已结束)的项目,项目score为85.87141. 生成的预测文件为work/PaddleOCR中的test2.txt文件 项目任务为识别包含中文文字的 ...

  9. 飞桨PaddlePaddle升级解读 | PaddleDetection物体检测统一框架

    目标检测是机器视觉领域的核心问题之一.7 月 3 日百度 AI 开发者大会,飞桨核心框架 Paddle Fluid v1.5 宣布开源了 PaddleDetection 物体检测统一框架,用户可以非常 ...

最新文章

  1. 解题报告:AcWing 352. 闇の連鎖(树上差分、方案统计)
  2. 微软开源可解释机器学习工具包lnterpretML
  3. 【bzoj2751】[HAOI2012]容易题(easy) 数论,简单题
  4. 13-Qt6 QMap
  5. prometheus实战:
  6. 蓝绿发布、滚动发布、灰度发布,有什么区别?
  7. 用VS.NET2003制作WEB应用程序的安装包
  8. poj2182 Lost Cows-暴力
  9. 双向循环链表【数据结构】
  10. ios 如何在cell中去掉_iOS开发:关于 去除UITableViewCell复用机制 的几种方法
  11. blongsTo 用法
  12. Python的if判断与while循环
  13. 没有一颗平常心的人千万不要做外贸
  14. java编程显当前月示日历表_显示当前月的日历 1(java实现)
  15. 生育医疗费用出院结算流程
  16. HMM隐马尔可夫模型详解
  17. 差分与反差分计算(MATLAB)
  18. python实现马科维茨模型的资本市场线_资产配置理论的基础之马科维茨模型
  19. 电源管理芯片TMI6201A,助力电池供电系统超长续航更有价值!
  20. 简单枚举(ZJM要抵御宇宙射线)

热门文章

  1. 【虚拟网络编辑器】vmnet8设置中出现错误,子网IP和子网掩码不一致
  2. 现代C++教程:高速上手(四)-容器
  3. 【React】Redux、React-Redux简介及应用
  4. 【ROOT from CERN】——如何读取Tree
  5. android标题栏沉浸式,Android沉浸式状态栏方法总结
  6. python(json):序列化 、反序列化 --- json.dump() / json.dumps() / json.load() / json.loads()的使用
  7. CAD二次开发(C#)第一个例子
  8. java 8583报文解析_ISO8583报文工具类(组装和解析报文) | 学步园
  9. mysql异地备份xtrabackup_xtrabackup备份(MySQL备份)与恢复
  10. xtrabackup 的全备和恢复