使用【PaddleSeg3D】搭建项目对肝脏进行3D分割
PaddleSeg3D 是一个易于使用的 3D 医学图像分割工具包。是基于PaddlePaddle进行开发的3D分割套件。由飞桨的CV兴趣小组进行开发和维护。
!git clone https://github.com/PaddleCV-SIG/PaddleSeg3D.git
1. PaddleSeg3D
从这个工具的github地址https://github.com/PaddleCV-SIG/PaddleSeg3D.git ,可以看出是飞桨的兴趣小组(PPSIG,飞桨特殊兴趣小组)的CV小组开发和维护的。如果对飞桨的分割套件PaddleSeg熟悉的话,知道PaddleSeg目前支持都是2D分割,没有3D分割这方面的工具,不过有很多用户或者行业有3D分割的需求,特别医疗行业的用户。现在飞桨兴趣小组开发了PaddleSeg3D的3D分割工具,后面估计会整合到PaddleSeg分割套件中。
现在尝试用PaddleSeg3D这个工具搭建3D分割项目,分割自己的医疗数据。
PaddleSeg3D跟PaddleSeg很像的,用起来也很方便,但是就是对自己的医疗数据预处理没有提供太多的脚本,例如PaddleSeg3D中快速运行的教程中,是对新冠胸部CT的数据集进行肺部的分割,里面的预处理都是根据肺部“打量的”,还不支持nii后缀名的医疗格式,所以如果你要分割自己的数据,器官不是肺部的话,那需要自己写脚本。不过除自己需要对数据进行预处理外,后面的训练,就很方便,PaddleSeg3D提供一行代码就可以训练、验证、评估。
希望PaddleSeg3D可以尽快加入PaddleSeg开发套件中。
# 安装依赖
!pip install -r ./PaddleSeg3D/requirements.txt
#解压数据
!unzip -o /home/aistudio/data/data129670/livers.zip -d /home/aistudio/PaddleSeg3D
2. 数据集介绍
这个项目主要分割肝脏和肿瘤,数据的模式是CT,属于薄层数据(体素约为0.7x0.7x0.7),在Z轴上可以达到500多层。通过ITK-SNAP中看到显示红色的是肝脏,显示绿色的是肿瘤。这个数据集一共有28例
#记得运行这行
%cd /home/aistudio/PaddleSeg3D/
/home/aistudio/PaddleSeg3D
#导入常用的库
import nibabel as nib
import SimpleITK as sitk
import matplotlib.pyplot as plt
import numpy as np
import os
from tqdm import tqdm
3. 对数据进行预处理
PaddleSeg3D的快速运行教程是分割胸部CT数据的肺部。对数据处理如下:
用nibabel读取医疗数据后,
if "nii.gz" in filename:
f_np = nib.load(f).get_fdata(dtype=np.float32)
对CT值裁剪,然后对数据的Size 重采样到[128,128,128],再转换成numpy数据。
preprocess=[
HUNorm,
functools.partial(
resample, new_shape=[128, 128, 128], order=1)
],
HUNorm默认是 HU_min=-1000, HU_max=600
#这个值范围类似肺窗
如果是分割自己的数据(不是分割肺部)是不能用它提供的脚本,假如你的医疗数据是nii的话,直接不支持读取(脚本没有把nii的格式写进去),而且使用nibabel来读取nii的话,图像会旋转90度,对CT值裁剪也是针对肺部的。因此最好自己写脚本预处理自己的数据。
因此对这个项目的肝脏数据,自己写脚本进行如下的预处理:
- 用SimpleITK读取.nii医疗数据,而且用SimpleITK不会出现用nibabel读取后会旋转90度
- 对数据统一方向,避免SimpleITK读取后,图像上下翻转(统一方向后,用nibabel还是会旋转90度)
- 对数据的CT值根据窗宽窗位进行裁剪
- 对数据的Size 进行重采样到[128,128,128]
- 转换成numpy(.npy)文件
"""
发现nibabel读取会旋转90度,SImpleITK会上下翻转,为了解决这个问题,需要对数据进行方向统一.
不过统不统一方向,nibabel都会旋转90度,而PaddleSeg3D也是刚好用这库处理医学数据转换成numpy,
所以转换numpy时,我不用这分割套件自带的脚本,自己用SImpleITK写一个。
"""
plt.figure(figsize=(10,5))
f_nib = nib.load("./livers/data/volume-2.nii").get_fdata(dtype=np.float32)
print(f"nibabel读取文件转换numpy后形状为x,y,z{f_nib.shape}")
f_sitk= sitk.GetArrayFromImage(sitk.ReadImage('./livers/data/volume-2.nii'))
print(f"SimpleITK读取文件转换numpy后形状为z,y,x{f_sitk.shape}")
plt.subplot(1,2,1),plt.imshow(f_nib[:,:,60],'gray'),plt.title("nibabel")
plt.subplot(1,2,2),plt.imshow(f_sitk[60,:,:],'gray'),plt.title("SimpleITK")
plt.show()
nibabel读取文件转换numpy后形状为x,y,z(512, 512, 158)
SimpleITK读取文件转换numpy后形状为z,y,x(158, 512, 512)
"""
读取nii文件后,设置统一的Direction,
"""
def reorient_image(image):
"""Reorients an image to standard radiology view."""
dir = np.array(image.GetDirection()).reshape(len(image.GetSize()), -1)
ind = np.argmax(np.abs(dir), axis=0)
new_size = np.array(image.GetSize())[ind]
new_spacing = np.array(image.GetSpacing())[ind]
new_extent = new_size * new_spacing
new_dir = dir[:, ind]
flip = np.diag(new_dir) < 0
flip_diag = flip * -1
flip_diag[flip_diag == 0] = 1
flip_mat = np.diag(flip_diag)
new_origin = np.array(image.GetOrigin()) + np.matmul(new_dir, (new_extent * flip))
new_dir = np.matmul(new_dir, flip_mat)
resample = sitk.ResampleImageFilter()
resample.SetOutputSpacing(new_spacing.tolist())
resample.SetSize(new_size.tolist())
resample.SetOutputDirection(new_dir.flatten().tolist())
resample.SetOutputOrigin(new_origin.tolist())
resample.SetTransform(sitk.Transform())
resample.SetDefaultPixelValue(image.GetPixelIDValue())
resample.SetInterpolator(sitk.sitkNearestNeighbor)
return resample.Execute(image)
for f in tqdm(os.listdir("./livers/data")) :
d_path = os.path.join('./livers/data',f)
seg_path = os.path.join('./livers/mask',f.replace("volume","segmentation"))
d_sitkimg = sitk.ReadImage(d_path)
d_sitkimg = reorient_image(d_sitkimg)
seg_sitkimg = sitk.ReadImage(seg_path)
seg_sitkimg = reorient_image(seg_sitkimg)
sitk.WriteImage(d_sitkimg,d_path)
sitk.WriteImage(seg_sitkimg,seg_path)
#统一方向后,再用SimpleITK读取,不再是上下翻转了,显示正常了
plt.figure(figsize=(10,5))
img= sitk.GetArrayFromImage(sitk.ReadImage('./livers/data/volume-2.nii'))
seg= sitk.GetArrayFromImage(sitk.ReadImage('./livers/mask/segmentation-2.nii'))
plt.subplot(1,2,1),plt.imshow(img[60,:,:],'gray'),plt.title("origin")
plt.subplot(1,2,2),plt.imshow(seg[60,:,:],'gray'),plt.title("mask")
plt.show()
"""
对已经CT值裁剪和size重采样的数据转换成numpy并保存.npy文件
"""
from paddleseg3d.datasets.preprocess_utils import HUNorm, resample
dataset_root = "livers/"
image_dir = os.path.join(dataset_root, "images") #images 不要改,存放转换后原始数据的npy文件
label_dir = os.path.join(dataset_root, "labels") #labels 不要改,存放转换后的标签npy文件
os.makedirs(image_dir, exist_ok=True)
os.makedirs(label_dir, exist_ok=True)
ww = 350
wc = 80
for f in tqdm(os.listdir("./livers/data")) :
d_path = os.path.join('./livers/data',f)
seg_path = os.path.join('./livers/mask',f.replace("volume","segmentation"))
d_img = sitk.GetArrayFromImage(sitk.ReadImage(d_path))
d_img = HUNorm(d_img,HU_min=int(wc-int(ww/2)), HU_max=int(wc+int(ww/2)))
d_img = resample(d_img,new_shape=[128, 128, 128], order=1).astype("float32")#new_shape=[z,y,x]
seg_img = sitk.GetArrayFromImage(sitk.ReadImage(seg_path))
seg_img = resample(seg_img,new_shape=[128, 128, 128], order=0).astype("int64")
np.save(os.path.join(image_dir,f.split('.')[0]), d_img)
np.save(os.path.join(label_dir,f.split('.')[0].replace("volume","segmentation")), seg_img)
# 划分数据集,训练集和测试集为8:2
import random
random.seed(1000)
path_origin = './livers/images/'
files = list(filter(lambda x: x.endswith('.npy'), os.listdir(path_origin)))
random.shuffle(files)
rate = int(len(files) * 0.8)#训练集和测试集8:2
train_txt = open('./livers/train_list.txt','w')
val_txt = open('./livers/val_list.txt','w')
for i,f in enumerate(files):
image_path = os.path.join('images', f)
label_path = image_path.replace("images", "labels").replace('volume','segmentation')
if i < rate:
train_txt.write(image_path + ' ' + label_path+ '\n')
else:
val_txt.write(image_path + ' ' + label_path+ '\n')
train_txt.close()
val_txt.close()
print('完成')
完成
"""
最后读取转换后的npy文件并展示,可见图像显示肝脏的窗宽窗位,形状大小也为128*128,数据都归一化到0到1之间
"""
data = np.load('livers/images/volume-0.npy')
print(data.shape)
print(np.max(data),np.min(data))#把数据归一化到0-1
img = data[60,:,:]
plt.imshow(img,'gray')
plt.show()
(128, 256, 256)
1.0 0.0
4. 设置训练配置文件
PaddleSeg3D通过配置yaml文件来设置训练参数的。
这次训练用到的yaml文件内容如下:
data_root: livers/ #随便设置,只要是一个路径即可,因为dataset_root用来绝对路径
batch_size: 2
iters: 15000
train_dataset:
type: LungCoronavirus #不用管
dataset_root: /home/aistudio/PaddleSeg3D/livers/ #这里用绝对路径省事好似
result_dir: None #目前好似没啥用
transforms:
- type: RandomResizedCrop3D #随机缩放裁剪
size: 128
scale: [0.8, 1.4]
- type: RandomRotation3D #随机旋转
degrees: 60 #旋转角度[-60 ,+60]度
- type: RandomFlip3D # 随机翻转
mode: train #训练模式
num_classes: 3 #分割类别数(背景,肝脏,肿瘤)
val_dataset:
type: LungCoronavirus
dataset_root: /home/aistudio/PaddleSeg3D/livers/
result_dir: None
num_classes: 3
transforms: []
mode: val
optimizer: #优化器设置
type: sgd
momentum: 0.9
weight_decay: 1.0e-4
lr_scheduler: #学习率设置
type: PolynomialDecay
decay_steps: 15000
learning_rate: 0.0003
end_lr: 0
power: 0.9
loss: #损失函数,交叉熵和dice结合一起用
types:
- type: MixedLoss
losses:
- type: CrossEntropyLoss
weight: Null
- type: DiceLoss
coef: [1, 1] #设置交叉熵和dice的权重
coef: [1]
model:
type: VNet #目前只有Unet3d和Vnet两个3D分割网络选择
elu: False
in_channels: 1
num_classes: 3
pretrained: null
5. VNet
VNet是医疗3D分割网络,结构上也是采用U型结构。比起Unet3D,层内采用残差结构(第一个红框)。用卷积层替代池化层(第二个红框)。论文中也强调了Dice损失函数的作用
#打印vnet的网络结构
!python paddleseg3d/models/vnet.py
/home/aistudio/PaddleSeg3D/paddleseg3d/models/../../paddleseg3d/cvlibs/manager.py:118: UserWarning: VNet exists already! It is now updated to <class '__main__.VNet'> !!!
component_name, component))
W0228 19:18:39.534801 27494 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1
W0228 19:18:39.538172 27494 device_context.cc:465] device: 0, cuDNN Version: 7.6.
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/nn/layer/norm.py:653: UserWarning: When training, we now always track global mean and variance.
"When training, we now always track global mean and variance.")
out Tensor(shape=[1], dtype=float32, place=CUDAPlace(0), stop_gradient=False,
[-0.45796004]) Tensor(shape=[1], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
[0.49996352])
-----------------------------------------------------------------------------------------------------------
Layer (type) Input Shape Output Shape Param #
===========================================================================================================
Conv3D-1 [[1, 1, 128, 256, 256]] [1, 16, 128, 256, 256] 2,016
BatchNorm3D-1 [[1, 16, 128, 256, 256]] [1, 16, 128, 256, 256] 64
PReLU-1 [[1, 16, 128, 256, 256]] [1, 16, 128, 256, 256] 16
InputTransition-1 [[1, 1, 128, 256, 256]] [1, 16, 128, 256, 256] 0
Conv3D-2 [[1, 16, 128, 256, 256]] [1, 32, 64, 128, 128] 4,128
BatchNorm3D-2 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 128
PReLU-2 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 32
Conv3D-3 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 128,032
BatchNorm3D-3 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 128
PReLU-4 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 32
LUConv-1 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 0
PReLU-3 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 32
DownTransition-1 [[1, 16, 128, 256, 256]] [1, 32, 64, 128, 128] 0
Conv3D-4 [[1, 32, 64, 128, 128]] [1, 64, 32, 64, 64] 16,448
BatchNorm3D-4 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 256
PReLU-5 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 64
Conv3D-5 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 512,064
BatchNorm3D-5 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 256
PReLU-7 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 64
LUConv-2 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 0
Conv3D-6 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 512,064
BatchNorm3D-6 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 256
PReLU-8 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 64
LUConv-3 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 0
PReLU-6 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 64
DownTransition-2 [[1, 32, 64, 128, 128]] [1, 64, 32, 64, 64] 0
Conv3D-7 [[1, 64, 32, 64, 64]] [1, 128, 16, 32, 32] 65,664
BatchNorm3D-7 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 512
PReLU-9 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 128
Dropout3D-3 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 0
Conv3D-8 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 2,048,128
BatchNorm3D-8 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 512
PReLU-11 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 128
LUConv-4 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 0
Conv3D-9 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 2,048,128
BatchNorm3D-9 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 512
PReLU-12 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 128
LUConv-5 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 0
Conv3D-10 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 2,048,128
BatchNorm3D-10 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 512
PReLU-13 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 128
LUConv-6 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 0
PReLU-10 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 128
DownTransition-3 [[1, 64, 32, 64, 64]] [1, 128, 16, 32, 32] 0
Conv3D-11 [[1, 128, 16, 32, 32]] [1, 256, 8, 16, 16] 262,400
BatchNorm3D-11 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 1,024
PReLU-14 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 256
Dropout3D-4 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 0
Conv3D-12 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 8,192,256
BatchNorm3D-12 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 1,024
PReLU-16 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 256
LUConv-7 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 0
Conv3D-13 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 8,192,256
BatchNorm3D-13 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 1,024
PReLU-17 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 256
LUConv-8 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 0
PReLU-15 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 256
DownTransition-4 [[1, 128, 16, 32, 32]] [1, 256, 8, 16, 16] 0
Dropout3D-5 [[1, 256, 8, 16, 16]] [1, 256, 8, 16, 16] 0
Dropout3D-6 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 0
Conv3DTranspose-1 [[1, 256, 8, 16, 16]] [1, 128, 16, 32, 32] 262,272
BatchNorm3D-14 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 512
PReLU-18 [[1, 128, 16, 32, 32]] [1, 128, 16, 32, 32] 128
Conv3D-14 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 8,192,256
BatchNorm3D-15 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 1,024
PReLU-20 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 256
LUConv-9 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 0
Conv3D-15 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 8,192,256
BatchNorm3D-16 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 1,024
PReLU-21 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 256
LUConv-10 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 0
PReLU-19 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 256
UpTransition-1 [[1, 256, 8, 16, 16], [1, 128, 16, 32, 32]] [1, 256, 16, 32, 32] 0
Dropout3D-7 [[1, 256, 16, 32, 32]] [1, 256, 16, 32, 32] 0
Dropout3D-8 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 0
Conv3DTranspose-2 [[1, 256, 16, 32, 32]] [1, 64, 32, 64, 64] 131,136
BatchNorm3D-17 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 256
PReLU-22 [[1, 64, 32, 64, 64]] [1, 64, 32, 64, 64] 64
Conv3D-16 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 2,048,128
BatchNorm3D-18 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 512
PReLU-24 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 128
LUConv-11 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 0
Conv3D-17 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 2,048,128
BatchNorm3D-19 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 512
PReLU-25 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 128
LUConv-12 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 0
PReLU-23 [[1, 128, 32, 64, 64]] [1, 128, 32, 64, 64] 128
UpTransition-2 [[1, 256, 16, 32, 32], [1, 64, 32, 64, 64]] [1, 128, 32, 64, 64] 0
Conv3DTranspose-3 [[1, 128, 32, 64, 64]] [1, 32, 64, 128, 128] 32,800
BatchNorm3D-20 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 128
PReLU-26 [[1, 32, 64, 128, 128]] [1, 32, 64, 128, 128] 32
Conv3D-18 [[1, 64, 64, 128, 128]] [1, 64, 64, 128, 128] 512,064
BatchNorm3D-21 [[1, 64, 64, 128, 128]] [1, 64, 64, 128, 128] 256
PReLU-28 [[1, 64, 64, 128, 128]] [1, 64, 64, 128, 128] 64
LUConv-13 [[1, 64, 64, 128, 128]] [1, 64, 64, 128, 128] 0
PReLU-27 [[1, 64, 64, 128, 128]] [1, 64, 64, 128, 128] 64
UpTransition-3 [[1, 128, 32, 64, 64], [1, 32, 64, 128, 128]] [1, 64, 64, 128, 128] 0
Conv3DTranspose-4 [[1, 64, 64, 128, 128]] [1, 16, 128, 256, 256] 8,208
BatchNorm3D-22 [[1, 16, 128, 256, 256]] [1, 16, 128, 256, 256] 64
PReLU-29 [[1, 16, 128, 256, 256]] [1, 16, 128, 256, 256] 16
Conv3D-19 [[1, 32, 128, 256, 256]] [1, 32, 128, 256, 256] 128,032
BatchNorm3D-23 [[1, 32, 128, 256, 256]] [1, 32, 128, 256, 256] 128
PReLU-31 [[1, 32, 128, 256, 256]] [1, 32, 128, 256, 256] 32
LUConv-14 [[1, 32, 128, 256, 256]] [1, 32, 128, 256, 256] 0
PReLU-30 [[1, 32, 128, 256, 256]] [1, 32, 128, 256, 256] 32
UpTransition-4 [[1, 64, 64, 128, 128], [1, 16, 128, 256, 256]] [1, 32, 128, 256, 256] 0
Conv3D-20 [[1, 32, 128, 256, 256]] [1, 2, 128, 256, 256] 8,002
BatchNorm3D-24 [[1, 2, 128, 256, 256]] [1, 2, 128, 256, 256] 8
PReLU-32 [[1, 2, 128, 256, 256]] [1, 2, 128, 256, 256] 2
Conv3D-21 [[1, 2, 128, 256, 256]] [1, 2, 128, 256, 256] 6
OutputTransition-1 [[1, 32, 128, 256, 256]] [1, 2, 128, 256, 256] 0
===========================================================================================================
Total params: 45,609,250
Trainable params: 45,598,618
Non-trainable params: 10,632
-----------------------------------------------------------------------------------------------------------
Input size (MB): 32.00
Forward/backward pass size (MB): 29372.00
Params size (MB): 173.99
Estimated Total Size (MB): 29577.99
-----------------------------------------------------------------------------------------------------------
Vnet test is complete
6. 开始训练
一行代码开始训练
#开始训练
"""
!python3 train.py --config /home/aistudio/vnet_livers.yml #yaml文件路径
--save_dir "/home/aistudio/output/livers" #模型保存路径
--save_interval 500 #多少iters保存模型参数
--log_iters 60 #多少iters打印一次信息
--iters 15000 #训练多少iters
--num_workers 6
--do_eval #是否训练期间验证模型性能
--use_vdl #是否使用VisualDL可视化训练指标的走势
"""
!python3 train.py --config /home/aistudio/vnet_livers.yml \
--save_dir "/home/aistudio/output/livers_vent128x128x128" \
--save_interval 500 --log_iters 20 \
--num_workers 6 --do_eval --use_vdl
7. 模型的验证和导出
2022-02-28 01:24:12 [INFO] [EVAL] #Images: 6, Dice: 0.6289, Loss: 0.634533
2022-02-28 01:24:12 [INFO] [EVAL] Class dice:
[0.9893 0.8679 0.0295]
用VNet跑了15000,验证集的效果如下:肝脏的dice为0.8679,肿瘤的dice为0.0295。对肿瘤这些小目标的检测效果比较差
#验证
"""
!python3 val.py --config /home/aistudio/vnet_livers.yml \ #yaml文件路径
--model_path /home/aistudio/output/livers/best_model/model.pdparams \ #最优模型的路径
--save_dir /home/aistudio/output/livers/best_model #验证后结果的保存路径
"""
!python3 val.py --config /home/aistudio/vnet_livers.yml \
--model_path /home/aistudio/output/livers/best_model/model.pdparams \
--save_dir /home/aistudio/output/livers/best_model
2022-02-28 01:24:04 [INFO]
---------------Config Information---------------
batch_size: 2
data_root: livers/
iters: 15000
loss:
coef:
- 1
types:
- coef:
- 0.7
- 0.3
losses:
- type: CrossEntropyLoss
weight: null
- type: DiceLoss
type: MixedLoss
lr_scheduler:
decay_steps: 15000
end_lr: 0
learning_rate: 0.0003
power: 0.9
type: PolynomialDecay
model:
elu: false
in_channels: 1
num_classes: 3
pretrained: null
type: VNet
optimizer:
momentum: 0.9
type: sgd
weight_decay: 0.0001
train_dataset:
dataset_root: /home/aistudio/PaddleSeg3D/livers/
mode: train
num_classes: 3
result_dir: None
transforms:
- scale:
- 0.8
- 1.2
size: 128
type: RandomResizedCrop3D
- degrees: 60
type: RandomRotation3D
- type: RandomFlip3D
type: LungCoronavirus
val_dataset:
dataset_root: /home/aistudio/PaddleSeg3D/livers/
mode: val
num_classes: 3
result_dir: None
transforms: []
type: LungCoronavirus
------------------------------------------------
W0228 01:24:04.360675 32748 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1
W0228 01:24:04.360720 32748 device_context.cc:465] device: 0, cuDNN Version: 7.6.
2022-02-28 01:24:08 [INFO] Loading pretrained model from /home/aistudio/output/livers/best_model/model.pdparams
2022-02-28 01:24:09 [INFO] There are 178/178 variables loaded into VNet.
2022-02-28 01:24:09 [INFO] Loaded trained params of model successfully
2022-02-28 01:24:09 [INFO] Start evaluating (total_samples: 6, total_iters: 6)...
2022-02-28 01:24:10 [INFO] [EVAL] Sucessfully save iter 0 pred and label.
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/math_op_patch.py:253: UserWarning: The dtype of left and right variables are not the same, left dtype is paddle.float32, but right dtype is paddle.bool, the right dtype will convert to paddle.float32
format(lhs_dtype, rhs_dtype, lhs_dtype))
1/6 [====>.........................] - ETA: 3s - batch_cost: 0.6990 - reader cost: 0.20632022-02-28 01:24:10 [INFO] [EVAL] Sucessfully save iter 1 pred and label.
2/6 [=========>....................] - ETA: 2s - batch_cost: 0.5683 - reader cost: 0.10322022-02-28 01:24:11 [INFO] [EVAL] Sucessfully save iter 2 pred and label.
3/6 [==============>...............] - ETA: 1s - batch_cost: 0.5247 - reader cost: 0.06882022-02-28 01:24:11 [INFO] [EVAL] Sucessfully save iter 3 pred and label.
4/6 [===================>..........] - ETA: 1s - batch_cost: 0.5027 - reader cost: 0.05172022-02-28 01:24:12 [INFO] [EVAL] Sucessfully save iter 4 pred and label.
5/6 [========================>.....] - ETA: 0s - batch_cost: 0.4912 - reader cost: 0.04132022-02-28 01:24:12 [INFO] [EVAL] Sucessfully save iter 5 pred and label.
6/6 [==============================] - 3s 483ms/step - batch_cost: 0.4830 - reader cost: 0.0345
2022-02-28 01:24:12 [INFO] [EVAL] #Images: 6, Dice: 0.6289, Loss: 0.634533
2022-02-28 01:24:12 [INFO] [EVAL] Class dice:
[0.9893 0.8679 0.0295]
#导出模型,方便推理和部署
"""
!python export.py --config /home/aistudio/vnet_livers.yml \ #yaml文件路径
--save_dir '/home/aistudio/save_model' \#导出模型的保存路径
--model_path /home/aistudio/output/livers/best_model/model.pdparams #需要导出的模型的路径
"""
!python export.py --config /home/aistudio/vnet_livers.yml \
--save_dir '/home/aistudio/save_model' \
--model_path /home/aistudio/output/livers/best_model/model.pdparams
#加载导出来的模型,对数据进行推理
!python deploy/python/infer.py --config /home/aistudio/save_model/deploy.yaml \
--image_path /home/aistudio/PaddleSeg3D/livers/images/volume-5.npy \
--save_dir '/home/aistudio'
#可视化推理后的结果
pre = np.load('/home/aistudio/volume-5.npy')
pre = np.squeeze(pre)
print(pre.shape)
img = pre[60,:,:]
plt.imshow(img,'gray')
plt.show()
(256, 128, 128)
更多推荐
所有评论(0)