Servir LLMs como DeepSeek-R1 671B o Llama 3.1 405B en bare metal


Información general

En esta guía se explica cómo ofrecer modelos de lenguaje extensos (LLMs) de última generación, como DeepSeek-R1 671B o Llama 3.1 405B, en Google Distributed Cloud (solo software) en hardware desnudo mediante unidades de procesamiento gráfico (GPUs) en varios nodos.

En esta guía se muestra cómo usar tecnologías portátiles de código abierto (Kubernetes, vLLM y la API LeaderWorkerSet [LWS]) para desplegar y publicar cargas de trabajo de IA y aprendizaje automático en clústeres de hardware desnudo. Google Distributed Cloud amplía GKE para usarlo en un entorno local, al tiempo que ofrece las ventajas del control granular, la escalabilidad, la resiliencia, la portabilidad y la rentabilidad de GKE.

Fondo

En esta sección se describen las tecnologías clave que se usan en esta guía, incluidos los dos LLMs que se usan como ejemplos en esta guía: DeepSeek-R1 y Llama 3.1 405B.

DeepSeek-R1

DeepSeek-R1, un modelo de lenguaje extenso de 671.000 millones de parámetros de DeepSeek, se ha diseñado para la inferencia lógica, el razonamiento matemático y la resolución de problemas en tiempo real en diversas tareas basadas en texto. Google Distributed Cloud gestiona las demandas computacionales de DeepSeek-R1, lo que permite que este modelo aproveche sus funciones con recursos escalables, computación distribuida y redes eficientes.

Para obtener más información, consulta la documentación de DeepSeek.

Llama 3.1 405B

Llama 3.1 405B es un modelo de lenguaje extenso de Meta diseñado para una amplia gama de tareas de procesamiento del lenguaje natural, como la generación de texto, la traducción y la respuesta a preguntas. Google Distributed Cloud ofrece la sólida infraestructura necesaria para dar respuesta a las necesidades de entrenamiento y servicio distribuidos de modelos de esta escala.

Para obtener más información, consulta la documentación de Llama.

Servicio de Kubernetes gestionado de Google Distributed Cloud

Google Distributed Cloud ofrece una amplia gama de servicios, incluido Google Distributed Cloud (solo software) para bare metal, que es ideal para desplegar y gestionar cargas de trabajo de IA o aprendizaje automático en tu propio centro de datos. Google Distributed Cloud es un servicio gestionado de Kubernetes que simplifica el despliegue, el escalado y la gestión de aplicaciones en contenedores. Google Distributed Cloud proporciona la infraestructura necesaria, incluidos recursos escalables, computación distribuida y redes eficientes, para gestionar las demandas computacionales de los LLMs.

Para obtener más información sobre los conceptos clave de Kubernetes, consulta Empezar a aprender sobre Kubernetes. Para obtener más información sobre Google Distributed Cloud y cómo te ayuda a escalar, automatizar y gestionar Kubernetes, consulta la descripción general de Google Distributed Cloud (solo software) para bare metal.

GPUs

Las unidades de procesamiento gráfico (GPUs) te permiten acelerar cargas de trabajo específicas, como el aprendizaje automático y el procesamiento de datos. Google Distributed Cloud admite nodos equipados con estas potentes GPUs, lo que te permite configurar tu clúster para obtener un rendimiento óptimo en las tareas de aprendizaje automático y procesamiento de datos. Google Distributed Cloud ofrece una serie de opciones de tipos de máquinas para la configuración de nodos, incluidos tipos de máquinas con GPUs NVIDIA H100, L4 y A100.

Para obtener más información, consulta Configurar y usar GPUs NVIDIA.

LeaderWorkerSet (LWS)

LeaderWorkerSet (LWS) es una API de implementación de Kubernetes que aborda patrones de implementación comunes de cargas de trabajo de inferencia de varios nodos de IA y aprendizaje automático. El servicio multinodo utiliza varios pods, cada uno de los cuales puede ejecutarse en un nodo diferente, para gestionar la carga de trabajo de inferencia distribuida. LWS permite tratar varios pods como un grupo, lo que simplifica la gestión del servicio de modelos distribuidos.

vLLM y servicio multihost

Cuando sirvas LLMs que requieran muchos recursos de computación, te recomendamos que uses vLLM y ejecutes las cargas de trabajo en GPUs.

vLLM es un framework de servicio de LLMs de código abierto muy optimizado que puede aumentar el rendimiento del servicio en GPUs. Incluye funciones como las siguientes:

  • Implementación optimizada de Transformer con PagedAttention

  • Agrupación continua para mejorar el rendimiento general del servicio

  • Servicio distribuido en varias GPUs

En el caso de los LLMs que requieren muchos recursos computacionales y no caben en un solo nodo de GPU, puedes usar varios nodos de GPU para servir el modelo. vLLM admite la ejecución de cargas de trabajo en GPUs con dos estrategias:

  • El paralelismo de tensores divide las multiplicaciones de matrices en la capa de transformador entre varias GPUs. Sin embargo, esta estrategia requiere una red rápida debido a la comunicación necesaria entre las GPUs, por lo que no es adecuada para ejecutar cargas de trabajo en varios nodos.

  • El paralelismo de la fase divide el modelo por capas, es decir, de forma vertical. Esta estrategia no requiere una comunicación constante entre las GPUs, por lo que es una mejor opción cuando se ejecutan modelos en varios nodos.

Puedes usar ambas estrategias en el servicio de varios nodos. Por ejemplo, si usas dos nodos con ocho GPUs H100 cada uno, puedes usar ambas estrategias:

  • Paralelismo de la fase de procesamiento bidireccional para fragmentar el modelo en los dos nodos

  • Paralelismo de tensores de ocho vías para fragmentar el modelo en las ocho GPUs de cada nodo

Para obtener más información, consulta la documentación de vLLM.

Objetivos

  1. Prepara tu entorno con un clúster de Google Distributed Cloud en modo Autopilot o Standard.

  2. Despliega vLLM en varios nodos de tu clúster.

  3. Usa vLLM para servir el modelo a través de curl.

Antes de empezar

Acceder al modelo

Puedes usar los modelos Llama 3.1 405B o DeepSeek-R1.

DeepSeek-R1

.

Generar un token de acceso

Si aún no tienes uno, genera un nuevo token de Hugging Face:

  1. Haz clic en Tu perfil > Configuración > Tokens de acceso.

  2. Selecciona New Token (Nuevo token).

  3. Especifica el nombre que quieras y un rol de al menos Read.

  4. Selecciona Generar un token.

Llama 3.1 405B

.

Generar un token de acceso

Si aún no tienes uno, genera un nuevo token de Hugging Face:

  1. Haz clic en Tu perfil > Configuración > Tokens de acceso.

  2. Selecciona New Token (Nuevo token).

  3. Especifica el nombre que quieras y un rol de al menos Read.

  4. Selecciona Generar un token.

Preparar el entorno

Para configurar tu entorno, sigue estos pasos:

  1. Define los siguientes parámetros en la estación de trabajo de administrador:

    gcloud config set project PROJECT_ID
    export PROJECT_ID=$(gcloud config get project)
    export HF_TOKEN=HUGGING_FACE_TOKEN
    export IMAGE_NAME= gcr.io/PROJECT_ID/vllm-multihost/vllm-multihost:latest
    

    Sustituye los siguientes valores:

    • PROJECT_ID: el ID de proyecto asociado a tu clúster.

    • HUGGING_FACE_TOKEN: el token de Hugging Face generado en la sección anterior Obtener acceso al modelo.

Crear un secreto de Kubernetes para las credenciales de Hugging Face

Crea un secreto de Kubernetes que contenga el token de Hugging Face con el siguiente comando:

kubectl create secret generic hf-secret \
    --kubeconfig KUBECONFIG \
    --from-literal=hf_api_token=${HF_TOKEN} \
    --dry-run=client -o yaml | kubectl apply -f -

Sustituye KUBECONFIG por la ruta del archivo kubeconfig del clúster en el que quieras alojar el LLM.

Crear tu propia imagen multinodo de vLLM

Para facilitar la comunicación entre nodos de vLLM, puedes usar Ray. El repositorio LeaderWorkerSet proporciona un Dockerfile que incluye una secuencia de comandos bash para configurar Ray con vLLM.

Para crear tu propia imagen multinodo de vLLM, debes clonar el repositorio LeaderWorkerSet, crear una imagen Docker con el Dockerfile proporcionado (que configura Ray para la comunicación entre nodos) y, a continuación, enviar esa imagen a Artifact Registry para implementarla en Google Distributed Cloud.

Compila el contenedor

Para crear el contenedor, sigue estos pasos:

  1. Clona el repositorio LeaderWorkerSet:

    git clone https://github.com/kubernetes-sigs/lws.git
    
  2. Crea la imagen.

    cd lws/docs/examples/vllm/build/ && docker build -f Dockerfile.GPU . -t vllm-multihost
    

Enviar la imagen a Artifact Registry

Para asegurarte de que tu implementación de Kubernetes pueda acceder a la imagen, almacénala en Artifact Registry dentro de tu proyecto de Google Cloud :

docker image tag vllm-multihost ${IMAGE_NAME}
docker push ${IMAGE_NAME}

Instalar LeaderWorkerSet

Para instalar LWS, ejecuta el siguiente comando:

kubectl apply --server-side \
    --kubeconfig KUBECONFIG \
    -f https://github.com/kubernetes-sigs/lws/releases/latest/download/manifests.yaml

Valida que el controlador LeaderWorkerSet se esté ejecutando en el espacio de nombres lws-system con el siguiente comando:

kubectl get pod -n lws-system --kubeconfig KUBECONFIG

El resultado debería ser similar al siguiente:

NAME                                      READY   STATUS    RESTARTS   AGE
lws-controller-manager-5c4ff67cbd-9jsfc   2/2     Running   0          6d23h

Desplegar el servidor de modelos vLLM

Para implementar el servidor de modelos vLLM, sigue estos pasos:

  1. Crea y aplica el archivo de manifiesto en función del LLM que quieras implementar.

    DeepSeek-R1

    1. Crea un manifiesto YAML, vllm-deepseek-r1-A3.yaml, para el modelo vLLM server:

      apiVersion: leaderworkerset.x-k8s.io/v1
      kind: LeaderWorkerSet
      metadata:
        name: vllm
      spec:
        replicas: 1
        leaderWorkerTemplate:
          size: 2
          restartPolicy: RecreateGroupOnPodRestart
          leaderTemplate:
            metadata:
              labels:
                role: leader
            spec:
              nodeSelector:
                cloud.google.com/gke-accelerator: nvidia-h100-80gb
              containers:
                - name: vllm-leader
                  image: IMAGE_NAME
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.sh leader --ray_cluster_size=$(LWS_GROUP_SIZE); 
                      python3 -m vllm.entrypoints.openai.api_server --port 8080 --model deepseek-ai/DeepSeek-R1 --tensor-parallel-size 8 --pipeline-parallel-size 2 --trust-remote-code --max-model-len 4096"
                  resources:
                    limits:
                      nvidia.com/gpu: "8"
                  ports:
                    - containerPort: 8080
                  readinessProbe:
                    tcpSocket:
                      port: 8080
                    initialDelaySeconds: 15
                    periodSeconds: 10
                  volumeMounts:
                    - mountPath: /dev/shm
                      name: dshm
              volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
                  sizeLimit: 15Gi
          workerTemplate:
            spec:
              containers:
                - name: vllm-worker
                  image: IMAGE_NAME
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.sh worker --ray_address=$(LWS_LEADER_ADDRESS)"
                  resources:
                    limits:
                      nvidia.com/gpu: "8"
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                  volumeMounts:
                    - mountPath: /dev/shm
                      name: dshm   
              volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
                  sizeLimit: 15Gi
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: vllm-leader
      spec:
        ports:
          - name: http
            port: 8080
            protocol: TCP
            targetPort: 8080
        selector:
          leaderworkerset.sigs.k8s.io/name: vllm
          role: leader
        type: ClusterIP
      
    2. Aplica el manifiesto ejecutando el siguiente comando:

      kubectl apply -f vllm-deepseek-r1-A3.yaml \
          --kubeconfig KUBECONFIG
      

    Llama 3.1 405B

    1. Crea un manifiesto YAML, vllm-llama3-405b-A3.yaml, para el modelo vLLM server:

      apiVersion: leaderworkerset.x-k8s.io/v1
      kind: LeaderWorkerSet
      metadata:
        name: vllm
      spec:
        replicas: 1
        leaderWorkerTemplate:
          size: 2
          restartPolicy: RecreateGroupOnPodRestart
          leaderTemplate:
            metadata:
              labels:
                role: leader
            spec:
              nodeSelector:
                cloud.google.com/gke-accelerator: nvidia-h100-80gb
              containers:
                - name: vllm-leader
                  image: IMAGE_NAME
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.sh leader --ray_cluster_size=$(LWS_GROUP_SIZE); 
                      python3 -m vllm.entrypoints.openai.api_server --port 8080 --model meta-llama/Meta-Llama-3.1-405B-Instruct --tensor-parallel-size 8 --pipeline-parallel-size 2"
                  resources:
                    limits:
                      nvidia.com/gpu: "8"
                  ports:
                    - containerPort: 8080
                  readinessProbe:
                    tcpSocket:
                      port: 8080
                    initialDelaySeconds: 15
                    periodSeconds: 10
                  volumeMounts:
                    - mountPath: /dev/shm
                      name: dshm
              volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
                  sizeLimit: 15Gi
          workerTemplate:
            spec:
              containers:
                - name: vllm-worker
                  image: IMAGE_NAME
                  command:
                    - sh
                    - -c
                    - "/vllm-workspace/ray_init.sh worker --ray_address=$(LWS_LEADER_ADDRESS)"
                  resources:
                    limits:
                      nvidia.com/gpu: "8"
                  env:
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                  volumeMounts:
                    - mountPath: /dev/shm
                      name: dshm   
              volumes:
              - name: dshm
                emptyDir:
                  medium: Memory
                  sizeLimit: 15Gi
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: vllm-leader
      spec:
        ports:
          - name: http
            port: 8080
            protocol: TCP
            targetPort: 8080
        selector:
          leaderworkerset.sigs.k8s.io/name: vllm
          role: leader
        type: ClusterIP
      
    2. Aplica el manifiesto ejecutando el siguiente comando:

      kubectl apply -f vllm-llama3-405b-A3.yaml \
          --kubeconfig KUBECONFIG
      
  2. Consulta los registros del servidor de modelos en ejecución con el siguiente comando:

    kubectl logs vllm-0 -c vllm-leader \
        --kubeconfig KUBECONFIG
    

    La salida debería ser similar a la siguiente:

    INFO 08-09 21:01:34 api_server.py:297] Route: /detokenize, Methods: POST
    INFO 08-09 21:01:34 api_server.py:297] Route: /v1/models, Methods: GET
    INFO 08-09 21:01:34 api_server.py:297] Route: /version, Methods: GET
    INFO 08-09 21:01:34 api_server.py:297] Route: /v1/chat/completions, Methods: POST
    INFO 08-09 21:01:34 api_server.py:297] Route: /v1/completions, Methods: POST
    INFO 08-09 21:01:34 api_server.py:297] Route: /v1/embeddings, Methods: POST
    INFO:     Started server process [7428]
    INFO:     Waiting for application startup.
    INFO:     Application startup complete.
    INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
    

Aplicar el modelo

Configura la redirección de puertos al modelo ejecutando el siguiente comando:

kubectl port-forward svc/vllm-leader 8080:8080 \
    --kubeconfig KUBECONFIG

Interactuar con el modelo mediante curl

Para interactuar con el modelo mediante curl, sigue estas instrucciones:

DeepSeek-R1

En una nueva terminal, envía una solicitud al servidor:

curl http://localhost:8080/v1/completions \
-H "Content-Type: application/json" \
-d '{
    "model": "deepseek-ai/DeepSeek-R1",
    "prompt": "I have four boxes. I put the red box on the bottom and put the blue box on top. Then I put the yellow box on top the blue. Then I take the blue box out and put it on top. And finally I put the green box on the top. Give me the final order of the boxes from bottom to top. Show your reasoning but be brief",
    "max_tokens": 1024,
    "temperature": 0
}'

La salida debería ser similar a la siguiente:

{
  "id": "cmpl-f2222b5589d947419f59f6e9fe24c5bd",
  "object": "text_completion",
  "created": 1738269669,
  "model": "deepseek-ai/DeepSeek-R1",
  "choices": [
    {
      "index": 0,
      "text": ".\n\nOkay, let's see. The user has four boxes and is moving them around. Let me try to visualize each step. \n\nFirst, the red box is placed on the bottom. So the stack starts with red. Then the blue box is put on top of red. Now the order is red (bottom), blue. Next, the yellow box is added on top of blue. So now it's red, blue, yellow. \n\nThen the user takes the blue box out. Wait, blue is in the middle. If they remove blue, the stack would be red and yellow. But where do they put the blue box? The instruction says to put it on top. So after removing blue, the stack is red, yellow. Then blue is placed on top, making it red, yellow, blue. \n\nFinally, the green box is added on the top. So the final order should be red (bottom), yellow, blue, green. Let me double-check each step to make sure I didn't mix up any steps. Starting with red, then blue, then yellow. Remove blue from the middle, so yellow is now on top of red. Then place blue on top of that, so red, yellow, blue. Then green on top. Yes, that seems right. The key step is removing the blue box from the middle, which leaves yellow on red, then blue goes back on top, followed by green. So the final order from bottom to top is red, yellow, blue, green.\n\n**Final Answer**\nThe final order from bottom to top is \\boxed{red}, \\boxed{yellow}, \\boxed{blue}, \\boxed{green}.\n</think>\n\n1. Start with the red box at the bottom.\n2. Place the blue box on top of the red box. Order: red (bottom), blue.\n3. Place the yellow box on top of the blue box. Order: red, blue, yellow.\n4. Remove the blue box (from the middle) and place it on top. Order: red, yellow, blue.\n5. Place the green box on top. Final order: red, yellow, blue, green.\n\n\\boxed{red}, \\boxed{yellow}, \\boxed{blue}, \\boxed{green}",
      "logprobs": null,
      "finish_reason": "stop",
      "stop_reason": null,
      "prompt_logprobs": null
    }
  ],
  "usage": {
    "prompt_tokens": 76,
    "total_tokens": 544,
    "completion_tokens": 468,
    "prompt_tokens_details": null
  }
}

Llama 3.1 405B

En una nueva terminal, envía una solicitud al servidor:

curl http://localhost:8080/v1/completions \
-H "Content-Type: application/json" \
-d '{
    "model": "meta-llama/Meta-Llama-3.1-405B-Instruct",
    "prompt": "San Francisco is a",
    "max_tokens": 7,
    "temperature": 0
}'

La salida debería ser similar a la siguiente:

{"id":"cmpl-0a2310f30ac3454aa7f2c5bb6a292e6c",
"object":"text_completion","created":1723238375,"model":"meta-llama/Meta-Llama-3.1-405B-Instruct","choices":[{"index":0,"text":" top destination for foodies, with","logprobs":null,"finish_reason":"length","stop_reason":null}],"usage":{"prompt_tokens":5,"total_tokens":12,"completion_tokens":7}}

Siguientes pasos