Ottimizzazione del grafico TensorFlow con Grappler

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza l'origine su GitHub Scarica quaderno

Panoramica

TensorFlow utilizza sia grafici che esecuzioni desiderose per eseguire calcoli. Un tf.Graph contiene un insieme di oggetti tf.Operation (ops) che rappresentano unità di calcolo e oggetti tf.Tensor che rappresentano le unità di dati che scorrono tra le operazioni.

Grappler è il sistema di ottimizzazione dei grafici predefinito nel runtime di TensorFlow. Grappler applica le ottimizzazioni in modalità grafico (all'interno di tf.function ) per migliorare le prestazioni dei tuoi calcoli TensorFlow attraverso semplificazioni dei grafici e altre ottimizzazioni di alto livello come l'inline dei corpi delle funzioni per abilitare le ottimizzazioni interprocedurali. L'ottimizzazione di tf.Graph riduce anche il picco di utilizzo della memoria del dispositivo e migliora l'utilizzo dell'hardware ottimizzando la mappatura dei nodi del grafico per calcolare le risorse.

Usa tf.config.optimizer.set_experimental_options() per un controllo più preciso sulle ottimizzazioni di tf.Graph .

Ottimizzatori grafici disponibili

Grappler esegue ottimizzazioni dei grafici tramite un driver di primo livello chiamato MetaOptimizer . Con TensorFlow sono disponibili i seguenti ottimizzatori di grafici:

  • Ottimizzatore di piegatura costante - Deduce staticamente il valore dei tensori quando possibile piegando i nodi costanti nel grafico e materializza il risultato usando le costanti.
  • Ottimizzatore aritmetico: semplifica le operazioni aritmetiche eliminando le sottoespressioni comuni e semplificando le istruzioni aritmetiche.
  • Ottimizzatore layout: ottimizza i layout del tensore per eseguire operazioni dipendenti dal formato dei dati, come le convoluzioni, in modo più efficiente.
  • Ottimizzatore di rimappatura: rimappa i sottografi su implementazioni più efficienti sostituendo i sottografi più comuni con kernel monolitici fusi ottimizzati.
  • Ottimizzatore di memoria: analizza il grafico per ispezionare il picco di utilizzo della memoria per ciascuna operazione e inserisce le operazioni di copia della memoria CPU-GPU per scambiare la memoria della GPU con la CPU per ridurre il picco di utilizzo della memoria.
  • Ottimizzatore delle dipendenze: rimuove o riorganizza le dipendenze di controllo per abbreviare il percorso critico per un passaggio del modello o abilita altre ottimizzazioni. Rimuove anche i nodi che sono effettivamente no-op come Identity.
  • Ottimizzatore di sfoltimento: elimina i nodi che non hanno alcun effetto sull'output del grafico. Di solito viene eseguito per primo per ridurre le dimensioni del grafico e accelerare l'elaborazione in altri passaggi Grappler.
  • Ottimizzatore di funzioni: ottimizza la libreria delle funzioni di un programma TensorFlow e integra i corpi delle funzioni per consentire altre ottimizzazioni interprocedurali.
  • Ottimizzatore di forma: ottimizza i sottografi che operano su forma e informazioni relative alla forma.
  • Ottimizzatore di parallelismo automatico: parallelizza automaticamente i grafici suddividendoli lungo la dimensione batch. Questo ottimizzatore è disattivato per impostazione predefinita.
  • Ottimizzatore di loop: ottimizza il flusso di controllo del grafico sollevando i sottografi invarianti dai loop e rimuovendo le operazioni di stack ridondanti nei loop. Ottimizza anche i loop con conteggi di viaggi staticamente noti e rimuove i rami morti staticamente noti nei condizionali.
  • Ottimizzatore di allocatore con ambito: introduce gli allocatori con ambito per ridurre lo spostamento dei dati e consolidare alcune operazioni.
  • Aggiungi all'ottimizzatore host: scambia piccole operazioni sulla CPU. Questo ottimizzatore è disattivato per impostazione predefinita.
  • Ottimizzatore automatico di precisione mista: converte i tipi di dati in float16 ove applicabile per migliorare le prestazioni. Attualmente si applica solo alle GPU.
  • Debug stripper - Elimina i nodi relativi alle operazioni di debug come tf.debugging.Assert , tf.debugging.check_numerics e tf.print dal grafico. Questo ottimizzatore è disattivato per impostazione predefinita.

Impostare

import numpy as np
import timeit
import traceback
import contextlib


import tensorflow as tf

Crea un gestore del contesto per alternare facilmente gli stati dell'ottimizzatore.

@contextlib.contextmanager
def options(options):
  old_opts = tf.config.optimizer.get_experimental_options()
  tf.config.optimizer.set_experimental_options(options)
  try:
    yield
  finally:
    tf.config.optimizer.set_experimental_options(old_opts)

Confronta le prestazioni di esecuzione con e senza Grappler

TensorFlow 2 e versioni successive vengono eseguiti avidamente per impostazione predefinita. Utilizzare tf.function per cambiare l'esecuzione predefinita in modalità Grafico. Grappler viene eseguito automaticamente in background per applicare le ottimizzazioni del grafico sopra e migliorare le prestazioni di esecuzione.

Ottimizzatore di piegatura costante

Come esempio preliminare, si consideri una funzione che esegue operazioni sulle costanti e restituisce un output.

def test_function_1():
  @tf.function
  def simple_function(input_arg):
    print('Tracing!')
    a = tf.constant(np.random.randn(2000,2000), dtype = tf.float32)
    c = a
    for n in range(50):
      c = c@a
    return tf.reduce_mean(c+input_arg)

  return simple_function

Spegnere l'ottimizzatore di piegatura costante ed eseguire la funzione:

with options({'constant_folding': False}):
  print(tf.config.optimizer.get_experimental_options())
  simple_function = test_function_1()
  # Trace once
  x = tf.constant(2.2)
  simple_function(x)
  print("Vanilla execution:", timeit.timeit(lambda: simple_function(x), number = 1), "s")
{'constant_folding': False, 'disable_model_pruning': False, 'disable_meta_optimizer': False}
Tracing!
Vanilla execution: 0.0018392090000816097 s

Abilitare l'ottimizzatore di piegatura costante ed eseguire nuovamente la funzione per osservare un'accelerazione nell'esecuzione della funzione.

with options({'constant_folding': True}):
  print(tf.config.optimizer.get_experimental_options())
  simple_function = test_function_1()
  # Trace once
  x = tf.constant(2.2)
  simple_function(x)
  print("Constant folded execution:", timeit.timeit(lambda: simple_function(x), number = 1), "s")
{'constant_folding': True, 'disable_model_pruning': False, 'disable_meta_optimizer': False}
Tracing!
Constant folded execution: 0.0006749789999958011 s

Ottimizzatore di debug stripper

Considera una semplice funzione che controlla il valore numerico del suo argomento di input e lo restituisce.

def test_function_2():
  @tf.function
  def simple_func(input_arg):
    output = input_arg
    tf.debugging.check_numerics(output, "Bad!")
    return output
  return simple_func

Innanzitutto, esegui la funzione con l'ottimizzatore di stripper di debug disattivato.

test_func = test_function_2()
p1 = tf.constant(float('inf'))
try:
  test_func(p1)
except tf.errors.InvalidArgumentError as e:
  traceback.print_exc(limit=2)
2021-09-22 20:34:55.871238: E tensorflow/core/kernels/check_numerics_op.cc:292] abnormal_detected_host @0x7f4878e00100 = {0, 1} Bad!
Traceback (most recent call last):
  File "/tmp/ipykernel_22954/3616845043.py", line 4, in <module>
    test_func(p1)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py", line 885, in __call__
    result = self._call(*args, **kwds)
tensorflow.python.framework.errors_impl.InvalidArgumentError:  Bad! : Tensor had Inf values
     [[node CheckNumerics (defined at tmp/ipykernel_22954/2241890286.py:5) ]] [Op:__inference_simple_func_131]

Errors may have originated from an input operation.
Input Source operations connected to node CheckNumerics:
 input_arg (defined at tmp/ipykernel_22954/3616845043.py:4)

Function call stack:
simple_func

tf.debugging.check_numerics genera un errore di argomento non valido a causa dell'argomento Inf in test_func .

Abilita l'ottimizzatore debug stripper ed esegui di nuovo la funzione.

with options({'debug_stripper': True}):
  test_func2 = test_function_2()
  p1 = tf.constant(float('inf'))
  try:
    test_func2(p1)
  except tf.errors.InvalidArgumentError as e:
    traceback.print_exc(limit=2)

L'ottimizzatore debug stripper rimuove il nodo tf.debug.check_numerics dal grafico ed esegue la funzione senza generare errori.

Riepilogo

Il runtime TensorFlow utilizza Grappler per ottimizzare automaticamente i grafici prima dell'esecuzione. Utilizzare tf.config.optimizer.set_experimental_options per abilitare o disabilitare i vari ottimizzatori di grafici.

Per ulteriori informazioni su Grappler, vedere Ottimizzazioni del grafico TensorFlow .