15 pontos por GN⁺ 2025-02-22 | 1 comentários | Compartilhar no WhatsApp
  • A GPU é um processador massivamente paralelo com milhares de núcleos, projetado para processar muitas tarefas ao mesmo tempo
  • A CPU se destaca em tarefas complexas e sequenciais, mas o número de tarefas que consegue processar de uma vez é limitado
  • Em contrapartida, a GPU tem como ponto forte o processamento paralelo de tarefas por meio de milhares de threads, sendo excelente para lidar rapidamente com grandes volumes de dados
  • Por exemplo, a GPU NVIDIA RTX 4090 tem 16.384 núcleos CUDA, em comparação com os 16 a 24 núcleos de uma CPU avançada
  • Cada núcleo de GPU é mais lento que um núcleo de CPU, mas o processamento paralelo de um grande número de núcleos a torna adequada para cálculos de larga escala, como operações com matrizes

CUDA e Python

  • O CUDA (Compute Unified Device Architecture) da NVIDIA é uma plataforma e uma extensão de C++ que permite escrever programas executados na GPU
  • O CUDA fornece um modelo de programação e APIs para que desenvolvedores possam escrever código executado diretamente na GPU
  • Com isso, é possível descarregar da CPU para a GPU tarefas que podem ser paralelizadas, buscando melhorar o desempenho
  • Desenvolvedores Python podem aproveitar a aceleração por GPU usando ferramentas como o Numba
  • O Numba é um compilador Python que compila código Python para execução em GPUs com suporte a CUDA
  • Isso permite que desenvolvedores Python comecem facilmente a usar computação acelerada por GPU com o mínimo de nova sintaxe e terminologia
  • O CUDA Python fornece wrappers em Cython/Python para as APIs de driver e runtime do CUDA, permitindo que desenvolvedores Python aproveitem a computação paralela da GPU
  • O CUDA Python pode ser instalado via PIP e Conda

Estrutura de threads e blocos no CUDA

  • No CUDA, um kernel é uma função executada na GPU. Ao executar um kernel, centenas ou milhares de threads paralelas são executadas simultaneamente para processar dados diferentes
  • Esse modelo é chamado de SIMT (Single-Instruction Multiple-Thread)
  • As threads são organizadas em warps (grupos de 32 threads), e os warps são agrupados em blocos
  • Cada bloco é executado em um streaming multiprocessor (SM), e o SM possui recursos limitados, como registradores e memória compartilhada
  • O tamanho do bloco afeta a alocação desses recursos e o número de warps que podem ser executados simultaneamente (occupancy)
  • Ao definir adequadamente a quantidade e o tamanho dos blocos de threads, é possível usar os recursos da GPU com mais eficiência

Gerenciamento de memória e otimização

  • Na programação CUDA, é necessário gerenciar explicitamente a memória entre a CPU (host) e a GPU (device)
  • O fluxo típico é o seguinte:
    • alocar memória na GPU (cudaMalloc)
    • copiar os dados do host para o device (cudaMemcpy)
    • executar o kernel
    • copiar o resultado do device para o host (cudaMemcpy)
    • liberar a memória da GPU (cudaFree)
  • A memória compartilhada é uma memória on-chip que permite que threads dentro de um bloco compartilhem dados rapidamente, melhorando a velocidade de acesso à memória
  • A sincronização entre threads é implementada com __syncthreads(), o que ajuda a evitar race conditions

Kernels CUDA customizados para LLMs

  • Em tarefas com grandes modelos de linguagem (LLMs), vêm sendo desenvolvidos kernels CUDA customizados que combinam várias operações em um único kernel para reduzir overhead de memória e aumentar a eficiência
  • Por exemplo, o FlashAttention otimiza o self-attention do Transformer, reduzindo leituras e escritas de memória e melhorando significativamente a eficiência
  • O FlashAttention utiliza memória compartilhada para fazer tiling das operações, alcançando alta eficiência mesmo em sequências longas
  • Essas otimizações ajudam a resolver o problema de gargalo de largura de banda de memória no deep learning

Comparação entre implementações em PyTorch e CUDA

  • No PyTorch, é possível realizar operações na GPU com facilidade por meio de abstrações de alto nível
  • Por exemplo, a operação de somar dois vetores pode ser implementada de forma simples da seguinte maneira:
import torch  
  
# Criar dois grandes vetores na GPU  
a = torch.rand(1000000, device='cuda')  
b = torch.rand(1000000, device='cuda')  
  
# Somar elemento por elemento  
c = a + b  
  • No entanto, quando é necessário otimizar o desempenho, é possível escrever kernels customizados usando CUDA diretamente
  • Com CUDA, é possível ajustar com precisão padrões de acesso à memória, organização de threads, uso de memória compartilhada e outros aspectos para maximizar o desempenho
  • Por exemplo, a implementação em CUDA do FlashAttention otimiza o acesso à memória e faz tiling das operações na memória compartilhada para melhorar o desempenho
  • Esse tipo de otimização de baixo nível pode atingir desempenho superior ao de uma implementação de alto nível em PyTorch

Conclusão

  • Ao aproveitar a capacidade de processamento paralelo da GPU, é possível executar com eficiência processamento de grandes volumes de dados e cálculos complexos
  • O CUDA é a plataforma que permite aproveitar ao máximo esse desempenho da GPU, e desenvolvedores Python também podem se beneficiar dele por meio de ferramentas como o Numba
  • Compreender a estrutura de threads e blocos do CUDA, além das técnicas de gerenciamento de memória, permite uma programação em GPU mais eficiente
  • Especialmente em áreas como deep learning, é possível maximizar o desempenho escrevendo kernels CUDA customizados
  • Mesmo usando frameworks de alto nível como o PyTorch, ainda é possível buscar desempenho mais alto com otimizações CUDA de baixo nível quando necessário

1 comentários

 
GN⁺ 2025-02-22
Comentários do Hacker News
  • Pergunta boba: como engenheiro, será que é possível se aprofundar bastante no baixo nível de CUDA ou da arquitetura de GPU sem aprender o lado matemático da IA? Se sim, como eu deveria começar? Parece que eu precisaria aprender sobre otimização e por que GPUs são usadas para certos tipos de cálculo

    • Pergunta paralela: trabalhando como engenheiro de dados, sempre tive curiosidade se dá para entrar em MLE ou engenharia de dados para IA sem conhecer IA/ML. Achei que bastava entender o formato dos dados, mas todas as descrições de vaga de MLE que vi até agora dizem que é preciso ter background em IA
  • Artigo muito bom. Os quizzes inline (QnA), que parecem ter sido gerados por IA, são muito úteis para testar a compreensão. Queria que todo tutorial tivesse esse recurso

  • Fiquei curioso se todo tutorial de CUDA tem IA como objetivo, ou se também existem, por exemplo, para computação científica geral. Parece que seria divertido tentar coisas como fluxo de ar sobre uma asa para computação de alto desempenho

  • Obrigado por compartilhar, gostei da leitura. Tenho uma pergunta meio relacionada: queria saber se alguém tem insights sobre como a DeepSeek conseguiu contornar o CUDA para tornar a execução mais eficiente

    • Sempre me surpreendeu que o CUDA, sendo uma biblioteca central desenvolvida ao longo de tanto tempo, ainda tenha margem para melhoria. Especialmente a ponto de uma equipe nova de desenvolvedores conseguir fechar essa lacuna por conta própria
  • Jensen dá, Guido tira

  • Este livro: "Programming Massively Parallel Processors" parece ser feito sob medida para quem está migrando da arquitetura de CPU para GPU

  • Também recomendo dar uma olhada em https://github.com/rust-gpu/rust-gpu e https://github.com/rust-gpu/rust-cuda

  • Links relacionados: https://sakana.ai/ai-cuda-engineer/ e https://reddit.com/r/MachineLearning/…

  • Fiquei curioso se alguém tem alguma ideia do que mudou recentemente para que simulações que antes só eram possíveis em CPU agora possam rodar inteiramente em GPU, como no caso de isaac sim

  • Como isso está no site da PySpur, queria saber se alguém tem experiência com ferramentas de UI para agentes de IA como PySpur e n8n. Estou procurando algo que possa ajudar a prototipar algumas ideias por diversão. Como vou precisar fazer self-hosting ($), prefiro algo relativamente fácil de configurar, como o Open Hands