医学图像分割模型U-Net介绍和Kaggle的Top1解决方案源码解析

本文涉及的产品
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
模型训练 PAI-DLC,100CU*H 3个月
交互式建模 PAI-DSW,每月250计算时 3个月
简介: 医学图像分割模型U-Net介绍和Kaggle的Top1解决方案源码解析

介绍

计算机视觉是人工智能的一个领域,训练计算机解释和理解视觉世界。利用来自相机、视频和深度学习模型的数字图像,机器可以准确地识别和分类物体,然后对它们看到的东西做出反应。

在过去几年里,深度学习使得计算机视觉领域迅速发展。在这篇文章中,我想讨论计算机视觉中一个叫做分割的特殊任务。尽管研究人员已经提出了许多方法来解决这个问题,但我将讨论一种特殊的架构,即UNET,它使用一个完全卷积的网络模型来完成这项任务。

我们将利用UNET构建Kaggle SCIENCE BOWL 2018 挑战赛的第一解决方案。

先决条件

这篇文章是假设读者已经熟悉机器学习和卷积网络的基本概念。同时,他/她也有一些使用Python和Keras库的ConvNets的工作知识。

什么是市场细分?

分割的目的是将图像的不同部分分割成可感知的相干部分。细分有两种类型:

  • 语义分割(基于标记类的像素级预测)
  • 实例分割(目标检测和目标识别)

在这篇文章中,我们将主要关注语义分割。

U-NET是什么?

U-Net创建于2015年,是一款专为生物医学图像分割而开发的CNN。目前,U-Net已经成为一种非常流行的用于语义分割的端到端编解码器网络。它有一个独特的上下结构,有一个收缩路径和一个扩展路径。

640.png

U-NET 结构

640.png

U-Net下采样路径由4个block组成,其层数如下:

3x3 CONV (ReLU +批次标准化和Dropout使用)

3x3 CONV (ReLU +批次标准化和Dropout使用)

2x2 最大池化

当我们沿着这些块往下走时,特征图会翻倍,从64开始,然后是128、256和512。

瓶颈层由2个CONV层、BN和Dropout组成

与下采样相似上采样路径由4个块组成,层数如下:

反卷积层

从特征图中拼接出相应的收缩路径

3x3 CONV (ReLU +BN和Dropout)

3x3 CONV (ReLU +BN和Dropout)

KAGGLE DATA SCIENCE BOWL 2018 CHALLENGE

这项挑战的主要任务是在图像中检测原子核。通过自动化核检测,你可以帮助更快的解锁治疗。识别细胞核是大多数分析的起点,因为人体30万亿个细胞中的大多数都包含一个充满DNA的细胞核,而DNA是给每个细胞编程的遗传密码。识别细胞核使研究人员能够识别样本中的每个细胞,并通过测量细胞对各种治疗的反应,研究人员可以了解潜在的生物学过程。

640.jpg

样本图像,目标和方法

我们将使用U-Net这个专门为分割任务而设计的CNN自动生成图像遮罩

640.png

导入所有必要的包和模块

importosimportsysimportrandomimportwarningsimportnumpyasnpimportpandasaspdimportmatplotlib.pyplotaspltfromtqdmimporttqdmfromitertoolsimportchainfromskimage.ioimportimread, imshow, imread_collection, concatenate_imagesfromskimage.transformimportresizefromskimage.morphologyimportlabelfromkeras.modelsimportModel, load_modelfromkeras.layersimportInputfromkeras.layers.coreimportDropout, Lambdafromkeras.layers.convolutionalimportConv2D, Conv2DTransposefromkeras.layers.poolingimportMaxPooling2Dfromkeras.layers.mergeimportconcatenatefromkeras.callbacksimportEarlyStopping, ModelCheckpointfromkerasimportbackendasKimporttensorflowastfIMG_WIDTH=128IMG_HEIGHT=128IMG_CHANNELS=3TRAIN_PATH='./U_NET/train/'TEST_PATH='./U_NET/validation/'warnings.filterwarnings('ignore', category=UserWarning, module='skimage')
seed=42random.seed=seednp.random.seed=seed

为训练和测试数据收集我们的文件名

train_ids=next(os.walk(TRAIN_PATH))[1]
test_ids=next(os.walk(TEST_PATH))[1]

创建尺寸为128 x 128的图像遮罩(黑色图像)

print('Getting and resizing training images ... ')
X_train=np.zeros((len(train_ids), IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS), dtype=np.uint8)
Y_train=np.zeros((len(train_ids), IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)#Re-sizingourtrainingimagesto128x128#Notesys.stdoutprintsinfothatcanbeclearedunlikeprint.
#UsingTQDMallowsustocreateprogressbarssys.stdout.flush()
forn, id_intqdm(enumerate(train_ids), total=len(train_ids)):
path=TRAIN_PATH+id_img=imread(path+'/images/'+id_+'.png')[:,:,:IMG_CHANNELS]
img=resize(img, (IMG_HEIGHT, IMG_WIDTH), mode='constant', preserve_range=True)
X_train[n] =imgmask=np.zeros((IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
#Nowwetakeallmasksassociatedwiththatimageandcombinethemintoonesinglemaskformask_fileinnext(os.walk(path+'/masks/'))[2]:
mask_=imread(path+'/masks/'+mask_file)
mask_=np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant',
preserve_range=True), axis=-1)
mask=np.maximum(mask, mask_)
#Y_trainisnowoursinglemaskassociatedwithourimageY_train[n] =mask#GetandresizetestimagesX_test=np.zeros((len(test_ids), IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS), dtype=np.uint8)
sizes_test= []
print('Getting and resizing test images ... ')
sys.stdout.flush()
#Hereweresizeourtestimagesforn, id_intqdm(enumerate(test_ids), total=len(test_ids)):
path=TEST_PATH+id_img=imread(path+'/images/'+id_+'.png')[:,:,:IMG_CHANNELS]
sizes_test.append([img.shape[0], img.shape[1]])
img=resize(img, (IMG_HEIGHT, IMG_WIDTH), mode='constant', preserve_range=True)
X_test[n] =imgprint('Done!')

建立U-Net模型

defmy_iou_metric(label, pred):     metric_value=tf.py_func(iou_metric_batch, [label, pred], tf.float32)    
returnmetric_value#BuildU-Netmodel#Notewemakeourlayersvaraiblessothatwecanconcatenateorstack#Thisisrequiredsothatwecanre-createourU-NetModelinputs=Input((IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS))
s=Lambda(lambdax: x/255) (inputs)c1=Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (s)
c1=Dropout(0.1) (c1)
c1=Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c1)
p1=MaxPooling2D((2, 2)) (c1)c2=Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (p1)
c2=Dropout(0.1) (c2)
c2=Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c2)
p2=MaxPooling2D((2, 2)) (c2)c3=Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (p2)
c3=Dropout(0.2) (c3)
c3=Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c3)
p3=MaxPooling2D((2, 2)) (c3)c4=Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (p3)
c4=Dropout(0.2) (c4)
c4=Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c4)
p4=MaxPooling2D(pool_size=(2, 2)) (c4)c5=Conv2D(256, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (p4)
c5=Dropout(0.3) (c5)
c5=Conv2D(256, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c5)u6=Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same') (c5)
u6=concatenate([u6, c4])
c6=Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (u6)
c6=Dropout(0.2) (c6)
c6=Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c6)u7=Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same') (c6)
u7=concatenate([u7, c3])
c7=Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (u7)
c7=Dropout(0.2) (c7)
c7=Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c7)u8=Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same') (c7)
u8=concatenate([u8, c2])
c8=Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (u8)
c8=Dropout(0.1) (c8)
c8=Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c8)u9=Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same') (c8)
u9=concatenate([u9, c1], axis=3)
c9=Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (u9)
c9=Dropout(0.1) (c9)
c9=Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same') (c9)#Noteouroutputiseffectivelyamaskof128x128outputs=Conv2D(1, (1, 1), activation='sigmoid') (c9)model=Model(inputs=[inputs], outputs=[outputs])
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=[my_iou_metric])
model.summary()

训练我们的模型

model_path="./nuclei_finder_unet_1.h5"checkpoint=ModelCheckpoint(model_path,
monitor="val_loss",
mode="min",
save_best_only=True,
verbose=1)
earlystop=EarlyStopping(monitor='val_loss',
min_delta=0,
patience=5,
verbose=1,
restore_best_weights=True)
#Fitourmodelresults=model.fit(X_train, Y_train, validation_split=0.1,
batch_size=16, epochs=10,
callbacks=[earlystop, checkpoint])

生成验证数据的预测

#Predictontrainingandvalidationdata#Noteouruseofmean_ioumetrimodel=load_model('./nuclei_finder_unet_1.h5',
custom_objects={'my_iou_metric': my_iou_metric})
#thefirst90%wasusedfortrainingpreds_train=model.predict(X_train[:int(X_train.shape[0]*0.9)], verbose=1)
#thelast10%usedasvalidationpreds_val=model.predict(X_train[int(X_train.shape[0]*0.9):], verbose=1)
#preds_test=model.predict(X_test, verbose=1)
#Thresholdpredictionspreds_train_t= (preds_train>0.5).astype(np.uint8)
preds_val_t= (preds_val>0.5).astype(np.uint8)

在我们的训练数据上显示我们预测的遮罩

ix=random.randint(0, 602)
plt.figure(figsize=(20,20))
#Ouroriginaltrainingimageplt.subplot(131)
imshow(X_train[ix])
plt.title("Image")
#Ouroriginalcombinedmaskplt.subplot(132)
imshow(np.squeeze(Y_train[ix]))
plt.title("Mask")
#ThemaskourU-Netmodelpredictsplt.subplot(133)
imshow(np.squeeze(preds_train_t[ix] >0.5))
plt.title("Predictions")
plt.show()

最后这里是完整的代码:

数据集:https://www.kaggle.com/c/data-science-bowl-2018

本文代码:https://github.com/bhaveshgoyal27/mediumblogs/blob/master/U-Net.ipynb

目录
相关文章
|
11天前
|
机器学习/深度学习 人工智能 算法
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
DeepSeek-R1 通过创新的训练策略实现了显著的成本降低,同时保持了卓越的模型性能。本文将详细分析其核心训练方法。
293 11
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
|
4天前
|
人工智能 自然语言处理 算法
DeepSeek模型的突破:性能超越R1满血版的关键技术解析
上海AI实验室周伯文团队的最新研究显示,7B版本的DeepSeek模型在性能上超越了R1满血版。该成果强调了计算最优Test-Time Scaling的重要性,并提出了一种创新的“弱到强”优化监督机制的研究思路,区别于传统的“从强到弱”策略。这一方法不仅提升了模型性能,还为未来AI研究提供了新方向。
175 5
|
1月前
|
自然语言处理
高效团队的秘密:7大团队效能模型解析
3分钟了解7大团队效能模型,有效提升团队绩效。
125 7
高效团队的秘密:7大团队效能模型解析
|
1月前
|
Serverless 对象存储 人工智能
智能文件解析:体验阿里云多模态信息提取解决方案
在当今数据驱动的时代,信息的获取和处理效率直接影响着企业决策的速度和质量。然而,面对日益多样化的文件格式(文本、图像、音频、视频),传统的处理方法显然已经无法满足需求。
93 4
智能文件解析:体验阿里云多模态信息提取解决方案
|
1月前
|
文字识别 开发者 数据处理
多模态数据信息提取解决方案评测报告!
阿里云推出的《多模态数据信息提取》解决方案,利用AI技术从文本、图像、音频和视频中提取关键信息,支持多种应用场景,大幅提升数据处理效率。评测涵盖部署体验、文档清晰度、模板简化、示例验证及需求适配性等方面。方案表现出色,部署简单直观,功能强大,适合多种业务场景。建议增加交互提示、多语言支持及优化OCR和音频转写功能...
105 3
多模态数据信息提取解决方案评测报告!
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
30天前
|
自然语言处理 数据处理 索引
mindspeed-llm源码解析(一)preprocess_data
mindspeed-llm是昇腾模型套件代码仓,原来叫"modelLink"。这篇文章带大家阅读一下数据处理脚本preprocess_data.py(基于1.0.0分支),数据处理是模型训练的第一步,经常会用到。
52 0
|
2月前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。

热门文章

最新文章

推荐镜像

更多