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/