Llama2.c: inferência do Llama 2 em um arquivo C puro
(github.com/karpathy)- llama2.c é uma solução “fullstack” de treinamento e inferência que treina a arquitetura LLM do Llama 2 com PyTorch e faz inferência com um simples arquivo C,
run.c - O foco principal é minimalismo e simplicidade: uma implementação educacional com a arquitetura do Llama 2 hardcoded e composta por um único arquivo de inferência em C puro, sem dependências
- A partir da ideia de que até LLMs muito pequenos podem ter desempenho forte se o domínio for suficientemente restrito, o projeto fornece modelos de exemplo baseados em TinyStories
- O modelo de 15M de parâmetros tem download de cerca de 60MB e pode ser executado com
make runseguido de./run stories15M.bin - Modelos de 42M e 110M de parâmetros também são fornecidos, e é informado que o modelo de 110M tem o mesmo tamanho do GPT-1
- O modelo de 15M de parâmetros tem download de cerca de 60MB e pode ser executado com
- Os modelos Llama 2 da Meta também podem ser usados para inferência, pois a arquitetura da rede neural é a mesma, mas é preciso obter o checkpoint seguindo as diretrizes da Meta e depois convertê-lo para o formato do llama2.c com
export.py- Atualmente,
run.cfaz apenas inferência em fp32, então modelos maiores que 7B provavelmente serão difíceis de carregar de forma prática - Modelos de 13B ou mais não funcionam no momento por causa de integer overflow na aritmética de ponteiros, e isso ainda não foi corrigido
- Atualmente,
- A inferência com quantização int8 está implementada em
runq.c, usando o esquema Q8_0 para quantizar os pesos que participam do matmul, enquanto os valores de ativação também são quantizados e desquantizados dinamicamente em tempo de execução- O export fp32 do Llama 2 7B gera um arquivo de 26GB, enquanto o export quantizado da version 2 gera um arquivo de 6,7GB
- No ambiente do autor, com OpenMP em 64 threads, o fp32 roda a 4,6 tok/s e o int8 a 14 tok/s, reduzindo o tamanho do checkpoint em 4x e melhorando a velocidade em cerca de 3x
- O modo de uso inclui execução da inferência em C, entrada de prompt, controle de sampling por temperature e top-p, modo chat e definição de tokenizer customizado
- Um exemplo de execução é
./run stories42M.bin -t 0.8 -n 256 -i "One day, Lily met a Shoggoth" - Modelos de chat são executados com a flag
-m chat, como em./run llama2_7b_chat.bin -m chat - Tokenizers customizados podem ser exportados em formato
.bincomtokenizer.pye depois informados com a flag-z
- Um exemplo de execução é
- Modelos no Hugging Face que usam a arquitetura Llama 2 podem ser exportados para arquivos
.bincom a flag--hfdeexport.py - O fluxo de treinamento segue download e pré-tokenização do TinyStories, execução de
train.py, export do modelo e depois inferência em C- O exemplo padrão com TinyStories é atualmente o único exemplo de dataset fornecido
- O treinamento de tokenizer customizado usa
sentencepiece, com o exemplo de configuração--vocab_size=4096
- Os builds voltados a desempenho são divididos entre
make run,make runfastemake runomp; o build com OpenMP ativa#pragma omp parallel fordentro de matmul e attention para dividir o trabalho dos loops entre vários processadores - Instruções de build para plataforma são fornecidas para Windows, Centos 7, Amazon Linux 2018 e Mac
- No Windows, use
build_msvc.batoumake win64 - Em Centos 7 e Amazon Linux 2018, use
make rungnuoumake runompgnu - No Mac, o build com OpenMP usa o clang do brew e
make runomp CC=/opt/homebrew/opt/llvm/bin/clang
- No Windows, use
- Os testes incluem
pyteste testes em C commake testcc;test_all.pyexecuta 200 passos de forward em C e Python e compara com a saída esperada conhecida - O objetivo do projeto é manter uma implementação de referência simples, composta por 2 arquivos
.pyde treinamento fáceis de ler e código de inferência em C, sem buscar frameworks complexos nem muitas opções - A licença é MIT
1 comentários
Comentários no Hacker News
Vi isso no HN e achei divertido :) O checkpoint original roda a 100 tok/s no MacBook Air M1 compilado com
-O3, muito mais rápido do que eu esperava, então agora estou treinando um modelo maior de 44MAinda deve dar para rodar de forma interativa, e talvez até um modelo Llama de 7B esteja ao alcance
nanoGPTpara pré-treinar um modelo de 12M com 2GB de dados do TinyStories gerados pelo GPT-4, e o resultado foi bem surpreendenteDepois adaptei um pouco com Wikipedia, e ele virou um gerador plausível de bobagens muito mais inteligente e muito menor do que um modelo n-gram suavizado. Acho que LLMs pequenos vão se tornar comuns em várias áreas, e o próximo objetivo é reduzir o Llama2 7B para 10~100M sem deixá-lo muito mais burro
Alugar uma instância com GPU em algo como Linode é muito mais caro do que um servidor normal para webapp, então queria saber se isso é uma área totalmente inviável ou se uma abordagem como essa, ou algum outro método, é um caminho realista
Georgi Gerganov, famoso pelo llama.cpp, tem uma versão rodando no navegador com Emscripten: https://ggerganov.com/llama2.c/
A thread no Twitter em andamento está em https://twitter.com/ggerganov/status/1683174252990660610
Tanto o original quanto esse trabalho são realmente muito legais e, embora sejam mais uma prova de conceito usando modelos bem pequenos, os LLMs local-first são especialmente interessantes. Gosto da ideia de poder criar webapps com inferência local
Se isso evoluir para otimizações, pesquisa em modelos menores, download parcial e uso de WebGPU, pode ser o ponto de partida para uma nova forma de criar apps privados baseados em LLM local. Talvez não chegue às mesmas capacidades de LLMs hospedados em grandes clusters com GPUs de ponta, mas há muitos casos de uso que essa abordagem pode abrir
Por exemplo, começa com “Once upon a time...”, parece a história de Lily e Timmy, mas depois aparecem coisas como “Butterfly would pauseWhy”, “TextField”,
querySelector,HttpRequeste fragmentos de vários idiomas, até virar uma saída completamente quebradaPara quem tiver curiosidade, também há uma versão em Rust. Em modo release ela faz cerca de 106 tokens/second
https://github.com/garrisonhess/llama2.c/blob/517a1a3e487f31...
A versão não web tem suporte completo a GPU, mas não é nada minimalista
Em alguns casos isso também dispersa os esforços da comunidade para melhorar o projeto
Acho que pouca gente entende o quão ousado é esse movimento
Andrej recebe uma grande remuneração na OpenAI (MSFT), mas ainda assim está ajudando Apple, Facebook e, mais importante, o movimento open source. Mesmo assim seria difícil afastá-lo, porque ele poderia ir direto para a Tesla ou para a xAI
Tenho a impressão de que o Llama-2 tem filtragem de segurança pesada demais a ponto de ficar inutilizável para trabalho criativo: https://i.imgur.com/GFY0wSL.png
Ainda assim, esse comportamento só foi reproduzido até certo ponto quando enviado como segunda mensagem no TGI Hugging Face do Llama2-70b-chat, e pode haver alguma estranheza na forma do prompt que esteja causando isso. Ainda não pude rodar o modelo por conta própria para investigar mais
Chat/instruct tem a vantagem de ser fácil de distribuir para usuários terceiros, os prompts são simples e há mecanismos de segurança, mas para uso próprio ele fica realmente muito atrás de um modelo pré-treinado. Nesse ponto, o Llama 2 pode até ter vantagem sobre a OpenAI, porque a OpenAI parece ter abandonado os modelos pré-treinados GPT-3 e estar seguindo para oferecer apenas modelos de chat no futuro
Não quero tesoura de segurança. Tudo bem limitar coisas que rodam no próprio servidor deles, mas não deveriam me dar um modelo que eu não possa modificar e usar como quiser no meu computador
O Andrej publicou mais detalhes aqui: https://twitter.com/karpathy/status/1683143097604243456?s=46...
Como referência, se você tem interesse nessa área, este código compila de forma limpa com o WASI SDK e roda em um runtime Wasm sem modificações
Fiquei me perguntando quanta memória é necessária para executar uma rede neural
Bastaria ler do disco só as duas primeiras camadas e calcular as ativações de todos os nós, depois descartar a primeira camada, ler a terceira, calcular de novo e então descartar a segunda? Se for assim, fico pensando se basta ter memória para armazenar apenas duas camadas
Resumindo, o pico de RAM varia conforme o método de quantização, e em linhas gerais fica em 4~8GB para modelos 7B, 8~15GB para 13B, 13~33GB para 30B e 31~75GB para 70B
Pensando aqui: hoje os LLMs retornam uma distribuição de probabilidades, e um amostrador aleatório escolhe uma delas, anexa ao resultado e repete o processo
Em vez disso, seria possível usar a aleatoriedade para escolher N tokens que aproximem a distribuição, fazer o LLM gerar N novas distribuições e então combiná-las de algum modo, para depois escolher novamente N tokens a partir da distribuição combinada?
Dá para ver um exemplo em https://huggingface.co/docs/transformers/internal/generation...
Só não sei como fazer isso
Claro que isso exigiria N vezes mais computação por geração de token. Você pode escolher os N mais prováveis ou, se necessário, aplicar temperatura aos logits para amostrar N deles
Isto é para fins educacionais? Pelo sucesso do llama.cpp e deste projeto, parece que a indústria está indo na direção de manter código-fonte separado para cada modelo lançado, em vez de usar frameworks genéricos como PyTorch, TensorFlow e ONNX Runtime
E não. Apesar do nome, o llama.cpp não suporta apenas llama. Também não é algo totalmente sob medida; ele é construído sobre a biblioteca/framework de tensores
ggml, que é mais genéricaMas, quando se encontra um modelo que funciona bem, esses avanços acabam entrando na versão seguinte do framework. Foi assim que o TensorFlow ganhou blocos básicos como CNN, GRU e TransformerEncoder, ao mesmo tempo em que surgiram implementações específicas para certos hardwares, abrindo mão de generalidade em troca de velocidade