AttributeError: 'Tensor' object has no attribute 'numpy' in Tensorflow 2.1

Question:

I am trying to convert the shape property of a Tensor in Tensorflow 2.1 and I get this error:

AttributeError: 'Tensor' object has no attribute 'numpy'

I already checked that the output of tf.executing eagerly() is True,

A bit of context: I load a tf.data.Dataset from a TFRecords, then I apply a map. The maping function is trying to convert the shape property of one of the dataset sample Tensor to numpy:

def _parse_and_decode(serialized_example):
    """ parse and decode each image """
    features = tf.io.parse_single_example(
        serialized_example,
        features={
            'encoded_image': tf.io.FixedLenFeature([], tf.string),
            'kp_flat': tf.io.VarLenFeature(tf.int64),
            'kp_shape': tf.io.FixedLenFeature([3], tf.int64),
        }
    )
    image = tf.io.decode_png(features['encoded_image'], dtype=tf.uint8)
    image = tf.cast(image, tf.float32)

    kp_shape = features['kp_shape']

    kp_flat = tf.sparse.to_dense(features['kp_flat'])
    kp = tf.reshape(kp_flat, kp_shape)

    return image, kp


def read_tfrecords(records_dir, batch_size=1):
    # Read dataset from tfrecords
    tfrecords_files = glob.glob(os.path.join(records_dir, '*'))
    dataset = tf.data.TFRecordDataset(tfrecords_files)
    dataset = dataset.map(_parse_and_decode, num_parallel_calls=batch_size)
    return dataset


def transform(img, labels):
    img_shape = img.shape  # type: <class 'tensorflow.python.framework.ops.Tensor'>`
    img_shape = img_shape.numpy()  # <-- Throws the error
    # ...    

dataset = read_tfrecords(records_dir)

This throws the error:

dataset.map(transform, num_parallel_calls=1)

While this perfecly works:

for img, labels in dataset.take(1):
    print(img.shape.numpy())

Edit: trying to access the img.numpy() instead of img.shape.numpy() results in the same behavior in the tranformer and the codde just above.

I checked the type of img_shape and it is <class 'tensorflow.python.framework.ops.Tensor'>.

Has anyone solved this sort of issue in new versions of Tensorflow?

Asked By: Nick Skywalker

||

Answers:

The problem in your code is that you cannot use .numpy() inside functions that are mapped onto tf.data.Datasets, because .numpy() is Python code not pure TensorFlow code.

When you use a function like my_dataset.map(my_function), you can only use tf.* functions inside your my_function function.

This is not a bug of TensorFlow 2.x versions, but rather on how static graphs are generated behind the scenes for performance purposes.

If you want to use custom Python code inside a function which you map on your dataset, you have to use tf.py_function(), docs: https://www.tensorflow.org/api_docs/python/tf/py_function. There is really no other way to mix Python code and TensorFlow code when mapping on a dataset.

You can also consult this question for further information; it’s the exact question that I asked a couple of months ago: Is there an alternative to tf.py_function() for custom Python code?

Answered By: Timbus Calin

To expand the answer of Timbus Calin further, here’s an implementation example for your use case using the tf.py_function(). Keeping the transform function you have as it is, you should change the dataset.map like this:

dataset.map(lambda img, labels: tf.py_function(transform, 
                                               inp=[img, labels], 
                                               Tout=[tf.float64, tf.float32]))

Change the output types in Tout accordingly to your data.

Answered By: Aelius