Tensor con dimensión no especificada en tensorflow

Estoy jugando con tensorflow y encontré un problema con el siguiente código:

def _init_parameters(self, input_data, labels): # the input shape is (batch_size, input_size) input_size = tf.shape(input_data)[1] # labels in one-hot format have shape (batch_size, num_classes) num_classes = tf.shape(labels)[1] stddev = 1.0 / tf.cast(input_size, tf.float32) w_shape = tf.pack([input_size, num_classes], 'w-shape') normal_dist = tf.truncated_normal(w_shape, stddev=stddev, name='normaldist') self.w = tf.Variable(normal_dist, name='weights') 

(Estoy usando tf.pack como se sugiere en esta pregunta , ya que estaba recibiendo el mismo error)

Cuando lo ejecuto (desde un script más grande que invoca este), recibo este error:

 ValueError: initial_value must have a shape specified: Tensor("normaldist:0", shape=TensorShape([Dimension(None), Dimension(None)]), dtype=float32) 

Intenté replicar el proceso en el shell interactivo. De hecho, las dimensiones de normal_dist no están especificadas, aunque los valores proporcionados sí existen:

 In [70]: input_size.eval() Out[70]: 4 In [71]: num_classes.eval() Out[71]: 3 In [72]: w_shape.eval() Out[72]: array([4, 3], dtype=int32) In [73]: normal_dist.eval() Out[73]: array([[-0.27035281, -0.223277 , 0.14694688], [-0.16527176, 0.02180306, 0.00807841], [ 0.22624688, 0.36425814, -0.03099642], [ 0.25575709, -0.02765726, -0.26169327]], dtype=float32) In [78]: normal_dist.get_shape() Out[78]: TensorShape([Dimension(None), Dimension(None)]) 

Esto es raro Tensorflow genera el vector pero no puede decir su forma. ¿Estoy haciendo algo mal?

Como dice Ishamael, todos los tensores tienen una forma estática, conocida en el momento de la construcción del gráfico y accesible mediante Tensor.get_shape() ; y una forma dinámica, que solo se conoce en tiempo de ejecución y se puede acceder a través del valor del tensor, o tf.shape a un operador como tf.shape . En muchos casos, las formas estáticas y dinámicas son iguales, pero pueden ser diferentes (la forma estática se puede definir parcialmente ) para permitir que la forma dinámica varíe de un paso a otro.

En su código, normal_dist tiene una forma estática parcialmente definida, porque w_shape es un valor computado. (TensorFlow a veces intenta evaluar estos valores calculados en el momento de la construcción del gráfico, pero se atasca en tf.pack ). tf.pack la forma TensorShape([Dimension(None), Dimension(None)]) , que significa “una matriz con una número desconocido de filas y columnas, “porque se sabe que w_shape es un vector de longitud 2, por lo que la normal_dist resultante debe ser bidimensional.

Tienes dos opciones para lidiar con esto. Puede establecer la forma estática como sugiere Ishamael, pero esto requiere que conozca la forma en el momento de la construcción del gráfico. Por ejemplo, lo siguiente puede funcionar:

 normal_dist.set_shape([input_data.get_shape()[1], labels.get_shape()[1]]) 

Alternativamente, puede pasar validate_shape=False al constructor tf.Variable . Esto le permite crear una variable con una forma parcialmente definida, pero limita la cantidad de información de forma estática que se puede inferir más adelante en el gráfico.

La variable puede tener una forma dinámica. get_shape() devuelve la forma estática.

En su caso, tiene un tensor que tiene una forma dinámica y actualmente tiene un valor de 4×3 (pero en algún otro momento puede mantener un valor con una forma diferente, porque la forma es dinámica). Para establecer la forma estática, use set_shape(w_shape) . Después de eso, la forma que establezca se aplicará y el tensor será un valor initial_value válido.

Una pregunta similar está bien explicada en las preguntas frecuentes de TF :

En TensorFlow, un tensor tiene una forma estática (inferida) y una forma dinámica (verdadera). La forma estática se puede leer utilizando el método tf.Tensor.get_shape : esta forma se deduce de las operaciones que se usaron para crear el tensor, y puede estar parcialmente completa. Si la forma estática no está completamente definida, la forma dinámica de un Tensor t puede determinarse evaluando tf.shape(t) .

Así que tf.shape() te devuelve un tensor, siempre tendrá un tamaño de shape=(N,) y se puede calcular en una sesión:

 a = tf.Variable(tf.zeros(shape=(2, 3, 4))) with tf.Session() as sess: print sess.run(tf.shape(a)) 

Por otro lado, puede extraer la forma estática utilizando x.get_shape().as_list() y esto se puede calcular en cualquier lugar.