Python 如何从目录中为tensorflow.keras.preprocessing.text\u dataset\u使用多个输入
所以我正在训练一个CNN,它接收输入的两幅图像,并在GPU上返回一个值作为输出。由于我有很多图像,为了将数据分批输入,我正在使用来自目录的tf.keras.preprocessing.text\u dataset\u创建一个tf.dataset对象,该对象针对GPU进行了优化 所以基本上我的输入目录是Python 如何从目录中为tensorflow.keras.preprocessing.text\u dataset\u使用多个输入,python,tensorflow,keras,conv-neural-network,data-processing,Python,Tensorflow,Keras,Conv Neural Network,Data Processing,所以我正在训练一个CNN,它接收输入的两幅图像,并在GPU上返回一个值作为输出。由于我有很多图像,为了将数据分批输入,我正在使用来自目录的tf.keras.preprocessing.text\u dataset\u创建一个tf.dataset对象,该对象针对GPU进行了优化 所以基本上我的输入目录是 Class_1/ Class1_1/ image1.png image2.png Class1_2/ image3.png image4.png .
Class_1/
Class1_1/
image1.png
image2.png
Class1_2/
image3.png
image4.png
...
Class_2/
Class2_1/
image1.png
image2.png
Class2_2/
image3.png
image4.png
默认函数仅适用于以下结构
Class_1/
image1.png
image2.png
image3.png
image4.png
...
Class_2/
image1.png
image2.png
image3.png
image4.png
任何帮助都将不胜感激。我猜您指的是来自目录的
图像数据集,因为您正在加载图像而不是文本数据。无论哪种方式,您都无法使用这些辅助函数的多个输入生成批次,您可以看到返回形状已定义:
一个tf.data.Dataset对象
- 如果label_mode为None,则会产生32个形状张量(批处理大小、图像大小[0]、图像大小[1]、数量通道),对图像进行编码(有关数量通道的规则,请参见下文)
- 否则,它将生成一个元组(图像、标签),其中图像具有形状(批处理大小、图像大小[0]、图像大小[1]、数量通道),标签遵循下面描述的格式
相反,您需要编写自己的自定义生成器函数,生成从数据目录加载的多个输入,然后使用自定义生成器调用fit
,并将kwargvalidation\u data
传递给生成验证数据的单独生成器。(注意:在一些旧版本的Keras中,您可能需要fit_generator
而不是fit
)
下面是一些助手函数模块的示例,这些函数可以从一些目录中读取图像,并在培训中将其作为多图像输入显示
def _generate_batch(training):
in1s, in2s, labels = [], [], []
batch_tuples = _sample_batch_of_paths(training)
for input1_path, input2_path in batch_tuples:
# skip any exception so that image GPU batch loading isn't
# disrupted and any faulty image is just skipped.
try:
in1_tmp = _load_image(
os.path.join(INPUT1_PATH_PREFIX, input1_path),
)
in2_tmp = _load_image(
os.path.join(INPUT2_PATH_PREFIX, input2_path),
)
except Exception as exc:
print("Unhandled exception during image batch load. Skipping...")
print(str(exc))
continue
# if no exception, both images loaded so both are added to batch.
in1s.append(in1_tmp)
in2s.append(in2_tmp)
# Whatever your custom logic is to determine the label for the pair.
labels.append(
_label_calculation_helper(input1_path, input2_path)
)
in1s, in2s = map(skimage.io.concatenate_images, [in1s, in2s])
# could also add a singleton channel dimension for grayscale images.
# in1s = in1s[:, :, :, None]
return [in1s, in2s], labels
def _make_generator(training=True):
while True:
yield _generate_batch(training)
def make_generators():
return _make_generator(training=True), _make_generator(training=False)
助手\u load\u image
可以是这样的:
def _load_image(path, is_gray=False):
tmp = skimage.io.imread(path)
if is_gray:
tmp = skimage.util.img_as_float(skimage.color.rgb2gray(tmp))
else:
tmp = skimage.util.img_as_float(skimage.color.gray2rgb(tmp))
if tmp.shape[-1] == 4:
tmp = skimage.color.rgba2rgb(tmp)
# Do other stuff here - resizing, clipping, etc.
return tmp
@lru_cache(1)
def _load_and_split_input_paths():
training_in1s, testing_in1s = train_test_split(
os.listdir(INPUT1_PATH_PREFIX),
test_size=TEST_SIZE,
random_state=RANDOM_SEED
)
training_in2s, testing_in2s = train_test_split(
os.listdir(INPUT2_PATH_PREFIX),
test_size=TEST_SIZE,
random_state=RANDOM_SEED
)
return training_in1s, testing_in1s, training_in2s, testing_in2s
def _sample_batch_of_paths(training):
training_in1s, testing_in1s, training_in2s, testing_in2s = _load_and_split_input_paths()
if training:
return list(zip(
random.sample(training_in1s, BATCH_SIZE),
random.sample(training_in2s, BATCH_SIZE)
))
else:
return list(zip(
random.sample(testing_in1s, BATCH_SIZE),
random.sample(testing_in2s, BATCH_SIZE)
))
从磁盘上列出的一组路径中采样批次的助手函数可以如下所示:
def _load_image(path, is_gray=False):
tmp = skimage.io.imread(path)
if is_gray:
tmp = skimage.util.img_as_float(skimage.color.rgb2gray(tmp))
else:
tmp = skimage.util.img_as_float(skimage.color.gray2rgb(tmp))
if tmp.shape[-1] == 4:
tmp = skimage.color.rgba2rgb(tmp)
# Do other stuff here - resizing, clipping, etc.
return tmp
@lru_cache(1)
def _load_and_split_input_paths():
training_in1s, testing_in1s = train_test_split(
os.listdir(INPUT1_PATH_PREFIX),
test_size=TEST_SIZE,
random_state=RANDOM_SEED
)
training_in2s, testing_in2s = train_test_split(
os.listdir(INPUT2_PATH_PREFIX),
test_size=TEST_SIZE,
random_state=RANDOM_SEED
)
return training_in1s, testing_in1s, training_in2s, testing_in2s
def _sample_batch_of_paths(training):
training_in1s, testing_in1s, training_in2s, testing_in2s = _load_and_split_input_paths()
if training:
return list(zip(
random.sample(training_in1s, BATCH_SIZE),
random.sample(training_in2s, BATCH_SIZE)
))
else:
return list(zip(
random.sample(testing_in1s, BATCH_SIZE),
random.sample(testing_in2s, BATCH_SIZE)
))
这将从一些“input 1”目录中随机采样图像,并将它们与“input 2”目录中的随机样本配对。显然,在您的用例中,您需要改变这一点,以便根据定义数据对和标签的文件结构确定地提取数据
最后,一旦您想使用此功能,您可以调用培训代码,例如:
training_generator, testing_generator = make_generators()
try:
some_compiled_model.fit(
training_generator,
epochs=EPOCHS,
validation_data=testing_generator,
callbacks=[...],
verbose=VERBOSE,
steps_per_epoch=STEPS_PER_EPOCH,
validation_steps=VALIDATION_STEPS,
)
except KeyboardInterrupt:
pass
fit\u generator
是否已弃用?对不起,是的,现在fit
可以使用发电机。我将更新我最关心的远离发电机的问题是它们的性能。在理想情况下,我希望在GPU处理前一批时使用CPU处理下一批。在python生成器的情况下,上述方法是否可行?这就是keras让您处理批生成器的方式,它可以在gpu工作时预取一个批队列(这与生成器和其他加载方法无关)。生成器的主要优点之一是性能和减少内存开销。它通常优于tf数据集,因为您可以对加载和预处理逻辑进行更多的控制,但在加载时间或内存开销方面不会付出更大的代价。