Bilinear resizes a tensor t to have shape target_shape.

  This function bilinearly resizes a n-dimensional tensor by iteratively
  applying tf.image.resize_bilinear (which can only resize 2 dimensions).
  For bilinear interpolation, the order in which it is applied does not matter.

  Args:
    t: tensor to be resized
    target_shape: the desired shape of the new tensor.

  Returns:
   The resized tensor

def resize_bilinear_nd(t, target_shape):
  """Bilinear resizes a tensor t to have shape target_shape.

  This function bilinearly resizes a n-dimensional tensor by iteratively
  applying tf.image.resize_bilinear (which can only resize 2 dimensions).
  For bilinear interpolation, the order in which it is applied does not matter.

  Args:
    t: tensor to be resized
    target_shape: the desired shape of the new tensor.

  Returns:
   The resized tensor
  """
  shape = t.get_shape().as_list()
  target_shape = list(target_shape)
  assert len(shape) == len(target_shape)

  # We progressively move through the shape, resizing dimensions...
  d = 0
  while d < len(shape):

    # If we don't need to deal with the next dimesnion, step over it
    if shape[d] == target_shape[d]:
      d += 1
      continue

    # Otherwise, we'll resize the next two dimensions...
    # If d+2 doesn't need to be resized, this will just be a null op for it
    new_shape = shape[:]
    new_shape[d : d+2] = target_shape[d : d+2]

    # The helper collapse_shape() makes our shapes 4-dimensional with
    # the two dimesnions we want to deal with in the middle.
    shape_ = collapse_shape(shape, d, d+2)
    new_shape_ = collapse_shape(new_shape, d, d+2)

    # We can then reshape and use the 2d tf.image.resize_bilinear() on the
    # inner two dimesions.
    t_ = tf.reshape(t, shape_)
    t_ = tf.image.resize_bilinear(t_, new_shape_[1:3])

    # And then reshape back to our uncollapsed version, having finished resizing
    # two more dimensions in our shape.
    t = tf.reshape(t_, new_shape)
    shape = new_shape
    d += 2

  return t