Introdução ao hardware

Por que um “guia introdutório de hardware” importa no ML moderno

O desempenho do aprendizado de máquina (machine learning) é dominado por quão rápido você consegue executar grandes quantidades de operações de álgebra linear (multiplicações de matrizes, convoluções) e quão eficientemente você consegue mover dados (pesos, ativações, estado do otimizador) por uma hierarquia de memória. O mesmo modelo pode ser:

  • 10–100× mais rápido em uma GPU/TPU do que em uma CPU para treinamento,
  • mais barato ou mais caro dependendo da utilização e do processamento em lotes (batching),
  • limitado por computação (FLOPs) ou limitado por largura de banda/capacidade de memória,
  • limitado por latência em tamanhos de lote pequenos ou limitado por vazão (throughput) em tamanhos de lote grandes.

Este artigo explica como CPUs, GPUs e TPUs são construídas de forma diferente, por que essas diferenças importam para treinamento vs inferência, e como raciocinar sobre as compensações práticas.

Tópicos de sistemas relacionados que você pode querer junto com este:

A carga de trabalho: o que os kernels de ML realmente fazem

A maioria das cargas de trabalho de aprendizado profundo (deep learning) se reduz a um pequeno conjunto de operações:

  • GEMM (multiplicação de matrizes): o núcleo de Transformers e MLPs.
  • Convoluções: comuns em modelos de visão (muitas vezes reduzidas a GEMM internamente).
  • Operações elemento a elemento (elementwise ops): ativações, normalizações de camada (layer norms), adição de bias.
  • Reduções: softmax, reduções de escores de atenção, computações de perda.
  • Operações esparsas/irregulares (sparse / irregular ops): embeddings, recuperação (retrieval), roteamento de MoE (mais difíceis de acelerar).

Duas propriedades determinam em grande parte qual hardware funciona melhor:

  1. Paralelismo (parallelism)
    Matrizes grandes oferecem trabalho paralelo abundante (milhões/bilhões de multiplicações-somas). Hardware com muitas “pistas” de computação se destaca aqui.

  2. Custos de movimentação de dados (data movement costs)
    Mover bytes da memória costuma ser mais lento (e mais caro energeticamente) do que fazer aritmética. É por isso que largura de banda de memória (memory bandwidth) e o design de cache/scratchpad on-chip importam tanto. Veja Memória e Largura de Banda.

Um modelo mental útil é a intensidade aritmética (arithmetic intensity):

Quantas operações matemáticas você faz por byte carregado da memória.
Alta intensidade (matmuls grandes) é amigável para computação; baixa intensidade (lotes pequenos, muitas operações elemento a elemento) tende a ser limitada por memória/latência.

Fundamentos de CPU: flexível, orientada a latência, ótima para “todo o resto”

Para o que uma CPU é otimizada

CPUs são projetadas para computação de propósito geral, de baixa latência:

  • Um pequeno número de núcleos poderosos (frequentemente ~8–128 em servidores)
  • Predição de desvio (branch prediction) sofisticada, execução fora de ordem (out-of-order execution) e caches grandes
  • Forte desempenho por thread
  • Boas para fluxo de controle irregular, tarefas de SO, pré-processamento de dados e inferência com lotes pequenos

CPUs também têm unidades vetoriais (SIMD) como AVX2/AVX-512 e às vezes AMX, permitindo aceleração moderada para operações de matriz. Mas, em relação a GPUs/TPUs, CPUs geralmente têm:

  • Menor vazão paralela para álgebra linear densa
  • Menor largura de banda de memória do que aceleradores baseados em HBM
  • Menos unidades especializadas de matriz (embora isso esteja melhorando)

Onde CPUs brilham em ML

  • Pipelines de dados: decodificação de imagens, pré-processamento de texto, aumento de dados (augmentation), tokenização.
  • ML clássico / modelos pequenos: modelos de árvore, modelos lineares, MLPs pequenos.
  • Inferência sensível à latência com tamanhos de lote pequenos: se você não consegue agrupar em lotes, a utilização da GPU pode ser ruim.
  • Orquestração de serving: servidores web, roteamento de requisições, camadas de cache.
  • Cargas não-tensor ao redor do treinamento: checkpointing, métricas, logging.

Treinamento em CPU: quando é razoável

Treinamento somente em CPU pode ser prático para:

  • Modelos pequenos (por exemplo, CNNs/MLPs leves)
  • Prototipagem
  • Educação
  • Quando GPUs não estão disponíveis

Mas para Transformers grandes, treinar em CPU normalmente é lento de forma proibitiva.

Fundamentos de GPU: máquinas de vazão para matemática densa e paralela

Para o que uma GPU é otimizada

GPUs trocam latência por thread por vazão massiva:

  • Milhares de threads leves
  • Hardware projetado para manter muitas operações “em voo”
  • Alta largura de banda de memória (especialmente com HBM em GPUs de datacenter)
  • Unidades de matriz (matrix units) especializadas (por exemplo, NVIDIA Tensor Cores) para FP16/BF16/INT8 e às vezes FP8

Em vez de “um núcleo faz muitas coisas diferentes rapidamente” (CPU), uma GPU é “muitas pistas fazem o mesmo tipo de coisa ao mesmo tempo”.

O modelo de programação em um parágrafo

Uma GPU executa kernels: funções lançadas sobre grandes grades de threads. Threads são agrupadas (warps/wavefronts); o hardware fica mais eficiente quando as threads seguem o mesmo fluxo de controle e acessam a memória em padrões previsíveis. Desvios divergentes e acesso aleatório à memória reduzem a eficiência.

Se você quiser a visão de alto nível de como isso se conecta a ML, veja Noções Básicas de CUDA.

Por que GPUs dominam o treinamento (hoje)

Treinamento envolve:

  • Passagem direta (forward pass)
  • Passagem reversa (Retropropagação (Backpropagation))
  • Atualizações do otimizador (frequentemente pesadas em memória: Adam mantém estado extra)

A passagem reversa aproximadamente dobra/triplica a computação e o tráfego de memória em comparação com inferência. GPUs lidam bem com isso porque:

  • Elas conseguem saturar unidades de matriz em matmuls grandes
  • Elas suportam precisão mista (mixed precision) eficientemente (FP16/BF16/FP8)
  • Elas têm bibliotecas maduras (cuBLAS, cuDNN) e pilhas de compiladores (TensorRT, Triton, etc.)

Gargalos comuns de GPU na prática

  • Subutilização (underutilization): tamanhos de lote pequenos, matrizes pequenas, muitos kernels minúsculos.
  • Camadas limitadas por memória: normalizações de camada, buscas de embedding, etapas de softmax na atenção.
  • Sobrecarga host-device: cópias CPU→GPU, sobrecarga de Python, sincronizações frequentes.
  • Escalonamento multi-GPU: all-reduce de gradientes se torna dominante sem interconexões rápidas; veja Interconexões (NVLink/InfiniBand).

Fundamentos de TPU: aceleradores específicos de domínio para programas tensoriais

Para o que uma TPU é otimizada

TPUs (Tensor Processing Units) são os aceleradores de ML do Google projetados em torno de uma ideia simples: tornar a matemática tensor densa extremamente eficiente e fazer do treinamento distribuído uma preocupação de primeira classe.

Características típicas de TPU:

  • Vazão muito alta em matmul/conv via matrizes sistólicas (systolic arrays)
  • Forte suporte para BF16/INT8 (e formatos mais novos de menor precisão dependendo da geração)
  • Uma pilha de software construída em torno de compilação de grafos (XLA) para otimização do programa como um todo

Embora “TPU” seja uma linha de produtos específica, o conceito mais amplo é o de aceleradores específicos de domínio (domain-specific accelerators): hardware que assume que sua carga de trabalho se parece com álgebra tensor e, portanto, pode simplificar o hardware e aumentar a eficiência.

Modelo de software: compilar primeiro

Fluxos de trabalho em TPU dependem fortemente de compilação para otimizar:

  • Fusão de kernels (kernel fusion) (reduzindo tráfego de memória)
  • Transformações de layout
  • Sharding entre dispositivos

Isso torna Compiladores e Runtimes especialmente relevante: o desempenho frequentemente depende de quão bem sua computação compila e de quão estáveis as formas (shapes) são.

Onde TPUs se encaixam bem

  • Treinamento em grande escala com shapes estáveis e muita matmul
  • Cargas de trabalho que se beneficiam de integração estreita de compilador + hardware
  • Times com infraestrutura alinhada a ecossistemas de TPU (por exemplo, stacks JAX/XLA-first)

Treinamento vs inferência: o mesmo modelo se comporta de forma muito diferente

Características do treinamento

Treinamento geralmente é:

  • Pesado em computação (forward + backward)
  • Pesado em memória (ativações + gradientes + estados do otimizador)
  • Orientado a vazão (você se importa com exemplos/segundo ou tokens/segundo)

Implicações-chave:

  • Lotes grandes ajudam a manter aceleradores ocupados, mas podem afetar a dinâmica de otimização (veja Descida do Gradiente (Gradient Descent)).
  • Precisão mista é comum para melhorar velocidade e reduzir memória.
  • Escalonamento multi-dispositivo depende fortemente de largura de banda/latência de interconexão.

Características da inferência

Inferência pode ser:

  • Orientada a latência (chat interativo, visão em tempo real)
  • Orientada a vazão (jobs offline em lote, geração de embeddings)

Implicações-chave:

  • Lotes pequenos podem tornar GPUs/TPUs ineficientes a menos que você use batching dinâmico.
  • Pegada de memória importa: os pesos precisam caber (ou ser paginados/streamed).
  • Quantização frequentemente é a maior alavanca para custo e latência; veja Quantização.

Exemplo prático: o tamanho do lote muda tudo

Considere um Transformer usado em uma API:

  • Tamanho do lote = 1 (uma requisição por vez): a GPU pode ficar subutilizada; a CPU pode ser competitiva para modelos pequenos.
  • Tamanho do lote = 64 (o servidor agrupa requisições): a vazão de GPU/TPU pode aumentar dramaticamente, reduzindo o custo por token.

Em outras palavras: a escolha de hardware não é apenas sobre o modelo — é sobre o padrão de serving.

Formatos de precisão: FP32 vs BF16/FP16 vs INT8/INT4 (e por que o hardware se importa)

O hardware difere dramaticamente em quão rápido consegue computar em diferentes formatos numéricos:

  • FP32: alta precisão, mais lento em aceleradores em relação a precisões menores.
  • BF16/FP16: amplamente usado para treinamento; bons ganhos de velocidade com perda mínima de acurácia quando feito corretamente (loss scaling, operações estáveis).
  • FP8: cada vez mais usado para treinamento em GPUs/aceleradores mais novos; pode ser muito rápido, mas requer calibração cuidadosa.
  • INT8/INT4: comum para inferência via quantização; grandes benefícios de velocidade/memória, com possíveis trade-offs de acurácia.

Aceleradores (GPUs/TPUs) frequentemente têm unidades especializadas que podem executar muitas multiplicações-acumulações em baixa precisão por ciclo. CPUs também podem fazer baixa precisão, mas a vantagem de vazão geralmente é menor.

Para trade-offs de implantação, veja Quantização.

Hierarquia de memória e por que “largura de banda é o novo FLOPs”

Mesmo que uma GPU anuncie um pico enorme de FLOPs, seu modelo pode não alcançá-los. Muitas cargas de trabalho de ML são limitadas por:

  • Largura de banda de HBM / DRAM
  • Capacidade de SRAM/cache on-chip
  • Overhead de lançamento de kernel / sincronização
  • Largura de banda de comunicação (multi-dispositivo)

Uma boa regra prática:

  • Matmuls grandes podem ser limitadas por computação (boa utilização do acelerador).
  • Normalizações de camada, softmax, embeddings e inferência com lote pequeno frequentemente são limitadas por memória ou latência.

Entender esses gargalos em profundidade é o foco de Memória e Largura de Banda.

Escalando além de um dispositivo: interconexões e estratégias de paralelismo

Quando um modelo não cabe mais em um único acelerador — ou você quer treinamento mais rápido — você escala horizontalmente. Estratégias comuns:

  • Paralelismo de dados (data parallelism): replica o modelo em cada dispositivo e divide os lotes. Exige sincronização de gradientes (all-reduce).
  • Paralelismo tensor/modelo (tensor/model parallelism): divide pesos dentro de uma camada entre dispositivos.
  • Paralelismo de pipeline (pipeline parallelism): divide camadas entre dispositivos.

A eficiência do escalonamento depende de:

  • Largura de banda e latência de interconexão: NVLink, InfiniBand ou interconexão de TPU.
  • Padrão de comunicação: all-reduces frequentes vs menos transferências grandes.
  • Sobreposição (overlap): dá para sobrepor computação com comunicação?

Para o lado de sistemas, veja Interconexões (NVLink/InfiniBand).

Pilhas de software: hardware só é tão bom quanto kernels + compiladores

O desempenho de pico do hardware só é alcançável com kernels e compiladores otimizados:

  • GPUs: kernels CUDA, cuBLAS/cuDNN, kernels de atenção fundidos (fused attention kernels), TensorRT para inferência, Triton para kernels customizados.
  • TPUs: compilação XLA, anotações de sharding, disciplina de shapes.
  • CPUs: MKL/oneDNN, BLAS otimizado, vetorização, threading, alocação ciente de NUMA (NUMA-aware).

Por isso o trabalho moderno de desempenho em ML frequentemente se parece com:

  • escolher as implementações corretas de operadores,
  • habilitar fusão,
  • evitar polimorfismo de shapes (shape polymorphism) quando ele bloqueia a compilação,
  • e reduzir overhead de Python via captura de grafo ou compilação.

Veja Compiladores e Runtimes para um mapa de alto nível dessas ideias.

Exemplos práticos: como a escolha de hardware muda resultados

Exemplo 1: ajuste fino de um Transformer (treinamento)

Cenário: fazer ajuste fino (fine-tune) de um Transformer de tamanho médio para classificação de texto.

  • Somente CPU: pode levar de horas a dias, majoritariamente limitado pela vazão de matmul.
  • Uma única GPU: frequentemente minutos a horas, dependendo do tamanho do lote e do comprimento da sequência.
  • Multi-GPU: mais rápido se o job for grande o suficiente; pode ficar limitado pela sincronização de gradientes.
  • TPU: pode ser altamente competitiva, especialmente com código amigável ao XLA e treinamento com lotes grandes.

Conclusões práticas:

  • Se você está iterando rapidamente, uma única GPU frequentemente fornece o melhor “ciclo de feedback para desenvolvedor”.
  • Se você está treinando em escala, a interconexão e o comportamento do compilador podem importar tanto quanto FLOPs brutos.

Exemplo 2: serving de um LLM (inferência)

Cenário: você está servindo um LLM para chat.

Dois regimes:

  • Baixa QPS, baixa latência (lote≈1–4): você pode estar limitado por latência. Overhead de lançamento de kernel e decodificação sequencial dominam.
  • Alta QPS (batching funciona): você fica limitado por vazão. GPUs/TPUs vencem com folga.

Alavancas de otimização:

  • Quantize os pesos (INT8/INT4) para reduzir largura de banda de memória e acomodar modelos maiores.
  • Use batching contínuo/dinâmico (continuous/dynamic batching) para manter o acelerador ocupado.
  • Garanta padrões rápidos de armazenamento e carregamento de checkpoints ao implantar com frequência; veja Armazenamento.

Exemplo 3: pipeline de embeddings (vazão offline)

Cenário: gerar embeddings para 100M de documentos.

  • GPUs/TPUs se destacam porque você pode agrupar em lotes pesados e rodar perto da vazão de pico.
  • CPUs podem funcionar se você tiver frotas enormes de CPU, mas custo/desempenho pode ser pior a menos que seu modelo seja pequeno e altamente otimizado.

Isso é frequentemente onde o escalonamento de cluster importa: você quer jobs grandes e constantes que utilizem aceleradores plenamente; veja Escalonamento de GPU e Filas de Cluster.

Como escolher: um checklist prático de decisão

Escolha CPU quando

  • O modelo é pequeno ou sensível à latência com batching mínimo.
  • A carga de trabalho tem muitos desvios/operações irregulares.
  • Você é dominado por pré-processamento, não por computação do modelo.
  • Você precisa de simplicidade e baixo overhead operacional.

Escolha GPU quando

  • Você treina redes profundas com muita matmul/conv.
  • Você quer máximo suporte de ecossistema e maturidade de ferramentas.
  • Você precisa de opções flexíveis de implantação (muitos fornecedores/nuvens).
  • Você consegue agrupar inferência em lotes ou rodar jobs offline de alta vazão.

Escolha TPU quando

  • Sua pilha se alinha a XLA/JAX ou fluxos de trabalho “compiler-first”.
  • Você treina modelos densos grandes em escala e quer configurações distribuídas eficientes.
  • Você consegue manter shapes estáveis e aproveitar bem a compilação.

Não esqueça as restrições do “sistema”

A escolha de hardware frequentemente é limitada por:

  • Capacidade de memória (modelo + ativações + estado do otimizador)
  • Interconexão (para escalar)
  • Disponibilidade e escalonamento (tempo de fila, fragmentação)
  • Custo total de propriedade (total cost of ownership) (energia, utilização, tempo de engenharia)

Um mindset mínimo de profiling (o que medir)

Ao comparar hardware, evite depender apenas de “TFLOPs de pico”. Meça:

  • Vazão (throughput): tokens/s, imagens/s, exemplos/s
  • Latência: latência end-to-end p50/p95 (especialmente para serving)
  • Utilização (utilization): duty cycle de GPU/TPU, FLOPs alcançados, largura de banda de memória
  • Tempo de comunicação (multi-dispositivo): percentual do tempo de step em all-reduce / transferências
  • Tempo do pipeline de entrada: aceleradores estão esperando por dados?

Um padrão simples (agnóstico a framework) é:

step_time = data_time + forward_backward_time + optimizer_time + comm_time

Você quer identificar o maior termo e otimizar esse, não adivinhar.

Armadilhas e equívocos comuns

  • “GPUs são sempre mais rápidas.”
    Para modelos minúsculos ou inferência com batch=1, CPUs podem ser competitivas ou mais baratas.

  • “FLOPs de pico predizem desempenho real.”
    Muitos modelos são limitados por memória; largura de banda e fusão importam mais do que FLOPs.

  • “Escalar para mais dispositivos é linear.”
    Overhead de comunicação e desequilíbrio de carga rapidamente dominam sem boa interconexão e estratégia de paralelismo.

  • “A escolha de hardware é separada do design do modelo.”
    Comprimento de sequência, tamanho do hidden, padrões de atenção e checkpointing de ativações (activation checkpointing) podem mudar drasticamente o balanço memória/compute.

Resumo

  • CPUs priorizam flexibilidade e execução de baixa latência; são essenciais para pré-processamento, orquestração e alguns regimes de inferência.
  • GPUs são aceleradores de propósito geral para paralelismo denso massivo e dominam grande parte do treinamento e da inferência de alta vazão.
  • TPUs são aceleradores focados em tensores e fortemente acoplados a fluxos de trabalho com compilador; podem ser extremamente eficientes para cargas densas grandes em escala.
  • O desempenho no mundo real é moldado por precisão, largura de banda de memória, fusão/compilação de kernels e comunicação multi-dispositivo, não apenas pela computação anunciada.

Se você quiser se aprofundar a seguir, os artigos mais diretamente conectados são Memória e Largura de Banda, Compiladores e Runtimes, Interconexões (NVLink/InfiniBand) e Quantização.