Qululu
Qululu

Reputation: 1070

Keras/Tensorflow: ValueError: Shape (?,12) must have rank 1

(Keras 1.0.7, Tensorflow r0.10)

I am trying to implement my own activation function:

# Custom activation function (Radial Basis Function - RBF)
l2_norm = lambda a, b: K.sqrt(((a - b) ** 2).sum())
def rbf(x, gamma=1.0):
     return K.exp(-1 * gamma * l2_norm(x[0], x[1]) ** 2)

Here is the relevant section of my model where I specify my custom activation function:

model = Sequential()
# Some other layers go here
model.add(Dense(n_classes, activation=rbf))

I get the following error:

/raid/home/user/anaconda2/envs/tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/tensor_shape.pyc in assert_has_rank(self, rank)
619     """
620     if self.ndims not in (None, rank):
--> 621       raise ValueError("Shape %s must have rank %d" % (self, rank))
622 
623   def with_rank(self, rank):

ValueError: Shape (?, 12) must have rank 1

The error occurs on the line return K.exp(-1 * gamma * l2_norm(x[0], x[1]) ** 2) when trying to slice x (which has shape (?, 12)) into x[0] and x[1].

Why does the Tensorflow slice method throw this error?

Upvotes: 2

Views: 3701

Answers (2)

Wasi Ahmad
Wasi Ahmad

Reputation: 37691

As the error says, the shape (?, 12) is not of rank 1. Tensor rank (sometimes referred to as order or degree or n-dimension) is the number of dimensions of the tensor. For example, the following tensor (defined as a Python list) has a rank of 2:

t = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In TensorFlow, the slicing operation is slightly less flexible than in python numpy. The number of dimensions specified in the slice must be equal to the rank of the tensor.

tf.slice(input, begin, size, name=None)

This operation extracts a slice of size size from a tensor input starting at the location specified by begin. The slice size is represented as a tensor shape, where size[i] is the number of elements of the 'i'th dimension of input that you want to slice. The starting location (begin) for the slice is represented as an offset in each dimension of input. In other words, begin[i] is the offset into the 'i'th dimension of input that you want to slice from.

begin is zero-based; size is one-based. If size[i] is -1, all remaining elements in dimension i are included in the slice.

In short, the operator requires that the begin and size vectors — which define the subtensor to be sliced — have the same length as the number of dimensions in input. For example, to slice a 3-D tensor, you must pass a vector (or list) of three numbers as the second and third arguments of tf.slice().

For example:

# 'input' is [[[1, 1, 1], [2, 2, 2]],
#             [[3, 3, 3], [4, 4, 4]],
#             [[5, 5, 5], [6, 6, 6]]]
tf.slice(input, [1, 0, 0], [1, 1, 3]) ==> [[[3, 3, 3]]]
tf.slice(input, [1, 0, 0], [1, 2, 3]) ==> [[[3, 3, 3],
                                            [4, 4, 4]]]
tf.slice(input, [1, 0, 0], [2, 1, 3]) ==> [[[3, 3, 3]],
                                           [[5, 5, 5]]]

So, you can modify your rbf() function as follows and it should work:

def rbf(x, gamma=1.0):
    return K.exp(-1 * gamma * l2_norm(x[0, :], x[1, :]) ** 2)

Upvotes: 1

mrry
mrry

Reputation: 126154

N.B. I couldn't reproduce this problem with the latest version of TensorFlow. I suspect you're using one of the release candidates of TensorFlow 0.10, or an earlier version, because in the released version it is possible to write the following:

x = tf.placeholder(tf.float32, shape=[None, 12])
print(x[0].get_shape())  # ==> (12,)
print(x[1].get_shape())  # ==> (12,)

In older versions of TensorFlow, you had to specify every dimension of the slice explicitly when using the tf.slice() op or the [] Python slice operator. If you can't upgrade to the latest version (which we'd generally recommend!), the following modified version of your rbf() function should work:

def rbf(x, gamma=1.0):
    return K.exp(-1 * gamma * l2_norm(x[0, :], x[1, :]) ** 2)

Upvotes: 0

Related Questions