title: Get labels from dataset when using tensorflow image_dataset_from_directory
body: <p>I wrote a simple CNN using tensorflow (v2.4) + keras in python (v3.8.3). I am trying to optimize the network, and I want more info on what it is failing to predict. I am trying to add a confusion matrix, and I need to feed tensorflow.math.confusion_matrix() the test labels.</p>
  <p>My problem is that I cannot figure out how to access the labels from the dataset object created by tf.keras.preprocessing.image_dataset_from_directory()</p>
  <p>My images are organized in directories having the label as the name. The documentation says the function returns a tf.data.Dataset object.</p>
  <blockquote>
  <pre><code>If label_mode is None, it yields float32 tensors of shape (batch_size, image_size[0], image_size[1], num_channels), encoding
  </code></pre>
  <p>images (see below for rules regarding num_channels).
  Otherwise, it yields a tuple (images, labels), where images has shape (batch_size, image_size[0], image_size[1], num_channels), and
  labels follows the format described below.</p>
  </blockquote>
  <p>Here is the code:</p>
  <pre><code>import tensorflow as tf
  from tensorflow.keras import layers
  #import matplotlib.pyplot as plt
  import numpy as np
  import random
  
  import PIL
  import PIL.Image
  
  import os
  import pathlib
  
  #load the IMAGES
  dataDirectory = '/p/home/username/tensorflow/newBirds'
  
  dataDirectory = pathlib.Path(dataDirectory)
  imageCount = len(list(dataDirectory.glob('*/*.jpg')))
  print('Image count: {0}\n'.format(imageCount))
  
  #test display an image
  # osprey = list(dataDirectory.glob('OSPREY/*'))
  # ospreyImage = PIL.Image.open(str(osprey[random.randint(1,100)]))
  # ospreyImage.show()
  
  # nFlicker = list(dataDirectory.glob('NORTHERN FLICKER/*'))
  # nFlickerImage = PIL.Image.open(str(nFlicker[random.randint(1,100)]))
  # nFlickerImage.show()
  
  #set parameters
  batchSize = 32
  height=224
  width=224
  
  (trainData, trainLabels) = tf.keras.preprocessing.image_dataset_from_directory(
      dataDirectory,
      labels='inferred',
      label_mode='categorical',
      validation_split=0.2,
      subset='training',
      seed=324893,
      image_size=(height,width),
      batch_size=batchSize)
  
  testData = tf.keras.preprocessing.image_dataset_from_directory(
      dataDirectory,
      labels='inferred',
      label_mode='categorical',
      validation_split=0.2,
      subset='validation',
      seed=324893,
      image_size=(height,width),
      batch_size=batchSize)
  
  #class names and sampling a few images
  classes = trainData.class_names
  testClasses = testData.class_names
  #plt.figure(figsize=(10,10))
  # for images, labels in trainData.take(1):
  #     for i in range(9):
  #         ax = plt.subplot(3, 3, i+1)
  #         plt.imshow(images[i].numpy().astype(&quot;uint8&quot;))
  #         plt.title(classes[labels[i]])
  #         plt.axis(&quot;off&quot;)
  # plt.show()
  
  #buffer to hold the data in memory for faster performance
  autotune = tf.data.experimental.AUTOTUNE
  trainData = trainData.cache().shuffle(1000).prefetch(buffer_size=autotune)
  testData = testData.cache().prefetch(buffer_size=autotune)
  
  #augment the dataset with zoomed and rotated images
  #use convolutional layers to maintain spatial information about the images
  #use max pool layers to reduce
  #flatten and then apply a dense layer to predict classes
  model = tf.keras.Sequential([
      #layers.experimental.preprocessing.RandomFlip('horizontal', input_shape=(height, width, 3)),
      #layers.experimental.preprocessing.RandomRotation(0.1),
      #layers.experimental.preprocessing.RandomZoom(0.1),
      layers.experimental.preprocessing.Rescaling(1./255, input_shape=(height, width, 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.Conv2D(128, 3, padding='same', activation='relu'),
      layers.MaxPooling2D(),
      layers.Conv2D(256, 3, padding='same', activation='relu'),
      layers.MaxPooling2D(),
      # layers.Conv2D(512, 3, padding='same', activation='relu'),
      # layers.MaxPooling2D(),
      #layers.Conv2D(1024, 3, padding='same', activation='relu'),
      #layers.MaxPooling2D(),
      #dropout prevents overtraining by not allowing each node to see each datapoint
      #layers.Dropout(0.5),
      layers.Flatten(),
      layers.Dense(512, activation='relu'),
      layers.Dense(len(classes))
      ])
  
  model.compile(optimizer='adam',
                loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
                metrics=['accuracy'])
  model.summary()
      
  epochs=2
  history = model.fit(
      trainData,
      validation_data=testData,
      epochs=epochs
      )
  
  #create confusion matrix
  predictions = model.predict_classes(testData)
  confusionMatrix = tf.math.confusion_matrix(labels=testClasses, predictions=predictions).numpy()
  </code></pre>
  <p>I have tried using (foo, foo1) = tf.keras.preprocessing.image_dataset_from_directory(dataDirectory, etc), but I get
  (trainData, trainLabels) = tf.keras.preprocessing.image_dataset_from_directory(
  ValueError: too many values to unpack (expected 2)</p>
  <p>And if I try to return as one variable and then split it as so:</p>
  <pre><code>train = tf.keras.preprocessing.image_dataset_from_directory(
      dataDirectory,
      labels='inferred',
      label_mode='categorical',
      validation_split=0.2,
      subset='training',
      seed=324893,
      image_size=(height,width),
      batch_size=batchSize)
  trainData = train[0]
  trainLabels = train[1]
  </code></pre>
  <p>I get TypeError: 'BatchDataset' object is not subscriptable</p>
  <p>I can access the labels via testClasses = testData.class_names, but I get:</p>
  <blockquote>
  <p>2020-11-03 14:15:14.643300: W
  tensorflow/core/framework/op_kernel.cc:1740] OP_REQUIRES failed at
  cast_op.cc:121 : Unimplemented: Cast string to int64 is not supported
  Traceback (most recent call last):   File &quot;birdFake.py&quot;, line 115, in
  
  confusionMatrix = tf.math.confusion_matrix(labels=testClasses, predictions=predictions).numpy()   File
  &quot;/p/home/username/miniconda3/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py&quot;,
  line 201, in wrapper
  return target(*args, **kwargs)   File &quot;/p/home/username/miniconda3/lib/python3.8/site-packages/tensorflow/python/ops/confusion_matrix.py&quot;,
  line 159, in confusion_matrix
  labels = math_ops.cast(labels, dtypes.int64)   File &quot;/p/home/username/miniconda3/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py&quot;,
  line 201, in wrapper
  return target(*args, **kwargs)   File &quot;/p/home/username/miniconda3/lib/python3.8/site-packages/tensorflow/python/ops/math_ops.py&quot;,
  line 966, in cast
  x = gen_math_ops.cast(x, base_type, name=name)   File &quot;/p/home/username/miniconda3/lib/python3.8/site-packages/tensorflow/python/ops/gen_math_ops.py&quot;,
  line 1827, in cast
  _ops.raise_from_not_ok_status(e, name)   File &quot;/p/home/username/miniconda3/lib/python3.8/site-packages/tensorflow/python/framework/ops.py&quot;,
  line 6862, in raise_from_not_ok_status
  six.raise_from(core._status_to_exception(e.code, message), None)   File &quot;&quot;, line 3, in raise_from
  tensorflow.python.framework.errors_impl.UnimplementedError: Cast
  string to int64 is not supported [Op:Cast]</p>
  </blockquote>
  <p>I am open to any method to get those labels into the confusion matrix. Any ideas as to why what I am doing is not working would also be appreciated.</p>
  <p>UPDATE: I tried the method proposed by Alexandre Catalano, and I get the following error</p>
  <blockquote>
  <p>Traceback (most recent call last):   File &quot;./birdFake.py&quot;, line 118,
  in 
  labels = np.concatenate([labels, np.argmax(y.numpy(), axis=-1)])   File &quot;&lt;<strong>array_function</strong> internals&gt;&quot;, line 5, in concatenate
  ValueError: all the input arrays must have same number of dimensions,
  but the array at index 0 has 1 dimension(s) and the array at index 1
  has 0 dimension(s)</p>
  </blockquote>
  <p>I printed the first element of the labels array, and it is zero</p>