tensorflow: tf.make_ndarray() throws an AttributeError: 'Tensor' object has no attribute 'tensor_shape'
System information
- Have I written custom code (as opposed to using a stock example script provided in TensorFlow): yes
- OS Platform and Distribution: Linux Ubuntu 16.04
- TensorFlow installed from (source or binary): binary
- TensorFlow version (use command below): 1.12.2
- Python version: 3.5
- CUDA/cuDNN version: V8.0.61
- GPU model and memory: Tesla P100-PCIE, 12193MiB
Describe the current behavior
When calling tf.make_ndarray()
on a tensor (<class 'tensorflow.python.framework.ops.Tensor'>
, dtype uint8
, shape (?, 1000, 1500)
), I get the following error:
File "/home/.../python3.5/site-packages/tensorflow/python/framework/tensor_util.py", line 563, in MakeNdarray shape = [d.size for d in tensor.tensor_shape.dim] AttributeError: 'Tensor' object has no attribute 'tensor_shape'
I call the function inside a function given to tf.Dataset.map()
, which is not executing eagerly. However, the error also occurs when using eager execution (as tested by using a for-loop on the dataset instead of .map()
).
Describe the expected behavior
I expect tf.make_ndarray()
to return a NumPy array as advertised đ
Code to reproduce the issue My dataset: https://we.tl/t-rZYNJ6I9oU
from __future__ import absolute_import, division, print_function
import tensorflow as tf
import numpy as np
import os
import sys
def decode_png_mask(image_buffer):
"""
Takes string of bytes encoding a PNG and produces a tensor image
"""
image = tf.squeeze(tf.image.decode_image(image_buffer, channels=1), axis=2)
image.set_shape([None, None])
image = tf.greater(image, 0)
image = tf.cast(image, dtype=tf.uint8)
return image
def masks_to_onehots(tag_masks, tag_class_indices, num_classes):
def onehotify(pixel_tag_masks):
nonzero_indices = np.flatnonzero(pixel_tag_masks)
tag_mask_sizes_suppressed = [tag_mask_sizes[i] if i in nonzero_indices else 9999999 for i in range(len(tag_mask_sizes))]
smallest_mask_index = np.argmin(tag_mask_sizes_suppressed)
class_index = tag_class_indices[smallest_mask_index]
onehot = eye[class_index]
return onehot
eye = np.eye(num_classes)
tag_masks = tf.make_ndarray(tag_masks) #tag_masks = tag_masks.numpy()
tag_class_indices = tf.make_ndarray(tag_class_indices) #tag_class_indices = tag_class_indices.numpy()
tag_mask_sizes = np.sum(tag_masks, axis=(1, 2))
image_masks = np.transpose(tag_masks, axes=[1, 2, 0])
onehots = np.apply_along_axis(onehotify, axis=2, arr=image_masks)
#onehots = np.array([[eye[tag_class_indices[np.argmin([tag_mask_sizes[i] if i in np.flatnonzero(pixel_tag_masks) else 9999999 for i in range(len(tag_mask_sizes))])]] for pixel_tag_masks in image_masks[height]] for height in range(image_masks.shape[0])])
return tf.convert_to_tensor(onehots)
def parse_example(example_proto, width, height, num_classes):
features = {
'image/encoded': tf.FixedLenFeature((), tf.string),
'image/height': tf.FixedLenFeature((), tf.int64),
'image/width': tf.FixedLenFeature((), tf.int64),
'image/filename': tf.FixedLenFeature((), tf.string),
'image/object/bbox/xmin': tf.VarLenFeature(tf.float32),
'image/object/bbox/xmax': tf.VarLenFeature(tf.float32),
'image/object/bbox/ymin': tf.VarLenFeature(tf.float32),
'image/object/bbox/ymax': tf.VarLenFeature(tf.float32),
'image/object/class/label': tf.VarLenFeature(tf.int64),
'image/object/class/text': tf.VarLenFeature(tf.string),
'image/object/mask': tf.VarLenFeature(tf.string),
'image/depth': tf.FixedLenFeature((), tf.string)
}
parsed_example = tf.parse_single_example(example_proto, features)
# Decode image
image = tf.image.decode_jpeg(parsed_example['image/encoded'])
parsed_example['image/encoded'] = image
tag_masks = tf.sparse.to_dense(parsed_example['image/object/mask'], default_value="")
tag_masks = tf.map_fn(decode_png_mask, tag_masks, dtype=tf.uint8)
tag_masks = tf.reshape(tag_masks, shape=tf.stack([-1, height, width]), name='tag_masks')
# All segmentation now have their mask in mask, their labelmap index in classes_indices and their tagname in classes_text
tag_class_indices = tf.sparse.to_dense(parsed_example['image/object/class/label'])
tag_class_names = tf.sparse.to_dense(parsed_example['image/object/class/text'], default_value="")
onehots = masks_to_onehots(tag_masks, tag_class_indices, num_classes)
parsed_example['image/labels'] = onehots
return parsed_example
tf.enable_eager_execution()
NUM_CLASSES = 21
tfrecord_train = "/path/to/tf.record"
dataset_train = tf.data.TFRecordDataset(tfrecord_train)
# Read image widht/height from the TFRecord file
iterator = dataset_train.make_one_shot_iterator()
next_element = iterator.get_next()
parsed_element = np.fromstring(next_element.numpy(), dtype=np.uint8)
example = tf.train.Example.FromString(parsed_element)
height = example.features.feature['image/height'].int64_list.value[0]
width = example.features.feature['image/width'].int64_list.value[0]
dataset_train = dataset_train.map(lambda x: parse_example(x, width, height, NUM_CLASSES))
Other info / logs Full traceback:
Traceback (most recent call last): File "/home/local/CYCLOMEDIA001/ebos/Workspace/all_cf/src/experimental/cityfusion/tasks/material_segmentation/semantic_fpn.py", line 114, in <module> dataset_train = dataset_train.map(lambda x: parse_example(x, width, height, NUM_CLASSES)) File "/home/.../python3.5/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 1038, in map return MapDataset(self, map_func) File "/home/.../python3.5/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 2611, in __init__ map_func, "Dataset.map()", input_dataset) File "/home/.../python3.5/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 1860, in __init__ self._function.add_to_graph(ops.get_default_graph()) File "/home/.../python3.5/site-packages/tensorflow/python/framework/function.py", line 479, in add_to_graph self._create_definition_if_needed() File "/home/.../python3.5/site-packages/tensorflow/python/framework/function.py", line 335, in _create_definition_if_needed self._create_definition_if_needed_impl() File "/home/.../python3.5/site-packages/tensorflow/python/framework/function.py", line 344, in _create_definition_if_needed_impl self._capture_by_value, self._caller_device) File "/home/.../python3.5/site-packages/tensorflow/python/framework/function.py", line 864, in func_graph_from_py_func outputs = func(*func_graph.inputs) File "/home/.../python3.5/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 1794, in tf_data_structured_function_wrapper ret = func(*nested_args) File "/path/to/script.py", line 114, in <lambda> dataset_train = dataset_train.map(lambda x: parse_example(x, width, height, NUM_CLASSES)) File "path/to/script.py", line 86, in parse_example onehots = masks_to_onehots(tag_masks, tag_class_indices, num_classes) File "/path/to/script.py", line 25, in masks_to_onehots tag_masks = tf.make_ndarray(tag_masks) #tag_masks = tag_masks.numpy() File "/home/.../python3.5/site-packages/tensorflow/python/framework/tensor_util.py", line 563, in MakeNdarray shape = [d.size for d in tensor.tensor_shape.dim] AttributeError: 'Tensor' object has no attribute 'tensor_shape'
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 1
- Comments: 24 (8 by maintainers)
The handling of this issue speaks volumes of why the research community is moving from tensorflow to pytorch.
I am having the same issue, trying to use tf.make_ndarray in tf.Dataset.map call
I am also stuck with the same bug. And yes it is a bug since this is 100% non-pythonic. Please fix it. Eager execution in Tensorflow2+ is a lie that made me waste more time than it should. It should be instead âeager execution sometimesâ
tf.make_ndarray
is used to convertTensorProto
values into NumPy arrays, nottf.Tensor
objects. These values are generally the constants used in a graph. For example, in graph mode, when you usetf.constant
, you create aConst
operation with an attributevalue
holding the constant value that the operation will produce. That attribute is stored as aTensorProto
. Hence, you can âextractâ the value of aConst
operation as a NumPy array like this (TF 1.x):In general, though, you cannot convert arbitrary tensors into NumPy arrays in graph mode, as their values will depend on the values of the variables and the fed inputs within a particular session.
Why is this issue still closed?
can this issue be re-opened? I am experiencing the same problem as described above.
Why is this a thing though?
I know this should not happen. Unfortunately the code is quite long and complex, my workaround was to pre-process the data with numpy before feeding it to tensorflow, so I couldnât really solve this issue.
On other forums I found solutions which involved changing NumPy version and/or TF version.
All in all itâs very frustrating that such a simple operation required so much time and effort, on PyTorch this is something that never gave me headaches, not even close.
This issue keeps popping up in my inbox and I donât even know why as there really is no bug to solve here. I already explained this above, but letâs go through it again for TensorFlow 2.
tf.make_ndarray
is NOT a general function to convert tensors to NumPy arrays (in spite to what the admittedly misleading documentation of the function might say). What it does is it converts aTensorProto
, which is a low-level binary representation of a tensor, into a NumPy array. Most typical TensorFlow code will never useTensorProto
objects (directly), sotf.make_ndarray
is just not a useful function for most people. Depending on the case, it may be possible to build a NumPy array from a tensor with it, but, again, its purpose is not to convert tensors to NumPy arrays in general, and it should rarely or never be used.If you want to convert a TensorFlow tensor into a NumPy array, you need to be mindful that TensorFlow code may run in eager mode or graph mode. Graph mode is less âconvenientâ to use, but it is important for performance, optimisation, serialisation and other reasons. Although it is rare to explicitly enter into graph mode as a library user, it is very normal to write code that runs in graph mode, like the code in a Keras model, for example. It is not always straightforward to know what mode your code is running, especially since TensorFlow aims to hide this complexity from the library users, but the complexity is still there and it is important to understand it.
If you are in eager mode, you can just do
.numpy()
on your tensor. In graph mode, though, you CANNOT obtain the NumPy array corresponding to a tensor, because tensors do not hold any value in particular in graph mode, but they rather expresses a symbolic intermediate results (with some exceptions liketf.constant
, which is possible to convert into a NumPy array even in graph mode, because it always has the same value). If you want to do a NumPy operation with your tensor in graph mode (which would not be differentiable in TensorFlow btw), you need to temporarily switch to eager mode within graph mode, which you can do withtf.py_function
. There, your tensors will be eager tensors and you can call.numpy()
on them.NB: I am not a TensorFlow developer nor have any affiliation of any kind with anyone involved with its development.
Since TensorFlow 1.0, tf.Tensor now has a tf.Tensor.shape property, which returns the same value as tf.Tensor.get_shape(). In versions prior to TensorFlow 1.0 tf.Tensor doesnât have a .shape property. You should use the Tensor.get_shape() method instead: Hope this helps.
Did anyone manage to solve this one? Itâs unbelievable the amount of hassle you need to go through to perform such a simple operation. Really unbelievable.
@ymodak No, because
.numpy()
only works in eager execution, and code ran throughtf.Dataset.map()
isnât executed eagerly. This is the reason I try to rely on.make_ndarray()
. Bothtag_masks
andtag_class_indices
are<class 'tensorflow.python.framework.ops.Tensor'>
.I already moved on though. I abandoned TFRecords because they are getting me absolutely nowhere. However, other people might run into this same problem.
I am able to reproduce the issue reported here on my system with same configuration. Got the error AttributeError: âTensorâ object has no attribute âtensor_shapeâ