<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Docker on IBM UFCG</title><link>https://llm-pt-ibm.github.io/tags/docker/</link><description>Recent content in Docker on IBM UFCG</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>IBM &amp; UFCG - 2025</copyright><lastBuildDate>Wed, 01 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://llm-pt-ibm.github.io/tags/docker/index.xml" rel="self" type="application/rss+xml"/><item><title>Executando VMs com KubeVirt na IBM Power9 (ppc64le)</title><link>https://llm-pt-ibm.github.io/posts/kubevirt-post/</link><pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/kubevirt-post/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este post tem como objetivo apresentar o processo de adaptação do &lt;a href="https://kubevirt.io/" rel="external">KubeVirt&lt;/a> para a arquitetura IBM POWER9 (ppc64le). Serão abordados os principais desafios encontrados, as modificações realizadas no código-fonte, o papel de cada componente e os resultados obtidos ao final do processo.&lt;/p>&lt;p>O KubeVirt é um operador que estende o Kubernetes para gerenciar máquinas virtuais (VMs) como recursos nativos. Em ambientes tradicionais, VMs são gerenciadas por ferramentas como libvirt/virsh, separadas do ecossistema de containers. O KubeVirt elimina essa separação: com ele, é possível criar, iniciar, parar e monitorar VMs usando os mesmos comandos e workflows do Kubernetes — &lt;code>kubectl&lt;/code>, YAML, namespaces e RBAC. As VMs rodam como processos QEMU/KVM reais dentro de pods gerenciados pelo Kubernetes.&lt;/p>&lt;p>A motivação para este trabalho surgiu no contexto do projeto Multiarq, que mantém uma infraestrutura compartilhada de HPC na IBM POWER9. A possibilidade de gerenciar VMs e containers no mesmo cluster Kubernetes simplifica a administração do ambiente e abre caminho para cenários como GPU passthrough para workloads de AI/ML dentro de VMs, isolamento de ambientes de pesquisa e testes de compatibilidade multi-arquitetura.&lt;/p>&lt;p>O principal desafio é que o KubeVirt &lt;strong>não oferece suporte oficial para ppc64le&lt;/strong>. Apenas x86_64 (amd64), arm64 e s390x são suportados. Isso significa que o sistema de build, as validações da API, os defaults de configuração e o pipeline de geração de domínios libvirt não reconhecem ppc64le, tratando tudo como amd64 por padrão.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>O KubeVirt não suporta ppc64le oficialmente; todo o pipeline assume amd64 como fallback.&lt;/li>&lt;li>Compilamos os binários Go diretamente, contornando o sistema de build Bazel que não reconhece a arquitetura.&lt;/li>&lt;li>Foram necessários patches em ~14 arquivos Go e a criação de 4 arquivos novos para adicionar suporte a ppc64le.&lt;/li>&lt;li>As imagens Docker foram criadas com Dockerfiles customizados e servidas via registry local.&lt;/li>&lt;li>Com as adaptações, foi possível executar uma VM CirrOS ppc64le via KubeVirt no POWER9, gerenciada inteiramente pelo Kubernetes.&lt;/li>&lt;/ul>&lt;h2 id="ambiente-de-execução">Ambiente de Execução&lt;/h2>&lt;ul>&lt;li>&lt;strong>Arquitetura:&lt;/strong> Servidor IBM Power9 (ppc64le).&lt;/li>&lt;li>&lt;strong>Sistema Operacional:&lt;/strong> AlmaLinux 8.10, binário compatível com RHEL 8.9/8.10.&lt;/li>&lt;li>&lt;strong>GPUs:&lt;/strong> 4x NVIDIA Tesla V100-SXM2-16GB.&lt;/li>&lt;li>&lt;strong>Docker:&lt;/strong> Docker CE 26.1.3.&lt;/li>&lt;li>&lt;strong>Kubernetes:&lt;/strong> v1.35.0 via minikube v1.38.0 (driver docker, runtime containerd).&lt;/li>&lt;li>&lt;strong>KubeVirt:&lt;/strong> v1.8.2.&lt;/li>&lt;li>&lt;strong>Go:&lt;/strong> 1.24.9.&lt;/li>&lt;/ul>&lt;h2 id="o-que-é-o-kubevirt-e-como-ele-funciona">O que é o KubeVirt e como ele funciona&lt;/h2>&lt;p>O KubeVirt é composto por vários componentes que trabalham juntos para traduzir um recurso Kubernetes (a VirtualMachineInstance, ou VMI) em uma VM QEMU/KVM real rodando no host.&lt;/p>&lt;p>O &lt;strong>virt-operator&lt;/strong> é o ponto de entrada: quando o administrador cria o Custom Resource KubeVirt no cluster, o operator provisiona todos os outros componentes — deployments, daemonsets, services, RBAC. Ele funciona como um instalador permanente que reconcilia o estado desejado.&lt;/p>&lt;p>O &lt;strong>virt-api&lt;/strong> recebe as chamadas da API do Kubernetes para os recursos do KubeVirt. Quando o usuário faz &lt;code>kubectl apply&lt;/code> de uma VMI, o virt-api valida o YAML (ex: a arquitetura é suportada? o machine type existe?) e injeta defaults (ex: firmware UUID, CPU topology).&lt;/p>&lt;p>O &lt;strong>virt-controller&lt;/strong> observa as VMIs e decide onde elas devem rodar. Ele cria um pod especial — o virt-launcher — no node adequado, com todas as configurações necessárias (volumes, devices, node selectors).&lt;/p>&lt;p>O &lt;strong>virt-handler&lt;/strong> roda como DaemonSet (um por node) e é o agente local que faz a ponte entre Kubernetes e libvirt/QEMU. Quando o pod do virt-launcher aparece no node, o virt-handler lê a spec da VMI, gera o XML do domínio libvirt e instrui o libvirt a criar a VM. Também registra device plugins no kubelet (&lt;code>/dev/kvm&lt;/code>, &lt;code>/dev/net/tun&lt;/code>, &lt;code>/dev/vhost-net&lt;/code>) para que os pods possam acessar os dispositivos necessários.&lt;/p>&lt;p>O &lt;strong>virt-launcher&lt;/strong> é o pod que encapsula a VM. Cada VMI gera um pod dedicado com três containers: o compute (QEMU + libvirt), o guest-console-log e o container disk. Dentro do container compute, o processo QEMU roda a VM real — com seu próprio kernel, memória e CPU virtual.&lt;/p>&lt;p>O fluxo completo é:&lt;/p>&lt;ol>&lt;li>&lt;code>kubectl apply&lt;/code> → API Server → virt-api (valida, injeta defaults)&lt;/li>&lt;li>virt-controller detecta a VMI → cria o pod virt-launcher no node adequado&lt;/li>&lt;li>kubelet inicia o pod virt-launcher no node&lt;/li>&lt;li>virt-handler detecta o pod → lê a spec da VMI → gera XML libvirt → chama o libvirt&lt;/li>&lt;li>libvirt inicia o QEMU → VM roda dentro do pod&lt;/li>&lt;/ol>&lt;p>É importante ressaltar que a VM &lt;strong>não vira um container&lt;/strong> — ela roda como um processo QEMU real dentro de um pod. O Kubernetes gerencia o ciclo de vida do pod, e o KubeVirt traduz entre os dois mundos.&lt;/p>&lt;h2 id="desafios-e-adaptações">Desafios e Adaptações&lt;/h2>&lt;h3 id="sistema-de-build">Sistema de Build&lt;/h3>&lt;p>O sistema de build do KubeVirt utiliza Bazel, que não reconhece ppc64le. A função &lt;code>format_archname&lt;/code> no script de build só aceita &lt;code>x86_64&lt;/code>, &lt;code>aarch64&lt;/code> e &lt;code>s390x&lt;/code>. A solução foi compilar os binários Go diretamente com &lt;code>go build&lt;/code>, contornando o Bazel.&lt;/p>&lt;p>Uma dependência adicional é o &lt;strong>libnbd&lt;/strong>: o virt-launcher requer a versão 1.18+, mas o AlmaLinux 8 só disponibiliza a 1.6. Foi necessário compilar o libnbd 1.20 do fonte. O componente &lt;strong>container-disk&lt;/strong> é um programa C (não Go) que precisa de compilação estática para rodar em containers &lt;code>FROM scratch&lt;/code>.&lt;/p>&lt;h3 id="validação-da-api">Validação da API&lt;/h3>&lt;p>O webhook de validação do virt-api rejeita VMIs com arquitetura desconhecida. Sem o patch, uma VMI com &lt;code>architecture: ppc64le&lt;/code> seria recusada antes mesmo de chegar ao scheduler. Foi necessário adicionar cases no admitter e criar uma função de validação específica para ppc64le.&lt;/p>&lt;h3 id="defaults-de-configuração">Defaults de Configuração&lt;/h3>&lt;p>O KubeVirt precisa saber qual machine type usar para cada arquitetura (ex: &lt;code>pc-q35&lt;/code> para amd64, &lt;code>virt&lt;/code> para arm64). Para ppc64le, configuramos &lt;code>pseries&lt;/code> como machine type padrão — o tipo de máquina virtual do POWER.&lt;/p>&lt;h3 id="geração-do-domínio-libvirt">Geração do Domínio Libvirt&lt;/h3>&lt;p>Este foi o desafio central. O KubeVirt converte a spec da VMI em um XML de domínio libvirt que o QEMU interpreta. Esse pipeline tem duas partes:&lt;/p>&lt;p>O &lt;strong>arch-defaulter&lt;/strong> define valores padrão do OS type (&lt;code>arch&lt;/code> e &lt;code>machine&lt;/code>) no XML. Sem o patch, ele retornava &lt;code>x86_64&lt;/code> para ppc64le, fazendo o libvirt tentar criar uma VM x86 numa máquina POWER — resultando no erro &lt;code>No emulator found for arch 'x86_64'&lt;/code>.&lt;/p>&lt;p>O &lt;strong>converter&lt;/strong> é uma interface com ~12 métodos que definem comportamentos específicos de cada arquitetura: se precisa de USB, SMBIOS, PCIe placement, ROM tuning, etc. Existiam implementações para amd64, arm64 e s390x, mas não para ppc64le. O código caía no fallback &lt;code>converterAMD64&lt;/code>, gerando configurações incompatíveis. Criamos o &lt;code>converterPPC64LE&lt;/code> com valores adequados para POWER: sem USB, sem SMBIOS, sem PCIe placement, com VirtIO como modelo de disco.&lt;/p>&lt;p>Resolvido o converter, surgiu o erro de &lt;strong>dispositivos USB&lt;/strong>: o pipeline de graphics/video não tinha case para ppc64le, fazendo o libvirt adicionar um video device VGA default que dependia de USB — mas o controller USB estava desabilitado (&lt;code>IsUSBNeeded: false&lt;/code>). A solução foi adicionar um case ppc64le no configurador de video com &lt;code>virtio&lt;/code> como dispositivo de vídeo, seguindo o mesmo padrão do s390x e arm64.&lt;/p>&lt;p>Por fim, o &lt;strong>CPU model&lt;/strong>: o KubeVirt usa &lt;code>host-model&lt;/code> como default, que não funciona em virtualização aninhada no POWER9. A solução foi especificar &lt;code>POWER9&lt;/code> como CPU model na VMI.&lt;/p>&lt;h3 id="imagens-docker">Imagens Docker&lt;/h3>&lt;p>Sem Dockerfiles no projeto (tudo é gerado pelo Bazel), criamos Dockerfiles customizados para cada componente. Os componentes mais simples (virt-operator, virt-api, virt-controller, virt-exportproxy) usam &lt;code>ubi8/ubi-minimal&lt;/code> como base. O virt-handler requer ferramentas de sistema adicionais. O virt-launcher é o mais complexo, com &lt;code>almalinux:8&lt;/code> como base e dependências de qemu-kvm, libvirt e o libnbd compilado. Um registry local (&lt;code>registry:2&lt;/code> na porta 5000) serve as imagens para o minikube.&lt;/p>&lt;h3 id="passo-a-passo-técnico">Passo a Passo Técnico&lt;/h3>&lt;p>Devido à grande quantidade de etapas envolvidas, o passo a passo com os procedimentos detalhados, incluindo todos os patches no código Go, Dockerfiles, comandos de compilação e configuração, está disponível neste link: &lt;a href="https://github.com/llm-pt-ibm/kubevirt-ppc64le" rel="external">guia-instalacao-kubevirt-ppc64le&lt;/a>.&lt;/p>&lt;h2 id="resultados">Resultados&lt;/h2>&lt;p>Com todas as adaptações aplicadas, foi possível executar uma VM CirrOS ppc64le via KubeVirt no POWER9, gerenciada inteiramente pelo Kubernetes:&lt;/p>&lt;pre tabindex="0">&lt;code>$ kubectl get vmi test-vmi -o wideNAME AGE PHASE IP NODENAME READYtest-vmi 2m43s Running 10.244.120.124 minikube True&lt;/code>&lt;/pre>&lt;p>Dados coletados de dentro da VM confirmam a execução correta:&lt;/p>&lt;table>&lt;thead>&lt;tr>&lt;th>&lt;/th>&lt;th>Valor&lt;/th>&lt;/tr>&lt;/thead>&lt;tbody>&lt;tr>&lt;td>Arquitetura&lt;/td>&lt;td>ppc64le&lt;/td>&lt;/tr>&lt;tr>&lt;td>CPU&lt;/td>&lt;td>POWER9 (architected), altivec supported&lt;/td>&lt;/tr>&lt;tr>&lt;td>Hypervisor&lt;/td>&lt;td>KVM&lt;/td>&lt;/tr>&lt;tr>&lt;td>Plataforma&lt;/td>&lt;td>pSeries&lt;/td>&lt;/tr>&lt;tr>&lt;td>Modelo&lt;/td>&lt;td>IBM pSeries (emulated by qemu)&lt;/td>&lt;/tr>&lt;tr>&lt;td>Kernel&lt;/td>&lt;td>5.15.0-71-generic ppc64le&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>&lt;p>Esses dados confirmam que o KubeVirt está gerando o domínio libvirt correto para ppc64le, com machine type &lt;code>pseries&lt;/code>, CPU POWER9 e virtualização KVM/QEMU com paravirtualização VirtIO.&lt;/p>&lt;h2 id="considerações-finais">Considerações Finais&lt;/h2>&lt;p>Com as adaptações realizadas, tornou-se possível utilizar o KubeVirt para criar e gerenciar máquinas virtuais em uma IBM POWER9 via Kubernetes. A VM executada é uma VM KVM/QEMU real — com kernel próprio, memória isolada e CPU virtual — gerenciada como qualquer outro recurso Kubernetes.&lt;/p>&lt;p>No contexto do projeto Multiarq, essa solução permite unificar a gestão de containers e VMs no mesmo cluster, simplificando a administração da infraestrutura compartilhada. Workloads que exigem isolamento de kernel ou acesso direto a hardware (como GPU passthrough) podem ser executados em VMs sem abandonar o ecossistema Kubernetes.&lt;/p>&lt;p>Os patches realizados são potencialmente contribuíveis ao projeto KubeVirt upstream. A arquitetura do KubeVirt já prevê extensibilidade por arquitetura — o padrão de interfaces (Converter, ArchDefaulter) e switches por arch facilita a adição de novas plataformas. O ppc64le segue o mesmo padrão do s390x, que também foi adicionado posteriormente ao projeto.&lt;/p>&lt;h2 id="próximos-passos">Próximos Passos&lt;/h2>&lt;ul>&lt;li>Resolver o conflito USB/Graphics para permitir VNC sem o workaround &lt;code>autoattachGraphicsDevice: false&lt;/code>, habilitando acesso gráfico às VMs;&lt;/li>&lt;li>Ajustar o CPU model default no código para que ppc64le use &lt;code>POWER9&lt;/code> automaticamente, sem exigir especificação manual na VMI;&lt;/li>&lt;li>Explorar GPU passthrough das V100 via KubeVirt para executar workloads de AI/ML dentro de VMs gerenciadas pelo Kubernetes;&lt;/li>&lt;li>Testar outras distribuições como containerDisk (Fedora, Ubuntu Server, AlmaLinux ppc64le) para validar a compatibilidade além do CirrOS;&lt;/li>&lt;li>Configurar masquerade networking para habilitar live migration entre nodes;&lt;/li>&lt;li>Documentar as mudanças em formato de PR para contribuição ao KubeVirt upstream;&lt;/li>&lt;li>Validar o KubeVirt no Single Node OpenShift (OCP 4.21) já instalado na máquina, usando o OpenShift Virtualization como operador.&lt;/li>&lt;/ul></description></item><item><title>TensorFlow 2.21 CPU na IBM Power9 (ppc64le)</title><link>https://llm-pt-ibm.github.io/posts/post_tf221_power9/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/post_tf221_power9/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>O TensorFlow (TF) é o framework de machine learning mais adotado globalmente. No entanto, desde 2021, o Google encerrou o suporte oficial de binários pré-compilados para a arquitetura ppc64le, e o repositório comunitário &lt;code>tensorflow/community&lt;/code> foi arquivado em 2025.&lt;/p>&lt;h2 id="ambiente-utilizado">Ambiente utilizado&lt;/h2>&lt;ul>&lt;li>&lt;strong>Hardware:&lt;/strong> Arquitetura ppc64le;&lt;/li>&lt;li>&lt;strong>RAM:&lt;/strong> ~64GB;&lt;/li>&lt;li>&lt;strong>Execução:&lt;/strong> Máquina Virtual (VM);&lt;/li>&lt;li>&lt;strong>Sistema Operacional:&lt;/strong> Alma Linux 8.10 (ppc64le), binário compatível com Red Hat Enterprise Linux (RHEL) 8.9/8.10.&lt;/li>&lt;/ul>&lt;h2 id="setup-inicial-instalação-do-tf-214">Setup Inicial (Instalação do TF 2.14)&lt;/h2>&lt;p>Como ponto de partida, validamos a instalação do TensorFlow 2.14.1 (via RocketCE) em uma VM IBM Power9 (arquitetura ppc64le) com AlmaLinux, usando Miniforge (conda). Seguem os comandos para a instalação:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>conda create -n tf214 python&lt;span style="color:#f92672">=&lt;/span>3.11 -y&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>conda activate tf214&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>conda install -c rocketce tensorflow-cpu&lt;span style="color:#f92672">=&lt;/span>2.14.1 -y&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># saída esperada: 2.14.1&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python -c &lt;span style="color:#e6db74">&amp;#34;import tensorflow as tf; print(tf.__version__)&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Como resultado, espera-se o TensorFlow 2.14.1 funcional. Essa mesma versão também está disponível nos canais Open-CE da Oregon State University e do MIT. Com o TF 2.14 funcionando, temos acesso ao: Keras, TensorBoard, TensorFlow Hub, tensorflow-text, Hugging Face Transformers, Jupyter, e todo o stack de ML clássico.&lt;/p>&lt;h2 id="tf-214-vs-tf-221-o-mais-recente">TF 2.14 vs TF 2.21 (o mais recente)&lt;/h2>&lt;p>A versão 2.14 é funcional, mas está a algumas versões de distância da mais recente, a 2.21. As diferenças mais significativas se concentram na incompatibilidade com duas ferramentas muito importantes:&lt;/p>&lt;ul>&lt;li>&lt;strong>Keras 3:&lt;/strong> uma reescrita completa que transforma o Keras em um framework multi-backend, que permite rodar o mesmo modelo e o mesmo código em TensorFlow, PyTorch ou JAX sem qualquer alteração. O TF 2.14 dá suporte apenas ao Keras 2.&lt;/li>&lt;li>&lt;strong>NumPy 2:&lt;/strong> Além de corrigir dezenas de inconsistências históricas da API, o NumPy 2.0 traz ganhos significativos de eficiência. O TF 2.14 não suporta o NumPy 2.&lt;/li>&lt;/ul>&lt;h2 id="compilando-o-tensorflow-221-nativamente-no-power9-cpu-only">Compilando o TensorFlow 2.21 Nativamente no Power9 (CPU-Only)&lt;/h2>&lt;p>Inicialmente, compilamos com sucesso o TensorFlow 2.21 (CPU-Only) diretamente a partir do código-fonte. Essa compilação foi realizada em uma VM IBM Power9 e gerou um pacote &lt;code>.whl&lt;/code> nativo para &lt;code>linux_ppc64le&lt;/code>. Em seguida, o TF 2.21 teve seu funcionamento validado através de uma suíte completa de testes. Este é um marco fundamental sobre o qual o suporte a GPU será construído na próxima etapa.&lt;/p>&lt;h2 id="desafios-hermetismo-e-dependência-de-x86">Desafios: Hermetismo e Dependência de x86&lt;/h2>&lt;p>A arquitetura moderna do TensorFlow (e seu sistema de build, o Bazel 7) abraçou o modelo &amp;ldquo;Hermético&amp;rdquo;: forçando o uso de binários pré-compilados e lógicas atreladas às arquiteturas x86_64, aarch64 e aceleradores NVIDIA. Para ppc64le, isso significa que a compilação naive simplesmente falha ao tentar baixar ferramentas para arquiteturas incompatíveis.&lt;/p>&lt;h3 id="identificamos-quatro-categorias-de-bloqueio">Identificamos quatro categorias de bloqueio:&lt;/h3>&lt;ol>&lt;li>&lt;strong>Bazel 7:&lt;/strong> O Google não distribui o Bazel 7 para PowerPC. Seria necessário compilá-lo do zero.&lt;/li>&lt;li>&lt;strong>Toolchains herméticas:&lt;/strong> O TF 2.21 tenta baixar LLVM/Clang pré-compilado para x86 ou aarch64, que não executa no Power9.&lt;/li>&lt;li>&lt;strong>Dependências CUDA/GPU:&lt;/strong> Mesmo em modo CPU-only, o sistema de build tenta baixar e vincular bibliotecas NVIDIA gigantes. Nossa estratégia foi isolar completamente o suporte a GPU com stubs vazios, garantindo uma fundação CPU-only estável antes de adicionar qualquer acelerador.&lt;/li>&lt;li>&lt;strong>Bugs de C++ latentes:&lt;/strong> O código do XLA e do MLIR contém construções que funcionam no Clang do Google, mas quebram no GCC 8.5 padrão do sistema, de flags AVX-512 até ambiguidades de template em &lt;code>absl::NoDestructor&lt;/code>.&lt;/li>&lt;/ol>&lt;h2 id="processo-de-compilação">Processo de Compilação&lt;/h2>&lt;h3 id="etapa-1-compilando-o-bazel-710-do-zero">Etapa 1: Compilando o Bazel 7.1.0 do Zero&lt;/h3>&lt;p>Como o Google não distribui o Bazel 7 para ppc64le, o primeiro passo para permitir seu uso em arquitetura ppc64le foi compilar o próprio Bazel a partir do seu código-fonte, usando o arquivo &lt;code>-dist.zip&lt;/code>, que já inclui os artefatos de bootstrap necessários para que o Bazel se autoconstrua sem depender de uma versão anterior de si mesmo. O processo exige Java 21 e leva entre 1 e 2 horas dependendo dos núcleos disponíveis na VM. O ponto crítico aqui é passar as variáveis corretas para o script &lt;code>compile.sh&lt;/code>. Sem esse passo, nenhuma das etapas seguintes é possível. O comando &lt;code>bazel build&lt;/code> simplesmente não existe para ppc64le de outra forma. Criamos um &lt;a href="https://github.com/llm-pt-ibm/TensorFlow-2.21-Power9/blob/main/bazel/tutorial_bazel7_power9.md" rel="external">tutorial&lt;/a> com o processo de instalação do Bazel 7.1 que pode ser acessado no repositório.&lt;/p>&lt;h3 id="etapa-2-estratégia-de-bypass--repositórios-stub">Etapa 2: Estratégia de Bypass — Repositórios Stub&lt;/h3>&lt;p>Com o Bazel 7 funcional em arquitetura ppc64le, atacamos o problema das dependências herméticas. Nossa solução foi criar repositórios &amp;ldquo;stub&amp;rdquo;, diretórios locais vazios que satisfazem as declarações de dependência do Bazel sem baixar nada:&lt;/p>&lt;ul>&lt;li>&lt;strong>LLVM stubs:&lt;/strong> Filesgroups vazios que satisfazem as regras de toolchain sem tentar instalar o LLVM.&lt;/li>&lt;li>&lt;strong>CUDA/ROCm/TensorRT stubs:&lt;/strong> Bibliotecas C++ e regras Starlark vazias que permitem que o build prossiga sem erros de dependência faltante.&lt;/li>&lt;li>&lt;strong>PyPI stubs:&lt;/strong> Módulos Python stub que simulam as dependências do pip hermético do Google, forçando o uso das bibliotecas do ambiente conda.&lt;/li>&lt;li>&lt;strong>Python stub:&lt;/strong> Redireciona para o Python do nosso ambiente conda, contornando o download do Python hermético que não existe para ppc64le.&lt;/li>&lt;/ul>&lt;p>Todos os stubs são injetados via &lt;code>--override_repository&lt;/code> na chamada do &lt;code>bazel build&lt;/code>, sem alterar o código-fonte do TensorFlow.&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/tf221_bypass_strategy.png" alt="Estratégia de Bypass"/>&lt;figcaption> &lt;p>Estratégia de Bypass - Repositórios Stub&lt;/p> &lt;/figcaption>&lt;/figure>&lt;h3 id="etapa-3-patches-cirúrgicos-no-código-fonte">Etapa 3: Patches Cirúrgicos no Código-Fonte&lt;/h3>&lt;p>Com a infraestrutura de build resolvida, encontramos 21 incompatibilidades no código C++ e Python do TensorFlow que se manifestam exclusivamente na combinação GCC 13 + ppc64le. Os problemas se concentraram em três categorias:&lt;/p>&lt;ol>&lt;li>Flags de compilação exclusivas do Clang que o GCC rejeita.&lt;/li>&lt;li>Ambiguidades de templates C++ em componentes do XLA e MLIR que o compilador do Google mascara mas o GCC 13 expõe.&lt;/li>&lt;li>Referências a headers de CUDA e TensorRT que deixam de existir quando substituídos pelos stubs.&lt;/li>&lt;/ol>&lt;p>Cada incompatibilidade foi resolvida com um patch Python preciso, sem alterar a lógica funcional do TensorFlow. A &lt;a href="https://github.com/llm-pt-ibm/TensorFlow-2.21-Power9/blob/main/cpu/tutorial_tf221_power9.md" rel="external">tabela completa com todos os 21 patches&lt;/a> está disponível no repositório.&lt;/p>&lt;h3 id="etapa-4-a-compilação">Etapa 4: A Compilação&lt;/h3>&lt;p>Com todos os patches aplicados, a compilação final é disparada com um único comando &lt;code>bazel build&lt;/code>. Além das flags de otimização padrão, o comando injeta todos os repositórios stub via &lt;code>--override_repository&lt;/code>, totalizando cerca de 80 flags. O cache incremental do Bazel é fundamental aqui: cada vez que um patch é necessário e a compilação é retomada, apenas os alvos afetados são recompilados. Isso transformou o ciclo &amp;ldquo;patch → compilar → erro → patch&amp;rdquo; de inviável em gerenciável (cerca de 4 horas).&lt;/p>&lt;h2 id="a-solução-definitiva-pacote-conda-e-binários-pronto-para-uso">A Solução Definitiva: Pacote Conda e Binários (Pronto para Uso)&lt;/h2>&lt;p>Para que a comunidade não precise refazer todo esse complexo processo de build, nós empacotamos o resultado dessa engenharia em uma solução &amp;ldquo;plug and play&amp;rdquo;.&lt;/p>&lt;p>Disponibilizamos uma &lt;a href="https://github.com/llm-pt-ibm/tensorflow/releases/tag/v2.21.0-cpu-only" rel="external">Release oficial&lt;/a> no repositório contendo o código-fonte já com todos os patches aplicados e o binário &lt;code>.whl&lt;/code> gerado nativamente. Mais importante ainda: criamos e publicamos uma receita Conda completa que resolve de forma automática os clássicos problemas de compatibilidade de bibliotecas C++ (GLIBCXX e GCC mismatch) comuns no Power9.&lt;/p>&lt;p>Agora, o TensorFlow 2.21 nativo pode ser instalado diretamente através do nosso canal Conda, proporcionando a mesma experiência de instalação oficial de distribuições corporativas.&lt;/p>&lt;h2 id="como-instalar-tutorial-rápido">Como Instalar (Tutorial Rápido)&lt;/h2>&lt;p>Para utilizar o TensorFlow 2.21 em seu ambiente Power9 imediatamente, basta executar:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>conda create -n tf221 python&lt;span style="color:#f92672">=&lt;/span>3.11 -y&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>conda activate tf221&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>conda install -c ufcg-ibm -c conda-forge tensorflow-cpu&lt;span style="color:#f92672">=&lt;/span>2.21.0 -y&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Um &lt;a href="https://github.com/llm-pt-ibm/TensorFlow-2.21-Power9/blob/main/cpu/install-tensorflow-ppc64le.md" rel="external">tutorial detalhado de instalação via Conda&lt;/a> também está disponível no nosso repositório.&lt;/p>&lt;h2 id="resultado-funcional-no-servidor-ibm-power9">Resultado Funcional no servidor IBM Power9&lt;/h2>&lt;p>Instalamos o pacote final e executamos uma suíte completa de 35 testes, cobrindo oito categorias funcionais: desde operações básicas com tensores até save/load de modelos e testes de stress. Todos os 35 testes passaram. O teste de stress (multiplicação de matrizes 5000×5000) executou com sucesso na CPU do IBM Power9, e o treinamento de um MLP por 20 épocas confirmou convergência de loss, indicando que diferenciação automática, otimizadores e operações numéricas estão todos funcionando corretamente de ponta a ponta.&lt;/p>&lt;h2 id="ferramentas-ibm-que-usam-tensorflow">Ferramentas IBM que usam TensorFlow&lt;/h2>&lt;p>Ferramentas de IA da IBM como AIF360, AIX360 e ART, já eram compatíveis com o TensorFlow 2.14, pois são bibliotecas Python que utilizam o TF do ambiente sem acoplamento binário. O valor real do TensorFlow 2.21 compilado nativamente para Power9 está na continuidade: essas bibliotecas já começavam a declarar dependências em versões de TF superiores ao 2.14, o que significava que, sem esse build, o ambiente no Power9 ficaria preso em versões antigas e sem suporte. Além disso, as melhorias acumuladas no TF entre as versões 2.14 e 2.21 trazem ganhos incrementais de desempenho para os pipelines de análise de fairness, explicabilidade e robustez adversarial.&lt;/p>&lt;h2 id="reprodutibilidade-e-materiais">Reprodutibilidade e Materiais&lt;/h2>&lt;p>Todo o processo e os artefatos gerados estão documentados e disponíveis em nosso repositório:&lt;/p>&lt;ul>&lt;li>&lt;strong>&lt;a href="https://github.com/llm-pt-ibm/tensorflow/releases/tag/v2.21.0-cpu-only" rel="external">Release oficial&lt;/a>:&lt;/strong> Código-fonte alterado e o binário &lt;code>.whl&lt;/code> pronto.&lt;/li>&lt;li>&lt;strong>&lt;a href="https://github.com/llm-pt-ibm/TensorFlow-2.21-Power9/blob/main/cpu/install-tensorflow-ppc64le.md" rel="external">tutorial_instalacao_conda.md&lt;/a>:&lt;/strong> Guia prático para instalar a versão 2.21 diretamente pelo nosso canal Conda.&lt;/li>&lt;li>&lt;strong>&lt;a href="https://github.com/llm-pt-ibm/TensorFlow-2.21-Power9/blob/main/bazel/tutorial_bazel7_power9.md" rel="external">tutorial_bazel7_power9.md&lt;/a>:&lt;/strong> Compilação do Bazel 7.1.0 a partir do código-fonte.&lt;/li>&lt;li>&lt;strong>&lt;a href="https://github.com/llm-pt-ibm/TensorFlow-2.21-Power9/blob/main/cpu/tutorial_tf221_power9.md" rel="external">tutorial_tf221_power9.md&lt;/a>:&lt;/strong> Compilação do TensorFlow 2.21 com todos os patches.&lt;/li>&lt;/ul>&lt;h2 id="impacto">Impacto&lt;/h2>&lt;p>Esta compilação representa a versão mais recente do TensorFlow disponível nativamente para ppc64le e com ela:&lt;/p>&lt;ul>&lt;li>&lt;strong>Keras 3&lt;/strong> fica disponível para ppc64le pela primeira vez.&lt;/li>&lt;li>&lt;strong>NumPy 2.0&lt;/strong> deixa de ser um gargalo para o ecossistema científico Python no IBM Power9.&lt;/li>&lt;li>&lt;strong>Stack Hugging Face Transformers&lt;/strong> com mais modelos compatíveis com a Power9.&lt;/li>&lt;/ul>&lt;h2 id="próximos-passos">Próximos Passos&lt;/h2>&lt;p>O TF 2.21 que compilamos roda exclusivamente em CPU. O próximo desafio é repetir o processo com CUDA habilitado em servidores IBM Power9 equipados com GPUs NVIDIA. Os stubs que criamos para isolar a GPU nesta compilação foram projetados justamente para facilitar essa transição: ao substituí-los pelas bibliotecas CUDA reais, teremos um ponto de partida sólido para a compilação GPU. Se bem-sucedido, o Power9 passaria a ter o framework de deep learning mais recente com aceleração de hardware, algo inexistente hoje em qualquer distribuição para ppc64le.&lt;/p></description></item><item><title>Inferência de LLMs com Ollama na IBM Power9 Utilizando GPU</title><link>https://llm-pt-ibm.github.io/posts/ollama_gpu/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/ollama_gpu/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este é o segundo post da série sobre inferência de modelos de linguagem na POWER9 com o &lt;a href="https://ollama.com/" rel="external">&lt;span class="link-personalizado">&lt;em>Ollama&lt;/em>&lt;/span>&lt;/a>. Neste post, abordaremos como enviar requisições utilizando GPU, obtendo um ganho significativo de desempenho em relação à abordagem via CPU apresentada no &lt;a href="https://llm-pt-ibm.github.io/posts/ollama_cpu/" rel="external">&lt;span class="link-personalizado">&lt;em>post anterior&lt;/em>&lt;/span>&lt;/a>.&lt;/p>&lt;p>O principal desafio é que o Ollama não oferece suporte oficial para a arquitetura &lt;em>ppc64le&lt;/em> com &lt;a href="https://developer.nvidia.com/cuda-12-2-0-download-archive?target_os=Linux&amp;target_arch=ppc64le&amp;Distribution=RHEL&amp;target_version=8&amp;target_type=rpm_local" rel="external">&lt;span class="link-personalizado">&lt;em>CUDA&lt;/em>&lt;/span>&lt;/a>. A solução encontrada foi através de um blog da &lt;a href="https://community.ibm.com/community/user/blogs/andrey-klyachkin/2025/03/06/run-ollama-on-almalinux-ppc64le-ibm-power" rel="external">&lt;span class="link-personalizado">&lt;em>comunidade oficial IBM&lt;/em>&lt;/span>&lt;/a>, onde um contribuidor disponibilizou um &lt;a href="https://github.com/naveedus/ollama-ppc64le" rel="external">&lt;span class="link-personalizado">&lt;em>fork&lt;/em>&lt;/span>&lt;/a> do Ollama adaptado para suportar GPUs NVIDIA na POWER9 via CUDA. No entanto, esse fork está desatualizado e não suporta modelos mais recentes como Gemma 3 e DeepSeek.&lt;/p>&lt;p>Por isso, desenvolvemos um &lt;a href="https://github.com/llm-pt-ibm/ollama-ppc64le" rel="external">&lt;span class="link-personalizado">&lt;em>fork atualizado&lt;/em>&lt;/span>&lt;/a>, baseado no Ollama oficial (v0.23.2), com os patches necessários para ppc64le e suporte a GPU via CUDA. Este tutorial explica como compilar o Ollama para a arquitetura ppc64le, e para quem não quiser compilar, também disponibilizamos um &lt;a href="https://github.com/llm-pt-ibm/ollama-ppc64le/releases/tag/v0.23.2-ppc64le-power9" rel="external">&lt;span class="link-personalizado">&lt;em>binário pré-compilado&lt;/em>&lt;/span>&lt;/a> nas &lt;em>releases&lt;/em> no GitHub.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta detalhes sobre a configuração do ambiente para realizar inferências utilizando a infraestrutura da IBM POWER9;&lt;/li>&lt;li>O Ollama não oferece suporte oficial para &lt;em>ppc64le&lt;/em> com CUDA;&lt;/li>&lt;li>O fork foi compilado do zero utilizando CMake e Go, apontando para CUDA 12.2 e especificando a arquitetura do V100 (&lt;code>sm_70&lt;/code>);&lt;/li>&lt;li>Um binário pré-compilado também está disponível no github do projeto;&lt;/li>&lt;li>Com isso, foi possível executar inferência de LLMs na IBM POWER9 com aceleração GPU e suporte para modelos recentes.&lt;/li>&lt;/ul>&lt;h2 id="ambiente-utilizado">Ambiente utilizado&lt;/h2>&lt;p>&lt;strong>Hardware&lt;/strong>:&lt;/p>&lt;ul>&lt;li>Arquitetura &lt;em>ppc64le&lt;/em>;&lt;/li>&lt;li>RAM: mínimo recomendado de ~64GB;&lt;/li>&lt;li>GPU: NVIDIA Tesla V100;&lt;/li>&lt;li>&lt;em>Driver&lt;/em> NVIDIA: 535.54.03;&lt;/li>&lt;li>CUDA: versão 12.2.&lt;/li>&lt;/ul>&lt;p>&lt;strong>Sistema Operacional:&lt;/strong> Alma Linux 8.10 (&lt;em>ppc64le&lt;/em>), binário compatível com &lt;em>Red Hat Enterprise Linux (RHEL)&lt;/em> 8.9/8.10.&lt;/p>&lt;h2 id="verificações-iniciais">Verificações iniciais&lt;/h2>&lt;ol>&lt;li>Verificar se o driver e a GPU estão visíveis&lt;/li>&lt;/ol>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nvidia-smi&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">&lt;li>Verificar se o CUDA está instalado&lt;/li>&lt;/ol>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nvcc --version&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>OBS: Se não aparecer nada, tente:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>export PATH&lt;span style="color:#f92672">=&lt;/span>/usr/local/cuda-12.2/bin:$PATH&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>export CUDACXX&lt;span style="color:#f92672">=&lt;/span>/usr/local/cuda-12.2/bin/nvcc&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">&lt;li>Verifique também se o CUDA 12 existe:&lt;/li>&lt;/ol>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ls -la /usr/local/cuda-12&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="execução-em-ambiente-virtual">Execução em Ambiente Virtual&lt;/h2>&lt;p>Neste tutorial, estamos fazendo as configurações necessárias em um ambiente virtual para isolar o ambiente de execução e as configurações utilizadas. Essa execução é opcional, mas recomendada.&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>conda create -n ollamaGPU python&lt;span style="color:#f92672">=&lt;/span>3.11 -y&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>conda activate ollamaGPU&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para desativar o ambiente:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>conda deactivate&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="setup-inicial">&lt;em>Setup&lt;/em> inicial&lt;/h2>&lt;p>Para compilar o Ollama na POWER9, são necessárias as seguintes dependências com as versões adequadas:&lt;/p>&lt;ul>&lt;li>&lt;strong>Go:&lt;/strong> 1.26.0&lt;/li>&lt;li>&lt;strong>GCC:&lt;/strong> 11.2.1 (via gcc-toolset-11)&lt;/li>&lt;li>&lt;strong>CMake:&lt;/strong> &amp;gt;= 3.24&lt;/li>&lt;/ul>&lt;h2 id="clonando-e-compilando-o-ollama">Clonando e compilando o Ollama&lt;/h2>&lt;p>Com o ambiente configurado, podemos realizar o &lt;em>build&lt;/em> do Ollama. A compilação utiliza CMake para gerar os &lt;em>kernels&lt;/em> CUDA com &lt;code>nvcc&lt;/code>, e Go para compilar o binário. Um detalhe importante é o parâmetro &lt;code>CUDA_ARCHITECTURES=70&lt;/code>: cada GPU NVIDIA possui uma arquitetura específica identificada por um código &lt;code>sm_XX&lt;/code>, e o V100 é da arquitetura Volta (&lt;code>sm_70&lt;/code>). Especificando esse valor, instruímos o &lt;em>build&lt;/em> a compilar apenas para o V100, reduzindo o tempo de compilação.&lt;/p>&lt;p>O passo a passo completo de compilação, incluindo os fixes necessários para ppc64le, além da instalação e configuração das dependências mencionadas anteriormente, está documentado no &lt;a href="https://github.com/llm-pt-ibm/ollama-ppc64le/blob/ollama-ppc64le/README_POWER9.md" rel="external">&lt;span class="link-personalizado">&lt;em>README do repositório&lt;/em>&lt;/span>&lt;/a>.&lt;/p>&lt;p>Para quem não quiser compilar, um binário pré-compilado está disponível diretamente na página de &lt;a href="https://github.com/llm-pt-ibm/ollama-ppc64le/releases/tag/v0.23.2-ppc64le-power9" rel="external">&lt;span class="link-personalizado">&lt;em>releases&lt;/em>&lt;/span>&lt;/a>:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Baixe o binário&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>wget https://github.com/llm-pt-ibm/ollama-ppc64le/releases/download/v0.23.2-ppc64le-power9/ollama-ppc64le&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Dê permissão de execução&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod +x ollama-ppc64le&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Nota:&lt;/strong> O repositório contém as branches do Ollama oficial. Os patches para ppc64le estão exclusivamente na branch &lt;code>ollama-ppc64le&lt;/code>.&lt;/p>&lt;h2 id="realizando-a-inferência">Realizando a inferência&lt;/h2>&lt;p>Com o Ollama compilado, podemos iniciar o servidor:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./ollama serve&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para verificar se deu certo, digite o comando: &lt;code>ps aux | grep ollama&lt;/code>.&lt;/p>&lt;p>Aguarde alguns segundos e verifique os logs para confirmar que o servidor detectou as GPUs corretamente. Procure por estas linhas:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>inference compute ... library&lt;span style="color:#f92672">=&lt;/span>CUDA compute&lt;span style="color:#f92672">=&lt;/span>7.0 ... description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Tesla V100-SXM2-16GB&amp;#34;&lt;/span> total&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;16.0 GiB&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="baixar-o-modelo-de-teste-e-executar-a-inferência">Baixar o modelo de teste e executar a inferência&lt;/h2>&lt;p>Para validação, utilizamos o modelo &lt;code>llama3.1:8b&lt;/code>. Para isso, em outro terminal, rode:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./ollama pull llama3.1:8b&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para executar a inferência:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./ollama run llama3.1:8b &lt;span style="color:#e6db74">&amp;#34;me fale todos os números ímpares até 100&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="confirmar-o-uso-da-gpu">Confirmar o uso da GPU&lt;/h2>&lt;p>Em outro terminal, com a inferência em execução, rode:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nvidia-smi&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Na seção de processos, você deve ver o &lt;code>ollama&lt;/code> com memória alocada em uma das GPUs:&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/ollama_gpu.png" alt="Figura 1"/>&lt;figcaption> &lt;p>Ollama usando a GPU&lt;/p> &lt;/figcaption>&lt;/figure>&lt;h2 id="considerações-finais">Considerações finais&lt;/h2>&lt;p>Com os passos apresentados, foi possível configurar o ambiente para executar inferências de LLMs em uma máquina IBM POWER9, utilizando as GPUs NVIDIA Tesla V100. Com essa abordagem, a inferência de modelos possui um ganho de desempenho significativo em relação à execução via CPU. Utilizando o modelo Meta Llama 3.1 8B Instruct como referência, a execução via GPU atingiu uma maior geração de tokens por segundo em relação à execução via CPU.&lt;/p>&lt;p>Vejamos os dados coletados para uma mesma requisição (&lt;code>Me fale todos os números ímpares até 100&lt;/code>) com os dois tipos de execução:&lt;/p>&lt;table>&lt;thead>&lt;tr>&lt;th>&lt;/th>&lt;th>CPU&lt;/th>&lt;th>GPU&lt;/th>&lt;/tr>&lt;/thead>&lt;tbody>&lt;tr>&lt;td>Taxa de geração de &lt;em>tokens&lt;/em>&lt;/td>&lt;td>0.71 tokens/s&lt;/td>&lt;td>79.82 tokens/s&lt;/td>&lt;/tr>&lt;tr>&lt;td>Duração total&lt;/td>&lt;td>3m49s&lt;/td>&lt;td>4.52s&lt;/td>&lt;/tr>&lt;tr>&lt;td>Taxa de avaliação do &lt;em>prompt&lt;/em>&lt;/td>&lt;td>10.67 tokens/s&lt;/td>&lt;td>295.77 tokens/s&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>&lt;p>Com os dados apresentados na tabela, percebemos que a execução com GPU foi aproximadamente 112 vezes mais rápida na geração de &lt;em>tokens&lt;/em>, com o tempo total de resposta reduzido de 3 minutos e 49 segundos para 4.52 segundos.&lt;/p>&lt;h2 id="próximos-passos">Próximos Passos&lt;/h2>&lt;ul>&lt;li>Avaliar a execução com GPU e CPU em um post comparativo e com outras arquiteturas;&lt;/li>&lt;li>Testar a inferência em GPU com modelos maiores, com mais de 8 bilhões de parâmetros, por exemplo;&lt;/li>&lt;li>Testar novos modelos disponíveis no fork atualizado, como Gemma 3 e DeepSeek;&lt;/li>&lt;/ul></description></item><item><title>Inferência de LLMs com vLLM Utilizando GPU em Power9</title><link>https://llm-pt-ibm.github.io/posts/vllm_gpu/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/vllm_gpu/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este post tem como objetivo apresentar os passos necessários para instalar o &lt;a href="https://github.com/vllm-project/vllm" rel="external">&lt;span class="link-personalizado">vLLM&lt;/span>&lt;/a> em um ambiente IBM POWER9 (arquitetura ppc64le). Serão detalhados os principais recursos necessários, modificações, dependências, versões utilizadas e etapas de instalação necessárias para executar inferências com um determinado modelo.&lt;/p>&lt;p>O vLLM é uma ferramenta voltada para serving e inferência eficiente de modelos de linguagem de grande porte (LLMs), permitindo disponibilizar modelos por meio de uma API e executar inferências de forma otimizada, especialmente em ambientes com GPU.&lt;/p>&lt;p>A necessidade de instalar o vLLM surgiu durante o processo de geração de dados com a ferramenta &lt;a href="https://github.com/instructlab" rel="external">&lt;span class="link-personalizado">InstructLab&lt;/span>&lt;/a>. Nesse fluxo, é necessário utilizar um modelo professor para gerar dados sintéticos que serão posteriormente utilizados no treinamento ou refinamento de outros modelos. Para isso, é possível utilizar ferramentas como llama-cpp, já compatível com o ambiente IBM POWER9, ou o vLLM, que ainda não estava disponível devido a dificuldades relacionadas à instalação nesta arquitetura. Diferentemente do llama-cpp, que é mais voltado para execução local e cenários de menor escala, o vLLM se destaca pelo melhor aproveitamento de GPU e pela capacidade de atender múltiplas requisições simultaneamente de forma eficiente, sendo mais adequado para cenários de inferência em larga escala e ambientes de produção.&lt;/p>&lt;p>Dessa forma, apresentaremos os passos técnicos necessários para viabilizar a instalação do vLLM no ambiente IBM POWER9 (ppc64le), descrevendo as adaptações realizadas para que a ferramenta funcione corretamente nesse contexto.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Compilação e instalação do LLVM, necessário como infraestrutura de compilação para dependências subsequentes.&lt;/li>&lt;li>Compilação e adaptação do Triton, incluindo ajustes para compatibilidade com a arquitetura Power9.&lt;/li>&lt;li>Instalação e configuração do vLLM, considerando suas dependências e requisitos específicos de execução.&lt;/li>&lt;li>Desenvolvimento de containers contendo todo o ambiente configurado para execução da ferramenta.&lt;/li>&lt;li>Demonstração prática do uso das imagens, incluindo a inicialização do servidor e a realização de inferências utilizando GPU.&lt;/li>&lt;/ul>&lt;h2 id="ambiente-de-execução">Ambiente de Execução&lt;/h2>&lt;p>O ambiente utilizado para a instalação do vLLM inclui:&lt;/p>&lt;ul>&lt;li>&lt;strong>Arquitetura:&lt;/strong> Servidor IBM Power9 (Arquitetura ppc64le).&lt;/li>&lt;li>&lt;strong>Sistema Operacional (SO):&lt;/strong> AlmaLinux 8.10 binário compatível com Red Hat Enterprise Linux (RHEL) 8.9/8.10.&lt;/li>&lt;li>&lt;strong>RAM:&lt;/strong> 512GB.&lt;/li>&lt;li>&lt;strong>GPUs:&lt;/strong> 4x NVIDIA Tesla V100 SXM2 16GB (NVLink2).&lt;/li>&lt;/ul>&lt;h2 id="dependências-e-instalação">Dependências e Instalação&lt;/h2>&lt;p>Durante o processo de build do vLLM, destacam-se três dependências principais: &lt;a href="https://github.com/llvm/llvm-project" rel="external">&lt;span class="link-personalizado">LLVM&lt;/span>&lt;/a>, &lt;a href="https://github.com/triton-lang/triton" rel="external">&lt;span class="link-personalizado">Triton&lt;/span>&lt;/a> e &lt;a href="https://github.com/pytorch/pytorch" rel="external">&lt;span class="link-personalizado">PyTorch&lt;/span>&lt;/a>. Essas dependências são problemáticas para o funcionamento correto da ferramenta.&lt;/p>&lt;p>O LLVM constitui a base da infraestrutura de compilação utilizada ao longo de todo o processo, sendo responsável pela geração, otimização e transformação de código intermediário em código de baixo nível executável. No contexto do vLLM, sua função é essencial para viabilizar a execução eficiente de kernels em GPU, especialmente aqueles definidos pelo Triton, que dependem diretamente de seus backends de compilação (componentes responsáveis por gerar código otimizado para diferentes arquiteturas de hardware). O Triton, por sua vez, atua como o componente responsável pela definição e execução de kernels otimizados para GPU, desempenhando um papel central na eficiência da inferência de modelos de linguagem. Sua integração com o LLVM permite a geração de código altamente otimizado para diferentes arquiteturas. Já o PyTorch fornece a base para a manipulação de tensores e execução dos modelos de linguagem, oferecendo as operações fundamentais para inferência em GPU, além de servir como interface com os mecanismos de aceleração e bibliotecas de baixo nível.&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/vllm_dependencias.png" alt="Figura 1"/>&lt;figcaption> &lt;p>Fluxo de Dependências para compilar vLLM na Power9.&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>Devido à ausência de suporte nativo desses pacotes para a arquitetura ppc64le, sua utilização na IBM POWER9 exigiu a realização de diversas adaptações a partir dos repositórios oficiais dessas ferramentas. Essas modificações envolveram desde a correção de incompatibilidades em métodos específicos até ajustes em subdependências que não possuíam suporte para a arquitetura ppc64le, além do uso do Conda para auxiliar na gestão de ambientes e dependências. Em alguns casos, também foi necessária a compilação manual de componentes adicionais. Após a superação desses desafios, tornou-se possível instalar e executar o vLLM no ambiente IBM POWER9.&lt;/p>&lt;p>Devido à grande quantidade de etapas envolvidas, o passo a passo com os procedimentos detalhados são apresentados neste link: &lt;a href="https://github.com/llm-pt-ibm/vllm_gpu/blob/main/manual-installation-guide.md" rel="external">&lt;span class="link-personalizado">guia-instalacao-vllm&lt;/span>&lt;/a>. Ressalta-se que cada um dos passos descritos é essencial para garantir a correta compilação e execução do vLLM no ambiente proposto.&lt;/p>&lt;h2 id="conteinerização">Conteinerização&lt;/h2>&lt;p>Durante o processo de instalação, observou-se que a grande quantidade de etapas envolvidas poderia dificultar a reprodução do ambiente e levar à cenários inconsistentes. Diante disso, optamos pela conteinerização da solução como forma de tornar o experimento reprodutível, portátil e mais simples de ser utilizado por outros usuários.Para isso, disponibilizamos (neste &lt;a href="https://github.com/llm-pt-ibm/vllm_gpu" rel="external">&lt;span class="link-personalizado">repositório&lt;/span>&lt;/a>) scripts responsáveis tanto pela construção das imagens quanto pela automação da execução, organizando todas as etapas necessárias. Esses scripts realizam tarefas como a identificação dos recursos disponíveis, cópia dos binários CUDA necessários e a inicialização do vLLM de forma adequada.&lt;/p>&lt;p>A execução foi simplificada de forma que é necessário que o usuário apenas informe o caminho local do modelo a ser utilizado. Parâmetros como porta, quantidade de GPUs e imagem a ser executada são opcionais, possuindo valores padrões previamente definidos.&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/repositorio_git_vllm.png" alt="Figura 2"/>&lt;figcaption> &lt;p>Repositório desenvolvido para execução do vLLM via containers.&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>Além disso, disponibilizamos um vídeo (&lt;a href="https://drive.google.com/file/d/1chIuklLfjQBMMu6XlgpohP08rTW04Keg/view" rel="external">&lt;span class="link-personalizado">demonstração do vLLM no Power9&lt;/span>&lt;/a>) que demonstra o uso do vLLM a partir do repositório disponibilizado.&lt;/p>&lt;h2 id="considerações-finais">Considerações Finais&lt;/h2>&lt;p>Com os recursos disponibilizados neste repositório, tornou-se possível automatizar o processo de instalação e utilização do vLLM em arquiteturas ppc64le com GPUs V100.&lt;/p>&lt;p>No contexto do projeto IBM-MultiArq, essa solução se mostra especialmente relevante para a utilização do InstructLab, permitindo a execução local de modelos professores por meio do vLLM, ampliando as possibilidades de experimentação e desenvolvimento dentro do ambiente proposto.&lt;/p>&lt;h2 id="próximos-passos">Próximos Passos&lt;/h2>&lt;p>Como continuidade deste trabalho, propõe-se a realização de um estudo comparativo de desempenho entre o llama-cpp e o vLLM. Além disso, o repositório foi estruturado para oferecer suporte contínuo ao vLLM, incluindo sua adaptação a versões futuras, a identificação de limitações ainda existentes e a evolução das soluções à medida que novos desafios surgirem.&lt;/p></description></item><item><title>Inferência de LLMs com Ollama na IBM Power9 Utilizando CPU</title><link>https://llm-pt-ibm.github.io/posts/ollama_cpu/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/ollama_cpu/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este post apresenta um guia prático para realizar inferência de grandes Modelos de Linguagem (LLMs) utilizando o &lt;a href="https://ollama.com/" rel="external">&lt;span class="link-personalizado">&lt;em>Ollama&lt;/em>&lt;/span>&lt;/a>, em um ambiente IBM POWER9. O Ollama é um &lt;em>framework&lt;/em> baseado no &lt;a href="https://github.com/ggml-org/llama.cpp.git" rel="external">&lt;span class="link-personalizado">&lt;em>llama.cpp&lt;/em>&lt;/span>&lt;/a>, projetado para simplificar a implementação e execução de tais modelos, oferecendo uma interface amigável e suporte para diversas tarefas.&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/funcionamento_ollama.png" alt="Figura 1"/>&lt;figcaption> &lt;p>Fluxo de uma requisição&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>Apesar do crescimento no uso de LLMs, a disponibilidade de materiais voltados para a arquitetura &lt;em>ppc64le&lt;/em> (IBM POWER9) ainda é bastante limitada. Em geral, os tutoriais disponíveis são antigos, pouco detalhados ou focados em arquiteturas mais comuns, como &lt;em>x86_64&lt;/em>, o que dificulta a reprodução do ambiente no contexto apresentado. Este é o primeiro de dois posts dessa série, que tem como objetivo realizar a inferência inteiramente via CPU, explorando a arquitetura &lt;em>ppc64le&lt;/em>, de maneira atualizada, prática e reproduzível. No próximo post, abordaremos a utilização de GPU para acelerar o processo.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta detalhes sobre como configurar o ambiente para realizar inferências com a infraestrutura da IBM POWER9.&lt;/li>&lt;li>A execução é realizada via CPU utilizando o Ollama;&lt;/li>&lt;li>O principal desafio envolve a configuração correta do ambiente, especialmente dependências como &lt;em>Go&lt;/em>, &lt;em>GCC&lt;/em> e &lt;em>CMake&lt;/em>, além da compatibilidade com &lt;a href="https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux" rel="external">&lt;span class="link-personalizado">&lt;em>RHEL&lt;/em>&lt;/span>&lt;/a>&lt;/li>&lt;/ul>&lt;h2 id="ambiente-utilizado">Ambiente utilizado&lt;/h2>&lt;p>&lt;strong>Hardware&lt;/strong>:&lt;/p>&lt;ul>&lt;li>Arquitetura &lt;em>ppc64le&lt;/em>;&lt;/li>&lt;li>RAM: ~64GB;&lt;/li>&lt;li>Execução: Máquina Virtual (VM);&lt;/li>&lt;/ul>&lt;p>&lt;strong>Sistema Operacional:&lt;/strong> Alma Linux 8.10 (&lt;em>ppc64le&lt;/em>), binário compatível com &lt;em>Red Hat Enterprise Linux (RHEL)&lt;/em> 8.9/8.10.&lt;/p>&lt;h2 id="setup-inicial">&lt;em>Setup&lt;/em> inicial&lt;/h2>&lt;p>Para executar o Ollama na arquitetura POWER9, é necessário preparar o ambiente com as dependências adequadas.O primeiro passo é atualizar o sistema e instalar os utilitários básicos:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dnf update -y&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo dnf install -y wget git tar make gcc gcc-c++ cmake gcc-toolset-11&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Embora esse comando instale parte das dependências, é necessário garantir que as versões corretas estejam sendo utilizadas.&lt;/p>&lt;h3 id="configuração-do-go">Configuração do &lt;em>Go&lt;/em>&lt;/h3>&lt;p>O Ollama é desenvolvido em &lt;em>Go&lt;/em>, portanto é necessário garantir a versão adequada.&lt;/p>&lt;p>&lt;strong>Versão esperada:&lt;/strong> 1.25.7 linux/ppc64le&lt;/p>&lt;h4 id="caso-não-esteja-instalado">Caso não esteja instalado:&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>wget https://go.dev/dl/go1.25.7.linux-ppc64le.tar.gz&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo tar -C /usr/local -xzf go1.25.7.linux-ppc64le.tar.gz&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>export PATH&lt;span style="color:#f92672">=&lt;/span>/usr/local/go/bin:$PATH&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para adicionar ao &lt;em>PATH&lt;/em> permanentemente:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>echo &lt;span style="color:#e6db74">&amp;#39;export PATH=/usr/local/go/bin:$PATH&amp;#39;&lt;/span> &amp;gt;&amp;gt; ~/.bashrc&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>source ~/.bashrc&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Verifique se a versão está correta: &lt;code>go version&lt;/code>&lt;/p>&lt;h3 id="configuração-do-cmake">Configuração do &lt;em>Cmake&lt;/em>&lt;/h3>&lt;p>Verifique se a versão está correta: &lt;code>cmake --version&lt;/code>&lt;/p>&lt;p>&lt;strong>Versão esperada:&lt;/strong> cmake 3.26.5&lt;/p>&lt;h4 id="caso-não-esteja-instalado-1">Caso não esteja instalado:&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>wget https://github.com/Kitware/CMake/releases/download/v3.26.5/cmake-3.26.5.tar.gz&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tar -xzf cmake-3.26.5.tar.gz&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd cmake-3.26.5&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./bootstrap&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make -j&lt;span style="color:#66d9ef">$(&lt;/span>nproc&lt;span style="color:#66d9ef">)&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo make install&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="configuração-do-gcc">Configuração do &lt;em>GCC&lt;/em>&lt;/h3>&lt;p>&lt;strong>Versão esperada:&lt;/strong> &lt;code>gcc 11.2.1&lt;/code>&lt;/p>&lt;p>&lt;strong>Importante:&lt;/strong> No AlmaLinux 8, o &lt;em>gcc-toolset&lt;/em> não é ativado automaticamente. É necessário habilitar a sessão manualmente:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>scl enable gcc-toolset-11 bash&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Esse comando ativa o GCC apenas na sessão atual. Se abrir outro terminal, será necessário executar o comando novamente.&lt;/p>&lt;p>&lt;strong>Verifique a versão:&lt;/strong> &lt;code>gcc --version&lt;/code>&lt;/p>&lt;h4 id="caso-não-esteja-instalado-2">Caso não esteja instalado:&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dnf install -y gcc-toolset-11&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>scl enable gcc-toolset-11 bash&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="clonando-o-ollama">Clonando o Ollama&lt;/h3>&lt;p>Com o ambiente configurado, podemos realizar o &lt;em>build&lt;/em> do Ollama. Aqui vamos clonar o repositório oficial do ollama e mudar a versão utilizada (importante para a compatibilidade com a POWER e para obter uma versão estável).&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cd /root&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git clone https://github.com/ollama/ollama.git&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd ollama&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#Alterar a versão: &lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git checkout v0.9.4&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para verificar, use: &lt;code>git status&lt;/code>&lt;/p>&lt;h2 id="build-do-ollama">&lt;em>Build&lt;/em> do Ollama&lt;/h2>&lt;p>Após ativar GCC na versão certa:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>export CGO_ENABLED&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go clean -cache -modcache -i -r&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>go build -o ollama .&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>O &lt;em>CGO&lt;/em> precisa estar habilitado porque o Ollama depende do llama.cpp, que utiliza código em C/C++ para otimizações de performance. Sem isso, o &lt;em>build&lt;/em> falha ou perde compatibilidade com a arquitetura.&lt;/p>&lt;p>Isso deve ocorrer sem nenhum erro e gerar o binário &lt;code>ollama&lt;/code> criado no diretório atual.&lt;/p>&lt;p>Para verificar: &lt;code>./ollama --version&lt;/code>&lt;/p>&lt;h2 id="realizando-a-inferência">Realizando a Inferência&lt;/h2>&lt;p>Com o &lt;em>Ollama&lt;/em> compilado, podemos iniciar o servidor:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./ollama serve&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Uma observação importante é que, como o ambiente está sendo executado em uma máquina virtual, não é possível manter o comando em execução no terminal principal e, simultaneamente, utilizar outro terminal na mesma sessão para realizar a inferência, sem alguma ferramenta auxiliar para gerenciar múltiplos terminais.O que faremos então é executar o servidor em segundo plano (&lt;em>background&lt;/em>), mas você pode optar por usar &lt;em>Tmux&lt;/em> ou &lt;em>Screen&lt;/em>, permitindo que o mesmo terminal continue disponível para a execução dos demais comandos (que veremos a seguir). Para isso, você pode rodar:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./ollama serve &amp;amp;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para verificar se deu certo: &lt;code>ps aux | grep ollama&lt;/code>. Vai aparecer algo assim:&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/print_ollama_serve.png" alt="Figura 2"/>&lt;figcaption> &lt;p>Ollama executando&lt;/p> &lt;/figcaption>&lt;/figure>&lt;h2 id="baixar-o-modelo-de-teste-e-executar-a-inferência">Baixar o modelo de teste e executar a inferência&lt;/h2>&lt;p>Para validação, utilizamos o modelo &lt;em>TinyLlama&lt;/em>, por ser leve e adequado para execução em CPU. Para isso, em outro terminal, rode:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./ollama pull tinyllama&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para executar a inferência:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./ollama run tinyllama &lt;span style="color:#e6db74">&amp;#34;O céu é azul?&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Se tudo tiver sido feito de maneira correta, você terá algo como:&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/ollama_run.png" alt="Figura 3"/>&lt;figcaption> &lt;p>Inferencia sendo executada&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>É importante destacar que o &lt;em>Ollama&lt;/em> trabalha, por padrão, com modelos disponibilizados em seu próprio repositório, que já estão convertidos e otimizados para execução, geralmente no formato compatível com o &lt;em>llama.cpp&lt;/em>. Esses modelos podem ser facilmente utilizados por meio do comando &lt;code>ollama pull&lt;/code>, como no caso do &lt;em>TinyLlama&lt;/em> utilizado neste exemplo. Embora seja possível utilizar modelos externos, isso exige etapas adicionais, como a conversão para formatos compatíveis (por exemplo, &lt;em>GGUF&lt;/em>) e a criação de um &lt;em>Modelfile&lt;/em>.&lt;/p>&lt;h2 id="considerações-finais">Considerações Finais&lt;/h2>&lt;p>Com os passos apresentados, foi possível configurar o ambiente para executar inferências de LLMs em uma máquina IBM POWER9 utilizando a CPU. Apesar de ser funcional, essa abordagem apresenta limitações no desempenho, especialmente para modelos maiores, devido a ausência de aceleração via GPU. Como próximo passo, pretendemos explorar a execução utilizando GPU, avaliando ganhos de desempenho e escalabilidade.&lt;/p>&lt;h2 id="próximos-passos">Próximos Passos&lt;/h2>&lt;ul>&lt;li>Testar versões mais recentes e a compatibilidade entre elas;&lt;/li>&lt;li>Realizar uma experimentação de &lt;em>benchmarks&lt;/em> para comparar o desempenho da Inferência em CPU em relação a inferência em GPU;&lt;/li>&lt;li>Segundo post dessa série, realizando inferência em GPU.&lt;/li>&lt;/ul></description></item><item><title>Instalação do Docker em ambiente Arquitetura ppc64le (Power9)</title><link>https://llm-pt-ibm.github.io/posts/post_docker/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/post_docker/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Diante da necessidade de padronizar a execução de softwares no nosso servidor IBM Power9 (ppc64le), o uso de contêineres apresenta-se como uma solução robusta para evitar conflitos de ambiente. Este post dá continuidade à estruturação da nossa infraestrutura, detalhando a instalação do Docker Engine no AlmaLinux. A adoção desta tecnologia é estratégica para garantir o isolamento rigoroso de dependências e a portabilidade das diversas aplicações. Com isso, conseguimos encapsular desde bibliotecas de uso geral até serviços mais complexos, assegurando um ambiente de execução limpo, seguro e altamente reprodutível.&lt;/p>&lt;p>O Docker Engine tem suporte oficial para AlmaLinux nas arquiteturas x86_64, arm64, s390x e ppc64le, o que nos permite utilizá-lo diretamente no Power9 sem adaptações especiais. No entanto, alguns cuidados são necessários antes e durante a instalação, como desinstalar ferramentas que conflitam com o Docker e garantir que as imagens utilizadas sejam compatíveis com a arquitetura ppc64le.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta o passo a passo para instalar o Docker Engine no AlmaLinux na arquitetura ppc64le.&lt;/li>&lt;li>É necessário remover o Podman e o Buildah antes de instalar, pois conflitam com o Docker.&lt;/li>&lt;li>Imagens do Docker Hub precisam ter suporte explícito a ppc64le para funcionar no Power9.&lt;/li>&lt;/ul>&lt;h2 id="ambiente-utilizado">Ambiente utilizado&lt;/h2>&lt;ul>&lt;li>&lt;strong>Arquitetura&lt;/strong>: Servidor IBM Power9 (Arquitetura ppc64le)&lt;/li>&lt;li>&lt;strong>Sistema Operacional (SO)&lt;/strong>: AlmaLinux 8.10 binário compatível com Red Hat Enterprise Linux (RHEL) 8.9/8.10&lt;/li>&lt;li>&lt;strong>RAM&lt;/strong>: 512GB&lt;/li>&lt;/ul>&lt;h2 id="pré-requisitos">Pré-requisitos&lt;/h2>&lt;p>Antes de instalar o Docker, é importante estar ciente de uma limitação relacionada ao firewall: ao expor portas de contêineres usando o Docker, essas portas ignoram as regras padrão do firewalld. Certifique-se de que isso não representa um problema para o seu ambiente antes de prosseguir. Além disso, é importante destacar que o Docker Engine é compatível com Rocky Linux 8 e 9 e o AlmaLinux 8 na arquitetura ppc64le.&lt;/p>&lt;h2 id="removendo-pacotes-conflitantes">Removendo pacotes conflitantes&lt;/h2>&lt;p>O AlmaLinux, por padrão, possui o Podman e o Buildah instalados. Esses pacotes conflitam com o Docker Engine e precisam ser removidos antes da instalação. Também é recomendável remover quaisquer versões antigas do Docker que possam estar presentes:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dnf remove -y podman &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> buildah &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker-client &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker-client-latest &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker-common &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker-latest &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker-latest-logrotate &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker-logrotate &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> docker-engine&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="adicionando-repositório-do-docker-e-instalando-pacotes-necessários">Adicionando repositório do Docker e instalando pacotes necessários&lt;/h2>&lt;h3 id="configuração-do-repositório">Configuração do repositório&lt;/h3>&lt;p>O método recomendado de instalação é utilizar o repositório oficial do Docker. Vale mencionar que o Docker utiliza o repositório do CentOS para distribuições baseadas em RHEL — como o AlmaLinux — e isso é oficialmente suportado. Primeiro, instale o pacote dnf-plugins-core e adicione o repositório:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dnf install -y dnf-plugins-core&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="instalando-o-docker-engine">Instalando o Docker Engine&lt;/h3>&lt;p>Com o repositório configurado, instale a versão mais recente do Docker Engine junto com os plugins de build e compose:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="iniciando-o-serviço">Iniciando o serviço&lt;/h3>&lt;p>Diferentemente de distribuições baseadas em Debian, como o Ubuntu, o Docker não inicia automaticamente no AlmaLinux após a instalação. É necessário iniciar o serviço manualmente e habilitá-lo para que suba junto com o sistema:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl start docker&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl enable docker&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="verificando-a-instalação">Verificando a instalação&lt;/h2>&lt;p>Para confirmar que tudo foi instalado corretamente, execute a imagem hello-world. O Docker detectará automaticamente a arquitetura ppc64le e baixará a imagem correta:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo docker run hello-world&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A saída esperada é uma mensagem que confirme que o Docker está funcionando corretamente.&lt;/p>&lt;h2 id="configurações-pós-instalação">Configurações pós-instalação&lt;/h2>&lt;p>Por padrão, apenas o usuário root ou usuários com privilégios de sudo podem executar comandos do Docker. Para evitar o uso de sudo em todo comando, adicione seu usuário ao grupo docker. Primeiro, crie o grupo caso ele não exista:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo groupadd docker&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Em seguida, adicione seu usuário ao grupo:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo usermod -aG docker $USER&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>É necessário deslogar e logar novamente para que as permissões sejam aplicadas.&lt;/p>&lt;h2 id="dicas-para-arquitetura-power9">Dicas para arquitetura Power9&lt;/h2>&lt;p>Como estamos utilizando o IBM Power9, alguns cuidados adicionais são importantes ao trabalhar com o Docker Hub. O primeiro ponto é a compatibilidade de imagens: nem todas as imagens disponíveis no Docker Hub possuem suporte a ppc64le. Imagens exclusivas para x86_64 resultarão em erro de execução no Power9, por isso sempre verifique se a imagem desejada possui a tag ppc64le antes de utilizá-la.&lt;/p>&lt;p>Para validar se o Docker está rodando corretamente e reconhecendo a arquitetura da máquina, use:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker version --format &lt;span style="color:#e6db74">&amp;#39;{{.Server.Arch}}&amp;#39;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A saída esperada é ppc64le.&lt;/p>&lt;h2 id="considerações-finais">Considerações finais&lt;/h2>&lt;p>A instalação do Docker Engine no AlmaLinux (ppc64le) segue um fluxo direto, desde que os conflitos com o Podman e o Buildah sejam resolvidos previamente. O suporte oficial ao ppc64le pelo Docker garante uma experiência estável no Power9, com a ressalva de que a compatibilidade das imagens utilizadas deve ser sempre verificada antes do uso.&lt;/p>&lt;p>Com o Docker instalado e configurado, o ambiente está pronto para executar contêineres e avançar para as próximas etapas da nossa infraestrutura de modelos de linguagem.&lt;/p></description></item><item><title>Virtualização em Power9: como estruturamos um ambiente isolado com KVM e Libvirt</title><link>https://llm-pt-ibm.github.io/posts/post_virtualization/</link><pubDate>Fri, 27 Mar 2026 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/post_virtualization/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Diante da necessidade de estabelecer ambientes isolados e seguros para a instalação de bibliotecas, frameworks e ferramentas de uso geral, o encapsulamento de um ambiente surgiu como alternativa para resolução desse problema, fazendo-se presente através do KVM gerenciado por meio do virt-manager e do virsh.&lt;/p>&lt;p>A virtualização é amplamente utilizada em ambientes x86, com ferramentas e fluxos bem consolidados. No entanto, quando migramos para arquiteturas como o IBM Power9 (ppc64le), muitos desses processos deixam de ser diretos e exigem adaptações específicas. Abaixo, temos um diagrama que demonstra essa comunicação dividida em 4 camadas.&lt;/p>&lt;h2 id="fluxo-de-comunicação-entre-hardware-power9-e-máquinas-virtuais">Fluxo de comunicação entre Hardware (Power9) e Máquinas Virtuais&lt;/h2>&lt;p>O fluxo é organizado nas seguintes camadas:&lt;/p>&lt;!--&lt;div style="text-align: center;"> &lt;img src="https://llm-pt-ibm.github.io/images/kvm_virtualizacao.png" style="max-width: 90%;">&lt;/div> -->&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/kvm_virtualizacao.png" alt="Figura 1: Diagrama que representa a arquitetura de virtualização em 4 camadas."/>&lt;figcaption> &lt;p>Figura 1: Diagrama que representa a arquitetura de virtualização em 4 camadas.&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>Neste trabalho, exploramos a construção de um ambiente virtualizado utilizando KVM e Libvirt em um servidor Power9, com foco em isolamento, reprodutibilidade e uso compartilhado entre membros de uma equipe.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Implementamos um ambiente virtualizado no Power9 usando KVM + Libvirt.&lt;/li>&lt;li>Adaptamos fluxos comuns de virtualização para arquitetura ppc64le, resolvendo problemas de permissão, lock de escrita e provisionamento.&lt;/li>&lt;li>O ambiente permite isolamento seguro entre usuários e fácil gerenciamento de VMs.&lt;/li>&lt;li>Disponibilizamos imagens prontas com drivers NVIDIA/CUDA para uso imediato.&lt;/li>&lt;/ul>&lt;h2 id="ambiente-utilizado">Ambiente utilizado&lt;/h2>&lt;ul>&lt;li>&lt;strong>Arquitetura&lt;/strong>: Servidor IBM Power9 (Arquitetura ppc64le).&lt;/li>&lt;li>&lt;strong>Sistema Operacional (SO)&lt;/strong>: AlmaLinux 8.10 binário compatível com Red Hat Enterprise Linux (RHEL) 8.9/8.10.&lt;/li>&lt;li>&lt;strong>RAM&lt;/strong>: 512GB.&lt;/li>&lt;li>&lt;strong>Execução&lt;/strong>: Virtual Manager para gerenciamento de Máquinas Virtuais (VMs).&lt;/li>&lt;li>&lt;strong>Hypervisor&lt;/strong>: KVM (Kernel-based Virtual Machine) / QEMU.&lt;/li>&lt;li>&lt;strong>Gerenciamento&lt;/strong>: Libvirt (virsh, virt-install, virt-customize).&lt;/li>&lt;li>&lt;strong>Armazenamento&lt;/strong>: Discos virtuais no formato .qcow2.&lt;/li>&lt;li>&lt;strong>GPUs&lt;/strong>: 4x NVIDIA Tesla V100 SXM2 16GB (NVLink2).&lt;/li>&lt;/ul>&lt;h2 id="instalando-o-ambiente-de-virtualização-kvm--libvirt">Instalando o ambiente de virtualização (KVM + Libvirt)&lt;/h2>&lt;p>Antes de criar qualquer VM, é necessário instalar e configurar o KVM e o Libvirt no servidor Power9.&lt;/p>&lt;ol>&lt;li>&lt;strong>Instalação dos pacotes&lt;/strong>:&lt;/li>&lt;/ol>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dnf install -y qemu-kvm libvirt libvirt-client libvirt-daemon libvirt-daemon-kvm virt-install virt-viewer guestfs-tools &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span>libguestfs-tools python3-libvirt&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">&lt;li>&lt;strong>Iniciando serviço&lt;/strong>:&lt;/li>&lt;/ol>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl enable --now libvirtd&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl status libvirtd&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">&lt;li>&lt;strong>Adicionando o usuário ao grupo libvirt&lt;/strong>:Para que usuários não-root possam gerenciar VMs sem precisar de sudo em todo comando:&lt;/li>&lt;/ol>&lt;p>Execute o comando abaixo:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo usermod -aG libvirt &lt;span style="color:#66d9ef">$(&lt;/span>whoami&lt;span style="color:#66d9ef">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Faça logout e login novamente para aplicar a mudança.&lt;/p>&lt;ol start="4">&lt;li>&lt;strong>Verificando instalação&lt;/strong>:&lt;/li>&lt;/ol>&lt;p>Verifique a versão do &lt;code>virsh&lt;/code>:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh version&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Valide o suporte à virtualização no processador:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virt-host-validate&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="setup">Setup&lt;/h2>&lt;ol>&lt;li>&lt;strong>Preparação de ambiente&lt;/strong>:No KVM, a forma mais rápida de provisionar VMs é clonar uma imagem &amp;ldquo;semente&amp;rdquo; (.qcow2) e expandi-la, em vez de fazer uma instalação limpa via ISO. Portanto, para manter a organização, todos os discos virtuais ficarão em um diretório separado:&lt;/li>&lt;/ol>&lt;p>Baixe a imagem base do Alma Linux 8:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cd /home/user/&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>wget https://repo.almalinux.org/almalinux/8/cloud/ppc64le/images/AlmaLinux-8-GenericCloud-latest.ppc64le.qcow2 -O alma8_base.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">&lt;li>&lt;strong>Gerenciamento do Hipervisor&lt;/strong>:A administração do hipervisor e das instâncias segue protocolos específicos para garantir a estabilidade do sistema. Comandos para o Administrador controlar o serviço no Power9:&lt;/li>&lt;/ol>&lt;p>Desative o sistema KVM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl stop libvirtd&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Reative o sistema KVM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl start libvirtd&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Habilite no boot:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl enable libvirtd&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">&lt;li>&lt;strong>Resolução de permissões&lt;/strong>:O usuário do sistema que executa o KVM (chamado qemu) precisa ter permissão para acessar os discos da VM. Se o diretório estiver dentro de uma home pessoal, o Linux bloqueará o acesso por padrão. Para permitir que o hipervisor acesse a pasta de discos sem expor seus arquivos pessoais, conceda permissão de execução (o+x) nos diretórios:&lt;/li>&lt;/ol>&lt;p>Permita que o qemu &amp;ldquo;atravesse&amp;rdquo; a home (apenas travessia, não leitura):&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>chmod o+x /home/user&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Permita que o qemu acesse a pasta de discos:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>chmod o+x /home/user/discos&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="4">&lt;li>&lt;strong>Configuração de rede virtual (Libvirt)&lt;/strong>:O Libvirt cria uma rede NAT padrão (default) que coloca as VMs na faixa 192.168.122.0/24. As VMs têm acesso à internet via NAT, mas não são acessíveis diretamente da rede externa sem configuração adicional.&lt;/li>&lt;/ol>&lt;p>Verifique o status da rede:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh net-list --all&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Se estiver inativa, inicie e habilite no boot:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh net-start default&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo virsh net-autostart default&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Se a rede não existir, defina e inicialize:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh net-define /usr/share/libvirt/networks/default.xml&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo virsh net-start default&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo virsh net-autostart default&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Se o XML não for encontrado, instale o pacote de configuração de rede:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dnf install -y libvirt-daemon-config-network&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="5">&lt;li>&lt;strong>Criando novas VMs&lt;/strong>:&lt;/li>&lt;/ol>&lt;p>Clone a imagem base:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cp /home/user/alma8_base.qcow2 /home/user/discos/nome_vm.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Expanda o disco (a expansão deve ser feita ANTES de criar a VM):&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>qemu-img resize /home/user/discos/nome_vm.qcow2 +100G&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Crie a VM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virt-install &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --connect qemu:///system &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --name vm_nome &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --memory &lt;span style="color:#ae81ff">131072&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --vcpus &lt;span style="color:#ae81ff">16&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --cpu host &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --disk path&lt;span style="color:#f92672">=&lt;/span>/home/user/discos/nome_vm.qcow2,format&lt;span style="color:#f92672">=&lt;/span>qcow2 &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --import &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --os-variant almalinux8 &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --network network&lt;span style="color:#f92672">=&lt;/span>default &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --graphics none &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --noautoconsole&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="6">&lt;li>&lt;strong>Customização após criar as VMs&lt;/strong>:Após criar a VM, é necessário definir a senha root, pois a imagem cloud vem sem senha por padrão. Utilizamos o virt-customize para isso. &lt;strong>Importante&lt;/strong>: A VM deve estar desligada para que o disco possa ser editado em segurança.&lt;/li>&lt;/ol>&lt;p>Desligue a VM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh shutdown vm_nome&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Aguarde o desligamento completo:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh list --all&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Injete a senha no disco:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virt-customize -a /home/user/discos/nome_vm.qcow2 &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --root-password password:senha_desejada&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ligue a VM novamente:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh start vm_nome&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="7">&lt;li>&lt;strong>Acessando VMs&lt;/strong>:&lt;/li>&lt;/ol>&lt;p>&lt;strong>Via console serial&lt;/strong>&lt;/p>&lt;p>Conecte ao console da VM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh console vm_nome&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para sair do console, use &lt;code>Ctrl + ]&lt;/code>.&lt;/p>&lt;p>&lt;strong>Via SSH&lt;/strong>&lt;/p>&lt;p>Descubra o IP da VM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh domifaddr vm_nome&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Acesse via SSH:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ssh root@&amp;lt;ip_da_vm&amp;gt;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="8">&lt;li>&lt;strong>Gerenciar e apagar VMs&lt;/strong>:Se você precisar destruir um ambiente para recriá-lo do zero, siga os 3 passos obrigatórios para limpar tudo:&lt;/li>&lt;/ol>&lt;p>Force o desligamento da VM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh destroy nome_da_vm&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Remova a definição da VM do Libvirt:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh undefine nome_da_vm&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Apague o disco virtual para liberar espaço no Power9:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>rm -f /home/user/discos/nome_da_vm.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="9">&lt;li>&lt;strong>Criar VM a partir de imagem existente (clonagem)&lt;/strong>:Para criar uma nova VM a partir de uma imagem já configurada, como as imagens prontas com drivers NVIDIA:&lt;/li>&lt;/ol>&lt;p>Opção A: clonar via &lt;code>qemu-img&lt;/code> (mantém a imagem original intacta):&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>qemu-img create -f qcow2 -b imagem-base.qcow2 -F qcow2 nova-vm.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Opção B: clonar via &lt;code>virt-clone&lt;/code>:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>virt-clone &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --original vm-base &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --name vm-nova &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --file /home/user/discos/nova-vm.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Caso seja necessário, pode-se executar o passo de excluir a VM e recriá-la conforme a etapa 5.&lt;/p>&lt;h2 id="imagens-prontas-com-drivers-nvidia">Imagens prontas com drivers NVIDIA&lt;/h2>&lt;p>Para facilitar o uso das GPUs Tesla V100 presentes no servidor, disponibilizamos imagens .qcow2 pré-configuradas com os drivers NVIDIA, CUDA e cuDNN instalados. Isso elimina a necessidade de configurar o ambiente base a cada novo uso.&lt;/p>&lt;ol>&lt;li>&lt;p>&lt;strong>Imagens disponíveis&lt;/strong>:&lt;/p>&lt;table>&lt;thead>&lt;tr>&lt;th style="text-align:left">Imagem&lt;/th>&lt;th style="text-align:left">Conteúdo&lt;/th>&lt;/tr>&lt;/thead>&lt;tbody>&lt;tr>&lt;td style="text-align:left">AlmaLinux-8-Power9-NVIDIA-drivers.qcow2.xz&lt;/td>&lt;td style="text-align:left">AlmaLinux 8.10 + drivers NVIDIA 535 + CUDA 12.2 + cuDNN 9.0&lt;/td>&lt;/tr>&lt;tr>&lt;td style="text-align:left">InstructLab-Power9-0.25.0.qcow2.xz&lt;/td>&lt;td style="text-align:left">AlmaLinux 8.10 + InstructLab 0.25.0 + dependências necessárias para execução no Power9 (ppc64le).&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>&lt;/li>&lt;li>&lt;p>&lt;strong>Como usar imagens pré-configuradas&lt;/strong>:&lt;/p>&lt;/li>&lt;/ol>&lt;p>Baixe a imagem da pasta compartilhada e descompacte:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>pip install --user gdown&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gdown --folder &lt;span style="color:#e6db74">&amp;#34;https://drive.google.com/drive/u/1/folders/1WM8fHKWaMu-NJOzwqh6cdcET7mNE50du&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>xz -d InstructLab-Power9-0.25.0.qcow2.xz&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Mova para o diretório de discos e crie a VM a partir dela:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cp InstructLab-Power9-0.25.0.qcow2 /home/user/discos/minha-vm-gpu.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Crie a VM normalmente:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virt-install &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --connect qemu:///system &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --name vm_gpu &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --memory &lt;span style="color:#ae81ff">131072&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --vcpus &lt;span style="color:#ae81ff">16&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --cpu host &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --disk path&lt;span style="color:#f92672">=&lt;/span>/home/user/discos/minha-vm-gpu.qcow2,format&lt;span style="color:#f92672">=&lt;/span>qcow2 &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --import &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --os-variant almalinux8 &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --network network&lt;span style="color:#f92672">=&lt;/span>default &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --graphics none &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> --noautoconsole&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para que a VM tenha acesso às GPUs físicas, é necessário configurar o passthrough PCIe conforme descrito no próximo post desta série.&lt;/p>&lt;ol start="3">&lt;li>&lt;strong>Como gerar nova imagem a partir de VM configurada&lt;/strong>:Após instalar drivers ou qualquer software dentro de uma VM, você pode exportar o estado atual como nova imagem para reuso:&lt;/li>&lt;/ol>&lt;p>Desligue a VM:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo virsh shutdown vm_nome&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Converta e compacte a imagem (remove espaço não utilizado):&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>qemu-img convert -O qcow2 -c &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> /home/user/discos/vm_nome.qcow2 &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> /home/user/discos/AlmaLinux-8-Power9-minha-imagem.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Comprima para distribuição:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>xz -T0 -v /home/user/discos/AlmaLinux-8-Power9-minha-imagem.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Saída esperada: &lt;code>AlmaLinux-8-Power9-minha-imagem.qcow2.xz&lt;/code>.&lt;/p>&lt;p>Verifique a integridade:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>qemu-img check AlmaLinux-8-Power9-minha-imagem.qcow2&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>qemu-img info AlmaLinux-8-Power9-minha-imagem.qcow2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Avaliação de Modelos IBM Granite para Tarefas de Geração de Código no HumanEvalX</title><link>https://llm-pt-ibm.github.io/posts/post_humanevalx/</link><pubDate>Fri, 28 Nov 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/post_humanevalx/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>O uso de modelos de linguagem para &lt;strong>geração e compreensão de código&lt;/strong> tem se tornado essencial em fluxos de desenvolvimento modernos.&lt;br>Como parte do esforço conjunto entre o &lt;strong>LSD/UFCG&lt;/strong> e a &lt;strong>IBM Brasil&lt;/strong>, investigamos a performance da família &lt;strong>IBM Granite 4&lt;/strong> no benchmark &lt;strong>HumanEvalX&lt;/strong>, que avalia capacidades de programação em &lt;em>cinco linguagens&lt;/em>: Python, Java, Go, C++, e JavaScript.&lt;/p>&lt;p>O objetivo foi responder perguntas centrais da equipe:&lt;/p>&lt;ul>&lt;li>&lt;em>Quão versáteis são os modelos Granite entre linguagens diferentes?&lt;/em>&lt;/li>&lt;li>&lt;em>Modelos menores entregam performance útil?&lt;/em>&lt;/li>&lt;li>&lt;em>Como os Granite se posicionam frente a modelos open-source como DeepSeek Coder e CodeLlama?&lt;/em>&lt;/li>&lt;/ul>&lt;hr>&lt;h2 id="metodologia--processo">Metodologia / Processo&lt;/h2>&lt;p>A avaliação foi conduzida utilizando o &lt;strong>OpenCompass&lt;/strong>, um framework moderno e extensível para benchmarking de LLMs em escala. Ele permitiu executar todos os experimentos de forma padronizada, reprodutível e com protocolos consistentes de inferência.&lt;/p>&lt;p>Como o OpenCompass não possui suporte nativo aos modelos hospedados na &lt;strong>IBM Cloud&lt;/strong>, foi necessário desenvolver um &lt;em>client&lt;/em> personalizado para integrar o framework à IBM Cloud Inference API. Esse &lt;em>client&lt;/em> permitiu que o processo de avaliação executasse requisições de forma transparente, tratasse autenticação, controlasse parâmetros de geração e retornasse as respostas no formato esperado pelo benchmark. Os experimentos também foram executados no &lt;strong>Google Colab&lt;/strong>, que serviu como ambiente prático de prototipação e execução dos modelos.&lt;/p>&lt;p>Utilizamos o benchmark HumanEvalX, uma extensão do HumanEval tradicional, cobrindo cinco linguagens com métricas consistentes de avaliação como, por exemplo ,&lt;strong>Pass@1&lt;/strong>.&lt;/p>&lt;p>Os modelos avaliados incluíram:&lt;/p>&lt;ul>&lt;li>Granite 4.0 Micro (3B)&lt;/li>&lt;li>Granite 4.0 (1B)&lt;/li>&lt;li>Granite 4.0 h-tiny (7B)&lt;/li>&lt;li>Granite 4.0 h-small (30B) — via IBM Cloud&lt;/li>&lt;li>granite 4.0 (350M)&lt;/li>&lt;li>granite code instruct 8B — via IBM Cloud&lt;/li>&lt;li>DeepSeek Coder (6.7B)&lt;/li>&lt;li>CodeLlama (7B)&lt;/li>&lt;/ul>&lt;p>A métrica utilizada foi &lt;strong>Pass@1&lt;/strong>, seguindo o protocolo do benchmark.&lt;/p>&lt;hr>&lt;h2 id="resultados-e-conclusões">Resultados e Conclusões&lt;/h2>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/heatmap_humanevalX.png" alt="Heatmap de desempenho"/>&lt;figcaption> &lt;p>Heatmap do desempenho dos modelos no HumanEvalX.&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>A avaliação revelou comportamentos importantes:&lt;/p>&lt;h3 id="1-o-granite-40-h-small-se-destacou-pela-versatilidade">&lt;strong>1. O granite-4.0-h-small se destacou pela versatilidade&lt;/strong>&lt;/h3>&lt;p>Ele superou 60% de Pass@1 em Java, C++ e JavaScript, além de manter mais de 50% em Python e Go. Esse desempenho consistente entre linguagens sugere que o modelo tem boa capacidade de generalização, mostrando-se promissor em cenários que envolvem diferentes ecossistemas de programação, embora análises adicionais em outros benchmarks sejam importantes para uma conclusão mais ampla.&lt;/p>&lt;h3 id="2-o-granite-micro-3b-apresentou-performance-acima-do-esperado">&lt;strong>2. O Granite Micro (3B) apresentou performance acima do esperado&lt;/strong>&lt;/h3>&lt;p>Apesar de ser um modelo pequeno, o Granite Micro (3B) surpreendeu ao alcançar 65.85% em JavaScript e 68.90% em Java, superando inclusive modelos maiores avaliados.Esse comportamento mostra que, mesmo com uma arquitetura compacta, ele consegue entregar resultados sólidos, tornando-se uma opção altamente eficiente para aplicações que exigem baixo custo computacional sem abrir mão de desempenho.&lt;/p>&lt;h3 id="3-a-progressão-de-tamanhos-350m--1b--3b--7b--30b-mostra-evolução-gradual-e-coerente">&lt;strong>3. A progressão de tamanhos (350M → 1B → 3B → 7B → 30B) mostra evolução gradual e coerente&lt;/strong>&lt;/h3>&lt;p>Os resultados mostram que, à medida que avançamos pelos diferentes tamanhos da linha Granite, há uma evolução coerente no desempenho. Os modelos menores entregam resultados estáveis dentro da sua categoria, enquanto os maiores ampliam progressivamente a capacidade de resolver tarefas mais complexas. Essa distribuição ajuda a entender melhor onde cada modelo se encaixa no espectro de uso.&lt;/p>&lt;h3 id="4-a-comparação-entre-provedores-ajuda-a-contextualizar-os-resultados">&lt;strong>4. A comparação entre provedores ajuda a contextualizar os resultados&lt;/strong>&lt;/h3>&lt;p>Ao lado dos modelos da IBM, também avaliamos modelos de outros provedores, como DeepSeek e Meta. Em algumas linguagens, as diferenças foram pequenas, mas em todas elas houve ao menos um modelo da família Granite que alcançou a melhor pontuação. Os modelos Granite 4 Micro (3B) e Granite 4 h-small (30B) foram os destaques com resultados que ficaram próximos, e em alguns casos acima, de modelos reconhecidos por serem especialistas em código.&lt;/p>&lt;hr>&lt;h2 id="próximos-passos">Próximos Passos&lt;/h2>&lt;ul>&lt;li>Executar os mesmos modelos da família Granite no LiveCodeBench, um benchmark mais amplo que vai além de &lt;strong>code-generation&lt;/strong>, avaliando também &lt;strong>code execution&lt;/strong> e &lt;strong>test-output&lt;/strong>.&lt;/li>&lt;li>Realizar um &lt;strong>fine-tuning de um modelo Granite 4.0 Micro (3B) utilizando o InstructLab&lt;/strong> e observar o impacto dessa adaptação no desempenho do modelo no &lt;strong>HumanEvalX&lt;/strong>, comparando antes e depois do ajuste.&lt;/li>&lt;/ul></description></item><item><title>Contaminação por dados de Benchmark em LLMs: Fundamentos, Causas e Estratégias de Detecção</title><link>https://llm-pt-ibm.github.io/posts/introducao_contaminacao/</link><pubDate>Mon, 21 Jul 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/introducao_contaminacao/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>&lt;em>Benchmarks&lt;/em> são estruturas organizadas e padronizadas que podem ser utilizadas para avaliar o desempenho de grandes modelos de linguagem (LLMs). Compostos, em geral, por uma base de dados, um conjunto de tarefas e métricas de avaliação, esses recursos fornecem um ponto de referência comum para mensurar avanços, comparar arquiteturas e orientar decisões de desenvolvimento e implantação.&lt;/p>&lt;p>Apesar de seu uso recorrente, os resultados obtidos em &lt;em>benchmarks&lt;/em> podem ser influenciados por diversos fatores. Um dos fatores ocorre quando, de alguma forma, os dados de teste são previamente expostos ao modelo durante seu treinamento. Esse cenário caracteriza o fenômeno conhecido como &lt;strong>contaminação por dados de &lt;em>benchmark&lt;/em>&lt;/strong>, que pode ocorrer de forma acidental ou deliberada. A presença desse tipo de contaminação tende a comprometer a avaliação, pois o modelo pode memorizar parcial ou integralmente os exemplos avaliados em uma determinada tarefa, distorcendo seu desempenho real.&lt;/p>&lt;div style="text-align: center; display: table;"> &lt;img src="https://llm-pt-ibm.github.io/images/contaminacao_explicacao.png" alt="Explicação contaminação" style="max-width: 50%; box-shadow: none;"> &lt;p style="margin-top: 0.3em; font-size: 0.8em; font-style: italic; color: #000000eb">Contaminação por dados de benchmark&lt;/p>&lt;/div>&lt;p>Com o objetivo de introduzir e difundir esse tema, esta postagem apresenta os fundamentos conceituais da contaminação por dados de &lt;em>benchmark&lt;/em>, suas causas recorrentes e as metodologias atualmente utilizadas para sua detecção.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Modelos são vulneráveis à contaminação quando os dados utilizados para testá-lo são previamente expostos durante o treinamento.&lt;/li>&lt;li>A contaminação pode ocorrer de forma acidental ou intencional e compromete a validade das avaliações.&lt;/li>&lt;li>Existem diferentes formas de contaminação, que variam pelo conteúdo exposto, momento da exposição e nível de abstração.&lt;/li>&lt;li>Métodos de detecção podem ser diretos (quando os dados de treinamento são acessíveis) ou indiretos (baseados em comportamento ou inferência).&lt;/li>&lt;li>Ferramentas como LLMSanitize, BenBench, ConStat e CDD-TED auxiliam na identificação sistemática de contaminações.&lt;/li>&lt;/ul>&lt;h2 id="impactos-da-contaminação">Impactos da contaminação&lt;/h2>&lt;p>A contaminação por dados de &lt;em>benchmarks&lt;/em> provoca distorções que afetam tanto o rigor científico das avaliações quanto a confiabilidade de aplicações baseadas em LLMs. Os principais impactos descritos abaixo, também são discutidos em estudos como &lt;a href="#ref1">[1]&lt;/a> &lt;a href="#ref5">[5]&lt;/a> &lt;a href="#ref7">[7]&lt;/a>.&lt;/p>&lt;div style="text-align: center; display: table; width: 100%;"> &lt;img src="https://llm-pt-ibm.github.io/images/icones_riscos_contaminacao.png" alt="Riscos da contaminação" style="max-width: 40%; box-shadow: none;"> &lt;p style="margin-top: 0.3em; font-size: 0.8em; font-style: italic; color: #000000eb">Riscos da contaminação por dados de benchmark&lt;/p>&lt;/div>&lt;ul>&lt;li>&lt;p>&lt;strong>Inflacionamento de métricas:&lt;/strong> A exposição prévia aos dados de avaliação pode elevar artificialmente o desempenho dos modelos, resultando em métricas superestimadas, como acurácia e calibragem. Isso dificulta a interpretação precisa de suas capacidades reais.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Avaliação comprometida:&lt;/strong> Quando um &lt;em>benchmark&lt;/em> é aplicado a modelos que já tiveram acesso a seus dados, ele deixa de refletir a dificuldade real das tarefas, comprometendo sua função como instrumento de avaliação imparcial.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Redução da generalização:&lt;/strong> A contaminação favorece a memorização de exemplos específicos em vez da aprendizagem de padrões gerais, o que reduz a capacidade do modelo de lidar com dados não vistos, especialmente em casos de contaminação por rótulo ou semântica.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Riscos em aplicações sensíveis:&lt;/strong> Avaliações contaminadas podem levar à adoção de modelos em domínios críticos, como saúde, direito e finanças, com base em métricas distorcidas. Isso aumenta o risco de falhas operacionais e decisões inadequadas.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Comparações enviesadas e desperdício de recursos:&lt;/strong> A contaminação prejudica a equidade entre modelos, especialmente quando apenas alguns foram expostos previamente aos dados de &lt;em>benchmark&lt;/em>. Isso compromete comparações, favorece modelos não auditáveis e pode levar à alocação ineficiente de recursos.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Comprometimento da integridade científica:&lt;/strong> Avaliações baseadas em &lt;em>benchmarks&lt;/em> contaminados afetam a reprodutibilidade e podem resultar em conclusões inválidas, enfraquecendo a confiabilidade de estudos que utilizam esses resultados como base empírica.&lt;/p>&lt;/li>&lt;/ul>&lt;h2 id="causas-da-contaminação-por-dados-de-benchmark">Causas da contaminação por dados de &lt;em>benchmark&lt;/em>&lt;/h2>&lt;p>A contaminação por dados de &lt;em>benchmarks&lt;/em> em LLMs pode ocorrer de forma &lt;strong>acidental&lt;/strong> &lt;a href="#ref1">[1]&lt;/a> &lt;a href="#ref4">[4]&lt;/a> ou &lt;strong>intencional&lt;/strong> &lt;a href="#ref1">[1]&lt;/a> &lt;a href="#ref3">[3]&lt;/a>, com diferentes origens e consequências, dependendo principalmente da forma como os dados de treinamento são coletados, utilizados e reaproveitados nos ciclos de desenvolvimento dos modelos.&lt;/p>&lt;p>A contaminação &lt;strong>acidental&lt;/strong> é a mais comum e ocorre, na maioria dos casos, devido ao uso de &lt;strong>dados extraídos automaticamente da internet para pré-treinamento em larga escala&lt;/strong> &lt;a href="#ref1">[1]&lt;/a> &lt;a href="#ref4">[4]&lt;/a>. Esses corpora, por sua diversidade e volume, frequentemente incluem conteúdos associados a &lt;em>benchmarks&lt;/em>, como exemplos idênticos, trechos brutos ou textos semanticamente relacionados. Isso se deve ao fato de &lt;em>benchmarks&lt;/em> e dados de treinamento frequentemente compartilharem fontes públicas comuns, como Wikipedia, repositórios educacionais, artigos técnicos e redes sociais.&lt;/p>&lt;div style="text-align: center; display: table;"> &lt;img src="https://llm-pt-ibm.github.io/images/contaminacao_nao_intencional.png" alt="Contaminação não intencional" caption="" style="max-width: 80%; box-shadow: none;"> &lt;p style="margin-top: 0.3em; font-size: 0.8em; font-style: italic; color: #000000eb">Exemplo de fluxo de contaminação não intencional&lt;/p>&lt;/div>&lt;p>Embora mecanismos de filtragem possam ser implementados para evitar a inclusão de &lt;em>benchmarks&lt;/em> conhecidos, essa estratégia apresenta limitações &lt;a href="#ref4">[4]&lt;/a>. É difícil garantir a exclusão de todos os &lt;em>benchmarks&lt;/em> existentes, especialmente os lançados recentemente ou ainda não amplamente documentados. Além disso, a identificação de sobreposição semântica é complexa, o que torna a detecção de vazamentos indiretos ainda mais desafiadora.&lt;/p>&lt;p>Outro vetor de contaminação acidental está relacionado à &lt;strong>reutilização de interações com usuários&lt;/strong> para re-treinamento ou ajuste fino de modelos implantados em produção &lt;a href="#ref7">[7]&lt;/a>. Sistemas comerciais podem reaproveitar entradas fornecidas por usuários durante testes, avaliações públicas ou uso real. Quando essas interações reproduzem exemplos derivados de &lt;em>benchmarks&lt;/em>, há risco de contaminação retroativa, mesmo que não intencional, nos ciclos seguintes de treinamento.&lt;/p>&lt;p>Além disso, a contaminação pode se propagar por meio da &lt;strong>geração de conteúdo por LLMs&lt;/strong> &lt;a href="#ref1">[1]&lt;/a>. Modelos contaminados podem gerar textos que replicam padrões ou trechos presentes em &lt;em>benchmarks&lt;/em>, mesmo que de forma parafraseada ou reestruturada. Esses textos, quando reutilizados em novos &lt;em>benchmarks&lt;/em> ou conjuntos de treinamento, perpetuam e amplificam a contaminação original. Apesar de, nesses casos, os desenvolvedores poderem estar cientes da contaminação prévia, a natureza recursiva do processo faz com que a propagação ocorra de forma indireta e, muitas vezes, incontrolável. Por esse motivo, esse tipo de exposição também pode ser considerado um caso de contaminação acidental.&lt;/p>&lt;p>Por outro lado, a &lt;strong>contaminação intencional&lt;/strong> ocorre quando dados de &lt;em>benchmark&lt;/em> são deliberadamente incluídos no treinamento, com o objetivo de melhorar o desempenho do modelo em tarefas específicas &lt;a href="#ref1">[1]&lt;/a> &lt;a href="#ref3">[3]&lt;/a>. Essa prática pode ocorrer, por exemplo, ao incorporar conjuntos como MATH ou GSM8K com o propósito de otimizar a performance em raciocínio matemático &lt;a href="#ref6">[6]&lt;/a>. Embora esse uso possa ser justificável como dado supervisionado, sua posterior reutilização como &lt;em>benchmark&lt;/em> invalida a avaliação.&lt;/p>&lt;div style="text-align: center; display: table;"> &lt;img src="https://llm-pt-ibm.github.io/images/contaminacao_intencional.png" alt="Contaminação intencional" caption="" style="max-width: 80%; box-shadow: none;"> &lt;p style="margin-top: 0.3em; font-size: 0.8em; font-style: italic; color: #000000eb">Exemplo de fluxo de contaminação intencional&lt;/p>&lt;/div>&lt;p>É fundamental que, em casos como esse, haja &lt;strong>transparência na documentação dos modelos&lt;/strong>. &lt;em>benchmarks&lt;/em> utilizados como parte do treinamento não devem ser reaplicados como instrumentos de avaliação. Ainda assim, essa distinção nem sempre é respeitada, especialmente em modelos comerciais cuja documentação é limitada ou inexistente &lt;a href="#ref5">[5]&lt;/a>.&lt;/p>&lt;h2 id="categorias-e-níveis-de-contaminação">Categorias e níveis de contaminação&lt;/h2>&lt;p>A contaminação por dados de &lt;em>benchmark&lt;/em> pode assumir diferentes formas, variando conforme o tipo de conteúdo exposto, o grau de abstração da informação vazada e o estágio do treinamento em que a contaminação ocorre. Essas categorias não são mutuamente exclusivas e frequentemente se combinam, o que torna o fenômeno difícil de rastrear e mitigar.&lt;/p>&lt;p>Em muitos casos, a exposição ocorre devido a um &lt;strong>vazamento de entrada&lt;/strong>, que é quando apenas as entradas dos &lt;em>benchmarks&lt;/em> são expostas ao modelo &lt;a href="#ref4">[4]&lt;/a>, como perguntas, comandos ou &lt;em>prompts&lt;/em>. No entanto, há situações em que tanto as entradas quanto os rótulos ou respostas anotadas estão presentes no treinamento, e essa situação é conhecida como &lt;strong>vazamento de entrada-saída&lt;/strong> &lt;a href="#ref4">[4]&lt;/a>.&lt;/p>&lt;p>Outra forma comum de categorizar a contaminação é quando os modelos são expostos ao &lt;strong>texto bruto&lt;/strong> utilizado na construção de &lt;em>benchmarks&lt;/em> &lt;a href="#ref5">[5]&lt;/a>, como artigos da Wikipedia, decisões judiciais ou descrições técnicas. Complementarmente, há o caso que envolve a &lt;strong>contaminação por diretrizes de anotação&lt;/strong> &lt;a href="#ref5">[5]&lt;/a>, quando o modelo acessa instruções empregadas no processo de rotulagem dos dados. Esse tipo de vazamento pode induzir comportamentos compatíveis com os critérios esperados pelo &lt;em>benchmark&lt;/em>, mesmo sem exposição direta aos exemplos.&lt;/p>&lt;p>Além disso, a contaminação pode ocorrer em diferentes &lt;strong>níveis de abstração&lt;/strong>. No &lt;strong>nível semântico&lt;/strong>, o modelo é exposto a conteúdos conceitualmente semelhantes ou derivados dos &lt;em>benchmarks&lt;/em>, como reformulações, tópicos correlatos ou textos provenientes da mesma fonte &lt;a href="#ref1">[1]&lt;/a>. Essa forma de vazamento pode introduzir vieses temáticos e comprometer a capacidade de generalização do modelo, sendo difícil de detectar por não envolver cópia literal. No &lt;strong>nível informacional&lt;/strong>, o vazamento ocorre por meio de estruturas secundárias associadas ao &lt;em>benchmark&lt;/em>, como distribuições temporais, frequências de rótulos, metadados ou até análises externas sobre o conjunto de dados &lt;a href="#ref1">[1]&lt;/a>. Essas informações, mesmo sem conter o conteúdo principal, podem influenciar sutilmente o comportamento do modelo. No &lt;strong>nível de dados&lt;/strong>, ocorre a exposição literal de exemplos do conjunto de avaliação, mas sem os rótulos correspondentes, o que ainda assim permite que o modelo aprenda padrões específicos do &lt;em>benchmark&lt;/em> &lt;a href="#ref1">[1]&lt;/a>. Já no &lt;strong>nível de rótulos&lt;/strong>, o caso mais crítico, tanto os exemplos quanto os rótulos estão presentes no treinamento, o que favorece memorização direta, reduz a capacidade de generalização e compromete seriamente a validade da avaliação &lt;a href="#ref1">[1]&lt;/a>.&lt;/p>&lt;p>Por fim, a contaminação pode ocorrer em diferentes fases do ciclo de treinamento &lt;a href="#ref5">[5]&lt;/a>. Durante o &lt;strong>pré-treinamento&lt;/strong>, é comum que corpora amplos e não curados incluam trechos relacionados a &lt;em>benchmarks&lt;/em>, por compartilharem fontes comuns. No &lt;strong>ajuste fino supervisionado&lt;/strong>, conjuntos rotulados podem conter instâncias próximas ou idênticas às utilizadas posteriormente nos dados de teste do modelo. Já na &lt;strong>fase pós-implantação&lt;/strong>, dados derivados de interações com usuários ou gerados por outras LLMs também podem introduzir contaminação, especialmente quando reaproveitados para re-treinamento.&lt;/p>&lt;p>Essas diferentes manifestações evidenciam que a contaminação por dados de &lt;em>benchmarks&lt;/em> é um fenômeno multifacetado, que pode ser sutil ou direta, intencional ou não, com impactos relevantes para a validade das avaliações, a comparação entre modelos e a confiabilidade dos sistemas desenvolvidos.&lt;/p>&lt;h2 id="metodologias-de-detecção">Metodologias de detecção&lt;/h2>&lt;p>A identificação de contaminação em &lt;em>benchmarks&lt;/em> exige metodologias específicas, que variam conforme o nível de acesso ao modelo avaliado. Esse acesso costuma ser classificado em três categorias. Modelos &lt;strong>caixa branca&lt;/strong> permitem acesso completo aos pesos e aos dados de treinamento. Modelos &lt;strong>caixa cinza&lt;/strong> têm documentação limitada e expõem distribuições de probabilidade ou valores de log‑probabilidade, mas não os dados originais. Já modelos &lt;strong>caixa preta&lt;/strong> oferecem apenas as respostas finais, sem qualquer visibilidade sobre arquitetura ou treinamento.&lt;/p>&lt;div style="text-align: center; display: table;"> &lt;img src="https://llm-pt-ibm.github.io/images/tipos_de_modelos.png" alt="Tipos de Modelos" caption="" style="max-width: 70%; box-shadow: none;"> &lt;p style="margin-top: 0.3em; font-size: 0.8em; font-style: italic; color: #000000eb">Níveis de acesso a modelos&lt;/p>&lt;/div>&lt;p>Cada configuração impõe limitações próprias e condiciona as técnicas de detecção disponíveis. Metodologias de detecção direta, como busca por duplicação literal ou análise de similaridade semântica, requerem transparência total sobre os dados de treinamento e, portanto, aplicam‑se principalmente a modelos caixa branca &lt;a href="#ref1">[1]&lt;/a> &lt;a href="#ref3">[3]&lt;/a> &lt;a href="#ref4">[4]&lt;/a>. Já metodologias de detecção indireta, focadas em vazamentos comportamentais, manipulação de entrada, perturbações ou evidências temporais, podem ser empregadas inclusive em modelos caixa cinza ou caixa preta, pois não dependem de acesso direto aos dados utilizados no treinamento &lt;a href="#ref3">[3]&lt;/a> &lt;a href="#ref4">[4]&lt;/a>. A seguir, apresentam‑se as principais abordagens descritas na literatura, organizadas de acordo com a origem da evidência e o grau de inferência envolvido.&lt;/p>&lt;h3 id="metodologias-de-detecção-direta">Metodologias de detecção direta&lt;/h3>&lt;p>Algumas metodologias de detecção partem da premissa de que o conjunto de dados utilizado no treinamento do modelo é conhecido ou publicamente acessível. Nesses casos, é possível realizar comparações diretas entre os dados de teste (&lt;em>benchmarks&lt;/em>) e os dados efetivamente utilizados no treinamento, o que permite evidenciar contaminações com alto grau de precisão.&lt;/p>&lt;p>Modelos classificados como &lt;strong>caixa branca&lt;/strong>, como o &lt;a href="https://huggingface.co/TucanoBR" target="_blank" rel="noopener noreferrer">&lt;strong>Tucano&lt;/strong>&lt;/a>, disponibilizam não apenas a arquitetura e os pesos, mas também todo o processo de pré-processamento e os dados utilizados no treinamento, possibilitando esse tipo de verificação. Já para modelos &lt;strong>caixa cinza&lt;/strong>, mesmo entre os de código aberto como o &lt;a href="https://huggingface.co/meta-llama" target="_blank" rel="noopener noreferrer">&lt;strong>LLaMA&lt;/strong>&lt;/a> ou o &lt;a href="https://huggingface.co/mistralai" target="_blank" rel="noopener noreferrer">&lt;strong>Mistral&lt;/strong>&lt;/a>, a ausência dos dados de treinamento impossibilita a aplicação dessas estratégias.&lt;/p>&lt;p>Entre os métodos mais utilizados nesse cenário estão:&lt;/p>&lt;ul>&lt;li>&lt;p>&lt;strong>String matching&lt;/strong>: busca por duplicações exatas entre exemplos do &lt;em>benchmark&lt;/em> e entradas do conjunto de treinamento. Essa técnica utiliza substrings, n‑gramas ou trechos completos, sendo eficiente e de fácil implementação. Embora direta e objetiva, há limitação quanto à identificação de repetições literais, sem capturar variantes semânticas ou paráfrases &lt;a href="#ref4">[4]&lt;/a>.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Similaridade via &lt;em>embeddings&lt;/em>&lt;/strong>: utiliza representações vetoriais de sentenças para medir a proximidade semântica entre exemplos do conjunto de treinamento e do &lt;em>benchmark&lt;/em>. Essa técnica permite identificar contaminações menos explícitas, como reformulações e variações estruturais, sendo especialmente útil em casos em que não há duplicações literais. No entanto, além de mais custosa, sua eficácia depende da escolha apropriada do modelo de &lt;em>embeddings&lt;/em> e da métrica de distância utilizada &lt;a href="#ref4">[4]&lt;/a>.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Detecção de paráfrases&lt;/strong>: utiliza LLMs ou classificadores especializados para avaliar se exemplos do &lt;em>benchmark&lt;/em> são paráfrases de conteúdos previamente vistos. Essa abordagem é útil quando há suspeita de reformulações, mas exige supervisão humana ou limiares bem definidos para reduzir falsos positivos &lt;a href="#ref4">[4]&lt;/a>.&lt;/p>&lt;/li>&lt;/ul>&lt;p>Essas técnicas são consideradas &lt;strong>concretas e verificáveis&lt;/strong>, pois operam diretamente sobre os dados de treinamento e permitem mensurar de forma clara a sobreposição com os &lt;em>benchmarks&lt;/em>. No entanto, apresentam alto custo metodológico, já que requerem acesso completo aos dados de treinamento e demandam recursos computacionais significativos para análise em larga escala.&lt;/p>&lt;h3 id="metodologias-de-detecção-indireta">Metodologias de detecção indireta&lt;/h3>&lt;p>Em contextos em que os dados de treinamento não são públicos, como no caso de modelos proprietários (&lt;a href="https://chatgpt.com/" target="_blank" rel="noopener noreferrer">&lt;strong>GPT-4&lt;/strong>&lt;/a>, &lt;a href="https://claude.ai/" target="_blank" rel="noopener noreferrer">&lt;strong>Claude&lt;/strong>&lt;/a> ou &lt;a href="https://gemini.google.com/" target="_blank" rel="noopener noreferrer">&lt;strong>Gemini&lt;/strong>&lt;/a>), não é possível realizar comparações diretas com os &lt;em>benchmarks&lt;/em>. Nessas situações, a detecção de contaminação depende de evidências indiretas, geralmente obtidas por meio de inferência estatística, análise cronológica ou observação de comportamentos em tarefas específicas.&lt;/p>&lt;p>Essas abordagens são especialmente relevantes em modelos classificados como &lt;strong>caixa preta&lt;/strong> e &lt;strong>caixa cinza&lt;/strong>, nos quais não há acesso aos dados de treinamento. Ainda assim, também podem ser aplicadas a modelos &lt;strong>caixa branca&lt;/strong>, especialmente em análises comparativas, complementares ou em cenários de validação cruzada.&lt;/p>&lt;p>As principais estratégias empregadas nesse cenário incluem:&lt;/p>&lt;ul>&lt;li>&lt;p>&lt;strong>Análise cronológica&lt;/strong>: busca comparar o desempenho do modelo em &lt;em>benchmarks&lt;/em> publicados em momentos distintos. Uma melhora abrupta em &lt;em>benchmarks&lt;/em> liberados após a data de corte do treinamento pode sugerir exposição posterior ao conteúdo de teste &lt;a href="#ref4">[4]&lt;/a>.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Análise comportamental&lt;/strong>: avalia se o modelo responde corretamente a variações nos exemplos do &lt;em>benchmark&lt;/em>, como &lt;em>prompts&lt;/em> truncados, reordenados ou parafraseados. Técnicas como o &lt;strong>TS-Guessing&lt;/strong> exploram esse princípio para detectar memorização implícita &lt;a href="#ref2">[2]&lt;/a> &lt;a href="#ref4">[4]&lt;/a>.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;strong>Inferência por confiança&lt;/strong>: abrange métodos que estimam a presença de exemplos de treinamento com base no padrão de respostas do modelo. Técnicas como os &lt;strong>Membership Inference Attacks (MIA)&lt;/strong> e o &lt;strong>BenBench&lt;/strong> comparam o grau de confiança ou perplexidade do modelo em exemplos suspeitos em relação a exemplos sabidamente fora do treinamento. Uma concentração anormal de confiança ou variação de perplexidade em itens específicos pode indicar memorização &lt;a href="#ref4">[4]&lt;/a> &lt;a href="#ref6">[6]&lt;/a>.&lt;/p>&lt;/li>&lt;/ul>&lt;p>Essas metodologias são úteis para detectar contaminação em modelos sem transparência sobre seus dados de origem, mas envolvem maior grau de incerteza. Por dependerem de inferências comportamentais ou contextuais, os resultados exigem interpretação cuidadosa, especialmente quando utilizados de forma isolada. Ainda assim, úteis para a avaliação de modelos comerciais ou sem documentação disponível.&lt;/p>&lt;h3 id="ferramentas-auxiliares-na-detecção-de-contaminação">Ferramentas auxiliares na detecção de contaminação&lt;/h3>&lt;p>Com o aumento da preocupação em torno da contaminação por dados de &lt;em>benchmarks&lt;/em>, diversas ferramentas têm sido desenvolvidas para automatizar e padronizar estratégias de detecção. Essas ferramentas integram métodos complementares baseados em correspondência literal, similaridade semântica, comportamento do modelo e análises estatísticas, permitindo investigações mais robustas mesmo em contextos com acesso restrito aos dados ou aos parâmetros dos modelos.&lt;/p>&lt;p>O &lt;a href="https://github.com/ntunlp/LLMSanitize" target="_blank" rel="noopener noreferrer">&lt;strong>LLMSanitize&lt;/strong>&lt;/a> implementa diversas técnicas descritas em diferentes estudos, oferecendo métodos voltados a modelos &lt;strong>caixa branca&lt;/strong>, como &lt;em>string matching&lt;/em>, truncamento de entrada e avaliação semântica com LLMs, bem como estratégias para modelos &lt;strong>caixa cinza&lt;/strong> e &lt;strong>caixa preta&lt;/strong>, como o &lt;strong>TS-Guessing&lt;/strong> e o &lt;strong>Sharded Likelihood&lt;/strong>, metodologias baseadas em análise comportamental.&lt;/p>&lt;p>Algumas ferramentas são voltadas a metodologias específicas. O &lt;a href="https://github.com/GAIR-NLP/benbench" target="_blank" rel="noopener noreferrer">&lt;strong>BenBench&lt;/strong>&lt;/a>, por exemplo, busca sinais de memorização implícita por meio da análise de perplexidade, similaridade e acurácia em versões originais e parafraseadas de &lt;em>benchmarks&lt;/em>, sendo especialmente útil na avaliação de modelos &lt;strong>caixa preta&lt;/strong> ou &lt;strong>caixa cinza&lt;/strong>. O &lt;a href="https://github.com/eth-sri/ConStat" target="_blank" rel="noopener noreferrer">&lt;strong>ConStat&lt;/strong>&lt;/a> é voltado à comparação estatística entre o desempenho do modelo em dados suspeitos e em outros &lt;em>benchmarks&lt;/em> similares, visando detectar padrões de desempenho atípicos. Já o &lt;a href="https://github.com/YihongDong/CDD-TED4LLMs" target="_blank" rel="noopener noreferrer">&lt;strong>CDD-TED&lt;/strong>&lt;/a> propõe o uso de &lt;em>benchmarks&lt;/em> diagnósticos controlados para examinar discrepâncias na distribuição de confiança e entropia das respostas, oferecendo evidências indiretas de contaminação.&lt;/p>&lt;p>Essas ferramentas representam meios práticos e sistemáticos para detectar exposições em diferentes níveis.&lt;/p>&lt;h2 id="conclusão">Conclusão&lt;/h2>&lt;p>A contaminação por dados de &lt;em>benchmark&lt;/em> constitui um desafio relevante para a avaliação justa de modelos de linguagem. Como discutido ao longo do texto, esse fenômeno compromete a validade das métricas, dificulta comparações entre LLMs e pode levar à adoção de modelos com desempenho superestimado em aplicações reais.&lt;/p>&lt;p>Para mitigar a contaminação, diversas estratégias têm sido indicadas na literatura. Entre elas, destacam-se a reformulação de &lt;em>benchmarks&lt;/em> por meio de técnicas como &lt;em>paraphrasing&lt;/em> e &lt;em>back-translation&lt;/em>, a criação de conjuntos de teste dinâmicos, o uso de avaliações mediadas por modelos de linguagem mais robustos e a implementação de &lt;em>benchmarks&lt;/em> privados com acesso controlado. No entanto, essas soluções ainda enfrentam limitações práticas, especialmente em idiomas sub-representados, nos quais a variedade e a qualidade dos dados disponíveis são restritas.&lt;/p>&lt;p>Este artigo apresentou uma caracterização geral da contaminação por dados de &lt;em>benchmark&lt;/em>, abordando suas causas, impactos e principais metodologias de detecção. Como continuidade, serão conduzidos estudos empíricos com foco em idiomas sub-representados. Embora a maioria dos trabalhos existentes se concentre em idiomas amplamente representados nos dados globais, como o inglês e o chinês, há indícios de que o problema seja ainda mais crítico em línguas com menor presença nos repositórios de treinamento. A escassez de &lt;em>benchmarks&lt;/em> exclusivos e a ampla reutilização de fontes públicas aumentam a probabilidade de sobreposição entre dados de treinamento e teste nesse contexto.&lt;/p>&lt;p>Tomando o português brasileiro como exemplo de idioma sub-representado, os estudos futuros utilizarão modelos multilíngues e especializados no idioma, com o objetivo de estimar o grau de exposição a dados de avaliação e contribuir para práticas mais consistentes de validação e comparação entre modelos.&lt;/p>&lt;h2 id="referências">Referências&lt;/h2>&lt;p>&lt;a name="ref1">[1]&lt;/a> Cheng Xu, Shuhao Guan, Derek Greene, and M-Tahar Kechadi. 2024. &lt;em>Benchmark Data Contamination of Large Language Models: A Survey&lt;/em>. arXiv preprint arXiv:2406.04244.&lt;/p>&lt;p>&lt;a name="ref2">[2]&lt;/a> Chunyuan Deng, Yilun Zhao, Xiangru Tang, Mark Gerstein, and Arman Cohan. 2024. &lt;em>Investigating Data Contamination in Modern Benchmarks for Large Language Models&lt;/em>. In &lt;em>Proceedings of the 2024 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies (Volume 1: Long Papers)&lt;/em>, pages 8706–8719, Mexico City, Mexico. Association for Computational Linguistics.&lt;/p>&lt;p>&lt;a name="ref3">[3]&lt;/a> Chunyuan Deng, Yilun Zhao, Yuzhao Heng, Yitong Li, Jiannan Cao, Xiangru Tang, and Arman Cohan. 2024. &lt;em>Unveiling the Spectrum of Data Contamination in Language Model: A Survey from Detection to Remediation&lt;/em>. In &lt;em>Findings of the Association for Computational Linguistics: ACL 2024&lt;/em>, pages 16078–16092, Bangkok, Thailand. Association for Computational Linguistics.&lt;/p>&lt;p>&lt;a name="ref4">[4]&lt;/a> Mathieu Ravaut, Bosheng Ding, Fangkai Jiao, Hailin Chen, Xingxuan Li, Ruochen Zhao, Chengwei Qin, Caiming Xiong, and Shafiq Joty. 2024. &lt;em>How much are LLMs contaminated? A Comprehensive Survey and the LLMSanitize Library&lt;/em>. arXiv preprint arXiv:2404.00699.&lt;/p>&lt;p>&lt;a name="ref5">[5]&lt;/a> Oscar Sainz, Jon Campos, Iker García-Ferrero, Julen Etxaniz, Oier Lopez de Lacalle, and Eneko Agirre. 2023. &lt;em>NLP Evaluation in Trouble: On the Need to Measure LLM Data Contamination for Each Benchmark&lt;/em>. In &lt;em>Findings of the Association for Computational Linguistics: EMNLP 2023&lt;/em>, pages 10776–10787, Singapore. Association for Computational Linguistics.&lt;/p>&lt;p>&lt;a name="ref6">[6]&lt;/a> Ruijie Xu, Zengzhi Wang, Run-Ze Fan, and Pengfei Liu. 2024. &lt;em>Benchmarking Benchmark Leakage in Large Language Models&lt;/em>. arXiv preprint arXiv:2404.18824.&lt;/p>&lt;p>&lt;a name="ref7">[7]&lt;/a> Simone Balloccu, Patrícia Schmidtová, Mateusz Lango, and Ondrej Dusek. 2024. &lt;em>Leak, Cheat, Repeat: Data Contamination and Evaluation Malpractices in Closed-Source LLMs&lt;/em>. In &lt;em>Proceedings of the 18th Conference of the European Chapter of the Association for Computational Linguistics (Volume 1: Long Papers)&lt;/em>, pages 67–93, St. Julian’s, Malta. Association for Computational Linguistics.&lt;/p></description></item><item><title>Computação@UFCG lidera contribuições do Brasil ao framework HELM-Stanford em parceria com a IBM</title><link>https://llm-pt-ibm.github.io/posts/contribuicao_helm/</link><pubDate>Wed, 09 Jul 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/contribuicao_helm/</guid><description>&lt;p>&lt;strong>Colaboração entre Ciência da Computação da UFCG e a IBM faz da universidade a maior contribuinte brasileira para o &lt;em>framework&lt;/em> de avaliação &lt;a href="https://github.com/stanford-crfm/helm" rel="external">&lt;span class="link-personalizado">HELM-Stanford&lt;/span>&lt;/a> em 2025.&lt;/strong>&lt;/p>&lt;p>O HELM-Stanford é um dos principais &lt;em>frameworks&lt;/em> globais para avaliar modelos de linguagem, medindo precisão, robustez e responsabilidade. Ser a maior contribuinte brasileira — por meio da parceria entre Computação@UFCG e a IBM — destaca o protagonismo nacional na construção de métricas mais justas, seguras e representativas para LLMs, especialmente em contextos multilíngues e culturais diversos.&lt;/p>&lt;p>A parceria entre Computação@UFCG e a IBM resultou em 15 contribuições significativas ao HELM-Stanford em 2025. Essas contribuições incluem a adição de benchmarks voltados à língua portuguesa, correções de bugs, melhorias no código-fonte e a inclusão de novos conjuntos de avaliação, ampliando a diversidade linguística e a robustez do framework.&lt;/p>&lt;p>O projeto coordenado pelo professor João Brunet, com participação dos professores Fábio Morais e Leandro Balby, conta com uma equipe multidisciplinar dedicada à avaliação de LLMs. Participam também um professor do IFPB, três alunos de pós-graduação, três de graduação e um profissional com experiência em desenvolvimento de software. A IBM, parceira no projeto, também destaca profissionais para atuarem diretamente na colaboração. Juntos, o grupo tem contribuído de forma expressiva para o avanço do HELM-Stanford, com foco na inclusão da língua portuguesa e na melhoria contínua do &lt;em>framework&lt;/em>.&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/carvalheira.jpeg" alt="Equipe multidisciplinar do projeto"/>&lt;figcaption> &lt;p>Equipe multidisciplinar do projeto&lt;/p> &lt;/figcaption>&lt;/figure></description></item><item><title>API de inferência de Modelos de Linguagem no servidor Power9 IBM</title><link>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt4_en/</link><pubDate>Thu, 03 Jul 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt4_en/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este é o quarto e último post de uma série de tutoriais cujo objetivo é mostrar passo a passo como construir uma API de Modelos de Linguagem em um servidor Power9, desde a configuração do sistema operacional até a execução remota de inferências. Já configuramos o sistema operacional, os drivers NVIDIA, CUDA e cuDNN no &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt1_en/">&lt;span class="link-personalizado">primeiro post&lt;/span>&lt;/a>, no &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt2_en/">&lt;span class="link-personalizado">segundo post&lt;/span>&lt;/a> instalamos Conda e PyTorch e no &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt3_en/">&lt;span class="link-personalizado">terceiro post&lt;/span>&lt;/a> construímos a API. Nesta etapa, vamos apresentar a API construída e mostrar como realizar requisições.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta a API de inferência de LLMs construída e como utilizar.&lt;/li>&lt;li>Vamos mostrar como realizar requisições via python e curl.&lt;/li>&lt;/ul>&lt;h2 id="apresentando-a-api">Apresentando a API&lt;/h2>&lt;p>Esta API foi desenvolvida para expor modelos de linguagem de grande porte para inferência remota. Permite ao usuário carregar modelos específicos, mantê-los na memória da GPU para chamadas sucessivas e gerar texto a partir de prompts enviados via requisição HTTP. Foi implementada em FastAPI e inclui controle de acesso via API Key, gerenciamento de memória (carregar e descarregar modelos), suporte a múltiplas GPUs com sharding automático e endpoints para consulta de status. O objetivo é oferecer um serviço robusto, otimizado para uso intensivo, garantindo rapidez nas inferências e facilidade de integração com aplicações externas.&lt;/p>&lt;h4 id="visão-geral-da-arquitetura">Visão Geral da Arquitetura&lt;/h4>&lt;p>A API expõe modelos de linguagem via FastAPI com endpoints REST. O ModelManager gerencia o carregamento, descarregamento e a inferência dos modelos, mantendo-os em GPU para chamadas rápidas. A autenticação é feita por API Key. A arquitetura suporta múltiplas GPUs com sharding automático para otimizar o uso de memória e desempenho. Os modelos são importados do HuggingFace e utiliza a biblioteca Transformers para execução de inferências.&lt;/p>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/arquitetura_api_llm_01.png" alt="Descrição alternativa"/>&lt;figcaption> &lt;p>Diagrama da arquitetura&lt;/p> &lt;/figcaption>&lt;/figure>&lt;h4 id="principais-funcionalidades">Principais Funcionalidades&lt;/h4>&lt;ul>&lt;li>&lt;p>&lt;strong>Carregar Modelos&lt;/strong>&lt;/p>&lt;ul>&lt;li>&lt;code>/load_model&lt;/code>&lt;/li>&lt;li>Carrega modelo do HuggingFace Hub&lt;/li>&lt;li>Faz sharding para as GPUs&lt;/li>&lt;li>Suporte ao HuggingFace Token&lt;/li>&lt;/ul>&lt;/li>&lt;li>&lt;p>&lt;strong>Gerar Texto&lt;/strong>&lt;/p>&lt;ul>&lt;li>&lt;code>/generate&lt;/code>&lt;/li>&lt;li>Recebe prompt, max_tokens, nome do modelo, temperatura e top_p&lt;/li>&lt;li>Usa modelo já carregado ou carrega um novo&lt;/li>&lt;li>Retorna resultado em JSON&lt;/li>&lt;/ul>&lt;/li>&lt;li>&lt;p>&lt;strong>Gerenciamento&lt;/strong>&lt;/p>&lt;ul>&lt;li>&lt;code>/status&lt;/code>: Verifica modelo carregado em device (CPU/GPU)&lt;/li>&lt;li>&lt;code>/unload_model&lt;/code>: libera GPU e memória&lt;/li>&lt;li>&lt;code>/generate_apikey&lt;/code>: cria chaves a partir de usuário LDAP&lt;/li>&lt;/ul>&lt;/li>&lt;/ul>&lt;h4 id="fluxo-de-uso">Fluxo de Uso&lt;/h4>&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/arquitetura_api_llm_02.png" alt="Descrição alternativa"/>&lt;figcaption> &lt;p>Diagrama do fluxo de uso&lt;/p> &lt;/figcaption>&lt;/figure>&lt;h4 id="entradas-e-endpoints">Entradas e Endpoints&lt;/h4>&lt;p>Na tabela abaixo estão descritos o endpoints da API, entradas necessárias e retornos.&lt;/p>&lt;style>table { border-collapse: collapse; width: 100%;}th { background-color: #cccccc; text-align: center; padding: 8px; border: 1px solid #b3b3b3;}td { padding: 8px; border: 1px solid #ccc; text-align: left;}td.center { text-align: center;}caption { caption-side: bottom}&lt;/style>&lt;table> &lt;caption>Tabela de endpoints e entradas &lt;thead> &lt;tr> &lt;th>Endpoints&lt;/th> &lt;th>Método&lt;/th> &lt;th>Api Key&lt;/th> &lt;th>Entrada (Body/Query)&lt;/th> &lt;th>Retorno&lt;/th> &lt;/tr> &lt;/thead> &lt;tbody> &lt;tr> &lt;td>&lt;code>/generate_apikey&lt;/code>&lt;/td> &lt;td class="center">POST&lt;/td> &lt;td class="center">❌&lt;/td> &lt;td class="center">{username}&lt;/td> &lt;td class="center">API Key&lt;/td> &lt;/tr> &lt;tr> &lt;td>&lt;code>/load_model&lt;/code>&lt;/td> &lt;td class="center">POST&lt;/td> &lt;td class="center">✅&lt;/td> &lt;td class="center">{model_name &lt;br> hf_token(opcional) &lt;br> device(opcional)}&lt;/td> &lt;td class="center">Nenhum, apenas carrega o modelo&lt;/td> &lt;/tr> &lt;tr> &lt;td>&lt;code>/generate&lt;/code>&lt;/td> &lt;td class="center">POST&lt;/td> &lt;td class="center">✅&lt;/td> &lt;td class="center">{model_name &lt;br> prompt &lt;br> hf_token(opcional) &lt;br> max_tokens(opcional) &lt;br> temperature(opcional) &lt;br> top_p(opcional)}&lt;/td> &lt;td class="center">Texto gerado pelo modelo&lt;/td> &lt;/tr> &lt;tr> &lt;td>&lt;code>/status&lt;/code>&lt;/td> &lt;td class="center">GET&lt;/td> &lt;td class="center">✅&lt;/td> &lt;td class="center">Nenhuma&lt;/td> &lt;td class="center">Status do modelo e dispositivo que ele está carregado&lt;/td> &lt;/tr> &lt;tr> &lt;td>&lt;code>/unload_model&lt;/code>&lt;/td> &lt;td class="center">POST&lt;/td> &lt;td class="center">✅&lt;/td> &lt;td class="center">Nenhuma&lt;/td> &lt;td class="center">Nenhum, apenas descarrega o modelo&lt;/td> &lt;/tr> &lt;/tbody>&lt;/table>&lt;h2 id="como-usar-a-api-com-python">Como usar a API com Python&lt;/h2>&lt;h4 id="gerar-api-key">Gerar API Key&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> requests&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> json&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> os&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5&lt;/span>&lt;span>url &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;http://&amp;lt;ip_servidor_power9&amp;gt;:8000/&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6&lt;/span>&lt;span>username &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span>usuario_ldap&lt;span style="color:#f92672">&amp;gt;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7&lt;/span>&lt;span>hf_token &lt;span style="color:#f92672">=&lt;/span> os&lt;span style="color:#f92672">.&lt;/span>getenv(&lt;span style="color:#e6db74">&amp;#34;HUGGINGFACE_TOKEN&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9&lt;/span>&lt;span>response &lt;span style="color:#f92672">=&lt;/span> requests&lt;span style="color:#f92672">.&lt;/span>post(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/generate_apikey&amp;#34;&lt;/span>, json&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;username&amp;#34;&lt;/span>: username})&lt;span style="color:#f92672">.&lt;/span>content&lt;span style="color:#f92672">.&lt;/span>decode()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11&lt;/span>&lt;span>api_key &lt;span style="color:#f92672">=&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>loads(response)&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#34;api_key&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>&lt;li>É importante que o HuggingFace Token esteja definido como variável de ambiente no local em que esteja executando a inferência.&lt;/li>&lt;li>&lt;code>api_key&lt;/code> será o retorno da função chamada.&lt;/li>&lt;/ul>&lt;h4 id="carregar-modelo">Carregar Modelo&lt;/h4>&lt;p>Primeiramente precisamos criar um header que irá conter a API Key retornada com o código acima e o payload que irá conter o &lt;code>model_name&lt;/code> o token do huggingface &lt;code>hf_token&lt;/code>. Após isso, podemos enviar a requisições com essas duas informações.&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1&lt;/span>&lt;span>headers &lt;span style="color:#f92672">=&lt;/span> {&lt;span style="color:#e6db74">&amp;#34;Content-Type&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;application/json&amp;#34;&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2&lt;/span>&lt;span>&lt;span style="color:#e6db74">&amp;#34;x-api-key&amp;#34;&lt;/span>: api_key}&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4&lt;/span>&lt;span>payload &lt;span style="color:#f92672">=&lt;/span> {&lt;span style="color:#e6db74">&amp;#34;model_name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;ibm-granite/granite-3.3-8b-instruct&amp;#34;&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5&lt;/span>&lt;span> &lt;span style="color:#e6db74">&amp;#34;hf_token&amp;#34;&lt;/span>: hf_token}&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7&lt;/span>&lt;span>resp &lt;span style="color:#f92672">=&lt;/span> requests&lt;span style="color:#f92672">.&lt;/span>post(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/load_model&amp;#34;&lt;/span>, headers&lt;span style="color:#f92672">=&lt;/span>headers, json&lt;span style="color:#f92672">=&lt;/span>payload)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="gerar-texto">Gerar Texto&lt;/h4>&lt;p>Agora precisamos criar um novo payload com as informações necessárias para gerar um texto com uma llm, são elas: &lt;code>prompt&lt;/code>, &lt;code>model_name&lt;/code> e &lt;code>hf_token&lt;/code>.&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1&lt;/span>&lt;span>payload &lt;span style="color:#f92672">=&lt;/span> {&lt;span style="color:#e6db74">&amp;#34;prompt&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Olá, me fale um pouco sobre a Universidade Federal de Campina Grande (UFCG)&amp;#34;&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2&lt;/span>&lt;span> &lt;span style="color:#e6db74">&amp;#34;model_name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;ibm-granite/granite-3.3-8b-instruct&amp;#34;&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3&lt;/span>&lt;span> &lt;span style="color:#e6db74">&amp;#34;hf_token&amp;#34;&lt;/span>: hf_token}&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5&lt;/span>&lt;span>resp &lt;span style="color:#f92672">=&lt;/span> requests&lt;span style="color:#f92672">.&lt;/span>post(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/generate&amp;#34;&lt;/span>, headers&lt;span style="color:#f92672">=&lt;/span>headers, json&lt;span style="color:#f92672">=&lt;/span>payload)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7&lt;/span>&lt;span>resp &lt;span style="color:#f92672">=&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>loads(resp&lt;span style="color:#f92672">.&lt;/span>content&lt;span style="color:#f92672">.&lt;/span>decode())&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="consultar-status-e-descarregar-o-modelo">Consultar status e descarregar o modelo&lt;/h4>&lt;p>Para consultar o status e descarregar o modelo não precisamos passar conteúdo pelo payload, apenas o header com a API key:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1&lt;/span>&lt;span>requests&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/status&amp;#34;&lt;/span>, headers&lt;span style="color:#f92672">=&lt;/span>headers)&lt;span style="color:#f92672">.&lt;/span>content&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1&lt;/span>&lt;span>resp &lt;span style="color:#f92672">=&lt;/span> requests&lt;span style="color:#f92672">.&lt;/span>post(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/unload_model&amp;#34;&lt;/span>, headers&lt;span style="color:#f92672">=&lt;/span>headers)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="como-usar-a-api-com-curl-em-cli">Como usar a API com curl em CLI&lt;/h2>&lt;h4 id="gerar-api-key-1">Gerar API Key&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X POST &lt;span style="color:#e6db74">&amp;#34;http://&amp;lt;ip_servidor_power9&amp;gt;:8000/generate_apikey&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -d &lt;span style="color:#e6db74">&amp;#39;{&amp;#34;username&amp;#34;: &amp;lt;usuario_ldap&amp;gt;}&amp;#39;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>&lt;li>É importante que o HuggingFace Token esteja definido como variável de ambiente no local em que esteja executando a inferência.&lt;/li>&lt;li>O usuário no campo de &lt;code>username&lt;/code> deve estar entre aspas (&amp;quot; &amp;ldquo;)&lt;/li>&lt;li>Após executar a requisição acima, a API key retornada deverá ser salva como variável de ambiente para facilitar as próximas execuções. Para salvar você deve copiar a API key retornada e executar o comando:&lt;/li>&lt;/ul>&lt;pre tabindex="0">&lt;code>export API_KEY_P9=&amp;lt;api_key_retornada&amp;gt;&lt;/code>&lt;/pre>&lt;h4 id="carregar-modelo-1">Carregar Modelo&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X POST &lt;span style="color:#e6db74">&amp;#34;http://&amp;lt;ip_servidor_power9&amp;gt;:8000/load_model&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;x-api-key: &lt;/span>$API_KEY&lt;span style="color:#e6db74">&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -d &lt;span style="color:#e6db74">&amp;#39;{&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;model_name&amp;#34;:&amp;#34;ibm-granite/granite-3.3-8b-instruct&amp;#34;,&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;hf_token&amp;#34;:&amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>$HUGGINGFACE_TOKEN&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> }&amp;#39;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="gerar-texto-1">Gerar Texto&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X POST &lt;span style="color:#e6db74">&amp;#34;http://&amp;lt;ip_servidor_power9&amp;gt;:8000/generate&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;x-api-key: &lt;/span>$API_KEY&lt;span style="color:#e6db74">&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -d &lt;span style="color:#e6db74">&amp;#39;{&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;model_name&amp;#34;: &amp;#34;ibm-granite/granite-3.3-8b-instruct&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;prompt&amp;#34;:&amp;#34;Olá, me fale um pouco sobre a Universidade Federal de Campina Grande (UFCG)&amp;#34;,&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;hf_token&amp;#34;: &amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>$HUGGINGFACE_TOKEN&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&amp;#34;,&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;max_tokens&amp;#34;:50&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> }&amp;#39;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="consultar-status-e-descarregar-o-modelo-1">Consultar status e descarregar o modelo&lt;/h4>&lt;p>Para consultar o status e descarregar o modelo não precisamos passar conteúdo pelo payload, apenas o header com a API key:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X GET &lt;span style="color:#e6db74">&amp;#34;http://&amp;lt;ip_servidor_power9&amp;gt;:8000/status&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;x-api-key: &lt;/span>$API_KEY&lt;span style="color:#e6db74">&amp;#34;&lt;/span> &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X POST &lt;span style="color:#e6db74">&amp;#34;http://&amp;lt;ip_servidor_power9&amp;gt;:8000/unload_model&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;Content-Type: applicatzion/json&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;x-api-key: &lt;/span>$API_KEY&lt;span style="color:#e6db74">&amp;#34;&lt;/span> &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Esperamos que estes posts tenham ajudado a esclarecer todo o processo de desenvolvimento e implantação. O time LLM-IBM-UFCG está à disposição para dúvidas ou sugestões sobre aprimoramentos futuros.&lt;/p></description></item><item><title>Construindo API para inferências de LLMs em um servidor IBM Power9</title><link>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt3_en/</link><pubDate>Wed, 02 Jul 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt3_en/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este é o terceiro post de uma série de tutoriais cujo objetivo é mostrar passo a passo como construir uma API de Modelos de Linguagem em um servidor Power9, desde a configuração do sistema operacional até a execução remota de inferências. Já configuramos o sistema operacional, os drivers NVIDIA, CUDA e cuDNN no &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt1_en/">&lt;span class="link-personalizado">primeiro post&lt;/span>&lt;/a>, e no &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt2_en/">&lt;span class="link-personalizado">segundo post&lt;/span>&lt;/a> instalamos Conda e PyTorch. Nesta etapa, vamos construir a API usando FastAPI e a biblioteca Transformers, baixando modelos do Hugging Face e executando o servidor web com uvicorn.&lt;/p>&lt;p>A API implementada terá as funcionalidades de gerar API Key, carregar modelos, realizar inferências, obter status e desccaregar modelos.&lt;/p>&lt;p>&lt;strong>FastAPI&lt;/strong>: Framework web moderno para construção de APIs com Python 3.8+, baseado em tipagem estática e assíncrona. Foi projetado para ser rápido, fácil de usar e robusto, tornando o desenvolvimento de APIs mais eficiente.&lt;/p>&lt;p>&lt;strong>Transformers&lt;/strong>: Biblioteca de código aberto desenvolvida pela Hugging Face. Fornece acesso prático e eficiente a uma ampla coleção de modelos pré-treinados de última geração para Processamento de Linguagem Natural (PLN), visão computacional e áudio.&lt;/p>&lt;p>&lt;strong>Hugging Face&lt;/strong>: Hugging Face é uma plataforma focada em inteligência artificial, conhecida por hospedar modelos de NLP e outras tarefas. O Hugging Face Hub é um repositório colaborativo onde desenvolvedores e pesquisadores podem compartilhar, versionar e baixar modelos prontos para uso, facilitando o acesso e integração de modelos.&lt;/p>&lt;p>&lt;strong>Uvicorn&lt;/strong>: Servidor web ASGI (Asynchronous Server Gateway Interface). O Uvicorn é um servidor de alta performance para aplicações Python assíncronas.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta o passo a passo para implementar uma API que realiza inferências de Grandes Modelos de Linguagem.&lt;/li>&lt;li>Usaremos FastAPI e Transformers para desenvolver essa API e Hugging Face para baixar os modelos.&lt;/li>&lt;/ul>&lt;h2 id="configuração-do-ambiente">Configuração do Ambiente&lt;/h2>&lt;h4 id="estrutura-de-diretórios">Estrutura de Diretórios&lt;/h4>&lt;p>Primeiro, vamos criar a estrutura básica do projeto:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-txt" data-lang="txt">&lt;span style="display:flex;">&lt;span>model_api/&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── requirements.txt&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── app/&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── __init__.py&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── main.py&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── schemas.py&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── auth.py&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── model_manager.py&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── utils.py&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ └── apikey_store.json&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>└── README.md (opcional)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="arquivo-requirementstxt">Arquivo &lt;code>requirements.txt&lt;/code>&lt;/h4>&lt;p>Vamos usar FastAPI e Transformers para implementar a API. Além disso, usaremos uvicorn para executar o servidor, pydantic para validação de dados de entrada e torch, que já instalamos no &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt2_en/">tutorial anterior&lt;/a>.&lt;/p>&lt;p>Primeiro, vamos instalar as bibliotecas necessárias e depois preencher o arquivo &lt;code>requirements.txt&lt;/code>. Lembre-se de ativar o ambiente &lt;code>conda&lt;/code> se você o criou, para garantir o uso correto do &lt;code>pytorch&lt;/code>.&lt;/p>&lt;pre tabindex="0">&lt;code>conda activate llm_apipip install fastapi uvicorn transformers&lt;/code>&lt;/pre>&lt;p>O arquivo &lt;code>requirements.txt&lt;/code> ficará assim:&lt;/p>&lt;p>&lt;strong>requirements.txt&lt;/strong>&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-txt" data-lang="txt">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1&lt;/span>&lt;span>fastapi&amp;gt;=0.104.0&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2&lt;/span>&lt;span>uvicorn&amp;gt;=0.24.0&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3&lt;/span>&lt;span>torch&amp;gt;=2.0.0&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4&lt;/span>&lt;span>transformers&amp;gt;=4.35.0&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5&lt;/span>&lt;span>pydantic&amp;gt;=2.0.0&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="arquivo-de-armazenamento-de-api-keys">Arquivo de Armazenamento de API Keys&lt;/h4>&lt;p>O arquivo &lt;code>apikey_store.json&lt;/code> será usado para armazenar as chaves de API geradas. Vamos iniciá-lo vazio, contendo apenas &lt;code>{}&lt;/code>.&lt;/p>&lt;p>&lt;strong>apikey_store.json&lt;/strong>&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1&lt;/span>&lt;span>{}&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="schemas-e-validação-de-dados">Schemas e validação de dados&lt;/h2>&lt;p>Os schemas são essenciais para validar os dados de entrada e saída da API. Eles garantem que os dados estejam no formato correto e permitem a geração automática de documentação.&lt;/p>&lt;p>Vamos criar o arquivo &lt;code>app/schemas.py&lt;/code> com todos os modelos de dados. Teremos quatro modelos: &lt;code>GenerateRequest&lt;/code>, &lt;code>LoadModelRequest&lt;/code>, &lt;code>ApiKeyResponse&lt;/code> e &lt;code>LDAPUserRequest&lt;/code>.&lt;/p>&lt;p>&lt;strong>schemas.py&lt;/strong>&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> pydantic &lt;span style="color:#f92672">import&lt;/span> BaseModel, Field&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> typing &lt;span style="color:#f92672">import&lt;/span> Optional&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4&lt;/span>&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">GenerateRequest&lt;/span>(BaseModel):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5&lt;/span>&lt;span> model_name: str &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#f92672">...&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The name of the model to use for generation.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6&lt;/span>&lt;span> prompt: str &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#f92672">...&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The input text to generate a response for.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7&lt;/span>&lt;span> max_tokens: Optional[int] &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#ae81ff">300&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The maximum length of the generated response.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8&lt;/span>&lt;span> temperature: Optional[float] &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#ae81ff">1.0&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The sampling temperature for generation.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9&lt;/span>&lt;span> top_p: Optional[float] &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#ae81ff">1.0&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The cumulative probability for nucleus sampling.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10&lt;/span>&lt;span> hf_token: Optional[str] &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#66d9ef">None&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The Hugging Face tokenizer to use, if applicable.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13&lt;/span>&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">LoadModelRequest&lt;/span>(BaseModel):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14&lt;/span>&lt;span> model_name: str &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#f92672">...&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The name of the model to load.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15&lt;/span>&lt;span> device: Optional[str] &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#e6db74">&amp;#34;cuda&amp;#34;&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The device to load the model on (e.g., &amp;#39;cpu&amp;#39;, &amp;#39;cuda&amp;#39;).&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16&lt;/span>&lt;span> hf_token: Optional[str] &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#66d9ef">None&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The Hugging Face tokenizer to use, if applicable.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18&lt;/span>&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ApiKeyResponse&lt;/span>(BaseModel):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19&lt;/span>&lt;span> api_key: str &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#f92672">...&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The API key for accessing the model API.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21&lt;/span>&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">LDAPUserRequest&lt;/span>(BaseModel):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22&lt;/span>&lt;span> username: str &lt;span style="color:#f92672">=&lt;/span> Field(&lt;span style="color:#f92672">...&lt;/span>, description&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;The username for LDAP authentication.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>&lt;li>Todas as classes herdam da classe &lt;code>BaseModel&lt;/code> da biblioteca &lt;code>pydantic&lt;/code>, obtendo funcionalidades de validação, serialização e documentação automática.&lt;/li>&lt;li>O campo &lt;code>Field(...)&lt;/code> define um campo obrigatório sem valor padrão.&lt;/li>&lt;li>O campo &lt;code>Field(value)&lt;/code> define um campo obrigatório com &lt;code>value&lt;/code> como valor padrão.&lt;/li>&lt;li>O tipo &lt;code>Optional[type]&lt;/code> indica que o campo é opcional, mas deve ser do tipo &lt;code>type&lt;/code> se fornecido.&lt;/li>&lt;/ul>&lt;p>Com os schemas definidos, vamos criar o arquivo responsável pela autenticação via API Key.&lt;/p>&lt;h2 id="autenticação-e-api-keys">Autenticação e API Keys&lt;/h2>&lt;p>O sistema de autenticação protege a API, garantindo que apenas usuários autorizados possam acessar os endpoints. Vamos implementar um mecanismo baseado em API Keys.&lt;/p>&lt;p>Vamos criar o arquivo &lt;code>app/auth.py&lt;/code> com todas as funcionalidades de autenticação.&lt;/p>&lt;p>&lt;strong>auth.py&lt;/strong>&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> secrets &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> json&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> fastapi &lt;span style="color:#f92672">import&lt;/span> HTTPException, Request&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5&lt;/span>&lt;span>APIKEY_STORE_FILE &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;app/apikey_store.json&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7&lt;/span>&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">load_apikeys&lt;/span>():&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8&lt;/span>&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9&lt;/span>&lt;span> &lt;span style="color:#66d9ef">with&lt;/span> open(APIKEY_STORE_FILE, &lt;span style="color:#e6db74">&amp;#34;r&amp;#34;&lt;/span>) &lt;span style="color:#66d9ef">as&lt;/span> f:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>load(f)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11&lt;/span>&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> &lt;span style="color:#a6e22e">FileNotFoundError&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13&lt;/span>&lt;span> status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">404&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14&lt;/span>&lt;span> detail&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Arquivo de API keys não encontrado: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>APIKEY_STORE_FILE&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16&lt;/span>&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">save_apikeys&lt;/span>(keys: dict):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17&lt;/span>&lt;span> &lt;span style="color:#66d9ef">with&lt;/span> open(APIKEY_STORE_FILE, &lt;span style="color:#e6db74">&amp;#34;w&amp;#34;&lt;/span>) &lt;span style="color:#66d9ef">as&lt;/span> f:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18&lt;/span>&lt;span> json&lt;span style="color:#f92672">.&lt;/span>dump(keys, f, indent&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">4&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20&lt;/span>&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">generate_apikey&lt;/span>(user:str) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> str:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21&lt;/span>&lt;span> key &lt;span style="color:#f92672">=&lt;/span> secrets&lt;span style="color:#f92672">.&lt;/span>token_hex(&lt;span style="color:#ae81ff">32&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22&lt;/span>&lt;span> keys &lt;span style="color:#f92672">=&lt;/span> load_apikeys()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23&lt;/span>&lt;span> keys[user] &lt;span style="color:#f92672">=&lt;/span> key&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24&lt;/span>&lt;span> save_apikeys(keys)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> key&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27&lt;/span>&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">verify_apikey&lt;/span>(request: Request) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> bool:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28&lt;/span>&lt;span> apikey &lt;span style="color:#f92672">=&lt;/span> request&lt;span style="color:#f92672">.&lt;/span>headers&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#34;x-API-Key&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> apikey:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31&lt;/span>&lt;span> status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">401&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32&lt;/span>&lt;span> detail&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;API key não fornecida.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33&lt;/span>&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34&lt;/span>&lt;span> keys &lt;span style="color:#f92672">=&lt;/span> load_apikeys()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> apikey &lt;span style="color:#f92672">in&lt;/span> keys&lt;span style="color:#f92672">.&lt;/span>values():&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38&lt;/span>&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>JSONDecodeError:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40&lt;/span>&lt;span> status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">403&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41&lt;/span>&lt;span> detail&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;API key inválida.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>&lt;li>A função &lt;code>load_apikeys&lt;/code> carrega as informações armazenadas no arquivo &lt;code>app/apikey_store.json&lt;/code>.&lt;/li>&lt;li>&lt;code>save_apikeys&lt;/code> é responsável por salvar o conteúdo no formato JSON.&lt;/li>&lt;li>A função &lt;code>generate_apikey&lt;/code> cria uma chave para um usuário e a adiciona ao dicionário, usando o username como chave.&lt;/li>&lt;li>&lt;code>verify_apikey&lt;/code> será chamada sempre que uma requisição chegar, para realizar a validação.&lt;/li>&lt;/ul>&lt;h2 id="gerenciador-de-modelos-e-gpu">Gerenciador de Modelos e GPU&lt;/h2>&lt;p>O &lt;code>app/model_manager.py&lt;/code> é o coração da API, responsável por carregar, gerenciar e executar os modelos de linguagem. Ele otimiza o uso de GPU/CPU e garante eficiência na geração do texto.&lt;/p>&lt;p>&lt;strong>model_manager.py&lt;/strong>&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> transformers &lt;span style="color:#f92672">import&lt;/span> AutoTokenizer, AutoModelForCausalLM&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> fastapi &lt;span style="color:#f92672">import&lt;/span> HTTPException&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> gc&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> .utils &lt;span style="color:#f92672">import&lt;/span> is_model_on_gpu&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7&lt;/span>&lt;span>DEVICE &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;cuda&amp;#34;&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>is_available() &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#e6db74">&amp;#34;cpu&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9&lt;/span>&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ModelManager&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10&lt;/span>&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>tokenizer &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15&lt;/span>&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">load_model&lt;/span>(self, model_name: str, hf_token:str &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>, device: str &lt;span style="color:#f92672">=&lt;/span> DEVICE):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span> &lt;span style="color:#f92672">and&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#f92672">!=&lt;/span> model_name:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17&lt;/span>&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Removendo modelo carregado anteriormente...&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>unload_model() &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20&lt;/span>&lt;span> print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Carregando modelo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>model_name&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> no dispositivo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>device&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">...&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#f92672">!=&lt;/span> model_name:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23&lt;/span>&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>: &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> hf_token: &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>tokenizer &lt;span style="color:#f92672">=&lt;/span> AutoTokenizer&lt;span style="color:#f92672">.&lt;/span>from_pretrained(model_name, token&lt;span style="color:#f92672">=&lt;/span>hf_token)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model &lt;span style="color:#f92672">=&lt;/span> AutoModelForCausalLM&lt;span style="color:#f92672">.&lt;/span>from_pretrained(model_name, device_map&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;balanced&amp;#34;&lt;/span>, token&lt;span style="color:#f92672">=&lt;/span>hf_token)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27&lt;/span>&lt;span> &lt;span style="color:#66d9ef">else&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>tokenizer &lt;span style="color:#f92672">=&lt;/span> AutoTokenizer&lt;span style="color:#f92672">.&lt;/span>from_pretrained(model_name)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model &lt;span style="color:#f92672">=&lt;/span> AutoModelForCausalLM&lt;span style="color:#f92672">.&lt;/span>from_pretrained(model_name, device_map&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;balanced&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model&lt;span style="color:#f92672">.&lt;/span>eval()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#f92672">=&lt;/span> model_name&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32&lt;/span>&lt;span> print(is_model_on_gpu(self&lt;span style="color:#f92672">.&lt;/span>model&lt;span style="color:#f92672">.&lt;/span>hf_device_map, self&lt;span style="color:#f92672">.&lt;/span>model_name))&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34&lt;/span>&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> &lt;span style="color:#a6e22e">Exception&lt;/span> &lt;span style="color:#66d9ef">as&lt;/span> e:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">500&lt;/span>, detail&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Erro ao carregar modelo: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>str(e)&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36&lt;/span>&lt;span> &lt;span style="color:#66d9ef">else&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37&lt;/span>&lt;span> print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;O modelo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>model_name&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> já está carregado.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39&lt;/span>&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">generate&lt;/span>(self, model_name:str, hf_token: str, prompt:str, max_tokens:int &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">300&lt;/span>, temperature:float &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.0&lt;/span>, top_p:float &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.0&lt;/span>) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> str:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#f92672">!=&lt;/span> model_name:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">42&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>load_model(model_name, hf_token, device&lt;span style="color:#f92672">=&lt;/span>DEVICE)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">43&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">44&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span> &lt;span style="color:#f92672">or&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>tokenizer &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">45&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">400&lt;/span>, detail&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Nenhum modelo carregado.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">46&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">47&lt;/span>&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">48&lt;/span>&lt;span> inputs &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>tokenizer(prompt, return_tensors&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;pt&amp;#34;&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>to(self&lt;span style="color:#f92672">.&lt;/span>model&lt;span style="color:#f92672">.&lt;/span>device)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">49&lt;/span>&lt;span> &lt;span style="color:#66d9ef">with&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>no_grad(): &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">50&lt;/span>&lt;span> outputs &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model&lt;span style="color:#f92672">.&lt;/span>generate(&lt;span style="color:#f92672">**&lt;/span>inputs, max_new_tokens&lt;span style="color:#f92672">=&lt;/span>max_tokens,temperature&lt;span style="color:#f92672">=&lt;/span>temperature, top_p&lt;span style="color:#f92672">=&lt;/span>top_p, eos_token_id&lt;span style="color:#f92672">=&lt;/span>self&lt;span style="color:#f92672">.&lt;/span>tokenizer&lt;span style="color:#f92672">.&lt;/span>eos_token_id)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">51&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>tokenizer&lt;span style="color:#f92672">.&lt;/span>decode(outputs[&lt;span style="color:#ae81ff">0&lt;/span>], skip_special_tokens&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">52&lt;/span>&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> &lt;span style="color:#a6e22e">Exception&lt;/span> &lt;span style="color:#66d9ef">as&lt;/span> e:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">53&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">500&lt;/span>, detail&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Erro ao gerar texto: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>str(e)&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">54&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">55&lt;/span>&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">get_status&lt;/span>(self) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> str: &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">56&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">57&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>unload_model()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">58&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Nenhum modelo carregado.&amp;#34;&lt;/span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">59&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> is_model_on_gpu(self&lt;span style="color:#f92672">.&lt;/span>model&lt;span style="color:#f92672">.&lt;/span>hf_device_map, self&lt;span style="color:#f92672">.&lt;/span>model_name)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">60&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">61&lt;/span>&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">unload_model&lt;/span>(self):&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">62&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">63&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>tokenizer &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">64&lt;/span>&lt;span> old_model &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">False&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">65&lt;/span>&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model_name &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">66&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">67&lt;/span>&lt;span> gc&lt;span style="color:#f92672">.&lt;/span>collect()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">68&lt;/span>&lt;span> torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>empty_cache()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">69&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Modelo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>old_model&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> descarregado com sucesso.&amp;#34;&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> old_model &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Nenhum modelo carregado para descarregar.&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">70&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">71&lt;/span>&lt;span>manager &lt;span style="color:#f92672">=&lt;/span> ModelManager()&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>&lt;li>A função &lt;code>load_model&lt;/code> carrega o novo modelo na memória, removendo algum modelo que foi carregado anteriormente.&lt;/li>&lt;li>&lt;code>generate&lt;/code> é a principal função da API, ela é responsável por realizar a inferência do modelo. Permite alterar os parâmetros: temperature, top_p e max_tokens.&lt;/li>&lt;li>&lt;code>get_status&lt;/code> é responsável por informar se existe modelo carregado e se está em GPU ou CPU.&lt;/li>&lt;li>A função &lt;code>unload_model&lt;/code> remove o modelo da memória, limpando o cache do CUDA e utilizando o garbage collector do python para não restar resquícios que possam atrapalhar futuros carregamentos.&lt;/li>&lt;/ul>&lt;h2 id="endpoints-da-api-fastapi">Endpoints da API FastAPI&lt;/h2>&lt;p>O arquivo &lt;code>app/main.py&lt;/code> é onde todos os componentes se conectam. Nele definimos todos os endpoints e a lógica de roteamento da API.&lt;/p>&lt;p>&lt;strong>main.py&lt;/strong>&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> fastapi &lt;span style="color:#f92672">import&lt;/span> FastAPI, Request, HTTPException, Depends&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> fastapi.responses &lt;span style="color:#f92672">import&lt;/span> JSONResponse&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3&lt;/span>&lt;span>&lt;span style="color:#f92672">from&lt;/span> app &lt;span style="color:#f92672">import&lt;/span> schemas, model_manager, auth&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5&lt;/span>&lt;span>app &lt;span style="color:#f92672">=&lt;/span> FastAPI()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7&lt;/span>&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">require_api_key&lt;/span>(request: Request) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> schemas&lt;span style="color:#f92672">.&lt;/span>LDAPUserRequest:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8&lt;/span>&lt;span> user &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> auth&lt;span style="color:#f92672">.&lt;/span>verify_apikey(request)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> user:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">401&lt;/span>, detail&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;API key invalida.&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> user&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13&lt;/span>&lt;span>&lt;span style="color:#a6e22e">@app.post&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;/generate_apikey&amp;#34;&lt;/span>)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14&lt;/span>&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">generate_apikey&lt;/span>(payload: schemas&lt;span style="color:#f92672">.&lt;/span>LDAPUserRequest) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> JSONResponse:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15&lt;/span>&lt;span> key &lt;span style="color:#f92672">=&lt;/span> auth&lt;span style="color:#f92672">.&lt;/span>generate_apikey(payload&lt;span style="color:#f92672">.&lt;/span>username)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> JSONResponse(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">200&lt;/span>, content&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;api_key&amp;#34;&lt;/span>: key})&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18&lt;/span>&lt;span>&lt;span style="color:#a6e22e">@app.post&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;/load_model&amp;#34;&lt;/span>, dependencies&lt;span style="color:#f92672">=&lt;/span>[Depends(require_api_key)])&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19&lt;/span>&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">load_model&lt;/span>(payload: schemas&lt;span style="color:#f92672">.&lt;/span>LoadModelRequest) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> JSONResponse:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20&lt;/span>&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21&lt;/span>&lt;span> model_manager&lt;span style="color:#f92672">.&lt;/span>manager&lt;span style="color:#f92672">.&lt;/span>load_model(payload&lt;span style="color:#f92672">.&lt;/span>model_name, payload&lt;span style="color:#f92672">.&lt;/span>hf_token, payload&lt;span style="color:#f92672">.&lt;/span>device)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> JSONResponse(content&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;message&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Modelo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>payload&lt;span style="color:#f92672">.&lt;/span>model_name&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> carregado com sucesso.&amp;#34;&lt;/span>})&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23&lt;/span>&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> &lt;span style="color:#a6e22e">Exception&lt;/span> &lt;span style="color:#66d9ef">as&lt;/span> e:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">500&lt;/span>, content&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;error&amp;#34;&lt;/span>: str(e)})&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26&lt;/span>&lt;span>&lt;span style="color:#a6e22e">@app.post&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;/generate&amp;#34;&lt;/span>, dependencies&lt;span style="color:#f92672">=&lt;/span>[Depends(require_api_key)])&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27&lt;/span>&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">generate&lt;/span>(payload: schemas&lt;span style="color:#f92672">.&lt;/span>GenerateRequest)&lt;span style="color:#f92672">-&amp;gt;&lt;/span> JSONResponse:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28&lt;/span>&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29&lt;/span>&lt;span> result &lt;span style="color:#f92672">=&lt;/span> model_manager&lt;span style="color:#f92672">.&lt;/span>manager&lt;span style="color:#f92672">.&lt;/span>generate(payload&lt;span style="color:#f92672">.&lt;/span>model_name, payload&lt;span style="color:#f92672">.&lt;/span>hf_token,payload&lt;span style="color:#f92672">.&lt;/span>prompt, payload&lt;span style="color:#f92672">.&lt;/span>max_tokens, payload&lt;span style="color:#f92672">.&lt;/span>temperature, payload&lt;span style="color:#f92672">.&lt;/span>top_p)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> {&lt;span style="color:#e6db74">&amp;#34;result&amp;#34;&lt;/span>: result}&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31&lt;/span>&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> &lt;span style="color:#a6e22e">Exception&lt;/span> &lt;span style="color:#66d9ef">as&lt;/span> e:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> JSONResponse(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">500&lt;/span>, content&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;error&amp;#34;&lt;/span>: str(e)})&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33&lt;/span>&lt;span> &lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34&lt;/span>&lt;span>&lt;span style="color:#a6e22e">@app.get&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;/status&amp;#34;&lt;/span>, dependencies&lt;span style="color:#f92672">=&lt;/span>[Depends(require_api_key)])&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35&lt;/span>&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">status&lt;/span>()&lt;span style="color:#f92672">-&amp;gt;&lt;/span> JSONResponse:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36&lt;/span>&lt;span> str_status &lt;span style="color:#f92672">=&lt;/span> model_manager&lt;span style="color:#f92672">.&lt;/span>manager&lt;span style="color:#f92672">.&lt;/span>get_status()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> JSONResponse(content&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;status&amp;#34;&lt;/span>: str_status})&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38&lt;/span>&lt;span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39&lt;/span>&lt;span>&lt;span style="color:#a6e22e">@app.post&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;/unload_model&amp;#34;&lt;/span>, dependencies&lt;span style="color:#f92672">=&lt;/span>[Depends(require_api_key)])&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40&lt;/span>&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">unload_model&lt;/span>() &lt;span style="color:#f92672">-&amp;gt;&lt;/span> JSONResponse:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41&lt;/span>&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">42&lt;/span>&lt;span> str_unload &lt;span style="color:#f92672">=&lt;/span> model_manager&lt;span style="color:#f92672">.&lt;/span>manager&lt;span style="color:#f92672">.&lt;/span>unload_model()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">43&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> JSONResponse(content&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;message&amp;#34;&lt;/span>:str_unload})&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">44&lt;/span>&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> &lt;span style="color:#a6e22e">Exception&lt;/span> &lt;span style="color:#66d9ef">as&lt;/span> e:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">45&lt;/span>&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> HTTPException(status_code&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">500&lt;/span>, content&lt;span style="color:#f92672">=&lt;/span>{&lt;span style="color:#e6db74">&amp;#34;error&amp;#34;&lt;/span>: str(e)})&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>&lt;li>A função &lt;code>require_api_key&lt;/code> verifica a API Key sempre que chega uma requisição e retorna o usuário autenticado ou gera erro 401.&lt;/li>&lt;li>&lt;code>generate_apikey&lt;/code> gera e retorna uma nova chave de API para o usuário informado.&lt;/li>&lt;li>&lt;code>load_model&lt;/code> carrega o modelo especificado. Caso o modelo necessite de um token Hugging Face, a função também recebe esse parâmetro.&lt;/li>&lt;li>A função &lt;code>generate&lt;/code> é responsável por fazer o modelo realizar a inferência a partir do prompt e os parâmetros passados.&lt;/li>&lt;li>Ao chamar o endpoint &lt;code>status&lt;/code> o usuário recebe o status atual do gerenciador de modelos.&lt;/li>&lt;li>&lt;code>unload_model&lt;/code> descarrega o modelo atualmente carregado e retorna uma mensagem de sucesso caso tenha concluído corretamente.&lt;/li>&lt;/ul>&lt;h2 id="arquivo-utilspy">Arquivo &lt;code>utils.py&lt;/code>&lt;/h2>&lt;p>O arquivo &lt;code>app/utils.py&lt;/code> contém a função que verifica se o modelo carregado está totalmente/parcialmente em GPU ou foi carregado em CPU.&lt;/p>&lt;p>&lt;strong>utils.py&lt;/strong>&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1&lt;/span>&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">is_model_on_gpu&lt;/span>(hf_device_map: dict, model_name: str) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> str:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2&lt;/span>&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span> &lt;span style="color:#f92672">in&lt;/span> hf_device_map&lt;span style="color:#f92672">.&lt;/span>keys() &lt;span style="color:#f92672">and&lt;/span> hf_device_map[&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>] &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;cpu&amp;#39;&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Modelo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>model_name&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> carregado totalmente na CPU.&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4&lt;/span>&lt;span> &lt;span style="color:#66d9ef">elif&lt;/span> &lt;span style="color:#e6db74">&amp;#39;cpu&amp;#39;&lt;/span> &lt;span style="color:#f92672">in&lt;/span> hf_device_map&lt;span style="color:#f92672">.&lt;/span>values():&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Algumas camadas do modelo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>model_name&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> estão carregadas na CPU.&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6&lt;/span>&lt;span> &lt;span style="color:#66d9ef">else&lt;/span>:&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7&lt;/span>&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Modelo &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>model_name&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> carregado totalmente na GPU.&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="executando-a-api">Executando a API&lt;/h2>&lt;p>Para executar a API com o &lt;code>uvicorn&lt;/code> é muito simples, basta executar um comando com as informações de host e porta para o serviço rodar.&lt;/p>&lt;pre tabindex="0">&lt;code>uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload&lt;/code>&lt;/pre>&lt;ul>&lt;li>&lt;p>&lt;code>app:main&lt;/code> se refere ao arquivo &lt;code>app/main.py&lt;/code> responsável por conectar todos os componentes e receber as requisições realizadas pelo usuário.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;code>--host 0.0.0.0&lt;/code> define o endereço IP no qual o servidor Uvicorn irá escutar as requisições. O valor &lt;code>0.0.0.0&lt;/code> define que este servidor estará acessível de qualquer interface de rede disponível na máquina Power9.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;code>--port 8000&lt;/code> especifica a porta na qual o servidor irá escutar as requisições.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;code>--reload&lt;/code> flag para ser utilizada em desenvolvimento. Recarrega a aplicação sempre que uma mudança é realizada.&lt;/p>&lt;/li>&lt;/ul>&lt;p>Seguindo estas implementações, você terá uma API capaz de realizar inferências com Modelos de Linguagem baixados do Hugging Face. No &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt4_en/">&lt;span class="link-personalizado">próximo tutorial&lt;/span>&lt;/a> será demonstrado como enviar requisições para a API via curl e python.&lt;/p></description></item><item><title>Configurando Conda e PyTorch em um servidor IBM Power9</title><link>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt2_en/</link><pubDate>Mon, 30 Jun 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt2_en/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este é o segundo post de uma série de tutoriais que vamos mostrar o passo-a-passo de como construir uma API de Modelos de Linguagem em um servidor Power9, desde da configuração do Sistema Operacional, até a API executando inferências de forma remota. O &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt1_en/">&lt;span class="link-personalizado">primeiro post&lt;/span>&lt;/a> mostra como instalar o S.O e configurar drivers NVIDIA, CUDA e CUDNN. Nesta etapa do tutorial vamos mostrar a configuração do gerenciador de pacotes Conda e da biblioteca PyTorch&lt;/p>&lt;p>&lt;strong>Conda&lt;/strong>: Conda é um sistema de gerenciamento de pacotes e ambientes de código aberto e multiplataforma. Ele funciona como uma &amp;ldquo;caixa de ferramentas&amp;rdquo; para cientistas de dados e desenvolvedores, ajudando a organizar seus projetos.&lt;/p>&lt;p>&lt;strong>PyTorch&lt;/strong>: PyTorch é uma biblioteca de código aberto para aprendizado de máquina, desenvolvida principalmente pelo Facebook AI Research (FAIR). Ela é especialmente popular para o desenvolvimento de aplicações de deep learning (aprendizado profundo), um subcampo do aprendizado de máquina que se inspira no funcionamento do cérebro humano.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta o passo-a-passo para a instalação do Conda e PyTorch.&lt;/li>&lt;li>O desafio maior é encontrar versões compatíveis com a arquitetura das máquinas Power.&lt;/li>&lt;/ul>&lt;h2 id="configurando-conda">Configurando Conda&lt;/h2>&lt;p>Vamos começar com a instalação do &lt;strong>Conda&lt;/strong>. Em sistemas Power, a arquitetura usada é a &lt;code>ppc64le&lt;/code> (PowerPC 64 bits little-endian), por isso é essencial que a versão baixada seja para esta arquitetura. Para isso, vamos utilizar o &lt;strong>miniconda&lt;/strong>, uma versão mais leve e direta para setups customizados como o servidor Power9.&lt;/p>&lt;ol>&lt;li>Para baixar e instalar a versão mais atualizada do miniconda:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-ppc64le.shbash ~/Miniconda3-latest-Linux-ppc64le.sh&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Verifique se a instalação ativou o conda automático:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>conda -–version&lt;/code>&lt;/pre>&lt;p>Caso não tenha iniciado automaticamente, o Conda precisa ser ativado.&lt;/p>&lt;ol start="3">&lt;li>Para não precisar ativar sempre que realizar uma nova conexão, vamos escrever o comando no bashrc (ou zshrc):&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>echo &amp;#39;source ~/miniconda3/etc/profile.d/conda.sh&amp;#39; &amp;gt;&amp;gt; ~/.bashrcsource ~/.bashrc&lt;/code>&lt;/pre>&lt;p>Verifique novamente com o comando:&lt;/p>&lt;pre tabindex="0">&lt;code>conda --version&lt;/code>&lt;/pre>&lt;p>A saída esperada é algo semelhante a: &lt;code>conda 23.10.0&lt;/code>&lt;/p>&lt;h2 id="instalando-e-configurando-a-biblioteca-pytorch">Instalando e configurando a biblioteca PyTorch&lt;/h2>&lt;p>Não existem builds oficiais ou wheels Conda/PyPi com suporte completo para a arquitetura ppc64le, sendo assim, para instalar o PyTorch precisamos buildar manualmente.&lt;/p>&lt;h4 id="opcional-criação-de-ambiente-virtual-conda">(Opcional) Criação de ambiente virtual Conda&lt;/h4>&lt;p>Para iniciarmos a instalação é aconselhável criar um ambiente virtual para instalar o pytorch apenas nele.&lt;/p>&lt;ol>&lt;li>Para criar e ativar o ambiente virtual executamos os comandos:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>conda create -y -n api_llm python=3.10conda activate api_llm&lt;/code>&lt;/pre>&lt;h4 id="instalando-pré-requisitos">Instalando pré-requisitos&lt;/h4>&lt;p>Precisamos instalar alguns pacotes necessários para realizar o build do PyTorch da forma correta.&lt;/p>&lt;ol>&lt;li>Inicialmente, vamos instalar os pacotes com os seguintes comandos:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>conda install -y -c conda-forge openblas libblas cmake ninja python3-devel gcc-c++ rust cargo&lt;/code>&lt;/pre>&lt;p>O CMake (sistema de build utilizado pelo PyTorch) removeu o suporte a scripts que declaram compatibilidade com versões antigas (&amp;lt;3.5). Para resolver isso, precisamos instalar via pip uma versão do cmake &amp;lt;3.5.&lt;/p>&lt;ol start="2">&lt;li>Executamos o comando:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>pip install cmake==3.27.7&lt;/code>&lt;/pre>&lt;p>Para garantir que a versão correta foi instalada, executamos o comando:&lt;/p>&lt;pre tabindex="0">&lt;code>cmake --version&lt;/code>&lt;/pre>&lt;p>A saída esperada é: &lt;code>cmake version 3.27.7&lt;/code>&lt;/p>&lt;h4 id="build-do-pytorch">Build do Pytorch&lt;/h4>&lt;p>Agora vamos iniciar o processo de build do &lt;strong>PyTorch&lt;/strong>.&lt;/p>&lt;ol>&lt;li>O primeiro passo é clonar o repositório e configurar para instalar a versão 2.6.0:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>git clone --recursive https://github.com/pytorch/pytorchcd pytorchgit checkout v2.6.0 git submodule sync git submodule update --init --recursive &lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Para instalar os pacotes necessários via pip executamos o seguinte comando:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>pip install -r requirements.txt&lt;/code>&lt;/pre>&lt;ol start="3">&lt;li>E, finalmente, para realizar o build do PyTorch, executamos o setup.py do python:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo USE_CUDA=1 USE_DISTRIBUTED=1 USE_NCCL=1 USE_GLOO=1 USE_CUDNN=1 python setup.py install&lt;/code>&lt;/pre>&lt;p>O processo de build geralmente demora um tempo considerável, cerca de 15 minutos.&lt;/p>&lt;ol start="4">&lt;li>Para testar se tudo ocorreu certo, vamos criar um arquivo chamado &lt;code>test_torch.py&lt;/code>&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>nano test_torch.py&lt;/code>&lt;/pre>&lt;p>Esse arquivo deve conter as seguintes linhas:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1&lt;/span>&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2&lt;/span>&lt;span>print(torch&lt;span style="color:#f92672">.&lt;/span>__version__)&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3&lt;/span>&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;CUDA disponível:&amp;#34;&lt;/span>, torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>is_available())&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4&lt;/span>&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;Número de GPUs:&amp;#34;&lt;/span>, torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>device_count())&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5&lt;/span>&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;Nome da GPU:&amp;#34;&lt;/span>, torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>get_device_name(&lt;span style="color:#ae81ff">0&lt;/span>))&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6&lt;/span>&lt;span>x &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>rand(&lt;span style="color:#ae81ff">3&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>cuda()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7&lt;/span>&lt;span>y &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>rand(&lt;span style="color:#ae81ff">3&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>cuda()&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8&lt;/span>&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;Soma na GPU:&amp;#34;&lt;/span>, (x &lt;span style="color:#f92672">+&lt;/span> y))&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9&lt;/span>&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;cuDNN disponível:&amp;#34;&lt;/span>, torch&lt;span style="color:#f92672">.&lt;/span>backends&lt;span style="color:#f92672">.&lt;/span>cudnn&lt;span style="color:#f92672">.&lt;/span>is_available())&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10&lt;/span>&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;Extensões C carregadas:&amp;#34;&lt;/span>, torch&lt;span style="color:#f92672">.&lt;/span>_C&lt;span style="color:#f92672">.&lt;/span>_cuda_getDeviceCount() &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ao executar esse arquivo, saberemos:&lt;/p>&lt;ul>&lt;li>Versão instalada do pytorch&lt;/li>&lt;li>Disponibilidade do CUDA&lt;/li>&lt;li>Quantidade de GPUs disponíveis&lt;/li>&lt;li>Nome da GPU no servidor Power9&lt;/li>&lt;li>Se a utilização da GPU está acontecendo de forma correta&lt;/li>&lt;li>Disponibilidade do CUDNN&lt;/li>&lt;li>Se os arquivos .so foram compilados corretamentes&lt;/li>&lt;/ul>&lt;p>Esse arquivo apenas checa algumas informações do CUDA e PyTorch e executa uma operação de soma utilizando tensores em GPU.&lt;/p>&lt;ol start="5">&lt;li>Vamos executar o arquivo com o comando:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>python test_gpu.py&lt;/code>&lt;/pre>&lt;p>A saída deve ser algo semelhante a:&lt;/p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>2.6.0a0+git1eba9b3&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>CUDA disponível: True&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Número de GPUs: &lt;span style="color:#ae81ff">4&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Nome da GPU: Tesla V100-SXM2-16GB&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Soma na GPU: tensor&lt;span style="color:#f92672">([[&lt;/span>1.9163, 1.2208, 0.5998&lt;span style="color:#f92672">]&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">[&lt;/span>1.7962, 0.6040, 1.3943&lt;span style="color:#f92672">]&lt;/span>,&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">[&lt;/span>0.9536, 0.8010, 0.0668&lt;span style="color:#f92672">]]&lt;/span>, device&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;cuda:0&amp;#39;&lt;/span>&lt;span style="color:#f92672">)&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cuDNN disponível: True&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Extensões C carregadas: True&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>É importante lembrar que as saídas podem ser diferentes em relação ao número e modelo das GPUs e a soma de tensores (devido a aleatoriedade). É importante que as saídas booleanas do código que executamos tenham resultados igual a &lt;code>True&lt;/code>.&lt;/p>&lt;p>Com isso, a biblioteca PyTorch está instalada e configurada para ser utilizada. No &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt3_en/">&lt;span class="link-personalizado">próximo tutorial&lt;/span>&lt;/a> vamos realizar a primeira inferência de um Modelo de Linguagem no servidor Power9.&lt;/p></description></item><item><title>Configurando S.O, NVIDIA Drivers, CUDA e CUDNN em um servidor IBM Power9</title><link>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt1_en/</link><pubDate>Sun, 29 Jun 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/tutorial_power9_pt1_en/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este é o primeiro post de uma série de tutoriais sobre como construir uma API de Modelos de Linguagem em um servidor Power9, desde da configuração do Sistema Operacional, até a API executando inferências de forma remota.Esta etapa do tutorial mostra como configurar o Sistema Operacional, instalar os drivers da NVIDIA, CUDA e CUDNN em máquinas com processador IBM Power9 AC922. O foco é garantir que tudo funcione corretamente em arquiteturas &lt;code>ppc64le&lt;/code>, comuns em ambientes de alto desempenho.&lt;/p>&lt;p>&lt;strong>IBM Power9&lt;/strong>: A IBM Power9 AC922 é uma máquina de alto desempenho usada em tarefas pesadas como inteligência artificial e processamento científico. Ela usa processadores Power9 e trabalha bem com GPUs NVIDIA, oferecendo alta velocidade de comunicação entre CPU e GPU.&lt;/p>&lt;p>&lt;strong>NVIDIA Drivers&lt;/strong>: Programas que permitem que o sistema operacional se comunique corretamente com as placas de vídeo da marca. São essenciais para ativar o uso de GPUs.&lt;/p>&lt;p>&lt;strong>CUDA&lt;/strong>: Plataforma NVIDIA que permite usar GPUs para acelerar cálculos paralelos. Com essa plataforma é possível rodar algoritmos complexos de forma rápida, como a execução de Grandes Modelos de Linguagem, por exemplo.&lt;/p>&lt;p>&lt;strong>CUDNN&lt;/strong>: Uma biblioteca de primitivas otimizadas para redes neurais profundas (DNNs), desenvolvida pela NVIDIA. Ele oferece implementações de alto desempenho para operações essenciais em DNNs, como convoluções, pooling e normalização, acelerando significativamente o treinamento e a inferência em GPUs.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta o passo-a-passo de configurar um servidor Power9 incluindo setup do SO e configurações NVIDIA.&lt;/li>&lt;li>O desafio maior é encontrar versões compatíveis com a arquitetura das máquinas Power.&lt;/li>&lt;/ul>&lt;h2 id="configurando-sistema-operacional">Configurando Sistema Operacional&lt;/h2>&lt;p>Vamos começar com a instalação do &lt;strong>Red Hat Enterprise Linux 8.10 (Ootpa)&lt;/strong>. Em sistemas Power, a arquitetura usada é a &lt;code>ppc64le&lt;/code> (PowerPC 64 bits little-endian), por isso é essencial que a imagem .iso seja compatível com essa arquitetura. Caso contrário, o petitboot da Power9 não reconhecerá a mídia e a instalação não poderá continuar.&lt;/p>&lt;ol>&lt;li>Você pode baixar a imagem correta pelo &lt;a href="https://access.redhat.com/downloads/content/279/ver=/rhel---8/8.10/ppc64le/product-software" rel="external">&lt;span class="link-personalizado">link&lt;/span>&lt;/a> indicado.&lt;/li>&lt;li>Neste tutorial, usaremos a opção &lt;strong>Boot ISO&lt;/strong> e seguiremos as instruções da &lt;a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/interactively_installing_rhel_from_installation_media/assembly_creating-a-bootable-installation-medium_rhel-installer" rel="external">&lt;span class="link-personalizado">documentação oficial da Red Hat&lt;/span>&lt;/a> para criar uma mídia USB inicializável.&lt;/li>&lt;li>Após inserir a mídia de instalação no servidor Power 9 e reiniciar a máquina, o sistema deve iniciar automaticamente no petitboot.&lt;/li>&lt;li>A partir desta etapa, basta seguir o &lt;a href="https://www.ibm.com/docs/en/linuxonibm/liabw/rhelqs_guide_Power_p9_usb.pdf" rel="external">&lt;span class="link-personalizado">guia de instalação&lt;/span>&lt;/a> oficial para concluir a configuração do sistema.&lt;/li>&lt;/ol>&lt;h2 id="configurando-driver-nvidia-e-cuda">Configurando Driver NVIDIA e CUDA&lt;/h2>&lt;h4 id="checagem-de-gpus-e-sistema-operacional">Checagem de GPUs e Sistema Operacional&lt;/h4>&lt;p>Para o sistema operacional realizar comunicação correta com as GPUs do servidor, precisamos instalar e configurar o driver da NVIDIA.&lt;/p>&lt;ol>&lt;li>Inicialmente, vamos checar a presença da(s) GPU(s):&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>lspci | grep -i nvidia&lt;/code>&lt;/pre>&lt;p>A saída esperada é algo como:&lt;/p>&lt;p>&lt;code>0004:04:00.0 3D controller: NVIDIA Corporation GV100GL [Tesla V100 SXM2 16GB] (rev a1)&lt;/code>&lt;/p>&lt;ol start="2">&lt;li>Após isso, vamos verificar arquitetura e nome do sistema operacional:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>uname -m &amp;amp;&amp;amp; cat /etc/redhat-release&lt;/code>&lt;/pre>&lt;p>A saída esperada é:&lt;/p>&lt;p>&lt;code>ppc64le Red Hat Enterprise Linux release 8.10 (Ootpa)&lt;/code>&lt;/p>&lt;h4 id="evitando-interferências">Evitando interferências&lt;/h4>&lt;p>Para evitar algumas interferências, é recomendável desativar o driver &lt;code>nouveau&lt;/code> e &lt;code>SELinux&lt;/code>.&lt;/p>&lt;p>O &lt;code>noveau&lt;/code> é um driver de código aberto para GPUs NVIDIA que subsitui o driver proprietário quando o usuário quer apenas usar o software livre, sem necessidade de de alto desempenho.&lt;/p>&lt;p>O &lt;code>SELinux=enable&lt;/code> restringe alguns processos de aplicarem mudanças no sistema, podendo conflitar com as instalações que vamos fazer neste tutorial.&lt;/p>&lt;ol>&lt;li>Desative o driver &lt;code>nouveau&lt;/code>:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>echo -e &amp;#34;blacklist nouveau\noptions nouveau modeset=0&amp;#34; | sudo tee /etc/modprobe.d/disable-nouveau.conf&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Para desativar o &lt;code>SELinux&lt;/code>, primeiro vamos checar o status executando:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sestatus&lt;/code>&lt;/pre>&lt;p>Caso esteja ativo, será preciso setar o parâmetro &lt;code>SELINUX=disabled&lt;/code> no arquivo &lt;code>/etc/selinux/config&lt;/code> para prosseguir. É importante lembrar que a edição só será salva com permissão sudo.&lt;/p>&lt;ol start="3">&lt;li>Após isso, vamos atualizar o &lt;code>initrafms&lt;/code> e reiniciar a máquina com os seguintes comandos:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo dracut --forcesudo reboot&lt;/code>&lt;/pre>&lt;ol start="4">&lt;li>Para checar se tudo deu certo até agora, vamos checar se o &lt;code>nouveau&lt;/code> foi desabilitado:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>lsmod | grep nouveau&lt;/code>&lt;/pre>&lt;p>Caso tenha sido desabilitado, não terá saída.&lt;/p>&lt;ol start="5">&lt;li>Para checar o SELinux:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sestatus&lt;/code>&lt;/pre>&lt;p>Caso tenha sido desabilitado, a saída será: &lt;code>SELinux status: disabled&lt;/code>&lt;/p>&lt;h4 id="instalando-pré-requisitos">Instalando pré-requisitos&lt;/h4>&lt;ol>&lt;li>Vamos instalar alguns pré-requisitos antes de iniciar a instalação de fato:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo dnf install pciutils environment-modulessudo dnf install kernel-devel-$(uname -r) kernel-headerssudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpmsudo dnf clean all sudo dnf install dkms&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Também precisamos habilitar alguns repositórios:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo subscription-manager repos --enable=rhel-8-for-ppc64le-appstream-rpmssudo subscription-manager repos --enable=rhel-8-for-ppc64le-baseos-rpmssudo subscription-manager repos --enable=codeready-builder-for-rhel-8-ppc64le-rpms&lt;/code>&lt;/pre>&lt;h4 id="baixando-e-instalando-repositórios-dos-pacotes-cuda">Baixando e instalando repositórios dos pacotes CUDA&lt;/h4>&lt;ol>&lt;li>Vamos baixar a versão &lt;strong>12.2 do CUDA&lt;/strong> e o &lt;strong>Driver NVIDIA 535.54.03-1&lt;/strong> com o comando seguinte:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>wget https://developer.download.nvidia.com/compute/cuda/12.2.0/local_installers/cuda-repo-rhel8-12-2-local-12.2.0_535.54.03-1.ppc64le.rpm&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Para instalar o pacote baixado:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo rpm -i cuda-repo-rhel8-12-2-local-12.2.0_535.54.03-1.ppc64le.rpm&lt;/code>&lt;/pre>&lt;ol start="3">&lt;li>Para instalar o driver NVIDIA e o CUDA, os seguintes comandos serão executados:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo dnf install nvidia-driver-cuda sudo dnf clean all sudo dnf module reset nvidia-driver sudo dnf module enable nvidia-driver:latest-dkmssudo dnf -y module install nvidia-driver:latest-dkmssudo dnf -y install cuda &lt;/code>&lt;/pre>&lt;p>Com esses comandos a instalação do driver e do CUDA estão finalizadas.&lt;/p>&lt;h4 id="processos-pós-instalação">Processos pós-instalação&lt;/h4>&lt;ol>&lt;li>Vamos declarar as variáveis de ambiente &lt;code>PATH&lt;/code> e &lt;code>LD_LIBRARY_PATH&lt;/code>. Para isso, deve-se editar o arquivo &lt;code>.bashrc&lt;/code> e adicionar essas duas linhas:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>export PATH=/usr/local/cuda/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH&lt;/code>&lt;/pre>&lt;p>Para atualizar as variáveis de ambiente, vamos executar o comando:&lt;/p>&lt;pre tabindex="0">&lt;code>source ~/.bashrc&lt;/code>&lt;/pre>&lt;p>Precisamos realizar duas mudanças de forma manual, pois não são tratadas de forma automática pela instalação dos pacotes CUDA. Caso não sejam realizadas, a instalação do driver CUDA ficará inoperante.&lt;/p>&lt;ol start="2">&lt;li>A primeira mudança será configurar o &lt;code>deamon&lt;/code> de persistência da NVIDIA. Primeiro vamos verificar o status e caso não esteja ativo, vamos ativar:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>systemctl status nvidia-persistencedsystemctl enable nvidia-persistenced&lt;/code>&lt;/pre>&lt;p>Algumas distros Linux possuem uma regra do udev que coloca a memória hot-plug em estado online assim que é detectada fisicamente, impedindo que o software da NVIDIA configure a memória da GPU com os parâmetros corretos no Power9.&lt;/p>&lt;ol start="3">&lt;li>Para desativar esta regra, vamos executar os comandos:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo cp /lib/udev/rules.d/40-redhat.rules /etc/udev/rules.d/sudo sed -i &amp;#39;s/SUBSYSTEM!=&amp;#34;memory&amp;#34;,.*GOTO=&amp;#34;memory_hotplug_end&amp;#34;/SUBSYSTEM==&amp;#34;*&amp;#34;, GOTO=&amp;#34;memory_hotplug_end&amp;#34;/&amp;#39; /etc/udev/rules.d/40-redhat.rules&lt;/code>&lt;/pre>&lt;h4 id="checagem-de-instalação">Checagem de instalação&lt;/h4>&lt;p>Após realizar todos esses procedimentos, vamos reiniciar a máquina e checar as instalações:&lt;/p>&lt;ol>&lt;li>Reiniciando a máquina:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo reboot&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Checagem de driver NVIDIA:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>nvidia-smi&lt;/code>&lt;/pre>&lt;p>A saída do comando acima deve mostrar informações do compilador CUDA: versão e data de instalação. Além de mostrar os dispositivos (GPUs) disponíveis com nome, memória, temperatura entre outras informações.&lt;/p>&lt;p>Para realizar a última checagem, vamos baixar o repositório &lt;code>cuda-samples&lt;/code> e executar o teste de dispositivos.&lt;/p>&lt;ol start="3">&lt;li>Baixando o repositório e acessando a versão do &lt;code>cuda-samples&lt;/code> referente ao CUDA instalado:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>git clone https://github.com/NVIDIA/cuda-samples.git cd cuda-samples/Samples/1_Utilities/deviceQuerygit checkout v12.2 &lt;/code>&lt;/pre>&lt;ol start="4">&lt;li>Para buildar e executar os testes:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>make./deviceQuery&lt;/code>&lt;/pre>&lt;p>Após executar este teste, espera-se que na última linha contenha: &lt;code>Result = PASS&lt;/code>. Com isso, a Power9 está configurada, com driver NVIDIA e CUDA funcionando corretamente.&lt;/p>&lt;h2 id="configurando-cudnn">Configurando CUDNN&lt;/h2>&lt;ol>&lt;li>Inicialmente, precisamos baixar e instalar o &lt;code>.rpm&lt;/code> específico para &lt;code>ppc64le&lt;/code>.&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>wget https://developer.download.nvidia.com/compute/cudnn/9.0.0/local_installers/cudnn-local-repo-rhel8-9.0.0-1.0-1.ppc64le.rpmsudo rpm -i cudnn-local-repo-rhel8-9.0.0-1.0-1.ppc64le.rpmsudo dnf clean allsudo dnf -y install cudnn&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Após a instalação, precisamos configurar as variáveis de ambiente &lt;code>CUDNN_LIBRARY&lt;/code> e &lt;code>CUDNN_INCLUDE_DIR&lt;/code>: (De uma forma mais direta do que fizemos anteriormente)&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>echo &amp;#39;export CUDNN_LIBRARY=/usr/lib64&amp;#39; &amp;gt;&amp;gt; ~/.bashrc echo &amp;#39;export CUDNN_LIBRARY=/usr/lib64&amp;#39; &amp;gt;&amp;gt; ~/.bashrc &lt;/code>&lt;/pre>&lt;p>Após isso, o processo de instalação do CUDNN está finalizado.&lt;/p>&lt;p>Esta é a primeira parte do nosso tutorial. Uma vez que todas as etapas mostradas neste post foram finalizadas, o servidor está pronto para ter o gerenciador de pacotes &lt;code>conda&lt;/code> e a biblioteca &lt;code>pytorch&lt;/code> instaladas, você pode acessar a segunda parte deste tutorial neste &lt;a href="https://llm-pt-ibm.github.io/posts/tutorial_power9_pt2_en/">&lt;span class="link-personalizado">link&lt;/span>&lt;/a>.&lt;/p></description></item><item><title>Avaliando LLMs de Pequeno Porte (até 8B) em Benchmarks PT-BR</title><link>https://llm-pt-ibm.github.io/posts/experimentos_benchmarks_pt_br/</link><pubDate>Mon, 02 Jun 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/experimentos_benchmarks_pt_br/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Este é o primeiro de dois posts desta série, que tem como objetivo apresentar um resumo da investigação que conduzimos utilizando o &lt;em>framework&lt;/em> de avaliação &lt;a href="https://github.com/stanford-crfm/helm" rel="external">&lt;span class="link-personalizado">HELM&lt;/span>&lt;/a> &lt;em>(Holistic Evaluation of Language Models)&lt;/em> para avaliar os modelos da família &lt;a href="https://huggingface.co/ibm-granite" rel="external">&lt;span class="link-personalizado">Granite&lt;/span>&lt;/a>, o modelo &lt;a href="https://huggingface.co/meta-llama/Llama-3.1-8B" rel="external">&lt;span class="link-personalizado">Llama-3.1-8B&lt;/span>&lt;/a> e o modelo &lt;a href="https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Llama-8B" rel="external">&lt;span class="link-personalizado">DeepSeek-R1-Distill-Llama-3.1-8B&lt;/span>&lt;/a>. As avaliações contemplam tanto &lt;em>benchmarks&lt;/em> em português quanto tarefas voltadas à geração de código. Nesta primeira parte, o foco é avaliar o desempenho dos modelos no contexto do português brasileiro (PT-BR) para as tarefas de &lt;strong>análise de sentimentos&lt;/strong> e &lt;strong>MQA&lt;/strong> &lt;em>(Multiple-Choice Question Answering)&lt;/em>. Depois, na segunda parte, que será publicada em breve, abordará os resultados das avaliações em tarefas de geração de código.&lt;/p>&lt;p>O uso de conjuntos de dados em inglês para a avaliação de modelos de linguagem é uma prática comum. No entanto, para verificar a eficácia desses modelos em diferentes idiomas e contextos culturais, é relevante testá-los em &lt;em>benchmarks&lt;/em> de outras línguas. No caso do PT-BR, que costuma representar uma parcela menor dos dados utilizados no treinamento de modelos multilíngues, compreender o comportamento desses modelos é um passo importante para avaliar sua adequação a tarefas e contextos específicos dessa língua. Neste sentido, este post busca contribuir para esse entendimento, destacando avanços e desafios ainda presentes no desempenho dessas LLMs em tarefas no contexto do PT-BR.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;div style="text-align: justify;">&lt;ul>&lt;li>Avaliamos os modelos: Granite, Llama-3.1-8B e DeepSeek-R1-Distill-Llama-3.1-8B nos &lt;em>benchmarks&lt;/em> ENEM Challenge, TweetSent-Br e IMDB.&lt;/li>&lt;li>Nosso método envolveu uma experimentação apoiada pelo &lt;em>framework&lt;/em> HELM, que apresentamos em detalhes neste documento.&lt;/li>&lt;li>Os resultados revelam que os modelos classificam com precisão os sentimentos em críticas de filmes em PT-BR.&lt;/li>&lt;/ul>&lt;/div>&lt;h2 id="método">Método&lt;/h2>&lt;h3 id="ambiente-de-execução-e-ferramenta-utilizada">Ambiente de Execução e Ferramenta Utilizada&lt;/h3>&lt;p>O HELM foi a ferramenta utilizada para conduzir as avaliações. Trata-se de um &lt;em>framework&lt;/em> de avaliação de LLMs, desenvolvido por pesquisadores da Universidade de Stanford, que contempla uma variedade de &lt;em>benchmarks&lt;/em>, como análise de sentimentos, geração de código, questões de múltipla escolha, entre outros. Com base nesses &lt;em>benchmarks&lt;/em>, utilizamos os modelos Granite (até 8B), Llama-3.1-8B e DeepSeek-R1-Distill-Llama-3.1-8B para medir e comparar seus desempenhos.&lt;/p>&lt;p>Para a execução dos experimentos, utilizamos o Google Colab como ambiente, que conta com uma GPU A100. Neste ambiente, foi possível clonar o repositório do HELM e executar modelos com até 8 bilhões de parâmetros. Todo o processo de configuração e testes foi realizado nessa plataforma, garantindo praticidade e acesso aos recursos computacionais necessários.&lt;/p>&lt;p>Em uma postagem futura, iremos detalhar as estratégias e ferramentas de avaliação de LLMs, com um foco mais aprofundado no funcionamento e nas capacidades do HELM.&lt;/p>&lt;h3 id="benchmarks-e-modelos">&lt;em>Benchmarks&lt;/em> e Modelos&lt;/h3>&lt;p>Para realizar os testes em cenários voltados ao português brasileiro, foi necessário estender o HELM com a inserção de novos &lt;em>benchmarks&lt;/em>, uma vez que, até então, a ferramenta não apresentava suporte para esse idioma. Essa iniciativa representou uma contribuição direta ao HELM, com a adição de três &lt;em>benchmarks&lt;/em>:&lt;/p>&lt;ul>&lt;li>&lt;p>&lt;a href="https://huggingface.co/datasets/eduagarcia/enem_challenge" rel="external">&lt;span class="link-personalizado">&lt;strong>ENEM Challenge&lt;/strong>&lt;/span>&lt;/a>: construído a partir de questões do Exame Nacional do Ensino Médio (ENEM), com o objetivo de avaliar a capacidade dos LLMs em resolver tarefas de MQA em diversas áreas do conhecimento, incluindo Ciências Humanas, Ciências da Natureza, Linguagens e Códigos e Matemática.&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;a href="https://huggingface.co/datasets/eduagarcia/tweetsentbr_fewshot" rel="external">&lt;span class="link-personalizado">&lt;strong>TweetSent-Br&lt;/strong>&lt;/span>&lt;/a>: composto por &lt;em>tweets&lt;/em>, voltado especificamente para tarefas de análise de sentimentos. O dataset é organizado em três classes principais de avaliação: positivo (&lt;em>tweets&lt;/em> que expressam uma reação ou avaliação positiva em relação ao tópico principal da postagem), negativo (&lt;em>tweets&lt;/em> que expressam uma reação ou avaliação negativa sobre o tema central) e neutro (&lt;em>tweets&lt;/em> que não se enquadram nas categorias anteriores).&lt;/p>&lt;/li>&lt;li>&lt;p>&lt;a href="https://huggingface.co/datasets/maritaca-ai/imdb_pt" rel="external">&lt;span class="link-personalizado">&lt;strong>IMDB&lt;/strong>&lt;/span>&lt;/a>: composto por críticas de filmes escritas em português brasileiro, esse &lt;em>benchmark&lt;/em> também se concentra em tarefas de classificação de sentimentos, mas utiliza textos originados de resenhas mais completas, ao contrário do TweetSent-Br, que usa publicações breves.&lt;/p>&lt;/li>&lt;/ul>&lt;p>Em relação aos modelos, a seleção foi guiada pela compatibilidade com a infraestrutura de execução disponível e com base na relevância de citações e performance. Estes incluem os modelos da família Granite, desenvolvidos pela IBM; os modelos Llama, da Meta; e o DeepSeek-R1-Distill-Llama-8B, uma versão compacta e otimizada derivada do Llama 3.1. Essa escolha permitiu uma comparação justa e viável entre os modelos.&lt;/p>&lt;h2 id="resultados">Resultados&lt;/h2>&lt;p>A seguir, apresentamos os resultados obtidos, acompanhados de gráficos desenvolvidos pela equipe, com o objetivo de facilitar a visualização e compreensão do desempenho dos modelos nas tarefas avaliadas.&lt;/p>&lt;ul>&lt;li>&lt;strong>ENEM Challenge&lt;/strong>:&lt;/li>&lt;/ul>&lt;!--&lt;div style="text-align: center;"> &lt;img src="https://llm-pt-ibm.github.io/images/experimentos_benchmarks_pt_br_image001.png" style="max-width: 90%;">&lt;/div> -->&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/experimentos_benchmarks_pt_br_image001.png" alt="Gráfico dos resultados no ENEM Challenge"/>&lt;figcaption> &lt;p>Gráfico dos resultados no ENEM Challenge&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>Os resultados indicam que os modelos apresentaram desempenhos semelhantes, com uma leve vantagem para o Llama. Os modelos alcançaram uma média de acerto de 62,53%, esse percentual sugere que, embora os modelos demonstrem algum nível de compreensão das questões, ainda não possuem aptidão suficiente para responder de forma satisfatória às provas do ENEM, ou seja, para selecionar a alternativa correta. Há, portanto, um espaço para melhorias, especialmente no que diz respeito à capacidade de raciocínio e interpretação em língua portuguesa.&lt;/p>&lt;ul>&lt;li>&lt;strong>TweetSent-Br&lt;/strong>:&lt;/li>&lt;/ul>&lt;!--&lt;div style="text-align: center;"> &lt;img src="https://llm-pt-ibm.github.io/images/experimentos_benchmarks_pt_br_image002.png" style="max-width: 90%;">&lt;/div> -->&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/experimentos_benchmarks_pt_br_image002.png" alt="Gráfico dos resultados no TweetSent-Br"/>&lt;figcaption> &lt;p>Gráfico dos resultados no TweetSent-Br&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>Nesse &lt;em>benchmark&lt;/em>, assim como observado no ENEM Challenge, os resultados também foram semelhantes entre os modelos. Isso reforça a percepção de que ainda existem lacunas no desempenho dos modelos em tarefas relacionadas à classificação de sentimentos em português. Classificar uma mensagem como positiva, negativa ou neutra ainda representa um desafio para esses modelos, especialmente diante das nuances e ambiguidades da linguagem.&lt;/p>&lt;ul>&lt;li>&lt;strong>IMDB&lt;/strong>:&lt;/li>&lt;/ul>&lt;!--&lt;div style="text-align: center;"> &lt;img src="https://llm-pt-ibm.github.io/images/experimentos_benchmarks_pt_br_image003.png" style="max-width: 90%;">&lt;/div>-->&lt;figure>&lt;img src="https://llm-pt-ibm.github.io/images/experimentos_benchmarks_pt_br_image003.png" alt="Gráfico dos resultados no IMDB"/>&lt;figcaption> &lt;p>Gráfico dos resultados no IMDB&lt;/p> &lt;/figcaption>&lt;/figure>&lt;p>No IMDB os resultados foram bastante positivos, os modelos apresentaram taxas de acerto superiores a 90%, demonstrando boa performance na tarefa de classificação de sentimentos. O destaque foi o modelo Granite com 8B de parâmetros, que teve uma leve superioridade em relação aos demais. Esses resultados indicam que os modelos conseguem categorizar com facilidade as críticas de filmes em português, mostrando maior domínio nesse tipo de tarefa.&lt;/p>&lt;h2 id="conclusão">Conclusão&lt;/h2>&lt;p>Com este estudo, foi possível obter uma visão mais clara sobre o desempenho dos modelos de linguagem em PT-BR, por meio da avaliação em três &lt;em>benchmarks&lt;/em> distintos. Os resultados indicam que os modelos analisados possuem desempenho razoável ao selecionar uma alternativa para áreas do conhecimento do ENEM, e evidenciam que ainda há espaço para melhorias. Por outro lado, em tarefas de análise de sentimentos no &lt;em>benchmark&lt;/em> IMDB, os modelos de pequeno porte demonstraram boa capacidade de classificação.&lt;/p>&lt;p>A equipe planeja, em estudos futuros, conduzir experimentos com modelos de grande porte, a fim de possibilitar comparações mais amplas de desempenho e eficiência. Isso permitirá uma análise detalhada dos erros cometidos por cada modelo, contribuindo para uma compreensão mais aprofundada de seus pontos fortes e limitações.&lt;/p></description></item><item><title>Realizando Inferências em CPU na Power10</title><link>https://llm-pt-ibm.github.io/posts/power10/</link><pubDate>Sun, 06 Apr 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/power10/</guid><description>&lt;h2 id="contexto">Contexto&lt;/h2>&lt;p>Neste post iremos apresentar a nossa experiência em executar o modelo Granite-20b-Code-Instruct em uma máquina Power10, apresentando os desafios e demais configurações necessárias para realizar inferências utilizando o Llama.cpp, uma das bibliotecas opensource mais populares neste domínio.&lt;/p>&lt;h2 id="tldr">TL;DR&lt;/h2>&lt;ul>&lt;li>Este post apresenta detalhes sobre como configurar e realizar inferências utilizando a infraestrutura da IBM Power 10;&lt;/li>&lt;li>Nosso maior desafio foi a configuração do Llama cpp, que demandou ajustes como a instalação do Ninja-builder, realização da compilação do OpenBLAS e atualização do compilador C.&lt;/li>&lt;/ul>&lt;h2 id="infraestrutura">Infraestrutura&lt;/h2>&lt;p>As inferências foram realizadas em uma máquina com arquitetura IBM POWER10, equipada com 750 GB de memória RAM e executando o sistema operacional Red Hat Enterprise Linux 8.10. O acesso ao ambiente é realizado por meio de uma VM, sendo necessário o uso de uma VPN para estabelecer uma comunicação segura e controlada com o sistema, possibilitando a execução das atividades de forma remota e eficiente.&lt;/p>&lt;h2 id="setup-inicial">Setup Inicial&lt;/h2>&lt;p>A biblioteca que nos permite executar LLMs utilizando os recursos computacionais da CPU é o Llama.cpp. Para a sua configuração, foi necessário resolver duas dependências externas: o Ninja-builder e o OpenBLAS. O NinjaBuilder é responsável por otimizar o processo de compilação, enquanto o OpenBLAS é uma biblioteca responsável pelos cálculos matriciais de alto desempenho.&lt;/p>&lt;p>Durante o processo de build do OpenBLAS, identificamos discrepâncias nos testes internos de validação dos cálculos matriciais, indicando um problema de compatibilidade com o compilador C disponível, que estava em uma versão mais antiga, a 8.5.0. A solução, portanto, &lt;strong>foi a atualização do compilador para uma versão mais recente, a 13.2&lt;/strong>, garantindo melhor compatibilidade com a arquitetura Power10 e validando a precisão das operações numéricas necessárias para o funcionamento do Llama.cpp. A seguir, apresentamos o passo a passo realizado para viabilizar a compilação das bibliotecas necessárias, bem como a atualização do compilador C.&lt;/p>&lt;ol>&lt;li>Criando o ambiente de compilação para o builder&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>sudo dnf update -y &amp;amp;&amp;amp; dnf -y groupinstall &amp;#39;Development Tools&amp;#39; &amp;amp;&amp;amp; dnf install -y \ cmake git ninja-build-debugsource.ppc64le \ &amp;amp;&amp;amp; dnf clean all&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Atualizando compilador C e definindo variáveis de ambiente&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>scl enable gcc-toolset-13 bashexport CC=/usr/bin/gcc-13export CXX=/usr/bin/g++-13&lt;/code>&lt;/pre>&lt;ol start="3">&lt;li>Baixando e compilando o OpenBLAS&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>git clone --recursive https://github.com/DanielCasali/OpenBLAS.git &amp;amp;&amp;amp; cd OpenBLAS &amp;amp;&amp;amp; \ make -j$(nproc --all) TARGET=POWER10 DYNAMIC_ARCH=1 &amp;amp;&amp;amp; \ make PREFIX=/opt/OpenBLAS install &amp;amp;&amp;amp; \ cd /&lt;/code>&lt;/pre>&lt;ol start="4">&lt;li>Baixando e compilando o Llama.cpp usando a biblioteca OpenBLAS que acabamos de baixar&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code> git clone https://github.com/DanielCasali/llama.cpp.git &amp;amp;&amp;amp; cd llama.cpp &amp;amp;&amp;amp; sed -i &amp;#34;s/powerpc64le/native -mvsx -mtune=native -D__POWER10_VECTOR__/g&amp;#34; ggml/src/CMakeLists.txt &amp;amp;&amp;amp; \ mkdir build; \ cd build; \ cmake -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS -DBLAS_INCLUDE_DIRS=/opt/OpenBLAS/include -G Ninja ..; \ cmake --build . --config Release&lt;/code>&lt;/pre>&lt;p>Com todos esses passos realizados com sucesso, o ambiente foi devidamente configurado e otimizado para a execução local do Llama.cpp. Agora, somos capazes de iniciar um servidor para realizar inferências com LLM&amp;rsquo;s de forma eficiente, utilizando exclusivamente os recursos da CPU.&lt;/p>&lt;h2 id="realizando-inferência">Realizando Inferência&lt;/h2>&lt;p>Nós escolhemos o modelo Granite-20b-code-instruct no formato .GGUF, que é desenvolvido especificamente para otimizar o desempenho de modelos de linguagem em ambientes que utilizam apenas CPU. Esses modelos são quantizados, ou seja, a precisão dos cálculos feitos por eles são reduzidas, e, por conseguinte, o tamanho e consumo de memória também são menores, tornando-os ideais para a execução eficiente com Llama.cpp. Essa abordagem viabiliza inferências locais com alto desempenho, mesmo em arquiteturas baseadas exclusivamente em processadores, como é o caso da POWER10.O download do modelo foi feito diretamente do Hugging Face. A seguir, mostraremos o passo a passo para realizar o download:&lt;/p>&lt;ol>&lt;li>Criar um diretório para o modelo no Llama.cpp:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>mkdir -p /root/llama.cpp/models/granite-20b-code-instruct-8k-GGUF&lt;/code>&lt;/pre>&lt;ol start="2">&lt;li>Acessar o diretório no Llama.cpp:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>cd /root/llama.cpp/models/granite-20b-code-instruct-8k-GGUF&lt;/code>&lt;/pre>&lt;ol start="3">&lt;li>Baixar o modelo via Hugging Face:&lt;/li>&lt;/ol>&lt;pre tabindex="0">&lt;code>wget https://huggingface.co/ibm-granite/granite-20b-code-instruct-8k-GGUF/resolve/main/granite-20b-code-instruct.Q4_K_M.gguf&lt;/code>&lt;/pre>&lt;p>O último passo pode ser mais demorado a depender da quantidade de parâmetros do modelo. Todavia, após concluir os passos acima, podemos subir um servidor Llama.cpp para que seja possível realizarmos inferências, por padrão, o servidor é exposto na porta 8080 da Power10, mas isso é completamente customizável. O código a seguir ilustra como configurar e executar o servidor Llama:&lt;/p>&lt;pre tabindex="0">&lt;code>/root/llama.cpp/build/bin/llama-server --host 0.0.0.0 --model /root/llama.cpp/models/granite-20b-code-instruct-8k-GGUF/granite-20b-code-instruct.Q4_K_M.gguf&lt;/code>&lt;/pre>&lt;p>Com o servidor do Llama.cpp executando na porta 8080, agora somos capazes de realizar inferências via requisições HTTP. Neste exemplo, para fins de simplicidade, utilizamos o curl para requisições:&lt;/p>&lt;pre tabindex="0">&lt;code>curl -X POST http://localhost:8080/completion \ -H &amp;#34;Content-Type: application/json&amp;#34; \ -d &amp;#39;{ &amp;#34;prompt&amp;#34;: &amp;#34;Make a hello world program in Java. Your answer should be in Java code only.&amp;#34;, &amp;#34;max_tokens&amp;#34;: 100 }&amp;#39;&lt;/code>&lt;/pre>&lt;p>A seguir, um exemplo de como a resposta é retornada:&lt;/p>&lt;pre tabindex="0">&lt;code>{ &amp;#34;content&amp;#34;: &amp;#34;public class HelloWorld { public static void main(String[] args) { System.out.println(&amp;#34;Hello, World!&amp;#34;); }}&lt;/code>&lt;/pre>&lt;p>Com isso, agora somos capazes de realizar inferências em CPU. Nossos próximos passos visa realizar essas inferências utilizando o &lt;em>Framework&lt;/em> de avaliação HELM (&lt;em>Holistic Evaluation of Language Models&lt;/em>) como mediador.&lt;/p></description></item><item><title>Introdução</title><link>https://llm-pt-ibm.github.io/posts/introducao/</link><pubDate>Wed, 12 Mar 2025 00:00:00 +0000</pubDate><guid>https://llm-pt-ibm.github.io/posts/introducao/</guid><description>&lt;p>Bem-vindo ao blog da parceria entre a &lt;strong>Universidade Federal de Campina Grande (UFCG)&lt;/strong> e a &lt;strong>IBM&lt;/strong>!&lt;/p>&lt;p>Este espaço reúne artigos, tutoriais e resultados de pesquisa produzidos pela nossa equipe ao longo de diferentes projetos. Cada projeto aborda uma área de investigação distinta:&lt;/p>&lt;ul>&lt;li>&lt;strong>&lt;a href="https://llm-pt-ibm.github.io/projects/llm-eval/">LLM Evaluation&lt;/a>&lt;/strong> — avaliação de modelos de linguagem de grande porte, com foco em benchmarks para o português brasileiro.&lt;/li>&lt;li>&lt;strong>&lt;a href="https://llm-pt-ibm.github.io/projects/agents-ai">AgentOps&lt;/a>&lt;/strong> — criação de agentes de inteligência artificial capazes de executar múltiplas tarefas de forma autônoma.&lt;/li>&lt;li>&lt;strong>&lt;a href="https://llm-pt-ibm.github.io/projects/judo-ai/">Judo-AI&lt;/a>&lt;/strong> — uso de modelos de IA para análise de partidas e sessões de treinamento de judô, usando técnicas de visão computacional e deep learning para detecção de movimentos e reconhecimento de ações.&lt;/li>&lt;li>&lt;strong>&lt;a href="https://llm-pt-ibm.github.io/projects/5g/">5G&lt;/a>&lt;/strong> — interação de técnicas de IA em ambientes de rede 5G, com controle inteligente, otimização e mecanismos de gestão de rede.&lt;/li>&lt;li>&lt;strong>&lt;a href="https://llm-pt-ibm.github.io/projects/multiarq/">MultiArq&lt;/a>&lt;/strong> — provisão de ferramentas comuns para novas arquiteturas (ppc64le), buscando e adaptando ferramentas específicas e criando documentações técnicas acerca da arquitetura.&lt;/li>&lt;/ul>&lt;p>Explore os posts e acompanhe as novidades!&lt;/p></description></item></channel></rss>