Python 如何从目录中为tensorflow.keras.preprocessing.text\u dataset\u使用多个输入

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 .

所以我正在训练一个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_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
,并将kwarg
validation\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数据集,因为您可以对加载和预处理逻辑进行更多的控制,但在加载时间或内存开销方面不会付出更大的代价。