stable-diffusion.cpp - Inferência de modelos Diffusion implementada em C/C++
(github.com/leejet)- Uma ferramenta para executar inferência de modelos Diffusion, incluindo as famílias SD, Flux e Wan, em C/C++ puro, com foco em uma implementação leve e sem dependências externas
- A implementação é baseada em ggml e tem uma estrutura em Plain C/C++ que funciona de modo semelhante ao llama.cpp
- O escopo de modelos compatíveis é dividido em modelos de imagem, modelos de edição de imagem e modelos de vídeo, abrangendo SD1.x, SD2.x, SDXL, SD3/SD3.5, FLUX, Qwen Image, Wan2.1/Wan2.2, LTX-2.3 e outros
- O conjunto de recursos inclui PhotoMaker, Control Net para SD 1.5, LoRA no estilo do stable-diffusion-webui, LCM/LCM-LoRA, decodificação latente baseada em TAESD, upscale com ESRGAN, negative prompt e suporte a tokenizer com pesos de tokens
- Os backends de execução são CPU, CUDA, Vulkan, Metal, OpenCL e SYCL; na CPU, inclui suporte a AVX, AVX2 e AVX512 na arquitetura x86
- As plataformas compatíveis são Linux, Mac OS, Windows e Android; no Android, a execução é via Termux e Local Diffusion
- Os formatos de pesos compatíveis são
.ckpt,.pth,.pt,.safetensorse.gguf; o modo de conversão transforma os pesos do modelo para.ggufou.safetensors - O fluxo básico de uso consiste em baixar um binário pré-compilado na releases page ou compilar a partir do código-fonte, baixar os pesos do modelo e então gerar uma imagem com um comando como
./bin/sd-cli -m ../models/v1-5-pruned-emaonly.safetensors -p "a lovely cat" - Como recursos de otimização de uso de memória, oferece Flash Attention e processamento de VAE em tiles; a alocação de runtime e parâmetros por backend e melhorias de desempenho são tratados em um guia separado
- As opções de reprodutibilidade são divididas em
--rng cudae--rng cpu, com o objetivo de manter consistência, respectivamente, com o RNG de GPU dostable-diffusion-webuie o RNG do ComfyUI - A saída em PNG insere os parâmetros de geração como uma string de texto compatível com webui
- Há projetos de wrappers para Golang, C#, Python, Rust e Flutter/Dart; Jellybox, Local Diffusion, LocalAI, KoboldCpp e outros usam o
stable-diffusion.cppcomo backend de geração de imagens - O projeto está em desenvolvimento ativo, e a API e as opções de linha de comando podem mudar com frequência
1 comentários
Opiniões no Hacker News
Llama.cpp/ggml combina excepcionalmente bem com LLMs
Os requisitos de memória são altos, a quantização é eficaz, a geração de tokens é surpreendentemente serial e limitada pela largura de banda de memória, então se encaixa bem em CPUs — e ainda melhor no pipeline peculiar de inferência CPU/GPU do ggml
Mas Stable Diffusion é diferente. A quantização não funciona tão bem, a UNet exige muito cálculo, e a geração de imagens em lote é eficaz e útil até para um único usuário. Por isso, ela se encaixa melhor em GPUs/GPUs integradas e se beneficia muito da facilidade de hackear a implementação em Python
Para Stable Diffusion, acho que o caminho certo é criar executáveis por meio de compilação de machine learning. O AITemplate já é muito rápido https://github.com/VoltaML/voltaML-fast-stable-diffusion, e o TVM Vulkan também é muito promissor se alguém concluir direito uma implementação de demonstração https://github.com/mlc-ai/web-stable-diffusion
Além disso, a maior parte da hackeabilidade de uma implementação em PyTorch puro é preservada
Por exemplo,
GGML_CUBLASé suportado na compilação e traz uma melhoria de velocidade bem razoável em comparação com C/C++ puroMesmo que leve um tempo, dá para rodar em um notebook antigo
torch.compile, e lembro de ter trabalhado nisso diretamenteVou ver se consigo encontrar os números
Excelente terem implementado até o CLIP
Seria interessante extrair só isso e compilar como uma implementação em WebAssembly
Edit: parece que alguém já fez https://github.com/monatis/clip.cpp. Agora é só transformar em WebAssembly
É uma pena pensar que talvez já exista, em algum cofre secreto, um modelo do nível do CLIP mais avançado
Edit: não estou falando de CLIP-2, mas de um avanço tão importante quanto o CLIP
A configuração é inacreditavelmente fácil, então tentei rodar de primeira
Fico curioso para saber que velocidade seria considerada normal
Rodei no Linux com
cmake .. -DGGML_OPENBLAS=ONem um AMD Ryzen 7 5700G, sem GPU dedicada, só com gráficos integradosAo executar
./bin/sd -m ../models/sd-v1-4-ggml-model-f32.bin -p "a lovely cat", cada etapa de amostragem levou cerca de 12 segundos, e a amostragem inteira levou 246,40 segundosGostaria de saber se esse é o desempenho esperado
Edit: o OpenBLAS não estava instalado, então essa flag não teve efeito
Na época, quase todas as soluções exigiam uma pilha de dependências em Python, e a instalação demorava tanto que acabava falhando por falta de espaço em disco
Sério, literalmente substitui vários gigabytes de espaço em disco por um único binário de 799 KB. De quebra, usando o formato Q8_0, que parece ser o mais rápido, os dados também economizam cerca de 2,3 GB
Mas parece haver bugs fora do tamanho padrão de imagem 512x512. Alguns tamanhos como 544x544 tendem a causar falha de assert, tamanhos menores que 512x512 às vezes geram imagens ruins, e tamanhos menores que 384x384 quase sempre fazem isso
[0] https://news.ycombinator.com/item?id=32555608
Há algo especialmente atraente em implementações de IA em C/C++
O código parece limpo e intuitivo, e faz toda a área de IA parecer algo palpável e possível de aprender
Será porque o ecossistema Python é bagunçado demais?
A versão em Python também usa código em C e C++ por desempenho, mas aqui está tudo em uma única linguagem
É como se três fatores que possibilitam código limpo estivessem atuando juntos
É bom ver o pessoal de machine learning saindo do Python e usando uma linguagem que aproveita o hardware de forma ótima e não exige ajustar um ambiente especial para compilar e executar
Para começar, o projeto do post original, assim como o llama.cpp, não usa GPU, enquanto a maior parte do código de machine learning em Python usa GPU. Não é difícil escrever código em Python que aproveite a GPU de forma ótima. Dá para chamar a GPU de ambiente especial para compilação e execução, mas, para este problema, dá para dizer que GPU é uma opção muito mais adequada
Em segundo lugar, o projeto do post original também, como o llama.cpp, criou código eficiente e altamente especializado depois que se confirmou que modelos específicos como Stable Diffusion/LLaMA funcionavam bem. Já onde o Python brilha é na fase de prototipagem, quando ainda não se encontrou o modelo adequado. Ainda não vi prototipagem tão fácil e conveniente assim em C++
Não quero diminuir o ótimo trabalho que o pessoal do llama.cpp faz na área de machine learning em CPU. Só que os problemas que eles resolvem são completamente diferentes
Por dentro, há muito tempo é tudo CUDA, C e C++
Python é apenas uma cola muito eficaz que une tudo isso
Foi a única forma pela qual consegui rodar esses modelos sem problemas irritantes. A diferença é enorme. A combinação CUDA e Linux também não é boa, e AMD com Windows é miserável. Imagino que eu não seja o único
No fim das contas, será que era tudo uma questão de largura de banda de memória?
A arquitetura de GPU não trata apenas de capacidade de cálculo, mas também de colocar a memória de trabalho perto das unidades de computação. Cada unidade tem memória local que é sincronizada com a memória global. Será que esse é um dos grandes motivos de GPUs serem fortes nesse tipo de tarefa?
Parece C++, então por que chamar de C/C++?
Vi esse repositório hoje, baixei e compilei uma
.dylibno Mac, e gerei bindings a partir do arquivo de header fornecido usando a ferramenta ffi-gen do DartEstou fazendo experimentos com Flutter e usando FFI para evitar iniciar um subprocesso
No fim, fiquei com uma dor de cabeça enorme e um app quebrado. Amanhã pretendo tentar de novo com a cabeça limpa
Ainda assim, o repositório em si é excelente, e no M1 chegou a rodar em menos de 10 minutos com f16
Vendo exemplos de vários níveis de quantização, é bem impressionante
A mudança de f16 para q8_0 parece mais uma mudança de direção do que perda de qualidade. O resultado em q5_1 parece difícil de distinguir de q8_0
Em modelos de alta precisão, perde-se determinismo, mas, na prática, há chance de ser bastante utilizável
Há benchmarks?
https://github.com/leejet/stable-diffusion.cpp/issues/1
cmake .. -DGGML_CUBLAS=ON -DCMAKE_CUDA_COMPILER=/opt/cuda/bin/nvcce usei uma NVIDIA GeForce RTX 2060 SUPERO modelo foi convertido para FP16
Com essa opção, o tempo por iteração fica entre 8,5 e 9 segundos, e o tempo total para gerar uma imagem é de cerca de 200 segundos