Passa al contenuto principale

TensorFlow™ su Databricks

Illustration

Utilizzo della GPU

La GPU (Graphical Processing Unit) è un componente presente nella maggior parte dei computer moderni, progettato per eseguire i calcoli necessari alla grafica 3D. Il suo uso principale è l'esecuzione dei calcoli necessari per posizionare correttamente le forme nei videogame, in modo che il giocatore possa visualizzare il gioco. Banalizzando molto, una GPU è fondamentalmente una serie di piccoli processori (CPU) che eseguono calcoli altamente parallelizzati. In pratica è come avere a disposizione un mini-supercomputer*!

Ogni singola CPU presente in una GPU è piuttosto lenta, ma il loro numero è elevato e sono tutte specializzate in elaborazioni numeriche. Questo significa che una GPU può eseguire simultaneamente molti compiti di calcolo semplici. Fortuna vuole che questo sia esattamente ciò di cui molti algoritmi di machine learning hanno bisogno.

Non hai una GPU?

La maggior parte dei computer moderni (almeno degli ultimi 10 anni) ha qualche tipo di GPU, magari integrata nella scheda madre. Ai fini di questo tutorial, è sufficiente.

Bisogna conoscere il tipo di scheda grafica installato. Gli utenti di Windows possono seguire queste istruzioni mentre chi usa altri sistemi operativi dovrà consultare la documentazione del sistema in questione.

Utenti di schede grafiche diverse da Nvidia

Anche se possono essere supportate altre schede grafiche, questo tutorial è stato testato solo su una scheda grafica NVidia recente. Se hai una scheda grafica di altro tipo, ti raccomando di procurarti una scheda grafica NVidia (acquistandola o prendendola in prestito) per svolgere questa esercitazione. Se non hai questa possibilità, rivolgiti a una scuola o un'università della tua zona e chiedi se ti possono aiutare. Se proprio non trovi una scheda Nvidia, continua pure a leggere e svolgi il tutorial su una normale CPU. Potrai comunque mettere in pratica quanto imparato in un secondo tempo.

* Nota bene: non si tratta veramente di un supercomputer, ma è simile per molti aspetti.

Installare TensorFlow con abilitazione per la GPU

Se non hai ancora installato TensorFlow con abilitazione per la GPU, è necessario compiere prima questa operazione. Le istruzioni fornite nella Lezione 1 non specificavano questo aspetto; pertanto, se non hai abilitato il supporto GPU di tua iniziativa, devi farlo ora.

A tale scopo ti consiglio di creare un nuovo ambiente Anaconda invece di provare ad aggiornare quello precedente.

Prima di cominciare

Vai alle istruzioni ufficiali per l'installazione di TensorFlow e segui le indicazioni per l'installazione di Anaconda. La differenza principale fra questa procedura e quella eseguita nella Lezione 1 è che ti serve la versione di TensorFlow con abilitazione per la GPU per il tuo sistema operativo. Tuttavia, prima di installare TensorFlow in questo ambiente, è necessario configurare il computer per abilitare la GPU con CUDA e CuDNN. La documentazione ufficiale di TensorFlow descrive questo processo in modo dettagliato, ma se devi configurare un'installazione Ubuntu recente, ti consiglio di guardare questo tutorial.  Il motivo principale è che, a oggi (luglio 2016), CUDA non è stato ancora aggiornato alla versione più recente di Ubuntu e, quindi, il processo è molto più manuale.

Utilizzare la propria GPU

È veramente molto semplice, almeno per quanto riguarda la sintassi. Basta modificare questo codice...

 

# Setup operations

with tf.Session() as sess:
    # Run your code

 

...con questo codice:

 

with tf.device("/gpu:0"):
    # Setup operations

with tf.Session() as sess:
    # Run your code

 

La nuova riga creerà un nuovo gestore di contesto, dicendo a TensorFlow di eseguire quelle azioni sulla GPU.

Vediamo un esempio concreto. Il codice successivo crea una matrice casuale con determinate dimensioni sulla riga di comando. Possiamo eseguire il codice sulla CPU o sulla GPU usando le opzioni della riga di comando:

 

import sys
import numpy as np
import tensorflow as tf
from datetime import datetime

device_name = sys.argv[1]  # Choose device from cmd line. Options: gpu or cpu
shape = (int(sys.argv[2]), int(sys.argv[2]))
if device_name == "gpu":
    device_name = "/gpu:0"
else:
    device_name = "/cpu:0"

with tf.device(device_name):
    random_matrix = tf.random_uniform(shape=shape, minval=0, maxval=1)
    dot_operation = tf.matmul(random_matrix, tf.transpose(random_matrix))
    sum_operation = tf.reduce_sum(dot_operation)


startTime = datetime.now()
with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as session:
        result = session.run(sum_operation)
        print(result)

# It can be hard to see the results on the terminal with lots of output -- add some newlines to improve readability.
print("\n" * 5)
print("Shape:", shape, "Device:", device_name)
print("Time taken:", datetime.now() - startTime)

print("\n" * 5)

 

L'azione può essere eseguita sulla riga di comando con:

python matmul.py gpu 1500

In questo modo si utilizzerà la GPU con una matrice che misura 1500 al quadrato. Il codice qui sotto esegue la stessa operazione sulla CPU:

python matmul.py cpu 1500

La prima cosa che si nota quando si esegue un codice sulla GPU è un notevole incremento della produttività (output) rispetto a un normale script di TensorFlow. Ecco che cosa stampa il mio computer, prima di stampare qualsiasi risultato delle operazioni.

 

I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcudnn.so.5 locally
I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcurand.so locally
I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:925] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
I tensorflow/core/common_runtime/gpu/gpu_init.cc:102] Found device 0 with properties: 
name: GeForce GTX 950M
major: 5 minor: 0 memoryClockRate (GHz) 1.124
pciBusID 0000:01:00.0
Total memory: 3.95GiB
Free memory: 3.50GiB
I tensorflow/core/common_runtime/gpu/gpu_init.cc:126] DMA: 0 
I tensorflow/core/common_runtime/gpu/gpu_init.cc:136] 0:   Y 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:838] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 950M, pci bus id: 0000:01:00.0)

 

Se il codice non produce un output simile a questo, significa che non stai utilizzando TensorFlow abilitato per la GPU. Oppure, se ottieni un errore come ImportError: libcudart.so.7.5: cannot open shared object file: No such file or directory, significa che non hai installato correttamente la libreria CUDA. In questo caso riprendi le istruzioni per installare CUDA sul tuo sistema operativo.

Prova a eseguire il codice precedente sia sulla CPU, sia sulla GPU, aumentando il numero gradualmente. Comincia con 1500, poi prova 3000, poi 4500, e così via. Vedrai che la CPU comincerà a impiegare molto tempo, mentre la GPU è molto, molto veloce con questa operazione!

Se hai più GPU, puoi utilizzare quella che vuoi. Le GPU sono indicizzate a zero: il codice precedente accede alla prima GPU. Cambiando il dispositivo a gpu:1 verrà utilizzata la seconda GPU, e così via. È possibile anche inviare una parte del calcolo a una GPU e una parte a un'altra. Inoltre, si può accedere alle CPU della macchina in modo analogo, usando cpu:0 (o qualsiasi altro numero).

Quali tipi di operazioni è meglio inviare alla GPU?

In generale, se un passaggio del processo può essere definito come "esegui questa operazione matematica migliaia di volte", allora è meglio affidarlo alla GPU. Alcuni esempi sono la moltiplicazione di matrici e il calcolo dell'inverso di una matrice. Molte operazioni elementari con le matrici sono ideali per le GPU. Come regola semplice e generale, le altre operazioni dovrebbero essere svolte sulla CPU.

Cambiare dispositivi e usare le GPU implica anche un costo. Le GPU non hanno accesso diretto alle altre componenti del computer (tranne il display, naturalmente). Per questo motivo, quando si esegue un comando su una GPU, è necessario copiare prima tutti i dati nella GPU e poi svolgere l'operazione, quindi copiare nuovamente il risultato nella memoria principale del computer. TensorFlow gestisce tutto questo "dietro le quinte"; pertanto, il codice risulta semplice, ma il lavoro viene comunque svolto.

Non tutte le operazioni possono essere fatte sulle GPU. Il messaggio di errore successivo indica che si sta provando a svolgere un'operazione non possibile su una GPU:

 

Cannot assign a device to node 'PyFunc': Could not satisfy explicit device specification '/device:GPU:1' because no devices matching that specification are registered in this process;

 

In tal caso si può cambiare manualmente il dispositivo indicando una CPU per svolgere l'operazione, oppure impostare TensorFlow per cambiare automaticamente il dispositivo. Per farlo, basta impostare allow_soft_placement su True nella configurazione, durante il processo di creazione della sessione. Il prototipo appare nel modo seguente:

 

with tf.Session(config=tf.ConfigProto(allow_soft_placement=True)):
    # Run your graph here

 

Consiglio anche di registrare il posizionamento del dispositivo quando si usa la GPU, perché questo agevola l'eliminazione di bug relativi all'utilizzo di diversi dispositivi. Questa operazione stampa l'utilizzo dei dispositivi nel registro, consentendo di verificare quando i dispositivi cambiano e come questo incide sul grafo.

 

with tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)):
    # Run your graph here

 

  1. Imposta il computer per usare la GPU con TensorFlow (oppure fatti prestare un computer se non hai una GPU recente).
  2. Prova ad eseguire gli esercizi precedenti sulla GPU. Quali operazioni possono essere eseguite su una GPU e quali no?
  3. Costruisci un programma che usa operazioni sia sulla GPU, sia sulla CPU. Usa il codice di profilazione che abbiamo visto nella Lezione 5 per stimare l'impatto del trasferimento di dati da e verso la CPU.
  4. Inviami il tuo codice! Mi piacerebbe vedere qualche esempio di codice, come usi TensorFlow ed eventuali trucchi che hai scoperto.