0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

UNet和UNet++:医学影像经典分割网络对比

OpenCV学堂 来源:AI公园 作者:AI公园 2022-04-25 10:38 次阅读

导读

在不同的任务上对比了UNet和UNet++以及使用不同的预训练编码器的效果。

介绍

语义分割是计算机视觉的一个问题,我们的任务是使用图像作为输入,为图像中的每个像素分配一个类。在语义分割的情况下,我们不关心是否有同一个类的多个实例(对象),我们只是用它们的类别来标记它们。有多种关于不同计算机视觉问题的介绍课程,但用一张图片可以总结不同的计算机视觉问题:

5891bd82-c3e2-11ec-bce3-dac502259ad0.png

语义分割在生物医学图像分析中有着广泛的应用:x射线、MRI扫描、数字病理、显微镜、内窥镜等。https://grand-challenge.org/challenges上有许多不同的有趣和重要的问题有待探索。

从技术角度来看,如果我们考虑语义分割问题,对于N×M×3(假设我们有一个RGB图像)的图像,我们希望生成对应的映射N×M×k(其中k是类的数量)。有很多架构可以解决这个问题,但在这里我想谈谈两个特定的架构,Unet和Unet++。

有许多关于Unet的评论,它如何永远地改变了这个领域。它是一个统一的非常清晰的架构,由一个编码器和一个解码器组成,前者生成图像的表示,后者使用该表示来构建分割。每个空间分辨率的两个映射连接在一起(灰色箭头),因此可以将图像的两种不同表示组合在一起。并且它成功了!

58bd8a7a-c3e2-11ec-bce3-dac502259ad0.png

接下来是使用一个训练好的编码器。考虑图像分类的问题,我们试图建立一个图像的特征表示,这样不同的类在该特征空间可以被分开。我们可以(几乎)使用任何CNN,并将其作为一个编码器,从编码器中获取特征,并将其提供给我们的解码器。据我所知,Iglovikov & Shvets 使用了VGG11和resnet34分别为Unet解码器以生成更好的特征和提高其性能。

58dcf5cc-c3e2-11ec-bce3-dac502259ad0.png

TernausNet (VGG11 Unet)

Unet++是最近对Unet体系结构的改进,它有多个跳跃连接。

58f2818a-c3e2-11ec-bce3-dac502259ad0.png

根据论文, Unet++的表现似乎优于原来的Unet。就像在Unet中一样,这里可以使用多个编码器(骨干)来为输入图像生成强特征。

我应该使用哪个编码器?

这里我想重点介绍Unet和Unet++,并比较它们使用不同的预训练编码器的性能。为此,我选择使用胸部x光数据集来分割肺部。这是一个二值分割,所以我们应该给每个像素分配一个类为“1”的概率,然后我们可以二值化来制作一个掩码。首先,让我们看看数据。

5913b238-c3e2-11ec-bce3-dac502259ad0.png

来自胸片X光数据集的标注数据的例子

这些是非常大的图像,通常是2000×2000像素,有很大的mask,从视觉上看,找到肺不是问题。使用segmentation_models_pytorch库,我们为Unet和Unet++使用100+个不同的预训练编码器。我们做了一个快速的pipeline来训练模型,使用Catalyst (pytorch的另一个库,这可以帮助你训练模型,而不必编写很多无聊的代码)和Albumentations(帮助你应用不同的图像转换)。

  1. 定义数据集和增强。我们将调整图像大小为256×256,并对训练数据集应用一些大的增强。
importalbumentationsasA
fromtorch.utils.dataimportDataset,DataLoader
fromcollectionsimportOrderedDict

classChestXRayDataset(Dataset):
def__init__(
self,
images,
masks,
transforms):
self.images=images
self.masks=masks
self.transforms=transforms

def__len__(self):
return(len(self.images))

def__getitem__(self,idx):
"""Willloadthemask,getrandomcoordinatesaround/withthemask,
loadtheimagebycoordinates
"""
sample_image=imread(self.images[idx])
iflen(sample_image.shape)==3:
sample_image=sample_image[...,0]
sample_image=np.expand_dims(sample_image,2)/255
sample_mask=imread(self.masks[idx])/255
iflen(sample_mask.shape)==3:
sample_mask=sample_mask[...,0]
augmented=self.transforms(image=sample_image,mask=sample_mask)
sample_image=augmented['image']
sample_mask=augmented['mask']
sample_image=sample_image.transpose(2,0,1)#channelsfirst
sample_mask=np.expand_dims(sample_mask,0)
data={'features':torch.from_numpy(sample_image.copy()).float(),
'mask':torch.from_numpy(sample_mask.copy()).float()}
return(data)

defget_valid_transforms(crop_size=256):
returnA.Compose(
[
A.Resize(crop_size,crop_size),
],
p=1.0)

deflight_training_transforms(crop_size=256):
returnA.Compose([
A.RandomResizedCrop(height=crop_size,width=crop_size),
A.OneOf(
[
A.Transpose(),
A.VerticalFlip(),
A.HorizontalFlip(),
A.RandomRotate90(),
A.NoOp()
],p=1.0),
])

defmedium_training_transforms(crop_size=256):
returnA.Compose([
A.RandomResizedCrop(height=crop_size,width=crop_size),
A.OneOf(
[
A.Transpose(),
A.VerticalFlip(),
A.HorizontalFlip(),
A.RandomRotate90(),
A.NoOp()
],p=1.0),
A.OneOf(
[
A.CoarseDropout(max_holes=16,max_height=16,max_width=16),
A.NoOp()
],p=1.0),
])


defheavy_training_transforms(crop_size=256):
returnA.Compose([
A.RandomResizedCrop(height=crop_size,width=crop_size),
A.OneOf(
[
A.Transpose(),
A.VerticalFlip(),
A.HorizontalFlip(),
A.RandomRotate90(),
A.NoOp()
],p=1.0),
A.ShiftScaleRotate(p=0.75),
A.OneOf(
[
A.CoarseDropout(max_holes=16,max_height=16,max_width=16),
A.NoOp()
],p=1.0),
])

defget_training_trasnforms(transforms_type):
iftransforms_type=='light':
return(light_training_transforms())
eliftransforms_type=='medium':
return(medium_training_transforms())
eliftransforms_type=='heavy':
return(heavy_training_transforms())
else:
raiseNotImplementedError("Notimplementedtransformationconfiguration")
  1. 定义模型和损失函数。这里我们使用带有regnety_004编码器的Unet++,并使用RAdam + Lookahed优化器使用DICE + BCE损失之和进行训练。
importtorch
importsegmentation_models_pytorchassmp
importnumpyasnp
importmatplotlib.pyplotasplt
fromcatalystimportdl,metrics,core,contrib,utils
importtorch.nnasnn
fromskimage.ioimportimread
importos
fromsklearn.model_selectionimporttrain_test_split
fromcatalyst.dlimportCriterionCallback,MetricAggregationCallback
encoder='timm-regnety_004'
model=smp.UnetPlusPlus(encoder,classes=1,in_channels=1)
#model.cuda()
learning_rate=5e-3
encoder_learning_rate=5e-3/10
layerwise_params={"encoder*":dict(lr=encoder_learning_rate,weight_decay=0.00003)}
model_params=utils.process_model_params(model,layerwise_params=layerwise_params)
base_optimizer=contrib.nn.RAdam(model_params,lr=learning_rate,weight_decay=0.0003)
optimizer=contrib.nn.Lookahead(base_optimizer)
scheduler=torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer,factor=0.25,patience=10)
criterion={
"dice":DiceLoss(mode='binary'),
"bce":nn.BCEWithLogitsLoss()
}
  1. 定义回调函数并训练!
callbacks=[
#Eachcriterioniscalculatedseparately.
CriterionCallback(
input_key="mask",
prefix="loss_dice",
criterion_key="dice"
),
CriterionCallback(
input_key="mask",
prefix="loss_bce",
criterion_key="bce"
),

#Andonlythenweaggregateeverythingintooneloss.
MetricAggregationCallback(
prefix="loss",
mode="weighted_sum",
metrics={
"loss_dice":1.0,
"loss_bce":0.8
},
),

#metrics
IoUMetricsCallback(
mode='binary',
input_key='mask',
)

]

runner=dl.SupervisedRunner(input_key="features",input_target_key="mask")
runner.train(
model=model,
criterion=criterion,
optimizer=optimizer,
scheduler=scheduler,
loaders=loaders,
callbacks=callbacks,
logdir='../logs/xray_test_log',
num_epochs=100,
main_metric="loss",
minimize_metric=True,
verbose=True,
)

如果我们用不同的编码器对Unet和Unet++进行验证,我们可以看到每个训练模型的验证质量,并总结如下:

59583070-c3e2-11ec-bce3-dac502259ad0.png

Unet和Unet++验证集分数

我们注意到的第一件事是,在所有编码器中,Unet++的性能似乎都比Unet好。当然,有时这种差异并不是很大,我们不能说它们在统计上是否完全不同 —— 我们需要在多个folds上训练,看看分数分布,单点不能证明任何事情。第二,resnest200e显示了最高的质量,同时仍然有合理的参数数量。有趣的是,如果我们看看https://paperswithcode.com/task/semantic-segmentation,我们会发现resnest200在一些基准测试中也是SOTA。

好的,但是让我们用Unet++和Unet使用resnest200e编码器来比较不同的预测。

597a5e7a-c3e2-11ec-bce3-dac502259ad0.png

Unet和Unet++使用resnest200e编码器的预测。左图显示了两种模型的预测差异

在某些个别情况下,Unet++实际上比Unet更糟糕。但总的来说似乎更好一些。

一般来说,对于分割网络来说,这个数据集看起来是一个容易的任务。让我们在一个更难的任务上测试Unet++。为此,我使用PanNuke数据集,这是一个带标注的组织学数据集(205,343个标记核,19种不同的组织类型,5个核类)。数据已经被分割成3个folds。

59e83314-c3e2-11ec-bce3-dac502259ad0.png

PanNuke样本的例子

我们可以使用类似的代码在这个数据集上训练Unet++模型,如下所示:

5a230200-c3e2-11ec-bce3-dac502259ad0.png

验证集上的Unet++得分

我们在这里看到了相同的模式 - resnest200e编码器似乎比其他的性能更好。我们可以用两个不同的模型(最好的是resnest200e编码器,最差的是regnety_002)来可视化一些例子。

5a37ee2c-c3e2-11ec-bce3-dac502259ad0.png

resnest200e和regnety_002的预测

我们可以肯定地说,这个数据集是一项更难的任务 —— 不仅mask不够精确,而且个别的核被分配到错误的类别。然而,使用resnest200e编码器的Unet++仍然表现很好。

总结

这不是一个全面语义分割的指导,这更多的是一个想法,使用什么来获得一个坚实的基线。有很多模型、FPN,DeepLabV3, Linknet与Unet有很大的不同,有许多Unet-like架构,例如,使用双编码器的Unet,MAnet,PraNet,U²-net — 有很多的型号供你选择,其中一些可能在你的任务上表现的比较好,但是,一个坚实的基线可以帮助你从正确的方向上开始。

审核编辑 :李倩
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编码器
    +关注

    关注

    45

    文章

    3640

    浏览量

    134451
  • 医学影像
    +关注

    关注

    1

    文章

    111

    浏览量

    17362

原文标题:UNet 和 UNet++:医学影像经典分割网络对比

文章出处:【微信号:CVSCHOOL,微信公众号:OpenCV学堂】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    东软发布新一代医学影像解决方案

    近日,东软全新发布新一代医学影像解决方案,以智能化为核心,以数据引擎为驱动,面向未来医学影像行业的发展需求,全新定义医学影像的产品价值,推动医学影像信息化的全面升级与一体化融合。这是东
    的头像 发表于 11-25 09:32 168次阅读

    Dell PowerScale数据湖助力医研一体化建设

    近年来,医疗影像设备不断向更高水平和精密化发展,推动医疗服务向更高更快的品质发展。基于医学影像多学科会诊的协作、智能辅助诊断、智能质控、智能术前规划,将快速推进各项医学科研成果进行规范化的临床应用与转化。
    的头像 发表于 10-16 10:13 308次阅读

    UNet模型属于哪种神经网络

    U-Net模型属于卷积神经网络(Convolutional Neural Network, CNN)的一种特殊形式 。它最初由德国弗莱堡大学计算机科学系的研究人员在2015年提出,专为生物医学图像
    的头像 发表于 07-24 10:59 2476次阅读

    医学影像存储与传输系统源码,PACS系统源码

     医学影像存储与传输系统中,PACS部分主要提供医学影像获取、影像信息网络传递、大容量数据存储、影像显示和处理、
    的头像 发表于 07-18 16:31 361次阅读
    <b class='flag-5'>医学影像</b>存储与传输系统源码,PACS系统源码

    图像语义分割的实用性是什么

    图像语义分割是一种重要的计算机视觉任务,它旨在将图像中的每个像素分配到相应的语义类别中。这项技术在许多领域都有广泛的应用,如自动驾驶、医学图像分析、机器人导航等。 一、图像语义分割的基本原理 1.1
    的头像 发表于 07-17 09:56 418次阅读

    图像分割和语义分割的区别与联系

    图像分割和语义分割是计算机视觉领域中两个重要的概念,它们在图像处理和分析中发挥着关键作用。 1. 图像分割简介 图像分割是将图像划分为多个区域或对象的过程。这些区域或对象具有相似的属性
    的头像 发表于 07-17 09:55 918次阅读

    图像识别技术在医疗领域的应用

    的应用已经成为推动医疗技术发展的重要力量。 二、医学影像诊断 医学影像诊断是图像识别技术在医疗领域应用最为广泛和成熟的领域之一。医学影像诊断主要包括X射线、CT、MRI、超声等影像技术
    的头像 发表于 07-16 10:48 864次阅读

    经典卷积网络模型介绍

    经典卷积网络模型在深度学习领域,尤其是在计算机视觉任务中,扮演着举足轻重的角色。这些模型通过不断演进和创新,推动了图像处理、目标检测、图像生成、语义分割等多个领域的发展。以下将详细探讨几个经典
    的头像 发表于 07-11 11:45 512次阅读

    图像分割与语义分割中的CNN模型综述

    图像分割与语义分割是计算机视觉领域的重要任务,旨在将图像划分为多个具有特定语义含义的区域或对象。卷积神经网络(CNN)作为深度学习的一种核心模型,在图像分割与语义
    的头像 发表于 07-09 11:51 856次阅读

    卷积神经网络在图像和医学诊断中的优势

    随着人工智能技术的迅猛发展,卷积神经网络(Convolutional Neural Network,简称CNN)作为一种深度学习的代表算法,在图像处理和医学诊断领域展现出了巨大的潜力和优势。CNN
    的头像 发表于 07-01 15:59 1064次阅读

    听医信人说 | 为什么医院建网选择极简以太彩光网络

    效率、改善患者的就医体验,网络部署需要更加灵活、高效。传统的频繁打孔和布线方式不仅影响医疗业务的正常进行,而且使用Hub和简易交换机可能会给网络稳定性和运维管理带来额外的挑战。 医学影像的即时读取 :高清
    的头像 发表于 06-20 14:56 306次阅读

    利用NVIDIA的nvJPEG2000库分析DICOM医学影像的解码功能

    本文将深入分析 DICOM 医学影像的解码功能。AWS HealthImaging 利用 NVIDIA 的 nvJPEG2000 库来实现此功能。
    的头像 发表于 05-28 14:27 791次阅读
    利用NVIDIA的nvJPEG2000库分析DICOM<b class='flag-5'>医学影像</b>的解码功能

    AI医学影像企业深智透医完成B+轮近千万美元融资

    AI医学影像领域的领军企业深智透医(Subtle Medical Inc.)近日成功完成了B+轮近千万美元的融资,使其累计融资额超过五千万美元。此次融资的注入,将为公司全球商业拓展和产品研发创新提供强大的资金支持。
    的头像 发表于 05-14 10:08 486次阅读

    西门子医疗与山东第一医科大学放射学院达成战略合作

    校企携手培育医学影像高端人才,虚实融生引领教育培训崭新模式 共建全国首个"医学影像元宇宙沉浸式教研示范学院" 探索实施"产学研用"四位一体的校企联合定向培养计划 促进各层级医研产学人才交叉培养与有机
    的头像 发表于 01-30 14:33 922次阅读
    西门子医疗与山东第一医科大学放射学院达成战略合作

    Harvard FairSeg:第一个用于医学分割的公平性数据集

    为了解决这些挑战,我们提出了第一个大规模医学分割领域的公平性数据集, Harvard-FairSeg。该数据集旨在用于研究公平性的cup-disc segmentation,从SLO眼底图像中诊断青光眼,如图1所示。
    的头像 发表于 01-25 16:52 547次阅读
    Harvard FairSeg:第一个用于<b class='flag-5'>医学分割</b>的公平性数据集