'How do I use tf.keras.preprocessing.image_dataset_from_directory() to create a dataset with a certain shape?

I have a dataset of around 3500 images, divided into 3 folders, that I loaded into Google Collab from my google drive, and I'm trying to make them into an ML algorithm using keras and tensorflow with the following code:

train = tf.keras.preprocessing.image_dataset_from_directory(
  path,
  labels = "inferred",
  label_mode = "categorical",
  color_mode = "rgb",
  batch_size = 32,
  image_size = (140,140),
  seed = 1234,
  subset = "training",
  validation_split = 0.2
  
)

shape = tf.TensorShape([None,140,140,3])
print(shape)


valid = tf.keras.preprocessing.image_dataset_from_directory(
  path,
  labels = "inferred",
  label_mode = "categorical",
  color_mode = "rgb",
  batch_size = 32,
  image_size = (140,140),
  seed = 1234,
  subset = "validation",
  validation_split = 0.2
)

print(train)
print(valid)


print(tf.keras.utils.image_dataset_from_directory(path, labels='inferred'))
from keras.models import Sequential
from keras.layers import Dense
from tensorflow import keras
#from tensorflow.keras import layers

model = Sequential()
model.add(Dense(256, activation = "softmax", input_shape = (140,140,3)))
model.add(Dense(64, activation = "softmax"))
model.add(Dense(32, activation = "softmax"))
#model.add(Dense(3, activation = "softmax"))
model.compile(loss = 'categorical_crossentropy', optimizer = 'adam', metrics = ['accuracy']) 

print(model.summary())
keras.utils.plot_model(model, "my_first_model_with_shape_info.png", show_shapes=True)
#print(tf.keras.utils.plot_model(model))
model.fit(train, validation_data = valid, epochs = 50, batch_size = 32)

However when I run the code I get this error:

ValueError: Shapes (None, 3) and (None, 140, 140, 32) are incompatible

I tried fixing this by adding the (None,140,140,3) shape to the "train" variable but I'm not sure how to do that, so does anyone know how to make the shape of my "train" and "valid" variables compatible with the model I made? Thank you.

For reference this is the train variable:

train = tf.keras.preprocessing.image_dataset_from_directory(
  path,
  labels = "inferred",
  label_mode = "categorical",
  color_mode = "rgb",
  batch_size = 32,
  image_size = (140,140),
  seed = 1234,
  subset = "training",
  validation_split = 0.2
)

when I print "train" out however, I get this

<BatchDataset element_spec=(TensorSpec(shape=(None, 140, 140, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 3), dtype=tf.float32, name=None))>

So can someone also explain what a BatchDataset element is, and how do I edit its shape in the first place? thanks.



Solution 1:[1]

No neurons in the last layer should be same as the number of classes you want to classify (it should be 3 if you are trying to classify 3 types of flowers not 32) . Added a few convolution layers and pooling layers to improve the performance too.

import tensorflow as tf
from tensorflow.keras import layers
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
path = pathlib.Path(data_dir)
train = tf.keras.preprocessing.image_dataset_from_directory(
  path,
  labels = "inferred",
  label_mode = "categorical",
  color_mode = "rgb",
  batch_size = 32,
  image_size = (140,140),
  seed = 1234,
  subset = "training",
  validation_split = 0.2
  
)

shape = tf.TensorShape([None,140,140,3])
print(shape)


valid = tf.keras.preprocessing.image_dataset_from_directory(
  path,
  labels = "inferred",
  label_mode = "categorical",
  color_mode = "rgb",
  batch_size = 32,
  image_size = (140,140),
  seed = 1234,
  subset = "validation",
  validation_split = 0.2
)
classnames = train.class_names
print(classnames)
print(train)
print(valid)
num_classes = len(classnames)

print(tf.keras.utils.image_dataset_from_directory(path, labels='inferred'))
from keras.models import Sequential
from keras.layers import Dense
from tensorflow import keras
#from tensorflow.keras import layers

model = Sequential([
  layers.Rescaling(1./255, input_shape=(140,140, 3)),
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes) // in your case layers.Dense(3)
])
model.compile(loss = tf.keras.losses.CategoricalCrossentropy(),optimizer = 'adam', metrics = ['accuracy']) 

print(model.summary())
keras.utils.plot_model(model, "my_first_model_with_shape_info.png", show_shapes=True)

#print(tf.keras.utils.plot_model(model))
model.fit(train, validation_data = valid, epochs = 50, batch_size = 32)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tensorflow Support