Je sais que je peux mesurer le temps d'exécution d'un appel à sess.run()
, mais est-il possible d'obtenir une granularité plus fine et de mesurer le temps d'exécution d'opérations individuelles?
Il n'y a pas encore de moyen de le faire dans la version publique. Nous sommes conscients que c'est une fonctionnalité importante et nous y travaillons.
J'ai utilisé l'objet Timeline
pour obtenir le temps d'exécution pour chaque nœud du graphique:
sess.run()
classique mais spécifiez également les arguments optionnels options
et run_metadata
Timeline
avec les données run_metadata.step_stats
Voici un exemple de programme mesurant les performances d'une multiplication matricielle:
import tensorflow as tf
from tensorflow.python.client import timeline
x = tf.random_normal([1000, 1000])
y = tf.random_normal([1000, 1000])
res = tf.matmul(x, y)
# Run the graph with full trace option
with tf.Session() as sess:
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
sess.run(res, options=run_options, run_metadata=run_metadata)
# Create the Timeline object, and write it to a json
tl = timeline.Timeline(run_metadata.step_stats)
ctf = tl.generate_chrome_trace_format()
with open('timeline.json', 'w') as f:
f.write(ctf)
Vous pouvez ensuite ouvrir Google Chrome, aller à la page chrome://tracing
et charger le fichier timeline.json
. Vous devriez voir quelque chose comme:
Etant donné que ceci est élevé lors de la recherche de "Tensorflow Profiling" sur Google, notez que la méthode actuelle (fin 2017, TensorFlow 1.4) pour obtenir la timeline utilise un ProfilerHook . Cela fonctionne avec les sessions surveillées dans tf.Estimator où les options tf.RunOptions ne sont pas disponibles.
estimator = tf.estimator.Estimator(model_fn=...)
hook = tf.train.ProfilerHook(save_steps=10, output_dir='.')
estimator.train(input_fn=..., steps=..., hooks=[hook])
Vous pouvez extraire ces informations à l’aide de statistiques d’exécution . Vous devrez faire quelque chose comme ceci (voir l'exemple complet dans le lien mentionné ci-dessus):
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
sess.run(<values_you_want_to_execute>, options=run_options, run_metadata=run_metadata)
your_writer.add_run_metadata(run_metadata, 'step%d' % i)
Mieux que de simplement l’imprimer, vous pouvez le voir sur le tensorboard:
De plus, cliquer sur un nœud affichera la mémoire totale exacte, temps de calcul et tailles de sortie du tenseur.
Pour mettre à jour cette réponse, nous disposons de certaines fonctionnalités pour le profilage de la CPU, axées sur l'inférence. Si vous regardez https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/benchmark , vous verrez un programme que vous pouvez exécuter sur un modèle pour obtenir des minutages par opération.
Pour les commentaires de fat-lobyte under Olivier Moindrot , vous pouvez remplacer "open('timeline.json', 'w')
" par "open('timeline.json', 'a')
" si vous souhaitez rassembler la chronologie de toutes les sessions.
Depuis Tensorflow 1.8, il existe un très bon exemple d'utilisation du tf.profile.Profiler
ici .
Pour profiler automatiquement les sessions TensorFlow, vous pouvez utiliser le profileur StackImpact . Pas besoin d'instrumenter des sessions ou d'ajouter des options. Il vous suffit d’initialiser le profileur:
import stackimpact
agent = stackimpact.start(
agent_key = 'agent key here',
app_name = 'MyApp')
Les profils de temps d'exécution et de mémoire seront disponibles dans le tableau de bord.
Informations détaillées dans cet article: Profilage TensorFlow dans les environnements de développement et de production .
Disclaimer: Je travaille pour StackImpact.
La bibliothèque d'opérations personnalisées Uber SBNet ( http://www.github.com/uber/sbnet récemment publiée) comporte une implémentation de timers basés sur des événements cuda, qui peuvent être utilisés de la manière suivante:
with tf.control_dependencies([input1, input2]):
dt0 = sbnet_module.cuda_timer_start()
with tf.control_dependencies([dt0]):
input1 = tf.identity(input1)
input2 = tf.identity(input2)
### portion of subgraph to time goes in here
with tf.control_dependencies([result1, result2, dt0]):
cuda_time = sbnet_module.cuda_timer_end(dt0)
with tf.control_dependencies([cuda_time]):
result1 = tf.identity(result1)
result2 = tf.identity(result2)
py_result1, py_result2, dt = session.run([result1, result2, cuda_time])
print "Milliseconds elapsed=", dt
Notez que n'importe quelle partie du sous-graphe peut être asynchrone. Vous devez donc faire très attention en spécifiant toutes les dépendances d'entrée et de sortie pour les opérations du minuteur. Sinon, le chronomètre pourrait être inséré dans le graphique dans le désordre et vous pourriez obtenir un temps erroné. J'ai trouvé les deux timeline et time.time () d'un utilitaire très limité pour le profilage de graphiques Tensorflow. Notez également que les API cuda_timer se synchroniseront sur le flux par défaut, qui est actuellement voulu par conception, car TF utilise plusieurs flux.
Cela dit, je recommande personnellement de passer à PyTorch :) L’itération de développement est plus rapide, le code est plus rapide et tout est beaucoup moins pénible.
Une autre approche quelque peu hacky et obscure pour soustraire le temps système de tf.Session (qui peut être énorme) consiste à reproduire le graphique N fois et à l’exécuter pour une variable N, en résolvant une équation de temps système fixe inconnu. C'est à dire. vous mesureriez environ session.run () avec N1 = 10 et N2 = 20 et vous savez que votre temps est t et que le temps système est x. Donc quelque chose comme
N1*x+t = t1
N2*x+t = t2
Résoudre pour x et t. L'inconvénient est que cela peut nécessiter beaucoup de mémoire et n'est pas nécessairement précis :) Assurez-vous également que vos entrées sont complètement différentes/aléatoires/indépendantes, sinon TF pliera l'intégralité du sous-graphique et ne l'exécutera pas N fois ... Amusez-vous avec TensorFlow: )