O artigo foi escrito por Rakshith Vasudev e John Lockmanm – Laboratório de inovação em IA e HPC em outubro de 2019
Introdução
O Horovod é uma estrutura distribuída de aprendizagem profunda para acelerar o treinamento em diferentes estruturas, como TensorFlow, Keras, Pytorch e MXNet. Ele foi desenvolvido para facilitar o estabelecimento de projetos distribuídos de aprendizagem profunda e acelerá-los com o TensorFlow. O Horovod oferece suporte à paralelização do processo de treinamento. Ele é compatível com o paralelismo de dados e de modelos. Quando um trabalho de treinamento de rede neural que usa o Horovod estiver em execução, essas dicas comuns poderão ser usadas para depurar e ver a melhoria no desempenho.
Descrição
Este artigo usa o CheXNet como exemplo de referência. O CheXNet é um modelo de assistente de radiologia de IA que usa o DenseNet para identificar até 14 patologias em uma imagem específica de raios X do tórax.
- A configuração correta do ambiente pode economizar muito tempo ao tentar depurar problemas de desempenho. Certifique-se de que a versão da GPU da estrutura de deep learning esteja sendo usada. Neste exemplo, a tensorflow-gpu empacotada pelo anaconda está sendo usada.
-
Usar horovodrun ou mpirun com parâmetros de associação poderá gerar ganhos de desempenho. O ideal é que o processo que controla uma GPU seja associado ao soquete da CPU mais próximo. No Dell EMC PowerEdge C4140, a opção ideal seria --map-by socket. Não é necessário especificar nenhuma opção de associação.
A aparência será semelhante a esta:
mpirun --map-by socket -np x python pyfile.py - -pyoptions
- O trabalho deverá ser configurado de modo que um processo de MPI funcione em uma GPU. Se houver mais processos do que o número de GPUs, os processos competirão por recursos de computação e não conseguirão executar o trabalho com bom desempenho. No exemplo anterior, x deverá ser igual ao número de GPUs a ser usado.
-
Para definir um processo por GPU, use o ConfigProto() do tensorflow da seguinte maneira:
config.gpu_options.visible_device_list=str(hvd.local_size())
-
Para verificar o número de processos que usam a GPU, é possível usar o consumo de memória da GPU ‘watch nvidia-smi’. Isso também permite ver o consumo de energia.
Figura 1: Captura de tela do resultado do comando "nvidia-smi" mostrando a utilização de memória, energia e GPU.
- Se o pipeline de dados estiver configurado corretamente e os parâmetros mpirun estiverem corretos, a utilização da GPU excederá 90% de modo consistente assim que o treinamento do modelo iniciar. Quedas ocasionais de 10 a 25% na utilização são aceitáveis, mas serão pouco frequentes.
- Especifique o tamanho do lote de modo que a memória da GPU fique quase cheia, mas limitada, para que não se excedam os requisitos de memória. É importante considerar a maneira como o dimensionamento da taxa de aprendizagem é realizado. No dimensionamento da taxa de aprendizagem, à medida que o número de GPUs aumenta, a taxa de aprendizagem também deve ser multiplicada por um fator proporcional ao número de GPUs. Isso permite a convergência eficaz do modelo. Dessa forma, o número de operações de E/S é reduzido com o ajuste do número máximo de imagens possíveis em uma GPU, sem comprometer a convergência do modelo. Deve-se observar que o dimensionamento da taxa de aprendizagem nem sempre é a melhor solução para melhorar a convergência do modelo em uma configuração de carga de trabalho distribuída.
Para verificar se o dimensionamento da taxa de aprendizagem é necessário:
a) Treine o modelo com e sem o dimensionamento da taxa de aprendizagem em um modo distribuído.
b) Se o modelo sem o dimensionamento da taxa de aprendizagem apresentar desempenho melhor que o do modelo com dimensionamento da taxa de aprendizagem, significa que o dimensionamento não é necessário.
Ao treinar a convergência em particular, ajustar-se ao maior número possível de imagens por lote nem sempre será uma regra obrigatória. Geralmente, há uma compensação entre o tamanho do lote e a convergência (independentemente de o dimensionamento da taxa de aprendizagem ser usado ou não) que o cientista de dados deve ser capaz de decidir com base no caso de uso.
Mais uma vez, é possível observar o consumo de memória da GPU usando ‘watch nvidia-smi’. Neste estudo de caso, o dimensionamento da taxa de aprendizagem não foi usado, pois gerava um modelo melhor com valores de AUC, e o tamanho local de minibatch era 64. É comum ter momentos de warmup, conforme descrito neste documento, quando o dimensionamento da taxa de aprendizagem for usado.
-
Defina os perfis de seus trabalhos usando horovod timeline e nvprof para visualizar quaisquer gargalos que possam ocorrer. É mais provável que o gargalo ocorra devido a uma das seguintes situações:
a) O pipeline de dados do Tf não está configurado corretamente e, portanto, gasta-se muito tempo para preparar os dados enquanto o acelerador está ocioso. Para reparar isso, deve-se corrigir tf pipeline.
Leia este artigo para obter informações sobre como configurar um tf data pipeline.
B) A comunicação pode não estar usando o fabric correto – certifique-se de utilizar InfiniBand. Para ver o uso do fabric, inclua –x NCCL_DEBUG=INFO durante a execução de mpirun, da seguinte maneira:
mpirun -np 8 --map-by socket -x NCCL_DEBUG=INFO python $HOME/models/chexnet/chexnet.py --batch_size=128 --epochs=15
ou use horovodrun , que inclui o –x binding.
- Para implementar a distribuição adequadamente, as GPUs precisam comunicar-se entre si de modo eficaz. Se elas não se comunicarem efetivamente, isso causará um gargalo de comunicação. Para verificar se as GPUs estão se comunicando de maneira ideal, use o seguinte processo:
Primeiro, veja como as GPUs estão se comunicando, usando o -x binding como visto anteriormente no ponto 8b.
Se as GPUs estiverem se comunicando:
1) Dentro do nó de maneira ideal – a aparência será semelhante a esta:
gpu002:1299562:1299573 [0] NCCL INFO Ring 00 : 0[0] -> 1[1] via P2P/IPC
2) Fora do nó de maneira ideal – a aparência será semelhante a esta:
gpu028:149460:149495 [0] NCCL INFO Ring 01 : 16 -> 0 [send] via NET/IB/0
gpu009:164181:164216 [0] NCCL INFO Ring 01 : 12 -> 8 [receive] via NET/IB/0
gpu009:164181:164216 [0] NCCL INFO Ring 01 : 4 -> 8 [receive] via NET/IB/0
A distribuição do trabalho de deep learning pode, muitas vezes, ser desafiadora, principalmente quando o número de nós/GPUs utilizado não se converte efetivamente no desempenho correspondente. Para que se possa aproveitar ao máximo o investimento no acelerador, é importante implementar estas práticas recomendadas:
- Utilizar as opções de associação corretas.
- Avaliar vários processos que não desperdicem a memória da GPU.
- Usar uma abordagem moderna de pipeline.
- Definir os perfis para verificar se as GPUs são usadas em pelo menos 80% do tempo em que o trabalho está em execução.
- Usar as bibliotecas relacionadas ao CUDA mais recentes.