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

本文涉及的产品
交互式建模 PAI-DSW,每月250计算时 3个月
模型训练 PAI-DLC,100CU*H 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
简介: 医学图像分割模型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

目录
相关文章
|
9天前
|
自然语言处理
高效团队的秘密:7大团队效能模型解析
3分钟了解7大团队效能模型,有效提升团队绩效。
58 7
高效团队的秘密:7大团队效能模型解析
|
22天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
22天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
22天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
1月前
|
机器学习/深度学习 人工智能 PyTorch
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
本文探讨了Transformer模型中变长输入序列的优化策略,旨在解决深度学习中常见的计算效率问题。文章首先介绍了批处理变长输入的技术挑战,特别是填充方法导致的资源浪费。随后,提出了多种优化技术,包括动态填充、PyTorch NestedTensors、FlashAttention2和XFormers的memory_efficient_attention。这些技术通过减少冗余计算、优化内存管理和改进计算模式,显著提升了模型的性能。实验结果显示,使用FlashAttention2和无填充策略的组合可以将步骤时间减少至323毫秒,相比未优化版本提升了约2.5倍。
69 3
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
|
24天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
88 1
|
1月前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
23天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
17天前
|
监控 前端开发 API
一款基于 .NET MVC 框架开发、功能全面的MES系统
一款基于 .NET MVC 框架开发、功能全面的MES系统
|
4月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
55 7

热门文章

最新文章

推荐镜像

更多