赞
踩
由于本人的笔记本计算资源有限,实验室的服务器资源师兄师姐经常使用,因此这里选择云服务器进行学习尝试。
近年来的云服务器资源比较丰富,阿里、华为等大厂甚至是移动都有相应的服务器资源。我用过阿里云、华为云、AutoDL这三种云服务器。按照我的使用感受,华为云由于学校赠送代金券,而且镜像方面比较全面,数据存储服务等都是上乘,使用的比较舒服,但个人使用的话GPU价格还是有点小高。阿里云用的时间比较久远,当时好像有图形化界面,对于新手比较友好。AutoDL是我最近在用的云服务器,其中的环境都比较高,python3.8为主,不过好处是可以无卡开机,并且网盘上传。这里就以AutoDL为主。
打开AutoDL官网
https://www.autodl.com/
点击右上角的控制台
点击左上角的我的实例,进行服务器租赁。
之后进行相应的环境选择
创建完成后可以先关机,之后用无卡模式启动,比较我们后面还要安装一些外围环境并准备数据。
nnUNet官网地址:
https://github.com/MIC-DKFZ/nnUNet
点击更多,选择无卡模式开机。
点击jupyterLab进入控制页面,选择终端进行nnUNet环境的安装。
由于AutoDL中,存储空间分为数据盘和系统盘,如果将所有的数据都放在默认的系统盘的话,之后会出现系统盘数据溢出,不能关机的情况,因此我们先跳转到数据盘autodl-tmp,并创建一个文件夹nnUNetFrame,专门存放nnUNet数据。之后跳转至相应的文件夹中
cd autodl-tmp/nnUNetFrame
之后按照git中的教程进行安装
查看pytorch版本:
python -c 'import torch;print(torch.backends.cudnn.version())'
python -c 'import torch;print(torch.__version__)'
根据使用案例安装 nnU-Net:
用作标准化基线、开箱即用的分割算法,或用于使用预训练模型运行推理:
pip install nnunet
用作集成框架(这将在计算机上创建 nnU-Net 代码的副本,以便您可以根据需要对其进行修改):
git clone https://github.com/MIC-DKFZ/nnUNet.git
cd nnUNet
pip install -e .
这里使用第二种方法
有时候会出现
failed: The TLS connection was non-properly terminated.
关机重启,多试几次就可以了
(可选)安装隐藏层。hiddenlayer使nnU-net能够生成它生成的网络拓扑的图(参见模型训练)。要安装隐藏层,请运行以下命令:
pip install --upgrade git+https://github.com/FabianIsensee/hiddenlayer.git@more_plotted_details#egg=hiddenlayer
此外,还需要安装一些额外库
conda install h5py
在已有的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"
永久改变可以参考这里链接
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"
修改后注意保存文件
nnUNetFrame文件夹中新建CREMI_nnUNet文件夹,存放CREMI原始数据
数据下载地址:https://cremi.org/
这里我们只使用非padding数据
点击AutoPanel使用网盘传输
选择相应的网盘,点击右侧下载按钮即可,文件会自动上传至/root/autodl-tmp中
这里只上传非padding部分,如图所示:
之后将文件移入相应的文件夹中,完成。
打开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"
然后进行保存。
之后打开命令行,输入指令运行程序,使得原始的hdf数据转换为nnUNet能读取的数据。
python autodl-tmp/nnUNetFrame/nnUNet/nnunet/dataset_conversion/Task061_CREMI.py
数据预处理使用如下命令
nnUNet_plan_and_preprocess -t 61
CREMI任务ID为61,所以参数t为61。这个过程会消耗很多的时间,速度慢的原因在于对要进行插值等各种操作。
开始训练
nnUNet_train 3d_fullres nnUNetTrainerV2 61 4
61代表任务ID,4代表五折交叉验证中的第4折(0代表分成五折后的第一折)。所有的任务都应当在“4”的情况下,也就是五折交叉验证中的第一折数据集下进行。
如果出现训练终端,你要继续训练的情况请在这行命令之后加上:
-c
可以看到已经进行训练。
官方的预训练文件地址:
https://zenodo.org/record/3734294#.XyYR5mMzY5n
在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
nnUNet_predict:执行预测的命令;
-i: 输入(待推理测试集);
-o: 输出(测试集的推理结果);
-t: 你的任务对应的数字ID;
-m: 对应的训练时使用的网络架构;
-f: 数字4代表使用五折交叉验证训练出的模型;
推理完全部需要消耗相当长的时间,建议先只用一个测试文件进行推理。
最终可能会出现警告
WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run consolidate_folds in the output folder of the model first!
这个问题的解决方案在原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
其中,要保证所有的多折交叉验证全部训练完毕
即运行
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
根据作者的描述,后处理部分是可选选项,在文件目录中我们也能看到推理文件已经生成
新建文件夹DataPrepare,并切换至该目录,下载相应的CREMI官方处理文件
cd autodl-tmp/DataPrepare
git clone https://github.com/cremi/cremi_python.git
下载完成后进入文件进行编程
新建文件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")
运行完该py文件
得到结果,完成。
可以看到相关的推理文件已经生成
在/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')
运行完毕后打开相应的文件夹,可以看到如下效果
本人入门期间一直使用pycharm作为开发软件,原因是上手快,debug友好,各种查看方面。但在使用pycharm进行远程开发的时候,它会先将工程文件上传至云服务器中,之后设置文件同步进行修改开发。在使用的过程中可能会出现文件不同步的问题,而且项目中的命令行仍然是本机的命令行,容易与服务器上的命令产生冲突。
这里推荐使用vscode进行远程连接开发。连接方式如下
https://www.autodl.com/docs/vscode/
后续会进行源码的阅读。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。