Práticas recomendadas: inferência de IA em serviços do Cloud Run com GPUs

Esta página fornece práticas recomendadas para otimizar o desempenho quando usa um serviço do Cloud Run com GPU para inferência de IA, com foco em modelos de linguagem grandes (LLMs). Para criar e implementar um serviço do Cloud Run que possa responder em tempo real a eventos de escalabilidade, deve:
  • Use modelos que sejam carregados rapidamente e exijam uma transformação mínima em estruturas prontas para GPU e otimize a forma como são carregados.
  • Use configurações que permitam a execução simultânea máxima e eficiente para reduzir o número de GPUs necessárias para publicar um pedido alvo por segundo, mantendo os custos baixos.

Formas recomendadas de carregar modelos de ML grandes no Cloud Run

A Google recomenda que armazene os modelos de ML em imagens de contentores ou otimize o carregamento dos mesmos a partir do Cloud Storage.

Compromissos de armazenamento e carregamento de modelos de aprendizagem automática

Segue-se uma comparação das opções:

Localização do modelo Tempo de implementação Experiência de desenvolvimento Tempo de arranque do contentor Custo de armazenamento
Imagem do contentor Lento. Uma imagem que contenha um modelo grande demora mais tempo a ser importada para o Cloud Run. As alterações à imagem do contentor requerem uma nova implementação, que pode ser lenta para imagens grandes. Depende do tamanho do modelo. Para modelos muito grandes, use o Cloud Storage para um desempenho mais previsível, mas mais lento. Potencialmente várias cópias no Artifact Registry.
Cloud Storage, carregado através da montagem de volume FUSE do Cloud Storage Rápido. Modelo transferido durante o arranque do contentor. Não é difícil de configurar e não requer alterações à imagem do Docker. Rápido quando usa otimizações de rede. Não paraleliza a transferência. Uma cópia no Cloud Storage.
Cloud Storage, transferidos em simultâneo através do comando gcloud storage cp da CLI do Google Cloud ou da API Cloud Storage, conforme mostrado no exemplo de código de transferência em simultâneo do gestor de transferências. Rápido. Modelo transferido durante o arranque do contentor. É ligeiramente mais difícil de configurar, porque tem de instalar a CLI do Google Cloud na imagem ou atualizar o código para usar a API Cloud Storage. Rápido quando usa otimizações de rede. A CLI do Google Cloud transfere o ficheiro do modelo em paralelo, o que a torna mais rápida do que a montagem FUSE. Uma cópia no Cloud Storage.
Internet Rápido. Modelo transferido durante o arranque do contentor. Normalmente, mais simples (muitas frameworks transferem modelos de repositórios centrais). Normalmente, fraca e imprevisível:
  • As frameworks podem aplicar transformações de modelos durante a inicialização. (Deve fazê-lo no momento da compilação).
  • O anfitrião do modelo e as bibliotecas para transferir o modelo podem não ser eficientes.
  • Existe um risco de fiabilidade associado à transferência de conteúdo da Internet. O serviço pode não ser iniciado se o destino de transferência estiver inativo e o modelo subjacente transferido pode ser alterado, o que diminui a qualidade. Recomendamos que faça o alojamento no seu próprio contentor do Cloud Storage.
Depende do fornecedor de alojamento do modelo.

Armazene modelos em imagens de contentores

Ao armazenar o modelo de AA na imagem do contentor, o carregamento do modelo beneficia da infraestrutura de streaming de contentores otimizada do Cloud Run. No entanto, a criação de imagens de contentores que incluem modelos de AA é um processo que requer muitos recursos, especialmente quando trabalha com modelos grandes. Em particular, o processo de compilação pode ficar limitado ao débito da rede. Quando usar o Cloud Build, recomendamos que use uma máquina de compilação mais potente com um desempenho de computação e rede melhorado. Para o fazer, crie uma imagem com um ficheiro de configuração de compilação que tenha os seguintes passos:

steps:
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'IMAGE', '.']
- name: 'gcr.io/cloud-builders/docker'
  args: ['push', 'IMAGE']
images:
- IMAGE
options:
 machineType: 'E2_HIGHCPU_32'
 diskSizeGb: '500'
 

Pode criar uma cópia do modelo por imagem se a camada que contém o modelo for distinta entre as imagens (hash diferente). Pode haver um custo adicional do Artifact Registry porque pode existir uma cópia do modelo por imagem se a camada do modelo for única em cada imagem.

Armazene modelos no Cloud Storage

Para otimizar o carregamento de modelos de ML quando carrega modelos de ML a partir do Cloud Storage, quer use montagens de volumes do Cloud Storage ou use diretamente a API Cloud Storage ou a linha de comandos, tem de usar a VPC direta com o valor da definição de saída definido como all-traffic, juntamente com o acesso privado à Google.

Carregue modelos da Internet

Para otimizar o carregamento de modelos de ML a partir da Internet, encaminhe todo o tráfego através da rede VPC com o valor da definição de saída definido como all-traffic e configure o Cloud NAT para alcançar a Internet pública com uma largura de banda elevada.

Considerações sobre a compilação, a implementação, o tempo de execução e o design do sistema

As secções seguintes descrevem considerações para a criação, a implementação, o tempo de execução e o design do sistema.

No momento da compilação

A lista seguinte mostra as considerações que tem de ter em conta quando estiver a planear a criação:

  • Escolha uma boa imagem base. Deve começar com uma imagem dos contentores de aprendizagem profunda ou do registo de contentores da NVIDIA para a framework de ML que está a usar. Estas imagens têm os pacotes mais recentes relacionados com o desempenho instalados. Não recomendamos que crie uma imagem personalizada.
  • Escolha modelos quantizados de 4 bits para maximizar a simultaneidade, a menos que possa provar que afetam a qualidade dos resultados. A quantização produz modelos mais pequenos e rápidos, o que reduz a quantidade de memória da GPU necessária para publicar o modelo e pode aumentar o paralelismo no tempo de execução. Idealmente, os modelos devem ser preparados na profundidade de bits alvo e não quantizados para essa profundidade.
  • Escolha um formato de modelo com tempos de carregamento rápidos para minimizar o tempo de arranque do contentor, como o GGUF. Estes formatos refletem com maior precisão o tipo de quantização alvo e requerem menos transformações quando carregados na GPU. Por motivos de segurança, não use pontos de verificação no formato pickle.
  • Crie e aqueça as caches de MDIs no momento da criação. Inicie o MDG na máquina de compilação enquanto cria a imagem do Docker. Ativar a colocação em cache de comandos e fornecer comandos comuns ou de exemplo para ajudar a preparar a cache para utilização no mundo real. Guardar as saídas geradas para serem carregadas no tempo de execução.
  • Guarde o seu próprio modelo de inferência que gera durante o tempo de compilação. Isto poupa tempo significativo em comparação com o carregamento de modelos armazenados de forma menos eficiente e a aplicação de transformações, como a quantização, no arranque do contentor.

Na implementação

A lista seguinte mostra as considerações que tem de ter em conta quando estiver a planear a implementação:

  1. Certifique-se de que define a simultaneidade do serviço com precisão no Cloud Run.
  2. Ajuste as sondagens de arranque com base na sua configuração.

As sondas de arranque determinam se o contentor foi iniciado e está pronto para aceitar tráfego. Tenha em conta estes pontos importantes ao configurar as sondagens de arranque:

  • Tempo de arranque adequado: permita tempo suficiente para que o contentor, incluindo os modelos, seja totalmente inicializado e carregado.
  • Validação da disponibilidade do modelo: configure a sua sonda para ser aprovada apenas quando a sua aplicação estiver pronta para publicar pedidos. A maioria dos motores de publicação alcança automaticamente este objetivo quando o modelo é carregado na memória da GPU, o que evita pedidos prematuros.

Tenha em atenção que o Ollama pode abrir uma porta TCP antes de um modelo ser carregado. Para resolver este problema:

  • Pré-carregue modelos: consulte a documentação do Ollama para ver orientações sobre o pré-carregamento do modelo durante o arranque.

No tempo de execução

  • Gerir ativamente o comprimento do contexto suportado. Quanto menor for a capacidade de resposta que suporta, mais consultas pode suportar em execução em paralelo. Os detalhes de como o fazer dependem da estrutura.
  • Use as caches de MDIs que gerou no momento da compilação. Forneça as mesmas flags que usou durante o tempo de compilação quando gerou a cache de comandos e prefixos.
  • Carregue a partir do modelo guardado que acabou de escrever. Consulte o artigo Compromissos de armazenamento e carregamento de modelos para ver uma comparação sobre como carregar o modelo.
  • Considere usar uma cache de chaves-valores quantizada se a sua estrutura a suportar. Isto pode reduzir os requisitos de memória por consulta e permite a configuração de um paralelismo superior. No entanto, também pode afetar a qualidade.
  • Ajuste a quantidade de memória da GPU a reservar para os pesos dos modelos, as ativações e as caches de chave-valor. Defina-o o mais alto possível sem receber um erro de falta de memória.
  • Verifique se a sua framework tem opções para melhorar o desempenho do arranque do contentor (por exemplo, usando a paralelização do carregamento de modelos).
  • Configure a simultaneidade corretamente no código do serviço. Certifique-se de que o código do serviço está configurado para funcionar com as definições de simultaneidade do serviço do Cloud Run.

Ao nível do design do sistema

  • Adicione caches semânticas quando adequado. Em alguns casos, o armazenamento em cache de consultas e respostas completas pode ser uma excelente forma de limitar o custo das consultas comuns.
  • Controle a variação nos seus preâmbulos. As caches de comandos só são úteis quando contêm os comandos em sequência. As caches são efetivamente armazenadas em cache com prefixos. As inserções ou as edições na sequência significam que não estão em cache ou que estão apenas parcialmente presentes.

Escala automática e GPUs

Se usar o dimensionamento automático predefinido do Cloud Run, o Cloud Run dimensiona automaticamente o número de instâncias de cada revisão com base em fatores como a utilização da CPU e a simultaneidade de pedidos. No entanto, o Cloud Run não dimensiona automaticamente o número de instâncias com base na utilização da GPU.

Para uma revisão com uma GPU, se a revisão não tiver uma utilização significativa da CPU, o Cloud Run é dimensionado horizontalmente para a concorrência de pedidos. Para alcançar uma escalabilidade ideal para a simultaneidade de pedidos, tem de definir um máximo de pedidos simultâneos por instância ideal, conforme descrito na secção seguinte.

Máximo de pedidos simultâneos por instância

A definição maximum concurrent requests per instance controla o número máximo de pedidos que o Cloud Run envia a uma única instância de uma só vez. Tem de ajustar a simultaneidade para corresponder à simultaneidade máxima que o código em cada instância consegue processar com um bom desempenho.

Concorrência máxima e cargas de trabalho de IA

Quando executa uma carga de trabalho de inferência de IA numa GPU em cada instância, a concorrência máxima que o código consegue processar com um bom desempenho depende de detalhes específicos da implementação e da framework. O seguinte afeta a forma como define a definição ideal de pedidos simultâneos máximos:

  • Número de instâncias do modelo carregadas na GPU
  • Número de consultas paralelas por modelo
  • Utilização do processamento em lote
  • Parâmetros de configuração de lote específicos
  • Quantidade de trabalho não processado pela GPU

Se o número máximo de pedidos simultâneos for definido como demasiado elevado, os pedidos podem acabar por esperar na instância para aceder à GPU, o que leva a um aumento da latência. Se o número máximo de pedidos simultâneos estiver definido como demasiado baixo, a GPU pode ser subutilizada, o que faz com que o Cloud Run aumente o número de instâncias mais do que o necessário.

Uma regra geral para configurar o número máximo de pedidos simultâneos para cargas de trabalho de IA é:

(Number of model instances * parallel queries per model) + (number of model instances * ideal batch size)

Por exemplo, suponhamos que uma instância carrega 3 instâncias de modelos na GPU e que cada instância de modelo pode processar 4 consultas paralelas. O tamanho ideal do lote também é 4, porque é o número de consultas paralelas que cada instância do modelo pode processar. Usando a regra prática, definiria o número máximo de pedidos simultâneos como 24: (3 * 4) + (3 * 4).

Tenha em atenção que esta fórmula é apenas uma regra geral. A definição ideal de pedidos simultâneos máximos depende dos detalhes específicos da sua implementação. Para alcançar o desempenho ideal real, recomendamos que teste a carga do seu serviço com diferentes definições de pedidos simultâneos máximos para avaliar que opção tem o melhor desempenho.

Equilíbrios entre o débito, a latência e o custo

Consulte o artigo Compromissos entre o débito, a latência e os custos para saber o impacto dos pedidos concorrentes máximos no débito, na latência e no custo. Tenha em atenção que todos os serviços do Cloud Run que usam GPUs têm de ter a faturação baseada em instâncias configurada.