3 pontos por GN⁺ 2023-08-21 | 1 comentários | Compartilhar no WhatsApp
  • 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, .safetensors e .gguf; o modo de conversão transforma os pesos do modelo para .gguf ou .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 cuda e --rng cpu, com o objetivo de manter consistência, respectivamente, com o RNG de GPU do stable-diffusion-webui e 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.cpp como 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

 
GN⁺ 2023-08-21
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

    • O projeto acima também oferece algum suporte a GPU se você passar as flags de compilação do GGML corretas
      Por exemplo, GGML_CUBLAS é suportado na compilação e traz uma melhoria de velocidade bem razoável em comparação com C/C++ puro
    • Por outro lado, é bom para quem não tem uma GPU NVIDIA com 6 GB ou mais de VRAM, mas quer experimentar essas redes neurais localmente
      Mesmo que leve um tempo, dá para rodar em um notebook antigo
    • Se minha memória não falha, também vi uma melhoria de velocidade bem boa com torch.compile, e lembro de ter trabalhado nisso diretamente
      Vou 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

    • Já que estamos falando de CLIP, sempre me preocupa que, com OpenAI e Google entrando em modo competitivo, o próximo modelo no nível do CLIP talvez não seja divulgado
      É 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=ON em um AMD Ryzen 7 5700G, sem GPU dedicada, só com gráficos integrados
    Ao 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 segundos
    Gostaria de saber se esse é o desempenho esperado
    Edit: o OpenBLAS não estava instalado, então essa flag não teve efeito

    • Isso é bom. Basicamente faz o que eu queria um ano atrás[0]
      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
    • É preciso quantizar o modelo, mas cerca de 12 segundos por iteração parece certo
    • Em uma máquina só com CPU, quantização de 8 bits, Intel Core i7 4770S, 16 GB de RAM DDR3, um PC fanless de 10 anos, levou 32 segundos por etapa de amostragem, e a saída ficou normal
  • 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?

    • Reescritas em geral aumentam a qualidade do código, e trocar dependências por código sob medida que faz só o necessário também aumenta a qualidade do código
      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

    • É uma comparação bem estranha
      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
    • Seria muito melhor se todos os modelos de machine learning tivessem uma API de inferência em C simples, para que pudessem ser chamados diretamente a partir de praticamente qualquer linguagem ou plataforma, sem a bagunça de dependências e configuração de ambiente
    • Os componentes críticos para desempenho na stack de machine learning nem são realmente implementados em Python
      Por dentro, há muito tempo é tudo CUDA, C e C++
      Python é apenas uma cola muito eficaz que une tudo isso
    • Sou realmente grato às pessoas que fazem esse tipo de trabalho
      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
    • É interessante que minha CPU consiga rodar alguns deles em forma quantizada a uma velocidade quase parecida com a da GPU
      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++?

    • Pelo que entendo, a dependência de base, ggml, é escrita em C
  • Vi esse repositório hoje, baixei e compilei uma .dylib no Mac, e gerei bindings a partir do arquivo de header fornecido usando a ferramenta ffi-gen do Dart
    Estou 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?

    • Algumas pessoas mediram tempos aqui, e parece levar cerca de 15 a 20 segundos por iteração, dependendo da quantização e do hardware
      https://github.com/leejet/stable-diffusion.cpp/issues/1
    • Compilei com o comando cmake .. -DGGML_CUBLAS=ON -DCMAKE_CUDA_COMPILER=/opt/cuda/bin/nvcc e usei uma NVIDIA GeForce RTX 2060 SUPER
      O 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