Pubblicato da Alex Wiltschko, Dan Moldovan, Wolff Dobson
Oggi vorremmo presentare la nuova funzionalità di TensorFlow chiamata "AutoGraph". AutoGraph converte il codice Python, tra cui il flusso di controllo, print() e altre funzionalità native di Python, in puro codice grafico TensorFlow.
Scrivere il codice TensorFlow senza utilizzare Eager Execution significa eseguire un po' di metaprogrammazione, ossia scrivere un programma che crea un grafico che a sua volta viene eseguito successivamente. Ciò può creare confusione, specialmente per gli sviluppatori nuovi. In particolare in alcune situazioni difficili che riguardano i modelli più complessi, come quelli che usano if e while o quelli che hanno effetti collaterali come print() o accettano input strutturati.
Abbiamo davvero bisogno di grafici? I grafici consentono tutti i tipi di ottimizzazioni, come la rimozione di espressioni secondarie comuni e la fusione dei kernel. Inoltre, semplificano l'addestramento distribuito e l'implementazione in tutti i tipi di ambienti, poiché formano un modello di calcolo indipendente dalla piattaforma. Questo è particolarmente importante per l'addestramento distribuito su GPU o TPU multiple o per la distribuzione del modello su altre piattaforme, come IoT o mobile tramite TensorFlow Lite.
Ecco un esempio semplice di un'operazione che forse potresti aggiungere al tuo grafico:
def huber_loss(a): if tf.abs(a) <= delta: loss = a * a / 2 else: loss = delta * (tf.abs(a) - delta / 2) return loss
Con Eager Execution, l'esempio "funzionerà abbastanza bene" ma le operazioni potrebbero essere lente a causa dei costi generali dell'interprete Python o delle opportunità mancate di ottimizzazione dei programmi.
Per prepararci all'esecuzione del grafico, bisogna riscrivere il codice usando costrutti come tf.cond(), ma ciò può rivelarsi oneroso e difficile da implementare. AutoGraph può effettuare automaticamente questa conversione mantenendo la facilità di programmazione Eager e sfruttando al tempo stesso i vantaggi prestazionali dell'esecuzione basata su grafici.
Nell'esempio possiamo assegnare autograph.convert() alla nostra funzione in modo che AutoGraph generi automaticamente il codice pronto per il grafico.
Utilizzando AutoGraph, il codice:
@autograph.convert() def huber_loss(a): if tf.abs(a) <= delta: loss = a * a / 2 else: loss = delta * (tf.abs(a) - delta / 2) return loss
diventa questo codice in fase di esecuzione a causa dell'elemento Decorator.
def tf__huber_loss(a): with tf.name_scope('huber_loss'): def if_true(): with tf.name_scope('if_true'): loss = a * a / 2 return loss, def if_false(): with tf.name_scope('if_false'): loss = delta * (tf.abs(a) - delta / 2) return loss, loss = ag__.utils.run_cond(tf.less_equal(tf.abs(a), delta), if_true, if_false) return loss
Puoi quindi chiamare il tuo codice come se fosse un op TensorFlow:
with tf.Graph().as_default(): x_tensor = tf.constant(9.0) # The converted function works like a regular op: tensors in, tensors out. huber_loss_tensor = huber_loss(x_tensor) with tf.Session() as sess: print('TensorFlow result: %2.2f\n' % sess.run(huber_loss_tensor))
È da notare che AutoGraph colma il divario tra Eager Execution e i grafici. Prende il codice Python in stile Eager e lo converte in codice che genera grafici.
AutoGraph non è una semplice raccolta di macro utili: è uno strumento che usa la trasformazione del codice sorgente per consentire di sovrascrivere qualsiasi parte del linguaggio Python, inclusi controllo del flusso, applicazione della funzione, assegnazione, generazione di codice boilerplate e refactoring di Python idiomatico, per semplificare la trasformazione in grafici.
Una delle problematiche dei compilatori è la leggibilità dei messaggi di errore. A tal fine, AutoGraph è impostato per creare messaggi di errore e tracce di stack che rivelano la fonte dell'errore nel codice sorgente originale piuttosto che mostrare solo riferimenti al codice generato.
Come può aiutarti AutoGraph? Ecco alcuni esempi di codice che ora puoi trasformare direttamente in codice di grafico senza alcuna modifica. Per scoprire come funziona, consulta il nostro notebook in Colab o in GitHub.
Qui vediamo la Congettura Collatz che usa loop e rami. Nota che, per cambiare, al posto dell'elemento Decorator usiamo la funzione di AutoGraph .to_graph() che lo trasforma in grafico.
def collatz(a): counter = 0 while a != 1: if a % 2 == 0: a = a // 2 else: a = 3 * a + 1 counter = counter + 1 return counter graph_mode_collatz = autograph.to_graph(collatz) # The code is human-readable, too print(autograph.to_code(collatz)) collatz_tensor = graph_mode_collatz(tf.constant(n))
AutoGraph può supportare flussi di controllo annidati arbitrari, come ad esempio:
def f(n): if n >= 0: while n < 5: n += 1 print(n) return n
AutoGraph consente di aggiungere elementi agli array all'interno dei loop. Per eseguire questa operazione, usiamo gli helper di AutoGraph, set_element_type e stack.
def f(n): z = [] # We ask you to tell us the element dtype of the list autograph.set_element_type(z, tf.int32) for i in range(n): z.append(i) # when you're done with the list, stack it # (this is just like np.stack) return autograph.stack(z)
Supportiamo anche costrutti come break, continue e persino print e assert. Terminata la conversione, l'assert Python di questo snippet viene convertito in un grafico che utilizza l'appropriato tf.Assert.
def f(x): assert x != 0, 'Do not pass zero!' return x * x
Aggiungere facilmente ai grafici i loop, controllare il flusso e altro, significa che spostare il ciclo di addestramento nel grafico è semplice. Possiamo vederne un esempio in questo notebook dove prendiamo un ciclo di addestramento RNN e lo eseguiamo con una singola chiamata sess.run(). Questa operazione potrebbe essere utile quando è necessario passare l'intero loop di addestramento all'acceleratore, piuttosto che gestire l'addestramento tramite un controller della CPU.
AutoGraph offre nuovi modi di pensare alla creazione e all'addestramento dei modelli. Non vediamo l'ora di aggiungere ulteriori funzionalità ad AutoGraph in base ai suggerimenti della community degli sviluppatori, quindi ti preghiamo di segnalarci qualsiasi problema!
Eager execution è di facile utilizzo ma i grafici possono essere più veloci. Sebbene il benchmarking sia complesso (e dipende sia dall'applicazione che dalla configurazione hardware), in questo semplice esempio vediamo un significativo aumento della velocità quando passiamo dal codice Eager a quello AutoGraph, che fa grande uso di if e while.
In definitiva, AutoGraph consente di utilizzare i modelli dinamici e con controllo del flusso sull'hardware dell'acceleratore, come GPU e TPU Cloud, necessari quando addestriamo modelli di grandi dimensioni su molti dati.
Siamo agli inizi del processo di esplorazione delle prestazioni, quindi segnalaci qualsiasi problema se trovi un costrutto grafico che funziona più lentamente del previsto.
Anche se utilizzi Eager Execution, puoi comunque sfruttare l'esecuzione di grafici per alcune parti del codice tramite tf.contrib.eager.defun. Ciò richiede l'utilizzo di grafici TensorFlow ops come tf.cond(). In futuro AutoGraph sarà perfettamente integrato con defun per consentire la creazione del codice di grafico in puro Python stile Eager. Una volta completata l'implementazione, potrai utilizzare AutoGraph per accelerare gli hotspot trasformando selettivamente il codice Eager in frammenti di grafici.
AutoGraph è uno strumento che consente di creare facilmente modelli intuitivi e complessi, eseguibili senza difficoltà nei grafici TensorFlow. Per ora questo è uno strumento sperimentale in contrib, ma prevediamo di spostarlo presto nel core TensorFlow.
Raccontaci la tua esperienza con AutoGraph. Segnalaci qualsiasi problema e, se hai feedback, suggerimenti o idee, invia i tuoi messaggi al gruppo degli sviluppatori TensorFlow.
Ringraziamenti
Vogliamo ringraziare in modo particolare Andrew Johnson, Bart van Merriënboer, Zachary Nado e Alex Passos per il contributo fondamentale. E anche ringraziare i nostri colleghi: Akshay Agrawal, Mark Daoust, Josh Levenberg, Dougal Maclaurin, Rajat Monga, Mahima Pushkarna, Alexey Radul, D. Sculley e Asim Shankar.