GPU Computing

Com o crescente frenesi em torno de assuntos como Inteligência artificial, Machine learning e Deep learning, temos um grande astro neste cenário que tem trazido agilidade e maior poder de processamento de grandes Datasets e treinos de redes neurais cada vez mais profundas, as unidades de processamento gráfico (Graphical process units) popularmente conhecida apenas como GPU.

Quando falamos de GPU geralmente temos este termo associado a computadores mais voltados para jogos e supercomputadores, mas a cada dia cresce a utilização de GPUs para processamento de modelos analíticos de big data, Machine learning e em especial Deep

Foi observado que GPUs poderiam acelerar o processamento de cálculos matemáticos que necessitam de computação intensiva, e desta forma a Nvidia criou GPUs para uso geral, junto com a linguagem CUDA, passando a utilizar as GPUs para processamento de dados com CUDA atuando em conjunto com frameworks.

Um software pode ser mais veloz sendo processado em uma GPU que em uma CPU e com custos de utilização e energia menores. A arquitetura de uma CPU é composta de vários cores e memória cache e tratam threads uma por vez, as GPUs possuem uma arquitetura com milhares de cores que tratam milhares de threads utilizando paralelismo.

A forma mais fácil de entender essas diferenças é comparar o modo que elas processam as tarefas. Uma CPU possui núcleos otimizados para processamento serial sequencial, enquanto que uma GPU tem uma arquitetura paralela gigantesca que consiste em milhares de núcleos menores e mais eficientes criados para lidar com múltiplas tarefas de forma simultânea.

Veja o exemplo na imagem abaixo

 

http://www.nvidia.com.br/object/what-is-gpu-computing-br.html

GPGPU

A computação de propósito geral em unidade de processamento gráfico também conhecido como GPGPU, reconhece que existe uma tendência de uso de GPUs para aplicações não gráficas.

Até meados de 2006 a api gráfica OpenGL e directX eram as únicas formas de programar usando GPU, o que limitava o processo. Há diversas razões que levaram Deep Learning ao patamar que temos hoje e ainda está em constante desenvolvimento, mas certamente um deles é o poder computacional de processamento obtido com uso de GPUs, o que reduz significativamente o tempo e o resultado obtido com redes neurais profundas, uma vez que quanto maior a complexidade da rede, maior é o requerimento de poder computacional.

A computação acelerada por GPU nada mais é do que o uso da unidade de processamento gráfico atuando em conjunto com as CPUs, basicamente a GPU recebe da aplicação o que necessita de maior uso de computação, como pode ser visto na imagem abaixo.

 

Podemos notar na imagem abaixo a divisão entre componentes entre unidades de processamento gráfico GPU e unidades de processamento central CPU, observe o porquê da GPU ter maior agilidade em processamento multi thread altamente paralelizado, pois a mesma utiliza muito mais núcleos que uma CPU.

Quase todo espaço de uma GPU é destinado a ALU (Aritmetic Logical unit), cache e controle, o que a torna mais adequada para cálculos repetitivos em grandes massas de dados.

CUDA

CUDA é uma plataforma de computação paralela e desenvolvimento desenvolvido pela NVIDIA, para prover ganhos em performance e maior aproveitamento da unidade de processamento gráfico GPU.

Com as dificuldades e limitações de programar utilizando GPUs com linguagens de programação gráfica, sabia se que um hardware extremamente rápido deveria ser combinado com uma ferramenta intuitiva entre hardware e software. Com esta junção de hardware e software a NVIDIA em 2006 apresentou a CUDA, a primeira solução para computação de propósitos geral em GPUs.

Com a utilização da CUDA é possível gerenciar memória e threads da GPU tornando a experiencia muito mais proveitosa, uma vez que você poderá extrair todo potencial de sua GPU.

Hoje a forma mais fácil de desenvolver seus códigos aproveitando a performance das GPUs é utilizando o CUDA Toolkit, ambiente para desenvolvimento em C e C++, Python, inclusive existe um ambiente chamado PyCuda desenvolvido exclusivamente para desenvolvimento de aplicações em Python para aplicações desenvolvidas para GPU.

O CUDA Toolkit possui compilador, bibliotecas matemáticas, ferramentas de depuração e otimização de performance, além do Nvidia Parallel Nsight for Visual Studio, ambiente de desenvolvimento para aplicativos de processamento massivo que utilizam CPUs e GPUs, e tudo isso oferecido de forma gratuita.

Uma GPU CUDA oferece diversos novos componentes projetados para uso de computação em GPU e destinados a acabar com as limitações.

Observe a área destinada a execução paralela em cache na arquitetura atual.

Programação em GPU’s

Para que haja um entendimento de como funciona a programação utilizando CUDA, devemos entender alguns conceitos. O fluxo de processamento em CUDA não é tão complexo, os inputs dos dados são copiados da memória principal para a unidade de processamento gráfico, em seguida o processador aloca processo para a GPU, que executa as tarefas simultaneamente em seus núcleos e depois é feito o caminho inverso, ou seja, da memória da GPU para a memória principal. Todo esse processamento é realizado dentro dos núcleos CUDA, os CUDA Cores, que podem ser comparados a núcleos de um processador comum.

O comportamento das threads pode ser controlado via código, utilizando TensorFlow podemos com poucas alterações definir como será processado cada thread.

No TensorFlow os dispositivos suportados são apresentados da seguinte forma:

/cpu:0 – CPU da maquina

/gpu:0 – GPU da máquina (caso seja apenas uma)

/gpu:1 – Segunda GPU da maquina

/gpu:2 – Terceira GPU da máquina e daí por diante.

Para definir um código a ser executado na GPU, podemos usar tf. device(‘/gpu:0’)

Para descobrir quais dispositivos nossas operações e tensores são atribuídos criaremos uma sessão com o parâmetro log_device_placement definido como true.

log_device_placement = True

 

Veja um exemplo da criação de uma função para multiplicar matrizes definindo para ser executada em GPU.

with tf.device(‘/gpu:0’): # Para executar na CPU, utilize /cpu:0

    a = tf.placeholder(tf.float32, [10000, 10000])

    b = tf.placeholder(tf.float32, [10000, 10000])

    c1.append(matpow(a, n))

    c1.append(matpow(b, n))

Estou executando um código que realiza a multiplicação de duas matrizes, e através da instrução log_device_placement saberemos em qual dispositivo nossos tensores serão atribuídos, e com a função tf.device  do TensorFlow indicarei em que dispositivo a multiplicação deve ocorrer, a primeira execução será realizada em CPU e a segunda em GPU, faremos o comparativo de tempo de execução.

Na maquina que foi executado este teste há uma GPU GeForce GTX e o tensorflow instalado em sua versão apropriada para GPU, juntamente com os requisitos necessários, cudaDNN e CUDA ToolKit.

 

Vejamos a primeira execução em CPU.

Veja o tempo de execução em CPU. 07:15 Minutos.

Agora vejamos a execução em GPU.

Tempo de execução em GPU 01:05 Minuto.

 

Conclusão

Veja porque este é um dos principais motivos que tem levado ao crescimento de Deep Learning e a resultados cada vez mais expressivos, o tempo de processamento é muito superior, claro que estes recursos devem ser explorados no desenvolvimento do código. Sua aplicação, seu modelo de Deep Learning deve ser desenvolvido pensando nestes recursos para se beneficiar de todo esse poder de processamento.

About Leandro Romualdo

Cientista de dados na Ngr Solutions.