web-dev-qa-db-fra.com

Tenseur avec dimension non spécifiée en flux tensoriel

Je joue avec tensorflow et j'ai rencontré un problème avec le code suivant:

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')

(J'utilise tf.pack comme suggéré dans cette question , car j'avais la même erreur)

Lorsque je l'exécute (à partir d'un script plus grand qui appelle celui-ci), j'obtiens cette erreur:

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

J'ai essayé de reproduire le processus dans le shell interactif. En effet, les dimensions de normal_dist ne sont pas spécifiées, bien que les valeurs fournies existent:

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)])

C'est bizarre. Tensorflow génère le vecteur mais ne peut pas dire sa forme. Est-ce que je fais quelque chose de mal?

19
erickrf

Comme Ishamael le dit, tous les tenseurs ont une forme statique, qui est connue au moment de la construction du graphe et accessible avec Tensor.get_shape() ; et une forme dynamique, connue uniquement à l'exécution et accessible en récupérant la valeur du tenseur, ou en la transmettant à un opérateur tel que tf.shape . Dans de nombreux cas, les formes statiques et dynamiques sont identiques, mais elles peuvent être différentes - la forme statique peut être définie partiellement définie - afin de permettre à la forme dynamique de varier d’une étape à l’autre.

Dans votre code, normal_dist a une forme statique partiellement définie, car w_shape est une valeur calculée. (TensorFlow tente parfois d'évaluer Ces valeurs calculées au moment de la construction du graphe, mais reste bloqué à tf.pack.) Il en déduit la forme TensorShape([Dimension(None), Dimension(None)]), qui signifie "une matrice avec un nombre inconnu de lignes et de colonnes" w_shape est un vecteur de longueur 2, le normal_dist résultant doit donc être bidimensionnel.

Vous avez deux options pour régler ce problème. Vous pouvez définir la forme statique comme le suggère Ishamael, mais cela nécessite de connaître la forme au moment de la construction du graphique. Par exemple, les éléments suivants peuvent fonctionner:

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

Vous pouvez également passer validate_shape=False au constructeur tf.Variable . Cela vous permet de créer une variable avec une forme partiellement définie, mais limite la quantité d'informations de forme statique pouvant être déduites ultérieurement dans le graphique.

34
mrry

La variable peut avoir une forme dynamique. get_shape() renvoie la forme statique.

Dans votre cas, vous avez un tenseur qui a une forme dynamique et qui détient actuellement une valeur de 4x3 (mais à un autre moment, il peut contenir une valeur de forme différente - car la forme est dynamique). Pour définir la forme statique, utilisez set_shape(w_shape) . Après cela, la forme que vous définissez sera appliquée et le tenseur sera un initial_value valide.

3
Ishamael

Une question similaire est bien expliquée dans TF FAQ :

Dans TensorFlow, un tenseur a à la fois une forme statique (déduite) et un forme dynamique (vraie). La forme statique peut être lue en utilisant le Méthode tf.Tensor.get_shape: cette forme est déduite des opérations qui ont été utilisés pour créer le tenseur, et peuvent être partiellement complets. Si la forme statique n'est pas complètement définie, la forme dynamique d'un tenseur t peut être déterminé en évaluant tf.shape(t).

So tf.shape() vous renvoie un tenseur, aura toujours une taille de shape=(N,) et pourra être calculé en une session:

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

D'autre part, vous pouvez extraire la forme statique à l'aide de x.get_shape().as_list() et cela peut être calculé n'importe où.

2
Salvador Dali