废话不多说直接上代码(修改过的classification的code)
import tensorflow
class DataGenerator(tensorflow.keras.utils.Sequence):
'Generates data for Keras'
def __init__(self, list_IDs, batch_size=32, dim=(224,224), n_channels=3,
n_classes=2, shuffle=True):
'Initialization'
self.dim = dim
self.batch_size = batch_size
self.list_IDs = list_IDs
self.n_channels = n_channels
self.n_classes = n_classes
self.shuffle = shuffle
self.on_epoch_end()
def __len__(self):
'Denotes the number of batches per epoch'
return int(np.floor(len(self.list_IDs) / self.batch_size))
def __getitem__(self, index):
'Generate one batch of data'
# Generate indexes of the batch
indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]
# Find list of IDs
list_IDs_temp = [self.list_IDs[k] for k in indexes]
# Generate data
X, y = self.__data_generation(list_IDs_temp)
return X, y
def on_epoch_end(self):
'Updates indexes after each epoch'
self.indexes = np.arange(len(self.list_IDs))
if self.shuffle == True:
np.random.shuffle(self.indexes)
def __data_generation(self, list_IDs_temp):
'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
# Initialization
X = np.empty(shape=(self.batch_size, *self.dim, self.n_channels))
y = np.empty(shape=(self.batch_size, *self.dim))
# Generate data
for i, ID in enumerate(list_IDs_temp):
# Store sample
img1 = np.load(ID)[:,:,:]
seg1 = np.load(mask[i])[:,:]
# Add data augmentation here
image = augmentation(img=img1, seg=seg1)
X[i] = image["image"]
y[i] = image["mask"]
X[i] = add_noise(X[i])
# Store class
return X, y
前三段类似Dataset类,提供构造器,长度和样本生成。on epoch end为1个epoch结束后,对已有的indexes进行洗牌,随机获取新的若干个一个batch_size的数据作为一个epoch。data_generation优先运行,将img里的路径读取为numpy,并且随机裁剪为224*224大小,概率添加噪声或翻转后储存为X与y,丢给模型进行训练。(数据增广)。X为3通道RGB图片img,y为单通道mask。
Generator会返回包含img:(32, 224, 224, 3) 和mask:(32, 224, 224)两个numpy数组的一个元组(tuple)。
相比于classification,在segmentation中y的值应该是ID(也就是img)对应的mask,而不是标签0或1。同时需要注意img为三通道,维度应该加一个3(channel),seg只有一个通道所以不需要加。由于所有图片都经过随机裁剪240 → 224,所以generator里生成的数组也要适应大小。