Técnicas para treinar grandes redes neurais PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Técnicas para treinar grandes redes neurais

Técnicas para treinar grandes redes neurais

Grandes redes neurais estão no centro de muitos avanços recentes em IA, mas treiná-las é um difícil desafio de engenharia e pesquisa que requer orquestrar um cluster de GPUs para realizar um único cálculo sincronizado. À medida que os tamanhos dos clusters e dos modelos aumentaram, os profissionais de aprendizado de máquina desenvolveram uma variedade cada vez maior de técnicas para paralelizar o treinamento de modelos em muitas GPUs. À primeira vista, entender essas técnicas de paralelismo pode parecer assustador, mas com apenas algumas suposições sobre a estrutura da computação essas técnicas se tornam muito mais claras – nesse ponto, você está apenas navegando entre bits opacos de A para B como uma rede. alternar ônibus em torno de pacotes.

Paralelismo de dados

Técnicas para treinar grandes redes neurais

Paralelismo de pipeline

Técnicas para treinar grandes redes neurais

Paralelismo tensorial

Técnicas para treinar grandes redes neurais

Paralelismo Especialista

Técnicas para treinar grandes redes neurais

Paralelismo de dados

Técnicas para treinar grandes redes neurais

Paralelismo de pipeline

Técnicas para treinar grandes redes neurais

Paralelismo tensorial

Técnicas para treinar grandes redes neurais

Paralelismo Especialista

Técnicas para treinar grandes redes neurais

Uma ilustração de várias estratégias de paralelismo em um modelo de três camadas. Cada cor se refere a uma camada e as linhas tracejadas separam diferentes GPUs.

Sem paralelismo

Treinar uma rede neural é um processo iterativo. Em cada iteração, fazemos uma passagem através do modelo camadas para calcular uma saída para cada exemplo de treinamento em um lote de dados. Então outra passagem prossegue para trás através das camadas, propagando o quanto cada parâmetro afeta a saída final calculando um gradiente em relação a cada parâmetro. O gradiente médio do lote, os parâmetros e algum estado de otimização por parâmetro são passados ​​para um algoritmo de otimização, como Adam , que calcula os parâmetros da próxima iteração (que devem ter um desempenho um pouco melhor em seus dados) e o novo estado de otimização por parâmetro. À medida que o treinamento itera em lotes de dados, o modelo evolui para produzir resultados cada vez mais precisos.

Várias técnicas de paralelismo dividem esse processo de treinamento em diferentes dimensões, incluindo:

  • Paralelismo de dados – execute diferentes subconjuntos do lote em diferentes GPUs;
  • Paralelismo de pipeline – execute diferentes camadas do modelo em diferentes GPUs;
  • Paralelismo de tensores – divida a matemática para que uma única operação, como uma multiplicação de matrizes, seja dividida entre GPUs;
  • Mistura de especialistas – processe cada exemplo apenas por uma fração de cada camada.

(Nesta postagem, assumiremos que você está usando GPUs para treinar suas redes neurais, mas as mesmas ideias se aplicam àqueles que usam qualquer outra acelerador de rede neural.)

Paralelismo de dados

Paralelo de Dados treinar significa copiar os mesmos parâmetros para várias GPUs (geralmente chamadas de "trabalhadores") e atribuir exemplos diferentes a cada uma para serem processados ​​simultaneamente. O paralelismo de dados por si só ainda exige que seu modelo caiba na memória de uma única GPU, mas permite utilizar a computação de muitas GPUs ao custo de armazenar muitas cópias duplicadas de seus parâmetros. Dito isto, existem estratégias para aumentar a RAM efetiva disponível para sua GPU, como descarregar temporariamente parâmetros para a memória da CPU entre os usos.

À medida que cada trabalhador paralelo de dados atualiza a sua cópia dos parâmetros, eles precisam de se coordenar para garantir que cada trabalhador continue a ter parâmetros semelhantes. A abordagem mais simples é introduzir bloqueio de comunicação entre trabalhadores: (1) calcular independentemente o gradiente de cada trabalhador; (2) média dos gradientes entre os trabalhadores; e (3) calcular independentemente os mesmos novos parâmetros em cada trabalhador. A etapa (2) é uma média de bloqueio que requer a transferência de uma grande quantidade de dados (proporcional ao número de trabalhadores vezes o tamanho dos seus parâmetros), o que pode prejudicar o rendimento do seu treinamento. Existem vários esquemas de sincronização assíncrona para eliminar esta sobrecarga, mas prejudicam a eficiência da aprendizagem; na prática, as pessoas geralmente aderem à abordagem síncrona.

Paralelismo de pipeline

Com o Pipeline Paralelo treinamento, particionamos partes sequenciais do modelo entre GPUs. Cada GPU contém apenas uma fração dos parâmetros e, portanto, o mesmo modelo consome proporcionalmente menos memória por GPU.

É simples dividir um modelo grande em pedaços de camadas consecutivas. No entanto, há uma dependência sequencial entre entradas e saídas de camadas, portanto, uma implementação ingênua pode levar a uma grande quantidade de tempo ocioso enquanto um trabalhador espera que as saídas da máquina anterior sejam usadas como entradas. Esses períodos de tempo de espera são conhecidos como “bolhas”, desperdiçando o cálculo que poderia ser feito pelas máquinas ociosas.

Técnicas para treinar grandes redes neurais para a frente
Técnicas para treinar grandes redes neurais para trás
Técnicas para treinar grandes redes neurais Atualização de gradiente
Técnicas para treinar grandes redes neurais inativo
Técnicas para treinar grandes redes neurais

Ilustração de uma configuração ingênua de paralelismo de pipeline onde o modelo é dividido verticalmente em 4 partições por camada. O trabalhador 1 hospeda os parâmetros do modelo da primeira camada da rede (mais próxima da entrada), enquanto o trabalhador 4 hospeda a camada 4 (que está mais próxima da saída). “F”, “B” e “U” representam operações de avanço, retrocesso e atualização, respectivamente. Os subscritos indicam em qual trabalhador uma operação é executada. Os dados são processados ​​por um trabalhador de cada vez devido à dependência sequencial, levando a grandes “bolhas” de tempo ocioso.

Podemos reutilizar as ideias do paralelismo de dados para reduzir o custo da bolha, fazendo com que cada trabalhador processe apenas um subconjunto de elementos de dados de cada vez, o que nos permite sobrepor de forma inteligente a nova computação ao tempo de espera. A ideia central é dividir um lote em vários microlotes; cada microlote deve ser proporcionalmente mais rápido de processar e cada trabalhador começa a trabalhar no próximo microlote assim que estiver disponível, agilizando assim a execução do pipeline. Com microlotes suficientes, os trabalhadores podem ser utilizados na maior parte do tempo com uma bolha mínima no início e no final da etapa. A média dos gradientes é calculada entre os microlotes, e as atualizações nos parâmetros acontecem somente depois que todos os microlotes forem concluídos.

O número de trabalhadores sobre os quais o modelo é dividido é comumente conhecido como profundidade do gasoduto.

Durante a passagem direta, os trabalhadores só precisam enviar a saída (chamadas ativações) de seu bloco de camadas para o próximo trabalhador; durante a passagem para trás, ele apenas envia os gradientes dessas ativações para o trabalhador anterior. Há um grande espaço de design sobre como programar essas passagens e como agregar os gradientes em microlotes. GPipe faz com que cada processo de trabalho passe para frente e para trás consecutivamente e, em seguida, agrega gradientes de vários microlotes de forma síncrona no final. Pipe Dream em vez disso, agenda cada trabalhador para processar alternativamente passes para frente e para trás.

Técnicas para treinar grandes redes neurais para a frente
Técnicas para treinar grandes redes neurais para trás
Técnicas para treinar grandes redes neurais Atualizar
Técnicas para treinar grandes redes neurais inativo
GPipe

Técnicas para treinar grandes redes neurais

Pipe Dream

Técnicas para treinar grandes redes neurais

Comparação dos esquemas de pipeline GPipe e PipeDream, usando 4 microlotes por lote. Os microlotes 1 a 8 correspondem a dois lotes de dados consecutivos. Na imagem, “(número)” indica em qual microlote uma operação é executada e o subscrito marca o ID do trabalhador. Observe que o PipeDream obtém mais eficiência ao realizar alguns cálculos com parâmetros obsoletos.

Paralelismo tensorial

O paralelismo de pipeline divide um modelo “verticalmente” por camada. Também é possível dividir “horizontalmente” certas operações dentro de uma camada, o que geralmente é chamado Tensor Paralelo treinamento. Para muitos modelos modernos (como o transformador), o gargalo do cálculo é multiplicar uma matriz de lote de ativação por uma matriz de peso grande. Multiplicação da matriz pode ser pensado como produtos escalares entre pares de linhas e colunas; é possível calcular produtos escalares independentes em GPUs diferentes ou calcular partes de cada produto escalar em GPUs diferentes e somar os resultados. Com qualquer estratégia, podemos dividir a matriz de peso em “fragmentos” de tamanhos iguais, hospedar cada fragmento em uma GPU diferente e usar esse fragmento para calcular a parte relevante do produto geral da matriz antes de comunicar posteriormente para combinar os resultados.

Um exemplo é a Megatron-LM, que paraleliza multiplicações de matrizes nas camadas de autoatenção e MLP do Transformer. PTD-P usa paralelismo de tensor, dados e pipeline; seu cronograma de pipeline atribui múltiplas camadas não consecutivas a cada dispositivo, reduzindo a sobrecarga de bolha ao custo de mais comunicação de rede.

Às vezes, a entrada da rede pode ser paralelizada em uma dimensão com um alto grau de computação paralela em relação à comunicação cruzada. Paralelismo de sequência é uma dessas ideias, onde uma sequência de entrada é dividida ao longo do tempo em vários subexemplos, diminuindo proporcionalmente o pico de consumo de memória, permitindo que a computação prossiga com exemplos de tamanho mais granular.

Mistura de Especialistas (MoE)

Com o Mistura de Especialistas (MoE) abordagem, apenas uma fração da rede é usada para calcular a saída para qualquer entrada. Um exemplo de abordagem é ter muitos conjuntos de pesos e a rede pode escolher qual conjunto usar por meio de um mecanismo de controle no momento da inferência. Isso permite muito mais parâmetros sem aumentar o custo de computação. Cada conjunto de pesos é denominado “especialistas”, na esperança de que a rede aprenda a atribuir computação e habilidades especializadas a cada especialista. Diferentes especialistas podem ser hospedados em diferentes GPUs, fornecendo uma maneira clara de aumentar o número de GPUs usadas para um modelo.

Técnicas para treinar grandes redes neurais

Ilustração de uma camada de mistura de especialistas (MoE). Apenas 2 dos n especialistas são selecionados pela rede de gating. (Imagem adaptada de: Shazeer et al., 2017)

GShard dimensiona um transformador MoE em até 600 bilhões de parâmetros com um esquema onde apenas as camadas MoE são divididas em vários dispositivos TPU e outras camadas são totalmente duplicadas. Mudar Transformador dimensiona o tamanho do modelo para trilhões de parâmetros com esparsidade ainda maior, roteando uma entrada para um único especialista.

Outros designs para economizar memória

Existem muitas outras estratégias computacionais para tornar o treinamento de redes neurais cada vez maiores mais tratável. Por exemplo:

  • Para calcular o gradiente, você precisa ter salvo as ativações originais, o que pode consumir muita memória RAM do dispositivo. Ponto de verificação (também conhecido como recomputação de ativação) armazena qualquer subconjunto de ativações e recalcula as intermediárias just-in-time durante a passagem para trás. Isso economiza muita memória com o custo computacional de no máximo uma passagem completa adicional. Também é possível negociar continuamente entre custo de computação e memória, recomputação de ativação seletiva, que verifica subconjuntos de ativações que são relativamente mais caras para armazenar, mas mais baratas para calcular.

  • Treinamento de precisão mista é treinar modelos usando números de menor precisão (mais comumente FP16). Os aceleradores modernos podem atingir contagens de FLOP muito mais altas com números de menor precisão, e você também economiza memória RAM do dispositivo. Com os devidos cuidados, o modelo resultante quase não pode perder precisão.

  • Descarregando é descarregar temporariamente os dados não utilizados para a CPU ou entre diferentes dispositivos e depois lê-los quando necessário. Implementações ingênuas retardarão muito o treinamento, mas implementações sofisticadas irão pré-buscar os dados para que o dispositivo nunca precise esperar por eles. Uma implementação desta ideia é Zero que divide os parâmetros, gradientes e estados do otimizador em todo o hardware disponível e os materializa conforme necessário.

  • Otimizadores eficientes de memória foram propostos para reduzir o consumo de memória do estado de execução mantido pelo otimizador, como Adaptador.

  • Compressão também pode ser usado para armazenar resultados intermediários na rede. Por exemplo, Essência compacta ativações que são salvas para a passagem para trás; DALL · E comprime os gradientes antes de sincronizá-los.


Na OpenAI, estamos treinando e melhorando grandes modelos desde a infraestrutura subjacente até sua implantação para problemas do mundo real. Se você quiser colocar em prática as ideias desta postagem - especialmente relevantes para nossas equipes de Scaling e Pesquisa Aplicada - estamos contratação!


Agradecimentos
Obrigado a Nikolas Tezak, Sam Altman, Daniel Gackle, Ilya Sutskever e Steven Adler pelos comentários sobre os rascunhos. Obrigado a Justin Jay Wang, Bianca Martin e Steve Dowling pelas comunicações e design.

Carimbo de hora:

Mais de OpenAI