Deep Learning Distribuído com Horovod
Deep Learning já era rápida e eficiente para o processamento de muitos dados e redes complexas, porém, parece que quanto maior a solução mais se abrem portas para explorar seus limites. Neste artigo, eu vou te apresentar o que é Deep Learning Distribuído, as principais estratégias sendo desenvolvidas para isso, e te explicar passo-a-passo de como utilizar o Horovod, o framework mais popular, criado pela Uber e querido por várias empresas. Uma ferramenta fácil de usar e que pode te permitir executar seus treinamentos ainda mais rápido!
Deep Learning Distribuído
Utilizar múltiplas GPUs para executar os seus programas é essencial para resolver problemas em Deep Learning que lidam com muitos dados ou redes neurais artificiais com muitas camadas. Além disso, com mais facilidade para ter acesso a diversos recursos computacionais nos últimos anos, com serviços de nuvem como AWS, Google Cloud e Microsoft Azure, profissionais em Deep Learning e Inteligência Artificial podem acelerar ainda mais o treinamento de suas redes.
A estratégia para usar várias GPUs ao seu favor se chama Computação Paralela e Distribuída (CPD), e consiste basicamente em dividir o seu problema em subproblemas independentes e processar eles ao mesmo tempo, em paralelo. As principais estratégias de CPD em Deep Learning são:
Paralelismo de dados: consiste em dividir o dataset e distribuir um pedaço para cada GPU. Cada GPU deverá ter uma cópia do modelo da rede e, ao final de cada época, todos os gradientes obtidos em cada GPU são calculados em conjunto para atualização dos pesos de sua rede. Recomendado para treinos com muitos dados que possam extrapolar a memória das GPUs.
Paralelismo de modelo: consiste em dividir o modelo de rede neural entre as GPUs, assim cada dispositivo vai processar algumas das camadas da sua rede em paralelo. Essa é uma abordagem mais complexa pois exige maior sincronização e balanceamento de carga dividida para que nenhuma GPU trabalhe muito mais do que outra. Recomendado para treinos com redes muito profundas.
Paralelismo de camadas: o mais complexo de todos, que visa inserir computação nos intervalos entre operações, quando há comunicação entre os processos e a GPU em si não está sendo utilizada. Por exemplo, enquanto uma GPU está trocando dados com outras, outra GPU está processando a fase de forward propagation. Recomendada para atingir ainda melhor desempenho sobre as outras técnicas.
Híbrido: uma combinação de um ou mais técnicas acima.
Horovod
Horovod é uma biblioteca de código aberto escrita em C++ e Python desenvolvida pela Uber em 2017, e hoje faz parte da Linux Foundation. Além do próprio Uber, a ferramenta é utilizada por Amazon, IBM, NVIDIA, Alibaba e todas essas big empresas que precisam processar treinamento de redes neurais artificiais em larga escala.
O Horovod surgiu para facilitar a vida de profissionais em Deep Learning, buscando oferecer um framework “low-code”, ou seja, com pouco código, mas que vai te permitir avançar bastante no seu trabalho na área. Ele vai atuar como uma “capa de desempenho” sobre o seu modelo usual implementado com TensorFlow, Keras, PyTorch ou Apache MXNET. O Horovod funciona com GPUs e CPUs.
Algoritmos
Horovod utiliza paralelismo de dados implementando o algoritmo de comunicação em anel ring-all-allreduce. Ele consiste em executar várias cópias do script de treinamento de sua rede em diferentes GPUs, onde cada GPU vai ler um pedaço do dataset de treinamento, executar o modelo de sua rede sobre esses dados e computar os gradientes, que vão ser usados para otimizar a sua rede. Os gradientes calculados na rede são processados em diferentes GPUs e ao final são compartilhados entre GPUs para que se possa ter gradientes finais relacionados a todos os dados.
*Uma curiosidade é que o nome “Horovod” vem de uma dança russa com o mesmo nome onde os dançarinos formam uma roda, que se assemelha ao algoritmo de anel utilizado.
Instalação (Linux)
Você pode instalar como um pacote Python usando pip para um framework de Deep Learning específico ou para todos. Saiba mais aqui. Exemplo com TensorFlow:
$ HOROVOD_WITH_TENSORFLOW=1 pip install horovod[tensorflow]
ou você pode instalar por linha de comando através do repositório oficial disponível aqui.
Verifique que foi instalado corretamente utilizando:
$ pip list | grep horovod
Instale alguma distribuição do MPI (Message Passing Interface). É ele quem vai permitir que o Horovod troque informações entre GPUs na rede, inclusive entre GPUs em diferentes nós computacionais. Você vai precisar ter um compilador GCC instalado.
Verifique se você tem GCC:
$ gcc –version
Caso o comando não retorne nada, ele precisará ser instalado com o simples comando:
$ sudo apt install build-essential
Instale OpenMPI (leva algum tempinho):
$ wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.4.tar.gz
$ tar -xvf openmpi-4.1.4.tar.gz
$ cd openmpi-4.1.4/
$ ./configure –prefix=/usr/local
$ sudo make all install
Verifique que foi instalado corretamente com:
$ mpirun –version
Primeiros passos (com TensorFlow)
Instale o TensorFlow
$ pip install tensorflow
A maior vantagem de usar o Horovod para distribuir o treinamento de sua rede para várias GPUs é a facilidade que a ferramenta te permite fazer isso. Com poucas linhas de código, o Horovod vai fazer tudo para você por “debaixo dos panos”. Vamos lá?
Mude o seu código Python para adicionar as operações do Horovod:
# Importe a biblioteca
import horovod.tensorflow.keras as hvd
# Inicialize o Horovod
hvd.init()
# Verifique se há GPUs disponíveis e distribua um processo por GPU
gpus = tf.config.experimental.list_physical_devices(’GPU’)
if gpus:
tf.config.experimental.set_visible_devices(gpus[hvd.local_rank()], ’GPU’)
# Verifique se todas GPUs foram encontradas
print("Eu sou a GPU: ", hvd.rank())
…
# Defina o modelo de sua rede aqui usando Keras!
…
model = keras.models.Model.from_config(model_config)
# Estou usando o otimizador SGD, mas você pode usar o que quiser. Uma dica aqui é escalar a taxa de aprendizagem da rede (learning_rate) de acordo com o número de GPUs utilizadas (hvd.size())
opt = keras.optimizers.SGD(learning_rate=args.learning_rate * hvd.size())
# Adicione o otimizador de distribuição de Deep Learning do Horovod, que vai “embrulhar” o otimizador do Keras para aplicar paralelismo de dados
opt = hvd.DistributedOptimizer(opt)
# Compile o seu modelo de rede utilizando o otimizador do Horovod
model.compile(optimizer = opt, … )
# Envie os estados iniciais das variáveis do seu programa para que todos processos tenham acesso
callbacks = [hvd.callbacks.BroadcastGlobalVariablesCallback(0),]
...
# Implemente o treinamento da sua rede normalmente!
# Uma dica é dividir o número de interações do seu treinamento com o número de GPUs utilizadas, para você garantir que seu treino escale bem para mais dispositivos. Eu fiz isso para a etapa de treino e de validação.
model.fit(train_iter,
steps_per_epoch=len(train_iter) // hvd.size(),
callbacks=callbacks,
epochs=args.epochs,
verbose=verbose,
workers=args.my_workers,
use_multiprocessing = False,
validation_data=test_iter,
validation_steps = 3 * len(test_iter) // hvd.size())
Agora, basta executar o seu treinamento de sua rede:
$ horovodrun -np 2 python script.py
O parâmetro np vai definir o número de processos em paralelo que o Horovod vai executar. Ou seja, o número de GPUs que você tem no seu sistema. Você também pode executar diretamente com o comando do OpenMPI:
$ mpirun -np 2 python script.py
Executar com um ou outro não vai fazer diferença no desempenho de sua aplicação. Para a lista de todos os parâmetros disponíveis você pode usar:
$ horovodrun –help
Horovod Timeline
Esta é a ferramenta nativa do Horovod para analisar o perfil de execução de sua aplicação. Afinal, se estamos usando computação distribuída queremos saber se estamos de fato tirando vantagem de todos processadores utilizados.
Visualização do perfil de execução do seu treinamento gerado com o Horovod Timeline.
Para utilizar, basta executar com o parâmetro para coleta do perfil de execução:
$ horovodrun -np 2 — timeline-filename nome_do_arquivo_de_saida.json python script.py
Esse comando vai garantir que ao final da execução você tenha um arquivo em formato JSON que você pode visualizar no Google Chrome, usando o Tracing Viewer, acessando “chrome://tracing viewer” e importando o seu arquivo local.
Ele mostra a linha do tempo de execução de sua rede e as operações que foram chamadas, tudo em uma visualização interativa onde você pode arrastar, dar zoom e selecionar partes da execução. Ao selecionar, irá abrir um painel com o resumo de desempenho naquele intervalo de execução, como número de chamadas e tempo de execução de cada operação. Com essa visualização você pode, por exemplo, garantir que o seu treinamento está utilizando todas as GPUs corretamente.
Conclusão:
Em um futuro com cada vez mais poder computacional para ser utilizado, o Horovod é sem dúvidas uma ferramenta que chegou para ficar. Se você trabalha com Deep Learning e/ou tem interesse em Computação de Alto Desempenho, sugiro muito investir umas horinhas para aprender mais sobre essa ferramenta e usar ela a seu favor. Minha dica é que você comece a distribuir uma rede simples como MNIST, fashion MNIST e ResNet-50.
Gostou do conteúdo? Se tiver alguma dúvida, deixa aqui nos comentários que vou ficar feliz em ajudar.
Referências:
- Documentação: https://horovod.readthedocs.io/
- Artigo oficial: https://arxiv.org/abs/1802.05799
- Notícia de lançamento no site da Uber: https://eng.uber.com/horovod/
- Exemplos de uso do Horovod para diferentes frameworks: https://github.com/horovod/horovod/tree/3f08a1a872a46f62639a9d660e66ce41e042f206/examples
A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.