tf.data.Dataset iterator returning Tensor("IteratorGetNext:1", shape=(None, 16), dtype=int32) but cannot get the values of the Tensors

Viewed 4611

I am trying to write a Custom Model in which I am writing a custom train_step function

I am creating a 'tf.data.Dataset` from a Custom Datagenerator like

tds = tf.data.Dataset.from_generator(tdg.__iter__,args=None,output_types = (tf.float32,tf.int32),output_shapes = (tf.TensorShape([16,64,64,3]),tf.TensorShape([16])))
tds = tds.batch(1)

In the custom DataGenerator the __iter__ method is defined as

def __iter__(self):
    for item in (self[i] for i in range(len(self))):
        yield item

However, when I am trying to retrive the data inside the train_step function, with x,y = data I am getting

Tensor("IteratorGetNext:0", shape=(None, 16, 64, 64, 3), dtype=float32)

and

Tensor("IteratorGetNext:1", shape=(None, 16), dtype=int32) as output

If I run print(x[0]) then I am getting

Tensor("strided_slice:0", shape=(16,), dtype=int32)

I am not getting the Tensors with numpy() attribute

Where is this going wrong??

2 Answers

this works for tf.data

for data_batch, label in tfds:
    print(image_batch.numpy().shape)
    for data in data_batch:
         print(image.numpy().shape)

you can test something like this - some corrections in shapes are probably needed in your structure - I do not know your code), or make your corrections according your task:

# https://stackoverflow.com/questions/63660618/tf-data-dataset-iterator-returning-tensoriteratorgetnext1-shape-none-16/72104494#72104494
# my test
import tensorflow as tf
import tensorflow.keras
import numpy as np
from tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten, Dense, Dropout, Input
import pandas as pd

class my_DataGenerator(tf.keras.utils.Sequence):
  # https://github.com/mahmoudyusof/facial_keypoint_detection/blob/master/1.1%20Getting%20the%20data%20ready%20(the%20right%20way).ipynb
    def __init__(self, train_len=64, batch_size=16, shuffle=False):   # , csv_file='data.csv'
      #self.indecies = 0
      self.is_epoch_0=False
      self.train_len= train_len   # output_size
      self.batch_size= batch_size
      self.shuffle = shuffle
      #self.keypts_frame = pd.read_csv(csv_file)
      self.on_epoch_end()

    def on_epoch_end(self):
        #""" This function gets called after each epoch"""        
        # all possible indecies in the dataframe
        #self.indecies = np.arange(len(self.keypts_frame))
    #    self.indecies = np.arange(self.train_len)
    #    if self.shuffle:
    #        np.random.shuffle(self.indecies)

        print('on_epoch_end')
        self.is_epoch_0=False

    def __len__(self):
        """ The generator returns one batch at a time so it makes sence that it would have
        a length equal to the number of samples divided by the batch size
        giving the total number of batches
        """
        #self.data_frame = shuffle(self.data_frame)
        return math.ceil(self.train_len/self.batch_size)
        # return int(len(self.keypts_frame) / self.batch_size)

    def __getitem__(self,idx):    # will  return the tuple (X,y)
        """ This is where the magic hapenes, the model will call this function using the
        indexing operator 'generator[0]' or whatever.
        then and only then will the generator load the batch into memory and the garbage collector
        will remove it on the next iteration        
        """
        _feature = np.empty((self.batch_size, *self.train_len, 1))
        _label = np.empty((self.batch_size, 16, 1))
        # get the indecies of the current batch only
        indecies = self.indecies[idx*self.batch_size:(idx+1)*self.batch_size]

        _feature, _label = self[indecies]    # __call__ STUFF COULD BE HERE
        return _feature, _label

    #to error avoid: `generator` must be a Python callable.
    def __call__(self):
      # Make sure that your dataset or generator can generate at least `steps_per_epoch * epochs` batches (in this case, 20.0 batches).
        for t in range(0,20,1):
            labels= np.random.randint(0,5,16)
            labels= np.array(labels)
            labels= labels[:, np.newaxis]
            labels= np.c_[ labels, np.ones(16) ]
            print(labels)
            #
            yield np.random.sample(size =(16,64,64,3)), \
               labels

tdg=  my_DataGenerator(128,32)

NUM_CLASSES= 5      #tf.unique(tdg.classes)

training_set = tf.data.Dataset.from_generator(tdg,
                                     (tf.float32, tf.int32),
                                     (tf.TensorShape([None,64,64,3]),tf.TensorShape([None,2]))
                                     )

print('tdg train_len:',tdg.train_len)
print('tdg batch_size:',tdg.batch_size)

testing_set  = tf.data.Dataset.from_generator(tdg,
                                     (tf.float32, tf.int32),
                                     (tf.TensorShape([None,64,64,3]),tf.TensorShape([None,2]))
                                     )
# model https://stackoverflow.com/a/71914845/15893581
inputs = Input(shape=(64,64,3))
x = Conv2D(32, (4, 3), activation='relu', padding='valid')(inputs)
x = MaxPool2D(pool_size=(2, 2))(x)
x = Conv2D(64, (3, 3), activation='relu')(x)
x = MaxPool2D(pool_size=(2, 2))(x)
x = Conv2D(128, (3, 3), activation='relu')(x)
x = MaxPool2D(pool_size=(2, 2))(x)
x = Flatten()(x)
x = Dense(512, activation='relu')(x)
x = Dropout(0.5)(x)
outputs = Dense(2, activation='softmax')(x)

keras_model =  tf.keras.Model(inputs, outputs)

#Compile the model
keras_model.compile('adam', 'categorical_crossentropy', metrics=['acc'])

#Train with tf.data datasets
keras_training_history = keras_model.fit(
                            training_set,
                            steps_per_epoch= (128/32),   #training_set.train_len/training_set.batch_size,
                            epochs=5,
                            validation_data=testing_set,
                            validation_steps= (128/32),   #testing_set.train_len/training_set.batch_size,
                            verbose=1)
# ?! steps_per_epoch= (64/ 16)   #training_set.train_len/training_set.batch_size,
print(keras_training_history.history)
# Reduced WARNING!
# was WARNING:tensorflow:Your input ran out of data; interrupting training. Make sure that your dataset or generator can generate at least `steps_per_epoch * epochs` batches (in this case, 20.0 batches). You may need to use the repeat() function when building your dataset.

though strange results seems to me (increasing accuracy on increasing loss - is it normal??):

{'loss': [5.840527057647705, 47.09394836425781, 213.2418212890625, 738.29443359375, 2104.241455078125], 'acc': [0.6875, 0.828125, 0.84375, 0.84375, 0.859375], 'val_loss': [19.316448211669922, 122.56965637207031, 452.21417236328125, 1395.7388916015625, 3683.197021484375], 'val_acc': [0.703125, 0.78125, 0.859375, 0.78125, 0.90625]}

HERE can see short example... mainly in class dataGenerator only init & getitem & len methods are important... other methods ( iter, on_epoch_end) need testing in your own minimal reproducible example... may add on_epoch_end check

P.S.

Or you could just refactor your class to simple gen_function instead of class - e.g. - but I doubt that it could behave ok in training (though here gen-function seems working)

Related