7 votes

Erreur d'attribut : La couche n'a pas de nœuds entrants, ou AttributeError : La couche n'a jamais été appelée

J'ai besoin d'un moyen pour obtenir la forme du tenseur de sortie pour n'importe quel type de couche (i.e. Dense, Conv2D, etc) dans TensorFlow. D'après la documentation, il y a output_shape ce qui résout le problème. Cependant, chaque fois que j'y accède, j'obtiens AttributedError .

Voici un exemple de code illustrant le problème :

import numpy as np
import tensorflow as tf

x = np.arange(0, 8, dtype=np.float32).reshape((1, 8))
x = tf.constant(value=x, dtype=tf.float32, verify_shape=True)

dense = tf.layers.Dense(units=2)

out = dense(x)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    res = sess.run(fetches=out)
    print(res)
    print(dense.output_shape)

En print(dense.output_shape) produira un message d'erreur :

AttributeError: The layer has never been called and thus has no defined output shape.

ou print(dense.output) produira :

AttributeError('Layer ' + self.name + ' has no inbound nodes.')
AttributeError: Layer dense_1 has no inbound nodes.

Existe-t-il un moyen de corriger l'erreur ?

P.S. : Je sais que dans l'exemple ci-dessus, je peux obtenir la forme du tenseur de sortie via out.get_shape() . Cependant, je voudrais savoir pourquoi output_shape les biens ne fonctionnent pas et comment je peux y remédier ?

7voto

Amir Hadifar Points 5294

TL;DR

Comment puis-je y remédier ? Définir une couche d'entrée :

x = tf.keras.layers.Input(tensor=tf.ones(shape=(1, 8)))
dense = tf.layers.Dense(units=2)

out = dense(x)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    res = sess.run(fetches=out)
    print(dense.output_shape) # shape = (1, 2)

Accordint to Keras la documentation Si une couche a un seul nœud vous pouvez obtenir son tenseur d'entrée, son tenseur de sortie, sa forme d'entrée et sa forme de sortie via :

  • couche.entrée
  • couche.sortie
  • layer.input_shape
  • couche.forme_de_sortie

Mais dans l'exemple ci-dessus, lorsque nous appelons layer.output_shape ou d'autres attributs, il lance des exceptions qui semblent un peu étranges.

Si nous allons en profondeur dans le code source , l'erreur causée par nœuds entrants .

if not self._inbound_nodes:
  raise AttributeError('The layer has never been called '
                       'and thus has no defined output shape.')

Ce que ces nœuds entrants sont ?

A Nœud décrit les connectivité entre deux couches . Chaque fois qu'une couche est connectée à une nouvelle entrée, un nœud est ajouté à couche._nœuds_inbound . Chaque fois que la sortie d'une couche est utilisée par une autre couche, un nœud est ajouté à couche._nœuds_sortants .

Comme vous pouvez le voir ci-dessus, lorsque self._inbounds_nodes est None, il lève une exception. _Cela signifie qu'une couche n'est pas connectée à la couche d'entrée ou, plus généralement, qu'aucune des couches précédentes n'est connectée à une couche d'entrée, self._inbounds_nodes est vide, ce qui a causé le problème_ .

Notez que x dans votre exemple, est un tenseur et non une couche d'entrée. Voir un autre exemple pour plus de clarté :

x = tf.keras.layers.Input(shape=(8,))
dense = tf.layers.Dense(units=2)

out = dense(x)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    res = sess.run(fetches=out, feed_dict={x: np.ones(shape=(1, 8))})
    print(res)
    print(res.shape)  # shape = (1,2)
    print(dense.output_shape)  # shape = (None,2)

Cela ne pose aucun problème car la couche d'entrée est définie.


Notez que, dans votre exemple, out est un tenseur. La différence entre les tf.shape() et la fonction .shape =( get_shape() ) est :

tf.shape(x) renvoie un tenseur d'entiers 1-D représentant la dynamique de x. Une forme dynamique ne sera connue qu'au moment de l'exécution du graphique.

x.shape renvoie un tuple Python représentant les données statiques de de x. Une forme statique, connue au moment de la définition du graphe.

Pour en savoir plus sur la forme des tenseurs, consultez le site : https://pgaleone.eu/tensorflow/2018/07/28/understanding-tensorflow-tensors-shape-static-dynamic/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X