Prácticas recomendadas: trabajos de Cloud Run con GPUs

En esta página se describen las prácticas recomendadas para optimizar el rendimiento al usar un trabajo de Cloud Run con GPU para cargas de trabajo de IA, como entrenar modelos de lenguaje extensos (LLMs) con los frameworks que prefieras, ajustar los modelos y realizar inferencias por lotes o sin conexión en LLMs. Para crear una tarea de Cloud Run que pueda realizar tareas de computación intensivas o procesamiento por lotes en tiempo real, debes hacer lo siguiente:
  • Usa modelos que se carguen rápido y requieran una transformación mínima en estructuras listas para la GPU, y optimiza la forma en que se cargan.
  • Usa configuraciones que permitan una ejecución simultánea máxima y eficiente para reducir el número de GPUs necesarias para atender una solicitud por segundo y, al mismo tiempo, mantener los costes bajos.

Formas recomendadas de cargar modelos de aprendizaje automático grandes en Cloud Run

Google recomienda almacenar los modelos de aprendizaje automático en imágenes de contenedor o optimizar su carga desde Cloud Storage.

Ventajas e inconvenientes de almacenar y cargar modelos de aprendizaje automático

A continuación se muestra una comparación de las opciones:

Ubicación del modelo Tiempo de implementación Experiencia de desarrollo Tiempo de inicio del contenedor Coste de almacenamiento
Imagen del contenedor Lento. Una imagen que contenga un modelo grande tardará más en importarse a Cloud Run. Para aplicar los cambios en la imagen del contenedor, será necesario volver a implementar la aplicación, lo que puede ser un proceso lento en el caso de imágenes grandes. Depende del tamaño del modelo. En el caso de modelos muy grandes, usa Cloud Storage para obtener un rendimiento más predecible, pero más lento. Potencialmente, varias copias en Artifact Registry.
Cloud Storage, cargado mediante el montaje de volúmenes de Cloud Storage FUSE Rápido. Modelo descargado durante el inicio del contenedor. No es difícil de configurar y no requiere cambios en la imagen de Docker. Es rápida cuando usas optimizaciones de red. No paraleliza la descarga. Una copia en Cloud Storage.
Cloud Storage, descargado simultáneamente mediante el comando gcloud storage cp de la CLI de Google Cloud o la API de Cloud Storage, tal como se muestra en el ejemplo de código de descarga simultánea del gestor de transferencias. Rápido. Modelo descargado durante el inicio del contenedor. Es un poco más difícil de configurar, ya que tendrás que instalar la CLI de Google Cloud en la imagen o actualizar el código para usar la API de Cloud Storage. Es rápida cuando usas optimizaciones de red. Google Cloud CLI descarga el archivo del modelo en paralelo, por lo que es más rápido que el montaje de FUSE. Una copia en Cloud Storage.
Internet Rápido. Modelo descargado durante el inicio del contenedor. Suele ser más sencillo (muchos frameworks descargan modelos de repositorios centrales). Normalmente, la calidad es mala e impredecible:
  • Los frameworks pueden aplicar transformaciones de modelos durante la inicialización. (Debes hacerlo en tiempo de compilación).
  • Es posible que el host del modelo y las bibliotecas para descargar el modelo no sean eficientes.
  • Descargar contenido de Internet conlleva un riesgo de fiabilidad. Es posible que el trabajo no se inicie si el destino de descarga no funciona y que el modelo subyacente descargado cambie, lo que reduce la calidad. Te recomendamos que lo alojes en tu propio segmento de Cloud Storage.
Depende del proveedor de alojamiento del modelo.

Almacenar modelos en imágenes de contenedor

Al almacenar el modelo de aprendizaje automático en la imagen de contenedor, la carga del modelo se beneficiará de la infraestructura de streaming de contenedores optimizada de Cloud Run. Sin embargo, crear imágenes de contenedor que incluyan modelos de aprendizaje automático es un proceso que requiere muchos recursos, sobre todo cuando se trabaja con modelos grandes. En concreto, el proceso de compilación puede verse limitado por el rendimiento de la red. Cuando uses Cloud Build, te recomendamos que utilices una máquina de compilación más potente con un mayor rendimiento de computación y de red. Para ello, crea una imagen con un archivo de configuración de compilación que siga estos pasos:

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'
 

Puedes crear una copia del modelo por imagen si la capa que contiene el modelo es distinta entre las imágenes (hash diferente). Puede haber costes adicionales de Artifact Registry, ya que puede haber una copia del modelo por imagen si la capa del modelo es única en cada imagen.

Almacenar modelos en Cloud Storage

Para optimizar la carga de modelos de aprendizaje automático al cargar modelos de Cloud Storage, ya sea mediante montajes de volúmenes de Cloud Storage o directamente con la API o la línea de comandos de Cloud Storage, debes usar VPC directa con el valor del ajuste de salida definido en all-traffic, junto con Acceso privado a Google.

Cargar modelos de Internet

Para optimizar la carga de modelos de AA desde Internet, dirige todo el tráfico a través de la red de VPC con el valor all-traffic en el ajuste de salida y configura Cloud NAT para acceder a Internet pública con un ancho de banda alto.

Consideraciones sobre la compilación, la implementación, el tiempo de ejecución y el diseño del sistema

En las siguientes secciones se describen las consideraciones sobre la compilación, la implementación, el tiempo de ejecución y el diseño del sistema.

En tiempo de compilación

En la siguiente lista se muestran los aspectos que debes tener en cuenta al planificar tu compilación:

  • Elige una buena imagen base. Debes empezar con una imagen de Deep Learning Containers o del registro de contenedores de NVIDIA para el framework de aprendizaje automático que estés usando. Estas imágenes tienen instalados los paquetes más recientes relacionados con el rendimiento. No recomendamos crear una imagen personalizada.
  • Elige modelos cuantizados de 4 bits para maximizar la simultaneidad, a menos que puedas demostrar que afectan a la calidad de los resultados. La cuantización produce modelos más pequeños y rápidos, lo que reduce la cantidad de memoria de GPU necesaria para servir el modelo y puede aumentar el paralelismo en el tiempo de ejecución. Lo ideal es que los modelos se entrenen con la profundidad de bits de destino en lugar de cuantificarse hasta alcanzarla.
  • Elige un formato de modelo con tiempos de carga rápidos para minimizar el tiempo de inicio del contenedor, como GGUF. Estos formatos reflejan con mayor precisión el tipo de cuantización de destino y requieren menos transformaciones cuando se cargan en la GPU. Por motivos de seguridad, no utilices puntos de control en formato pickle.
  • Crea y calienta cachés de LLM en tiempo de compilación. Inicia el LLM en la máquina de compilación mientras se compila la imagen de Docker. Habilita el almacenamiento en caché de las peticiones y proporciona peticiones comunes o de ejemplo para ayudar a calentar la caché para su uso en el mundo real. Guarda las salidas que genera para cargarlas en el tiempo de ejecución.
  • Guarda tu propio modelo de inferencia, que se genera durante el tiempo de compilación. Esto ahorra mucho tiempo en comparación con la carga de modelos almacenados de forma menos eficiente y la aplicación de transformaciones, como la cuantización, al iniciar el contenedor.

En el momento del despliegue

En la siguiente lista se muestran los aspectos que debe tener en cuenta al planificar su implementación:

  • Define un tiempo de espera de una hora o menos para las ejecuciones de trabajos.
  • Si ejecutas tareas paralelas en una ejecución de un trabajo, determina y define el paralelismo en un valor inferior al valor más bajo de los límites de cuota aplicables que hayas asignado a tu proyecto. De forma predeterminada, la cuota de instancias de trabajos de GPU es de 5 para las tareas que se ejecutan en paralelo. Para solicitar un aumento de cuota, consulta Cómo aumentar la cuota. Las tareas de GPU se inician lo antes posible y pueden alcanzar un máximo que varía en función de la cuota de GPU que hayas asignado al proyecto y a la región seleccionados. Las implementaciones fallarán si defines un paralelismo superior al límite de la cuota de GPU.

En tiempo de ejecución

  • Gestiona activamente la longitud del contexto admitida. Cuanto más pequeña sea la ventana de contexto que admitas, más consultas podrás ejecutar en paralelo. Los detalles sobre cómo hacerlo dependen del framework.
  • Usa las cachés de LLM que has generado en tiempo de compilación. Proporciona las mismas marcas que usaste durante el tiempo de compilación al generar la caché de prefijos y peticiones.
  • Carga el modelo guardado que acabas de escribir. Consulta la sección Ventajas y desventajas de almacenar y cargar modelos para ver una comparación de cómo cargar el modelo.
  • Si tu framework lo admite, considera la posibilidad de usar una caché de pares clave-valor cuantificados. Esto puede reducir los requisitos de memoria por consulta y permite configurar más paralelismo. Sin embargo, también puede afectar a la calidad.
  • Ajusta la cantidad de memoria de la GPU que se va a reservar para los pesos, las activaciones y las cachés de clave-valor del modelo. Configúralo con el valor más alto posible sin que se produzca un error de falta de memoria.
  • Comprueba si tu framework tiene alguna opción para mejorar el rendimiento de inicio del contenedor (por ejemplo, mediante la paralelización de la carga de modelos).

A nivel de diseño del sistema

  • Añade cachés semánticas cuando corresponda. En algunos casos, almacenar en caché consultas y respuestas completas puede ser una forma excelente de limitar el coste de las consultas habituales.
  • Controla la varianza de tus preámbulos. Las cachés de peticiones solo son útiles cuando contienen las peticiones en secuencia. Las cachés se almacenan en caché de prefijos. Las inserciones o las ediciones en la secuencia significan que no están en la caché o que solo están presentes parcialmente.