Você está em uma entrevista para Engenheiro de ML no Google. Entrevistador: Precisamos treinar um LLM em 1.000 GPUs. Como você garantiria que todas as GPUs compartilhem o que aprendem? Você: Use um servidor central de parâmetros para agregar e redistribuir os pesos. Entrevista encerrada. Aqui está o que você perdeu:
Um grande gargalo de tempo de execução no treinamento de várias GPUs ocorre durante a sincronização da GPU. Por exemplo, no treinamento de várias GPUs por meio do paralelismo de dados: - O mesmo modelo é distribuído para diferentes GPUs. - Cada GPU processa um subconjunto diferente de todo o conjunto de dados. Verifique isso 👇
Isso leva a diferentes gradientes entre diferentes dispositivos. Então, antes de atualizar os parâmetros do modelo em cada dispositivo GPU, precisamos comunicar os gradientes para todos os outros dispositivos para sincronizá-los. Vamos entender 2 estratégias comuns a seguir!
Algoritmo 1) All-reduce Uma maneira óbvia é enviar os gradientes de um dispositivo para todos os outros dispositivos para sincronizá-los. Mas isso consome alta largura de banda. Se toda GPU tiver "N" elementos e houver "G" GPUs, isso resulta em uma transferência total de elementos G*(G-1)*N 👇
Podemos otimizar isso transferindo todos os elementos para uma GPU, calculando o valor final e enviando de volta para todas as outras GPUs. Isso é uma melhoria significativa. Mas agora uma única GPU precisa receber, calcular e comunicar de volta os gradientes, então isso não escala.
Algoritmo 2) Redução em anel Fase #1) Redução de participação Primeiro, gradientes são divididos em segmentos G em cada GPU (G = número total de GPUs). Veja isso 👇
Em uma iteração, cada GPU envia um segmento para a próxima GPU: - GPU1 envia a₁ para GPU2, onde é adicionado a b₁ - GPU2 envia b₂ para GPU3, onde é adicionado a c₂ - GPU3 envia c₃ para GPU4, onde é adicionado a d₃ - GPU4 envia d₄ para GPU1, onde é adicionado a a₄ Veja isso 👇
Esse processo é feito novamente: - GPU1 envia (d₄+a₄) para GPU2, onde é adicionado a b₄. - GPU2 envia (a₁+b₁) para GPU3, onde é adicionada a c₁. - GPU3 envia (b₂+c₂) para GPU4, onde é adicionado a d₂. - GPU4 envia (c₃+d₃) para GPU1, onde é adicionado a a₃. Veja isso 👇
Na iteração final, os segmentos a seguir são transferidos para a próxima GPU. Isso leva a um estado em que cada GPU tem um segmento inteiro e podemos transferir esses segmentos completos para todas as outras GPUs. Verifique isso 👇
Fase #2) Apenas compartilhamento Agora que cada GPU tem um segmento inteiro, podemos transferir esses segmentos completos para todas as outras GPUs. O processo é realizado de forma semelhante ao que discutimos acima, então não vamos entrar em detalhes completos. A Iteração 1 é mostrada abaixo👇
Em seguida, realizamos as iterações 2 e 3. Essas atividades são realizadas de forma semelhante ao que aprendemos na Fase 1. Veja isso 👇
E aí está! Os pesos dos modelos entre as GPUs foram sincronizados. Embora o total de elementos transferidos ainda seja o mesmo que tínhamos na abordagem "mestre de GPU única", essa abordagem em anel é muito mais escalável, pois não coloca toda a carga em uma única GPU. Veja isso 👇
Por padrão, modelos de deep learning utilizam apenas uma GPU para treinamento, mesmo que várias GPUs estejam disponíveis. Uma maneira ideal de treinar modelos é distribuir a carga de trabalho de treinamento entre múltiplas GPUs. O gráfico mostra quatro estratégias para treinamento👇 multi-GPU
364,84K