当前位置:   article > 正文

nnUNet实战(一):CREMI挑战赛简单实践_cremi数据集

cremi数据集

nnUNet实战


一、云服务器租赁

由于本人的笔记本计算资源有限,实验室的服务器资源师兄师姐经常使用,因此这里选择云服务器进行学习尝试。

近年来的云服务器资源比较丰富,阿里、华为等大厂甚至是移动都有相应的服务器资源。我用过阿里云、华为云、AutoDL这三种云服务器。按照我的使用感受,华为云由于学校赠送代金券,而且镜像方面比较全面,数据存储服务等都是上乘,使用的比较舒服,但个人使用的话GPU价格还是有点小高。阿里云用的时间比较久远,当时好像有图形化界面,对于新手比较友好。AutoDL是我最近在用的云服务器,其中的环境都比较高,python3.8为主,不过好处是可以无卡开机,并且网盘上传。这里就以AutoDL为主。
打开AutoDL官网
https://www.autodl.com/
在这里插入图片描述
点击右上角的控制台
在这里插入图片描述
点击左上角的我的实例,进行服务器租赁。
在这里插入图片描述
之后进行相应的环境选择
在这里插入图片描述
创建完成后可以先关机,之后用无卡模式启动,比较我们后面还要安装一些外围环境并准备数据。

二、nnUNet安装

nnUNet官网地址:
https://github.com/MIC-DKFZ/nnUNet

1.前期准备(文件目录、环境检查)

点击更多,选择无卡模式开机。
在这里插入图片描述
点击jupyterLab进入控制页面,选择终端进行nnUNet环境的安装。
由于AutoDL中,存储空间分为数据盘和系统盘,如果将所有的数据都放在默认的系统盘的话,之后会出现系统盘数据溢出,不能关机的情况,因此我们先跳转到数据盘autodl-tmp,并创建一个文件夹nnUNetFrame,专门存放nnUNet数据。之后跳转至相应的文件夹中

cd autodl-tmp/nnUNetFrame
  • 1

之后按照git中的教程进行安装
查看pytorch版本:

python -c 'import torch;print(torch.backends.cudnn.version())'
python -c 'import torch;print(torch.__version__)'   
  • 1
  • 2

![在这里插入图片描述](https://img-blog.csdnimg.cn/abc13f2ef1314a20bf253f0addcafbe5.png

2.安装nnUNet

根据使用案例安装 nnU-Net:
用作标准化基线、开箱即用的分割算法,或用于使用预训练模型运行推理:

pip install nnunet
  • 1

用作集成框架(这将在计算机上创建 nnU-Net 代码的副本,以便您可以根据需要对其进行修改):

git clone https://github.com/MIC-DKFZ/nnUNet.git
cd nnUNet
pip install -e .
  • 1
  • 2
  • 3

这里使用第二种方法
在这里插入图片描述
有时候会出现

failed: The TLS connection was non-properly terminated.
  • 1

关机重启,多试几次就可以了

在这里插入图片描述
(可选)安装隐藏层。hiddenlayer使nnU-net能够生成它生成的网络拓扑的图(参见模型训练)。要安装隐藏层,请运行以下命令:

pip install --upgrade git+https://github.com/FabianIsensee/hiddenlayer.git@more_plotted_details#egg=hiddenlayer
  • 1

在这里插入图片描述
此外,还需要安装一些额外库

conda install h5py
  • 1

在这里插入图片描述

3.数据整理

在已有的nnUNetFrame文件夹中新建DATASET文件夹

在这里插入图片描述
在DATASET文件夹中新建三个新的子文件夹
nnUNet_raw
nnUNet_preprocessed
nnUNet_trained_models
之后增加系统变量,临时增加系统变量可以使用如下命令:

export nnUNet_raw_data_base="/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw"
export nnUNet_preprocessed="/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_preprocessed"
export RESULTS_FOLDER="/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_trained_models"
  • 1
  • 2
  • 3

永久改变可以参考这里链接
https://github.com/MIC-DKFZ/nnUNet/blob/master/documentation/setting_up_paths.md

如果有些云服务器没有更改系统文件的权限,使用如下方法:
首先打开
autodl-tmp/nnUNetFrame/nnUNet/nnunet/paths.py
修改如下代码:

# base = os.environ['nnUNet_raw_data_base'] if "nnUNet_raw_data_base" in os.environ.keys() else None
# preprocessing_output_dir = os.environ['nnUNet_preprocessed'] if "nnUNet_preprocessed" in os.environ.keys() else None
# network_training_output_dir_base = os.path.join(os.environ['RESULTS_FOLDER']) if "RESULTS_FOLDER" in os.environ.keys() else None

base = os.environ['nnUNet_raw_data_base'] if "nnUNet_raw_data_base" in os.environ.keys() else "/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw"
preprocessing_output_dir = os.environ['nnUNet_preprocessed'] if "nnUNet_preprocessed" in os.environ.keys() else "/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_preprocessed"
network_training_output_dir_base = os.path.join(os.environ['RESULTS_FOLDER']) if "RESULTS_FOLDER" in os.environ.keys() else "/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_trained_models"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

修改后注意保存文件

nnUNetFrame文件夹中新建CREMI_nnUNet文件夹,存放CREMI原始数据
数据下载地址:https://cremi.org/
这里我们只使用非padding数据
点击AutoPanel使用网盘传输
在这里插入图片描述
选择相应的网盘,点击右侧下载按钮即可,文件会自动上传至/root/autodl-tmp中
在这里插入图片描述
这里只上传非padding部分,如图所示:
在这里插入图片描述
之后将文件移入相应的文件夹中,完成。

三、简单实践

1.训练

打开CREMI数据处理文件
autodl-tmp/nnUNetFrame/nnUNet/nnunet/dataset_conversion/Task061_CREMI.py
将其中main的base路径进行替换,我这里是90行

    # base = "/media/fabian/My Book/datasets/CREMI"
    base = "/root/autodl-tmp/nnUNetFrame/CREMI_nnUNet"
  • 1
  • 2

然后进行保存。
之后打开命令行,输入指令运行程序,使得原始的hdf数据转换为nnUNet能读取的数据。

python autodl-tmp/nnUNetFrame/nnUNet/nnunet/dataset_conversion/Task061_CREMI.py
  • 1

在这里插入图片描述
数据预处理使用如下命令

nnUNet_plan_and_preprocess -t 61
  • 1

CREMI任务ID为61,所以参数t为61。这个过程会消耗很多的时间,速度慢的原因在于对要进行插值等各种操作。
在这里插入图片描述
开始训练

nnUNet_train 3d_fullres nnUNetTrainerV2 61 4
  • 1

61代表任务ID,4代表五折交叉验证中的第4折(0代表分成五折后的第一折)。所有的任务都应当在“4”的情况下,也就是五折交叉验证中的第一折数据集下进行。
如果出现训练终端,你要继续训练的情况请在这行命令之后加上:
-c
在这里插入图片描述
可以看到已经进行训练。

官方的预训练文件地址:
https://zenodo.org/record/3734294#.XyYR5mMzY5n

2.推理

在autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI下创建inferTs文件夹,以存储测试集推理数据
这其中Ts代表测试集合,Ts代表训练集
在这里插入图片描述
这里看到测试集数据直接是nii.gz格式,因此不用转换。
在这里插入图片描述

nnUNet_predict -i autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI/imagesTs/ -o autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI/inferTs -t 61 -m 3d_fullres -f 4
  • 1
   nnUNet_predict:执行预测的命令;
   -i: 输入(待推理测试集);
   -o: 输出(测试集的推理结果);
   -t: 你的任务对应的数字ID;
   -m: 对应的训练时使用的网络架构;
   -f: 数字4代表使用五折交叉验证训练出的模型;
   推理完全部需要消耗相当长的时间,建议先只用一个测试文件进行推理。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述
在这里插入图片描述

最终可能会出现警告

WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run consolidate_folds in the output folder of the model first!
  • 1

这个问题的解决方案在原github中作者给出了解答
https://github.com/MIC-DKFZ/nnUNet/issues/410

You can run nnUNet_determine_postprocessing to let it figure out what postprocessing (connected component analysis) to use. This does not make a huge difference most of the time, so you can safely omit it.
Best,
Fabian

即运行

nnUNet_determine_postprocessing -t 61 -m 3d_fullres
  • 1

其中,要保证所有的多折交叉验证全部训练完毕

即运行

nnUNet_train 3d_fullres nnUNetTrainerV2 61 0 -c
nnUNet_train 3d_fullres nnUNetTrainerV2 61 1 -c
nnUNet_train 3d_fullres nnUNetTrainerV2 61 2 -c
nnUNet_train 3d_fullres nnUNetTrainerV2 61 3 -c
nnUNet_train 3d_fullres nnUNetTrainerV2 61 4 -c
  • 1
  • 2
  • 3
  • 4
  • 5

根据作者的描述,后处理部分是可选选项,在文件目录中我们也能看到推理文件已经生成

在这里插入图片描述
新建文件夹DataPrepare,并切换至该目录,下载相应的CREMI官方处理文件

cd autodl-tmp/DataPrepare
git clone https://github.com/cremi/cremi_python.git
  • 1
  • 2

下载完成后进入文件进行编程

新建文件mydata_prepare.py

打开autodl-tmp/nnUNetFrame/nnUNet/nnunet/dataset_conversion/Task061_CREMI.py,使用里面的函数进行nii.gz文件至hdf文件的转换。这里直接写入main函数即可

from collections import OrderedDict

from batchgenerators.utilities.file_and_folder_operations import *
import numpy as np
from nnunet.paths import nnUNet_raw_data, preprocessing_output_dir
import shutil
import SimpleITK as sitk

try:
    import h5py
except ImportError:
    h5py = None


def prepare_submission():
    from cremi.io import CremiFile
    from cremi.Volume import Volume

    # base = "/home/fabian/drives/datasets/results/nnUNet/test_sets/Task061_CREMI/"
    base = "/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI/inferTs/"
    # a+
    pred = sitk.GetArrayFromImage(sitk.ReadImage(join(base, "sample_a+.nii.gz"))).astype(np.uint64)
    pred[pred == 0] = 0xffffffffffffffff
    out_a = CremiFile(join(base, 'sample_A+_20160601.hdf'), 'w')
    clefts = Volume(pred, (40., 4., 4.))
    out_a.write_clefts(clefts)
    out_a.close()

    pred = sitk.GetArrayFromImage(sitk.ReadImage(join(base, "sample_b+.nii.gz"))).astype(np.uint64)
    pred[pred == 0] = 0xffffffffffffffff
    out_b = CremiFile(join(base, 'sample_B+_20160601.hdf'), 'w')
    clefts = Volume(pred, (40., 4., 4.))
    out_b.write_clefts(clefts)
    out_b.close()

    pred = sitk.GetArrayFromImage(sitk.ReadImage(join(base, "sample_c+.nii.gz"))).astype(np.uint64)
    pred[pred == 0] = 0xffffffffffffffff
    out_c = CremiFile(join(base, 'sample_C+_20160601.hdf'), 'w')
    clefts = Volume(pred, (40., 4., 4.))
    out_c.write_clefts(clefts)
    out_c.close()

if __name__ == "__main__":
    prepare_submission()
    print("prepare_submission OK")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

运行完该py文件
在这里插入图片描述
得到结果,完成。
在这里插入图片描述
可以看到相关的推理文件已经生成
在这里插入图片描述

3.推理结果可视化展示

在/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI路径下新建displayTs文件夹,存放推理结果可视化,新建py文件代码如下:

import h5py
import matplotlib.pyplot as plt
import numpy as np
import cv2
import os
import SimpleITK as sitk


if __name__ =="__main__":

    display_path = "/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI/displayTs"
    initial_label_path = "/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI/inferTs"
    initial_raw_path = "/root/autodl-tmp/nnUNetFrame/DATASET/nnUNet_raw/nnUNet_raw_data/Task061_CREMI/imagesTs"
    # 读取hdf文件
    # h5pyname = 'sample_A+_20160601'
    # h5pyname = 'sample_B+_20160601'
    h5pyname = 'sample_C+_20160601'
    if h5pyname[7] == 'A':
        raw_name = 'sample_a+_0000.nii.gz'
    elif h5pyname[7] == 'B':
        raw_name = 'sample_b+_0000.nii.gz'
    elif h5pyname[7] == 'C':
        raw_name = 'sample_c+_0000.nii.gz'
    else:
        raise ValueError

    f_label = h5py.File(os.path.join(initial_label_path, h5pyname + '.hdf'), 'r')
    f_raw = sitk.GetArrayFromImage(sitk.ReadImage(os.path.join(initial_raw_path, raw_name)))

    labels_path = os.path.join(os.path.join(display_path, h5pyname), 'labels')
    raws_path = os.path.join(os.path.join(display_path, h5pyname), 'raws')

    if not os.path.exists(labels_path):
        # 检查该路径是否存在
        os.makedirs(labels_path, exist_ok=True)
        # 不存在则递归创建该路径,注意exist_ok需要为True
        print(labels_path, 'created')

    if not os.path.exists(raws_path):
        # 检查该路径是否存在
        os.makedirs(raws_path, exist_ok=True)
        # 不存在则递归创建该路径,注意exist_ok需要为True
        print(raws_path, 'created')


    # read synapse labels in hdf files
    labels_data = f_label['volumes/labels/clefts']
    labels_data_array = labels_data[:]

    labels_data_array[labels_data_array == 0xffffffffffffffff] = 0
    labels_data_array[labels_data_array != 0] = 255
    labels_data_array = labels_data_array.astype(np.uint8)
    # save labels of testset
    for label_index in range(labels_data_array.shape[0]):
        cv2.imwrite(os.path.join(labels_path, r"%05d.png"%label_index), labels_data_array[label_index, :, :], [cv2.IMWRITE_PNG_COMPRESSION, 0])
        print("label " + os.path.join(labels_path, r"%05d.png"%label_index) + ' ok')

    # save raw data with labels of testset
    assert labels_data_array.shape == f_raw.shape
    for raw_index in range(f_raw.shape[0]):
        # convert gray to BGR
        save_img = np.stack([f_raw[raw_index], f_raw[raw_index], f_raw[raw_index]],axis=2)
        # add label in Red channal
        save_img[:, :, 0][labels_data_array[raw_index] == 255] = 0
        save_img[:, :, 1][labels_data_array[raw_index] == 255] = 0
        cv2.imwrite(os.path.join(raws_path, r"%05d.png"%raw_index), save_img, [cv2.IMWRITE_PNG_COMPRESSION, 0])
        print("raw " + os.path.join(raws_path, r"%05d.png"%raw_index) + ' ok')

    print('ok')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

运行完毕后打开相应的文件夹,可以看到如下效果
在这里插入图片描述

四、编程

本人入门期间一直使用pycharm作为开发软件,原因是上手快,debug友好,各种查看方面。但在使用pycharm进行远程开发的时候,它会先将工程文件上传至云服务器中,之后设置文件同步进行修改开发。在使用的过程中可能会出现文件不同步的问题,而且项目中的命令行仍然是本机的命令行,容易与服务器上的命令产生冲突。

这里推荐使用vscode进行远程连接开发。连接方式如下

https://www.autodl.com/docs/vscode/

后续会进行源码的阅读。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/290810
推荐阅读
相关标签
  

闽ICP备14008679号