-1

I am trying to build my first classifier on tensorflow 1.10 using tf.data.dataset as an input to a Keras.sequential but the fit method returns the following error:

ValueError: Error when checking target: expected dense_1 to have 2 dimensions, but got array with shape (None,)

First I initialized 2 tf.data.Dataset with the filenames of my dataset

 #Initialize dataset directories location and parameters
image_size=50
batch_size=10
mortys_file_pattern = r'C:\Users\Jonas\Downloads\mortys\*'
ricks_file_pattern = r'C:\Users\Jonas\Downloads\ricks\*'

#Each tensor in those dataset will be a filename for a specific image
mortys_dataset = tf.data.Dataset.list_files(mortys_file_pattern)
ricks_dataset = tf.data.Dataset.list_files(ricks_file_pattern)

Then I used the map method to prepare my datasets

#Now, each dataset entry will contain 2 tensors: image,label
mortys_dataset.map(lambda filename: load_resize_label(filename, "morty"))
ricks_dataset.map(lambda filename: load_resize_label(filename, "rick"))


def load_resize_label(filename, label):
    image_string = tf.read_file(filename)
    image_decoded = tf.image.decode_jpeg(image_string)
    image_resized = tf.image.resize_images(image_decoded, [image_size, image_size])
    image_resized=image_resized/255.0
    return image_resized, tf.convert_to_tensor(label)

Then, I concatenate the datasets into one final dataset and initialize the batch size

#Merge the datasets


dataset = mortys_dataset.concatenate(ricks_dataset)
dataset = dataset.batch(batch_size)
dataset = dataset.repeat()

In the end, use the compile and fit method of the model object

model.compile(loss='binary_crossentropy',
             optimizer='adam',
             metrics=['accuracy'])

model.fit(dataset, epochs=10, steps_per_epoch=30)

(Full code bellow)

I'm using:

Windows 10 64bits

cudnn-9.0-windows10-x64-v7.2.1.38

cuda_9.0.176_win10

tensorflow-gpu 1.10.0

  import tensorflow as tf
from tensorflow import keras
image_size=50
batch_size=10
# Reads an image from a file, decodes it into a dense tensor, resizes it
# to a fixed shape.
def load_resize_label(filename, label):
    image_string = tf.read_file(filename)
    image_decoded = tf.image.decode_jpeg(image_string)
    image_resized = tf.image.resize_images(image_decoded, [image_size, image_size])
    image_resized=image_resized/255.0
    return image_resized, tf.convert_to_tensor(label)

#Initialize dataset directories location
mortys_file_pattern = r'C:\Users\Jonas\Downloads\mortys\*'
ricks_file_pattern = r'C:\Users\Jonas\Downloads\ricks\*'

#Each tensor in those dataset will be a filename for a specific image
mortys_dataset = tf.data.Dataset.list_files(mortys_file_pattern)
ricks_dataset = tf.data.Dataset.list_files(ricks_file_pattern)

#Now, each dataset entry will contain 2 tensors: image,label
mortys_dataset = mortys_dataset.map(lambda filename: load_resize_label(filename, "morty"))
ricks_dataset = ricks_dataset.map(lambda filename: load_resize_label(filename, "rick"))

#Merge the datasets
dataset = mortys_dataset.concatenate(ricks_dataset)
dataset = dataset.batch(batch_size)
dataset = dataset.repeat()

#the CNN architecture
model = keras.Sequential([
    keras.layers.Convolution2D(filters=64, kernel_size=2, padding='same', activation='relu', input_shape=(image_size, image_size,3)),
    keras.layers.MaxPool2D(pool_size=2),
    keras.layers.BatchNormalization(),
    keras.layers.Flatten(),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dropout(0.3),
    keras.layers.Dense(2, activation=tf.nn.softmax)
])


model.compile(loss='binary_crossentropy',
             optimizer='adam',
             metrics=['accuracy'])

model.fit(dataset, epochs=10, steps_per_epoch=30)

Traceback:

    Traceback (most recent call last):
  File "C:/Users/Jonas/PycharmProjects/learning/lesson2.py", line 47, in <module>
    model.fit(dataset, epochs=10, steps_per_epoch=30)
  File "C:\Users\Jonas\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1278, in fit
    validation_split=validation_split)
  File "C:\Users\Jonas\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\keras\engine\training.py", line 917, in _standardize_user_data
    exception_prefix='target')
  File "C:\Users\Jonas\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\keras\engine\training_utils.py", line 182, in standardize_input_data
    'with shape ' + str(data_shape))
ValueError: Error when checking target: expected dense_1 to have 2 dimensions, but got array with shape (None,)
  • According to the keras guide for tensorflow, the input of model.fit can be tf.data datasets: https://www.tensorflow.org/guide/keras – Jonas Brami Sep 11 '18 at 11:58
  • I have 2 datasets (One containing pictures of Ricks, and one containing pictures of Mortys). I'm trying to make a classifier to recognize if a picture is a Rick or a Morty. The labels were added using the map method of the dataset object when map_func is lambda filename: load_resize_label(filename, "morty") – Jonas Brami Sep 11 '18 at 12:33
  • Yes. It's strange to not tackle this task as a binary cross entropy so I was confused. – Olivier Dehaene Sep 11 '18 at 12:37
  • This seems to be related to the issue discussed in this [thread](https://stackoverflow.com/questions/52218500/using-tf-data-dataset-as-training-input-to-keras-model-not-working/52222670#52222670) and [this](https://stackoverflow.com/questions/46135499/how-to-properly-combine-tensorflows-dataset-api-and-keras). The code pattern you could try is [this](https://gist.github.com/datlife/abfe263803691a8864b7a2d4f87c4ab8). Ultimately it seems to have been fixed by installing the nightly build. – Mohan Radhakrishnan Sep 11 '18 at 13:24

1 Answers1

-1

You're missing some '=' in your code.

Each dataset operation should be like :

dataset = dataset.some_ops(...)

Here is how your code should look:

import tensorflow as tf
from tensorflow import keras
image_size=50
batch_size=10
# Reads an image from a file, decodes it into a dense tensor, resizes it
# to a fixed shape.
def load_resize_label(filename, label):
    image_string = tf.read_file(filename)
    image_decoded = tf.image.decode_jpeg(image_string)
    image_resized = tf.image.resize_images(image_decoded, [image_size, image_size])
    image_resized=image_resized/255.0
    if label == 'morty':
         label = [0, 1]
    elif label == 'rick':
         label = [1, 0]
    else:
         raise ValueError(label)
    return image_resized, tf.convert_to_tensor(label)

#Initialize dataset directories location
mortys_file_pattern = r'C:\Users\Jonas\Downloads\mortys\*'
ricks_file_pattern = r'C:\Users\Jonas\Downloads\ricks\*'

#Each tensor in those dataset will be a filename for a specific image
mortys_dataset = tf.data.Dataset.list_files(mortys_file_pattern)
ricks_dataset = tf.data.Dataset.list_files(ricks_file_pattern)

#Now, each dataset entry will contain 2 tensors: image,label
mortys_dataset = mortys_dataset.map(lambda filename: load_resize_label(filename, "morty"))
ricks_dataset = ricks_dataset.map(lambda filename: load_resize_label(filename, "rick"))

#Merge the datasets
dataset = mortys_dataset.concatenate(ricks_dataset)
dataset = dataset.batch(batch_size)
dataset = dataset.repeat()

#the CNN architecture
model = keras.Sequential([
    keras.layers.Convolution2D(filters=64, kernel_size=2, padding='same', activation='relu', input_shape=(image_size, image_size, 3)),
    keras.layers.MaxPool2D(pool_size=2),
    keras.layers.BatchNormalization(),
    keras.layers.Flatten(),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dropout(0.3),
    keras.layers.Dense(2, activation=tf.nn.softmax)
])


model.compile(loss='categorical_crossentropy',
             optimizer='adam',
             metrics=['accuracy'])

model.fit(dataset, epochs=10, steps_per_epoch=30)

Also, I advise you to use dataset.prefetch(None) and use the num_parallel_calls argument in the map function. Here is why. TLDR: it's faster.

Olivier Dehaene
  • 1,620
  • 11
  • 15
  • Thank you! I've made the changes and now I'm not having the ValueError: Please provide data as a list or tuple of 2 elements - input and target pair. Received Tensor("IteratorGetNext:0", shape=(), dtype=string) But another ValueError has been raised ValueError: Error when checking target: expected dense_1 to have 4 dimensions, but got array with shape (None,). – Jonas Brami Sep 11 '18 at 13:11
  • You are missing a 'flatten' layer before the dense one. I updated my code accordingly. – Olivier Dehaene Sep 11 '18 at 13:16
  • Thanks! I just tested it, but it still doesn't work. A similar ValueError has been raised: ValueError: Error when checking target: expected dense_1 to have 2 dimensions, but got array with shape (None,) – Jonas Brami Sep 11 '18 at 13:21
  • Doing this raises : ValueError: Error when checking input: expected conv2d_input to have shape (3, 50, 50) but got array with shape (50, 50, None). So I think the original shape was right. I'm editing my first question with your changes and the new ValueError (input_shape=(image_size, image_size,3)) – Jonas Brami Sep 11 '18 at 13:32
  • Doing so result it line 1013, in resize_images raise ValueError('\'size\' must be a 1-D Tensor of 2 elements: ' ValueError: 'size' must be a 1-D Tensor of 2 elements: new_height, new_width . So it seems the shape argument in resize has to be [image_size, image_size] – Jonas Brami Sep 11 '18 at 13:51
  • Updated my answer. It was coming from the label. – Olivier Dehaene Sep 11 '18 at 14:02