Agentes que controlam a própria inferência — Du'an Lightfoot e Khaja Omer, Akamai Technologies
Autoria: AI Engineer · Assistir no YouTube
Vídeo de autoria do canal indicado, não da IANIA; todos os direitos pertencem ao criador. Transcrição, resumo e tradução gerados automaticamente; o conteúdo no idioma original é preservado na versão em idioma original.
Idioma original: inglês
Vídeo original: Agents That Own Their Inference — Du’an Lightfoot & Khaja Omer, Akamai Technologies · Canal: AI Engineer · 1:50:07 · Assistir no YouTube
Tópicos: Agentes de IA, Inferência e otimização de modelos, Infraestrutura e hardware de IA, Modelos locais e open source
Du’an Lightfoot e Khaja Omer apresentam estratégias para criar agentes de IA em produção usando GPUs dedicadas e controlando a própria inferência. O workshop aborda infraestrutura, uso de memória, prefill e decode, KV cache e diferenças entre modelos densos e mixture of experts. Os palestrantes demonstram técnicas de otimização como quantização, speculative decoding e ajuste de configurações do vLLM, destacando a importância de medir latência, throughput e qualidade com evals. A sessão termina com recomendações para encontrar limites de capacidade, ajustar a concorrência e escalar a infraestrutura conforme a carga.
Pontos-chave
Seção intitulada “Pontos-chave”- Controlar a própria inferência significa operar ou alugar GPUs dedicadas e manter maior controle sobre hardware, dados e modelos.
- A escolha entre inferência própria e provedores externos depende do volume e da regularidade do tráfego, dos requisitos de privacidade e da capacidade técnica da equipe.
- O vLLM oferece continuous batching e gerenciamento de KV cache, além de uma API compatível com OpenAI.
- O tamanho dos pesos do modelo e do KV cache determina quanta memória sobra para o contexto e para processar solicitações simultâneas.
- A latência do primeiro token está ligada ao prefill; a geração dos tokens seguintes corresponde ao decode.
- Quantizar de BF16 para FP8 pode reduzir o uso de memória e melhorar o desempenho, mas é necessário verificar a qualidade com evals próprios.
- Speculative decoding pode acelerar a geração, mas depende da compatibilidade entre o modelo principal e o draft model, da taxa de aceitação e da configuração.
- Ajustar a concorrência, a utilização de memória da GPU e outros parâmetros do vLLM exige testes de carga e mudanças graduais.
- Quando o throughput deixa de crescer e a latência aumenta muito, pode-se ter atingido o limite do hardware ou da configuração.
- Para tráfego variável, autoscaling e roteamento podem ajudar a ajustar a capacidade da infraestrutura à demanda.
Capítulos
Seção intitulada “Capítulos”| Início | Capítulo | Resumo |
|---|---|---|
| 00:12 | Por que controlar a própria inferência | Os palestrantes apresentam os desafios de custo, capacidade e latência que motivam operar agentes em GPUs dedicadas. |
| 08:48 | vLLM e métricas de inferência | A sessão explica continuous batching, gerenciamento do KV cache e métricas como throughput e tempo até o primeiro token. |
| 17:30 | Primeiro endpoint e primeiro agente | Os participantes testam o endpoint, medem geração de tokens e criam a base de um agente sem ferramentas. |
| 28:32 | Pesos do modelo e orçamento de memória | A apresentação relaciona parâmetros, precisão numérica e KV cache para estimar o contexto e a concorrência que cabem na GPU. |
| 36:40 | Prefill, decode e KV cache | Os palestrantes detalham as fases de inferência, o caching de prefixos e o efeito do tamanho do prompt na latência. |
| 48:19 | Técnicas de otimização e quantização | Khaja Omer introduz métodos para ajustar modelos em Kubernetes e apresenta diferentes formatos de quantização. |
| 53:40 | Testes de carga e evals para FP8 | A demonstração compara desempenho e latência antes e depois da quantização, ressaltando a necessidade de evals próprios. |
| 1:04:58 | Speculative decoding: funcionamento e configuração | O palestrante explica como um draft model propõe tokens e como ajustar a quantidade de tokens especulados. |
| 1:15:20 | Quando speculative decoding reduz o desempenho | O teste mostra uma queda de desempenho causada por baixa taxa de aceitação e incompatibilidade entre os modelos. |
| 1:26:50 | Ajuste de concorrência e limites de desempenho | A conversa aborda como encontrar o ponto de equilíbrio entre throughput e latência e quais parâmetros do vLLM ajustar. |
| 1:35:35 | Métricas de carga e ajustes de configuração | Os palestrantes retomam o benchmark e discutem utilização de memória, número máximo de sequências e tamanho dos batches. |
| 1:40:54 | Recursos do workshop e dúvidas sobre runtimes | A equipe compartilha slides e código e comenta quando usar runtimes locais ou serviços voltados a maior concorrência. |
| 1:44:01 | Aumentar sequências e acomodar picos | A demonstração aumenta o limite de sequências e discute autoscaling para responder a tráfego variável. |
| 1:49:28 | Encerramento e materiais | Os palestrantes encerram a sessão e indicam onde acessar o repositório, os slides e outros recursos. |
Citações
Seção intitulada “Citações”Tudo isso exige a geração de tokens e, dependendo da aplicação, pode gerar desafios de latência. — 02:21
Se o tráfego é baixo e irregular, talvez não seja eficiente ter suas próprias GPUs. — 04:33
É importante ter visibilidade dos seus agentes para entender como otimizá-los. — 24:13
É preciso garantir que o draft model seja compatível com o modelo que você quer usar. — 1:18:06
Mude uma configuração por vez. Depois, rode os benchmarks e veja o desempenho. — 1:38:11
Conceitos e entidades
Seção intitulada “Conceitos e entidades”- Du’an Lightfoot (pessoa): Apresenta o workshop sobre agentes de IA e inferência em GPUs dedicadas.
- Khaja Omer (pessoa): Engenheiro de software que aborda Kubernetes, otimização de inferência e implantação de modelos.
- Akamai Technologies (empresa): Empresa associada aos palestrantes e à infraestrutura de Kubernetes e GPUs apresentada.
- vLLM (ferramenta): Inference engine usado no workshop para servir modelos e otimizar batching e uso do KV cache.
- Kubernetes (conceito): Plataforma de orquestração usada para disponibilizar endpoints de inferência e agentes em um cluster.
- KV cache (conceito): Cache que armazena informações intermediárias da atenção e ocupa memória da GPU durante o processamento do contexto.
- continuous batching (conceito): Técnica que permite incluir e retirar solicitações de um batch continuamente para melhorar o processamento simultâneo.
- prefill (conceito): Fase em que o modelo processa o prompt de entrada antes de começar a gerar a resposta.
- decode (conceito): Fase de geração sequencial dos tokens que vêm depois do primeiro token da resposta.
- BF16 (conceito): Formato numérico de precisão usado para representar pesos de modelos, com impacto no consumo de memória.
- FP8 (conceito): Formato de menor precisão que pode reduzir o tamanho dos pesos e acelerar a inferência, sujeito a avaliação.
- speculative decoding (conceito): Técnica que usa um draft model para propor tokens que o modelo principal verifica.
- LKE (ferramenta): Serviço de Kubernetes mencionado para orquestrar nós e implantações com GPUs.
- Prometheus (ferramenta): Ferramenta de monitoramento usada para coletar métricas do serviço de inferência.
- Grafana (ferramenta): Ferramenta mencionada para visualizar métricas e acompanhar o comportamento da inferência.
- Langfuse (ferramenta): Ferramenta open source de observabilidade para inspecionar traces, etapas e latência de agentes.
- KServe (ferramenta): Ferramenta citada para roteamento, escalabilidade e autenticação de serviços de inferência.
- llama.cpp (ferramenta): Runtime de inferência mencionado para executar modelos locais e quantizados.
- Qwen 3 4B (modelo): Modelo de quatro bilhões de parâmetros usado no workshop para demonstrar inferência e otimização.
- RTX 4000 Ada (modelo): GPU dedicada usada no ambiente do workshop para servir modelos.
Tradução completa (pt-BR)
Seção intitulada “Tradução completa (pt-BR)”00:12 Mencionei antes que meu nome é Du’an Lightfoot. Sou defensor de desenvolvedores de IA na Akamai, e este é meu colega. >> Sou Khaja Omer. Também uso o nome R. Sou engenheiro de software sênior na Akamai. E vamos falar sobre agents que controlam a própria inference: como construir agents de IA em produção em GPUs dedicadas. Então, por que estamos aqui? As coisas estão mudando. Eu comecei a criar agents antes de existir tool calling. Foi em janeiro de 2023 que eu
00:44 criei meu primeiro agent. Eu usava um prompt cujo contexto tinha cerca de 8.000 tokens na época, analisava esse prompt, fazia uma chamada de ferramenta com Python e depois enviava a resposta de volta a um LLM, certo? Mas, enquanto fazia isso, percebi algo interessante: pode ficar muito caro, certo? Então comecei a usar modelos locais para descobrir como fazer isso. E aprendi outra coisa. Há outro
01:14 desafio relacionado a isso, porque, se eu usar um modelo menor, talvez ele não seja tão capaz e eu fique limitado pela computação; a memória daquela GPU talvez não dê conta do contexto maior. Então, temos as entradas e saídas e, depois, os vários turnos de uso das ferramentas. Como obter o máximo das GPUs, controlar os custos e alcançar a latência de que precisamos em produção ou nos nossos próprios casos de uso, certo? O motivo de estarmos aqui é falar sobre agents que costumam alugar sua inteligência e sobre como você pode retomar
01:48 esse controle e ser dono dela. Um agent é simplesmente um loop. Você invoca um LLM, que tem acesso a ferramentas e a um ambiente, toma uma decisão — uma decisão de raciocínio sobre quais ações executar — depois que você o invoca ou fornece um prompt. Então, suas ferramentas executam essas ações, seja com seu código Python ou com outras linguagens de programação, e os resultados são enviados de volta a um modelo. O modelo avalia as ações e os resultados, atualiza o plano, executa ações adicionais ou, por fim,
02:21 alcança o objetivo, certo? Mas tudo isso exige a geração de tokens, certo? E, dependendo da sua aplicação, pode gerar desafios de latência. Então vamos falar sobre como gerenciar tudo isso em GPUs dedicadas. O que significa controlar sua inference? Primeiro, para controlar sua inference, você precisa ser dono da GPU ou alugá-la. Quando faz isso, tem acesso à GPU, ao hardware no qual a IA será executada e onde os modelos
02:57 ficarão, o que significa que você tem controle sobre onde ela será executada. Assim, os dados nunca saem do seu cluster, do seu data center ou do seu laptop, certo? Você passa a controlar essa inteligência e o que acontece com o modelo. E, se estiver na nuvem, também pode usar algo como endpoints privados de VPC ou manter tudo na VPC, para que nada saia dela. Certo? Sei que todos temos ambientes diferentes e maneiras diferentes de configurar nossa infraestrutura. Podemos falar sobre todas elas.
03:30 Agora, qual é a diferença? Quando você controla e quando aluga? Bem, primeiro: se seu uso é alto e constante, por quê? Sim. >> Sim. No fim da apresentação, vou disponibilizar um link para os slides e tudo o que mostramos, incluindo o código. Vocês podem baixar tudo e levar com vocês. Obrigado. Então, quando vale a pena controlar a GPU? Quando o uso é alto, certo? Se você tem uma carga de trabalho em execução constante, porque, se estiver pagando por uma GPU, estará alugando
04:03 uma GPU. O que isso significa? Que essa GPU deve estar sempre trabalhando. Caso contrário, pelo que você está pagando? Então, é algo em que você precisa pensar. Depois, há a questão dos dados: se você precisa mantê-los privados, se precisa ser dono dos dados, se se importa com sua propriedade intelectual ou se há motivos de governança e conformidade pelos quais não pode usar um provedor público de IA, essa é outra razão para controlar a GPU. E também precisamos
04:33 pensar no hardware. Se você pode pagar pela capacidade e tem capacidade disponível, por que não executar esses modelos para seus casos de uso, certo? Assim, você tem controle total. E quando vale a pena alugar? Se seu tráfego é baixo e irregular, e você só precisa de inteligência esporadicamente, talvez não seja eficiente ter suas próprias GPUs. Em seguida, vamos falar de inteligência. Os modelos mais capazes vão custar mais por causa dessas
05:03 GPUs. E, muitas vezes, esses provedores oferecem essa inteligência nas GPUs porque têm a infraestrutura necessária. Portanto, pode fazer mais sentido usar esses provedores para obter essa inteligência e aproveitar esses benefícios. O próximo ponto, que costuma ser um desafio, é que suas equipes talvez não tenham o conhecimento ou a experiência necessários para dar suporte a IA dedicada ou hospedada por conta própria. Agora, na agenda de hoje, vamos começar discutindo alguns fundamentos que vocês precisam entender, como a pilha de infraestrutura que vamos usar,
05:36 as unidades e o orçamento de memória. Vamos analisar prefill, decode e o cache KV, e ver como funcionam. Depois, vamos examinar modelos densos em comparação com mixture of experts, para que vocês entendam como isso funciona na GPU e por que escolheriam um ou outro. Em seguida, vamos discutir como otimizar sua inference. Depois de decidir que querem hospedar tudo por conta própria, como otimizar para aproveitar ao máximo nossas GPUs, o inference engine que
06:07 executamos e toda a nossa carga de trabalho. Por fim, vamos pegar esse agent e fazer o deploy no nosso próprio cluster dedicado. Dito isso, vou passar a palavra para você, Omer. Certo. Obrigado. Em seguida, vamos falar sobre o ambiente que cada um de vocês receberá para este workshop. Temos um cluster Kubernetes com mais de 200 nós com GPU. Cada um de vocês terá uma única GPU. Configuramos tudo
06:41 de modo que cada um tenha seu próprio namespace e, dentro dele, um Jupyter notebook em execução, além de um endpoint de inference de VLM com o qual vocês poderão experimentar. Também vamos fazer o deploy do agent lá. O interessante é que vocês vão otimizar o endpoint de VLM em execução no seu namespace depois dos quatro primeiros módulos. Acho que isso vai ser bem interessante.
07:13 Vamos analisar diferentes técnicas que usaremos para fazer isso. Vocês vão fazer o deploy desse endpoint de VLM repetidas vezes até otimizá-lo para aumentar o throughput, reduzir a latência e garantir que estejam cumprindo todos os SLAs. Outra coisa sobre a qual quero falar são as GPUs no LKE. Trabalho com Kubernetes na Akamai, então esse é meu campo de atuação. Se alguém tiver perguntas relacionadas a Kubernetes, pode perguntar a qualquer momento.
07:47 Mas quero falar sobre o que a Akamai oferece. Vamos usar GPUs RTX 4000 Ada. Também temos outras GPUs disponíveis, mas estas são GPUs dedicadas. Cada GPU tem 20 GB de VRAM e uma largura de banda de memória de 260 GB por segundo. Por isso, o decode será bem rápido. Temos alto desempenho em TFLOPS e uma grande quantidade de núcleos CUDA. Por isso, o prefill também será bem rápido. Atualmente, para o seu
08:18 workshop, vamos usar uma única GPU, mas isso não significa que, quando vocês fizerem o deploy por conta própria, não poderão escolher outros planos que oferecemos, nos quais é possível ter até quatro GPUs em um nó. Isso chega a 80 GB de VRAM em um único nó. Assim, vocês também poderão fazer o deploy de modelos de tamanho razoável. E tudo é orquestrado pelo LKE: a configuração do nó, o deploy dos drivers e toda a configuração. Dessa forma, vocês não precisam fazer nada manualmente. Tudo
08:48 É mais ou menos como um clique. Você clica em um botão, tudo é implantado e pronto. Sim, para mais informações, também temos um link aqui. E, no final, vocês definitivamente receberão todos esses slides. Assim, poderão acessar as páginas e, então, vou passar de volta para Du’an. >> Certo. Para o mecanismo de inference, vamos usar o vLLM. Alguns de vocês talvez já tenham ouvido falar do Llama, que é ótimo para uso local, mas o vLLM oferece algumas vantagens melhores para
09:21 produção. Uma delas é o continuous batching pronto para uso; outra é o paged attention. Ele também é compatível com a API da OpenAI. Então, se vocês estiverem usando qualquer SDK compatível com a OpenAI, poderão usá-lo com o vLLM. Ele também permite fazer ajustes bem interessantes ao configurar a inference para seus endpoints e aplicações. Mencionei o continuous batching. Para quem
09:54 não sabe o que é nem como funciona, isso acontece na etapa de prefill, certo? Os prompts chegam e, normalmente, com o batching estático, digamos que vocês tenham um ônibus escolar cheio de crianças. Para deixar novas crianças com batching estático, é preciso deixar cada uma delas em um lugar, uma por vez. Depois que todas forem deixadas, vocês voltam para buscar as demais e, então, começam o próximo lote. Mas, com o continuous batching, vocês podem deixar uma criança e pegar outra ao mesmo tempo. Isso é muito mais eficiente quando se trata
10:26 do cache KV que é gerado durante a etapa de prefill. Agora, quando se trata de paged attention: pensem no cache KV e no que está acontecendo de fato. Há um espaço de memória envolvido. O prompt chega, e o prompt mais longo ocupa espaço na memória. Com o paged attention, esse espaço de memória é alocado até mesmo para prompts menores, certo? Mas, com o paged attention, isso tudo é gerenciado pelo vLLM
11:00 e garante que vocês possam processar, gerar e agrupar continuamente essas solicitações à medida que chegam ao vLLM. Ele tem um scheduler que gerencia o batching, o que torna tudo muito eficiente. Há outros mecanismos de serving por aí, e vamos falar de alguns deles neste workshop. Dito isso, algumas métricas importantes são o throughput, certo? Para entender o desempenho da GPU, o tempo até o primeiro token, para entender
11:33 que vocês enviaram um prompt. Quanto tempo leva para receber o primeiro token? Depois, a utilização do cache KV. Vamos analisar essas métricas e mostrar como obter tudo isso do vLLM e, em seguida, do QEP. Essas são algumas das métricas que vocês verão ao longo deste workshop e que ajudarão a entender melhor o assunto. Dito isso, vamos acessar o ambiente. Se puderem, leiam este QR code e peguem seus laptops caso queiram acompanhar. Se não, podem acompanhar enquanto percorremos o workshop. Neste notebook Jupyter, temos
12:04 nove laboratórios diferentes que vamos abordar, e todos os recursos e dependências já estão carregados neste ambiente. Se quiserem ver o código e experimentar por conta própria em casa, deixei o repo público no accommoders. Vou disponibilizar este link, junto com a apresentação e tudo o que compartilhamos, em um único QR code para vocês baixarem. Se precisarem que eu crie um link curto, eu faço.
12:36 Certo, dito isso, vamos começar o primeiro módulo do workshop, se todos estiverem conectados. >> Sim, também foi meio lento para mim, por isso usei meu próprio encurtador de links, porque consegui fazer isso bem rápido com o Russ. Então, sim,
13:07 >> espero que, se vocês tiverem um hotspot, usem-no. Mas vamos tentar aproveitar ao máximo a experiência. Combinado? Ótimo. Certo. No primeiro módulo, vamos falar sobre a pilha de inference. Vamos nos conectar ao nosso endpoint do vLLM, entendê-lo e ver como ele gera tokens. Também vamos ver como criar nosso primeiro agent, algumas coisas que precisamos saber, algumas métricas e, depois, entender o modelo ao qual vamos nos conectar. Vamos usar o Quinn 3 4B, mas temos vários
13:42 modelos em um PVC que vocês podem carregar e descarregar para esse endpoint. Ao falar do vLLM, uma das coisas a saber é que, ao disponibilizar um endpoint, ele só tem um modelo, certo? Então, se quiserem disponibilizar dois modelos, vão precisar de outro endpoint do vLLM, certo? Isso significa que talvez precisem de um roteamento de modelos, com um gateway na frente para gerenciar isso. Ele oferece suporte à autenticação, mas não à autorização. Então, talvez
14:16 precisem de um gateway ao redor dele, certo? O agent gateway é uma opção; o KServe é outra. Mais alguma? >> Tem o LLMD. Há todo tipo de ferramenta open source que permite fazer isso. Mas a principal, a principal que usamos bastante, é o KServe. Ele é bem bom para fazer o escalonamento, o roteamento e a autenticação, certo? Outra coisa que ele não tem é limitação de taxa, certo? Se vocês estiverem processando solicitações, talvez queiram limitar a taxa. Então, de novo, vão querer encontrar um gateway para colocar
14:47 na frente dele, para gerenciar essas solicitações e também cuidar do roteamento. Mencionei que, em termos de runtime, há outros endpoints de serviço, ou outros runtimes de serving, que vocês podem usar para o servidor. O SGLang é um deles, o TensorRT é outro, e o llama.cpp, que vamos abordar mais adiante com um pouco mais de profundidade, para que vocês possam entendê-lo melhor. Neste ambiente, vocês estão conectados a um notebook Jupyter que
15:20 fica no namespace. Também terão o endpoint do servidor vLLM, que verão daqui a pouco. Tudo isso fica em seu próprio pod. Depois, haverá outro pod. Bem, outro pod que vocês podem iniciar para o agent. E também vamos ver isso. Então, vamos instalar nossas dependências. Vamos instalar nossas dependências. Eu já executei isso, então algumas coisas já estão carregadas no meu runtime. Imaginei que não sabemos como estará a internet, certo? Mas o bom é que, depois que vocês enviam uma solicitação, ela
15:52 acontece dentro do cluster. Então, quando enviamos nossa primeira solicitação para entender como estamos configurados no vLLM, vocês podem ver o modelo que temos e o nome do namespace dentro do cluster. A configuração do Kubernetes é apenas para o namespace de vocês. Assim, ninguém pode acessar o namespace de outra pessoa no ambiente. Não temos uma API key configurada, mas vocês podem definir uma com o vLLM.
16:26 A partir daqui, vamos usar o endpoint compatível com a API da OpenAI para nos conectar ao modelo vLLM QN 34B, com 4 bilhões de parâmetros. Acho que estamos usando FP8, o que significa que ele fica com 8 bilhões de parâmetros. São 8 bilhões de parâmetros? >> Não, 4 bilhões de parâmetros. >> 4 bilhões de parâmetros. >> Estamos usando BF16. >> Ah, BF, era isso. >> Precisão de 4 bits. >> Sim. Então, estamos usando BF16, precisão total. Portanto, multipliquem os bits — ou
16:59 bytes — ou os parâmetros por dois. Então, são 4 bilhões, o que significa 8 gigabytes na GPU. Agora, depois de invocá-lo, recebemos a resposta do modelo e podemos ver qual modelo a serviu. Tudo isso aconteceu dentro do nosso cluster. Foi bem rápido, certo? Ele fica dentro do nosso cluster. Então, esperamos que, com essa experiência, como não estamos acessando a API pública e já estamos conectados por HTTP, tudo aconteça dentro do próprio cluster. A resposta
17:30 deve voltar um pouco mais rápido. Agora, vamos rastrear, enviar um trace no final, para podermos entender como isso realmente se parece ao passar pelas fases de prefill, do cache de KB e de decode. Aqui temos nosso stream, que vamos configurar. Vamos analisar os chunks e fazer alguns cálculos. Vamos obter o tempo até o primeiro token para entender isso. Daqui a pouco, veremos como tudo isso é gerado. Então, se executarmos isto,
18:03 Executei esse de novo. Vamos descer até aqui e executar. Pode demorar um pouco para processar, mas devemos ver o tempo. Os primeiros tokens levaram 37 milissegundos, e o tempo por token de saída na fase de decode — ou seja, cada token depois do tempo até o primeiro token, certo? Esse é o intervalo entre tokens, certo? O intervalo que ocorre enquanto esses tokens são processados. Então, estamos calculando isso e obtendo cerca de 40 tokens por segundo, que provavelmente será nosso limite.
18:37 Mas, quando começamos a falar de throughput, isso muda um pouco, porque aqui temos apenas uma solicitação. Mas imagine se tivéssemos centenas de solicitações, ou 16 solicitações: o throughput seria muito maior, mas ainda haveria um limite de 40 tokens por segundo, certo? Ou ele poderia cair, mas ainda poderíamos obter mais throughput. E acredito que Omer vai se aprofundar nisso. Uma das coisas que quero mostrar é a questão: por que simplesmente não executar isso na CPU? Eu não quis usar a CPU neste ambiente
19:09 porque este pod, ou este contêiner do Jupyter notebook, tem apenas um gigabyte, certo? Então, tentar executar um modelo local nele vai simplesmente fazer tudo travar. Por isso, simulei como seria. Mas, se você tentar executar um modelo local na CPU, vai ser muito mais lento, certo? Ela não consegue fazer as multiplicações complexas dessas matrizes como uma GPU. Esse é o propósito de uma GPU. Ela faz todos esses cálculos em paralelo, o que a torna muito mais rápida, certo? Então, simulamos isso na CPU.
19:46 E, a partir daí, analisamos isso na GPU para ver como fica. Obtivemos 45 tokens por segundo. E uma das coisas que acho interessante é que trabalho bastante com modelos locais e com sua execução. Mas 45 ou 39 tokens por segundo não é tão ruim para uma aplicação, se você a estiver executando para um caso de uso específico. Certo? Se você tiver um
20:20 caso de uso específico e não se importar com a latência, não se importar com coisas como, por exemplo, se tiver um chatbot, você vai querer que o primeiro token chegue rápido. Mas, para uma aplicação padrão em que você simplesmente inicia um job em segundo plano, 39 tokens por segundo talvez não seja tão ruim, certo? Então, às vezes, uma taxa menor de tokens por segundo ou um tempo maior até o primeiro token talvez não sejam tão importantes, dependendo da aplicação e da latência que importa para você, certo? Talvez você se importe mais com a inteligência e com a conclusão do job do que com a rapidez com que ele acontece, especialmente se, como eu disse, for um processo em segundo plano.
20:53 Agora, vamos criar nosso primeiro agent. Para quem está aqui, quando falamos de agents, este não tem ferramentas. Na verdade, é apenas uma solicitação, mas serve como base para o agent. Estamos fornecendo um system prompt para que ele saiba qual é o seu papel quando o usarmos mais adiante no curso. Mas, por enquanto, estamos dando a ele um único prompt e atribuindo-lhe o papel de agent de arquitetura de soluções da Akamai
21:30 e você pode ver que ele conseguiu gerar a resposta. A resposta saiu bem rápido. Funciona. Mas a questão é: se estamos tentando fazer isso em escala ou criar um agent que faça mais do que apenas receber um prompt e gerar uma resposta, talvez ele precise fazer várias chamadas de ferramentas, certo? É aí que você começa a pensar em coisas como o cache de KB. Você começa a pensar em quanto contexto, porque
22:05 quando começamos a falar desse cache de KB, estamos falando, na verdade, de quanto contexto cabe na GPU, certo? Com continuous batching, o que acontece é que você envia um prompt ao modelo. Pode haver 100 usuários tentando enviar prompts ao mesmo tempo, certo? E todos terão tamanhos diferentes. Então, uma GPU menor consegue lidar com várias solicitações se você estiver usando algo como VLM. Agora, se estiver usando algo como Ollama, vai perceber que o processamento será limitado muito mais rapidamente, porque ele
22:35 não processa essas solicitações da mesma maneira. Mas o VLM lida muito melhor com isso por meio do scheduler. Então, aqui vamos configurar nosso agent, invocá-lo e analisar as etapas. O código que estamos usando fica dentro de common, e você pode ver todo o código personalizado que importamos. Aqui temos este foundation.py, que nos permite fazer algumas medições
23:10 com o Prometheus do VLM, certo? Podemos analisar essas métricas. Falando em métricas, você pode usar Prometheus e Grafana. Em casa, também sempre uso Grafana quando estou criando meus agents. Além de analisar as métricas, outra coisa que sempre faço — uma das primeiras coisas que implemento nos meus agents — é observabilidade. O Langfuse é algo que uso com frequência. Quantos de vocês já ouviram falar do Langfuse? Existem outras ferramentas, mas ele é open source. Você também pode executá-lo no seu cluster, ao lado dos seus agents, e então ter acesso
23:43 a isso. Assim, sua observabilidade é privada, certo? E você pode ver cada etapa, cada trace, cada span do seu agent, incluindo a quantidade de tokens e a latência, não apenas o tempo até o primeiro token, mas também o de cada chamada de ferramenta, certo? Se estiver tentando solucionar problemas ou fazer uma avaliação, poderá ver todas as etapas de latência nos spans. E também poderá ver, por exemplo: estou usando um modelo menor e ele está fazendo muito mais chamadas de ferramentas. Está demorando muito mais do que deveria. Por quê? Bem, é aí que
24:13 entram as avaliações, e Omer vai falar mais sobre isso. Mas é importante ter essa visibilidade dos seus agents para entender como otimizá-los quando você está usando um modelo menor. E isso pode ser algo tão simples quanto ajustar um prompt, remover ferramentas ou tornar o agent um pouco mais especializado. Então, vamos executar isso. Vamos analisar as etapas. Vamos ver o máximo de tokens
24:45 e devemos ver o tempo até o primeiro token. Assim, você pode ver o que acontece com o tempo até o primeiro token, em milissegundos, à medida que aumentamos os tokens. À medida que aumentamos o prompt, certo? Conforme os prompts ficam maiores, o tempo até o primeiro token aumenta, certo? Então, a questão é: o que você otimiza? A mediana ou o maior valor? Certo? O que levou mais tempo, em termos de latência. Bem, você vai otimizar o que leva mais tempo, em vez da mediana, certo? E, assim, poderá aumentar sua mediana fazendo isso.
25:20 Agora, aqui falamos sobre alugar versus possuir. Vamos analisar os tokens. Quantos estão sendo gerados? É aqui que mencionei que, se você estiver usando de forma esporádica, sem invocar um modelo com tanta frequência por meio de um provedor, pode comparar o custo com o de ter um agent ou algumas aplicações agentic que estão sempre trabalhando. Então, aqui geramos uma resposta só para obter esses tokens. Agora, vamos analisar a cobrança e comparar qual opção seria mais
25:53 eficiente. Então, se você estiver processando, digamos, 200 mil tokens por dia em uma conta de serviço hospedado, alugando o serviço, isso vai custar cerca de 1.500 por mês, certo? Mas, se você alugar uma GPU, isso vai custar cerca de mil por mês. Agora, o tamanho da GPU importa, assim como o tamanho do modelo e se ele realmente tem o desempenho de que você precisa. Mas essas são algumas das coisas em que você pensa quando tenta comparar: devo alugar ou ter meu próprio equipamento? Na verdade, você pode fazer as contas para detalhar isso.
26:25 E já falamos sobre isso em relação à resiliência dos dados, sabe, à conformidade, à segurança, aos controles e a todas essas coisas boas de executar localmente. Agora, antes de encerrarmos, sobre o panorama dos ambientes de execução: mencionei que estamos usando VLL, mas você também pode usar SGLang, que é bom se você estiver usando — se tiver solicitações que compartilham prefixos longos, como em conversas com várias interações. Por isso, muitas organizações usam SGLang para agents. Quanto ao TensorRT-LLM, ele é voltado para o throughput máximo em hardware da Nvidia. Ele realmente
26:58 é especializado em oferecer isso, e então há o llama.cpp para a borda, para processamento realmente rápido. Ele pode ajudar com modelos muito quantizados, por exemplo, em um servidor ARM. Então, vamos invocar mais uma vez e conferir nosso cliente, só para verificar se continua tudo certo. Estamos verificando se conseguimos nos conectar. Podemos ver o serviço do modelo e o ID, e acredito que posso imprimir tudo para vermos como essa solicitação
27:30 realmente aparece quando retorna. Então, também vou imprimir tudo isso. E agora você pode ver — na verdade, vamos formatar a saída para facilitar a leitura, para enxergarmos melhor. Pronto. Quando essa solicitação retorna, você consegue ver o ID, consegue
28:00 ver o comprimento máximo do modelo, que é o comprimento do contexto. Você pode controlar isso, certo? É claro que pode ajustar esses parâmetros ao trabalhar com um modelo, mas podemos ver tudo sobre o próprio modelo. Agora vamos passar para a próxima sessão. Nela, você poderá explorar o cluster e a VM e ir um pouco além, se quiser, usando este notebook. Então, vou fechar isso.
28:32 Vamos descartar isso e passar para unidades e memória. Agora, na próxima seção, vou tentar ir um pouco mais rápido para que o Omar tenha algum tempo. Ao falar de unidades e memória, vamos abordar o teto de tokens por segundo ao usar um modelo. Também vamos analisar a configuração real do modelo e entender como ele se encaixa e como realmente aparece em uma GPU. Aqui, como o Omar mencionou, estamos
29:03 usando — e vou deixar isso um pouco menor. Vamos ver se conseguimos mostrar mais conteúdo na tela. Certo. Quando falamos do modelo propriamente dito na GPU, temos os pesos do modelo de 4 bilhões de parâmetros. Esses pesos, no formato BF16, ocupam 8 GB. Então, temos 8 GB, e o restante do espaço fica para o KV cache. Ou seja, quanto contexto você consegue acomodar nessa GPU? Porque tudo precisa caber nela. Agora, quando seu prompt chega, durante o prefill, o modelo vai
29:33 ler o prompt inteiro e armazená-lo no KV cache. E, toda vez que gerar um novo token, vai atualizar esse prefill. Então, o prefill vai crescer, certo? Portanto, mesmo que seu prompt de entrada tenha um determinado tamanho, à medida que passa pelo modelo e é processado, ele aumenta conforme o modelo gera tokens, certo? E imagine as chamadas de ferramentas, o system prompt, tudo isso é enviado ao modelo e precisa caber no KV cache para que ele consiga processar sua solicitação com eficiência. E também estamos considerando o uso de FP8, que vai nos levar a falar
30:09 sobre quantização e sobre como ela reduz o tamanho de um modelo, mantendo a eficiência que você procura. Agora vamos instalar nossas dependências e, depois, conectar para verificar o que carregamos. Então, novamente, temos o modelo Quinn 3 de 4 bilhões de parâmetros, nosso namespace do workshop e a chave da API do cluster.
30:40 Agora, quanto aos modelos, temos o arquivo config.json. O que é exatamente esse arquivo? Quando você baixa um modelo — digamos que acesse o Hugging Face e baixe um modelo —, recebe uma coleção de arquivos. Todos esses arquivos são necessários, certo? Você recebe o config.json e os arquivos .safetensors. Esses arquivos de tensores contêm os pesos do modelo, certo? Mas é a configuração que diz ao VLM como lidar com aquele modelo, certo? Na verdade, você pode examinar esses arquivos para entender
31:11 como eles são. Aqui, estamos mostrando a aparência desse arquivo de configuração. Temos 128 camadas. O tamanho é 1.024. Quanto às cabeças de atenção, são 16. Os valores são oito. Tamanho do vocabulário, certo? Como o modelo é treinado? Qual é o tamanho do vocabulário desse modelo? Você pode examinar essas configurações. Dá para modificá-las? Não, certo? Esses arquivos não podem ser modificados. Mas você pode fazer fine-tuning, certo?
31:43 Você pode usar valores menores. Pode fazer todas essas coisas para adaptar o modelo. Mas, se tentar modificar esses arquivos, ele simplesmente vai falhar. Não vai carregar. Agora, vamos ver os bytes por peso, de onde vêm e como calculá-los. Aqui, estamos considerando um modelo menor, de 6 bilhões de parâmetros, em BF16: multiplicamos o número de parâmetros por dois, o que dá 1,5 GB; e, para o modelo de 8
32:14 bilhões de parâmetros, esses valores dão 8 GB. E, se compararmos BF16 com FP8… Agora, quando falamos de precisão, a maioria dos modelos é treinada, às vezes, em FP32, mas você geralmente os obtém em FP16. Precisão total significa multiplicar o tamanho do modelo por quanto? Por quatro, certo? Então, esse modelo de 4 bilhões de parâmetros ocuparia 16 GB em precisão total, certo? na sua GPU. Quando você o quantiza para, digamos, FP8,
32:53 bem, você perde um pouco das capacidades do modelo, mas não muito, certo? Mas é aí que você começa a avaliar, certo? Se sua capacidade computacional for limitada, talvez você tenha esse modelo maior, com 70 bilhões de parâmetros, e talvez consiga executá-lo em FP8 ou até em int4. Assim, o modelo de 70 bilhões de parâmetros, que ocuparia 32, passa a ocupar 16 GB, certo? Se isso for possível, certo? Não sei quanto você vai perder em precisão,
33:26 mas vai precisar avaliar isso. Por isso, os harnesses de avaliação são importantes. Vamos analisar a GPU, onde ficam os pesos. Em BF16, você multiplica por dois; em FP8, multiplica por um. Estamos fazendo esse cálculo para o Quinn. E temos outro modelo que vamos usar neste curso: um modelo de 8 bilhões de parâmetros que ocupa, digamos, 5 GB na GPU. Dá para ver quanto espaço você economiza e que ainda mantém a inteligência necessária para
33:56 os casos de uso que estamos discutindo, se decidir quantizar o modelo. Então, estamos analisando esta placa e os gigabytes por segundo. Você pega o valor que estamos calculando. Certo, sabemos que a velocidade da GPU é 360, e estamos mostrando como calcular os tokens por segundo e identificar o que está limitando o desempenho. Então, o limite vai ser a velocidade da própria GPU, que determina
34:27 a rapidez com que ela consegue processar. E aqui estamos mostrando as contas do KV cache. Estou tentando ir um pouco mais rápido para podermos chegar à quantização e à otimização. Mas, se você passar por esses cálculos, poderá entender como funciona a fórmula do KV cache. Muitas vezes, talvez não precisemos fazer essas contas, mas você vai precisar delas quando tentar calcular, por exemplo, o seguinte: você tem 100 usuários que quer atender e uma GPU menor. A questão é: tenho essa GPU menor. Digamos que eu dê um exemplo perfeito. Precisei ministrar um workshop e tive que descobrir como
35:00 para atender 80 estudantes e fazer inferência para todos eles com cerca de três ou quatro GPUs de aproximadamente 20 GB, certo? Preciso de tantas assim? Vai caber? Bem, qual é o tamanho do meu contexto para a carga de trabalho? E se todo mundo fizer uma chamada ao mesmo tempo? As GPUs, o cluster, vão dar conta disso? O batching contínuo vai funcionar? Então, você configura uma avaliação para avaliar toda a carga de trabalho e determinar: certo, vai caber ou você vai atingir o limite, certo? Começa a haver transferência para a CPU? Isso causa lentidão na sua aplicação.
35:35 Ou seja, o orçamento de memória dos pesos versus o pool de KV. Então, vamos analisar isso, e aqui está como você pode fazer as contas. Nesta GPU Sega, podemos obter 37.000 tokens, certo? São 8 GB para os pesos do modelo. E o espaço disponível será de 37.000 tokens, certo? Então, se tivermos vários usuários enviando solicitações, certo? Isso vai mostrar quantos usuários há na lista de contextos. Se tivermos quatro usuários, todos poderão enviar
36:09 8.000 tokens, certo? Para entrada, saída e chamadas de ferramentas, isso vai somar 8.000 tokens ao mesmo tempo nessa GPU. Agora estamos mostrando a taxa conforme aumentam as solicitações diferentes e a geração de cada solicitação. Isso mostra como fazer as contas quando você está tentando entender sua restrição de computação, sua GPU e as cargas de trabalho que está
36:40 executando. Você pode pegar todo esse código e aplicá-lo aos seus casos de uso, fazer as contas e ver se cabe nas suas GPUs. Então, vamos passar para o prefill e o decode. Vamos nos aprofundar um pouco mais no prefill, no decode e no KV cache. De novo, estamos usando o modelo Qwen3, mas vamos examinar como isso funciona. Temos o prefill,
37:11 que, como mencionei, está relacionado ao tempo até o primeiro token, certo? Desde o momento em que você aperta enviar, quanto tempo leva para receber o primeiro token, se estiver transmitindo a resposta, certo? Porque, se não estiver transmitindo, você vai receber a resposta inteira de uma vez. Mas, se estiver transmitindo, quanto tempo leva para receber o primeiro token, certo? Essa é a etapa de prefill. E o decode corresponde a cada token depois desse primeiro; tudo isso é medido. Se você estiver olhando as métricas no VLM, enviando-as para o Grafana, poderá visualizá-las no painel e acompanhar,
37:44 certo, conforme aumento meus prompts, você pode ver o valor subir e também pode vê-lo cair, certo? E entender de verdade o que está acontecendo na GPU quando você envia solicitações. Então, vamos passar por isso. Vamos instalar nossas dependências. Depois, vamos verificar nosso ambiente. Confirmar que estamos conectados. Sim. Ainda estamos usando o Qwen 34B. E vamos analisar a autoatenção, ou seja, como o KV cache é processado. Esta é a
38:16 fórmula propriamente dita. Você pode analisar o softmax para entender de verdade como o KV cache é tratado dentro de um modelo. Vamos fazer isso à mão para que você veja as contas. No que diz respeito ao KV cache, há a abordagem ingênua e há a abordagem com KV cache, que é a forma como eu diria que isso é tratado. Na abordagem ingênua, você pega um prompt, o modelo analisa o prompt inteiro e, em seguida, armazena esse prompt no KV cache, uma parte de cada vez, e
38:46 gera uma resposta. O que o KV cache faz é dizer: certo, vou pegar o prompt, aprender com ele e armazená-lo em paralelo. Assim, o KV cache permite aprender com o prompt para poder consultar as informações, em vez de simplesmente seguir a sequência fixa da abordagem ingênua de armazenamento em cache ao lidar com esse KV cache. E, se gerarmos isso, [fungada], podemos ver como ele calcula
39:19 a redução obtida com a abordagem de KV cache em comparação com a abordagem ingênua. Estamos mostrando tudo isso à mão no código para que você possa detalhar e entender. Agora vamos analisar o uso do KV cache e medir o tempo até o primeiro token. Aqui temos 57 milissegundos, e o decode levou 25 milissegundos. Vamos continuar
39:53 e ver o que o VLM realmente expõe. Podemos analisar essas métricas; estamos mostrando algumas das métricas que são expostas e como você as veria no VL. Agora vamos invocar o prompt e aumentá-lo, e você pode acompanhar o preenchimento do KV cache. Como isso vai levar um tempinho, vamos esperar alguns minutos enquanto o processo continua aumentando o prompt. Podemos ver o uso do KV cache e analisar as métricas. Temos o pico de uso durante a execução
40:30 e, depois que termina, o uso do KV cache. Essas são as contas de como você faria esse processamento. De novo, o worker que usamos para este código está em foundation.py. Esse é o auxiliar deste código. Agora vamos analisar a execução do código com o cache de prefixo aquecido. O cache de prefixo é algo interessante. Não confunda isso com o cache de prompt — é algo que eu deveria ter mencionado antes. Se você usa um provedor e paga por
41:01 token, o cache de prompt é indispensável, especialmente se você tem uma aplicação contínua que fica em execução. A cada cinco minutos, o cache de prompt é indispensável, certo? Você pode reduzir o custo em até 75%, dependendo de quem estiver usando. Então, há maneiras de usar um provedor e economizar. Mas, quando falamos de cache de prefixo, estamos falando de armazenar esse prefixo em cache para o KV cache. E, quando fazemos isso, podemos ver como ele é tratado aqui. O código leva 220 milissegundos
41:34 e cai para 41 milissegundos. Tudo isso mostra como fazer isso no código. Você pode examinar esse código. Estou tentando ir um pouco mais rápido para o Omar conseguir chegar à parte dele e, com sorte, podermos fazer o deploy. Certo. Vamos voltar e ir para a quarta seção, em que falamos sobre modelos densos versus mistura de especialistas na GPU. O que é um modelo denso? Bem, um modelo denso
42:07 quando está em uma GPU, usa o modelo inteiro para gerar tokens, certo? Então, se tiver 30 bilhões de parâmetros — ou vamos usar o modelo que estamos usando agora: o Qwen 3 4B em BF16, que ocupa 8 GB na GPU. Quando ele gera tokens, quando está realmente trabalhando, o modelo inteiro está em funcionamento, certo? Então, vai ser um pouco mais lento do que se você usar uma mistura de especialistas. Uma mistura de especialistas pode ser um modelo maior. Talvez ocupe 30 GB, mas
42:41 quando está gerando dentro do modelo, ele seleciona um conjunto de especialistas e só essa parte dos especialistas faz a geração. Então, mesmo que ocupe 30 GB, talvez use apenas 1,5 GB para fazer a geração. Isso vai ser muito mais rápido. Esse é um dos benefícios. Embora seja um modelo maior, quando é uma mistura de especialistas, ele pode ter um desempenho muito melhor em uma aplicação ou funcionar bem mais rápido nela.
43:12 Aqui falamos um pouco sobre memória e por que o decode é limitado pela memória. Ou seja, quando falamos da fase de geração, depois do tempo até o primeiro token, essa geração é limitada pela memória. Quando analisamos a velocidade dessa GPU, vimos que ela é limitada por isso: não dá para ir mais rápido, certo? Não há nada que possamos ajustar para fazê-la ir mais rápido. Mas há algumas coisas que podemos fazer para ajudar quando isso é ampliado. Então, vamos analisar nossa linha de teto e representá-la num gráfico para poder visualizar isso.
43:44 Então, vamos garantir que nosso modelo esteja carregado. Usamos um Quint 3 de 4 bilhões de parâmetros, certo? E ele será limitado pela computação. Então, vai atingir esse limite máximo. Vamos analisar os FLOPs. Vamos analisar isto. A linha de crista é de 297 FLOPs por byte, certo? E aqui o limite é imposto pela memória. Agora, se olharmos para a mistura de especialistas, vamos analisar isso como código. Assim, podemos entender de fato. Então, nesse modelo de 30 bilhões de parâmetros, certo? 128 especialistas e apenas oito ativos
44:20 por token. São 48 camadas, 248 de dimensão oculta. E agora, o misturador de especialistas, isto são os pesos. Isto é o peso compartilhado. Então, é assim que vemos quanto é usado durante a geração. Isso é bastante; seria muito mais eficiente do que usar um modelo menor. Na verdade, ele pode ser mais rápido durante a geração. E aqui estamos olhando para o modelo denso, certo? Ele usa nove vezes menos bytes do que um modelo denso, certo? Então, decodifica um pouco
44:55 mais rápido. Então, é assim que se comparam os dois quando você tenta descobrir: certo, quero usar algo como Mistro ou um modelo Quinn? Comparamos os tamanhos de dent. Aqui vamos analisar a taxa, a largura de banda e o serviço da GPU. O Quinn 4B medido fica em cerca de 40 tokens por segundo, certo? O modelo menor do Quinn, o 0.6. Isso não foi feito na CPU, mas estamos apenas
45:30 mostrando 300 tokens por segundo, certo? Mas estamos olhando para o teto. Isso analisa a largura de banda e faz os cálculos aqui para obter o máximo que podemos alcançar. O teto que temos nesta GPU é de 45 tokens por segundo. Agora, se ativarmos o raciocínio nesse modelo, podemos analisar isso. No caso desses modelos Quinn, se você quiser usar qualquer tipo de agent e o modelo precisar raciocinar,
46:01 ou seja, talvez o prompt chegue, você tenha ferramentas e ele precise fazer várias chamadas de ferramenta. Nesse caso, você vai ativar o modo de raciocínio. Então, quando ele fizer uma chamada de ferramenta, receber os resultados e precisar fazer outra chamada ou verificar os resultados para fazer a chamada de ferramenta correta, será preciso ativar o raciocínio nesses modelos. Isso é apenas um parâmetro que você pode ajustar no modelo, certo? Mas, com o raciocínio desativado, ele simplesmente gerou uma resposta. Foram 35 tokens. Com o raciocínio ativado, porém, ele precisou pensar a respeito. Isso custou cerca de 600 tokens. Agora, com alguns modelos, como os modelos de provedores,
46:36 você pode definir um orçamento de tokens para o raciocínio. Essa é uma das maneiras de economizar nos custos com um modelo de provedor; talvez também dê para fazer isso com alguns dos modelos open source. Não tenho certeza. >> Dá, sim. >> Sim, também dá para ajustar o orçamento de tokens do raciocínio. Mais tokens para pensar nem sempre são bons, mas às vezes podem ajudar o modelo a solucionar problemas melhor e a chegar ao resultado final que você procura. Então, ao falar de inference, há muitas coisas a considerar, mas uma delas é o limite imposto pela memória da
47:09 placa em si e como aplicar isso ao agent. Então, analisamos todos os módulos e falamos sobre o cache KB, o cache de prefixo, as cabeças de atenção e também a quantização, que vou abordar daqui a pouco; depois, falamos também sobre o batching contínuo. Separamos o prefill do decode, ficamos com o conjunto de GPUs de prefill e o de decode, que é limitado pela memória. O prefill é limitado pela computação, certo? Então, precisa ir da memória para a GPU e precisa ficar em cache, certo? Há
47:43 [limpa a garganta] essa etapa, na qual é possível fazer muitas otimizações, mas, na fase de decode, não há muito o que fazer, porque o limite é imposto pela GPU. Então, mostramos isso em código, em vez de fazer uma demonstração, porque, de novo, [fungada] há limitações de tempo neste workshop. Dito isso, vou garantir que está tudo pronto aqui.
48:19 Não acho que precise trocar o mod. Acho que está tudo certo. Armor, vou passar para você. >> Certo. >> E então, sim, deve estar tudo pronto. Você pode falar sobre quantização. Obrigado. >> Certo. Obrigado, Dwan. >> Isso. >> Certo. Vou fechar isso. Claro. >> Isso é seu, na verdade. Pronto. >> Certo. Legal. Vou falar sobre várias outras técnicas de otimização que, acho, você pode usar para deployar esses modelos no Kubernetes. Como eu
48:50 disse, minha experiência é com Kubernetes. Desenvolvo muitas coisas relacionadas ao Kubernetes na Akami e trabalho na plataforma de Kubernetes gerenciado de lá. Então, muitas das coisas que fazemos são para garantir que possamos usar GPUs muito bem no Kubernetes e aproveitar todos os diferentes recursos disponíveis. E fazemos deploy de muitos desses modelos usando algumas das técnicas sobre as quais vou falar. Há diferentes técnicas. Vamos falar sobre quantização. Acho que esta é a principal. É superimportante. Vamos falar sobre
49:22 speculative decoding. É uma técnica bem legal. Ela pode proporcionar um ganho considerável de desempenho na sua taxa de processamento. Vamos falar sobre como ajustar a configuração do seu LM ou VLM para garantir o máximo desempenho e cumprir seus SLAs. Depois, vamos fazer alguns ajustes e avaliações. Vou deixar vocês com uma espécie de estrutura que podem usar para descobrir
49:53 qual configuração exata usar para suas cargas de trabalho e casos de uso específicos. Vou falar sobre quantização. Vamos ver. Se tivermos tempo, podemos fazer também uma sessão rápida de perguntas e respostas, mas acho que temos 30 minutos. Vou avançar num bom ritmo. Na quantização, há muitos tipos diferentes que podemos usar. Há o BF-16, aquele com o qual o
50:25 modelo começa. Esse é o modelo de precisão total que o Quint fornece; além dele, há muitas outras opções. As pessoas criaram o FP8, um dos modelos que vamos analisar neste módulo. Há INT4. Há AWQ, GPQ e GPTQ. São diferentes formas de quantizar o modelo. Há NVFP4, a técnica de quantização proprietária da Nvidia. Ela é acelerada por hardware em GPUs Blackwell, entre outras. Essa é bem
50:58 legal. Vamos ver. Vamos entrar no assunto. Vou ajustar isto; espero que caiba aí. Certo. Como podem ver, os pesos BF16 vão ocupar bastante memória. Neste caso de uso específico, temos 20 GB de VRAM e queremos maximizar quantas solicitações podemos atender com esses 20 GB. Queremos garantir que haja espaço suficiente para o cache KV. O motivo
51:29 é que, quanto mais solicitações houver e quanto mais cache KV couber na memória, mais solicitações você poderá processar em paralelo, aumentando assim sua taxa de processamento. Isso é muito importante. Por isso, queremos fazer a quantização. Queremos reduzir o tamanho do modelo para que caiba mais cache KV e, assim, aumentar a taxa de processamento. Esse é um dos motivos. Acho que o outro grande motivo é que, ao reduzir os pesos pela metade, você evita essa movimentação de dados entre as diferentes hierarquias de memória, o que resulta essencialmente em
52:02 decodificação mais rápida também. Então, veremos que você vai passar de, digamos, 40 tokens por segundo, que é o que o modelo-base provavelmente alcança, para algo em torno de 60 tokens por segundo, ou até mais. Então, vamos ver isso. Vamos instalar as dependências e depois vou confirmar que o modelo ainda está disponível e que tudo está funcionando. Então, sim, o modelo está em execução: é o mesmo modelo de quatro bilhões de parâmetros, e está rodando no namespace. Novamente, como eu disse, em linhas gerais,
52:35 há vários tipos diferentes de técnicas que você pode usar para fazer quantização. Por exemplo, o llama.cpp é bastante popular para executar muitos desses modelos com precisão menor. Ele usa o formato GGUF. Esse formato é bem interessante: você pode ter quantizações de cinco bits, três bits, dois bits e um bit, o que é bem interessante e legal. Mas a desvantagem é que você perde muita qualidade ao tentar obter muito desempenho. Então, há uma compensação.
53:08 Mas, em geral, passar de BF16 para FP8 resulta em uma queda de qualidade muito insignificante. E isso proporciona mais desempenho, mantendo a qualidade exatamente igual. É isso que queremos demonstrar, e essa é uma das premissas que estamos adotando. Obviamente, quando você fizer isso para sua carga de trabalho específica, dependendo do uso, recomendo muito que cada pessoa tenha seus próprios evals. Assim, se você estiver mudando de BF16 e seus evals indicarem que está tudo bem, que tudo está funcionando corretamente para sua carga de trabalho, ao passar para FP8, talvez
53:40 você tenha problemas: algumas coisas podem parar de funcionar, às vezes o modelo pode alucinar, às vezes pode entrar em um loop. Muitas dessas coisas podem acontecer em casos de uso muito específicos e, nesses cenários, é muito importante ter seu próprio conjunto de evals e executá-los para garantir que as alterações feitas sejam aceitáveis e que também não haja degradação de desempenho. Novamente, vamos executar e confirmar que temos a versão-base BF16 e, em seguida, medir o desempenho. Temos um utilitário de teste de carga,
54:14 um pacote que usamos para fazer alguns testes. Basicamente, o que estamos fazendo, se você olhar para os níveis, é enviar essas solicitações com diferentes níveis de concorrência. Cada solicitação terá cerca de 256 tokens, e a saída terá aproximadamente 128 tokens. Isso tenta simular quantas solicitações você consegue processar ao mesmo tempo, e vamos usar isso como referência para ver qual é o desempenho-base. Então, com 32, estamos obtendo um desempenho agregado de 714
54:49 tokens por segundo, o que é muito bom. Com concorrência de um, estamos obtendo 37,5 tokens por segundo. É importante anotar isso. Também estamos obtendo 61 milissegundos até o primeiro token. E aí você vai notar que o tempo até o primeiro token aumenta, certo? O salto entre 32 e 64 é bem grande. Passamos de 277 milissegundos para 1.300 milissegundos. É um salto bem grande, e talvez você não queira necessariamente
55:20 fazer essa compensação. Ou seja, talvez você queira parar em apenas 32 solicitações concorrentes sendo processadas, sem passar disso. Então, é importante notar isso. Novamente, como eu estava dizendo, evals são extremamente importantes. O motivo é que pode haver degradação de desempenho quando você faz quantização, e você pode perder um pouco de inteligência; o raciocínio pode não funcionar como deveria. Podem surgir muitos
55:51 problemas. Então, quero simular aqui, em um nível bem básico, que tipo de eval você talvez queira considerar. Você pode pensar, por exemplo, se o JSON está sendo gerado corretamente, se ele é corrompido quando você reduz a quantização. Com BF16, talvez você tenha boas respostas, mas, ao passar para FP8, talvez suas chamadas de função falhem. Por quê? Provavelmente porque o JSON não está sendo gerado corretamente. Então, há muitos desses
56:21 casos de eval que já estão disponíveis e que você pode usar no open source. O Hugging Face tem muitos evals. Você pode procurar no GitHub e encontrar muitos deles, mas precisa criar os seus para seu próprio caso de uso. O próximo passo é mudar de BF16 para um modelo FP8. Basicamente, vamos reduzir o tamanho do modelo pela metade. Depois disso, veremos quais são as diferenças de desempenho, se vale a pena e se há perda de qualidade.
56:53 Para fazer isso, você precisa estar na raiz e clicar em manifest. Lá, você verá vlm.yaml. Vou explicar isso rapidamente. Este é um arquivo de configuração manifest típico para deploys no Kubernetes. Quantos de vocês já usaram Kubernetes ou têm conhecimento de Kubernetes? Certo, alguns. Ótimo. Então, vai ser rápido. Não preciso explicar todos os detalhes, mas
57:25 basicamente, temos um PVC, que é essencialmente nosso cache, onde ficam todos os nossos modelos, e temos um deployment simples com o VLM e vários argumentos e flags diferentes aqui. Você pode ver que estamos usando o modelo Qwen de 34 bilhões de parâmetros. Depois, vamos trocá-lo por esta versão FP8 da Red Hat. Deixe-me
57:56 mencionar mais uma coisa rapidamente: você vê “dynamic” no final. Isso é muito importante. Significa que nem tudo neste modelo está quantizado para FP8. Em muitos casos e com várias técnicas de quantização diferentes, talvez você queira quantizar apenas partes específicas do modelo, e não as outras, para garantir que o desempenho continue igual e evitar muitos problemas. Esse é um dos motivos pelos quais você verá “dynamic” e todo tipo de coisa. Você também verá quantizações em que certas cabeças do modelo terão quatro bits, outras terão oito
58:27 bits e algumas terão precisão total. É interessante que as pessoas estejam fazendo isso e encontrando muitos ganhos de desempenho. Elas estão obtendo ganhos de desempenho e, ao mesmo tempo, garantindo que a qualidade continue igual. Depois que isso for alterado, vamos salvar e executar e aplicar. Isso serve apenas para confirmar que o diff está correto e que não estamos causando nenhum problema. Deve estar tudo certo. Então, vamos lá. Onde está
59:01 a opção de aplicar? Aqui. Vamos clicar em aplicar, e isso vai iniciar a atualização. Vai levar um pouco de tempo. Deixe-me salvar. Outra coisa que vocês também podem fazer é abrir uma aba de terminal. Basta clicar no sinal de mais; aí vocês verão a opção de terminal, que também permite ver o que há no namespace e o que podem fazer aqui. Se vocês observarem, o endpoint do VLM ainda está iniciando. Este pod é
59:31 essencialmente o Jupyter Notebook em execução dentro do seu namespace. Vamos ver, vai levar um pouco de tempo para iniciar. Sim. Enquanto isso, alguém tem alguma pergunta? Provavelmente podemos responder a uma pergunta. >> O contêiner já estava quantizado. >> Sim, já estava quantizado. Sim, você pode
1:00:01 quantizar seus próprios modelos. Existe o LLM Compressor. Acho que ele é fornecido pelo VLM. O LM Compressor. Há ferramentas disponíveis para você fazer isso por conta própria, se quiser. Mas, sim, o modelo que estamos usando agora já veio pré-quantizado; baixamos do Hugging Face. Certo, acho que já deve estar pronto. De novo, está levando um pouco de tempo,
1:00:31 principalmente porque está tirando todos os pesos da VRAM e carregando os novos pesos. Então, isso vai levar um tempinho. Mais alguém tem alguma pergunta? Desculpem. >> Olhem o arquivo YAML do vLLM para os argumentos. Olhem, parece que havia duas flags no modelo. >> Ah, havia mesmo. Boa observação. Obrigado por isso.
1:01:04 Não tinha visto. Certo, vamos fazer de novo. Vamos executar novamente. Certo, provavelmente foi por isso que não apareceu tão rápido quanto deveria. Ah, não posso fazer isso. Certo. Mais alguma pergunta enquanto isso está sendo executado? Pode falar.
1:01:35 >> Como vocês escolhem entre…? >> Como vocês escolhem entre FP8 e INT8? Essa é uma boa pergunta. Depende: o INT8 vai ter um pouco menos de precisão que o FP8. Esse é basicamente o motivo. A diferença é que o FP8 é de ponto flutuante, então você obtém um pouco mais de precisão. Já o INT8 é inteiro. Então, você pode usar um ou outro. De novo, estas são todas as outras opções que você tem. Pode escolher com base na sua carga de trabalho e nas suas restrições. Mas, sim, você pode usar também o
1:02:08 INT8, e deve funcionar bem. Onde isso aparece? >> Boa. >> Stack. Ah, sim. Quero dizer, essa é outra boa observação. Também depende da GPU. Algumas GPUs talvez não sejam compatíveis. >> Compatibilidade com a GPU. >> Isso. A compatibilidade com a GPU é importante. Essa é outra boa observação. Então, algumas GPUs podem ser compatíveis, mas
1:02:39 talvez a GPU não acelere a operação, ou seja, talvez você não obtenha todo o desempenho que esperava. Por exemplo, as GPUs que estamos usando, as RTX 4000, são compatíveis com FP8, e vamos obter toda a precisão e todo o desempenho, porque elas conseguem acelerar por hardware todos esses cálculos. Mas, se usarmos FP4, por exemplo, elas não vão conseguir fazer isso e, na verdade, não veremos muitos ganhos de desempenho; veremos o desempenho cair, em vez de aumentar. Então, é mais uma coisa para ter em mente. Certo. Onde está?
1:03:19 Certo. A implantação foi concluída com sucesso. Então, vamos dar uma olhada rápida. Agora podemos ver que está usando o modelo FP8. Depois, vamos fazer rapidamente outro teste de carga. Vai ser exatamente igual. Vamos fazer com concorrência 1, 4, 8, 16 e 32, acredito, aqui. Vai ser exatamente igual. Então, quando estiver pronto, podemos comparar e ver as diferenças de desempenho e
1:03:50 por que você iria querer quantizar. Certo, os resultados de desempenho chegaram. Se compararmos antes e depois, dá para ver — vou aumentar um pouco a tela — que, mesmo com concorrência 1, passamos de 37,5 tokens por segundo para 53,4 tokens por segundo. Então, vemos um aumento considerável de desempenho. E, no pico de throughput, com concorrência 64, passamos de 800 para 1.140. Isso dá cerca de 1,42 vezes, o que representa
1:04:27 um aumento de desempenho bem grande. Mas, de novo, lembrem-se de que o tempo até o primeiro token também aumenta bastante, em comparação com 32 e 64. Mas, sim, vocês podem… E, de novo, é preciso executar evals. Podemos passar por isso rapidamente e provavelmente não haverá diferenças. Então, mais uma vez: BF16 versus FP8. Não deve haver muita degradação de desempenho. Em geral, vai funcionar sem ajustes, mas, para
1:04:58 casos de uso específicos, talvez não. Mas, nos casos simples de eval que tivemos aqui, está funcionando bem. Acho que é isso para este módulo. O próximo tópico é speculative decoding, que acho bem interessante. Vamos ver, vamos entrar aqui. Certo, quantos de vocês já ouviram falar de speculative decoding? Bastante gente, que bom. Para quem não sabe o que é speculative decoding, vou diminuir a tela. Basicamente, estamos
1:05:31 usando outro modelo de rascunho, que vai ser bem menor que o modelo principal que estamos usando, e ele vai gerar vários tokens antecipadamente. Depois, nosso modelo principal, que tem 4 bilhões de parâmetros, vai analisar esses tokens gerados e dizer se eles parecem bons. Ele vai verificá-los e dizer se parecem bons ou não. Neste diagrama, dá para ver que o modelo de rascunho gerou quatro tokens antecipadamente, e o modelo verificador, que é o nosso modelo de 4 bilhões de parâmetros, vai dizer: “Ah, só o primeiro e o segundo token fazem sentido; os outros dois, não.” Então, vai descartá-los. E, basicamente, vai fazer isso toda vez que gerar novos tokens. Então, vai ficar repetindo esse ciclo. E, neste workshop, vamos usar o modelo de 6 bilhões de parâmetros da Qwen como modelo de rascunho e ver se isso vai nos ajudar ou não. Em muitos casos, também pode não ajudar e reduzir o desempenho, e
1:06:04 há vários motivos para isso, que vamos abordar em breve. Como estamos de tempo? Bem. Só vou confirmar que está tudo certo aqui: modelo-alvo. Certo, antes de começarmos, também quero falar brevemente sobre todas as diferentes maneiras de fazer speculative decoding. Há várias maneiras, e surgem mais a cada poucos meses. O modelo de rascunho é uma delas. Muitas vezes, uma das novas maneiras de fazer isso é usar um modelo de rascunho de difusão, o que acho muito legal. Eu uso isso pessoalmente em uma das máquinas do meu homelab. E isso proporciona um enorme ganho de desempenho. A diferença entre isso e o método que estamos usando é que, por ser um modelo de difusão, ele gera muitos tokens de uma só vez, em vez de fazer o que fazemos com LLMs, que é gerá-los sequencialmente. Depois, o modelo verificador consegue verificar uma quantidade X de tokens.
1:06:34 Mas, sim, há vários tipos diferentes de métodos que vocês podem usar. Dá para usar suffix decoding. Muitas vezes, o modelo vem com um modelo de rascunho integrado. São modelos nativos, treinados junto com o modelo principal. Então, não é preciso importar outro modelo para fazer isso. Há Medusa, Eagle e, de novo, o dFlash de difusão é uma opção importante que viralizou e está funcionando muito bem. Há uma configuração que você define para determinar por quanto tempo — quantos tokens —
1:07:09 ele gera antes de o verificador entrar e verificar. Então, você pode definir isso para dois tokens, quatro tokens ou cinco tokens. É importante definir isso corretamente, porque, por exemplo, se você definir como quatro e o modelo verificador entrar e disser: “Certo, só aceito dois”, isso dá uma taxa de aceitação de 50%, o que é bem ruim. Na verdade, isso vai ter um impacto negativo, porque você não só está executando dois modelos, gastando computação para executá-los, como também está obtendo uma taxa de aceitação de apenas 50%. E isso basicamente
1:07:40 Mas, mas sim, há muitos tipos diferentes de métodos que você pode usar. Você pode usar decodificação por sufixo. Muitas vezes, o modelo também vem com um modelo rascunhador integrado. Esses são os modelos nativos treinados junto com o modelo principal. Então, você não precisa importar outro modelo para fazer isso. Há o Medusa, o Eagle e, de novo, o Diffusion DFlash, que é um dos grandes e tem viralizado bastante, além de funcionar muito bem. Há uma configuração que você define para determinar por quanto tempo, ou seja, quanto
1:08:11 ele gera antes de o verificador entrar em ação e verificar. Você pode definir isso como dois, quatro ou cinco tokens. E é importante definir corretamente, porque, por exemplo, se você definir como quatro e o modelo verificador entrar em ação e disser: “Tudo bem, só aceito dois”, isso dá uma taxa de aceitação de 50%, o que é muito ruim. Na verdade, isso vai ter um impacto negativo, porque você não está apenas executando — está executando dois modelos, então está gastando capacidade computacional para executar dois modelos — e, no fim, está obtendo apenas 50% de taxa de aceitação, e isso é essencialmente
1:08:44 vai resultar em uma diminuição, tipo, na vazão. Então, isso não é algo que você queira. Isso é algo que você precisa ajustar e testar, para ver quantos tokens quer gerar antecipadamente. Tecnicamente, você poderia gerar 15 tokens, mas provavelmente não vai querer fazer isso. Provavelmente vai querer gerar dois, talvez três, talvez quatro. Também depende do tipo de… como se chama? Deixe-me voltar. Onde está? De que tipo de método você está usando, mesmo? Eu uso o deflash em boa parte dos meus testes no laboratório doméstico. E funciona muito bem se eu configurar para
1:09:18 oito. Se eu configurar para mais de oito, na verdade, tenho uma taxa de aceitação bem menor, e isso faz meu desempenho cair ou ficar muito instável. Mas tudo bem, vamos para a próxima. >> Você tem mais uma pergunta. >> Mais uma pergunta. Oi, desculpe, esta é sobre o módulo anterior, mas como funciona a compressão dinâmica? Acho que em uma ou duas frases.
1:09:51 >> Então, funciona assim: você entende as diferentes cabeças do modelo? Há diferentes camadas dentro de um LLM. Se você olhar o arquivo model.json, vai ver que há várias partes diferentes em um LLM e todo um pipeline que, de certa forma, encaminha os tokens de uma coisa para outra. E muitas vezes, quando você vê algo dinâmico, isso basicamente quer dizer: “Certo, vou quantizar apenas as cabeças de atenção para FPA, mas vou deixar todo o resto como está”. >> Entendi. >> Esse é o motivo. E, se você
1:10:23 se lembra dos módulos anteriores, viu que a versão FPA não tem exatamente metade do tamanho. Ela não fica com quatro gigabytes; fica com cerca de 5,1 gigabytes. Isso acontece porque nem todas as partes do modelo foram quantizadas para FPA. Essa é, de certa forma, a parte dinâmica. >> O mesmo cálculo se aplica a todos os modelos ou depende do modelo? >> Depende de cada modelo. Cada modelo tem uma arquitetura diferente. Então, em termos de arquitetura, depende de quais partes do modelo você quantiza. Há pessoas que quantizam algumas partes do modelo para int4, mas deixam outras partes em FP8 e algumas em BF16. Então… >> Obrigado. >> É. >> Tudo bem. Vamos executar isso de novo. Só estou confirmando que nossa linha de base está boa. Estamos usando aqui um modelo FP8. Depois, vamos fazer rapidamente outro teste de carga, mais ou menos para obter outra linha de base de como seria antes de implementarmos e adicionarmos a decodificação especulativa a este
1:10:54 deploy em VLM. Enquanto isso estiver em execução, vou só garantir que… Na verdade, deixa eu copiar isso corretamente. Não é isso. Ah, deixa para lá. Então, aqui estamos definindo a configuração especulativa. Esta é uma flag específica que você pode passar para VLM para definir o modelo de rascunho. Então, estamos configurando para o modelo de
1:11:26 0,6 bilhão de parâmetros. Também estamos definindo quantos tokens queremos gerar como tokens de rascunho. Neste cenário específico, estamos configurando para quatro. Mais uma vez, é algo que você precisa testar bastante. Você precisa experimentar: quero configurar para quatro? Quero configurar para dois? Quero colocar um valor maior? Tudo depende da taxa de aceitação e de quanto desempenho você está obtendo. Depois de definir essa flag, vamos fazer o redeploy. Voltamos aqui. Temos nossa
1:12:01 linha de base. Agora deixa eu confirmar que está tudo certo. Certo, parece tudo bem. Então, vamos aplicar e colocar isso em execução. Provavelmente vai levar mais alguns minutos. Alguém tem alguma pergunta? Pode falar. Ah, um segundo.
1:12:32 >> Notei que você configurou a utilização de memória da GPU para 7, o que deixa, essencialmente, 30% da VRAM sem uso. Há algum motivo específico para essa escolha? >> Neste cenário específico, pode haver vários motivos. Às vezes, você pode ter vários deploys na mesma GPU e quer garantir que haja RAM suficiente para outra coisa — VRAM, no caso —
1:13:10 para outra coisa, e manter VRAM suficiente para isto. Mas, neste cenário específico, não muito. Na verdade, vamos aumentar esse valor em um módulo seguinte. É um daqueles parâmetros que você precisa ajustar: tem que garantir que a utilização esteja configurada corretamente. Se configurar um valor baixo demais, você deixa desempenho na mesa. Se configurar um valor alto demais, vai derrubar seu nó, e isso não é bom. >> É. Então, isso…
1:13:41 >> Certo, ainda está iniciando. Está demorando um pouco mais. >> Pode falar. >> Desculpe, um segundo. >> O aumento que vemos de 32 para 64 na paralelização é porque o cache de chave-valor estourou, ou…? >> É, essencialmente o cache de chave-valor estourou e chegou ao limite máximo, sem conseguir passar dele. Há vários motivos, então…
1:14:14 tem essa parte e também há o batching contínuo. Muitas vezes, isso acontece se você configurar o batching contínuo em um nível que não seja ideal; isso também pode fazer com que você veja um número alto de tokens por segundo. Você também pode ver uma latência alta. Mas, sim, neste cenário, estamos essencialmente atingindo uma espécie de teto para a quantidade de VRAM que podemos usar. É por isso que estamos vendo isso. Mas, nos módulos seguintes, vamos ver
1:14:48 como podemos melhorar esse cenário e, com sorte, deixá-lo melhor. Certo, o deploy foi concluído. Agora temos a decodificação especulativa configurada corretamente. Então, vamos fazer outro teste de carga rápido. É exatamente o mesmo teste que executamos aqui. Só para lembrar: estamos obtendo 58,2 tokens por segundo com concorrência de um e latência de 42 milissegundos. Essa é nossa linha de base antes da decodificação especulativa. Mas o que quero mostrar aqui não é um caso ideal em que você obtém automaticamente uma melhoria absurda no desempenho. Na verdade, vocês vão ver que o desempenho caiu drasticamente. Estamos vendo 16 tokens por segundo, enquanto a linha de base era 58. E até o tempo até o primeiro token aumentou um pouco. Queremos entender por que isso está acontecendo. Há uma grande diferença e uma grande queda de desempenho. Mesmo olhando para a concorrência 16, passamos de 700 tokens por segundo para 240 tokens por
1:15:20 segundo. Então, é uma queda considerável no nosso desempenho. Há vários motivos possíveis para interpretar isso. Um deles, como mencionei antes, é a baixa taxa de aceitação. Se a taxa de aceitação for muito baixa e o modelo verificador ficar rejeitando os tokens gerados pelo modelo de rascunho, você desperdiça bastante computação gerando esses tokens de rascunho. Aí o verificador entra e diz: “Ei, não quero aproveitar esse trabalho; esse trabalho está ruim”. Esse é um motivo. Outro pode ser termos definido um número alto demais de tokens especulativos,
1:15:57 ou seja, na configuração atual, definimos quatro. Talvez precisemos reduzir esse valor e ver se isso ajuda a melhorar o critério de aceitação ou a taxa de aceitação. Também há muitos fatores relacionados ao escalonador no VLM. Dependendo de como ele agenda essas solicitações, isso pode fazer com que parte do desempenho disponível não seja aproveitada. Então, também depende da compatibilidade e de coisas assim. E, de novo, há a contenção da GPU: você está usando a mesma GPU para fazer esse trabalho. Então, isso pode estar resultando em…
1:16:28 segundo. Então, essa é uma queda considerável no nosso desempenho. Há muitos motivos para interpretar isso. Um deles, como eu estava dizendo antes, é a baixa taxa de aceitação. Se a sua taxa de aceitação for muito baixa e o modelo verificador ficar rejeitando os tokens gerados pelo modelo rascunhador, você estará desperdiçando muita capacidade computacional para gerar esses tokens preliminares. Aí o verificador entra e diz: “Ei, não quero usar isso; este trabalho está ruim”. Então, esse é um motivo. Pode ser porque definimos alto demais o número de tokens especulativos,
1:17:02 ou seja, na nossa configuração atual, definimos quatro. Talvez precisemos reduzir esse valor e ver se isso realmente ajuda a melhorar os critérios de aceitação ou a taxa de aceitação. Há muitas coisas relacionadas ao escalonador também, com VLM. Dependendo de como ele agenda essas solicitações, pode haver desempenho que não estamos aproveitando. Então, também depende de compatibilidade e coisas assim. E, de novo, há a mesma contenção de GPU: você está usando a mesma GPU para fazer esse trabalho. Então, isso pode estar resultando em
1:17:34 os recursos não estão sendo usados corretamente. Então, em muitos casos, geralmente isso funciona, mas no nosso cenário não funcionou. O principal motivo específico é que este modelo drafter não foi treinado corretamente para este modelo específico. Por isso estamos vendo uma taxa de aceitação muito, muito baixa. Então, quando fizerem isso com seus próprios modelos e implantações, vocês precisam garantir que o modelo drafter que estão usando seja compatível com o modelo para o qual querem
1:18:06 usá-lo. Se não fizerem isso, vão acabar numa situação como a que estou mostrando aqui, em que o desempenho vai despencar, e não há muita coisa que possam fazer a respeito. Posso dizer que, do ponto de vista dos recursos, esta GPU tem capacidade sobrando para dar conta de tudo isso. Mas o motivo dessa queda no desempenho é que os modelos não foram treinados corretamente. E isso é algo que vocês também devem levar em conta e testar. E precisam garantir que o número de tokens especulativos esteja definido corretamente. Mas, sim, quando tiverem um tempo, eu
1:18:42 com certeza incentivo todos a experimentar esse número, ou seja, mudar de quatro para dois, para seis, para um, e ver que tipo de ganho de desempenho obtêm, que tipo de queda de desempenho observam e por que isso está acontecendo. Mas é isso quanto à decodificação especulativa: ela não vai nos ajudar neste cenário. Então, vou comentar isso e depois vamos fazer o deploy novamente. Assim, voltamos à nossa linha de base.
1:19:15 >> Ei, tem uma pergunta. >> Uma pergunta. Oi. Então, sei que provavelmente há algumas nuances dependendo da arquitetura do modelo, mas, em geral, pelo que você viu, há uma grande queda na taxa de aceitação se você usar, essencialmente, precisão mista, tipo, executar o modelo principal em FP8 e depois quantizar o modelo drafter para Q2? Se eu estiver com muita restrição de memória, >> isso costuma valer a pena? Ou, sabe, o que você tem visto em
1:19:46 geral? Tipo, isso… >> Boa pergunta. Muitas vezes, isso não faz tanta diferença. Na maior parte do tempo, o ideal é manter o modelo drafter e o modelo principal na mesma precisão. Mas digamos que o modelo drafter esteja em BF-16 e o modelo principal esteja em FP8. Essa incompatibilidade pode fazer a taxa de aceitação ficar muito baixa. E o principal é que você precisa treinar o modelo drafter corretamente, para que ele consiga gerar os tokens certos. No nosso cenário específico, o modelo
1:20:18 drafter não foi treinado corretamente. Além disso, ele também foi quantizado para FP8. Então, provavelmente houve alguns problemas com essa receita quando treinaram o modelo, o que acabou resultando numa enorme queda de desempenho. Muitas vezes, quando um laboratório lança um modelo, também lança um modelo drafter junto com ele. Então, é recomendável usar os modelos drafter que vêm com o modelo. Há também laboratórios de terceiros que criam seus próprios modelos drafter. Então, vocês podem experimentar várias opções disponíveis e ver qual
1:20:49 funciona para vocês. E, em alguns casos, dependendo do caso de uso, digamos que vocês estejam usando para programação, o modelo drafter pode funcionar perfeitamente bem. Mas, se mudarem para algo como escrita em inglês, uma escrita acadêmica muito específica, talvez ele não funcione tão bem, e vocês vão observar uma queda na taxa de aceitação. Então, isso também depende bastante do caso de uso. Não se aplica universalmente. >> Entendi. Legal. Faz sentido. Obrigado. >> Sim. Certo. Vamos passar para o lado da inferência das
1:21:23 coisas. Mas, antes de passar para outra coisa, mais alguma pergunta? Ah, sim. Posso colocar o YAML ali. Então, o fato de termos decodificação especulativa é, presumivelmente, porque, para um modelo, verificar é mais rápido do que decodificar. >> Sim. Você pode explicar um pouco o modelo mental de como funciona, nos bastidores, para
1:21:55 verificar ser mais rápido do que decodificar? Sabe, não pode ser decodificar e depois comparar com o que o modelo drafter produz. Então, >> o que exatamente ele faz para ser mais rápido? >> Sim. Essencialmente, quando um LLM típico está decodificando, há um conjunto de vocabulário, um enorme vetor de números, que representa uma pontuação de confiança para cada um dos itens, certo? Então, em vez de fazer isso um token de cada vez, quando você executa com decodificação especulativa, executa o modelo
1:22:29 para várias coisas em paralelo. Com o batching contínuo também, você executa o modelo para várias requisições diferentes em paralelo. Então, faz o mesmo cálculo para tudo. E faz isso de uma vez para muitas requisições diferentes. Do mesmo modo, faz a mesma coisa na decodificação especulativa. Verifica a pontuação de confiança desses tokens especulados e confirma que, por exemplo, este tem alta confiança, então vamos aceitá-lo. Este tem, sabe, 0,95, e este outro tem, tipo, 0,9. Aí você aceita esses e, sabe, rejeita os outros. Esse é, mais ou menos, o modelo
1:23:03 mental: você executa em paralelo pelas camadas e confirma que cada um dos tokens gerados pelo modelo drafter tem alta confiança. Sim, espero que isso responda à sua pergunta. Ah, mais uma pergunta. >> Você tem algum exemplo que… >> Sim, tenho. Boa lembrança. Na verdade, deixei alguns links aqui. Onde foi que deixei?
1:23:36 Interpretando os resultados. Sim. Há muitas análises diferentes sobre decodificação especulativa em geral. Se fizerem isso da maneira certa, vão observar um aumento considerável no desempenho. A VLM fez um relatório extenso sobre isso e observou um aumento de cerca de 1,5 vez na geração de tokens, quando a configuração foi feita corretamente, com o modelo certo, o modelo drafter certo e as configurações certas. Então, sim, isso pode dar ótimos resultados. É só uma questão de acertar e ajustar corretamente, garantindo que tudo esteja preparado da maneira certa. Mas, pela minha experiência pessoal, no meu laboratório doméstico,
1:24:10 usei o modelo Quinn 3.6 de 35 bilhões e, junto com ele, usei um modelo drafter Dlash, e obtenho uma melhora no desempenho da geração de tokens de aproximadamente duas a três vezes, dependendo do caso de uso. Então, funciona. É só uma questão de fazer os modelos certos trabalharem juntos. >> Como você escolhe o tamanho do modelo >> para o drafter? >> Basicamente, você quer
1:24:42 descobrir qual é o menor modelo que consegue executar sem consumir tanta potência da GPU, porque o modelo principal é o que contém todo o conhecimento. É esse modelo que realmente importa, que tem tudo de que você precisa. Mas você não quer que o modelo drafter consuma muitos desses recursos do modelo principal. Então, ele precisa ser pequeno, mas não tão pequeno a ponto de ser burro, e grande o bastante para realmente oferecer… >> Você experimentou isso? Viu taxas de aceitação com um modelo de 3B? >> 3B é grande demais. O motivo é que muitos modelos, como eu estava falando, o Qwen 3.6 de 35 bilhões, são modelos de mistura de especialistas, e cada especialista tem cerca de três bilhões de parâmetros. Então, os especialistas podem ter esse tamanho e ainda assim oferecer um bom desempenho. Mas, para o modelo drafter, provavelmente é melhor ter menos de um bilhão de parâmetros. Só que isso também depende do modelo principal que você está usando, eu acho, certo? Tipo, se o seu modelo principal tiver 400 bilhões de parâmetros, provavelmente dá para usar um modelo drafter maior e garantir uma taxa de aceitação mais alta. Então, você precisa encontrar o tamanho certo
1:25:16 muitos modelos, como eu estava falando do Qwen 3.6, de 35 bilhões. Então, é um modelo de mistura de especialistas, e cada especialista tem cerca de três bilhões de parâmetros. Os especialistas podem ter esse tamanho, e você teria um bom desempenho com ele. Mas, para o modelo rascunhador, provavelmente você vai querer menos de um bilhão de parâmetros, só para garantir. Também depende do modelo principal que você está usando, eu acho, certo? Se o seu modelo principal tiver, por exemplo, 400 bilhões de parâmetros, provavelmente você poderia usar um modelo rascunhador maior para garantir uma taxa de aceitação mais alta. Então, você precisa encontrar o ponto certo
1:25:48 equilíbrio, basicamente. Sim. Legal. Temos mais alguma pergunta ali? Mais uma antes de você começar. >> Sim, eu tinha uma pergunta. Como o modelo de rascunho é treinado? É destilação ou outra coisa? >> É essencialmente destilação. Você pega o modelo grande e destila todas as capacidades dele. Cria um conjunto de dados e depois treina o
1:26:19 modelo de rascunho com esses dados. Na verdade, há diferentes técnicas para fazer isso. Outra técnica que você vai ver é treinar o modelo de rascunho junto com o modelo principal. Essa é outra maneira de fazer isso, e muitos laboratórios oferecem um modelo de rascunho dentro do mesmo pacote. Assim, você não precisa baixar e executar um segundo modelo. Há algumas maneiras diferentes de fazer isso, mas provavelmente a melhor é treiná-los juntos, porque assim você não tem muitos problemas e a taxa de aceitação tende a continuar alta.
1:26:50 Legal. Vamos passar para o módulo sete. Aqui quero falar sobre algumas das diferentes flags com as quais você deve se preocupar ao fazer o deploy usando VLM e sobre como você pode maximizar a saturação. Saturação significa que queremos manter a GPU trabalhando o máximo possível pelo maior tempo possível. Você quer aproveitar ao máximo o que está pagando: se estiver alugando uma GPU ou se tiver comprado uma, quer usá-la o máximo possível. Então, vamos parar por aqui. Um dos conceitos sobre os quais quero falar, se você
1:27:27 se lembra, antes estávamos analisando a concorrência de 34, 32 e 64. Vimos um grande aumento na latência, e a razão é que, em algum momento, o throughput vai se estabilizar, mas a latência pode continuar aumentando se você continuar aumentando a concorrência. Então, você quer encontrar o ponto ideal, e o VLM permite ajustar isso e garantir que você encontre
1:27:57 esse ponto ideal. Quando encontrá-lo, pode definir as configurações adequadas. Mas, essencialmente, você quer encontrar — não exatamente a interseção — o ponto logo antes de o throughput ficar estável, enquanto a latência ainda é aceitável. Esse é mais ou menos o ponto a que você quer chegar. Vamos fazer uma configuração e depois conferir se nossas configurações ainda estão todas corretas. O modelo está sendo servido. Deixe-me só confirmar se está no ar.
1:28:36 Deve estar. Certo. E agora vamos fazer outro teste de carga. Assim, teremos os dados e poderemos usá-los para descobrir onde fica esse ponto. Essencialmente, chamamos isso de joelho: o ponto em que as coisas começam a se estabilizar, mas em que, considerando a concorrência, o tempo até o primeiro token ainda é aceitável. Quando isso… Ah, acho que deve estar
1:29:08 tudo bem. Como você vê, o throughput aumenta aos poucos à medida que a concorrência aumenta. Isso é aceitável. Você também vê a latência subir. Isso também é aceitável, mas ela não está subindo drasticamente. Em breve, porém, devemos ver grandes saltos com mais concorrência aqui. Enquanto isso está
1:29:40 rodando, mais alguém tem alguma pergunta? >> Pode falar. Ah, ali. >> Minha pergunta era sobre a decodificação especulativa anterior. Queria saber, com base na sua experiência com modelos de rascunho, em que tipos de casos de uso você viu isso funcionar muito bem? Por exemplo, em loops de agentes com tool calling ou em programação? Que tipo de uso… >> Em loops de agentes, funciona muito bem; para tool calling, funciona muito bem; para uso do navegador,
1:30:11 esse é um caso de uso específico para o qual eu uso: quero automatizar muitas tarefas no navegador, porque ainda não existem APIs para tudo, necessariamente, e você quer preencher essa lacuna. E o modelo de rascunho ajuda a gerar mais tokens mais rápido. Então, você vê seu agente de navegador simplesmente sair por aí e fazer as coisas mais rápido. Portanto, de várias maneiras, ele ajuda. Eu diria que, para uso do navegador, vejo um aumento de cerca de 1,5x, enquanto, para programação, vejo algo mais próximo de 3x. Então, dependendo do seu caso de uso, você
1:30:42 pode ver um aumento maior ou menor, e coisas assim. E uma pergunta complementar: existem benchmarks mais confiáveis do que “confia em mim, cara”, como Coding Fire Ship? >> Com certeza existem benchmarks por aí. Pessoalmente, sou um pouco cético quando vejo benchmarks. Nunca obtenho os mesmos resultados. Não sei se alguém aqui concorda com isso. Então, no geral, você deve fazer seus próprios testes e ver o que funciona para você, porque isso depende muito do seu caso de uso: a taxa de aceitação
1:31:12 vai ser diferente dependendo do seu caso de uso e daquilo para que você está usando. >> Obrigado. >> Sim. Mais alguma pergunta? >> Teste do microfone. Teste do microfone. Tudo bem? Modelos grandes como Codex ou Claude usam esse tipo de técnica de programação? Eles já publicaram que usam esses padrões ou isso é mais para open source, caso você esteja treinando suas próprias coisas ou executando inference?
1:31:43 >> Não sei se eles fazem isso ou não. Imagino que façam, por questões de desempenho, mas, para open source, sim, isso é especificamente para open source. Todos os grandes modelos open source que você quiser usar — todos os modelos Qwen, os modelos GLM, os modelos Kimi — têm modelos de rascunho para decodificação especulativa disponíveis, que você pode usar. >> Existe um modelo de rascunho principal que eles usam, por exemplo, para DeepSeek ou GLM? >> Na verdade, a DeepSeek lançou uma coisa nova ontem, acho, ou anteontem.
1:32:14 Chama-se DSpark. É uma técnica própria para fazer decodificação especulativa de maneira mais dinâmica. Essencialmente, estão determinando como fazer isso. Aqui, por exemplo, nossa configuração é estática, certo? Dizemos que vamos gerar quatro tokens de cada vez. Mas, com o método da DeepSeek, isso é dinâmico: em tempo real, o modelo decide gerar apenas dois tokens, ou quatro, ou cinco, dependendo dos critérios de aceitação, da carga da GPU e de todo tipo de métrica. Então, cada
1:32:45 modelo, cada laboratório também tem sua própria maneira de fazer isso, e provavelmente você vai querer seguir essa abordagem, mas também pode experimentar. Por exemplo, os modelos Qwen: o laboratório Qwen não lança os modelos DFlash para rascunho, mas eles são lançados por um laboratório terceirizado e funcionam muito bem com eles. Então, você precisa testar e ver. >> Obrigado. >> Sim, acho que travou, né? >> Sim, eu verificaria o pod. Talvez eu tenha derrubado um cluster aqui.
1:33:19 >> Ah, não consigo digitar. >> Ah. >> Isso estava funcionando bem. >> Atualize. [risos] >> Deixe-me criar a aba de novo. Certo. Bem, tem alguma coisa errada. Ele copiou uma URL e abriu uma nova aba. Vamos ver o que acontece. Deixe-me abrir uma nova aba. Eu não fecharia aquela.
1:33:55 Sabe, em todos os testes que fizemos, isso nunca tinha acontecido. Aconteceu hoje. Pelo menos posso rolar a página e passar por algumas coisas? Certo, pelo menos consigo rolar a página. Como o cluster resolveu tirar férias, vou passar pelo conteúdo que eu ia abordar. O principal objetivo de executar este
1:34:27 benchmark aqui era mostrar onde fica esse joelho, ou seja, onde se observa o throughput máximo. Se voltarmos a este diagrama, é onde você vê o throughput máximo e, ao mesmo tempo, garante a menor latência na geração de tokens. E esse limite ficava na concorrência de 32. Porque, acima de 32 de concorrência, a geração de tokens vai ficar mais ou menos igual. Não vai mudar muito.
1:34:59 A taxa de transferência vai ser a mesma, mas a latência vai aumentar drasticamente, e você não quer isso. Então, esse é mais ou menos o limite que você está atingindo. E essa é uma informação importante que precisamos ter em mente e observar ao fazer o deploy dessas coisas. E, se… >> Sim, pode ir para 100. Vá olhar a planilha. >> 100. >> É, vá para 100 e depois continue a partir de… >> Sim. >> sete ou oito. Onde está?
1:35:35 >> Aí está. >> Certo. Bem, este está funcionando. Que bom. Certo. Legal. Então, vamos para o oito. Deixe-me também [risos] abrir… Quem está fazendo isso?
1:36:05 >> Certo, para o módulo A, vamos falar rapidamente sobre que tipos de flags e parâmetros você pode ajustar para garantir que consiga passar daquele ponto limite que discutimos, com concorrência 32. Você está vendo esse limite. Como podemos ultrapassá-lo? E o que precisamos ter em mente ao pensar nisso? Para este módulo, vou apresentar um modelo mental: essencialmente, você quer medir. É por isso que, em várias células diferentes, eu ficava executando testes de carga. É muito importante executar esses testes para ver como está o desempenho
1:36:38 e como as mudanças que você está fazendo afetam o desempenho: estão melhorando ou piorando? E em qual métrica específica estão piorando? Por exemplo, se a taxa de transferência continua aumentando ou fica igual, mas a latência está mudando, alguma coisa está certa ou errada. Então, é algo que precisamos ter em mente. Há vários parâmetros diferentes que você pode ajustar no vLLM para melhorar o desempenho. Mas os quatro principais são, mais uma vez, a utilização da memória da GPU. Você precisa garantir que está definindo isso corretamente, de acordo com seu caso de uso. Mais uma vez, se
1:37:11 você estiver executando vários modelos na mesma GPU, talvez queira manter esse valor baixo; esse é um compromisso que você está fazendo. Mas, se estiver executando apenas um modelo e quiser garantir o melhor desempenho possível, aumente para 0,9 ou até 0,95. Outra coisa é garantir que o número máximo de sequências esteja definido com um limite adequado. Você precisa descobrir isso por meio de testes. Na nossa implantação específica, se você olhar o VLM.yaml,
1:37:41 começamos com 32 sequências, certo? Isso informa ao vLLM que ele pode processar apenas 32 solicitações por vez, e não mais do que isso. Se você enviar mais do que isso, vai notar uma degradação no desempenho. Há várias flags diferentes, mas essas são as principais que você precisa ter em mente. Você também precisa garantir que o tamanho do modelo esteja definido corretamente. E precisa garantir que o número de tokens do lote também esteja definido corretamente. Você
1:38:11 não quer… Você quer manter esse valor maior se quiser fazer o prefill mais rápido, desde que sua GPU dê conta. Quer mantê-lo menor se sua GPU for um pouco mais lenta e não conseguir dar conta. Mas a ideia é mudar uma flag de cada vez. Não mude várias coisas. E, quando fizer mudanças, execute os benchmarks e veja o desempenho que está obtendo. Meça e, então, decida o que fazer em seguida. Vou passar por isso rapidamente.
1:38:42 Temos mais ou menos 10 minutos. Ah, >> Acho que perdemos o PVC. Acho que foi isso que aconteceu. Eu… >> Ah, pegou o outro. Sim, preciso mudar isso. Acho que preciso executar de novo. Deixe-me mudar isso aqui. Era para ser sequencial, mas o outro Jupyter Notebook travou. Então,
1:39:16 mude isso e aí deve funcionar. Mais uma vez, como eu disse, há vários parâmetros que você pode ajustar e observar o que acontece. Mas vamos medir: primeiro, a linha de base; depois, mudamos algumas flags e vemos o que acontece. Está funcionando? Certo, legal. Aí está, está funcionando. Enquanto este teste de carga está rodando, alguém tem mais alguma pergunta? >> Com licença.
1:39:52 >> Notei que há uma queda bem acentuada quando estamos otimizando o modelo. Aqui, de 32 para 64, a queda é enorme. É nessa hora que você decidiria que talvez devêssemos aumentar a escala do hardware, ou você tem confiança de que ainda dá para ajustar mais? >> Essencialmente, isso é o limite máximo? >> Sim, você descobre o limite máximo fazendo os cálculos. Acho que, em alguns dos módulos anteriores, Dwan abordou qual pode ser o limite máximo
1:40:22 de tokens por segundo, como fica a taxa de transferência e que tipo de expectativa você deve ter para a implantação. Se você estiver atingindo esses valores máximos esperados, provavelmente esse é o limite máximo do seu hardware. Então, provavelmente, vai precisar de hardware adicional ou melhor para isso. Sim, há um limite. Só dá para ajustar até certo ponto, mas você tenta extrair o máximo possível da GPU. Quer compartilhar os slides antes de continuar?
1:40:54 Compartilhe os slides rapidinho. >> Posso deixar o servidor disponível por mais um tempo, algumas horas. Não vou deixá-lo disponível por muito tempo, porque vocês têm acesso a GPUs. Mas o que vou fazer é dar acesso ao PowerPoint e ao repo: se vocês escanearem este QR code, poderão acessar os dois. Se quiserem iniciar isso na própria conta de nuvem de IA ou executar no laptop, podem fazer isso.
1:41:25 Então, se escanearem este QR code, serão levados a um site com todos os recursos. Se não tiverem uma conta de nuvem, podem se cadastrar e receber US$ 300 em créditos com uma conta gratuita. Então, é tudo de que precisam. E, se tiverem perguntas, as informações de contato de nós dois estão aqui. Omar, eu sou Dwan Lightfoot. >> Sim. >> E, com isso, se escanearem o QR code, vou deixar Omar concluir. Só quero garantir que vocês recebam isso antes de as pessoas começarem a sair. Obrigado. >> Vamos deixar isso na tela por mais alguns
1:41:56 minutos, para que todos consigam. >> Sim, pode falar. Assistente pessoal. Então… >> Então, você pode usar modelos Llama. Depende do seu hardware. Acho que essa é a
1:42:27 primeira coisa que eu verificaria. >> Sem problema. Obrigado. >> Ah, você tem os dois. Para fins de argumentação, digamos que você tenha a melhor GPU. Digamos que tenha uma… >> Sim. Sim. Você tem a GPU Blackwell mais recente. Para fazer testes e descobrir qual modelo quer usar no seu caso de uso, acho bom usar Ollama e llama.cpp para iniciá-lo rapidamente, experimentá-lo e ver o que acontece. Mas, quando tiver um modelo que sabe que vai usar nesse caso de uso e que está funcionando muito bem,
1:42:57 provavelmente vai querer mudar para vLLM, SGLang ou outro desses runtimes de modelos. O motivo é que eles permitem executar com níveis de concorrência mais altos e obter mais desempenho. Então, se você tiver um único agent em execução, acho que não tem problema usar Ollama, porque não é grande coisa: você só tem uma solicitação sendo processada por vez. Mas, digamos que você esteja executando uns 20 agents e queira executá-los em paralelo… >> Sim. Sim, você pode configurar speculative decoding com vLLM. Acho que o Ollama não…
1:43:31 Até onde sei, oferece suporte a speculative decoding, mas posso estar errado. Mas sim, quando você quer obter o máximo desempenho do seu hardware, definitivamente vale a pena fazer isso. >> É. >> Na verdade, não sei se existe algum LLM de difusão. Há algum modelo de difusão open source disponível agora? >> Sim, o Llama. Sim, quer dizer, acho que o VLM oferece suporte a isso. Então acho que você conseguiria
1:44:01 executá-lo no VLM. O Ollama também, se oferecer suporte, pode fazer isso. Sim, definitivamente é possível. Certo, vamos voltar ao módulo e passar por ele. De novo, como eu estava dizendo, com 32 você está vendo um bom desempenho, mas com 64, a taxa de transferência fica mais ou menos igual, ou até aumenta, mas vemos um aumento significativo na latência. E, para contornar isso, uma das
1:44:33 coisas de que quero falar é o número máximo de sequências. Mais uma vez, isso indica quantas solicitações o VLM consegue processar ao mesmo tempo. É basicamente uma configuração desse parâmetro. Se você quiser processar muitas solicitações em paralelo, deve aumentar esse valor. Acho que, no momento, está definido como 32. Então podemos aumentá-lo para 128, fazer o deploy e ver como isso muda o desempenho.
1:45:09 Certo, isso mudou muitas coisas aqui. É, [fungada] quando isso estiver pronto, podemos fazer outro teste e vocês vão ver que as limitações que estamos vendo aqui com 32 vão desaparecer, e a latência vai voltar a ser administrável, mesmo em níveis mais altos de concorrência. Então, esse é mais ou menos o ciclo que vocês devem seguir. É preciso encontrar os parâmetros certos para onde quer que esteja o gargalo. Encontre o gargalo, descubra por que isso está
1:45:42 acontecendo e qual parâmetro você pode ajustar para superar esse gargalo. Já está pronto. Isso vai levar um pouco de tempo. Alguma pergunta? Tem mais uma ali. >> Talvez haja picos de tráfego >> em certos momentos. >> Ah, sim. Existe algo como direcionar picos para serverless? Isso fica a cargo de uma camada de roteamento de modelos por cima? Qual é o padrão para
1:46:17 >> Sim. O autoscaling é um dos padrões. Especificamente, posso dizer que, no LKE, você pode ter autoscaling dinâmico. Assim, ele pode escalar conforme suas necessidades e os picos de tráfego. Pode escalar para, quem sabe, usar um nó com quatro GPUs em vez de um, porque talvez isso dê conta melhor, certo? Então você pode automatizar muitas dessas coisas para garantir que tudo funcione bem. Outra parte é que você também pode criar modelos estatísticos para entender
1:46:47 seus padrões de tráfego ao longo de um horizonte mais longo. O cluster também pode prever dinamicamente, de certa forma, os picos de tráfego e escalar com base nisso. >> Se estiver com o navegador aberto, posso mostrar onde fica. >> Abra o navegador e eu mostro. >> Certo, este foi implantado com sucesso. >> Agora vamos fazer um teste rápido de carga e, quando terminar, poderemos ver mais.
1:47:18 Certo. Mais alguma pergunta? A maioria das pessoas foi embora, mas >> sim, tipo H. >> Sim. 32. Foi aí que vimos o limite da última vez. Quando chegarmos a 64, devemos ver uma melhora. Certo. Houve uma melhora bem grande. A taxa de transferência aumentou bastante. Está em 1.100 tokens por segundo. Antes, se olharmos aqui, com 64, estávamos em 800 tokens
1:47:52 por segundo, e a latência era de 2.000 milissegundos. Mas agora, depois da alteração que fizemos, são 1.100 tokens por segundo, e a latência é de 800 milissegundos. A latência caiu bastante e também aumentamos bastante a taxa de transferência. Esse é o tipo de ajuste que você pode fazer com o tempo para garantir que tudo esteja funcionando bem depois de colocar o sistema em funcionamento. Você pode fazer isso para seu caso de uso específico. Talvez você não receba
1:48:23 seis, quer dizer, 64 solicitações simultâneas para determinado caso de uso, mas talvez receba. Então, você precisa decidir com base nos seus casos de uso. >> Sua concorrência ficou mais alta do que antes? Foi uma troca que você fez? >> A concorrência pode ficar um pouco mais alta ou mais baixa. Não vai ser igual o tempo todo. Por exemplo, antes era 37, mas agora é 35. Então há uma pequena variação que acontece ao executar modelos, mas
1:48:53 deve ficar dentro de mais ou menos dois segundos, dois tokens. Também estamos usando agora o modelo de precisão completa. Não estamos mais usando o FP8, porque tivemos que trocar o notebook. Esse é outro motivo para você ver a queda de algo como 50 e tantos tokens para 30 e tantos tokens. Esse é o desempenho que estamos vendo. Mas é isso que eu tinha para apresentar. Esse é um parâmetro que você pode ajustar. Há também vários outros parâmetros que recomendo a todos que consultem. O workshop também passa por eles. Mas acho que estamos no horário, então vou passar a palavra
1:49:28 de volta para Dwan. >> Sim. Obrigado a todos por participarem da nossa sessão hoje. Se ainda não escanearam o código QR, o código, o repo e as apresentações em PowerPoint estão disponíveis neste site. Sintam-se à vontade para criar uma conta gratuita no AMA Cloud. Meu nome é Du’an Lightfoot e estou aqui com meu colega Khaja Omer. Agradecemos a todos por terem participado hoje. Sintam-se à vontade para nos fazer perguntas depois desta sessão. Obrigado.
1:50:07 >> [música]
Transcrição original
[00:12] I mentioned before my name is Dewan Lightoot. I’m a developer AC advocate at Akami and this is my colleague. >> I’m Kaja Omar. I go by R. I’m a senior software engineer at Akami. And we’re going to be talking agents that own their own inference, building production AI agents on dedicated GPUs. Now, why are we here? Things are kind of changing. And for me, I started building agents before tool calling. Back in January 2023 is when I
[00:44] built my first agent. I would take a prompt, that context was about 8,000 tokens at the time, and I would parse that prompt and then make a tool call with Python and then give the response back to an LLM, right? But as I was doing that, I found something interesting. It can get really expensive, right? And then I started using local models to figure out, okay, how can I do this? And then I learned something else. There’s another
[01:14] challenge around that because if I’m using a smaller model, it may not be as capable and then I may be compute bound that memory in that GPU may not handle the larger context. So that’s the inputs and outputs and then the multiple turns in the tool cost. How do we get the most either the GPUs, the costs, the latency that we need in production or just for our own use cases, right? So the reason why we’re here, we’re going to talk about agents that are often renting their intelligence and then how you can take
[01:48] back that control and own it. When it comes to an agent, it’s just a loop. You invoke an LLM, it has access to tools, it has access to an environment, makes a decision, a reasoning decision on what actions to take once you invoke it or give it a prompt. And then those actions are being performed by your tools, your Python code, your other programming languages and then given back to a model. The model evaluates that the actions, the results and then updates the plan, takes additional actions or the goal is
[02:21] achieved, right? But all that requires tokens to be generated, right? And depending on your application can lead to latency challenges. So we’re going to talk about how you can actually man manage all of that on dedicated GPUs. So what does it mean to own your inference? First, when it comes to owning owning your inference, you actually own the GPU or rent the GPU. So when you do that, that means that you have access to the GPU, the hardware for that AI to be ran on, for the models to
[02:57] live on, which means then you have access to control where it goes. So the data never leaves your cluster, never leaves your data center, never leaves your laptop, right? You now own that intelligence and what’s happening with the model. And if you’re in the cloud, you can also do something like private VPC endpoints or have it in the VPC so it never leaves your VPC. Right? I know we all have different environments, have different ways to set up our infrastructure. We can talk about all of those.
[03:30] Now what’s the difference like when do you own when do you rent? Well, first if your usage is high and steady, why is that? Yes. >> Yes. At the end of the talk, I’ll have a link to the slide and everything that we showed code, everything. You can download it and take it with you. So, thank you. Now, when do you own if the usage is high? Right? If you’re constantly have a workload running, because if you’re paying for a GPU, you’re renting
[04:03] a GPU. What does that mean? that GPU should always be working. Otherwise, what are you paying for? So, that’s something you got to think about. Then, when it comes to the data, if you need that data to stay private, if you need to own the data, you care about your intellectual property, or you have some governance and compliance reasons why you can’t use a public provider when it comes to AI, that’s another reason you want to own. And then the hardware, that’s something we got to
[04:33] think about your hardware. If you can afford the capacity and you have the capacity, why not run those models, right, for your use cases because then you have that full control. Now, when do you rent? If your traffic is low, bursty, you just need intelligence sporadically, it might not be efficient for you to own some GPUs. Next, well, we start talking about intelligence. The more capable models, they’re going to cost for those
[05:03] GPUs. And often times, those providers will provide that intelligence on the GPUs because they have the infrastructure for that. So, it may make more sense to use those providers to get that intelligence, get those benefits. And then the next part which is often a challenge is that your teams may not have the knowledge or the expertise to support dedicated or self-hosted AI. Now today’s agenda we’re going to start out discussing some of the foundation you need to understand like the infrastructure stack we’ll be using
[05:36] units and memory budget. We’ll look at prefield decode and KB cache and what that looks like. And then from there we’ll look at dis dense models verse mixture of experts so you understand what that actually looks like on the GPU and why you would pick one or the other from there will discuss how to optimize your inference right once you figure out okay we want to do self-hosted how can we optimize this to get the most out of our GPUs the inference engine that we
[06:07] run and just our entire workload and then finally from there. We’ll take that agent and deploy it into our own dedicated cluster. With that being said, I’m going to pass it off to you, Omar. Right. Thank you. So, next uh we’ll talk about uh the environment that you each of you is going to get for this workshop. Um we have a Kubernetes cluster with around 200 plus GPU nodes. Each of you gets a single GPU. Um and we have set it up in
[06:41] such a way that uh each of you gets sort of like your own namespace and within that namespace you will have like your Jupyter notebook running and then you will have your VLM inference endpoint running as well that you’ll be playing around with. Um and then we’re also going to be deploying uh the agent on there as well. Uh the cool thing here is that the VLM endpoint that we have running in your namespace, you’re going to be optimizing it uh as part of uh um after the first four modules. And um I think that’ll be pretty interesting.
[07:13] We’re going to look at different techniques that we’re going to be using there uh to do so. And you’re going to redeploy this VLM endpoint over and over again until you have sort of optimized it to increase the throughput uh reduce the latency and uh make sure like you’re meeting all your SLAs’s. And then the other thing I want to talk about is uh GPUs on LKE. So I work on the Kubernetes side of things at Okami. Um so this is sort of my wheelhouse. So if anyone has any Kubernetes related questions, uh feel free to ask anytime.
[07:47] But I want to talk about what Akami has. So we have the uh we’re going to be using the RTX 4000 ADA GPUs. Uh we also have other GPUs available. Uh but these are dedicated GPUs. EGPU has 200 uh eGPU has 2 GB of uh VRAM with 260 GB per second memory bandwidth. So the decode will be pretty quick because of that. Uh we have high performance in Tflops. Uh large amount of CUDA core. So the pre-fill will be pretty quick as well because of that. Uh currently for your
[08:18] workshop we will be using a single GPU but that doesn’t mean when you want to deploy this at the end on your own you can have different plans that we offer as well where you can have up to four GPUs in a node. So that goes up to 80 gigabytes of uh VRAM on a single node. So you can deploy uh decently sized uh models on there as well. Um and uh everything is sort of orchestrated by LKE. So setting up the node, uh deploying the drivers, uh setting it all up for you. So that way you don’t have to do anything manually. Uh everything
[08:48] is sort of like one click. You click a button, everything gets deployed and you’re off to races. Um yeah, for more information, we have a link here as well. Um and at the end, you’ll definitely get all these slides. So you’ll be able to get to the pages and then um I’ll give it back to Dwan. >> All right. So for the inference engine, we’re going to be using V LLM. Now, some of you may have heard of Lama, which is great for local, but VLM offers some benefits that are better for
[09:21] production. One of those being being continuous batching out the box, the other being page detention. Now, it also supports the Open AI compatible API. So if you’re using whatever SDK that supports Open AI, you can use it with VLM. It also allows you to do some really interesting tweaks when you’re setting up inference for your for your endpoints and for your applications. Now, I mentioned continuous batching. For those
[09:54] of you that don’t know what it is and how it actually works, this happens at the prefill stage, right? the prompts come in and normally with static batch, let’s say you have a school bus full of kids. Well, in order for you to drop get new kids with static batching, you have to drop off every kid one at a time and then once all the kids are dropped off, you go back and get the rest of the kids and then start the next batch. But with continuous batching, you can drop off a kid and pick a kid all at the same time. This is way more efficient when it comes
[10:26] to the KV caching that happens during the preill stage. now or when it comes to page detention. Paged detention is when you think about the KB cache and you think about what’s actually happening there’s memory space that happens. So the prompt comes in and the longest prompt is going to take up memory space. When you when page attention that memory space gets allocated even for smaller prompts, right? But with page attention now that is all managed through c with the VLM
[11:00] that ensures that you can continuously pro process generate and batch those requests as they come through VLM. It has auler that kind of manages the batching, but it makes this really efficient. Now, there are other service engines that are out there, and we’ll talk about some of those in this workshop. With that being said, some of the metrics you’re going to want to care about is going to be throughput, right? To understand how your GPU is performing that time, the first token, understand
[11:33] that, okay, you sent a prompt. How long does it take to get the first token back? from there that KV cache utilization. We’re going to look at these metrics and show you how to get all of that out of VLM and then the QEP. So these are some of the metrics as we’re going through this workshop you’ll you’ll see and be able to better understand. And with that being said, we’re going to access the environment. So if you can scan this QR code, pull out your laptops if you want to follow along. If not, you can follow us as we go through the workshop. In this Jupyter notebook, we
[12:04] have nine different labs that we’ll cover and all of the resources and dependencies are loaded into this environment. Now, if you want to look at the code and try this on your own at home, I do have the repo public on accommoders. I’ll have this link along with the presentation and everything that we shared available with one QR code that you can download. And if you need me to make a short link, I will.
[12:36] All right, with that being said, we’re gonna start with the first module in the workshop. If everyone is connected. >> Yeah, it was kind of slow for me too, which is why I went to my own leak shortener because I kind of made that really fast with Russ. So yeah,
[13:07] >> hopefully like if you do have a hot spot, I would use your hotspot. Um but we’ll try to make the best out of the experience. Sound good? Awesome. All right. So in the first module module, we’re going to talk about the inference stack. We’re going to connect to our VLM endpoint, understand it, see how it generates tokens. We’ll also look at building our first agent. some things that we need to know, look at some met some metrics and then understand the model that we’ll connect to. The model that we’ll use is going to be Quinn 3 4B, but we have several
[13:42] models that sit on a PVC that you can actually load and unload for this endpoint. Now, when we talk about VL LM, one of the things about it is when you serve an endpoint, it just has one model, right? So if you want to serve two models, you’re going to need another V LMA endpoint, right? Which means you may need some model routing, a gateway in front of it to kind of handle that. Now, it does support authentication, but there’s no authorization. So you may
[14:16] need a gateway around that, right? So agent gateway is often kerve is another one. Um, any others? >> There’s LLMD. There’s there’s all sorts of open source tooling out there that lets you do that. Uh but the main but the main one is like Kserve is what we use a lot. Um and it’s it’s pretty good and doing the scaling, doing the routing and the authentication as well, right? Another thing it doesn’t have is rate limiting, right? If you’re processing requests, you may want to rate limit. So again, you want to find a gateway to put
[14:47] in front of it to manage those requests and also handle the routing. I mentioned that when it comes to the runtime there are other service endpoints that or service runtimes that you can actually use for the server. SG lang is one, tensor RT is another and llama CPP which we do go over this later with a little bit more in depth so you can kind of understand it. Now in this environment you are connected to a Jupyter notebook that
[15:20] lives in the name space. You also have the VLM server endpoint that you’ll see here in a moment. And all of this is in its own pod. And then you’ll have another pod. Well, another pod that you can launch for the agent. And we’ll see that too. So, let’s go ahead and install our dependencies. So, we’ll install our dependencies. I’ve kind of already ran through this, so some of this is already loaded in my runtime. I figured we don’t know how the internet will be, right? But the good thing is once you send a request, it
[15:52] happens within the cluster. So once we send our first request to understand how we’re configured in VLM, you can notice the model that we have the name of your name space inside of the cluster. The coupube config is just for your namespace. So that way nobody can access anyone else’s namespace in the environment. And then we don’t have an API key set, but you can set one with V L.
[16:26] Now from here, we’re going to use the open AI API compatible endpoint to be able or API to connect to the VLM QN 34B 4 billion parameter model. I believe we’re using that at FP8, meaning that it actually sits at um eight billion parameters. Is it eight billion parameters? >> No, four billion parameters. >> Four billion parameters. >> We’re using BF16. >> Oh, BF, that’s what it is. >> Four precision. >> Yeah. So, we’re using BF16 full position. So, you times the bits or
[16:59] bytes or parameters by two. So, it’s 4 billion, which means it’s eight gigs on the GPU. Now once we invoke we got our response for the model and we can see what it was actually served by. Now this was all within our cluster. That was pretty fast, right? It lives within our cluster. So hopefully with this experience since we’re not hitting the public API, we’re already connected to this HTTP. It’s going to happen right inside of the cluster. The response
[17:30] should come back a little faster. Now we’re going to trace send a trace in the end so we can actually understand how this actually looks like when it goes through the prefill the KB cache and the decode phase. So here we have our stream that we’re going to configure. We’re going to look at the chunks and do some calculations. We’ll get that time to first token so we can understand that. We’ll see how all of this is generated here in a moment. So if we run this,
[18:03] I ran that one again. We’ll come down here and run that. This may take a little bit to go through, but we should see time. The first tokens took 37 milliseconds and time output token, the decode phase, which means every token after the after the time of first token, right? That’s going to be that inner in interle latency, right? that inter latency that happens when those tokens are processed. So, we’re calculating that and we’re getting about 40 tokens per second, which is probably going to be our cap.
[18:37] But when we start talking throughput, that kind of changes because this is just one request. But imagine if we had hundreds of requests or 16 requests, that throughput is going to be a lot higher, but they’re still going to be capped at that 40 tokens per second, right? Or it could go down, but we can still get more on that throughput. And I believe Omar will go deeper into that. So one of the things that I want to showcase is the question is around why don’t you just run this on CPU? Um I didn’t want to do CPU on environment
[19:09] because this this um pod for this or this container for the Jupyter notebook is only one gig, right? So trying to run a local model on this is gonna it’s just going to crash. So I kind of simulated what that would look like. But if you’re trying to run a local model on CPU, it’s going to be a lot slower, right? It can’t do the complex multiplication in those matrices like a GPU can. That’s the purpose of a GPU. It does all those all that math in parallel, which makes it a lot faster, right? So, we simulate this on on the CPU.
[19:46] And then from there, we actually look look at this on the GPU to see how that looks. We got 45 tokens per second. And one of the things about this and which is interesting to me is that I do a lot of I would say local models and running them. But 45 tokens or 39 tokens per second isn’t that bad for an application if you’re running it for a specific use case. Right? If you have a
[20:20] specific use case and you don’t care about the latency, you don’t care about those like if you have a chatbot, you want that kind of that first token to come fast. But for a standard application where you just kick off a job in the background, well, that 39 tokens per second may not be that bad, right? So sometimes a lower token per second or a lower time to first token may not be as important depending on the application and the latency that you care about, right? you may care more about the intelligence in the job getting done than you do actually how fast it actually happens especially like
[20:53] I said if it’s a background process. Now here we’re going to build our first agent. Now for those of you that when we talk about agents there are no tools in this agent. So it’s actually just a request but just the foundation of the agent. We’re giving it a system prompt so it knows it role when we do give it to us later on in the course. But right now we’re just giving it a single prompt and we’re giving it a role as system as a solutions architect agent for Akami
[21:30] and you can see that it was able to generate the response. Now, this response pretty fast. It works. But then the question is, if we’re trying to do this at scale or we’re trying to build an agent that does more than just take it take a prompt and generate a response, it may need to make multiple tool calls, right? So, that’s when you start to think about things like the KB cache. You start to think about how much context because
[22:05] when we started talking about that KB cache, that’s actually how much context you can actually fit on that GPU, right? And so with continuous batching, what happens is you send a prompt to the model. Well, you may have 100 users trying to send prompts at the same time, right? Well, continuous batch, they’re all going to be different sizes. So, a smaller GPU can actually handle a bunch of requests if you’re using some with something like VLM. Now, if you’re using something like Olama, you’ll see you’ll get throttled a lot faster because it
[22:35] doesn’t process those requests the same way. But VLM actually handles that with theiruler a lot better. And so here we’re going to set up our our our agent and invoke it and we’re going to actually going to look at the steps. Now the code that we’re using for this is inside of common and you can actually look at all the code that we actually are importing that is custom code. So here we have this foundation.py that allows us to do some measures
[23:10] measurements from with Prometheus from VLM right we can look at those metrics. Now speaking speak speaking of metrics you can use Prometheus and you can use graphana right at home I always use graphana also when I’m building my agents outside of just looking at the metrics another thing that I always build one of the first things I build into my agents is observability right lanefuse that’s something I commonly use how many of you have heard of lanefuse now there are other tools out there but it’s open source you can run that in your cluster as well right beside your agents and then have access
[23:43] that now your observability is private as Right? And you can see every step, every trace, every span in your agent with how many tokens, what was the latency, not just from the time the first token, but for every tool call, right? If you’re trying to troubleshoot or you’re trying to evaluate now, you can see all of the latency steps in the spans. But then you can see, okay, I’m using a smaller model and it’s making way more tool calls. It’s taking way more time than it should. Why is that? Well, that’s where
[24:13] evaluations come in and OM will talk more about that. But it’s important to have that visibility into your agents so you can understand when you’re using a smaller model how to optimize. And that could be something as simple as a prompt removing tools or making the agent just a little bit more specialized. And so we’ll run this. And so we’re looking at the steps. We’re going to look at the max tokens
[24:45] and we should see the time to first token. So you can see as we increase the tokens, what happens to the time to first token in millisecond as we increase the pump, right? As the prompts get larger, that time the first token takes longer, right? So the question is what do you optimize on? Do you optimize on the median or the largest? Right? The one that took the most time doing the latency. Well, you’re going to optimize on the one that takes the most time rather than the median, right? And then that way you can increase your median by doing that.
[25:20] Now, [snorts] here we talk about renting versus owning. We’re going to look at tokens. How much are being generated? This is where I I mentioned that if you’re using bursty where you’re not using invoking a model as much with a provider versus if you have a agent [snorts] or some agentic applications that are always working you can kind of compare that cost. So here we generate a response just to get those tokens. And now we’re going to actually look at the billing and compare which one would actually be more
[25:53] efficient. So, if you’re processing, let’s say, 200,000 tokens per day on a hosted bill, rent it, that’s going to be about 1,500 per month, right? But if you’re renting a GPU, that’s going to be about a,000 per month. Now, it does matter the size of the GPU, the size of the model, the if it actually performs the way you need. But these are some of the things you think about when you’re trying to compare, should I rent versus own? You can actually do the math on that to break that down.
[26:25] And we already talked about these with the data resiliency, you know, the compliance, the security, the controls, and all of those good things when it comes to running locally. Now, before we go, the runtime landscape, I mentioned that we’re using VLL, but you can also use SE lane, which is good if you’re using if you have requests that share long prefixes, multi-turn chats. So for agents a lot of organizations are using SG lane for that. When it come to tensor well this is about that peak throughput on Nvidia hardware. It really
[26:58] specializes in providing you that and then llama CPP for that edge that that really fast processing. It can help you with those heavily quantized models like on the ARM server. So we’re going to invoke one more time here and we’re looking at our client just to verify that we’re still good. We’re verifying that we can connect. We can see the model serve and we can see the ID and I believe I can print the entire so we can see how that require that
[27:30] request actually looks when it comes back. So I’m going to print this whole thing as well. So we’ll and now you can see and actually let’s pretty print it. So we can see it even better. There we go. And so when that request comes back, you can see the ID, you can
[28:00] see the max model length, which the that context length. You can control that, right? You can tweak those parameters of course when you’re working with a model but we can see everything about the model itself. Now we’re going to move on to the next session. Um this will have some taking it further when you can explore the cluster explore vm you can feel free to do that in this notebook. So I’m going to close that
[28:32] out. We’ll discard that and we’ll move on to units and memory. Now the next section and I’m g kind of go faster so Omar can has some time. Now when it comes to units and memory, we’re going to talk about the ceiling when it comes to token per second on using a model. We’re also going to look at the model’s real config and understanding how a model actually is sits and how actually looks um when it comes to a GPU. So here, like Omar mentioned, we
[29:03] are using and I’m going to make that a little smaller. Let’s see if we can get more of that on there. All right. So when we talk about the the model actually sitting on the GPU, you have the model weights for the 4 billion parameter model, that model weights at BF16 is going to be 8 gigs. So we have 8 gigs and the rest of the room is going to be for KV cache. Meaning how much context can you fit on that GPU? because it all has to fit within there. Now, when your prompt comes in, when we talk about prefill, the model is going to
[29:33] read that entire prompt and store it in the KV cache. And then every time it generates a new token, it’s going to update that prefill. So, that prefill is going to grow, right? So, just because your your your prompt that goes in is one size, as it goes through and is processed through the model, it’s going to increase as it generates, right? And then imagine the tool calls, the system prompt, all of these go to the model and all of that has to fit on the KV cache in order for it to be able to handle your request efficiently. And so we’re also looking at um if we’re using at FP8, which is going to talk
[30:09] about quantization and what that actually looks like to shrink a model and to still get the efficiencies that you’re looking for. Now we’re going to install our dependencies and then from here we’re going to connect to verify what we have loaded. So again we have the Quinn 3 4 billion parameter model our workshop namespace the cluster API key.
[30:40] Now when it comes to models we have the config.json JSON like what is actually that file when you download a model you get the config.json let’s say you go to huggerface you download a model you’re going to get a collection of files all of those files are needed right you’re going to get the config.json JSON you’re going to get these save.tensors tensors. Those tensor files are the model weights, right? But the configuration is what tells VLM how to handle that model, right? So you can actually look at this and explore those files to understand
[31:11] what they actually look like. So here we’re showing what that configuration file looks like. So we have 128 layers. The size is 1,024. The attention head, there are 16 attention heads. The values are eight. Vocabulary size, right? How does the model train? What is the vocabulary size of that ma model? Right? You can actually look at these configurations. Can you modify them? No. Right? These files cannot be modified. But you can fine-tune. Right?
[31:43] You can use lower. You can do all these things to adapt the model. But to modify these files, if you try to do that, it’s just going to crash. It’s not going to load. Now here we’re going to look at the bytes per weight and where it comes from and we calculate here we’re looking at a smaller model at BF-16 for the 6 billion parameter model and the parameters you multiply by two 1.5 gigs and for the 8
[32:14] billion parameter models what those params look like and it’s gonna be eight gigs and if we compare the BF16 versus FP8 Now, when we talk about pre precision, most models when they’re trained, they’re going to be at sometimes FP32, but you’ll often get it at FP16. Full precision, meaning that you multiply whatever the model size by what? Four by four, right? So, this 4 billion parameter will be 16 gigs at full precision, right? on your GPU when you quantize it down to let’s say FP8
[32:53] well you kind of lose a little bit capabilities of the model but not much right but that’s when you start to evaluate right if your compute constraint you have this larger model maybe 70 billion parameters that maybe you can do it at FP8 or maybe with int4 right all the way down to where now that 70 billion parameter models is rather than 32 is 16 gigs, right? If that’s possible, right? I don’t know how much you’re going to lose for the position,
[33:26] but you’ll have to evaluate that. And so evaluation hardnesses are important. So we’ll look at the GPU where the weights live. So here BF16, you multiply by two, FP8, you multiply by one. We’re looking at this for Quinn. And then we have another model that we’re going to use in this course where it’s say at 8 billion parameters is five gigs on the GPU which you can see how much you save with the still intelligence that works for the
[33:56] use cases that we’re discussing if you decide to quantize down. So we’re looking at this card the gigabytes per second. you take the where we’re actually calculating. Okay, we know how the speed of the GPU is 360 and we’re showing how to calculate to get the tokens per second and where we’re actually bound. So, we’re going to be bound by the speed of the actual GPU on
[34:27] how fast it can go. And we’re showing the math for the KV cache here. And I’m trying to go a little faster so we can get into the quantization and optimization. But if you go through these, you can read through it and understand how the KV cache formula works. Oftent times we may not have to go through this and figure it out, but you will have to when you’re trying to calculate, for example, you have a 100 users you want to serve. You have a smaller GPU. The question is I got this smaller GPU. Let’s say I’ll give you a perfect example. I had to do a workshop and I had to figure out how
[35:00] to serve 80 students and perform inference for all the students with about three or four GPUs that were about 20 gigs, right? Do I need that many? Is it going to fit? Well, how big is my context for the workload? What if everybody is invoking at the same time? Will the GPUs will the cluster support that? Will continuous batching work? So, you set up an evaluation to evaluate the entire workload and to determine, okay, is it going to fit or do you hit that roof line, right? Do you have start to have spill over the CPU? These is your application slowdown
[35:35] or the memory weights memory budget versus KV pool. So we’ll look at that and then here’s how you can actually get that the math. So here’s our we can get 37,000 tokens on this GPU right on the Sega GPU this 8 gigs for the model weights. And then the room that you have is going to be 37,000 tokens, right? And so if we have multiple users sending requests, right? Well, this will show how many users in their context list. So if we have four users, they can all send
[36:09] 8,000 tokens, right? For input output tool calls, this going to add up to 8,000 tokens at the same time on that GPU. And now we’re showing the tax as this increases the different requests and the generation of that request. And this kind of shows how to do that math when you’re trying to understand your compute constraint, your GPU, and then the workloads that you’re
[36:40] performing. So you can take all this code and apply it and be able to take your use cases and do the math on it so you can see if it fits on your GPUs. So we will go to the prefill and decode. So going a little bit deeper into the prefill and the decode in the KV cache. Again, we’re using the Quinn3 model, but we’re actually going to dive in to see how this looks. So we have the prefill,
[37:11] which like I mentioned is going to be focused on that time to first token, right? from the time you press send, how long does the first token, if you’re streaming, right? Because if you’re not streaming, you’re just going to get the whole response back. But if you’re streaming, how long does it take to get that first token back, right? And that’s going to be that prefill stage. And then the decode is going to be that token, every token after that, that’s all measured. And if you’re looking at the metrics inside of VLM, you send that to Graphana, you can actually view that on the dashboard and you can watch,
[37:44] okay, as I increase my prompts, you can watch it increase, you can watch it decrease, right? Right. And really understand what’s actually happening on that GPU when you’re sending requests. So, we’ll go through here. We’ll install our dependencies. Then from there, we’ll look at our environment. Make sure we’re connected. Yes. And we’re still using the Quinn 34B. And we’re going to look at the self attention, meaning how does that KB cache get processed. So this is the
[38:16] actual formula. So you can look at that soft max to really understand how that KB cache is being handled within a model. We’re just doing it by hand just so you can see the math on that. And so when it comes to the KB cache, there’s the naive approach and there’s the KB cache approach that I would say is handled. So the naive approach is you take a prompt, the model looks at the whole prompt and then one by one stores that prompt in the KV cache and
[38:46] generates a response. What KV cache does, it says, okay, I’m gonna take the prompt, I’m gonna learn from it, and I’m gonna store it right in parallel. And so the KB cache allows you to learn from the prompt to be able to reference the information rather than just doing the fixed sequence of the naive caching approach when it comes to handling that KB cache. And so if we generate this, [snorts] we can look how it computes
[39:19] the reduction of how much if you use the KB cache approach rather than the naive approach and we’re just showing all that by hand in code so you can really break it down and understand. And now we’re going to look okay using K KV caching and we’ll measure the time to first token. And so here we have 57 milliseconds and then the decode was 25 milliseconds. And so we’ll continue on
[39:53] and we can see what VLM is actually exposing. So we can actually look at those metrics and we’re just showing some of the metrics that are actually being exposed and how you would view that in VL. Now we’re going to invoke the prompt and we’re going to increase it and you can watch that KB cache fill and you can see this is going to take a little while. So we’ll give it a couple minutes while this process we’re increasing it. So we can see the KB cache usage and we can look at the metrics. So we have peak usage running
[40:30] and then the KB usage after it’s finished. And this will be the math on how you would process that. Again the worker that we’re using for this code is in the foundation.py. So that’s going to be the helper for this code. Now we’re going to look at the warm the code um against the warm prefix caching. Now preface caching is an interesting thing. Um don’t confuse it with prompt caching for and that’s something I should have mentioned before. If you’re using a provider and you’re paying by
[41:01] the token, prompt caching, especially if you’re do you have a continuous application that’s running within every five minutes, prompt caching is a must, right? You can you can decrease the cost by like up to 75% depending on who you’re using. So there is some ways you can use a provider and save on cost. But when we’re talking about prefix caching, this is caching that prefix for the KB cache. And so when we do this, we can see how this actually is handled here. So the code is going to be 220 milliseconds
[41:34] and it’s down to 41 milliseconds. And this all shows you how to do that in the code. So you can go through that. And I’m trying to go a little faster so Omar can get to his part and hopefully we can deploy. All right. So we’ll go back and we’ll go to the fourth section where we talk about dense model verse the mixture of experts on the GPU. Now when it comes to a dense model, what is a dense model? Well, a disc model
[42:07] when it sits on a GPU, that whole model is used to generate tokens, right? So, if it’s 30 billion parameters or let’s let’s just do the model we’re using now. So, the Quinn 3 4B at BF16 8 gigs on the actual GPU. Well, when that actually generates tokens, when it actually is working, that whole entire model is working, right? So it’s going to be a little slower than if you use a mixture of experts. Mixture of experts may be a larger model. Maybe it’s 30 gigs, but
[42:41] when it actually generates inside of the model, it takes a collection of experts and only that that section of experts does the generation. So even if it’s 30 gigs, it may be 1.5 gigs just to do the generation. So it’s going to be a lot faster. So that’s one of the benefits. Even though it’s a larger model when it’s a mixture of experts, it’s actually a can be performed a lot better within an application or a lot faster within an application.
[43:12] And so here we kind of talk about memory and why decode is memory bound meaning that when we talk about the generation phase after that time to first token when that generation actually happens that’s actually going to be bound by the memory. So when we looked at the speed of this GPU that’s bound, you can’t go any faster than that, right? There’s nothing we can do to tweak that to make it go any faster. But there are some things we can do to help this at scale. So we’re going to look at our roof line and plot that so we can actually see it.
[43:44] So we’ll make sure that we have our model loaded. So we had a quint 3 for billion parameter, right? and it’s going to be compute bound. So it’s going to hit that roof line. So we’re going to look at the flops. We’re going to look at this. So the ridge line is 297 flops per bite, right? And where this is bound by the memory. Now if we look at the mixture of experts, now we’re just going to look at this as code. So we can actually understand it. So at this 30 billion parameter models, right? 128 experts and only eight active
[44:20] per token. That’s 48 layers, 248 hidden. And so now the expert mixer expert, this is the weights. This is the share weight. So this is how much it how much is being used when it generates. That’s a lot that would be a lot more efficient than using a smaller model. It can actually be faster when it actually does the generation. And so here we’re looking at the the dense model, right? is nine times fewer bytes than a dense model, right? So it decodes a little bit
[44:55] faster. So that’s kind of breaking down the two when you’re actually trying to figure out, okay, do I want to use something like Mistro, right? Or do I want to use like a Quinn model, we compare the dent sizes. So here we’re going to look at the rate, we’ll look at the bandwidth, the GPU serve. So measured Quinn 4B is about 40 40 tokens per second, right? The smaller model of the Quinn, the 0.6. Now, this isn’t done on the CPU, but we’re just
[45:30] showcasing 300 tokens per second, right? But we’re looking at the ceiling. This is actually looking at the bandwidth and it’s doing the math here to get that the max that we can get. The ceiling that we have on this GPU is going to be 45 tokens per second. Now, if we enable reasoning on that model and we can look at that. Now, when it comes to these Quinn models, if you’re wanting to do any type of agent and the model needs to reason,
[46:01] meaning that maybe the prompt comes in, you have tools and it needs to make multiple tool calls. Well, you’re going to enable thinking. So now when it makes a tool call, if it gets the results and it needs to make another tool call or verify the results to make the accurate tool call, you’re going to have to enable thinking on these models. And that’s just a parameter that you can adjust in the model, right? But with thinking off, it just generated a response. It was 35 tokens. But with thinking on now, it had to think about it. It cost about 600 tokens. Right now with some of the models like provider
[46:36] models you can actually set a token budget for life of thinking. So that’s one of the things you can save on cost with a provider model and maybe some of the open models you can do that too. I’m not sure. >> Yeah, you can. >> Yeah, you can also adjust that token budget on the thinking as well. So more tokens on thinking isn’t always good but sometimes it can help the model better troubleshoot and better get to that end result that you’re looking for. And so when we talk about inference, there’s a lot of things to think about, but one of the things we want to think about is that memory bound limit for the
[47:09] actual card and then how to apply that for the agent. So we look at all of the modules, we talk about that KB cache, the prefix caching, the attention heads as well as quantization which um is going to cover here in a minute and then from there that continuous batching we also discussed that. So if we split the prefill from the decode, you have the prefill GPU pool and the decode which is memory bound. So the prefill compute bound, right? So it needs to go from your memory to the GPU and it needs to be cached, right? There’s
[47:43] [clears throat] that that phase you can you can do a lot of optimizations, but when it comes to the decode phase, there’s nothing you can really do because you’re bounded by the GPU. And so we kind of show this in code rather than actually showing it because again we [snorts] only have so much limitation in this workshop. Now with that being said I am going to make sure that we are good to go here.
[48:19] Um I don’t think I need to switch the mod. I think you should be good. Armor. I’m gonna turn it over to you. >> All right. >> And then Yeah, we should be good to go. You can talk about quantization. Thank you. >> All right. Thank you, Dwan. >> Yep. >> All right. So, let me close that. Sure. >> That That’s yours, actually. There you go. >> Okay. Cool. So, I’ll be talking about a whole different um uh optimization techniques I think you can use to deploy these models on Kubernetes. Um, like I
[48:50] said, uh, my background is in Kubernetes. I develop a lot of Kubernetes stuff at Akami and I work on the manage Kubernetes platform there. So, a lot of the stuff that we do is we want to make sure that we’re able to use GPUs on Kubernetes really well. Uh, use all the different features that they have. Um, and uh, we deploy a lot of these models using some of these techniques that I’m going to be talking about. Um, so there’s uh, different techniques. So, we’re going to talk about quantization. I think this one’s like the main big one. Um, it’s super important. We’re going to talk about
[49:22] speculative decoding. Uh, this is a pretty cool technique. It can give you quite a big uh performance boost in your uh throughput. Um, we’re going to talk about um like how do you uh you know uh tweak your LM uh VLM config to make sure that you’re getting max performance out of it and um you’re meeting your SLAs’s. And then we’re going to actually do some tuning and evaluating. So this I’m going to leave you guys with some sort of framework that you can use to figure out
[49:53] what exact configuration you need to use for your specific workloads and specific use cases. Um so I’ll dive into quantization. Um let’s see. And if we have time, we can definitely go uh we can have like a quick Q&A as well, but I think we have 30 minutes. I’m going to run through it uh at a good pace. So in quantization um there’s a whole lot of different uh there’s a lot of different types of quantizations you can do. Um you know there’s the BF-16 the the one that the
[50:25] model is going to start off with. That’s the full precision model that uh Quint provides you and then there’s a lot of other conversations on top of that. People have created FP8 that’s one of the models that we’re going to look at in this particular module. Um there’s INT4. Uh there’s AWQ GPQ uh GPTQ. These are different types of uh ways you can quantize the model. Um there’s NVFP4 which is Nvidia’s proprietary quantization technique that they use. Uh it’s hardware accelerated on black hole GPUs and more. Uh that one is pretty
[50:58] cool. Um but let’s see. Let’s dive into it. Um make this hopefully we can fit that in there. All right. So as you can see, you know, like if you have the BF16 weights, it’s going to take a lot of your memory. Uh in this particular use case, we have 20 gigs of VRAM and we sort of want to maximize how many requests we can serve with these 20 gigs. Uh so we want to make sure we have enough space for KB cache. Uh reason
[51:29] being the more requests uh the more KV cache you can have on the memory, the more requests you can process in parallel. Uh thereby increasing your throughput. So that’s super important. Uh so that’s why we essentially want to do quantization. We want to reduce the size of the model so that way you can fit more KV cache and essentially increase your throughput. Um so that’s one reason. The other big reason I think is also because you’re shrinking the weights essentially by in half. You don’t have to do that memory movement between the different uh memory hierarchies resulting in essentially
[52:02] faster decode as well. So we will see you’ll go from you know 40 tokens per second which is the base model will probably go up to like 60 tokens per second if not more. Um so let’s look into this. Let’s um install the dependencies and then I’m just going to make sure that the model is still available and everything is running. So yeah, we do have the model running uh the same four billion parameter model and it’s running in the namespace. Again, as I said, um sort of like a high level overview,
[52:35] there’s a whole different sorts of different techniques you can do quantization with. Um for example, like um uh Llama CBP is a pretty popular one for running a lot of these models at a lower precision. Uh that uses GGUF format. Uh that format is pretty cool. you can have um uh you know five bit, 3bit, two bit, one bit quantizations which is pretty interesting um and pretty cool but the the downside of that is you lose a lot of uh you lose quality trying to get a lot of performance out of it. So, there’s a trade-off there.
[53:08] Um, but for the most part, going from BF-16 to FP8 is a very negligible drop in quality and performance. Um, and it will result in more performance while keeping the quality exactly the same. Uh, so that’s what we want to showcase and that’s one of the assumptions we’re making. Obviously, like when you’re doing this for your particular workload, depending on what you’re using it for, I highly encourage people to have their own evals. uh me so that way if you’re switching from you know BF-16 your eval are saying okay everything is good everything’s running well for our workload you switch to FP8 you might
[53:40] have issues where some things are breaking here sometimes it’s hallucinating sometimes it’s going in a loop so a lot of those things can happen for very specific use cases and in those scenarios it’s very important that you have your own eval set and you’re running your own evals to make sure any changes you make um are uh okay to make and also you don’t have any degradation in performance Um again we’ll run and make sure that we have the BF16 base and then we’re going to measure the performance. So uh we have a little load test uh utility
[54:14] package that we use to do some uh testing. Essentially what we’re doing if you look at the levels where these are like a at different concurrencies we’re making this request. Each request is going to have about 256 tokens and the output is roughly going to be about 128 tokens. So this is sort of trying to simulate how many requests you can process at one time and we’re sort of going to use this as a baseline to see what the baseline performance is. Um so for 32 uh we’re getting aggregate performance of 714
[54:49] tokens per second which is pretty good. uh at single concurrency we’re getting 37.5 tokens per second. Uh so that’s important to uh note down. And also we’re getting um uh 61 milliseconds for time to first token. And then you’ll notice the time to first token goes up, right? Like the jump between 32 and 64 is quite large. We’re going for 277 milliseconds to uh 1300 milliseconds. That’s a quite a big jump. and you might not necessarily want
[55:20] to make that trade-off, meaning you might want to potentially stop at only 32 uh concurrent requests that you’re processing and not go higher than that. So that is an important thing to notice there. Um again as I was saying um eval are extremely important. Uh reason being again you can have performance degradation when you do quantization and you can lose uh some intelligence reasoning can uh not work as it should there there’s going to be a lot of
[55:51] issues. So you want to essentially I’m kind of simulating here like a uh at a very basic level what kind of eval you might want to think about. Um, you know, you want to think about like if the JSON is being generated correctly, if the JSON is being corrupted when you reduce the quantization, you know, at uh BF16, you might have good uh responses, but when you go to FPA, maybe potentially your functions function calls are failing. Why is that? It’s probably because it’s not generating the JSON correctly. So, there’s a lot of these um
[56:21] eval cases that are already out there that you can kind of use in the open source. Hugging face has a lot of evals. You can go on GitHub, you can find a lot of these, but you want to come up with your own for your own use case. Um, but then so next thing what we’re going to do is we’re going to switch from BF16 to an FP8 model. So we are going to essentially reduce the size of the model in half. And once we do that, we’ll kind of get to see um what the performance differences are and are they worth it and are we losing any quality over it.
[56:53] Uh so to do this uh you will need to be in the root and then click on manifest and in there you will see vlm.yaml. So um I’ll kind of go over this. So this is a typical manifest uh configuration file that you uh uh have for Kubernetes deployments. Um how many of you have used Kubernetes before or have knowledge of Kubernetes? Okay, quite a few. Okay, great. So this will be quick. I don’t have to go over all all the details, but
[57:25] essentially we have um a PBC which is going which is essentially our cache where all of our models are living and we have a simple deployment with VLM with a lot of different arguments and flags here. Um so you can see we’re using the Quen uh 34 billion parameter model. Um, and then we’re going to switch it to this FP8 version from Red Hat. Uh, let me
[57:56] one more quick thing I want to quickly mention is you see the dynamic at the end. Uh, this is pretty important. This means that not everything in this model is quantized to FP8. In a lot of cases, in a lot of different quantization techniques, you might want to quantize the model uh only specific parts of the model and not the others to make sure the performance stays the same and you don’t have a lot of uh issues there. So that’s one of the reasons why you’ll see dynamic, you’ll see all kinds of things. You’ll even see quantizations where certain heads of the model are going to be 4bit and then some are going to be 8
[58:27] bit and some are going to be full precision. And you know, it’s it’s sort of uh interesting that people are doing that and finding a lot of performance there. They’re they’re finding the performance gain while making sure the quality stays the same. So once this is uh changed, we’re going to save it and then uh we’ll just quickly go through and run it and apply it. So this is just making sure that the diff is good. Um we’re not causing any issues here. Uh that should be fine. And then we’ll just go ahead and where’s
[59:01] apply? Right here. We’ll just go ahead and apply and that’ll roll out. Um it’s gonna take uh a little bit of time. Let me save that. But another thing you guys can also do is you can open up a terminal tab as well. Like if you just click on the plus sign and then you’ll see a terminal option and then that will also let you see sort of like what’s in your nameace and what you can do here. So if you get you see the VLM endpoint is still coming up. Uh this pod is
[59:31] essentially your Jupyter notebook running within your namespace. Um let’s see this will take a little bit of time to come up. Yeah. While this is coming up, does anyone have any questions? We can probably have one question in >> cont. was pre-quantized already. >> Yes, it was pre-quantized. Yeah, you can
[1:00:01] quantize your own models. There is LLM compressor. Uh it’s uh it’s provided by VLM, I believe. LM compressor. So there there there is tooling out there for you to do this on your own if you would like. Um, but yeah, the one that we’re using currently is already pre-quantized that we downloaded off of Hugging Face. All right, I think that should be up. Again, it’s taking a little bit of time,
[1:00:31] mainly because it’s taking all the weights out of the VRAMm and loading the new weights in. So, it’s going to take a little bit of time to do that. Um, anyone else have any question? I’m sorry. >> Look at your your VL your YAML file for your arcs. Look Oh, looked like they had uh two flags on the model. >> Oh, they did. Oh, that’s a good call out. Thank you for that.
[1:01:04] Did not see that. All right, we’re going to go through it again. Let’s rerun that. Okay, that’s probably why it didn’t come up as quickly as it should. Oh, I can’t do that. All right. Any any other questions while this is going through? Go ahead.
[1:01:35] >> How do you choose between? >> Uh, how do you choose between FPA and intake? Uh that’s a good question. So it depends right like int 8 is going to be slightly less precision than FP8. That’s essentially the reason. Uh the the difference is like FP8 is floating point so you get a little bit more precision out of it. Uh and then int8 is integer. So you could use either or. Uh again these are all the other options that you have. You can choose based on your workload and where your constraints are. Um but yeah you could totally go into
[1:02:08] eight as well and it should be fine. Um, where does it say that? >> Good. >> Stack. Oh, yeah. I mean, uh, oh, that’s the other good good call. Um, it depends on the GPU as well. Some of the GPUs might not necessarily support it. >> GPU support. >> Yeah. So, GPU support is important. That’s another good call out. So some of the um uh GPU might support it but it
[1:02:39] might not be accelerated by the GPU meaning you might not get the full performance that you would be expecting out of it. Um for example the GPUs that we’re using we’re using RTX 40008 they support FP8 and we’re going to get the full uh precision uh full performance out of it and it’s able to hardware accelerate all those calculations. But if we let’s just say use FP4, it won’t be able to do that and we would actually not see a whole lot of performance gains and we actually see performance go down instead of it going up. So that’s another thing to keep in mind. All right. Where is it?
[1:03:19] All right. It has successfully rolled out. So we’ll uh take a quick look. So now we can see it’s actually using the FP8 model now. And then we’ll also kind of quickly go through and do another load test. It’s going to be the exact same. We’re going to do it at uh concurrency 1 uh four 8 and uh 8 16 and 32 I believe over here. It’s going to be exactly the same. So and then once that is up we can compare and see the performance differences and
[1:03:50] why you would want to quantize. Okay. the performance is in. And if we compare it before and after, you can see, let me make this a little bit bigger. Uh, you can see even at concurrency one, you know, we’re going for 37.5 tokens per second to 53.4 tokens per second. So, we’re seeing considerable jump in performance here. Um, and then at peak throughput, we’re seeing uh at 64 concurrency, we’re going from 800 to,40. So, that’s about, you know, 1.4 four uh 42 times uh which is
[1:04:27] quite a big performance jump but again keep in mind the time to first token is going up considerably as well uh compared to 32 and 64 um but then yeah you can and then again you want to run evals um we can quickly run through this and it probably won’t have any differences so yeah again BF16 versus FP8 um there’s not a whole lot of uh performance degradation you should spec it’s it’s going to work out of the box for the most part but uh for
[1:04:58] specific use cases it might not but for simple eval cases that we had here it’s it’s working fine I think that is it for this module where we’ll jump into next is speculative decoding which I think is a pretty interesting one um let’s see let’s jump in here all right so how many of you have heard of uh speculative decoding before right quite a few people that is good. Uh for those who don’t know what speculative decoding is, let me make this smaller. Um it’s essentially we’re
[1:05:31] using another draft model which is going to be a much smaller model than the main model that we’re using and it’s going to generate multiple tokens ahead of time and then our main model which is the four billion parameter model is going to look at those generated tokens and it’s going to either say it’s it looks good. That’s it’s going to verify it and say it’s going to look good or it’s not going to look good. Uh so in this like diagram you kind of see like um the draft model you know generated four tokens ahead of time and then the verifier model which is our four billion parameter model is going to say oh only
[1:06:04] the first and second token make sense the other two don’t so it’s going to discard it and it’s essentially going to do this each time it’s generating new tokens. So it’s going to go in in a loop there. uh and uh for for this uh workshop we’re going to be using the 6 billion parameter model uh from Quen as a drafter model and see if that is going to either help us or not help us in a lot of cases uh it can also not help you and reduce the performance um and
[1:06:34] there’s multitude of reasons for that and we’ll go into that shortly. How are we doing on time? Good. uh just make sure we are good here target model. Okay, before we get into it, I also want to talk briefly about all of the different ways you can do um speculative decoding. Um there’s a lot of different ways and there’s more ways coming out uh every every few months. Uh but the you know the draft model is one way. Um, a
[1:07:09] lot of times, uh, a lot of new, uh, ways of doing it is actually using a diffusion drafter model, which I think is really cool. Uh, I personally use that for one of my home lab machines. Um, and, uh, that gives you a huge performance. The difference between that and this is because it’s a diffusion model, it’s going to be generating a lot of tokens uh, at once, uh, rather than doing what we do sequentially with LLMs. Um, and then the verifier model is able to verify X amount of tokens out of that. Um
[1:07:40] but but yeah there’s a there’s a lot of different types of uh methods you can use. You can use suffix decoding. Uh there’s a lot of times model would come with a built-in drafter model as well. So those are like the native models that are trained along with the main model. Uh so you don’t have to uh import another model to do this. Uh there’s medusa eagle again like diffusion dlash is a big one that uh has kind of been going viral and it’s working pretty well. So there’s a configuration you set for figuring out how long like how much
[1:08:11] it generates before the verifier comes in and verifies it. So you can set that you can set it to two tokens, four tokens and five tokens. And it’s important that you set it correctly uh because if there are for example let’s just say you set it at four and uh the model verifier comes in it’s like okay I only accept two that’s 50% acceptance rate and that is pretty bad. that’s actually going to have a negative impact because not only are you running you’re running two models so you’re spending compute to run two models and then you’re only getting 50% acceptance rate and that’s essentially
[1:08:44] going to result into a decrease like throughput. Uh so that’s not something you want. Um so that’s something you have to like kind of tweak and play around with and see how many tokens do I want to generate ahead of time. Um so yeah technically you could generate 15 tokens but you probably don’t want to do that. You probably want to do two maybe three maybe four. It also depends what type of um what’s it called? Um let me go back. Where is it? What type of method you’re using again? Like uh I use deflash uh for a lot of my home labbing. And uh that works pretty well if I set it to
[1:09:18] eight. And if I set it more than eight, I actually get a lot uh a lot less acceptance rate and that causes my performance to go down or be very flaky. Um but all right so we will next um >> you got one more question >> one more question. Hey uh sorry uh this is from the last module but uh how does dynamic uh compression work uh in a sentence or two I guess
[1:09:51] >> um so the way it works is if you do you understand um the different heads of the model uh different because there’s different layers within an LLM. So if you look at the model.json JSON, you’ll actually see there’s a lot of different parts to an LLM and there’s a whole pipeline that sort of like pushes the tokens from one thing to another. And a lot of a lot of times when you see a dynamic thing, it essentially is saying, okay, I’m going to only quantize uh the attention heads to FPA, but I’m going to leave everything else as is. >> I see. >> So, so that’s the reasoning. And if you
[1:10:23] remember from previous modules, you you saw that the FPA version is not exactly half in size. It’s not going four gigabytes, it’s like 5.1 gigabytes. That’s because not every part of the model has been quantized to FPA. So that’s like sort of the dynamic part of it. >> See, is the same math applicable to all the models or it depends model >> depends model to model. Every model has a different architecture. So architecturally speaking, it depends you know what parts of the model you quantize. uh there’s people who quantize you know some parts of the model to uh
[1:10:54] in4 but leave other parts to FP8 and then leave some parts to like BF16. So >> thank you. >> Yeah. >> All right. We’ll run through this again. I’m just confirming that our baseline is good. We’re using FP8 model here. Um and then uh we’ll do another load test quickly um sort of to get another baseline of um what it would look like before we implement and add speculative decoding uh to this particular
[1:11:26] deployment in VLM. And then while that is running, I’m just going to make sure uh to uh let me actually copy this correctly. Not that. Oh, never mind. You can just so in here um we are setting the speculative config. This so this is a particular flag you can pass in VLM to set the draft model. So we’re setting it to the
[1:12:01] uh 0.6 billion parameter model. And then we’re also uh setting how many tokens do we want to generate as draft tokens. So in this particular scenario we’re setting it to four. Again this is something you have to do a lot of testing on. Uh you have to try out do I want to set it to four? Do I want to set it to two? Do I want to set it higher? It all depends on the acceptance rate and uh how much performance you’re getting out of it. Um and then yeah once you set this flag and we will redeploy this. Um we go back in here. We got our
[1:12:32] baseline. And then let me make sure that it’s good. Okay, things look good here. And then we’ll go ahead and um apply and roll this out. And this is probably going to take another couple minutes. So, uh does anyone have any any questions? Go ahead. Oh, one second.
[1:13:10] >> I I noticed that you set the GPU memory utilization to 7 >> which leaves a lot of your um essentially leaves 30% of the VRAM >> unused. >> Is there any particular logic to that choice? Uh in this particular scenario um there could be a lot of reasons. Uh sometimes you know you might have multiple deployments on the same GPU and you want to make sure that you have enough RAM for something else VRAM for
[1:13:41] something else and then you keep enough VRAM for this but in this particular scenario not really. We’re going to bump it up in a following module actually. Um it’s it’s one of those knobs right like you have to keep you have to make sure that you’re setting the utilization correctly. If you set it too low, you’re leaving performance on the table. If you set it too high, um you’re going to um kill your node, and that’s not good. >> Yeah. So, this
[1:14:14] >> Okay, it’s still coming up. This is taking a little bit more time. >> Go ahead. from >> sorry one second >> uh the bump that we see from 60 32 to 64 parallelization it’s because of the key value cache just blowing out or I mean >> yeah yeah essentially the key value cache is blowing out and it sort of hit like its max limit and it can’t go above that uh so there’s a lot of reasons so
[1:14:48] there’s that part and then there’s also uh the continuous batching and a lot of times times will happen if if you don’t if you set the configuration to a level where the continuous batching is not optimal, it can also cause you to see like high tokens per sec. Uh uh you can see high latency there as well. Um but yeah, in this in this scenario, we’re essentially hitting like sort of like a ceiling on us uh uh for us in terms of how much VRAM we can use there. That’s why we’re seeing that. But in the following modules, we’ll see
[1:15:20] how we can improve that scenario and hopefully like make it better. Uh, okay. All right, we’re rolled out. So, we now have speculative decoding uh set up correctly. So, what we’ll do is we’ll do a quick load test again. It’s the same exact test that we ran up here where, you know, just keep in mind we’re getting 58.2 tokens per second for concurrency one and then 42 milliseconds of latency. So this is our sort of baseline before we do speculative decoding. Um but what I want to showcase here is not a happy path where you will
[1:15:57] automatically get a crazy improvement in performance. You’ll actually see the performance went down drastically. You’re seeing 16% uh 16 tokens per second whereas the baseline was 58. Um and then even the time to first token is sort of going uh up a little bit as well. uh and you know we want to figure out like why is this happening? So there’s a there’s a big difference and there’s a big uh decrease in performance like even if you look at concurrency 16 we’re going from 700 tokens per second to 240 tokens per
[1:16:28] second. So that’s a considerable decrease in our performance. So the way to interpret this is there’s a lot of different reasons. Um one is again as I was talking about earlier it’s the low acceptance rate. uh if your acceptance rate is very low and the verifier model is just it’s going to keep rejecting those tokens that are generating by draft model, you’re wasting a lot of compute to generate those draft tokens and then the verifier is coming in and then saying hey I don’t want to take this work like this is bad work. Um, so that’s one. Um, it could be because we set the speculative tokens too high,
[1:17:02] meaning in in our current config, we set it to four. Maybe we need to set it down. Uh, and see if that actually helps in improve the acceptance criteria or acceptance rate. Uh, there’s a lot of things with theuler as well with VLM. Uh, depending on how it’s scheduling these requests in, uh, that could be leaving some, uh, performance out on the table. So, it also depends on compatibility and things like that. Um and then yeah again same GPU contention you’re using the same GPU uh to do this work. So it could be uh resulting in u
[1:17:34] the resources not being used correctly. Um so in a lot of cases usually this works but in our scenario it didn’t work. Uh the main particular reason for that is um this particular drapher model is not trained correctly for this particular model. So that’s the reason we’re seeing a a very very low acceptance rate. Um so when you are doing this for your own models and for your own deployments, you have to make sure that the model, the draft model that you’re using is going to be compatible with the model that you want
[1:18:06] to use it for. If you don’t do that, you’ll run into scenario that I’m showcasing here where like your performance is going to tank and um there’s not a whole lot you can do about it. I can tell you from the resource perspective, this GPU has enough headroom to support all of this. But the reason for us seeing this decrease in performance is because the the models are not trained correctly. And uh that is something you want to keep in mind and test for as well. And you want to make sure the speculative tokens uh are set to the right uh number as well. Um but yeah when you in your own time I
[1:18:42] would definitely implore everyone to play around with that number meaning change this to from four to two to six to one and see uh what kind of performance gain you see what kind of performance decrease you see and why is that happening but yeah that that’s that is it for speculative decoding it is actually not going to help us in this scenario so I’m just going to go ahead and uh comment that out and then we’ll redeploy this. So we are back to our baseline.
[1:19:15] >> Hey, you got one question. >> One question. Hey. Um, so I know there’s probably some nuance depending on model architecture, but in general from what you’ve seen, is there a massive hit to acceptance rate if you use like mixed precision essentially like run the main model at FP8 and then quantize the draft model down to Q2? If I’m like really memory constrained, >> is it often even worth doing that? Uh, or you know, what have you seen in
[1:19:46] general? like does >> that’s a good question. Um a lot of times it you it doesn’t matter as much. Um most of the time what you want to do is you want to keep the draft model and the main model at the same precision. But let’s just say the draft model is at BF-16 and then the main model is FP8. The mismatch can cause the acceptance rate to be very low. So, and then the the main part of it is you have to train the draft model correctly so that way it’s able to generate the right tokens. In our particular scenario, the draft
[1:20:18] model was not trained correctly. Um, and then it was also quantized down to FP8. So, there was probably some issues with that recipe when they trained this model and which resulted in us actually taking a massive performance set. Um, so a lot of times when you when uh a lab releases a model, they release uh a drafter model along with it. So you want to use those drafter models uh that come with the model. Uh there’s also thirdparty labs that do their own drafter model. So you can try out a lot of different options that are out there and see which one
[1:20:49] works for you. And in some cases, depending on the use case, let’s just say you’re using for coding, the drafter model might work perfectly fine, but if you’re switching that to maybe some English writing, very specific academic writing, and it might not necessarily work well, and you’re going to see like decrease in acceptance rate. So, it’s also uh it also depends a lot on your use case as well. So, it’s not universally applicable. >> Gotcha. Cool. Makes sense. Thanks. >> Yeah. All right. Let’s jump on to the inference side of
[1:21:23] things. But before you make another jump, any other questions? Oh, yeah. I can put the YAML on there. Um, so the the fact that we have speculative decoding uh presumably is because um for for a model it’s faster to verify rather than decode. >> Yeah. Can you just give a little bit of mental model for like what it’s what a model does underneath the hood um to
[1:21:55] verify such that it’s faster than decoding you know it can’t be decoding and then comparing against what the draft model produces. So like >> what is it doing exactly so so that it’s faster. >> Yeah. So essentially uh when a typical LLM is you know decoding you have a set of vocabulary it’s a huge array of bunch of numbers and it’s representing um a confidence score for each of those items right so instead of um instead of doing that one token at a time when you run with specular decoding you’re running it
[1:22:29] for a lot of you you’re running the model for parallel things. So with continuous batching as well, you’re running a lot of different requests in parallel. Uh so you’re doing the same uh you’re doing the calculation for everything. Uh and you’re doing it at once for a lot of different requests. In the same way, you’re doing the same thing for speculative decoding. You’re checking the confidence score for this uh the speculated tokens and making sure that oh this is a high confidence, so we’re going to go for it. This is you know 0.95 and this one is like 0.9. And then you you accept that and then the other ones you you know uh you reject those. That’s sort of roughly the mental
[1:23:03] model is like you are in parallel running uh through the layers and making sure that each of the tokens that the draft model uh outputs is has a high confidence. Yeah, hopefully that answers your question. Oh, one more question. >> Do you have any examples that >> uh yes I do. That’s a good call out. Um there’s actually I left a few links in here. Um where did I leave those?
[1:23:36] Interpreting the results. Yeah. So there’s a lot of different uh writeups on speculative decoding in in general. If you do it right, you do see quite a bit of increase in performance. Uh VLM has actually done a big report on this and they’ve seen about 1.5x increase in token generation if you set it up correctly with the right model and with the right drafter and the right settings. Um so yeah, this this does excel. It’s just a matter of getting it right and tuning it correctly and making sure you have the right um things in place for it. Um but yeah, like from my personal experience, um for my home lab,
[1:24:10] I used the Quinn 3.6 35 billion model and along with that I use a Dlash um um draft model and I get roughly around two to 3x token generation uh performance improvement uh depending on the use case. So it it does work. It’s just a matter of getting the right models to work together. >> How do you choose the model size >> for the daffer? >> Uh you want to you basically want to
[1:24:42] figure out uh the smallest model that you can run that doesn’t take as much GPU power because you the main model is the model that has all the knowledge. That’s the model that you really care about that has everything that you need. But you don’t want draft model to take a lot of those resources away from the main model. So you want it to be small but not so small that it’s dumb but big enough where like it’s going to actually give you >> you experimented with that. Did you see like acceptance rates like 3B model >> 3B is too big. Uh the reason why is a
[1:25:16] lot of models like I was talking about qu 3.6 uh 35 billion. So it has it’s a mixture of experts model and each expert is about three billion parameters. So the experts can be around that uh and you would get good performance out of it. But for the draft model, you probably want to be less than 1 billion parameter just to make sure that it also depends on the main model you’re using I guess right like if you’re using if your main model is like 400 billion parameters you could probably get away with using a bigger drafter model to make sure that you get higher acceptance rate. So it’s you got to find the right
[1:25:48] balance essentially. Yeah. Cool. Um, do we have any other questions over there? One more before you jump in. >> Yeah, I just had a question. How is the draft model trained? Like is it distillation or something else? >> It’s essentially distillation. Uh, so you take the big model and you know you distill all of its capabilities. You create a data set and then you train the
[1:26:19] uh drafter model using that. And a lot of times actually what’s there’s different techniques to do this. Uh the other techniques you’ll see is the draft model is trained alongside the main model. Uh so that way that’s another way of doing it and a lot of labs will actually give you a drafter model uh inside of the same package. So you don’t have to essentially download a second model and run it. Um so there’s a couple of different ways of doing it. Uh but probably the best way is train alongside it and then that way you don’t have a lot of issues and acceptance rate sort of stays high.
[1:26:50] Cool. Um, we’ll jump into module seven. So, here I want to talk about some of the different flags that you uh should care about when deploying using VLM and what and how you want to get the saturation to be as high as possible. Saturation meaning we want to get the GPU to work as hard as possible as long as possible. Uh, and because you want to get your money’s worth if you’re renting a GPU or if you’re buying a GPU, you want to run it uh as much as possible. So uh we will stop here. So uh one of the concepts I want to talk about uh if you
[1:27:27] remember previously we were looking at the 34 uh 32 concurrency and 64 concurrency. We saw a steep increase in the latency and the reason for that is essentially you the throughput at some point is going to flatten out and but the uh but the latency can keep increasing if you keep increasing the uh concurrency. So you essentially want to find the sweet spot and uh that is something that VLM sort of lets you kind of tweak and make sure that you find
[1:27:57] that sweet spot and once you do find it you can set the right settings for it. Um but but essentially you want to find the inter not so not the intersection but essentially right before where the throughput gets to like the flat state but the latency is like still acceptable enough. It’s sort of like the point you want to get to. Um we will do a setup and then let’s make sure our settings are all good still. Serving model is up. Um, let me just double check if it’s up.
[1:28:36] Should be. Okay. And then here we’re again going to get um another we’re going to do another load test. So that way we know the data and then we can based on that figure out where that uh where this point is. Essentially the we call it the knee um where things are flattening but also the concurren based on concurrency uh the time to first token is acceptable. Um once that is Oh, I think that should be
[1:29:08] fine. So you know the throughput is slowly increasing as concurrency is increasing. That is acceptable. Um and then you also see the latency go up. That is also acceptable but it’s not going up drastically. Uh but we should shortly see the big jumps uh with more um concurrency here. But while this is
[1:29:40] running, any any other questions for anyone? >> Go ahead. Oh, over there. >> So my question was again on the previous speculative decoding. Uh just wanted to know based on your experience um with like drafter model uh what kind of use cases you have seen it to work really like for example with agent loops with tool call or with coding like what kind of like use >> uh agent loops it’s really good at tool calling it’s really good at u browser
[1:30:11] use is the one particular use case that I use it for I want to automate a lot of browser tasks um because there’s still you know you don’t necessarily get APIs for everything and so you want to bridge that gap. Uh and uh yeah, the drafting model helps you generate more tokens faster. So you see your browser agent just essentially run around and do things faster. Uh so in a lot of ways it does help. Uh I will say for browser use I probably see around 1.5x increase whereas for coding I see like closer to 3x. So depending on your use case you
[1:30:42] may see more or less and and things like that. Uh, and a followup on that one. Are there any benchmarks like more trust me bro like coding fire ship? >> There there’s definitely benchmarks out there. I I’m I’m personally a little skeptical of benchmarks whenever I see them. I never get the same results. I don’t know if people agree with that here. Um, so, um, yeah, for the for the most part, like you know, you want to do your own testing and see what works for you because it very much depends on your use case because the acceptance rate is
[1:31:12] going to be different depending on your use case, what you’re using it for. >> Thank you. >> Um, yeah. Any other questions? >> Mic check. Mic check. How’s it going? Um do like big models like codeex or cloud like do they use this type of the coding like have they published that they use these patterns or is this more like for open source if you’re training your own stuff or running inference
[1:31:43] >> I don’t know the question to if they do it or not um I would imagine they do sort of like free performance but uh for for the open source yeah this is particularly for the open source all the open source big models that you want to use all the Quinn models, the GLM models, Kimmy models, they all have specular decoding uh drafter models available that you want to use. >> Is there like a main drafting model that they use for example for like DeepSseek or GLM? >> Deepseek actually came out with a new uh
[1:32:14] thing yesterday I believe or the day before. It’s called DSpark. It’s like their own technique for doing specular decoding in a more dynamic way. Essentially they’re figuring out how so here our configuration is static right like we say we’re going to generate four tokens at a time uh but with deepseek’s way of doing it they are making it dynamic meaning you know it on on the fly sort of decides oh I’m going to generate only two tokens or I’m going to generate four tokens or five tokens depending on the acceptance criteria depending on the GPU load and all all sorts of metrics. So yeah, every every
[1:32:45] model uh every lab has like their own way of doing it as well and you probably want to stick to that but you can also experiment. For example, the Quinn models uh Quinn lab doesn’t release the Dlash models for drafting but these are released by uh a third party lab but they work quite well with them. So you sort of have to test it out and see. >> Thank you. >> Yeah, I think this is hanging right. >> Yeah, I would check the pot. Yeah, might have killed a cluster here.
[1:33:19] Uh >> oh, I can’t type. Uh >> oh, >> this was working well. >> Refresh. [laughter] >> Let me create the tab again. Okay. Um well, something is wrong. It copied a URL and opened in a new tab. See what happens. Let me open a new tab. I wouldn’t close that one.
[1:33:55] You know, in all the testing that has not happened, it happened today. Can I at least scroll through and go through different things? Okay, at least I can scroll scroll through um you know since uh the cluster decided to take uh a vacation uh I’ll sort of go through the content that I was going to cover. Um the main point of running this
[1:34:27] benchmark here was to kind of show where that knee is meaning where you see the max throughput. Uh if we go back to this diagram where you see the max throughput while making sure you are seeing the lowest uh tokens uh lowest latency for token generation. Um and that that is that essentially limit was at 32 concurrency. Um because anything above 32 concurrency you’ll see uh the token generation is going to be kind of the same. It’s not going to change much. uh
[1:34:59] the throughput is going to be the same but but the latency is going to go drastically up and you don’t want that. Uh so that’s sort of like the limit you are hitting. Um and that is important information that we need to keep in mind and look at when we’re deploying these things. Uh and if >> yeah you can go to 100. Go to look at the spreadsheet >> 100. >> Yeah, go to 100 and then just continue from >> Yeah. >> seven or eight. Where is it?
[1:35:35] >> There you go. >> All right. Well, this one’s working. That’s good. All right. Cool. So, we’ll jump into eight. Um, let me also [laughter] open up Who’s doing it?
[1:36:05] >> Okay, so for module A, we’re going to talk quickly through um what sort of flags and knobs you can tweak to make sure that you can sort of get above that limiting point that we were talking about at 32 concurrency. You’re sort of seeing that limit and how do we kind of get beyond that and what things you need to keep in mind when thinking about this. Uh so for this one I’m sort of going to give you guys um a thinking model is essentially you want to measure and that’s why with a lot of different cells I was I keep running load tests and it’s super important to run those load tests to see what your performance
[1:36:38] is like and any changes you’re making how is that changing the performance is it making better is it making it worse um and in what particular metric it’s is it making worse right like if is it if the throughput keeps going up or stays the same but like the latency is changing something is either correct or wrong there. So, that’s something we have to keep in mind. Um, and there’s a bunch of different knobs you can sort of like uh tweak in VLM to make it better. But the main four ones are again the GPU memory utilization. You want to make sure that you’re setting that correctly depending on your use case. Again, if
[1:37:11] you’re running multiple models on the same GPU, you might want to keep it low and that’s a trade-off you’re making. But if you’re only running a single model and you want to make sure that it’s getting the best performance possible, you want to bump that up to 0.9 or point even 0.95. Uh the other thing is you want to make sure that uh the max numbum sequences uh is set to a good limit as well. This is something you have to figure out by testing. Uh in our particular deployment, if you look at the VLM.yaml,
[1:37:41] um we start with 32 sequences, right? So what that is doing is it’s telling VLM that it can only process 32 requests at a time uh and not more than that. And if you do more than that, you’re going to see some performance uh degradation there. Um so there’s a lot of different flags, but those are like the key ones that you want to keep in mind. You want to make sure that you’re setting the model length to the correct length as well. Uh and then you know you want to make sure you’re the batch tokens are also set to the correct length. um you
[1:38:11] don’t want to you want to keep it bigger if you want to do prefill faster if your GPU can handle it. You want to do it smaller if your GPU is a on a little slower side and you can’t handle it. Um but yeah, the idea is you want to change one flag at a time. You don’t want to change multiple things. Um and when you change things, run the uh run the benchmarks and see uh what performance you’re seeing. See measure it and then make assumptions on what you should do next. Um, kind of go through it quickly here.
[1:38:42] We have about what 10 minutes left. Uh, oh, >> I think we lost the P PVC. I think that’s what happened. I got >> Oh, it got the different one. Yeah, I need to actually change this. Rerun this, I think. Um, let me actually just change this in here. This was supposed to be like sequential, but other Jupyter notebook died. So,
[1:39:16] change that and then that should work. Um, again, like I talked about, there’s different knobs uh that you want to tweak um and see what happens. But we’ll get sort of the measure. We’ll measure the baseline and then we’ll change a couple flags and see what happens next. Um, does it say work? Okay, cool. There you go. It’s working. While this load test is running, any other questions anyone has? >> Excuse me.
[1:39:52] >> I noticed that there’s a definite fall-off when we’re optimizing the model. Like here, the 32 to 64, huge falloff. Uh is that when you would decide that maybe we should scale the hardware or is that something that you’re confident you can still tune it further? >> Uh essentially is this is this the ceiling? >> Yeah, you figure out the ceiling by doing mathematics. I think in some of the previous modules Dwan covered uh like what the max ceiling can look like
[1:40:22] for tokens per second what the throughput looks like and um you know what sort of expectations you should have for the deployment and if you are like seeing those max expectations that’s probably the maximum limit of your hardware and then you probably have to get additional hardware or better hardware to do so. Uh so yeah there there is sort of a limit you know there’s only so much you can tune but you’re trying to squeeze as much out of the GPU as possible. You want to share the slides before you continue?
[1:40:54] Share the slides real quick. >> The server I can leave it up for a little bit, couple hours. I’m not going to leave it up just because you do have access to GPUs. Um but what what I am going to give you if you scan this QR code you’ll get access to the PowerPoint as well as the repo if you want to spin this up in your own AI cloud account or if you want to run on your laptop you can do that.
[1:41:25] So if you scan this QR code it’ll take you to a site that has all the resources and if you don’t have a cloud account you can sign up and you get $300 in credits with a free account. So that’s everything you need. And if you all have questions, both of our contact information is here. Omar, I’m Dwan Lightoot. >> Yeah. >> And yeah, with that being said, if you all scan the QR code, I’ll let Omar finish it up. I just want to make sure you all get this before people started to leave. Thank you. >> We’ll leave it up there for a couple
[1:41:56] more minutes gets it. >> Yeah, go ahead. personal assistant. Um, so >> so you can use llamas. It depends on your hardware. I think that’s like the
[1:42:27] first thing I would look at. Um, >> no problem. Thank you. >> Oh, you have both. for the sake of the argument, let’s just say you have the best GPU. Let’s just say you have um >> Yeah. Yeah. You have the latest Blackwill GPU. Um you know, I think for testing and doing like figuring out what model you want to use for your use case, I think it’s good to use Olama and Llama CPP to quickly spin it up and try it out and see what happens. Uh but once you have a model that you know I’m going to use for sure for this use case and this
[1:42:57] this is working great you probably want to switch to uh VLM sg lang or one of these other model uh runtimes. Uh reason being they allow you to run at higher concurrencies and give you more performance out of it. So if you have a single agent running I think it’s fine to use Olama. It’s not a big deal because you only have one request going in at a time. But if you let’s just say you’re running like 20 agents and you want to run it parallel uh Yeah. Yeah, you can set up speculative decoding with VLM. I don’t think Olma
[1:43:31] supports speculative decoding as far as I know, but I could be wrong. Um, but yeah, it when you want to get the max performance out of your hardware, you definitely want to do that. >> Yeah, >> I actually don’t know if there’s a diffusion uh LLM. Is there an open source diffusion model right now available? >> Yeah, Lana. Yeah, I mean I think VLM supports it. So I think you you would be
[1:44:01] able to run it on VLM. Uh Olama, if supports it, you can as well. Um yeah, that’s definitely possible. Okay, we’ll switch back to the module and kind of go through it. Um, again like I was saying, at 32 you’re seeing, you know, good performance, but at 64, uh, we’re going at, you know, the the throughput is sort of staying the same, if not going up, but we’re seeing, um, a significant increase in latency. And to kind of get around it, um, one of the
[1:44:33] things I want to talk about is the max num sequence. Again, this is sort of, uh, how many requests VLM is able to process at one time. It’s sort of setting that flag. If you want to have a lot of uh requests being processed in parallel uh then you want to sort of increase this amount. So currently I believe it’s set up at 32. So we can bump this up to 128 and then we can run this deploy it and see how that changes the performance.
[1:45:09] Okay, it changed a lot of things here. Yeah, [snorts] once this comes up, uh, we can do another test and, um, and you you’ll you’ll see the the limitations that we’re seeing here at 32 is going to go away and you’ll actually see the latency be manageable again um, at higher concurrency levels as well. So, this is sort of like the loop you want to go in. You want to find the right flags for wherever the bottleneck is. find the bottleneck, figure out why that is
[1:45:42] happening, what flag you can tweak uh to make sure that you’re kind of overcoming that bottleneck. Um it’s come up. That’s going to take a little bit of time. Um any questions? One more over there. >> Potentially bursty traffic >> um at times. Um >> Oh yeah. Is there such thing as like bursting to serverless? Is that the domain of you know model routing layer on top? Like what is the pattern for
[1:46:17] >> Yeah. Um I mean autoscaling is one of the patterns like specifically I’ll tell you in LKE uh you can have uh dynamic like autoscaling. So it can scale up uh depending on your needs depending on bursty traffic. it can scale up to you know maybe use a node that has four GPUs instead of one because maybe that handles it better right so you can automate a lot of those things uh to make sure that you’re doing it well and the other part of it is like you can also build like some statistical models to make sure that you kind of understand
[1:46:47] your traffic patterns over a long horizon and then the uh the cluster can also dynamically like sort of predict your burstiness in some ways and then can also scale based on that too >> if you got your browser I can show you where it’s at >> browser you open your browser, I’ll take it to you. >> Okay, so this one is successfully rolled out. >> Um, and then we’ll do a quick load test and once that is run, we can see more.
[1:47:18] All right. Uh, any other questions? Most folks are gone, but >> yeah, like foot H. >> Yeah. 32. That’s where we saw the limit last time. Once we get to 64, we should see uh that it should improve. Okay. So, there was a big drastic improvement. The throughput actually went up quite a bit. Um so, it’s at 1100 tokens per second. Whereas previously, if we look at it over here at 64, we were at 800 tokens
[1:47:52] per second and then the latency was uh 2,000 milliseconds. But now after the change that we made um it is uh 1100 tokens per second and then the latency is uh 800 milliseconds. So it’s gone down the latency has gone down quite drastically and then we have also increased the throughput quite drastically. So the these are the sort of the tuning you can do uh over time to make sure that things are running well uh once you have it up and running and you can do this for your particular use case. Maybe you’re not going to have uh
[1:48:23] six uh you know 64 concurrent requests coming in for a particular use case but maybe you are. So um you have to decide based on your use cases >> your concurrency one higher than before like was that a trade-off you just did >> concurrency one I mean it can be a little higher or lower. It’s not going to be the same all the time but for example before it was 37 but now it’s 35. So it’s a little bit of deviation that happens with running models, but it
[1:48:53] should be plus minus two sec two tokens there. Um we’re also running the full precision model now. We’re not we’re no longer running the FPA because we had to switch the notebook. So that’s the other reason why you’re seeing it go from like 50 something tokens to 30 something tokens. Uh so that’s the performance that we’re seeing there. But but yeah, that is all I have. That is one flag you can tweak. There’s also all sorts of other flags that I implore everyone to take a look at. The workshop kind of goes through it as well. But I think we’re on time and I’ll give it
[1:49:28] back to Dorne. >> Yeah. Thank you all for attending our session today. If you have not scanned the QR code, the code, the repo, the PowerPoints are available on this site. Feel free to start a free AMA cloud account. My name is Dwan Lightoot and I’m joined by my colleague Omar and we thank you all for joining us today. Feel free to ask us questions after this session. Thank you.
[1:50:07] >> [music]