我正在研究语义分割架构。我需要加快训练速度,但不知道该往哪里看。
一般信息
我尝试了不同的数据加载方法,但每次瓶颈似乎都是 CPU 而不是 GPU。我跑
nvidia-smi
和 htop
看利用率。到目前为止我尝试过的:
model.fit_generator(generator=training_generator,use_multiprocessing=True, workers=8)
model.fit(training_dataset.make_one_shot_iterator(),...)
我尝试了两种预取方式:dataset = dataset.prefetch(tf.contrib.data.AUTOTUNE)
dataset = dataset.apply(tf.contrib.data.prefetch_to_device('/gpu:0'))
=> 接下来是这个选项。
发现
我觉得现在,我的处理链是这样的:
磁盘上的数据 -> CPU 在 RAM 中加载数据 -> CPU 进行数据预处理 -> CPU 将数据移动到 GPU -> GPU 进行训练步骤
因此,加快训练速度的唯一方法是预先进行所有预处理并将文件保存到磁盘(数据增强会很大)。然后使用 tf.Records 高效加载文件。
您有其他想法如何提高训练速度吗?
更新
我已经用两个模型测试了我的管道。
简单模型
复杂模型
性能结果
我为 3 个 epoch 训练了 2 个模型,每个模型有 140 个步骤(批量大小 = 3)。
这是结果。
简单模型:126s
复杂模型:154s
简单型号:208s
复杂模型:215s
数据生成器
辅助功能
def load_image(self,path):
image = cv2.cvtColor(cv2.imread(path,-1), cv2.COLOR_BGR2RGB)
return image
主要部分#Collect a batch of images on the CPU step by step (probably the bottlebeck of the whole computation)
for i in range(len(image_filenames_tmp)):
#print(image_filenames_tmp[i])
#print(label_filenames_tmp[i])
input_image = self.load_image(image_filenames_tmp[i])[: self.shape[0], : self.shape[1]]
output_image = self.load_image(label_filenames_tmp[i])[: self.shape[0], : self.shape[1]]
# Prep the data. Make sure the labels are in one-hot format
input_image = np.float32(input_image) / 255.0
output_image = np.float32(self.one_hot_it(label=output_image, label_values=label_values))
input_image_batch.append(np.expand_dims(input_image, axis=0))
output_image_batch.append(np.expand_dims(output_image, axis=0))
input_image_batch = np.squeeze(np.stack(input_image_batch, axis=1))
output_image_batch = np.squeeze(np.stack(output_image_batch, axis=1))
return input_image_batch, output_image_batch
tf.data.dataset辅助功能
def preprocess_fn(train_image_filename, train_label_filename):
'''A transformation function to preprocess raw data
into trainable input. '''
x = tf.image.decode_png(tf.read_file(train_image_filename))
x = tf.image.convert_image_dtype(x,tf.float32,saturate=False,name=None)
x = tf.image.resize_image_with_crop_or_pad(x,512,512)
y = tf.image.decode_png(tf.read_file(train_label_filename))
y = tf.image.resize_image_with_crop_or_pad(y,512,512)
class_names, label_values = get_label_info(csv_path)
semantic_map = []
for colour in label_values:
class_map = tf.reduce_all(tf.equal(y, colour), axis=-1)
semantic_map.append(class_map)
semantic_map = tf.stack(semantic_map, axis=-1)
# NOTE cast to tf.float32 because most neural networks operate in float32.
semantic_map = tf.cast(semantic_map, tf.float32)
return x, semantic_map
主要部分dataset = tf.data.Dataset.from_tensor_slices((train_image_filenames, train_label_filenames))
dataset = dataset.apply(tf.contrib.data.map_and_batch(
preprocess_fn, batch_size,
num_parallel_batches=4, # cpu cores
drop_remainder=True if is_training
dataset = dataset.repeat()
dataset = dataset.prefetch(tf.contrib.data.AUTOTUNE) # automatically picks best buffer_size
最佳答案
我正在处理类似的问题,尝试优化管道是一场艰苦的战斗。
使用 horovod 而不是 keras multi-gpu 给我带来了几乎线性的加速,而 keras multi-gpu 没有:
https://medium.com/omnius/keras-horovod-distributed-deep-learning-on-steroids-94666e16673d
tf.dataset 绝对是要走的路。您可能还想进行 shuffle 操作以获得更好的泛化。
另一件对我来说有很大改善的事情是预先调整图像大小并使用 np.save() 将它们保存为 .npy 文件。它们需要更多的空间来保存,但读取它们的速度要快一个数量级。我使用 tf.py_func() 将我的 numpy 操作转换为张量(由于 python GIL 无法并行化)
Nvidia 最近发布了 DALI。它在 GPU 上进行了增强,这绝对是 future 的发展方向。对于简单的分类任务,它可能已经具备您需要的所有功能。
关于tensorflow - CPU端的性能瓶颈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51260680/