Cet article est l'article du 20e jour du Calendrier de l'Avent TensorFlow 2.0 2019. Je pense que le changement majeur dans TensorFlow 2.0 est que EagerExecution est devenu la valeur par défaut, vous permettant d'écrire dans un langage pédagogique et d'écrire plus librement dans un style pythonique. Cependant, d'un autre côté, il y a un problème que les performances et la portabilité sont sacrifiées, mais afin de le résoudre afin que vous puissiez bénéficier à la fois du mode Graph en 1.x et du mode Eager en 2.x. Celui qui est apparu dans est tf.function
. Dans cet article, je voudrais vous présenter comment utiliser tf.function
et les points à prendre en compte lors de son utilisation. Fondamentalement, il s'agit d'un résumé du Site officiel, donc si vous voulez en savoir plus, veuillez vous y référer également.
Il est facile à utiliser, ajoutez un collator avec @ tf.function
à la fonction qui décrit le traitement lourd que vous souhaitez optimiser, ou définissez une fonction et alimentez-la dans la méthode tf.function
pour séparer la fonction du mode graphique. C'est une méthode de création.
function_test.py
import tensorflow as tf
@tf.function
def f(x,y):
return x + y
#Ou
def g(x,y):
return x * y
h = tf.function(g)
De plus, si vous appelez une autre fonction dans @ tf.function
, la portée s'étend à cette fonction, vous n'avez donc pas à vous soucier de vérifier toutes les fonctions et d'ajouter @ tf.function
(ou plutôt, nous le recommandons). Sens). Par conséquent, il semble que vous puissiez facilement bénéficier du mode graphique simplement en l'ajoutant à la partie de traitement lourd pour le moment. Cependant, s'il s'agit d'un style d'écriture simple comme celui du tutoriel, ce n'est pas un gros problème, mais si vous essayez de faire quelque chose d'un peu compliqué, vous ne penserez pas que vous ne connaissez pas la spécification de tf.function
. Vous devez être prudent parce que vous le faites. Au début du Site officiel, il y a la description suivante.
for x in y
Il y a certains éléments qui sont difficiles à interpréter, mais je pense que c'est plus facile à comprendre si vous regardez un exemple concret, alors jetons un coup d'œil.
Tout d'abord, par souci de simplicité, préparez la fonction simple suivante.
tracing_test.py
import tensorflow as tf
@tf.function
def double(a):
print("Tracing with, {}".format(a) )
return a + a
C'est une fonction simple qui double l'argument d'entrée et le renvoie, et inclut également le processus d'impression de l'argument d'entrée. L'argument fonctionne avec des entiers, des nombres réels et des chaînes. Faisons cela avec quelques modèles.
tracing_test.py
print(double(3))
print()
print(double(2))
print()
print(double(tf.constant(1.1)))
print()
print(double(tf.constant('a')))
print()
print(double(tf.constant('b')))
Le résultat est le suivant.
Tracing with, 3
tf.Tensor(6, shape=(), dtype=int32)
Tracing with, 2
tf.Tensor(4, shape=(), dtype=int32)
Tracing with, Tensor("a:0", shape=(), dtype=float32)
tf.Tensor(2.2, shape=(), dtype=float32)
Tracing with, Tensor("a:0", shape=(), dtype=string)
tf.Tensor(b'aa', shape=(), dtype=string)
tf.Tensor(b'bb', shape=(), dtype=string)
Le résultat est un peu étrange. L'instruction print n'est pas exécutée uniquement à la suite de l'exécution du dernier tf.constant ('b')
comme argument. Si vous essayez à nouveau d'exécuter le programme ci-dessus, vous obtiendrez des résultats encore plus étranges.
tracing_test.py
print(double(3))
print()
print(double(2))
print()
print(double(tf.constant(1.1)))
print()
print(double(tf.constant('a')))
print()
print(double(tf.constant('b')))
Le résultat est le suivant.
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(4, shape=(), dtype=int32)
tf.Tensor(2.2, shape=(), dtype=float32)
tf.Tensor(b'aa', shape=(), dtype=string)
tf.Tensor(b'bb', shape=(), dtype=string)
La valeur correcte sera renvoyée, mais l'instruction d'impression écrite au milieu ne sera pas exécutée du tout. Qu'est-ce que ça veut dire?
Tracing
En fait, ce comportement étrange implique un processus appelé Tracing lorsque tf.function
construit et optimise une fonction sur un graphe de calcul. tf.function
convertit une fonction qui décrit non seulement le traitement dérivé de TensorFlow mais également spécifique à Python en un graphe de calcul. Et il omet le traitement spécifique à Python (instruction d'impression dans ce cas) qui n'est pas réellement lié à l'exécution du graphe de calcul. Mais pourquoi cela a-t-il été fait au début? C'est parce que lorsque tf.function
convertit une fonction en un graphe de calcul, un processus appelé Tracing s'exécute. Les fonctions écrites en Python n'ont pas de type explicite dans leurs arguments. Par conséquent, bien qu'il soit pratique de pouvoir entrer diverses valeurs, c'est un problème du côté de la fonction tf.function
d'essayer de créer un graphe de calcul optimal. Par conséquent, lorsqu'une valeur ou un type qui n'a pas été entré dans l'argument est entré et que la fonction est appelée pour la première fois, un processus appelé Tracing est exécuté pour exécuter tous les traitements spécifiques à Python dans la fonction. J'ai dit «des valeurs et des types qui n'ont jamais été inclus dans l'argument», mais à proprement parler, les critères sont les suivants.
Par conséquent, le comportement étrange du précédent est le suivant.
tracing_test.py
print(double(3)) #Tracing parce que c'est la valeur que je vois pour la première fois
print()
print(double(2)) #Tracing parce que c'est la valeur que je vois pour la première fois
print()
print(double(tf.constant(1.1))) #Tracing parce que c'est la valeur que je vois pour la première fois
print()
print(double(tf.constant('a'))) #Traçage car c'est la première forme à voir
print()
print(double(tf.constant('b'))) #Exécution de graphique optimisée car c'est la forme de type que nous avons vue auparavant
Une fois que vous exécutez Tracing, TensorFlow enregistre le graphe de calcul résultant en interne. Ensuite, la prochaine fois qu'une valeur précédemment tracée ou un argument type / forme est entré, le graphique de calcul optimisé sera exécuté. Par conséquent, dans le programme ci-dessus, l'instruction d'impression Python n'a pas été exécutée lors du dernier appel, et toutes les instructions d'impression n'ont pas été exécutées lors de sa nouvelle exécution.
Alors je reviendrai au début,
Cela signifie que. C'est Print plus tôt, mais si vous l'écrivez dans tf.print
à la place, il sera exécuté à chaque fois. Vous pouvez également éviter un comportement étrange en utilisant pleinement les fonctions dérivées de TensorFlow, telles que l'utilisation de tf.summary
ou l'utilisation de tf.Variable
si vous souhaitez mettre à jour diverses valeurs dans une fonction. Cela améliore également les performances. Cependant, veuillez noter que nous ne disons pas que nous ne devrions pas inclure de traitement spécifique à Python. L'avantage de pouvoir programmer de manière plus flexible en pouvant l'utiliser avec l'écriture pythonique est grand. Cependant, veuillez noter que si vous définissez une fonction sans penser à quoi que ce soit et que vous ajoutez tf.function
, elle se comportera étrangement.
C'est bien d'avoir TensorFlow 2.0 et de pouvoir bénéficier à la fois des modes Graph et Eager, mais cela crée des fonctions qui reposent trop sur des fonctionnalités spécifiques à Python autres que les pièges mentionnés ci-dessus. Vous pouvez marcher sur un bogue inattendu. Si vous utilisez TensorFlow, utilisez autant que possible les méthodes dérivées de TensorFlow et, lorsque vous utilisez des fonctions spécifiques à Python, concevez en tenant compte du comportement AutoGraph et du traçage. Le Site officiel a beaucoup d'autres choses à surveiller et comment contrôler ces comportements. Si vous avez besoin d'implémenter votre propre modèle à partir de maintenant et que vous devez utiliser tf.function
, veuillez le lire.
Recommended Posts