## Understanding static and dynamic shapes Tensors in TensorFlow have a static shape attribute which is determined during graph construction. The static shape may be underspecified. For example we might define a tensor of shape [None, 128]: ```python import tensorflow as tf a = tf.placeholder(tf.float32, [None, 128]) ``` This means that the first dimension can be of any size and will be determined dynamically during Session.run(). You can query the static shape of a Tensor as follows: ```python static_shape = a.shape.as_list() # returns [None, 128] ``` To get the dynamic shape of the tensor you can call tf.shape op, which returns a tensor representing the shape of the given tensor: ```python dynamic_shape = tf.shape(a) ``` The static shape of a tensor can be set with Tensor.set_shape() method: ```python a.set_shape([32, 128]) # static shape of a is [32, 128] a.set_shape([None, 128]) # first dimension of a is determined dynamically ``` You can reshape a given tensor dynamically using tf.reshape function: ```python a = tf.reshape(a, [32, 128]) ``` It can be convenient to have a function that returns the static shape when available and dynamic shape when it's not. The following utility function does just that: ```python def get_shape(tensor): static_shape = tensor.shape.as_list() dynamic_shape = tf.unstack(tf.shape(tensor)) dims = [s[1] if s[0] is None else s[0] for s in zip(static_shape, dynamic_shape)] return dims ``` Now imagine we want to convert a Tensor of rank 3 to a tensor of rank 2 by collapsing the second and third dimensions into one. We can use our get_shape() function to do that: ```python b = tf.placeholder(tf.float32, [None, 10, 32]) shape = get_shape(b) b = tf.reshape(b, [shape[0], shape[1] * shape[2]]) ``` Note that this works whether the shapes are statically specified or not. In fact we can write a general purpose reshape function to collapse any list of dimensions: ```python import tensorflow as tf import numpy as np def reshape(tensor, dims_list): shape = get_shape(tensor) dims_prod = [] for dims in dims_list: if isinstance(dims, int): dims_prod.append(shape[dims]) elif all([isinstance(shape[d], int) for d in dims]): dims_prod.append(np.prod([shape[d] for d in dims])) else: dims_prod.append(tf.reduce_prod([shape[d] for d in dims])) tensor = tf.reshape(tensor, dims_prod) return tensor ``` Then collapsing the second dimension becomes very easy: ```python b = tf.placeholder(tf.float32, [None, 10, 32]) b = reshape(b, [0, [1, 2]]) ```