2 pontos por GN⁺ 2024-10-10 | 1 comentários | Compartilhar no WhatsApp
  • O L-Mul é um algoritmo de multiplicação de complexidade linear que busca aproximar multiplicações por adições inteiras, partindo da observação de que o grande custo energético dos LLMs vem das multiplicações em ponto flutuante
  • Como uma multiplicação fp32 tem custo energético 37 vezes maior que uma adição int32, aplicar L-Mul em hardware de processamento tensorial tem potencial para reduzir em 95% a energia da multiplicação tensorial elemento a elemento em ponto flutuante e em 80% a energia de dot products
  • O método de cálculo omite a multiplicação da mantissa e o arredondamento, trata o sinal com XOR e compõe os demais bits como uma soma no formato x[1:] + y[1:] - offset
  • Nos experimentos, o L-Mul com mantissa de 4 bits mostrou precisão semelhante à multiplicação float8 e4m3, e o L-Mul com mantissa de 3 bits apresentou resultados melhores que float8 e5m2
  • Quando a atenção L-Mul foi aplicada a LLMs pré-treinados sem treinamento adicional, a perda média em tarefas de inferência em linguagem natural foi de 0,07%, e nas tarefas de visão a acurácia média aumentou 0,12%

O gargalo que o L-Mul mira

  • Redes neurais de grande porte usam boa parte da computação em multiplicações tensoriais em ponto flutuante, e essa operação tem custo energético maior que adição
  • O L-Mul é um algoritmo de multiplicação de complexidade linear que aproxima a multiplicação de números em ponto flutuante por adições inteiras
  • O alvo de aplicação cobre várias etapas de cálculo
    • multiplicações dentro do mecanismo de atenção
    • multiplicações de matrizes
    • multiplicações elemento a elemento
  • Em LLMs baseados em Transformer, a atenção tem complexidade O(N²) em relação ao comprimento do contexto de entrada N e, junto com multiplicações tensoriais de alta dimensionalidade, se torna um gargalo central de eficiência computacional

Custo energético por operação aritmética

  • A tabela de custo operacional de Horowitz (2014) mostra diretamente a diferença de energia entre adição e multiplicação
    • adição int8: 0.03 pJ
    • adição int32: 0.1 pJ
    • adição fp16: 0.4 pJ
    • adição fp32: 0.9 pJ
    • multiplicação int8: 0.2 pJ
    • multiplicação int32: 3.1 pJ
    • multiplicação fp16: 1.1 pJ
    • multiplicação fp32: 3.7 pJ
  • Uma multiplicação fp32 usa 4 vezes mais energia que uma adição fp32 e 37 vezes mais que uma adição int32
  • No PyTorch, a precisão padrão para acumular resultados de multiplicação tensorial é fp32
  • Excluindo I/O e operações de controle, ao aproximar uma multiplicação fp32 com uma adição int32, o uso de energia fica em cerca de 1/37 ≈ 2.7%
  • Mesmo reduzindo a precisão de acumulação para fp16, a adição inteira ainda usa só cerca de 4,7% da energia da multiplicação em ponto flutuante

Como o L-Mul calcula

  • A multiplicação comum em ponto flutuante para dois números x e y tem a forma seguinte
    • (1 + xm) · 2^xe · (1 + ym) · 2^ye
    • o resultado é composto por (1 + xm + ym + xm · ym) · 2^(xe+ye) e pelo XOR do sinal
  • O gargalo computacional é a multiplicação da mantissa de m bits, com complexidade O(m²)
  • O L-Mul remove xm · ym e aproxima a conta com a forma seguinte
    • (1 + xm + ym + 2^-l(m)) · 2^(xe+ye)
  • l(m) varia conforme o número de bits da mantissa
    • se m ≤ 3, então m
    • se m = 4, usa um valor separado
    • se m > 4, usa outro valor separado
  • A implementação em nível de bits se reduz a uma expressão mais simples
    • bit de sinal: x[0] ⊕ y[0]
    • bits restantes: x[1:] + y[1:] - offset
  • Como o formato de ponto flutuante trata 1 + xm de forma implícita, o L-Mul pode ser implementado na prática com um único adder
  • Quando a soma das mantissas passa de 2, o carry é transmitido automaticamente ao expoente
  • Isso reduz a carga de cálculo ao pular a multiplicação da mantissa e o arredondamento exigidos na multiplicação tradicional em ponto flutuante

Aplicação à atenção de Transformers

  • A atenção baseada em L-Mul cria Q, K e V e depois substitui a multiplicação de matrizes do cálculo de atenção por L-matmul
  • A forma de cálculo é a seguinte
    • K = H · Wk
    • Q = H · Wq
    • V = H · Wv
    • A = softmax[L-matmul(Q, Kᵀ) / √d]
    • H′ = L-matmul(A, H)
  • L-matmul é uma multiplicação de matrizes em que todas as multiplicações comuns em ponto flutuante são implementadas com L-Mul
  • Essa estrutura troca multiplicações em ponto flutuante por adições inteiras, reduzindo o uso de recursos computacionais

Análise de precisão, complexidade e resultados experimentais

  • A análise de precisão avalia a que quantidade de bits da fração de números em ponto flutuante o L-Mul equivale em termos de preservação
  • Na análise com operandos de distribuição uniforme, o L-Mul foi mais preciso que fp8 e5m2
  • Em uma análise prática baseada na distribuição de pesos combinados de 5 LLMs pré-treinados, foi possível obter precisão superior a fp8 e4m3 com operandos de mantissa de 5 bits
  • Os resultados experimentais foram consistentes com a estimativa teórica de erro
    • o L-Mul com mantissa de 4 bits teve precisão semelhante à multiplicação float8 e4m3
    • o L-Mul com mantissa de 3 bits teve precisão superior à float8 e5m2
  • Em LLMs pré-treinados, a implementação padrão de atenção foi trocada diretamente por atenção L-Mul, sem treinamento adicional
    • perda média de desempenho em tarefas de commonsense, structured reasoning e language understanding: 0,07%
    • variação média de acurácia em tarefas de visual question answering, object hallucination e free-form visual instruction: melhora de 0,12%
  • Em experimentos de fine-tuning, um modelo que substituiu por L-Mul de mantissa de 3 bits todas as multiplicações da atenção, transformação linear e multiplicação elemento a elemento apresentou desempenho semelhante ao de um modelo padrão com precisão de acumulação float8 e4m3
  • Na estimativa de volume de cálculo em nível de portas, a multiplicação comum ficou aproximadamente nos seguintes níveis
    • multiplicação fp16: cerca de 584
    • multiplicação fp8 e4m3: cerca de 325
    • multiplicação fp8 e5m2: cerca de 296
  • A estimativa de volume de cálculo em nível de portas do L-Mul foi menor
    • fp16 L-Mul: cerca de 256
    • fp8 L-Mul: cerca de 157
  • Como GPUs não têm implementação nativa de L-Mul, é difícil aproveitar toda a sua eficiência, e recomenda-se treinar e hospedar modelos baseados em L-Mul em dispositivos com arquiteturas especializadas integradas
  • A tecnologia está em status de patent pending

1 comentários

 
GN⁺ 2024-10-10
Comentários do Hacker News
  • Lembro que, antigamente, quando cálculos de ponto flutuante eram caros em CPUs Intel, havia vários truques que programadores usavam para contornar isso com inteiros.
    Chuck Moore, famoso pelo Forth, mostrava uma abordagem em que valores como 1,6 × 4,1 eram tratados nos cálculos intermediários como inteiros, tipo 16 × 41, e depois, na saída, o ponto decimal era recolocado na “posição correta”. Se o intervalo dos valores de ponto flutuante, mesmo multiplicado por 10, não passasse de 65536, isso funcionava bem até com inteiros de 16 bits, e se encaixava bem em chips embarcados que precisavam calcular rapidamente, várias vezes por segundo, valores analógicos com precisão de 10 bits.
    Também conversei há muito tempo com um engenheiro da Microsoft que trabalhou no Microsoft Streets and Trips, e ele disse que eles também colocavam números e cálculos que normalmente seriam de ponto flutuante em algum formato inteiro empacotado contendo apenas a precisão realmente necessária, para rodar mais rápido nas CPUs da época e comprimir mais facilmente para caber em CD-ROM. Há capturas de tela em https://archive.org/details/3135521376_qq_CD1

    • Essa é uma técnica chamada aritmética de ponto fixo, e é um método interessante que eu gostaria que mais programadores conhecessem.
      Código financeiro bem feito deveria usar isso, mas, no setor financeiro que vi, não era tão comum a menos que envolvesse mainframes. Curiosamente, vi aritmética de ponto fixo com muito mais frequência em rasterizadores de software como FreeType, GDI, WPF e WARP (o rasterizador de referência do D3D11)
    • Lembro de ter mexido no FRACTINT, um gerador de fractais da época em que coprocessadores de ponto flutuante não eram comuns. Ele calculava e exibia fractais usando matemática de ponto fixo, e naquela época fractais pareciam incrivelmente legais, todo mundo queria entrar no negócio de fractais e todos os prêmios Nobel iam para pesquisadores de fractais
    • Ozaki tem feito multiplicação de matrizes fp64 com tensor cores int8.
      https://arxiv.org/html/2306.11975v4
      Muito interessante
    • Até onde sei, essa ainda é a melhor forma de lidar com dinheiro ou números financeiros
    • Esse truque específico é conhecido como aritmética de ponto fixo. É um conceito diferente de ponto fixo de uma função
  • A alegação é algo como “pode reduzir potencialmente o custo de energia em 95% na multiplicação elemento a elemento de tensores de ponto flutuante e em 80% no produto interno”; se isso fosse sobre redes neurais convolucionais, a otimização computacional teria um significado muito maior.
    Mas transformers tendem a ser leves em computação e pesados em memória. O gargalo é trazer os pesos do modelo para os núcleos, e as reduções de energia de 95% e 80% citadas são números isolados apenas para a operação de multiplicação, não para todo o processo de inferência.

    • O prefill continua sendo dominado por computação mesmo com batch único, e a decodificação em múltiplos batches também.
      A frase repetida de que “a inferência de transformers somente decodificadores é limitada pela largura de banda da memória” só é estritamente verdadeira na decodificação de batch único com tamanho de batch 1. Nesse caso, a maior parte do trabalho são multiplicações vetor-matriz
    • Pior ainda. O ganho de energia é medido em comparação com cálculos fp32, mas em fp8 os multiplicadores são realmente pequenos, então somadores e shifters passam a ser uma parte maior do operador em energia e área; por isso, os ganhos deste artigo seriam menores.
      Em fp8, a estimativa de portas é 296 para um multiplicador fp8 comum e 157 para esta técnica, então o ganho de potência no multiplicador seria bem menor. Algo em torno de 50% é uma estimativa mais razoável e, de novo, em fp8 a soma representa uma grande parte das operações no produto interno.
      No geral, parece bastante desonesto alegar 80% de ganho de potência e pequena perda de precisão. O ganho de potência se aplica apenas a operações fp32, enquanto a pequena perda de precisão se aplica apenas ao operador fp8. A perda de precisão em fp32 não foi analisada, e a potência economizada no produto interno fp8 também não foi apresentada
    • fp8 é pequeno o bastante para que a multiplicação possa ser feita com circuitos muito mais simples do que em formatos de ponto flutuante maiores.
      Formatos ainda menores, como fp4, poderiam simplesmente usar uma tabela de consulta, e aí, na prática, isso fica bem próximo de algum esquema de quantização mais ou menos padronizado
    • Uma arquitetura realmente boa para transformers parece ser algo como colocação conjunta de memória e computação
    • Isso só vale para usuário único ou inferência leve. Em treinamento e inferência em batch, pode rapidamente se tornar um gargalo de computação
  • [2023] GradIEEEnt half decent: The hidden power of imprecise lines
    http://tom7.org/grad/murphy2023grad.pdf
    Também há um vídeo: https://www.youtube.com/watch?v=Ae9EKCyI1xU

  • Não li, mas suspeito que isso use tabelas de logaritmos de alguma forma.
    Não estou tentando desmerecer; é mais que sinto que não entendo logaritmos direito em um nível mais fundamental, como portas lógicas, então estou perguntando. Se dá para transformar multiplicação em consulta de tabela e soma, parece que também deveria existir o inverso: circuitos que oferecem soma difícil e multiplicação fácil, ou combinações desse tipo de compromisso

    • Espaço logarítmico é bom, porque permite substituir multiplicações por somas.
      Essa parte é fácil e qualquer um consegue implementar em hardware. A parte complicada é acumular, especialmente acumular ao longo de uma faixa grande, mantendo-se o tempo todo no espaço logarítmico
    • Sim, é assim que um sistema numérico logarítmico funciona
  • Achei estranho que o artigo não pareça ter uma derivação e discussão adequadas do termo de erro. Tudo é tratado apenas indiretamente por meio dos resultados de inferência

    • Também achei esse artigo meio estranho. Quando a estimativa de portas é feita apenas com explicações em texto, sem diagramas, é muito fácil deixar passar partes necessárias.
      Mesmo que não fosse uma descrição completa em nível de portas, deveria haver uma figura com blocos rotulados como “somador”. Ver o nome de Vries no primeiro parágrafo também não ajudou na credibilidade
  • Em uma nota de rodapé da seção de metodologia, está escrito: “Recomenda-se que modelos baseados em L-Mul sejam treinados e hospedados em dispositivos com projeto de arquitetura especializada integrado. Patente pendente”

  • A quantidade de computação parece que vai diminuir, mas como ainda usa 8 bits por valor, não reduz os requisitos de memória necessários para executar inferência.
    Por isso, é difícil dizer que torne os modelos mais acessíveis para uso em inferência. Se esse formato de armazenamento também for adequado para treinamento, pode ter aplicações potencialmente interessantes

    • Na prática, em termos de precisão e intervalo, ele é cerca de 0,5 bit menos eficiente por peso, e o artigo não destaca isso de forma alguma
  • Mover bytes consome mais de 10 vezes a energia de computar. Eficiência computacional não é um problema tão grande quanto as pessoas pensam.
    Hoje a computação está simplesmente no lugar errado; pelo menos na agregação inicial envolvida no produto interno, ela deveria contornar o barramento de memória e ficar bem ao lado das células de memória

    • Ainda assim, não poderia ser útil em dispositivos com restrição de bateria?
  • Pela minha experiência, os verdadeiros magos da matemática de ponto fixo eram os designers de videogames de 8 e 16 bits.
    As otimizações que eles faziam eram impressionantes e, por exemplo, permitiram calcular matemática de matrizes 3D em tempo real para criar os primeiros simuladores de voo e jogos de tiro em primeira pessoa

    • Redefinir ângulos como 2π = 256 foi um truque bem inteligente