Neste tutorial, mostramos como orquestrar um ambiente de treinamento distribuído para aprendizado por reforço (RL) no Google Kubernetes Engine (GKE). Você usa o Ray e o framework NVIDIA NeMo RL para configurar um ambiente de treinamento distribuído e ajustar um modelo.
Este tutorial se concentra no pipeline de treinamento da otimização de política relativa de grupo (GRPO) no GKE com Ray e NeMo RL. A GRPO é um algoritmo de aprendizado por reforço projetado para melhorar a capacidade de raciocínio de um modelo. Esse algoritmo eficiente em termos de memória simplifica o processo de RL eliminando o Critic, ou modelo de valor, e usando um cálculo relativo baseado em grupo.
Antes de executar este tutorial, recomendamos que você conclua o tutorial Ajustar e escalonar o aprendizado por reforço com verl no GKE. O tutorial a seguir usa a mesma configuração e configuração de cluster que o tutorial de ajuste e escalonamento de RL com verl.
Contexto
As seções a seguir oferecem uma breve visão geral dos conceitos usados neste tutorial.
Aprendizado por reforço (RL)
O RL ensina modelos por experiência, exploração e feedback, em vez de imitação estática. Embora o pré-treinamento ensine um modelo sobre o que dizer, o aprendizado por reforço com feedback humano (RLHF) ensina como ser útil, seguro e lógico. O RL serve como ponte entre um modelo de base e um modelo refinado para um caso de uso especializado.
Para mais informações, consulte O que é aprendizado por reforço?
Otimização de política relativa a grupos (GRPO)
O GRPO, um algoritmo popularizado pela DeepSeek, oferece uma alternativa com eficiência de memória à otimização de política proximal (PPO, na sigla em inglês) para o alinhamento de LLMs, removendo o modelo de crítica. Em vez de uma rede de crítica, o GRPO gera um grupo de respostas para o mesmo comando e usa a recompensa média desse grupo como base.
Para mais informações, consulte GRPO.
NVIDIA NeMo RL
O NeMo RL é uma biblioteca de pós-treinamento de código aberto da NVIDIA projetada para RL escalonável. Parte do ecossistema mais amplo do framework NeMo, o NeMo RL permite experimentos em pequena escala em uma única GPU e implantações de vários nós em milhares de GPUs.
Para mais informações, consulte NVIDIA NeMo RL.
Conjunto de dados GSM8k
Neste tutorial, você vai usar o conjunto de dados GSM8k, que contém 8.500 problemas de matemática de alta qualidade e linguisticamente diversos para o ensino fundamental.
Ao usar o GSM8k e o GRPO, o modelo gera um grupo de n respostas diferentes para o mesmo problema. O GRPO compara essas respostas com a média do grupo. O modelo é mais recompensado por caminhos que são consistentemente corretos e logicamente válidos em comparação com o restante do grupo. Com o tempo, o modelo aprende que articular as etapas com clareza é a maneira mais confiável de maximizar a recompensa, reduzindo efetivamente a recompensa por respostas de baixa performance.
Para mais informações, consulte GSM8k.
Objetivos
Neste tutorial, mostramos como configurar o RL no GKE com o NeMo RL seguindo estas etapas:
- Prepare seu ambiente.
- Configure um cluster do GKE com GPUs B200 ou H200.
- Configure o KubeRay para gerenciar um cluster distribuído do Ray.
- Use o Managed Lustre para armazenamento de alta performance.
- Execute um job de treinamento do GRPO que usa o NeMo RL.
Antes de começar
- Faça login na sua conta do Google Cloud . Se você começou a usar o Google Cloud, crie uma conta para avaliar o desempenho de nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
-
Instale a CLI do Google Cloud.
-
Ao usar um provedor de identidade (IdP) externo, primeiro faça login na CLI gcloud com sua identidade federada.
-
Para inicializar a CLI gcloud, execute o seguinte comando:
gcloud init -
Crie ou selecione um Google Cloud projeto.
Funções necessárias para selecionar ou criar um projeto
- Selecionar um projeto: não é necessário um papel específico do IAM para selecionar um projeto. Você pode escolher qualquer projeto em que tenha recebido um papel.
-
Criar um projeto: para criar um projeto, é necessário ter o papel de Criador de projetos
(
roles/resourcemanager.projectCreator), que contém a permissãoresourcemanager.projects.create. Saiba como conceder papéis.
-
Crie um projeto do Google Cloud :
gcloud projects create PROJECT_ID
Substitua
PROJECT_IDpor um nome para o projeto Google Cloud que você está criando. -
Selecione o projeto Google Cloud que você criou:
gcloud config set project PROJECT_ID
Substitua
PROJECT_IDpelo nome do projeto do Google Cloud .
-
Verifique se o faturamento está ativado para o projeto do Google Cloud .
Ative as APIs necessárias:
Funções necessárias para ativar APIs
Para ativar as APIs, é necessário ter o papel do IAM de administrador de uso do serviço (
roles/serviceusage.serviceUsageAdmin), que contém a permissãoserviceusage.services.enable. Saiba como conceder papéis.gcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
Instale a CLI do Google Cloud.
-
Ao usar um provedor de identidade (IdP) externo, primeiro faça login na CLI gcloud com sua identidade federada.
-
Para inicializar a CLI gcloud, execute o seguinte comando:
gcloud init -
Crie ou selecione um Google Cloud projeto.
Funções necessárias para selecionar ou criar um projeto
- Selecionar um projeto: não é necessário um papel específico do IAM para selecionar um projeto. Você pode escolher qualquer projeto em que tenha recebido um papel.
-
Criar um projeto: para criar um projeto, é necessário ter o papel de Criador de projetos
(
roles/resourcemanager.projectCreator), que contém a permissãoresourcemanager.projects.create. Saiba como conceder papéis.
-
Crie um projeto do Google Cloud :
gcloud projects create PROJECT_ID
Substitua
PROJECT_IDpor um nome para o projeto Google Cloud que você está criando. -
Selecione o projeto Google Cloud que você criou:
gcloud config set project PROJECT_ID
Substitua
PROJECT_IDpelo nome do projeto do Google Cloud .
-
Verifique se o faturamento está ativado para o projeto do Google Cloud .
Ative as APIs necessárias:
Funções necessárias para ativar APIs
Para ativar as APIs, é necessário ter o papel do IAM de administrador de uso do serviço (
roles/serviceusage.serviceUsageAdmin), que contém a permissãoserviceusage.services.enable. Saiba como conceder papéis.gcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
Atribua papéis à sua conta de usuário. Execute uma vez o seguinte comando para cada um dos seguintes papéis do IAM:
roles/container.admin, roles/iam.serviceAccountAdmin, roles/storage.admingcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
Substitua:
PROJECT_ID: o ID do projeto.USER_IDENTIFIER: o identificador da sua conta de usuário . Por exemplo,myemail@example.com.ROLE: o papel do IAM concedido à sua conta de usuário.
- Crie uma conta do Hugging Face caso ainda não tenha uma.
- Verifique se você tem um token do Hugging Face.
- Verifique se o projeto tem cota suficiente para GPUs B200 e H200. Para saber mais, consulte Planejar a cota de GPU e Cota de GPU.
Preparar o ambiente
Neste tutorial, você vai usar o Cloud Shell.
Acesse o console doGoogle Cloud .
Na parte de cima da janela do console do Google Cloud , clique no botão Ativar Cloud Shell.
Configure as variáveis de ambiente a seguir:
export PROJECT_ID=$(gcloud config get project) export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)") export CONTROL_PLANE_REGION=CONTROL_PLANE_REGION export NODE_ZONE=NODE_ZONE export CLUSTER_NAME=CLUSTER_NAME export GPU_TYPE=GPU_TYPE export MACHINE_TYPE=MACHINE_TYPE export KSA_NAME=generic-ksa export NAMESPACE=default export RESERVATION=RESERVATION export LUSTRE_NAME=LUSTRE_NAME export HF_TOKEN=YOUR_HF_TOKEN export WANDB_API_KEY=YOUR_WANDB_API_KEYSubstitua os seguintes valores:
CLUSTER_NAME: o nome do cluster do GKE.CONTROL_PLANE_REGION: a região do Compute Engine para o plano de controle do cluster do GKE.NODE_ZONE: a zona dos seus nós. Selecione uma zona em que as GPUs NVIDIA B200 ou H200 estejam disponíveis.GPU_TYPE: o acelerador que você reservou na reserva de capacidade do Compute Engine. Precisa ser um dos valores abaixo:nvidia-b200: NVIDIA B200 (180 GB)nvidia-h200-141gb: NVIDIA H200 (141 GB)
MACHINE_TYPE: o tipo de máquina a ser usado:- Para GPUs NVIDIA B200 (180 GB), use
a4-highgpu-8gou mais recente. - Para GPUs NVIDIA H200 (141 GB), use
a3-ultragpu-8gou mais recente.
- Para GPUs NVIDIA B200 (180 GB), use
RESERVATION: o nome da sua reserva de GPU.LUSTRE_NAME: o nome da instância do Lustre.YOUR_HF_TOKEN: seu token do Hugging Face.YOUR_WANDB_API_KEY: sua chave de API do Wandb.
Crie as seguintes variáveis de ambiente para a rede:
export NETWORK="NETWORK-NAME" export GVNIC_NETWORK_PREFIX="GVNIC-NAME" export RDMA_NETWORK_PREFIX="RDMA-NAME"Substitua os seguintes valores:
NETWORK-NAME: o nome da rede para o GKE.GVNIC-NAME: o prefixo do nome da rede gVNIC. Você pode usar qualquer prefixo.RDMA-NAME: o prefixo da rede de acesso direto à memória (RDMA) remota. Você pode usar qualquer prefixo.
Configurar a infraestrutura
Nesta seção, você cria redes VPC e um cluster do GKE.
Crie uma rede VPC
Crie uma rede VPC para a interface gVNIC:
gcloud compute networks create ${NETWORK} --subnet-mode=auto gcloud compute networks create ${GVNIC_NETWORK_PREFIX}-net \ --subnet-mode=custom gcloud compute networks subnets create ${GVNIC_NETWORK_PREFIX}-sub \ --network=${GVNIC_NETWORK_PREFIX}-net \ --region=${CONTROL_PLANE_REGION} \ --range=192.168.0.0/24 gcloud compute firewall-rules create ${GVNIC_NETWORK_PREFIX}-internal \ --network=${GVNIC_NETWORK_PREFIX}-net \ --action=ALLOW \ --rules=tcp:0-65535,udp:0-65535,icmp \ --source-ranges=192.168.0.0/16Crie uma rede e sub-redes VPC para RDMA que incluam oito sub-redes para oito GPUs:
gcloud compute networks create ${RDMA_NETWORK_PREFIX}-net \ --network-profile=${NODE_ZONE}-vpc-roce \ --subnet-mode=custom for N in $(seq 0 7); do gcloud compute networks subnets create ${RDMA_NETWORK_PREFIX}-sub-$N \ --network=${RDMA_NETWORK_PREFIX}-net \ --region=${CONTROL_PLANE_REGION} \ --range=192.168.$((N+1)).0/24 & done wait
Criar o cluster do GKE
É possível definir o NeMo RL em um cluster GKE Standard.
Criar um cluster padrão
gcloud container clusters create ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --enable-dataplane-v2 \ --enable-ip-alias \ --enable-multi-networking \ --addons=RayOperator,LustreCsiDriver \ --enable-legacy-lustre-port \ --machine-type=n2-highmem-80 \ --num-nodes=1 \ --min-nodes=1 \ --max-nodes=5 \ --enable-autoscaling \ --network=${NETWORK}Receba as credenciais do cluster:
gcloud container clusters get-credentials ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION}Crie o pool de nós de GPU:
gcloud container node-pools create gpu-pool \ --cluster=${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --node-locations=${NODE_ZONE} \ --machine-type=${MACHINE_TYPE} \ --accelerator=type=${GPU_TYPE},count=8,gpu-driver-version=DEFAULT \ --reservation-affinity=specific \ --reservation=${RESERVATION} \ --enable-autoscaling \ --num-nodes=0 \ --total-max-nodes=2 \ --additional-node-network=network=${GVNIC_NETWORK_PREFIX}-net,subnetwork=${GVNIC_NETWORK_PREFIX}-sub \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-0 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-1 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-2 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-3 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-4 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-5 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-6 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-7Instale o instalador do NCCL RDMA:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/refs/heads/master/gpudirect-rdma/nccl-rdma-installer.yaml
Configurar mapeamentos de rede
Salve o seguinte manifesto como
network-mapping.yaml:Aplique o manifesto:
envsubst < network-mapping.yaml > network-mapping-updated.yaml kubectl apply -f network-mapping-updated.yaml
Preparar o armazenamento
Nesta seção, você vai criar uma instância do Lustre gerenciado, que provisiona o armazenamento de alta performance necessário para sua carga de trabalho de RL.
Alocar um intervalo de endereços IP para acesso a serviços particulares:
gcloud compute addresses create ${LUSTRE_NAME}-range \ --global --purpose=VPC_PEERING \ --prefix-length=20 --network=${NETWORK}Conecte o peering:
gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=${LUSTRE_NAME}-range \ --network=${NETWORK}Crie uma instância do Managed Lustre:
gcloud lustre instances create ${LUSTRE_NAME} \ --per-unit-storage-throughput=500 \ --capacity-gib=18000 \ --filesystem=lustrefs \ --location=${NODE_ZONE} \ --network=projects/${PROJECT_ID}/global/networks/${NETWORK} \ --gke-support-enabledAcessar uma instância do Managed Lustre usando o driver CSI do Managed Lustre
Extraia o endereço IP da instância do Managed Lustre.
export LUSTRE_IP=$(gcloud lustre instances describe ${LUSTRE_NAME} \ --location=$NODE_ZONE --format="value(mountPoint)" | awk -F'@' '{print $1}')Inspecione o manifesto
lustre-pv.yaml.Aplique o manifesto:
envsubst < lustre-pv.yaml > lustre-pv-updated.yaml kubectl apply -f lustre-pv-updated.yamlInspecione o manifesto
lustre-pvc.yaml.Aplique o manifesto:
kubectl apply -f lustre-pvc.yaml
Implantar o RayCluster
Nesta seção, você vai clonar o repositório de exemplo, preparar os manifestos e implantar o cluster do Ray:
Clone o repositório de amostra:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samplesNavegue até o diretório de trabalho:
cd ai-ml/nemo-rl-on-gke/nemoRLInspecione o manifesto
values.yaml:Substitua
NCCL_TUNER_CONFIG_PATHpor qualquer um dos valores a seguir, com base no acelerador usado neste tutorial:- NVIDIA B200 (180 GB):
/usr/local/gib/configs/tuner_config_a4.txtpb - NVIDIA H200 (141 GB):
/usr/local/gib/configs/tuner_config_a3u.txtpb
Neste manifesto, o nó principal gerencia o job e hospeda o painel do Ray. Os nós de trabalho executam os jobs de treinamento.
- NVIDIA B200 (180 GB):
Implante o cluster do Ray:
export REPLICA_COUNT=2 helm install ray-cluster . \ --set additionalWorkerGroups.worker-grp-0.replicas=$REPLICA_COUNTNeste tutorial, você vai usar dois nós de trabalho. Se quiser mudar o número de nós de worker, altere o valor de
REPLICA_COUNT.Verifique se os nós de trabalho e de cabeçalho estão em execução:
kubectl get podsO resultado será o seguinte:
NAME READY STATUS RESTARTS AGE ray-cluster-kuberay-head-sw7dp 3/3 Running 0 33h ray-cluster-kuberay-worker-grp-0-worker-gkbxw 3/3 Running 0 33h ray-cluster-kuberay-worker-grp-0-worker-kdg62 3/3 Running 0 33hVerifique se o cluster do Ray está em execução:
kubectl ray get clusterO resultado será o seguinte:
NAME NAMESPACE DESIRED WORKERS AVAILABLE WORKERS CPUS GPUS TPUS MEMORY CONDITION STATUS AGE ray-cluster-kuberay default 2 2 618 17 0 1573741824k RayClusterProvisioned ready 33h
Iniciar o job do GRPO
Depois que o cluster do Ray estiver pronto, envie um job do Ray para o cluster do Ray em execução no GKE. O NeMo RL baixa automaticamente o modelo durante a execução do job de treinamento de RL.
Para enviar um job do Ray, inicie uma sessão interativa para executar o job.
Para estabelecer uma conexão local com o cluster do Ray, execute este comando:
kubectl ray session ray-cluster-kuberayEsse comando inicia o encaminhamento de porta entre a máquina local e o nó principal do Ray no cluster do GKE. Observe que o terminal vai ficar ocupado enquanto essa sessão estiver ativa. Para continuar, abra uma instância de terminal separada.
Edite o arquivo
gemma3-27b-gsm8k.sh:Substitua os seguintes valores no arquivo
gemma3-27b-gsm8k.sh:YOUR_WANDB_API_KEY: sua chave de API do WandB.YOUR_HF_TOKEN: seu token do Hugging Face.
Nesse arquivo, você pode conferir a configuração para executar um job com o modelo gemma3-27b-it no conjunto de dados GSM8k. Para concluir o pipeline de treinamento do GRPO, esse script define os seguintes parâmetros:
num_prompts_per_step: 16enum_generations_per_prompt: 32: o modelo Gemma3-27b-it gera um grande grupo de respostas para cada comando. Nessa configuração, o modelo produz 512 respostas no total (16 × 32 = 512).policy.generation.colocated.enabled=False: esse parâmetro desativa o recurso de geração colocada, o que significa que o modelo não gera respostas no mesmo nó que o processo de treinamento. No RL padrão, as mesmas GPUs processam o treinamento e a geração. Nesta configuração do NeMo RL, você dedica nós específicos (gerenciados com o parâmetropolicy.generation.colocated.resources) apenas à inferência do vLLM, enquanto o restante do cluster se concentra na matemática de treinamento pesado. Ao separar essas cargas de trabalho, você evita a disputa de recursos entre os buffers de treinamento com uso intensivo de memória e as cargas de trabalho de inferência com uso intensivo de computação.
Para enviar o job, execute o seguinte comando:
bash gemma3-27b-it/gemma3-27b-gsm8k.shQuando o job está em execução, a saída mostra os resultados do treinamento, o tempo e as métricas de performance.
Monitorar a integridade do job de GRPO
Depois que o Ray termina o job, o NeMo RL armazena os pontos de verificação no caminho configurado.
Para verificar a saída do job do GRPO, crie uma sessão SSH para o contêiner
ray-head:kubectl exec -it $(kubectl get pods -l ray.io/node-type=head -o name) -c ray-head -- bashInstale o utilitário de árvore apt no terminal do contêiner
ray-head:apt update && apt install -y treeO resultado será o seguinte:
root@ray-cluster-kuberay-worker-grp-0-worker-gkbxw:/opt/nemo-rl# tree /data/nemo_rl_gemma3_27b_3_17/ /data/nemo_rl_gemma3_27b_3_17/ `-- step_10 |-- config.yaml |-- policy | |-- optimizer | | |-- __0_0.distcp | | |-- __10_0.distcp | | |-- __11_0.distcp | | |-- __12_0.distcp | | |-- __13_0.distcp | | |-- __14_0.distcp | | |-- __15_0.distcp | | |-- __1_0.distcp | | |-- __2_0.distcp | | |-- __3_0.distcp | | |-- __4_0.distcp | | |-- __5_0.distcp | | |-- __6_0.distcp | | |-- __7_0.distcp | | |-- __8_0.distcp | | `-- __9_0.distcp | |-- tokenizer | | |-- chat_template.jinja | | |-- special_tokens_map.json | | |-- tokenizer.json | | `-- tokenizer_config.json | `-- weights | |-- __0_0.distcp | |-- __10_0.distcp | |-- __11_0.distcp | |-- __12_0.distcp | |-- __13_0.distcp | |-- __14_0.distcp | |-- __15_0.distcp | |-- __1_0.distcp | |-- __2_0.distcp | |-- __3_0.distcp | |-- __4_0.distcp | |-- __5_0.distcp | |-- __6_0.distcp | |-- __7_0.distcp | |-- __8_0.distcp | `-- __9_0.distcp |-- train_dataloader.pt `-- training_info.json 6 directories, 39 files ```
Limpar
Para evitar cobranças, exclua os recursos:
helm delete ray-cluster
gcloud container clusters delete ${CLUSTER_NAME} \
--location=${CONTROL_PLANE_REGION} \
--quiet
gcloud lustre instances delete ${LUSTRE_NAME} --location=${NODE_ZONE} --quiet
gcloud services vpc-peerings delete \
--service=servicenetworking.googleapis.com \
--network=${NETWORK}
gcloud compute addresses delete ${LUSTRE_NAME}-range --global --quiet
gcloud compute firewall-rules delete ${GVNIC_NETWORK_PREFIX}-internal --quiet
gcloud compute networks subnets delete ${GVNIC_NETWORK_PREFIX}-sub \
--region=${CONTROL_PLANE_REGION} --quiet
gcloud compute networks delete ${GVNIC_NETWORK_PREFIX}-net --quiet
for N in $(seq 0 7); do
gcloud compute networks subnets delete ${RDMA_NETWORK_PREFIX}-sub-$N \
--region=${CONTROL_PLANE_REGION} --quiet &
done
wait
gcloud compute networks delete ${RDMA_NETWORK_PREFIX}-net --quiet
gcloud compute networks delete ${NETWORK} --quiet