Prácticas recomendadas: Trabajos de Cloud Run con GPUs

En esta página, se proporcionan prácticas recomendadas para optimizar el rendimiento cuando se usa un trabajo de Cloud Run con GPU para cargas de trabajo de IA, como entrenar modelos de lenguaje grandes (LLM) con tus frameworks preferidos, realizar ajustes y llevar a cabo inferencias por lotes o sin conexión en LLM. Para crear un trabajo de Cloud Run que pueda realizar tareas de procesamiento intensivo 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 la ejecución simultánea máxima y eficiente para reducir la cantidad de GPUs necesarias para atender una solicitud objetivo por segundo y, al mismo tiempo, mantener bajos los costos.

Formas recomendadas de cargar modelos de AA grandes en Cloud Run

Google recomienda almacenar los modelos de AA dentro de imágenes de contenedor o optimizar su carga desde Cloud Storage.

Compensaciones entre el almacenamiento y la carga de modelos de AA

A continuación, se incluye una comparación de las opciones:

Ubicación del modelo Tiempo de implementación Experiencia de desarrollo Tiempo de inicio del contenedor Costo de almacenamiento
Imagen de contenedor Lenta Una imagen que contiene un modelo grande tardará más en importarse a Cloud Run. Los cambios en la imagen del contenedor requerirán una reimplementación, que puede ser lenta para imágenes grandes. Depende del tamaño del modelo. Para modelos muy grandes, usa Cloud Storage para obtener un rendimiento más predecible, pero más lento. Es posible que haya varias copias en Artifact Registry.
Cloud Storage, cargado con la activación de volumen de Cloud Storage FUSE Rápido. El modelo se descargó 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 de forma simultánea con el comando gcloud storage cp de Google Cloud CLI o la API de Cloud Storage, como se muestra en el muestra de código de descarga simultánea del administrador de transferencias Rápido. El modelo se descargó durante el inicio del contenedor. Es un poco más difícil de configurar, ya que deberás instalar Google Cloud CLI en la imagen o actualizar tu 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, lo que lo hace más rápido que el montaje de FUSE. Una copia en Cloud Storage
Internet Rápido. El modelo se descargó durante el inicio del contenedor. Por lo general, es más simple (muchos frameworks descargan modelos de repositorios centrales). Por lo general, es deficiente e impredecible:
  • Los frameworks pueden aplicar transformaciones del modelo durante la inicialización. (deberías hacerlo en el momento de la compilación).
  • Es posible que el host del modelo y las bibliotecas para descargarlo no sean eficientes.
  • Existe un riesgo de confiabilidad asociado con la descarga desde Internet. Es posible que tu trabajo no se inicie si el destino de descarga no funciona, y el modelo subyacente descargado podría cambiar, lo que disminuye la calidad. Te recomendamos que lo alojes en tu propio bucket de Cloud Storage.
Depende del proveedor de alojamiento del modelo.

Almacena modelos en imágenes de contenedor

Al almacenar el modelo de AA en la imagen del contenedor, la carga del modelo se beneficiará de la infraestructura optimizada de transmisión de contenedores de Cloud Run. Sin embargo, compilar imágenes de contenedores que incluyan modelos de AA es un proceso que requiere muchos recursos, en especial cuando se trabaja con modelos grandes. En particular, el proceso de compilación puede verse limitado por la capacidad de procesamiento de la red. Cuando uses Cloud Build, te recomendamos que uses una máquina de compilación más potente con mayor rendimiento de procesamiento y redes. Para ello, compila una imagen con un archivo de configuración de compilación que tenga los siguientes 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). Podría haber un costo adicional de Artifact Registry, ya que podría haber una copia del modelo por imagen si la capa del modelo es única en cada imagen.

Almacena modelos en Cloud Storage

Para optimizar la carga de modelos de AA cuando se cargan modelos de AA desde Cloud Storage, ya sea con activaciones 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 de configuración de salida establecido en all-traffic, junto con el Acceso privado a Google.

Cómo cargar modelos de Internet

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

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

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

En el momento de la compilación

En la siguiente lista, se muestran las consideraciones que debes tener en cuenta cuando planifiques tu compilación:

  • Elige una buena imagen base. Debes comenzar con una imagen de los contenedores de aprendizaje profundo o del registro de contenedores de NVIDIA para el framework de IA que usas. Estas imágenes tienen instalados los paquetes relacionados con el rendimiento más recientes. No recomendamos crear una imagen personalizada.
  • Elige modelos cuantificados de 4 bits para maximizar la simultaneidad, a menos que puedas demostrar que afectan la calidad de los resultados. La cuantización produce modelos más pequeños y rápidos, reduce la cantidad de memoria de GPU necesaria para entregar 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 objetivo en lugar de cuantificarse a la baja 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 cuantificación objetivo y requieren menos transformaciones cuando se cargan en la GPU. Por motivos de seguridad, no uses puntos de control en formato pickle.
  • Crea y calienta las cachés de LLM en el momento de la 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 instrucciones y proporciona instrucciones comunes o de ejemplo para ayudar a preparar la caché para el uso en el mundo real. Guarda los resultados que genera para que se carguen durante el tiempo de ejecución.
  • Guarda tu propio modelo de inferencia que generas durante el tiempo de compilación. Esto ahorra una cantidad significativa de tiempo en comparación con la carga de modelos almacenados de manera menos eficiente y la aplicación de transformaciones, como la cuantificación, en el inicio del contenedor.

Durante la implementación

En la siguiente lista, se muestran las consideraciones que debes tener en cuenta cuando planifiques tu implementación:

  • Establece un tiempo de espera de la tarea de una hora o menos para las ejecuciones de trabajos.
  • Si ejecutas tareas paralelas en la ejecución de un trabajo, determina y establece paralelismo en un valor inferior al valor más bajo de los límites de cuota aplicables que asignaste a tu proyecto. De forma predeterminada, la cuota de instancias de trabajos de GPU se establece en 5 para las tareas que se ejecutan en paralelo. Para solicitar un aumento de la cuota, consulta Cómo aumentar la cuota. Las tareas de GPU se inician lo más rápido posible y alcanzan un máximo que varía según la cuota de GPU que asignaste para el proyecto y la región seleccionada. Las implementaciones fallan si estableces un paralelismo superior al límite de la cuota de GPU.

En el tiempo de ejecución.

  • Administra de forma activa 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 para hacerlo dependen del framework.
  • Usar las cachés del LLM que generaste en el momento de la compilación Proporciona las mismas marcas que usaste durante el tiempo de compilación cuando generaste la caché de instrucciones y prefijos.
  • Carga el modelo guardado que acabas de escribir. Consulta Almacenamiento y carga de modelos: ventajas y desventajas para obtener una comparación sobre cómo cargar el modelo.
  • Considera usar una caché de clave-valor cuantificada si tu framework la admite. Esto puede reducir los requisitos de memoria por consulta y permite configurar más paralelismo. Sin embargo, también puede afectar la calidad.
  • Ajusta la cantidad de memoria de GPU que se reservará para los pesos, las activaciones y las memorias caché de clave-valor del modelo. Establécela lo más alto posible sin que se produzca un error de memoria insuficiente.
  • Comprueba si tu framework tiene alguna opción para mejorar el rendimiento de inicio del contenedor (por ejemplo, usar la paralelización de la carga del modelo).

A nivel del diseño del sistema

  • Agrega cachés semánticas cuando corresponda. En algunos casos, almacenar en caché las consultas y respuestas completas puede ser una excelente manera de limitar el costo de las consultas comunes.
  • Controla la varianza en tus preámbulos. Las memorias caché de instrucciones solo son útiles cuando contienen las instrucciones en secuencia. Las cachés se almacenan de forma eficaz con prefijos. Las inserciones o ediciones en la secuencia significan que no están almacenadas en caché o que solo están presentes de forma parcial.