【问题标题】:Correct way to create ImageDataGenerator from array with binary labels?从带有二进制标签的数组创建 ImageDataGenerator 的正确方法?
【发布时间】:2021-09-21 12:04:42
【问题描述】:

我正在尝试基于自创数据集训练我的第一个 Tensorflow 模型。该模型旨在识别照片中人物的性别,我准备了 9231 张带有性别标签的人物照片。 (我为此使用二元性别,enby 和genderfluid 图片很难获得。)

首先,图片被加载到numpy数组features,形状为(9231, 216, 172, 3),性别标签被加载到labels,形状为(9231, 2)

# Divide into multiple datasets
training_size = int(len(features) * .8)
validation_size = int(len(features) * .1)
testing_size = int(len(features) * .1)
features_train = np.array(features[:training_size])
labels_train = np.array(labels[:training_size])
features_validation = np.array(features[training_size:training_size+validation_size])
labels_validation = np.array(labels[training_size:training_size+validation_size])
features_testing = np.array(features[training_size+validation_size:])
labels_testing = np.array(labels[training_size+validation_size:])
# Create two image generators, one for training and one for validation
img_gen = ImageDataGenerator(
    rescale=1./255
)
generator_training = img_gen.flow(
    x=features_train,
    y=labels_train,
    batch_size=32,
    shuffle=True
)
generator_validation = img_gen.flow(
    x=features_validation,
    y=labels_validation,
    batch_size=32
)
# Check format of resulting generated data
print(generator_training[0][0].shape)
print(generator_training[0][1].shape)
print(generator_validation[0][0].shape)
print(generator_validation[0][1].shape)
print(generator_training.dtype)
print(generator_validation.dtype)

这打印出我的期望:

(32, 216, 172, 3)
(32, 2)
(32, 216, 172, 3)
(32, 2)
float32
float32

然后我构建模型,复制自狗猫教程:

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(172, 216, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dense(2, activation='softmax')
])
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)
model.fit(
    generator_training,
    epochs=100,
    validation_data=generator_validation,
)

这会导致model.fit() 抛出以下错误:

InvalidArgumentError:  logits and labels must have the same first dimension, got logits shape [32,2] and labels shape [64]

我不知道“logits”是什么,也不知道它们在 ML 过程中发挥作用,所以我真的不知道如何解决这个错误。但从生成的形状来看,标签数组似乎在某些时候被错误地展平了。我的猜测是我错误地创建了生成器,或者之前的标签格式错误。

我有一个关于哪里出了问题的提示:我从使用 flow_from_directory() 复制代码的教程创建生成器,允许附加参数 class_mode 设置为 'binary'。但是因为我使用数组而不是文件目录,所以我使用了flow(),它不允许class_mode。我的直觉说这就是问题的根源。但教程中从未解释过参数及其选项的实际效果。

不幸的是,由于程序其余部分的结构,我无法测试 flow_from_directory()。我也不想在没有生成器的情况下解决这个问题,因为我想稍后尝试图像增强。

【问题讨论】:

    标签: tensorflow machine-learning keras


    【解决方案1】:

    您以不适合 sparse_categorical_crossentropy 损失函数的形式使用标签。后者期望标签的格式为[0,1,2,3...n)。但是,您的 logits 格式为 (32,2)

    一种解决方案是将损失函数更改为categorical_crossentropy,以便[0,1](1 类)和[1,0](2 类)等标签可以正确地输入模型。

    如果您使用了flow_from_directory(),您可以使用参数class_mode = 'sparse',它可以与sparse_categorical_crossentropy 一起使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-25
      • 2015-06-16
      • 2016-02-02
      • 2017-11-08
      • 1970-01-01
      相关资源
      最近更新 更多