实验四 基于nnU-Net模型的3D医学图像分割实验
一、 实验介绍
腹部多器官分割一直是医学图像分析领域最活跃的研究领域之一,其作为一项基础技术,在支持疾病诊断,治疗规划等计算机辅助技术发挥着重要作用。近年来,基于深度学习的方法在该领域中获得了巨大成功。本实验数据集为多模态腹部分割数据集(AMOS),一个大规模,多样性的,收集自真实临床场景下的腹部多器官分割基准数据。本实验在百度飞桨平台上采用nnU-Net模型与V-Net模型对给定数据集进行3D医学图像分割。
利用提供的AMOS2022的训练数据,实现对腹部多器官图像的器官分割。在百度飞桨平台上采用nnU-Net[1]模型和V-Net[5]模型对数据进行预处理,在训练集上训练出模型后,再使用训练好的模型对测试集进行推理,最终得到分割结果。采用dice系数作为评价指标,最终得出各个不同部位前景类别的dice系数,同时采用15个前景类别的平均dice系数作为对比指标。
本次实验目的是将医学图像中的不同器官或组织结构进行准确的区分和分割。通过对医学图像进行分割,可以获得每个器官或结构的准确轮廓和位置信息,为医生提供更全面、深入的图像分析和诊断依据。对3D医学图像进行图像分割,旨在评估各种算法在复杂场景下的性能和效果。利用该数据集进行实验和算法开发,并基于准确性、鲁棒性、泛化能力等指标进行评估,以提升医学图像分割算法的准确性和可靠性。
V-net是一种基于全卷积神经网络的三维图像分割方法,采用编码器-解码器结构,类似于U-Net,但使用了3D卷积操作来处理体积医学图像。它能够从多个尺度上捕获特征,并通过学习全局上下文信息来准确地分割医学图像。而nnU-Net[2][3]是一种用于医学图像分割的神经网络架构,基于U-Net架构,并通过一系列tricks来适应医学图像分割的挑战,是一个自动适应任意给定新数据集的框架,论文中首次尝试根据给定数据集的属性自动执行必要的调整,如预处理、精确的补丁大小、批大小和推理设置。
nnU-Net[2][3]是一种用于医学图像分割的神经网络架构,基于U-Net架构,并通过一系列tricks来适应医学图像分割的挑战,是一个自动适应任意给定新数据集的框架,论文中首次尝试根据给定数据集的属性自动执行必要的调整,如预处理、精确的补丁大小、批大小和推理设置。
nnU-Net定义了dataset fingerprint和pipeline fingerprint。Dataset fingerprint是数据集的关键表征,比如图像大小、体素空间信息和类别比例;Pipeline fingerprint被分为三组:blueprint、inferred和empirical参数。Blueprint代表基本的架构设计,比如U-Net类的模板、损失函数、训练策略和数据增强;Inferd代表对新数据集的必要适应进行编码,并包括对确切的网络拓扑、补丁大小、批次大小和图像预处理的修改。数据指纹和inferd之间的关系是通过执行一组启发式规则建立的,当应用于看不见的数据集时,无需进行昂贵的重新优化。通过对训练案例进行交叉验证,可以自动确定empirical参数。默认情况下,nnU-Net会生成三种不同的U-Net配置:一个2D U-Net、一个以全图像分辨率运行的3D U-Net和一个3D U-Net级联。交叉验证后,nnU-Net会根据经验选择性能最佳的配置或整体。
1.1 实验内容
利用提供的AMOS2022的训练数据,实现对腹部多器官图像的器官分割。在百度飞桨平台上采用nnU-Net[1]模型和V-Net[5]模型对数据进行预处理,在训练集上训练出模型后,再使用训练好的模型对测试集进行推理,最终得到分割结果。采用dice系数作为评价指标,最终得出各个不同部位前景类别的dice系数,同时采用15个前景类别的平均dice系数作为对比指标。
1.2 实验目的
将医学图像中的不同器官或组织结构进行准确的区分和分割。通过对医学图像进行分割,可以获得每个器官或结构的准确轮廓和位置信息,为医生提供更全面、深入的图像分析和诊断依据。对3D医学图像进行图像分割,旨在评估各种算法在复杂场景下的性能和效果。利用该数据集进行实验和算法开发,并基于准确性、鲁棒性、泛化能力等指标进行评估,以提升医学图像分割算法的准确性和可靠性。
1.3 实验原理
V-net
V-net[5]是一种基于全卷积神经网络的三维图像分割方法,采用编码器-解码器结构,类似于U-Net,但使用了3D卷积操作来处理体积医学图像。它能够从多个尺度上捕获特征,并通过学习全局上下文信息来准确地分割医学图像。
编码器:V-Net的编码器由多个编码器模块组成。每个编码器模块由连续的卷积层和池化层组成,用于提取图像特征并减少特征图的尺寸。每个编码器模块后面紧跟一个残差连接,将该模块的输入直接连接到输出,以保留低级的图像细节信息。
解码器:V-Net的解码器与编码器相似,由多个解码器模块组成。每个解码器模块包括上采样层和卷积层,用于将特征图的尺寸恢复到原始图像的尺寸并提取特征。类似于编码器,解码器模块也包括跳跃连接,将对应的编码器模块的特征与解码器模块的特征进行融合。
损失函数:V-Net使用交叉熵损失函数来度量预测分割结果与真实标签之间的差异。此外,为了提高分割结果的平滑性和连续性,还可以采用Dice损失函数或其他常用的分割损失函数。
训练过程:在训练V-Net模型时,使用标记好的体积医学图像作为输入,将网络的输出与真实的分割标签进行对比,并通过反向传播算法更新网络的权重。通常,使用随机梯度下降等优化算法来最小化损失函数,并在验证集上进行评估和调优。
nnU-Net:
nnU-Net[2][3]是一种用于医学图像分割的神经网络架构,基于U-Net[4]架构,并通过一系列tricks来适应医学图像分割的挑战,是一个自动适应任意给定新数据集的框架,论文中首次尝试根据给定数据集的属性自动执行必要的调整,如预处理、精确的补丁大小、批大小和推理设置。
nnU-Net定义了dataset fingerprint和pipeline fingerprint。Dataset fingerprint是数据集的关键表征,比如图像大小、体素空间信息和类别比例;Pipeline fingerprint被分为三组:blueprint、inferred和empirical参数。Blueprint代表基本的架构设计,比如U-Net类的模板、损失函数、训练策略和数据增强;Inferd代表对新数据集的必要适应进行编码,并包括对确切的网络拓扑、补丁大小、批次大小和图像预处理的修改。数据指纹和inferd之间的关系是通过执行一组启发式规则建立的,当应用于看不见的数据集时,无需进行昂贵的重新优化。通过对训练案例进行交叉验证,可以自动确定empirical参数。默认情况下,nnU-Net会生成三种不同的U-Net配置:一个2D U-Net、一个以全图像分辨率运行的3D U-Net和一个3D U-Net级联。交叉验证后,nnU-Net会根据经验选择性能最佳的配置或整体。
1.4 数据源简介
深圳市大数据研究院、香港中文大学(深圳)、香港大学、中山大学等机构联合深圳市龙岗区人民医院、深圳市龙岗中心医院提出了多模态腹部分割数据集(AMOS),一个大规模,多样性的,收集自真实临床场景下的腹部多器官分割基准数据。本实验随机选择AMOS2022数据集中的160个训练数据,40个测试数据(CT图像)作为训练和评测数据。
多模态腹部分割数据集(AMOS)共有15个器官的标注,包括脾脏、右肾、左肾、胆囊、食道、肝、胃、主动脉、下腔静脉、胰腺、右肾上腺、左肾上腺、十二指肠、膀胱、前列腺/子宫。
数据集格式如下:-imagesTr 训练集目录,160个训练数据 |-labelsTr 训练集标签 |-imagesTs 测试集目录,40个测试数据 |-dataset.json 数据集说明文件
数据集图像如下所示:
图1:腹部多器官数据集图
二、 运行环境
硬件环境:百度飞桨AI Studio; Tesla V100; CPU 4 Cores; Video Mem:32GB; RAM 32GB; 总硬盘:100 GB
软件环境:Python:3.7.4 框架版本:PaddlePaddle 2.4.0
三、 方案设计
图2 实验整体流程图
数据预处理:首先,医学图像数据需要进行预处理。这包括调整图像大小、裁剪感兴趣区域、进行强度标准化等步骤。预处理的目的是减少噪声、提高数据质量,并使其适应网络的输入要求。
数据增强:为了增加训练数据的多样性,nnU-Net使用了多种数据增强技术,例如旋转、翻转、缩放等。这有助于提高模型的泛化能力,并减少过拟合风险。
损失函数:nnU-Net使用了一种称为Soft Dice Loss的损失函数。Soft Dice Loss通过计算预测分割掩码和真实分割掩码之间的相似度来衡量预测的准确性。它惩罚了假阳性和假阴性的预测,并通过优化损失函数来提高结果的质量。
超参数设计:调整学习率,Batch Size,加入L1正则化和L2正则化参数,选择优化器等。
模型训练:nnU-Net通过反向传播算法和梯度下降优化算法进行训练。训练过程中,使用训练集上的图像和对应的真实分割掩码来不断更新网络的权重,使其逐渐学会准确地预测医学图像的分割结果。
推理与部署:使用训练好的网络权重进行推理。对于V-Net,由于医疗图像一般比较大,为了加快推理,将动态图模型转换成静态图推理加快推理速度,对于nnU-Net模型,在推理前首先对验证集进行推理,生成推理结果json文件,在模型推理结束后,使用json文件对测试集的推理结果进行后处理,提高结果精度。在部署层面,将模型转换成静态图,在飞桨平台上进行部署。
四、 实验过程与结果分析(实验各关键步骤代码及结果分析)
数据预处理:
首先,医学图像数据需要进行预处理。这包括调整图像大小、裁剪感兴趣区域、进行归一化等步骤。预处理的目的是减少噪声、提高数据质量,并使其适应网络的输入要求。
1、下载数据集:
- tasks = {1: {"competition_dataset.zip":
- "https://bj.bcebos.com/v1/ai-studio-online/689cd00318284a188fd86e4f6ba276475daf592415df420b992dded777c6e8ec?responseContentDisposition=attachment%3B%20filename%3Dbase_train.zip&authorization=bce-auth-v1%2F5cfe9a5e1454405eb2a975c43eace6ec%2F2022-11-25T11%3A32%3A05Z%2F-1%2F%2F1b3edeb46c33df422e317a50762b51ee4210643e70f8c639903dcc73a3d145aa"}, }
2、归一化:将CT HU单位转换为uint8值。首先通过预定义的min和max绑定HU值,然后进行归一化。
- defHUnorm(image, HU_min=-1200, HU_max=600, HU_nan=-2000, multiply_255=True):
- if not isinstance(image, np.ndarray):
- image = np.array(image)
- image = np.nan_to_num(image, copy=False, nan=HU_nan)
- #[0, 1]
- image = (image - HU_min) / (HU_max - HU_min)
- if multiply_255:
- image *= 255
- clip(image, 0, 255, out=image)
- returnimage
3、resize:数据的shape不一致,为了方便训练,将其resize到同一维度[128,128,128]
- defresize_segmentation(segmentation, new_shape, order=3):
- tpe = segmentation.dtype
- unique_labels = np.unique(segmentation)
- assert len(segmentation.shape) == len(
- new_shape), "new shape must have same dimensionality as segmentation"
- if order == 0:
- return resize(
- astype(float),
- new_shape,
- order,
- mode="edge",
- clip=True,
- anti_aliasing=False).astype(tpe)
- else:
- reshaped = np.zeros(new_shape, dtype=segmentation.dtype)
- fori, c in enumerate(unique_labels):
- mask = segmentation == c
- reshaped_multihot = resize(
- astype(float),
- new_shape,
- order,
- mode="edge",
- clip=True,
- anti_aliasing=False)
- reshaped[reshaped_multihot >= 0.5] = c
- returnreshaped
- defresize_image(image, new_shape, order=3, cval=0):
- kwargs = {'mode': 'edge', 'anti_aliasing': False}
- returnresize(image, new_shape, order, cval=cval, **kwargs)
4、图片保存为npy格式
5、将数据集划分为训练集和验证集,训练集占比0.75,验证集0.25
- defgenerate_txt(self, train_split=0.75):
- """generate the train_list.txt and val_list.txt"""
- txtname = [
- join(self.phase_path, 'train_list.txt'),
- join(self.phase_path, 'val_list.txt')
- ]
- image_files_npy = os.listdir(self.image_path)
- label_files_npy = os.listdir(self.label_path)
- split_files_txt(txtname[0], image_files_npy, label_files_npy,
- train_split)
- split_files_txt(txtname[1], image_files_npy, label_files_npy,
- train_split)
数据增强:
为了增加训练数据的多样性,使用旋转、翻转、缩放等。这有助于提高模型的泛化能力,并减少过拟合风险。
1、缩放:代码同上述resize_segmentation
2、翻转:
- defaugment_mirroring(sample_data, sample_seg=None, axes=(0, 1, 2)):
- if (len(sample_data.shape) != 3) and (len(sample_data.shape) != 4):
- raise Exception(
- "Invalid dimension for sample_data and sample_seg. sample_data and sample_seg should be either "
- "[channels, x, y] or [channels, x, y, z]")
- if 0 in axes andrandom.uniform() < 0.5:
- sample_data[:, :] = sample_data[:, ::-1]
- if sample_seg is not None:
- sample_seg[:, :] = sample_seg[:, ::-1]
- if1 in axes andrandom.uniform() < 0.5:
- sample_data[:, :, :] = sample_data[:, :, ::-1]
- ifsample_seg is not None:
- sample_seg[:, :, :] = sample_seg[:, :, ::-1]
- if2 in axes and len(sample_data.shape) == 4:
- ifrandom.uniform() < 0.5:
- sample_data[:, :, :, :] = sample_data[:, :, :, ::-1]
- ifsample_seg is not None:
- sample_seg[:, :, :, :] = sample_seg[:, :, :, ::-1]
- returnsample_data, sample_seg
3、旋转:由于是3d图像,需要对3个维度操作
- defrotate_coords_3d(coords, angle_x, angle_y, angle_z):
- rot_matrix = np.identity(len(coords))
- rot_matrix = create_matrix_rotation_x_3d(angle_x, rot_matrix)
- rot_matrix = create_matrix_rotation_y_3d(angle_y, rot_matrix)
- rot_matrix = create_matrix_rotation_z_3d(angle_z, rot_matrix)
- coords = np.dot(coords.reshape(len(coords), -1).transpose(),
- rot_matrix).transpose().reshape(coords.shape)
- return coords
网络设计代码:
损失函数:DC_and_CE_loss,nnU-Net使用了一种称为Soft Dice Loss的损失函数。Soft Dice Loss通过计算预测分割掩码和真实分割掩码之间的相似度来衡量预测的准确性。它惩罚了假阳性和假阴性的预测,并通过优化损失函数来提高结果的质量。
超参数设计:调整学习率,Batch Size,加入L1正则化和L2正则化参数
选择优化器:使用SGD,adam和adamw三种优化器分别进行训练,进行比较。
V-Net网络:
图3 v-net结构图
- batch_size: 6
- iters: 30000
- train_dataset:
- type: MSDDataset
- dataset_root: competition_phase0
- result_dir: data/competition/competition_phase1
- num_classes: 16
- transforms:
- - type: RandomResizedCrop3D size: 128 scale: [0.8, 1.2]
- - type: RandomRotation3D degrees: 90
- - type: RandomFlip3D
- mode: train
- val_dataset:
- type: LungCoronavirus
- dataset_root: competition_phase0
- result_dir: data/competition/competition_phase1
- num_classes: 16
- transforms: []
- mode: val
- dataset_json_path: "data/competition_raw/dataset.json"
- test_dataset:
- type: LungCoronavirus
- dataset_root: competition_phase0
- result_dir: data/competition/competition_phase1
- num_classes: 16
- transforms: []
- mode: test
- dataset_json_path: "data/competition_raw/dataset.json"
- model:
- type: VNet
- elu: False
- in_channels: 1
- num_classes: 16
- optimizer:
- type: sgd/adam/adamw #这里优化器选择一个即可,其他参数可以对应修改使用哪个就用哪个
- momentum: 0.9
- weight_decay: 1.0e-4
- lr_scheduler:
- type: PolynomialDecay
- decay_steps: 15000
- learning_rate: 0.001
- end_lr: 0
- power: 0.9
- loss:
- types:
- - type: MixedLoss
- losses:
- - type: CrossEntropyLoss
- weight: Null
- - type: DiceLoss
- coef: [1, 1]
- coef: [1]
nnU-Net网络:
网络模型结构:
图4 nnU-Net网络结构图
- batch_size: 1
- iters: 50000
- model:
- type: NNUNet
- plan_path: data/preprocessed/nnUNetPlansv2.1_plans_3D.pkl
- stage: 0
- cascade: True
- train_dataset:
- type: MSDDataset
- plans_name: nnUNetPlansv2.1_plans_3D.pkl
- dataset_root: /
- result_dir: /
- raw_data_dir: data/raw_data
- decathlon_dir: data/decathlon
- cropped_data_dir: data/cropped
- preprocessed_dir: data/preprocessed
- plan2d: False
- plan3d: True
- num_batches_per_epoch: 250
- fold: 4
- stage: 0
- unpack_data: True
- cascade: True
- mode: train
- val_dataset:
- type: MSDDataset
- plans_name: nnUNetPlansv2.1_plans_3D.pkl
- dataset_root: /
- result_dir: /
- raw_data_dir: data/raw_data
- decathlon_dir: data/decathlon
- cropped_data_dir: data/cropped
- preprocessed_dir: data/preprocessed
- num_batches_per_epoch: 50
- fold: 4
- stage: 0
- unpack_data: True
- cascade: True
- mode: val
- optimizer:
- type:AdamDecay
- beta1:0.9
- beta2:0.999
- lr_scheduler:
- type: PolynomialDecay
- learning_rate: 0.01
- end_lr: 0
- power: 0.9
- loss:
- types:
- - type: MultipleLoss
- plan_path: data/preprocessed/nnUNetPlansv2.1_plans_3D.pkl
- stage: 0
- losses:
- - type: DC_and_CE_loss
- do_bg: False
- batch_dice: False
- coef: [1.0]
- coef: [1]
模型训练:
通过反向传播算法和梯度下降优化算法进行训练。训练过程中,使用训练集上的图像和对应的真实分割掩码来不断更新网络的权重,使其逐渐学会准确地预测医学图像的分割结果。
- #train.py文件
- defparse_args():
- parser = argparse.ArgumentParser(description='Model training')
- # params of training
- add_argument(
- "--config", dest="cfg", help="The config file.", default=None, type=str)
- add_argument(
- '--iters',
- dest='iters',
- help='iters for training',
- type=int,
- default=None)
- add_argument(
- '--batch_size',
- dest='batch_size',
- help='Mini batch size of one gpu or cpu',
- type=int,
- default=None)
- add_argument(
- '--learning_rate',
- dest='learning_rate',
- help='Learning rate',
- type=float,
- default=None)
- add_argument(
- '--save_interval',
- dest='save_interval',
- help='How many iters to save a model snapshot once during training.',
- type=int,
- default=1000)
- add_argument(
- '--resume_model',
- dest='resume_model',
- help='The path of resume model',
- type=str,
- default=None)
- add_argument(
- '--save_dir',
- dest='save_dir',
- help='The directory for saving the model snapshot',
- type=str,
- default='./output')
- add_argument(
- '--keep_checkpoint_max',
- dest='keep_checkpoint_max',
- help='Maximum number of checkpoints to save',
- type=int,
- default=5)
- add_argument(
- '--num_workers',
- dest='num_workers',
- help='Num workers for data loader',
- type=int,
- default=0)
- add_argument(
- '--do_eval',
- dest='do_eval',
- help='Eval while training',
- action='store_true')
- add_argument(
- '--log_iters',
- dest='log_iters',
- help='Display logging information at every log_iters',
- default=100,
- type=int)
- add_argument(
- '--use_vdl',
- dest='use_vdl',
- help='Whether to record the data to VisualDL during training',
- action='store_true')
- add_argument(
- '--seed',
- dest='seed',
- help='Set the random seed during training.',
- default=None,
- type=int)
- add_argument(
- '--data_format',
- dest='data_format',
- help='Data format that specifies the layout of input. It can be "NCHW" or "NHWC". Default: "NCHW".',
- type=str,
- default='NCHW')
- add_argument(
- '--profiler_options',
- type=str,
- default=None,
- help='The option of train profiler. If profiler_options is not None, the train '\
- 'profiler is enabled. Refer to the medseg/utils/train_profiler.py for details.'
- )
- add_argument(
- '--nnunet', dest='nnunet', help='nnunet training', action='store_true')
- add_argument(
- "--precision",
- default="fp32",
- type=str,
- choices=["fp32", "fp16"],
- help="Use AMP (Auto mixed precision) if precision='fp16'. If precision='fp32', the training is normal."
- )
- add_argument('--sw_num', default=None, type=int, help='sw_num')
- add_argument(
- '--is_save_data', default=True, type=eval, help='warmup')
- add_argument(
- '--has_dataset_json', default=True, type=eval, help='has_dataset_json')
- returnparse_args()
- defmain(args):
- ifseed is not None:
- seed(args.seed)
- random.seed(args.seed)
- seed(args.seed)
- env_info = get_sys_env()
- info = ['{}: {}'.format(k, v) for k, v initems()]
- info = '\n'.join(['', format('Environment Information', '-^48s')] + info +
- ['-' * 48])
- info(info)
- place = 'gpu' if env_info['Paddle compiled with cuda'] and env_info[
- 'GPUs used'] else 'cpu'
- set_device(place)
- if notcfg:
- raise RuntimeError('No configuration file specified.')
- cfg = Config(
- cfg,
- learning_rate=args.learning_rate,
- iters=args.iters,
- batch_size=args.batch_size)
- ifnnunet:
- core.train(
- model,
- train_dataset,
- val_dataset=val_dataset,
- optimizer=cfg.optimizer,
- save_dir=args.save_dir,
- iters=cfg.iters,
- batch_size=cfg.batch_size,
- resume_model=args.resume_model,
- save_interval=args.save_interval,
- log_iters=args.log_iters,
- num_workers=args.num_workers,
- use_vdl=args.use_vdl,
- losses=losses,
- keep_checkpoint_max=args.keep_checkpoint_max,
- precision=args.precision,
- profiler_options=args.profiler_options,
- to_static_training=cfg.to_static_training)
- if__name__ == '__main__':
- args = parse_args()
- main(args)
训练代码:20个iters输出一次结果,精度为fp16,1000个iters保存一次模型,可视化模型
- !python train.py
- --config ~/nnunet.yml
- --log_iters 20 #20个iters输出一次结果
- --precision fp16 #精度为fp16
- --nnunet
- --save_dir output/cascade_lowres/fold0
- --save_interval 1000 #1000个iters保存一次模型
- --use_vdl #可视化模型
nnU-Net网络训练曲线结果图
iters=30000,batchsize选为1,优化器为adamw,权重衰减0.0002,PolynomialDecay,learning_rate= 0.01,loss选择DC_and_CE_loss:
图5 nnunet训练的loss曲线图
图6 nnunet训练的batch_cost曲线图
图7 nnunet训练的reader_cost曲线图
图8 nnunet训练的mdice曲线图
训练结果分析:
可以看到采用adamw优化器后,模型的收敛速度变快很多,同时随着训练迭代次数的增加,模型的loss逐渐下降,准确率逐渐提高。与使用sgd模型需要到2w轮才逐渐收敛和adam虽然5000轮收敛,但loss值会比较低,比较而言,发现adamw优化器的效果确实是最好的,收敛速度快,且loss降的快的同时还能保证很低。
模型推理:
使用训练好的网络权重进行推理。对于V-Net,由于医疗图像一般比较大,为了加快推理,将动态图模型转换成静态图推理加快推理速度,对于nnU-Net模型,在推理前首先对验证集进行推理,生成推理结果json文件,在模型推理结束后,使用json文件对测试集的推理结果进行后处理,提高结果精度。在部署层面,将模型转换成静态图,在飞桨平台上进行部署。
推理部分代码:
V-Net模型:
1、将动态图模型转换成静态图推理加快推理速度
- %cd ~/PaddleSeg/contrib/MedicalSeg
- !python export.py --config /home/aistudio/test_configs/vnet.yml \
- --model_path output_vnet/best_model/model.pdparams \
- --save_dir output_vnet/export_model
2、转化为静态图后使用Paddle Inference 进行推理
- %cd ~/PaddleSeg/contrib/MedicalSeg
- !python deploy/python/competition_infer.py \
- --config ~/baseline_model/vnet/export_model/deploy.yaml \
- --image_path data/competition_raw/competition_dataset/imagesTs \
- --save_dir ~/submit \
- --benchmark False
nnU-Net模型:
1、先用验证集验证出json文件
- !python nnunet/single_fold_eval.py --config ~/configs/nnunet_fold2.yml \
- --model_path output/cascade_lowres/fold2/iter_2000/model.pdparams --val_save_folder output/cascade_lowres_val \
- --precision fp16 --predict_next_stage
2、模型推理+后处理
- %cd ~/PaddleSeg/contrib/MedicalSeg/
- !python nnunet/predict.py --image_folder data/decathlon/imagesTs \
- --output_folder ~/submit \
- --plan_path data/preprocessed/nnUNetPlansv2.1_plans_3D.pkl \
- --model_paths output/cascade_lowres/fold2/iter_30000/model.pdparams \
- --postprocessing_json_path output/cascade_lowres_val/postprocessing.json --model_type cascade_lowres \
- --num_threads_preprocessing 1 --num_threads_nifti_save 1
最终结果对比:评价指标为dice系数,一共有15个器官,为分割后的每个器官值,mean dice为15个dice值的均值。
表1 不同模型与优化器组合的结果对比图
模型(50000iters) | nnunet+adamw(有后处理) | nnunet+adamw(无后处理) | nnunet+adam(有后处理) | nnunet+adam(无后处理) | nnunet+sgd | vnet+sgd | |
left kidney | 0.96202 | 0.96245 | 0.96573 | 0.96074 | 0.96095 | 0.9219 | |
spleen | 0.97287 | 0.97303 | 0.96458 | 0.96877 | 0.96344 | 0.93916 | |
liver | 0.97479 | 0.97337 | 0.9705 | 0.97091 | 0.96458 | 0.94911 | |
arota | 0.95499 | 0.95535 | 0.95252 | 0.94949 | 0.94392 | 0.86334 | |
stomach | 0.93958 | 0.9367 | 0.91724 | 0.92227 | 0.89393 | 0.78717 | |
gall bladder | 0.87217 | 0.85408 | 0.82365 | 0.82721 | 0.78918 | 0.64069 | |
postcava | 0.92659 | 0.92678 | 0.91991 | 0.91591 | 0.90218 | 0.82374 | |
duodenum | 0.85216 | 0.84818 | 0.82781 | 0.832 | 0.78313 | 0.57309 | |
right adrenal gland | 0.80316 | 0.80315 | 0.79153 | 0.78097 | 0.75152 | 0.55784 | |
pancreas | 0.88005 | 0.87494 | 0.86401 | 0.8614 | 0.83619 | 0.7079 | |
bladder | 0.8992 | 0.88833 | 0.88549 | 0.88652 | 0.83983 | 0.68947 | |
esophagus | 0.86066 | 0.85527 | 0.83792 | 0.83298 | 0.81346 | 0.69781 | |
left adrenal gland | 0.80352 | 0.80543 | 0.8 | 0.80007 | 0.76002 | 0.62083 | |
prostate/uterus | 0.88635 | 0.86318 | 0.85096 | 0.85533 | 0.80733 | 0.71024 | |
right kidney | 0.96132 | 0.95889 | 0.9608 | 0.95604 | 0.9546 | 0.91769 | |
mean dice | 0.90329 | 0.89861 | 0.88884 | 0.88804 | 0.86428 | 0.76 |
|
五、 实验总结及创新点介绍
5.1 实验总结
本实验使用了多模态腹部分割数据集(AMOS)对腹部多器官图像进行器官分割,采用了nnU-Net和V-Net模型进行预处理和训练。最终通过对测试集进行推理得到了分割结果,并使用dice系数作为评价指标对两个模型进行了性能评估,最终得到了结论,nnU-Net模型的分割效果普遍优于v-net模型。分析原因推测,由于本次使用的数据集包含多个部位器官,如果采用全卷积神经网络(V-Net),对于特定部位的器官分割的准确率会比nnU-Net网络高,但是从整体平均dice出发来看的话是比不过nnU-Net的。
同时从网络设计的效率来看,nnU-Net比V-Net模型一个比较大的优点在于可以网络根据任务自动设计部分超参数,与V-Net模型需要对不同部位分割任务自己设计不同的超参数值相比,任务量减少了不少,同时模型的泛化能力也有了很大提升,在AMOS这个大规模数据集上得到了验证。
但是,值得注意的是,在模型大小与推理速度上,V-Net比nnU-Net不仅参数量小了一半多,同时在推理时间上也是nnU-Net四分之一(推理测试集,V-Net每张图片约2分钟,nnU-Net约9.5分钟)。可以看到nnU-Net牺牲了时间和参数量大小,同时对设备要求也高,换来了更好的泛化性能,更好的准确率,与更高的网络设计效率。V-Net如果针对特定任务进行精调,足够耐心的调参,其实也是能够达到不弱于nnU-Net的效果的。
同时,完整版的nnU-Net采用五折交叉验证与多模型集成策略进行后处理,在五折交叉验证过程中产生的npy文件非常大,同时多模型集成策略中所要用到的cascade级联策略,所需要保存的文件非常大,由于服务器硬盘大小限制,就只跑了一折中的3d-unet模型。
随着实践的深入,我也慢慢明白了大一时计算机科学导论老师说的那句“程序员其实做的更多是中庸的程序”,现在也慢慢体会到了,实际应用的时候,是选择便宜但是性能稍微弱一点,准确率可以用时间堆上去的模型,还是选择准确率高,设计成本低,但是使用推理成本高的网络,这些都是我们在真正做应用的时候要权衡利弊的。
5.2 创新点
1、自动化训练流程:nnU-Net提供了一个自动化的训练流程,可以从原始数据中生成所需的输入、标签和预处理步骤。在网络训练中通过最优化dice系数这样可以减少手动操作的工作量,并降低训练过程中的错误。
2、在训练前采用了数据增强:通过对数据进行旋转、缩放、镜像等增强操作,以加强模型的泛化能力。
3、采用了adamw,adam,sgd 三种优化器进行对比训练,最后进行比较发现,adamw优化器训练效果最好。
4、对分割结果进行了是否进行后处理的实验对比,最后得出结论,在这个实验中,后处理能够提升一点点模型分割的精度,对模型精度提升有帮助。
参考文献
[1] F. Isensee, P. F. Jäger, S. A. A. Kohl, J. Petersen, and K. H. Maier-Hein, “Automated Design of Deep Learning Methods for Biomedical Image Segmentation,” Nat Methods, vol. 18, no. 2, pp. 203–211, Feb. 2021, doi: 10.1038/s41592-020-01008-z.
[2] F. Isensee, C. Ulrich, T. Wald, and K. H. Maier-Hein, “Extending nnU-Net is all you need.” arXiv, Aug. 23, 2022. Available: http://arxiv.org/abs/2208.10791
[3] F. Isensee et al., “nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation.” arXiv, Sep. 27, 2018. Available: http://arxiv.org/abs/1809.10486
[4] O. Ronneberger, P. Fischer, and T. Brox, “U-Net: Convolutional Networks for Biomedical Image Segmentation.” arXiv, May 18, 2015. doi: 10.48550/arXiv.1505.04597.
[5] F. Milletari, N. Navab, and S.-A. Ahmadi, “V-Net: Fully Convolutional Neural Networks for Volumetric Medical Image Segmentation.” arXiv, Jun. 15, 2016. doi: 10.48550/arXiv.1606.04797.