Configurando vLLM para máxima performance

Fonte

Parâmetros do Engine vLLM que discutiremos:

  • max-num-batched-tokens
  • max-model-len
  • gpu-memory-utilization
  • enable-prefix-caching
  • enable-chunked-prefill
  • enforce-eager

max-model-len:

TL;DR corresponde à quantidade máxima de tokens utilizados (entrada + saída)

  • Por padrão, a máxima comprimento da model é igual à máxima extensão de contexto da sua model. Por exemplo, para a model llama 3 8B instruct, ela será igual a 8192.
  • Se você puder definir a máxima extensão de contexto para o seu caso de uso e se ela for menor que a máxima extensão de contexto da sua model, é melhor definir este parâmetro com esse valor.
  • Isso não só evita erros de falta de memória durante a carga ou uso da model, mas também ajuda a configurar outros parâmetros, como max-num-batched-tokens e gpu-memory-utilization.
  • O valor inclui o número de tokens de entrada e saída, portanto, se no seu caso o número total de tokens não exceder, digamos, 2046, defina este parâmetro com esse valor.

max-num-batched-tokens:

TL;DR comece com max-model-len, depois tente duplicar esse valor: max-model-len * 2, depois * 3… até obter erro de falta de memória ou aviso de expulsão. Escolha o valor que oferece boa performance. Se você estiver usando enable-chunked-prefill, comece com um valor menor, por exemplo 128, e tente diferentes valores. Veja explicações abaixo.

  • Observe que este parâmetro indica o número de tokens, e não o tamanho do pacote.
  • Cada pedido deve passar por uma fase de preenchimento prévio (cálculo dos valores KV para os tokens de entrada e distribuição desses blocos no cache KV), e depois uma fase de decodificação, onde ocorre o cálculo recursivo direto para obter os tokens um por um.
  • Assim, o valor mínimo deste parâmetro é igual à máxima extensão da model que você definiu para o preenchimento prévio (a menos que você não esteja usando chunked-prefill, detalhado mais adiante).
  • Quanto mais tokens estiverem no pacote, mais preenchimentos prévios haverá, o que significa que o primeiro token será gerado mais rapidamente. O agendador vLLM por padrão prefere preenchimentos prévios.
  • Assim, um grande tamanho de pacote pode ajudar a aumentar a capacidade de throughput, mas isso não funciona em todos os casos, pois a capacidade e a latência também dependem da relação entre recursos computacionais e memória da GPU (mais detalhes no tópico chunked-prefill), e, geralmente, os preenchimentos prévios exigem grandes recursos computacionais, portanto, eles rapidamente atingem o número máximo de tokens no pacote que podemos manter.
  • Portanto, é melhor começar com o valor max-model-len, tentar aumentá-lo ao dobro e observar como a performance muda até que ocorra erro de falta de memória ou aviso de expulsão, conforme indicado aqui, para escolher o número correto de tokens no pacote. Em seguida, tente aplicar essa teoria para entender como funciona o seu sistema.

enable-prefix-caching:

Resumo habilite-o, a menos que você esteja usando enable-chunked-prefill

  • Ele cacheia os valores KV calculados para uso futuro, o que economiza muito tempo.
  • Se a maior parte do seu pedido permanecer inalterada ao inserir dados, você notará um aumento significativo de performance em comparação com a configuração em que uma pequena parte dos tokens do pedido permanece inalterada.
  • Se o parâmetro enable-chunked-prefill estiver ativo, este parâmetro é inválido (no momento da publicação deste post)

gpu-memory-utilization:

TL;DR quanto mais, melhor, a menos que ocorra erro de falta de memória. Por padrão, 0,9

  • Quanto mais memória da GPU for alocada para armazenar o cache KV, melhor será a performance.
  • Reduza este valor se você enfrentar erro de falta de memória ou se a GPU estiver executando outra tarefa que exija reduzir este valor.

enforce-eager:

TL;DR se houver falta de memória, habilite esta função

  • Ao ser usado, não será criado um gráfico CUDA, o que pode afetar a performance, mas permitirá economizar memória que seria necessária para o gráfico.
  • Em algumas configurações, o gráfico CUDA não terá impacto significativo na performance, e a memória economizada pode ser útil para aumentar os valores dos parâmetros mencionados acima, como gpu-memory-utilization, max-num-batched-tokens, etc.

enable-chunked-prefill:

TL;DR tente habilitar esta função e use tokens em pacotes, começando com o valor 128 e aumentando gradualmente. Compare com a configuração sem este parâmetro. Mais detalhes abaixo.

  • A fase de decodificação é menos exigente em recursos computacionais em comparação com o preenchimento prévio (multiplicação de vetor por matriz em vez de multiplicação de matriz por matriz), mas mais exigente em memória, pois precisa ler os valores KV calculados.
  • Se quiser saber mais, consulte este artigo e esta página vLLM.
  • Como já mencionado, por padrão, o agendador vLLM dá preferência ao preenchimento prévio, que exige recursos computacionais, e durante a decodificação, a memória se torna o gargalo, impedindo que a decodificação com baixos recursos computacionais e alta demanda de memória seja totalmente utilizada, pois é necessário ler os valores KV.
  • Chunk prefill divide a fase de preenchimento em fragmentos, permitindo reduzir o número de tokens no pacote e formar o pacote primeiro, coletando pedidos de decodificação e adicionando pedidos de divisão em fragmentos para o preenchimento, para usar eficientemente os recursos da GPU, combinando tanto o fragmento exigente em recursos computacionais para o preenchimento quanto um número suficiente de pedidos de decodificação com baixa exigência em recursos computacionais, mas alta demanda de memória.
  • Tente novamente habilitar esta função e usar um pequeno número máximo de tokens no pacote, por exemplo 128, e aumente-o até obter os indicadores de capacidade e latência desejados.
  • Este método pode ajudar a reduzir a latência entre tokens, pois a decodificação tem prioridade devido ao pequeno tamanho do pacote (o que reduz a carga na memória), mas pode afetar a capacidade, portanto, é necessário tentar diferentes tamanhos de pacotes e comparar os resultados quando este parâmetro não está ativo.

Exemplo:

  • Vamos usar a API de pontos de entrada do vLLM api em vez do servidor compatível com openai
  • Para iniciar o servidor sem preenchimento prévio em fragmentos, você pode usar o exemplo a seguir:
python3 -m vllm.entrypoints.api_server — model MaziyarPanahi/Meta-Llama-3–8B-Instruct-GPTQ — gpu-memory-utilization 0.95 — port 5000 — dtype half — enforce-eager — max-model-len 4096 — max-num-batched-tokens 8192 — enable-prefix-caching
  • Se a função de preenchimento prévio em fragmentos estiver habilitada, o comando pode parecer assim:
python3 -m vllm.entrypoints.api_server — model MaziyarPanahi/Meta-Llama-3–8B-Instruct-GPTQ — gpu-memory-utilization 0.95 — port 5000 — dtype half — enforce-eager — max-model-len 4096 — max-num-batched-tokens 256 — enable-chunked-prefill
  • Envie uma requisição para a endpoint do servidor acima para verificar a performance com diferentes parâmetros.
  • Execute benchmarks usando scripts fornecidos pelo vLLM, e também tentarei escrever um script semelhante e compartilhá-lo aqui.

Do autor