TensorFlow™ no Databricks
Uso de GPU
A GPU (Unidade de Processamento Gráfico) é um componente encontrado na maioria dos computadores modernos, projetado para realizar os cálculos necessários para gráficos 3D. A aplicação mais popular é realizar os cálculos para posicionar corretamente os polígonos para que o jogador possa visualizar o jogo. Simplificando, uma GPU é basicamente uma série de pequenos processadores (CPUs) que executam cálculos altamente paralelizados. Na prática, é como ter um supercomputador* em miniatura à sua disposição!
Cada CPU em uma GPU é bastante lenta, mas elas são muitas, e todas são especializadas em processamento numérico. Isso significa que uma GPU pode executar muitas tarefas simples de computação simultaneamente. Por sorte, muitas vezes é exatamente disso que muitos algoritmos de aprendizado de máquina precisam.
Não tem uma GPU?
A maioria dos computadores modernos (pelo menos dos últimos 10 anos) tem algum tipo de GPU, talvez integrada à placa-mãe. Para os propósitos deste tutorial, isso é suficiente.
Você precisa saber o tipo de placa gráfica instalada. Os usuários do Windows podem seguir estas instruções, enquanto os que usam outros sistemas operacionais precisarão consultar a documentação do sistema em questão.
Usuários de placas gráficas que não são da NVIDIA
Embora outras placas gráficas possam ser compatíveis, este tutorial foi testado apenas em uma placa gráfica NVIDIA recente. Se você tiver outro tipo de placa gráfica, recomendo adquirir uma placa gráfica NVIDIA (comprada ou emprestada) para concluir este tutorial. Se você não tiver essa opção, entre em contato com uma escola ou universidade da sua região e pergunte se eles podem ajudar. Se você realmente não consegue encontrar uma placa NVIDIA, continue lendo e faça o tutorial em uma CPU normal. Em outro momento, você poderá colocar em prática o que aprendeu.
*Observação: não é bem um supercomputador, mas há muitas semelhanças.
Instalação do TensorFlow habilitado para GPU
Se você ainda não instalou o TensorFlow habilitado para GPU, precisará fazer isso primeiro. As instruções fornecidas na Lição 1 não especificavam isso. Portanto, se você não ativou a compatibilidade com GPU por conta própria, precisará fazer isso agora.
Para fazer isso, recomendo criar um novo ambiente Anaconda em vez de tentar atualizar o antigo.
Antes de começar
Vá para as instruções oficiais de instalação do TensorFlow e siga as instruções de instalação do Anaconda. A principal diferença entre este procedimento e aquele realizado na Lição 1 é que você precisa da versão do TensorFlow habilitada para GPU para o seu sistema operacional. Porém, antes de instalar o TensorFlow neste ambiente, você precisa configurar seu computador para habilitar a GPU com CUDA e CuDNN. A documentação oficial do TensorFlow descreve esse processo passo a passo, mas recomendo assistir a este tutorial se estiver configurando uma instalação recente do Ubuntu. A principal razão é que, no momento da redação deste artigo (julho de 2016), o CUDA ainda não foi atualizado para a versão mais recente do Ubuntu e, portanto, o processo é muito mais manual.
Usando sua GPU
É realmente muito simples, pelo menos no que diz respeito à sintaxe. Basta modificar este código:
# Setup operations
with tf.Session() as sess:
# Run your code
Para este:
with tf.device("/gpu:0"):
# Setup operations
with tf.Session() as sess:
# Run your code
A nova linha criará um novo gerenciador de contexto, instruindo o TensorFlow a executar essas ações na GPU.
Vejamos um exemplo concreto. O próximo código cria uma matriz aleatória com certas dimensões na linha de comando. Podemos executar o código na CPU ou GPU usando opções de linha de 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)
A ação pode ser executada na linha de comando com:
python matmul.py gpu 1500
Isso usará a CPU com uma matriz que mede 1.500 quadrados. O código a seguir executa a mesma operação na CPU:
python matmul.py cpu 1500
A primeira coisa que você nota ao executar código na GPU é um aumento notável na saída em comparação com um script normal do TensorFlow. Aqui está o que meu computador imprime, antes de imprimir qualquer resultado de operação.
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 o seu código não produzir uma saída como esta, você não está usando o TensorFlow habilitado para GPU. Ou, se você receber um erro como ImportError: libcudart.so.7.5: cannot open shared object file: No such file or directory
, significa que você não instalou a biblioteca CUDA corretamente. Neste caso, siga as instruções para instalar o CUDA no seu sistema operacional.
Tente executar o código acima na CPU e na GPU, aumentando o número gradualmente. Comece com 1.500, depois tente 3.000, depois 4.500, e assim por diante. Você verá que a CPU vai começar a demorar muito, enquanto a GPU fica muito rápida com esta operação.
Se você tiver várias GPUs, poderá usar a que quiser. GPUs são indexadas em zero: o código acima acessa a primeira GPU. Alterar o dispositivo para gpu:1
usará a segunda GPU e assim por diante. Também é possível enviar parte do cálculo para uma GPU e parte para outra. Além disso, as CPUs da máquina podem ser acessadas de forma semelhante, usando cpu:0
(ou qualquer outro número).
Que tipos de operações devo enviar para a GPU?
Em geral, se uma etapa do processo pode ser definida como “realizar esta operação matemática milhares de vezes”, então é melhor deixar para a GPU. Alguns exemplos são a multiplicação de matrizes e o cálculo do inverso de uma matriz. Muitas operações matriciais elementares são candidatas ideais para GPUs. Como regra simples e geral, outras operações devem ser realizadas na CPU.
Mudar de dispositivo e usar GPUs também tem um custo. As GPUs não têm acesso direto aos demais componentes do computador (exceto a tela, é claro). Por esse motivo, ao executar um comando em uma GPU, você deve primeiro copiar todos os dados para a GPU e depois realizar a operação, depois copiar o resultado de volta para a memória principal do computador. O TensorFlow cuida de tudo isso “nos bastidores”. Portanto, o código é simples, mas o trabalho precisa ser feito.
Nem todas as operações podem ser realizadas em GPUs. A próxima mensagem de erro indica que você está tentando realizar uma operação que não é possível em uma 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;
Neste caso, você pode alterar manualmente o dispositivo indicando uma CPU para realizar a operação ou configurar o TensorFlow para alterar automaticamente o dispositivo. Para fazer isso, basta definir allow_soft_placement
como True
na configuração durante o processo de criação da sessão. O protótipo fica assim:
with tf.Session(config=tf.ConfigProto(allow_soft_placement=True)):
# Run your graph here
Também recomendo registrar o posicionamento do dispositivo ao usar a GPU, pois isso ajuda a eliminar bugs relacionados ao uso de diferentes dispositivos. Isso imprime o uso do dispositivo no registro, permitindo ver quando os dispositivos mudam e como isso afeta o gráfico.
with tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)):
# Run your graph here
- Configure seu computador para usar a GPU com o TensorFlow (ou pegue um computador emprestado se você não tiver uma GPU recente).
- Tente executar as soluções dos exercícios anteriores na GPU. Quais operações podem ser executadas em uma GPU e quais não podem?
- Crie um programa que use operações de GPU e CPU. Use o código de criação de perfil que vimos na Lição 5 para estimar o impacto da transferência de dados de e para a CPU.
- Envie seu código para mim. Adoraria ver alguns exemplos do seu código, como você usa o TensorFlow e todos os truques que descobriu.