Nos últimos dois dias, acabei analisando diversos gráficos de perfil de memória da GPU. Como não há muita informação disponível sobre o que interpretar desses perfis, escrevi um script para fazer isso em uma única linha e publiquei um artigo no blog. Então, o que significam todas essas formas estranhas? Tutorial rápido🧵
Primeiramente, para analisar o desempenho de qualquer bloco de código, basta adicionar este arquivo Python ao seu projeto e usargithub.com/sytelus/nanugp…o para obter os dados de desempenho: https://t.co/iYTzEFksVR
Você obterá uma visualização como a abaixo. É possível observar imediatamente 3 padrões repetidos para 3 etapas de treinamento. Isso é um bom começo. Essas faixas indicam as operações de memória que ocorrem camada por camada. A faixa constante abaixo representa os parâmetros do modelo e os estados do otimizador. Mas o que são todas essas coisas?
Vamos começar pelo primeiro passo do treinamento e analisá-lo. Ele começa com meio triângulo, que é a passagem direta. Isso termina com a criação dos logits, que é um paralelogramo vermelho gigante. O pico acentuado no início é a memória temporária para a função softmax. O motivo dos logits serem tão grandes é que o vocabulário tem 151 mil palavras.
Em seguida, chamamos `zero_grad()`, que limpa as alocações antigas de `.grad`. Ao final de `zero_grad()`, há um pequeno pico e, em seguida, um grande declive. O pico ocorre quando `.backward()` começa na softmax, e o declive ocorre porque o tensor logit não é mais necessário. Isso produz os gradientes da cabeça do modelo linear (faixa verde).
Observe na imagem acima o padrão ondulatório à direita. Isso ocorre porque habilitei o checkpoint de ativação. Isso faz com que cada camada recalcule as ativações, causando pequenos picos e também liberando seu tensor de entrada à medida que o método `.backward()` avança camada por camada.
Finalmente, minha parte favorita: optimizer.step(). É simplesmente belíssimo, como um templo com um mastro de bandeira. Ele se apoia em duas fundações. A faixa laranja é, na verdade, o gradiente da camada de incorporação produzido ao final de .backward().
Na imagem acima, a faixa verde representa o armazenamento necessário para guardar a raiz quadrada do gradiente ao quadrado para o algoritmo Adam. O Fused Adam calcula as atualizações para aplicar camada por camada, resultando nas faixas. No topo, ele aplica essas atualizações de uma só vez. O pico é um buffer temporário necessário para a divisão antes da aplicação da atualização.
Há muito mais a dizer sobre essas belas visualizações. Por favor, me avise se encontrar algum erro ou outras coisas interessantes que devamos saber. Mais informações no meu blog: Como obter e ishital.com/blog/gpu-memor…memória da GPU https://t.co/3uPt0S6RIp





