Folders are your labels
keras.utils.image_dataset_from_directory is the standard on-ramp from a disk of image files to a batched, training-ready dataset. The trick is that it reads your folder layout as the label scheme: one subdirectory per class, images inside. Point it at the parent folder and it infers the class names, loads the images, resizes them to a uniform image_size, batches, and shuffles — all from one call. No manual label arrays, no glob loops.
Split once, with a shared seed
The validation_split + subset + seed trio is how you carve train and validation out of the same folder. The catch most people miss: you must call it twice — once with subset="training", once with subset="validation" — using the same seed both times. The seed is what guarantees the two calls partition the data consistently instead of overlapping. Pick label_mode="categorical" for one-hot targets (pairs with categorical_crossentropy) or "int" for integer labels (pairs with sparse_categorical_crossentropy).
Then make it fast
Loading from disk every epoch is slow. Chain .cache() to hold decoded images after the first pass, and .prefetch(tf.data.AUTOTUNE) to prepare the next batch on the CPU while the GPU chews on the current one. Together they often cut epoch time in half or more. Order matters: cache before any random augmentation (so the cache stores raw images and augmentation still varies each epoch), prefetch last.