nnUnet使用2d數據訓練方法-DKFZ官方版

2021-02-21 Python編程和深度學習

nnUnet使用2d數據訓練方法-DKFZ官方版


上一篇文章介紹了《保姆級教程:nnUnet在2維圖像的訓練和測試》,採用的是自己的2d數據集進行2d到3d的數據轉換,內容包括nnUnet介紹、環境配置、數據配置、預處理、訓練過程、確定最佳的U-Net配置、運行推斷,算是帶著大家在2d數據情況下把nnUnet訓練和測試了一遍。

最近官方也更新了nnUnet在2d數據情況下的訓練方法,連結為:https://github.com/MIC-DKFZ/nnUNet/blob/master/documentation/dataset_conversion.md,將2d的麻薩諸塞州道路數據road_segmentation_ideal轉換成3d的Task120_MassRoadsSeg數據。

麻薩諸塞州道路數據集是衛星標註圖像,從航空圖像中分割道路是一項具有挑戰性的任務。來自附近樹木的障礙物、相鄰建築物的陰影、道路紋理和顏色的變化、道路等級的不平衡(由於道路圖像像素相對較少)是阻礙當前模型分割從圖像一端延伸到另一端的尖銳道路邊界的其他挑戰。高質量的航空圖像數據集有助於對現有方法進行比較,並在機器學習和計算機視覺領域引起人們對航空圖像應用的興趣。

輸入圖像如下:

標註圖像如下:

一、官方說明How to use 2D data with nnU-Net

nnU-Net was originally built for 3D images. It is also strongestwhen applied to 3D segmentation problems because a large proportion of itsdesign choices were built with 3D in mind. Also note that many 2D segmentationproblems, especially in the non-biomedical domain, may benefit from pretrainednetwork architectures which nnU-Net does not support. Still, there is certainlya need for an out of the box segmentation solution for 2D segmentationproblems. And also on 2D segmentation tasks nnU-Net cam perform extremely well!We have, for example, won a 2D task in the cell tracking challenge with nnU-Net(see our Nature Methods paper) and we have also successfully applied nnU-Net tohistopathological segmentation problems. Working with 2D data in nnU-Netrequires a small workaround in the creation of the dataset. Essentially, allimages must be converted to pseudo 3D images (so an image with shape (X, Y)needs to be converted to an image with shape (1, X, Y). The resulting imagemust be saved in nifti format. Hereby it is important to set the spacing of thefirst axis (the one with shape 1) to a value larger than the others. If you areworking with niftis anyways, then doing this should be easy for you. Thisexample here is intended for demonstrating how nnU-Net can be used with'regular' 2D images. We selected the massachusetts road segmentation datasetfor this because it can be obtained easily, it comes with a good amount oftraining cases but is still not too large to be difficult to handle.

See here for anexample. This script contains a lot of comments and useful information. Alsohave a look here.

How to convert other image formats tonifti

Please have a look at the following tasks:

二、Task120數據集

這裡Task120的連結為:

https://github.com/MIC-DKFZ/nnUNet/blob/master/nnunet/dataset_conversion/Task120_Massachusetts_RoadSegm.py

首先簡單介紹一下代碼的功能:

創建原始數據的文件夾Task120_MassRoadsSeg以及子文件夾imagesTr、imagesTs、labelsTs、labelsTr。

/road_segmentation_ideal路徑內的有訓練集training和測試集testing兩個文件夾,數據集文件夾內有輸入圖像input和標籤output兩個文件夾,分別提取到每個數據的名稱。

調用convert_2d_image_to_nifti函數,讀取每個數據,將3通道的圖像拆成3個模態的3個數據,設置每個像素點實際的長度與寬度Spacing,並保存成nii.gz的3維數據,這裡的3維數據其實只有1層。

原始圖像img-1.png如下:

生成的3個通道的3個模態數據img-1_0000.nii.gz、img-1_0001.nii.gz和img-1_0002.nii.gz如下,是用ITK-SNAP打開的,只展示沿z軸的一層圖像。

三、代碼詳解

此部分代碼文件為:

nnUNet/nnunet/dataset_conversion/Task120_Massachusetts_RoadSegm.py

1. 首先導入需要的包

import numpy as np
from batchgenerators.utilities.file_and_folder_operations import *
from nnunet.dataset_conversion.utils import generate_dataset_json
from nnunet.paths import nnUNet_raw_data, preprocessing_output_dir
from nnunet.utilities.file_conversions impo

2. 定義main函數並做介紹

if __name__ == '__main__':
    """
    nnU-Net was originally built for 3D images. It is also strongest when applied to 3D segmentation problems because a 
    large proportion of its design choices were built with 3D in mind. Also note that many 2D segmentation problems, 
    especially in the non-biomedical domain, may benefit from pretrained network architectures which nnU-Net does not
    support.
    Still, there is certainly a need for an out of the box segmentation solution for 2D segmentation problems. And 
    also on 2D segmentation tasks nnU-Net cam perform extremely well! We have, for example, won a 2D task in the cell 
    tracking challenge with nnU-Net (see our Nature Methods paper) and we have also successfully applied nnU-Net to 
    histopathological segmentation problems. 
    Working with 2D data in nnU-Net requires a small workaround in the creation of the dataset. Essentially, all images 
    must be converted to pseudo 3D images (so an image with shape (X, Y) needs to be converted to an image with shape 
    (1, X, Y). The resulting image must be saved in nifti format. Hereby it is important to set the spacing of the 
    first axis (the one with shape 1) to a value larger than the others. If you are working with niftis anyways, then 
    doing this should be easy for you. This example here is intended for demonstrating how nnU-Net can be used with 
    'regular' 2D images. We selected the massachusetts road segmentation dataset for this because it can be obtained 
    easily, it comes with a good amount of training cases but is still not too large to be difficult to handle.
"""

大致意思是nnUnet最初適用於3D數據,當處理2D數據時需要將數據做成一個偽3D的圖像,形狀為(X,Y)的圖像需要轉換為形狀為(1,X,Y)的圖像,結果圖像必須以nifti格式保存,將第一軸(具有形狀1的軸)的間距設置為大於其他軸的值。該數據集為2d數據麻薩諸塞州道路分割數據集。

3. 下載數據集、修改文件路徑並創建nnUnet能識別的文件夾

   # download dataset from https://www.kaggle.com/insaff/massachusetts-roads-dataset
    # extract the zip file, then set the following path according to your system:
    base = '/media/fabian/data/road_segmentation_ideal'
    # this folder should have the training and testing subfolders

    # now start the conversion to nnU-Net:
    task_name = 'Task120_MassRoadsSeg'
    target_base = join(nnUNet_raw_data, task_name)
    target_imagesTr = join(target_base, "imagesTr")
    target_imagesTs = join(target_base, "imagesTs")
    target_labelsTs = join(target_base, "labelsTs")
    target_labelsTr = join(target_base, "labelsTr")

    maybe_mkdir_p(target_imagesTr)
    maybe_mkdir_p(target_labelsTs)
    maybe_mkdir_p(target_imagesTs)
maybe_mkdir_p(target_labelsTr)

這裡給出了數據集的下載連結:

https://www.kaggle.com/insaff/massachusetts-roads-dataset,解壓並修改文件路徑base。

創建原始數據的文件夾Task120_MassRoadsSeg以及子文件夾imagesTr、imagesTs、labelsTs、labelsTr。

4.  對訓練數據文件進行遍歷

# convert the training examples. Not all training images have labels, so we just take the cases for which there are
    # labels
    labels_dir_tr = join(base, 'training', 'output')
    images_dir_tr = join(base, 'training', 'input')
    training_cases = subfiles(labels_dir_tr, suffix='.png', join=False)
    for t in training_cases:
        unique_name = t[:-4]  # just the filename with the extension cropped away, so img-2.png becomes img-2 as unique_name
        input_segmentation_file = join(labels_dir_tr, t)
        input_image_file = join(images_dir_tr, t)

        output_image_file = join(target_imagesTr, unique_name)  # do not specify a file ending! This will be done for you
        output_seg_file = join(target_labelsTr, unique_name)  # do not specify a file ending! This will be done for you

這裡提示一下,該數據集部分數據無標籤,所以代碼查找的數據以有label的數據為準,無label的數據直接忽略。

針對/road_segmentation_ideal路徑內的訓練集training文件夾,數據集文件夾內有輸入圖像input和標籤output兩個文件夾,輸入圖像文件夾為images_dir_tr,標籤圖像文件夾為labels_dir_tr,提取到output文件夾裡的所有數據名稱training_cases。

分別依次讀取每個數據(這裡是3通道的彩色2d圖像),獲取數據名稱unique_name(去掉後綴),輸入圖像文件為input_image_file,標註圖像文件為input_segmentation_file,輸出圖像文件為output_image_file(不帶後綴,後面會分成3個模態3個輸出圖像文件),輸出標註文件output_seg_file。

5.  調用convert_2d_image_to_nifti函數進行數據轉換

# this utility will convert 2d images that can be read by skimage.io.imread to nifti. You don't need to do anything.
        # if this throws an error for your images, please just look at the code for this function and adapt it to your needs
        convert_2d_image_to_nifti(input_image_file, output_image_file, is_seg=False)

        # the labels are stored as 0: background, 255: road. We need to convert the 255 to 1 because nnU-Net expects
        # the labels to be consecutive integers. This can be achieved with setting a transform
        convert_2d_image_to_nifti(input_segmentation_file, output_seg_file, is_seg=True,
                                  transform=lambda x: (x == 255).astype(int))

上面的代碼是對訓練數據的輸入圖像和標籤圖像做轉換,調用了convert_2d_image_to_nifti函數,該函數首先做了定義和一些介紹:

from typing import Tuple, List
from skimage import io
import SimpleITK as sitk
import numpy as np
import tifffile


def convert_2d_image_to_nifti(input_filename: str, output_filename_truncated: str, spacing=(999, 1, 1),
                              transform=None, is_seg: bool = False) -> None:
    """
    Reads an image (must be a format that it recognized by skimage.io.imread) and converts it into a series of niftis.
    The image can have an arbitrary number of input channels which will be exported separately (_0000.nii.gz,
    _0001.nii.gz, etc for images and only .nii.gz for seg).
    Spacing can be ignored most of the time.
    !!!2D images are often natural images which do not have a voxel spacing that could be used for resampling. These images
    must be resampled by you prior to converting them to nifti!!!
    Datasets converted with this utility can only be used with the 2d U-Net configuration of nnU-Net
    If Transform is not None it will be applied to the image after loading.
    Segmentations will be converted to np.uint32!
    :param is_seg:
    :param transform:
    :param input_filename:
    :param output_filename_truncated: do not use a file ending for this one! Example: output_name='./converted/image1'. This
    function will add the suffix (_0000) and file ending (.nii.gz) for you.
    :param spacing:
    :return:
    """

大致意思是要做數據轉換了,輸入圖像可以是任意通道的(通常是3通道),後面會單獨輸出_0000.nii.gz、_0001.nii.gz等的結果,但標籤數據還是輸出不帶模態標誌的.nii.gz,間距spacing可以忽略,轉換之後的數據集只能用2d unet配置使用。

首先用skimage讀圖

img = io.imread(input_filename)

如果是標籤圖像,則應用transform,將[0,255]的標籤圖像轉換成[0,1]的標籤圖像

if transform is not None:
    img = transform(img)

這裡的

transform=lambda x: (x == 255).astype(int))

如果是1通道的2d圖像,則圖像形狀可能是(256,256),需要增加2個維度,變成(1,1,256,256)

if len(img.shape) == 2:  # 2d image with no color channels
    img = img[None, None]  # add dimensions

如果是3通道的2d圖像,則圖像形狀可能是(256,256,3),先轉置成(3,256,256),然後增加1個維度,變成(3, 1, 256, 256)。

else:
    assert len(img.shape) == 3, "image should be 3d with color channel last but has shape %s" % str(img.shape)
    # we assume that the color channel is the last dimension. Transpose it to be in first
    img = img.transpose((2, 0, 1))
    # add third dimension
    img = img[:, None]

再次確認標籤圖像的通道數為1

# image is now (c, x, x, z) where x=1 since it's 2d
if is_seg:
    assert img.shape[0] == 1, 'segmentations can only have one color channel, not sure what happened here'

遍歷圖像的通道數(通常為3個),分別提取不同通道的圖像,轉換成itk文件,設置spacing層厚,這裡預定義的spacing=(999, 1, 1),經過list(spacing)[::-1]後變成[1, 1, 999],sitk圖像順序是x,y,z三個方向的大小,numpy矩陣的順序是z,y,x三個方向的大小,所以spacing需要轉換成[1, 1, 999]。之後針對輸入圖像和標籤圖像分別存儲為帶模態標誌0000/0001/0002的nifti數據和不帶模態標誌的nifti數據。

for j, i in enumerate(img):

    if is_seg:
        i = i.astype(np.uint32)
    itk_img = sitk.GetImageFromArray(i)
    itk_img.SetSpacing(list(spacing)[::-1])
    if not is_seg:
        sitk.WriteImage(itk_img, output_filename_truncated + "_%04.0d.nii.gz" % j)
    else:
        sitk.WriteImage(itk_img, output_filename_truncated + ".nii.gz")

測試數據方法一樣,

# now do the same for the test set
    labels_dir_ts = join(base, 'testing', 'output')
    images_dir_ts = join(base, 'testing', 'input')
    testing_cases = subfiles(labels_dir_ts, suffix='.png', join=False)
    for ts in testing_cases:
        unique_name = ts[:-4]
        input_segmentation_file = join(labels_dir_ts, ts)
        input_image_file = join(images_dir_ts, ts)

        output_image_file = join(target_imagesTs, unique_name)
        output_seg_file = join(target_labelsTs, unique_name)

        convert_2d_image_to_nifti(input_image_file, output_image_file, is_seg=False)
        convert_2d_image_to_nifti(input_segmentation_file, output_seg_file, is_seg=True,
                                  transform=lambda x: (x == 255).astype(int))

最後生成json文件

# finally we can call the utility for generating a dataset.json
    generate_dataset_json(join(target_base, 'dataset.json'), target_imagesTr, target_imagesTs, ('Red', 'Green', 'Blue'),
                          labels={1: 'street'}, dataset_name=task_name, license='hands off!')

最終轉換之後的數據格式為:

nnUNet_raw_data_base/nnUNet_raw_data/Task120_MassRoadsSeg

├── dataset.json

├── imagesTr

│   ├── img-2_0000.nii.gz

│   ├── img-2_0001.nii.gz

│   ├── img-2_0002.nii.gz

│   ├── ...

├── imagesTs

│   ├── img-1_0000.nii.gz

│   ├── img-1_0001.nii.gz

│   ├── img-1_0002.nii.gz

│   ├── ...

├── labelsTr

│   ├── img-2.nii.gz

│   ├── img-7.nii.gz

│   ├── ...

├── labelsTs

│   ├── img-1.nii.gz

│   ├── img-2.nii.gz

│   ├── ...

這樣數據集就處理好了,之後再按照步驟進行預處理、訓練過程、確定最佳的U-Net配置、運行推斷就好了,可以參照官方https://github.com/MIC-DKFZ/nnUNet,也可以參考我們的前一篇文章《保姆級教程:nnUnet在2維圖像的訓練和測試》。

最後2021年衝鴨!!!

掃它!掃它!掃它!

相關焦點

  • unity中2d遊戲製作基礎訓練視頻教程
    unity中2d遊戲製作基礎訓練視頻教程本教程是關於Unity第三人稱射擊遊戲完整製作訓練視頻教程,時長:47分,大小:10.7
  • pytorch編程之使用 TensorBoard 可視化模型,數據和訓練
    本教程使用 Fashion-MNIST 數據集說明了其某些功能,可以使用 torchvision.datasets 將其讀取到 PyTorch 中。在本教程中,我們將學習如何:讀取數據並進行適當的轉換(與先前的教程幾乎相同)。設置 TensorBoard。寫入 TensorBoard。使用 TensorBoard 檢查模型架構。
  • 使用 YOLOv5 訓練自動駕駛目標檢測網絡
    但是,當在YOLOv4中使用PANET時,此方法略麻煩,因此,YOLO V4的作者沒有使用自適應特徵池添加相鄰層,而是對其進行Concat操作,從而提高了預測的準確性。為了方便將重心放在YOLO V5模型訓練上,我為大家提供了預處理過後的Bdd100k數據集(1drv.ms/u/s!An7G4eYRvZz),該預處理過後的數據集可以直接用來訓練YOLO V5對象檢測網絡。運行YOLO V5的第一步是克隆YOLO V5的官方代碼庫。
  • unity中2d遊戲製作全面技術訓練視頻教程
    unity中2d遊戲製作全面技術訓練視頻教程本教程是關於Unity中2D遊戲製作全面技術訓練視頻教程,時長:18小時30分,大小:
  • 輕鬆學Pytorch – 人臉五點landmark提取網絡訓練與使用
    首先說一下,這裡我參考了OpenVINO官方提供的一個基於卷積神經網絡回歸預測landmark的文檔,因為OpenVINO官方並沒有說明模型結構,更加沒有原始碼可以參考,但是我發現它對模型描述有一句話:It has a classic convolutional design: stacked 3x3 convolutions, batch normalizations
  • live2dviewer破解版
    Live2dviewerex安卓版是一款非常流行的桌面動態壁紙工具,提供了超多全新的LIVE的3D動態壁紙製作,支持自定義所有圖片背景和角色,使得小夥伴們可以自由設置更多全新的視頻動態壁紙
  • Unity 2D Inverse Kinematics資源包使用指南
    通過這種方法,我們可以將骨骼的Transform保留在正確的位置。但要注意,骨骼會以不同的方式到達Transform位置,因為此時動畫幀上沒有使用IK解決方案,除非在每一步都添加關鍵幀。 現在我們已經可以使用Inverse Kinematics資源包處理自己的動畫。二個2D資源包的功能可以完美地結合使用。
  • 乾貨 | YOLOV5 訓練自動駕駛數據集,並轉Tensorrt,收藏!
    準備數據集環境配置配置文件修改訓練推理轉TensorrtBDD100K是最大的開放式駕駛視頻數據集之一,其中包含10萬個視頻和10個任務每個高解析度視頻一共40秒。該數據集包括超過1000個小時的駕駛數據,總共超過1億幀。這些視頻帶有GPU / IMU數據以獲取軌跡信息。該數據集具有地理,環境和天氣多樣性,從而能讓模型能夠識別多種場景,具備更多的泛化能力。這些豐富的戶外場景和複雜的車輛運動使感知任務更具挑戰性。該
  • keras版Mask-RCNN來訓練自己的目標檢測數據集
    2、TensorFlow-gpu版本的安裝,這個安裝方法有三種,第一種是直接在pycharm裡的安裝庫裡安裝。第二種就是使用pip來安裝,這個在安裝的時候可以指定安裝的版本。數據集 獲取:關注微信公眾號 datayx  然後回復  mask  即可獲取。AI項目體驗地址 https://loveai.tech6、把打標後的jison文件轉換為對應的五個文件。其中的代碼文件是:labelme_json_to_dataset.py,使用的代碼是:
  • 3D目標檢測綜述:從數據集到2D和3D方法
    本文將使用 nuScenes 數據集來訓練和評估模型。nuScenes 數據集來自 nuTonomy,是一個大規模自動駕駛數據集,其中的數據進行了 3D 目標標註。與其它很多數據集相比,nuScenes 數據集不僅規模更大,目標標註更多,而且還提供了整套傳感器套件,包括雷射雷達、聲波雷達、GPS 和 IMU。圖 1 展示了 nuScenes 中一個雷射雷達點雲的示例。
  • Facebook新研究:加強版CNN,2D照片也能模擬3D效果
    構建這種增強版的3D照片技術需要克服各種各樣的技術挑戰,例如訓練一個能夠正確推斷非常多種主題圖片的 3D位置的模型,並優化系統讓它能夠瞬間在搭載傳統移動處理器的設備上運行。為了克服這些挑戰,Facebook 在數百萬對對外開放的3D圖像及其對應的深度圖上訓練卷積神經網絡(CNN),並使用了 Facebook AI 研究院此前開發的各種行動裝置優化技術,如FBNet 、 ChamNet等。下面來看構建 3D 照片功能的細節:
  • 使用YOLOv3訓練自己數據的目標檢測
    昨天LearnOpenCV網站博主又發福利,post了一個清晰明了的教程,一步一步示例,如何使用快速實時的YOLOv3算法,訓練某種特定類別目標的檢測器。作者收集了將近1000張雪人的圖片,訓練了一個雪人檢測器,先來看看效果吧全部代碼可在文末下載。
  • 快速上手筆記,PyTorch模型訓練實用教程(附代碼)
    本教程以實際應用、工程開發為目的,著重介紹模型訓練過程中遇到的實際問題和方法。如上圖所示,在機器學習模型開發中,主要涉及三大部分,分別是數據、模型和損失函數及優化器。本文也按順序的依次介紹數據、模型和損失函數及優化器,從而給大家帶來清晰的機器學習結構。通過本教程,希望能夠給大家帶來一個清晰的模型訓練結構。
  • 訓練神經網絡的方法分享-Andrej Karpathy
    或者,對測試數據進行兩次注釋,對於每個示例,將一次注釋視為預測,第二次注釋視為真是情況。    7、input-indepent baseline。訓練一個獨立於輸入的baseline(例如,最簡單的方法是將所有輸入設置為零)。這應該比實際插入數據而不清零時表現更差。是嗎?即,你的模型是否學會從輸入中提取任何信息?
  • MATLAB中使用CIFLog數據的方法
    ,需要把曲線數據利用專業測井軟體導成文本格式或excel格式後,導入到Matlab中,才能進行計算和可視化等操作,這給研究帶來很多困擾,廣大測井科研工作者多麼希望在Matlab中直接調用測井數據。本文將介紹一種在Matlab中讀寫CIFLog數據的方法。
  • 使用Pytorch訓練分類器詳解(附python演練)
    使用torchvision加載並且歸一化CIFAR10的訓練和測試數據集2. 定義一個卷積神經網絡3. 定義一個損失函數4. 在訓練樣本數據上訓練網絡5. 在測試樣本數據上測試網絡三.在GPU上訓練四.
  • 使用MLP多層感知器模型訓練mnist數據集
    mnist 數據集分兩部分:訓練集、測試集每集又分為:特徵、標籤,特徵就是拿來訓練和預測的數據,標籤就是答案使用 mnist.load_data() 導入數據集,可以給數據起個名字(train_image,train_label),(test_image,test_label) = mnist.load_data()
  • 資源 | GitHub新項目:輕鬆使用多種預訓練卷積網絡抽取圖像特徵
    機器之心簡要地介紹了該項目,並測試了使用Inception_V1預訓練模型抽取圖像特徵。項目地址:https://github.com/cameronfabbri/Compute-Features這個項目的用法非常簡單,我們只需要下載項目中的預訓練模型檢查點,例如 Inception V1 等。
  • PyTorch多GPU並行訓練方法及問題整理
    , 絕對不建議使用多機多gpu進行訓練, 我經過測試, 發現多臺機器之間傳輸數據的時間非常慢, 主要是因為我測試的機器可能只是千兆網卡, 再加上別的一些損耗, 網絡的傳輸速度跟不上, 導致訓練速度實際很慢.
  • 在TensorFlow量化感知訓練中排除指定layer
    封面圖片:Photo by Trevor Bobyk on UnsplashTensorFlow的量化感知訓練可以進一步提升量化後模型的準確率。不過目前這一工具支持的範圍有限。例如對於常見的BatchNorm層,它必須跟在卷積層後才可以被正確量化。對於沒有直接跟在卷積層後的BatchNorm層,我們需要將它排除在感知量化範圍外。本文記錄了HRNet下的具體實現方法。