本文采用Unet3d进行BRAST2015数据集的分割
BRAST2015读取 BRAST2015数据集为脑部肿瘤分割的,数据集分为两类,一类为HGG(高分级胶质瘤),另一类为LGG(低分级胶质瘤)
文件夹目录如图所示
文章图片
包含了MRI Flair T1 T1c T2四种模态,OT为ground Truth(0,1,2,3,4五种标签)
数据文件都为.mha文件,可以直接使用SimpleITK进行读取
def sitk_read(img_path):
nda = sitk.ReadImage(img_path)
nda = sitk.GetArrayFromImage(nda) #(155,240,240)
nda = nda.transpose(1, 2, 0) #(240,240,155)
return nda
直接调用SimpleITK.ReadImage得到Image对象,然后转成np,这里读出来的shape是(depth,height,width)
因为BRAST的数据集中只有train数据集有ground truth,val数据集是没有ground truth的,所以要在train数据集上分成train、val、test三部分用于网络,先读入所有train文件名用list存起来,然后用random随机打乱顺序,然后取8份为train,1份为val,1份为test,将三个数据集的文件名用txt存起来,以便于训练的时候直接读取
def write_train_val_test_name_list(self):
data_name_list = os.listdir(self.train_root_path + self.type + "\\")
random.shuffle(data_name_list)
length = len(data_name_list)
n_train_file = int(length / 10 * 8)
n_val_file = int(length / 10 * 1)
train_name_list = data_name_list[0:n_train_file]
val_name_list = data_name_list[n_train_file:(n_train_file + n_val_file)]
test_name_list = data_name_list[(n_train_file + n_val_file):len(data_name_list)]
self.write_name_list(train_name_list, "train_name_list.txt")
self.write_name_list(val_name_list, "val_name_list.txt")
self.write_name_list(test_name_list, "test_name_list.txt")def write_name_list(self, name_list, file_name):
f = open(self.train_root_path + file_name, 'w')
for i in range(len(name_list)):
f.write(name_list[i] + "\n")
f.close()
完整代码如下:
def make_one_hot_3d(x, n):
one_hot = np.zeros([x.shape[0], x.shape[1], x.shape[2], n])
for i in range(x.shape[0]):
for j in range(x.shape[1]):
for v in range(x.shape[2]):
one_hot[i, j, v, int(x[i, j, v])] = 1
return one_hotclass brast_reader:
def __init__(self, train_batch_size, val_batch_size, test_batch_size, type='HGG'):
self.train_root_path = "D:\\pyproject\\data\\BRATS2015\\BRATS2015_Training\\BRATS2015_Training\\"
self.type = typeself.train_name_list = self.load_file_name_list(self.train_root_path + "train_name_list.txt")
self.val_name_list = self.load_file_name_list(self.train_root_path + "val_name_list.txt")
self.test_name_list = self.load_file_name_list(self.train_root_path + "test_name_list.txt")self.n_train_file = len(self.train_name_list)
self.n_val_file = len(self.val_name_list)
self.n_test_file = len(self.test_name_list)self.train_batch_size = train_batch_size
self.val_batch_size = val_batch_size
self.test_batch_size = test_batch_sizeself.n_train_steps_per_epoch = self.n_train_file // self.train_batch_size
self.n_val_steps_per_epoch = self.n_val_file // self.val_batch_sizeself.img_height = 240
self.img_width = 240
self.img_depth = 160
self.n_labels = 5self.train_batch_index = 0
self.val_batch_index = 0def load_file_name_list(self, file_path):
file_name_list = []
with open(file_path, 'r') as file_to_read:
while True:
lines = file_to_read.readline().strip()# 整行读取数据
if not lines:
break
pass
file_name_list.append(lines)
pass
return file_name_listdef write_train_val_test_name_list(self):
data_name_list = os.listdir(self.train_root_path + self.type + "\\")
random.shuffle(data_name_list)
length = len(data_name_list)
n_train_file = int(length / 10 * 8)
n_val_file = int(length / 10 * 1)
train_name_list = data_name_list[0:n_train_file]
val_name_list = data_name_list[n_train_file:(n_train_file + n_val_file)]
test_name_list = data_name_list[(n_train_file + n_val_file):len(data_name_list)]
self.write_name_list(train_name_list, "train_name_list.txt")
self.write_name_list(val_name_list, "val_name_list.txt")
self.write_name_list(test_name_list, "test_name_list.txt")def write_name_list(self, name_list, file_name):
f = open(self.train_root_path + file_name, 'w')
for i in range(len(name_list)):
f.write(name_list[i] + "\n")
f.close()def next_train_batch_2d(self):
if self.train_batch_index >= self.n_train_file:
self.train_batch_index = 0data_path = self.train_root_path + self.type + '\\' + self.train_name_list[self.train_batch_index]# flair, t1, t1c, t2, ot=self.get_np_data(data_path)
t1, ot = self.get_np_data_2d(data_path)
train_imgs=t1[:,:,:,np.newaxis] #(155,240,240,1)
train_labels=make_one_hot_3d(ot,self.n_labels) #(155,240,240,5)self.train_batch_index+=1
return train_imgs,train_labelsdef next_val_batch_2d(self):
if self.val_batch_index >= self.n_val_file:
self.val_batch_index = 0data_path = self.train_root_path + self.type + '\\' + self.val_name_list[self.val_batch_index]# flair, t1, t1c, t2, ot=self.get_np_data(data_path)
t1, ot = self.get_np_data_2d(data_path)val_imgs=t1[:,:,:,np.newaxis] #(155,240,240,1)
val_labels=make_one_hot_3d(ot,self.n_labels)
self.val_batch_index += 1return val_imgs, val_labelsdef next_train_batch_3d(self):
train_imgs = np.zeros((self.train_batch_size, self.img_height, self.img_width, self.img_depth, 1))
train_labels = np.zeros([self.train_batch_size, self.img_height, self.img_width, self.img_depth, self.n_labels])
if self.train_batch_index >= self.n_train_steps_per_epoch:
self.train_batch_index = 0
for i in range(self.train_batch_size):
data_path = self.train_root_path + self.type + '\\' + self.train_name_list[
self.train_batch_size * self.train_batch_index + i]# flair, t1, t1c, t2, ot=self.get_np_data(data_path)
t1, ot = self.get_np_data_3d(data_path)
# flair=flair[:,:,:,np.newaxis]
t1 = t1[:, :, :, np.newaxis]
# t1c = t1c[:, :, :, np.newaxis]
# t2 = t2[:, :, :, np.newaxis]
train_imgs[i] = t1
one_hot = make_one_hot_3d(ot, self.n_labels)
train_labels[i] = one_hotself.train_batch_index += 1return train_imgs, train_labelsdef next_val_batch_3d(self):
val_imgs = np.zeros((self.train_batch_size, self.img_height, self.img_width, self.img_depth, 1))
val_labels = np.zeros([self.train_batch_size, self.img_height, self.img_width, self.img_depth, self.n_labels])
if self.val_batch_index >= self.n_val_steps_per_epoch:
self.val_batch_index = 0
for i in range(self.val_batch_size):
data_path = self.train_root_path + self.type + '\\' + self.val_name_list[
self.val_batch_size * self.val_batch_index + i]# flair, t1, t1c, t2, ot=self.get_np_data(data_path)
t1, ot = self.get_np_data_3d(data_path)
# flair=flair[:,:,:,np.newaxis]
t1 = t1[:, :, :, np.newaxis]
# t1c = t1c[:, :, :, np.newaxis]
# t2 = t2[:, :, :, np.newaxis]
val_imgs[i] = t1
one_hot = make_one_hot_3d(ot, self.n_labels)
val_labels[i] = one_hotself.val_batch_index += 1return val_imgs, val_labelsdef get_np_data_3d(self, data_path):
for i in glob.glob(os.path.join(data_path, 'VSD.Brain.XX.O.MR_T1.*\\VSD.Brain.XX.O.MR_T1.*.mha')):
t1_file_path = i
for i in glob.glob(os.path.join(data_path, 'VSD.Brain_3more.XX.*\\VSD.Brain_3more.XX.*.mha')):
ot_file_path = i'''
for i in glob.glob(os.path.join(data_path,'VSD.Brain.XX.O.MR_Flair.*\\VSD.Brain.XX.O.MR_Flair.*.mha')):
flair_file_path=ifor i in glob.glob(os.path.join(data_path,'VSD.Brain.XX.O.MR_T1c.*\\VSD.Brain.XX.O.MR_T1c.*.mha')):
t1c_file_path=ifor i in glob.glob(os.path.join(data_path,'VSD.Brain.XX.O.MR_T2.*\\VSD.Brain.XX.O.MR_T2.*.mha')):
t2_file_path=iflair=sitk_read(flair_file_path)t1c=sitk_read(t1c_file_path)
t2=sitk_read(t2_file_path)'''
t1 = sitk_read(t1_file_path)
ot = sitk_read(ot_file_path)
return t1, ot
# return flair,t1,t1c,t2,otdef get_np_data_2d(self, data_path):
for i in glob.glob(os.path.join(data_path, 'VSD.Brain.XX.O.MR_T1.*\\VSD.Brain.XX.O.MR_T1.*.mha')):
t1_file_path = i
for i in glob.glob(os.path.join(data_path, 'VSD.Brain_3more.XX.*\\VSD.Brain_3more.XX.*.mha')):
ot_file_path = i'''
for i in glob.glob(os.path.join(data_path,'VSD.Brain.XX.O.MR_Flair.*\\VSD.Brain.XX.O.MR_Flair.*.mha')):
flair_file_path=ifor i in glob.glob(os.path.join(data_path,'VSD.Brain.XX.O.MR_T1c.*\\VSD.Brain.XX.O.MR_T1c.*.mha')):
t1c_file_path=ifor i in glob.glob(os.path.join(data_path,'VSD.Brain.XX.O.MR_T2.*\\VSD.Brain.XX.O.MR_T2.*.mha')):
t2_file_path=iflair=sitk_read(flair_file_path)t1c=sitk_read(t1c_file_path)
t2=sitk_read(t2_file_path)'''
t1 = sitk_read_row(t1_file_path)
ot = sitk_read_row(ot_file_path)
return t1, ot
# return flair,t1,t1c,t2,ot
U-Net3D
import keras.backend as K
from keras.engine import Input, Model
import keras
from keras.optimizers import Adam
from keras.layers import BatchNormalization, Activation, Conv3D, Conv3DTranspose, MaxPooling3D
import metrics as m
from keras.layers.core import Lambda
import numpy as npdef up_and_concate_3d(down_layer, layer):
in_channel = down_layer.get_shape().as_list()[4]
out_channel = in_channel // 2
up = Conv3DTranspose(out_channel, [2, 2, 2], strides=[2, 2, 2], padding='valid')(down_layer)
print("--------------")
print(str(up.get_shape()))print(str(layer.get_shape()))
print("--------------")
my_concat = Lambda(lambda x: K.concatenate([x[0], x[1]], axis=4))concate = my_concat([up, layer])
# must use lambda
# concate=K.concatenate([up, layer], 3)
return concatedef attention_block_3d(x, g, inter_channel):
''':param x: x input from down_sampling same layer output x(?,x_height,x_width,x_depth,x_channel)
:param g: gate input from up_sampling layer last output g(?,g_height,g_width,g_depth,g_channel)
g_height,g_width,g_depth=x_height/2,x_width/2,x_depth/2
:return:
'''
# theta_x(?,g_height,g_width,g_depth,inter_channel)
theta_x = Conv3D(inter_channel, [2, 2, 2], strides=[2, 2, 2])(x)# phi_g(?,g_height,g_width,g_depth,inter_channel)
phi_g = Conv3D(inter_channel, [1, 1, 1], strides=[1, 1, 1])(g)# f(?,g_height,g_width,g_depth,inter_channel)
f = Activation('relu')(keras.layers.add([theta_x, phi_g]))# psi_f(?,g_height,g_width,g_depth,1)
psi_f = Conv3D(1, [1, 1, 1], strides=[1, 1, 1])(f)# sigm_psi_f(?,g_height,g_width,g_depth)
sigm_psi_f = Activation('sigmoid')(psi_f)# rate(?,x_height,x_width,x_depth)
rate = UpSampling3D(size=[2, 2, 2])(sigm_psi_f)# att_x(?,x_height,x_width,x_depth,x_channel)
att_x = keras.layers.multiply([x, rate])return att_xdef unet_model_3d(input_shape, n_labels, batch_normalization=False, initial_learning_rate=0.00001,
metrics=m.dice_coefficient):
"""
input_shape:without batch_size,(img_height,img_width,img_depth)
metrics:
"""inputs = Input(input_shape)down_layer = []layer = inputs# down_layer_1
layer = res_block_v2_3d(layer, 64, batch_normalization=batch_normalization)
down_layer.append(layer)
layer = MaxPooling3D(pool_size=[2, 2, 2], strides=[2, 2, 2],padding='same')(layer)print(str(layer.get_shape()))# down_layer_2
layer = res_block_v2_3d(layer, 128, batch_normalization=batch_normalization)
down_layer.append(layer)
layer = MaxPooling3D(pool_size=[2, 2, 2], strides=[2, 2, 2],padding='same')(layer)print(str(layer.get_shape()))# down_layer_3
layer = res_block_v2_3d(layer, 256, batch_normalization=batch_normalization)
down_layer.append(layer)
layer = MaxPooling3D(pool_size=[2, 2, 2], strides=[2, 2, 2],padding='same')(layer)print(str(layer.get_shape()))# down_layer_4
layer = res_block_v2_3d(layer, 512, batch_normalization=batch_normalization)
down_layer.append(layer)
layer = MaxPooling3D(pool_size=[2, 2, 2], strides=[2, 2, 2],padding='same')(layer)print(str(layer.get_shape()))# bottle_layer
layer = res_block_v2_3d(layer, 1024, batch_normalization=batch_normalization)
print(str(layer.get_shape()))# up_layer_4
layer = up_and_concate_3d(layer, down_layer[3])
layer = res_block_v2_3d(layer, 512, batch_normalization=batch_normalization)
print(str(layer.get_shape()))# up_layer_3
layer = up_and_concate_3d(layer, down_layer[2])
layer = res_block_v2_3d(layer, 256, batch_normalization=batch_normalization)
print(str(layer.get_shape()))# up_layer_2
layer = up_and_concate_3d(layer, down_layer[1])
layer = res_block_v2_3d(layer, 128, batch_normalization=batch_normalization)
print(str(layer.get_shape()))# up_layer_1
layer = up_and_concate_3d(layer, down_layer[0])
layer = res_block_v2_3d(layer, 64, batch_normalization=batch_normalization)
print(str(layer.get_shape()))# score_layer
layer = Conv3D(n_labels, [1, 1, 1], strides=[1, 1, 1])(layer)
print(str(layer.get_shape()))# softmax
layer = Activation('softmax')(layer)
print(str(layer.get_shape()))outputs = layermodel = Model(inputs=inputs, outputs=outputs)metrics = [metrics]model.compile(optimizer=Adam(lr=initial_learning_rate), loss=m.dice_coefficient_loss, metrics=metrics)return modeldef res_block_v2_3d(input_layer, out_n_filters, batch_normalization=False, kernel_size=[3, 3, 3], stride=[1, 1, 1],
padding='same'):
input_n_filters = input_layer.get_shape().as_list()[3]
print(str(input_layer.get_shape()))
layer = input_layerfor i in range(2):
if batch_normalization:
layer = BatchNormalization()(layer)
layer = Activation('relu')(layer)
layer = Conv3D(out_n_filters, kernel_size, strides=stride, padding=padding)(layer)if out_n_filters != input_n_filters:
skip_layer = Conv3D(out_n_filters, [1, 1, 1], strides=stride, padding=padding)(input_layer)
else:
skip_layer = input_layerout_layer = keras.layers.add([layer, skip_layer])return out_layer
和之前那篇使用u-net2d进行voc分割的网络结构没有什么区别,只是将卷积、pooling、concate操作都改成了3维操作
在跑的过程中发现了一些bug,最新代码可在git上找到,以最近代码为准:
【[深度学习从入门到女装]keras实战-Unet3d(BRAST2015)】https://github.com/panxiaobai/brats_keras
推荐阅读
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- paddle|动手从头实现LSTM
- pytorch|使用pytorch从头实现多层LSTM
- 推荐系统论文进阶|CTR预估 论文精读(十一)--Deep Interest Evolution Network(DIEN)
- pytorch|YOLOX 阅读笔记
- 前沿论文|论文精读(Neural Architecture Search without Training)
- 联邦学习|【阅读笔记】Towards Efficient and Privacy-preserving Federated Deep Learning
- OpenCV|OpenCV-Python实战(18)——深度学习简介与入门示例
- 深度学习|深度学习笔记总结
- 《繁凡的深度学习笔记》|一文绝对让你完全弄懂信息熵、相对熵、交叉熵的意义《繁凡的深度学习笔记》第 3 章 分类问题与信息论基础(中)(DL笔记整理