'Tensorflow: Getting scalar tensor value as int for pass to set_shape()

I'm attempting to load 3D images and their labels from a numpy array to TensorFlow records, then read them from a queue while training my network. The code for conversion is based on the conversion for TensorFlow's Inception model.

Each image has a different height, width, and depth value, so when reshaping the array I need to know these values. However, I'm getting an error when I try to use set_shape, as somewhere down the line int() is being used, and it doesn't accept Tensor values.

reader = tf.TFRecordReader()
_, value = reader.read(filename_queue)


# Features in Example proto
feature_map = {
    'height': tf.VarLenFeature(dtype=tf.int64),
    'width': tf.VarLenFeature(dtype=tf.int64),
    'depth': tf.VarLenFeature(dtype=tf.int64),
    'label': tf.VarLenFeature(dtype=tf.int64),
    'image_raw': tf.VarLenFeature(dtype=tf.string)
}

features = tf.parse_single_example(value, feature_map)
result.label = tf.cast(features['label'].values[0], dtype=tf.int32)
result.height = tf.cast(features['height'].values[0], dtype=tf.int32)
result.width = tf.cast(features['width'].values[0], dtype=tf.int32)
result.depth = tf.cast(features['depth'].values[0], dtype=tf.int32)

image = tf.decode_raw(features['image_raw'].values[0], tf.int16)

image = tf.reshape(image, [result.depth, result.height, result.width])
image = tf.cast(tf.transpose(image, [1, 2, 0]), tf.float32)
result.image = tf.expand_dims(image, 3)

result.image.set_shape([result.height, result.width, result.depth, 1])
result.label = tf.expand_dims(result.label, 0)
result.label.set_shape([1])

Error trace:

Traceback (most recent call last):
  File "dsb17_multi_gpu_train.py", line 227, in <module>
    tf.app.run()
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/platform/app.py", line 44, in run
    _sys.exit(main(_sys.argv[:1] + flags_passthrough))
  File "dsb17_multi_gpu_train.py", line 223, in main
    train()
  File "dsb17_multi_gpu_train.py", line 129, in train
    loss = tower_loss(scope)
  File "dsb17_multi_gpu_train.py", line 34, in tower_loss
    images, labels = dsb17.inputs(False)
  File "/home/ubuntu/dsb17/model/dsb17.py", line 104, in inputs
    batch_size=FLAGS.batch_size)
  File "/home/ubuntu/dsb17/model/dsb17_input.py", line 161, in inputs
    read_input = read_data(filename_queue)
  File "/home/ubuntu/dsb17/model/dsb17_input.py", line 62, in read_data
    result.image.set_shape([result.height, result.width, result.depth, 1])
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/ops.py", line 425, in set_shape
    self._shape = self._shape.merge_with(shape)
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/tensor_shape.py", line 573, in merge_with
    other = as_shape(other)
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/tensor_shape.py", line 821, in as_shape
    return TensorShape(shape)
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/tensor_shape.py", line 457, in __init__
    self._dims = [as_dimension(d) for d in dims_iter]
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/tensor_shape.py", line 457, in <listcomp>
    self._dims = [as_dimension(d) for d in dims_iter]
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/tensor_shape.py", line 378, in as_dimension
    return Dimension(value)
  File "/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/tensor_shape.py", line 33, in __init__
    self._value = int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'Tensor'

I originally thought this was because the Tensor did not have a value until it was evaluated in a session, but loss is being evaluated in a sess.run(), which is what requires the call to tower_loss(). My training code is identical in structure to cifar10_multi_gpu_train.py, and the overall file structure is also very similar.

The question then is: Is it actually being evaluated in a session, or is the graph not built yet? Do I need to somehow extract a value from the zero-dimensional Tensor? More generally, what am I misunderstanding about Tensors and sessions that is making my code not work as I expect it to?



Solution 1:[1]

According to TensorFlow's tf.cast docs, tf.cast returns a Tensor.

Your error says that when using set_shape(), you cannot have a Tensor as an argument, but rather an int.

You may try to force Tensorflow to evaluate the cast. This simple example works for me:

a = tf.constant(2.0)
b = tf.constant([1.0,2.0])
b.set_shape(a.eval())

Without the call to eval(), I get the same error as you.

Solution 2:[2]

In general you cannot do this using tf.Tensor.set_shape(), because that method expects a static shape. The tensors result.height, result.width, result.depth represent values read from a file, and at runtime they could evaluate to many different integers (depending on what is in your file), so there is no single int that you can pass for them. In that case, the best you can currently do is represent those dimensions as being statically unknown, using None for the unknown dimensions:

result.image.set_shape([None, None, None, 1])

Note that this statement shouldn't change anything, because TensorFlow should already be able to infer that the shape is 4-D with size 1 in the last dimension.

For more details about static and dynamic shapes, see this answer.

Solution 3:[3]

Actually you can pass the image shape to the reshape function but you need one more step. Just change the line:

image = tf.reshape(image, [result.depth, result.height, result.width])

to:

image_shape = tf.stack([result.depth, result.height, result.width])
image = tf.reshape(image, image_shape)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 vega
Solution 2 Community
Solution 3 anothernode