I'm trying to train my first Tensorflow model based on a self-created dataset. The model is meant to recognize the gender of a person in photos, and I have 9231 gender-labeled photos of people prepared. (I use binary genders for this, enby and genderfluid pictures are hard to come by.)
To begin, the pictures are loaded into numpy array features with shape (9231, 216, 172, 3), and the gender-labels are loaded into labels with shape (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)
This prints what I expect:
(32, 216, 172, 3)
(32, 2)
(32, 216, 172, 3)
(32, 2)
float32
float32
Then I build the model, copied from a dog-cat tutorial:
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,
)
This results in model.fit() throwing the following error:
InvalidArgumentError: logits and labels must have the same first dimension, got logits shape [32,2] and labels shape [64]
I don't know what "logits" are or what part in the ML process they come into play, so I don't really know how to troubleshoot this error. But from the resulting shapes, it seems like the label array were incorrectly flattened at some point. My guess is that I created the generators incorrectly, or misformatted the labels before that.
I have a hint about what's wrong though: The tutorial I copied code from used flow_from_directory() to create the generators, with allowed for the additional argument class_mode which was set to 'binary'. But since I use arrays instead of file directories, I instead used flow() which doesn't allow for class_mode. My gut feeling says this is where the problem stems from. But the actual effect of the argument and its options was never explained in the tutorial.
Unfortunately I cannot test flow_from_directory() instead, due to the structure of the rest of the program. I don’t really want to approach this without generator either, since I wanna try image augmentation later.