Supervisa las cargas de trabajo de aprendizaje por refuerzo en GKE

En este documento, se muestra cómo emitir, recopilar y ver métricas y registros clave para las aplicaciones de aprendizaje por refuerzo (RL) basadas en Python que se ejecutan en Google Kubernetes Engine (GKE).

Este documento te muestra cómo hacer lo siguiente:

  • Instrumenta la aplicación de RL para que emita métricas y registros. La instrumentación que se usa es para las métricas y los seguimientos que siguen el formato de OpenTelemetry.
  • Recopila métricas y registros cuando la aplicación se ejecuta en GKE. Los datos se recopilan con OpenTelemetry administrado para GKE (vista previa).
  • Visualiza las métricas recopiladas en Cloud Monitoring y los registros de seguimiento en Cloud Trace.
  • Identificar y comprender las métricas críticas del RL según las convenciones semánticas y los indicadores clave de OpenTelemetry Los indicadores clave son las cuatro métricas clave de un servicio que proporcionan una descripción general de alto nivel de su estado: Latencia, Tráfico, Errores y Saturación.

Antes de comenzar

  1. Asegúrate de tener una aplicación de RL basada en Python que quieras supervisar con métricas y datos de seguimiento.

  2. Asegúrate de tener un proyecto de Cloud de Confiance by S3NS con la facturación habilitada.

  3. Necesitas un clúster de GKE que ejecute la versión 1.34.1-gke.2178000 o posterior de GKE, que son las versiones en las que está disponible Managed OpenTelemetry para GKE (vista previa).

  4. Habilita las siguientes Cloud de Confiance APIs:

    • container.googleapis.com (GKE)
    • monitoring.googleapis.com (Supervisión)
    • cloudtrace.googleapis.com (Registro)
    • telemetry.googleapis.com (API de Telemetry de OpenTelemetry)

    Puedes habilitar estas APIs con gcloud:

    gcloud services enable \
        container.googleapis.com \
        monitoring.googleapis.com \
        cloudtrace.googleapis.com \
        telemetry.googleapis.com
    
  5. Instala el SDK de OpenTelemetry: En el entorno de tu aplicación de RL de Python, instala el SDK de OpenTelemetry y el exportador de OTLP:

    pip install opentelemetry-sdk \
                opentelemetry-exporter-otlp-proto-grpc \
                opentelemetry-api
    

    También es posible que necesites bibliotecas de instrumentación para los frameworks que use tu app de RL, por ejemplo, opentelemetry-instrumentation-flask.

Costos

Cuando envías datos de telemetría a Cloud de Confiance, se te factura según el volumen de transferencia. Las métricas se facturan según los precios de Google Cloud Managed Service para Prometheus, los registros se facturan según los precios de Cloud Logging y los registros de seguimiento se facturan según los precios de Cloud Trace.

Para obtener información sobre los costos asociados con la transferencia de registros, registros de seguimiento y métricas de Google Cloud Managed Service para Prometheus, consulta Precios de Google Cloud Observability.

Instrumenta tu aplicación con OpenTelemetry

Instrumenta el código de tu aplicación de RL en Python para que pueda emitir métricas de OpenTelemetry. Para instrumentar la aplicación, haz lo siguiente:

  1. Inicializa OpenTelemetry agregando el siguiente código a tu aplicación:

    import os
    import time
    from opentelemetry import metrics, trace
    from opentelemetry.sdk.metrics import MeterProvider
    from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
    from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.metrics import Counter, Histogram, UpDownCounter
    
    resource = Resource.create({
        "service.name": "rl-training-service",
        "service.namespace": "opentelemetry-demo",
    })
    
    # Initialize Metrics
    reader = PeriodicExportingMetricReader(
        OTLPMetricExporter(
            endpoint=os.environ.get("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", "localhost:4317"),
            insecure=True
        )
    )
    meter_provider = MeterProvider(metric_readers=[reader], resource=resource)
    metrics.set_meter_provider(meter_provider)
    meter = metrics.get_meter("rl-training-meter")
    
    # Initialize Tracing
    trace_provider = TracerProvider(resource=resource)
    trace_processor = BatchSpanProcessor(
        OTLPSpanExporter(
            endpoint=os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "localhost:4317"),
            insecure=True
        )
    )
    trace_provider.add_span_processor(trace_processor)
    trace.set_tracer_provider(trace_provider)
    tracer = trace.get_tracer("rl-training-tracer")
    
  2. Crea instrumentos para cada métrica y registra los valores que deseas que emita la aplicación. Adjunta convenciones semánticas pertinentes como atributos.

    Usa la lista de convenciones semánticas y los indicadores dorados para determinar qué métricas debes instrumentar para tu aplicación.

    A continuación, se muestra un ejemplo de instrumentos para métricas específicas:

    # Latency Histograms
    rl_loop_duration = meter.create_histogram(
        name="rl.loop.duration", description="Duration of a single RL loop iteration.", unit="ms"
    )
    rl_sample_duration = meter.create_histogram(
        name="rl.sample.duration", description="Duration of the sampling phase.", unit="ms"
    )
    rl_train_duration = meter.create_histogram(
        name="rl.train.duration", description="Duration of the training phase.", unit="ms"
    )
    # ... create other duration histograms (reward, train, sync, step)
    
    # Throughput Counters
    rl_sample_samples = meter.create_counter(
        name="rl.sample.samples", description="Number of samples generated.", unit="{samples}"
    )
    rl_train_steps = meter.create_counter(
        name="rl.train.steps", description="Number of training steps completed.", unit="{steps}"
    )
    # ... create other counter metrics (rl.sample.episodes, rl.train.tokens)
    
    # Performance/Saturation Gauges (using UpDownCounter)
    rl_reward_mean = meter.create_up_down_counter(
        name="rl.environment.reward.mean", description="Mean reward observed.", unit="1"
    )
    rl_train_loss = meter.create_up_down_counter(
        name="rl.train.loss", description="Current training loss.", unit="1"
    )
    rl_train_mfu = meter.create_up_down_counter(
        name="rl.train.mfu", description="Model Flop Utilization.", unit="1"
    )
    _rl_reward_mean_val, _rl_train_loss_val = 0.0, 0.0
    
    def get_common_attributes(rl_system, rl_run_id, rl_algorithm, rl_env_name, rl_model_name):
        return {
            "rl.system": rl_system,
            "rl.run.id": rl_run_id,
            "rl.algorithm": rl_algorithm,
            "rl.environment.name": rl_env_name,
            "rl.model.name": rl_model_name,
        }
    
    # Example Usage within your RL code:
    common_attrs = get_common_attributes("MyPPO", "run-42", "PPO", "Acrobot-v1", "PolicyModelV1")
    
    # Inside the main RL loop:
    with tracer.start_as_current_span("rl_loop_iteration", attributes={**common_attrs, "rl.loop.iteration": 5}) as span:
        loop_start_time = time.perf_counter()
    # --- Sampling Phase ---
    sample_start = time.perf_counter()
    # ... perform sampling ...
    sampled_count = 1024
    rl_sample_samples.add(sampled_count, attributes={**common_attrs, "rl.sample.batch_size": 128})
    rl_sample_duration.record((time.perf_counter() - sample_start) * 1000, attributes=common_attrs)
    
    # --- Training Phase ---
    train_start = time.perf_counter()
    # ... perform training step ...
    rl_train_steps.add(1, attributes={**common_attrs, "rl.loop.iteration": 5})
    current_loss = 0.125
    rl_train_loss.add(current_loss - _rl_train_loss_val, attributes=common_attrs) # Record current loss
    _rl_train_loss_val = current_loss
    rl_train_duration.record((time.perf_counter() - train_start) * 1000, attributes=common_attrs)
    
    # --- Record Mean Reward ---
    current_mean_reward = -5.5
    rl_reward_mean.add(current_mean_reward - _rl_reward_mean_val, attributes=common_attrs)
    _rl_reward_mean_val = current_mean_reward
    
    loop_duration = (time.perf_counter() - loop_start_time) * 1000
    rl_loop_duration.record(loop_duration, attributes={**common_attrs, "rl.loop.iteration": 5})
    
    # Ensure metrics are pushed before application exit in short-lived scripts
    # For long-running services, PeriodicExportingMetricReader handles this.
    # meter_provider.shutdown()
    

Ahora que inicializaste OpenTelemetry y creaste instrumentos para métricas específicas, la aplicación emite los datos de telemetría especificados cuando se ejecuta.

Habilita la recopilación de métricas y datos de seguimiento en GKE

Para recopilar los datos de telemetría que emite la aplicación mientras se ejecuta, puedes usar Managed OpenTelemetry para GKE (vista previa). Esta función recopila datos de telemetría, como métricas y registros de seguimiento, y los envía a Google Cloud Observability.

Para habilitar y configurar OpenTelemetry administrado para GKE, haz lo siguiente:

  1. Habilita OpenTelemetry administrado para GKE en el clúster en el que se ejecuta la aplicación. Para ello, sigue los pasos que se indican en Habilita OpenTelemetry administrado para GKE en un clúster.

  2. Anota la Deployment de tu aplicación con variables de entorno para dirigir el SDK de OpenTelemetry para que envíe datos de telemetría al extremo de OTLP del recopilador administrado. En el caso de una aplicación de RL basada en Python, no puedes usar la función de configuración automática de Managed OpenTelemetry para GKE.

    En su lugar, agrega la siguiente sección env a la especificación del contenedor en el manifiesto de Deployment:

    env:
      - name: OTEL_COLLECTOR_NAME
        value: 'opentelemetry-collector'
      - name: OTEL_COLLECTOR_NAMESPACE
        value: 'gke-managed-otel'
      - name: OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
        value: $(OTEL_COLLECTOR_NAME).$(OTEL_COLLECTOR_NAMESPACE).svc.cluster.local:4317
      - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
        value: $(OTEL_COLLECTOR_NAME).$(OTEL_COLLECTOR_NAMESPACE).svc.cluster.local:4317
      - name: OTEL_SERVICE_NAME
        value: 'rl-training-service'
      - name: OTEL_RESOURCE_ATTRIBUTES
        value: service.namespace=opentelemetry-demo
    

Ahora que la aplicación está instrumentada y el recopilador administrado está habilitado y configurado, cuando la aplicación se ejecute en el clúster de GKE, las métricas y los seguimientos se enviarán a Google Cloud Observability.

Puedes ver estos datos de telemetría en Monitoring y Trace.

Visualiza métricas en Monitoring

Una vez que tu aplicación de RL se ejecuta en GKE con Managed OpenTelemetry habilitado, las métricas se envían a Monitoring. Por lo general, las métricas están disponibles en el dominio prometheus.googleapis.com/.

Para ver tus métricas de RL personalizadas en Monitoring, haz lo siguiente:

  1. Para ver las métricas de RL en un panel, puedes hacer una de las siguientes acciones:

  2. En el campo Métrica del panel, busca las métricas que comiencen con prometheus.googleapis.com/. Las métricas disponibles corresponden a las que instrumentaste en la aplicación. Estos son algunos ejemplos de estas métricas:

    • prometheus.googleapis.com/rl_loop_duration_histogram/
    • prometheus.googleapis.com/rl_sample_samples_total/
    • prometheus.googleapis.com/rl_environment_reward_mean_total/
  3. Filtrado y agrupación: Puedes usar los filtros en el Explorador de métricas para aprovechar las convenciones semánticas que agregaste como atributos. Por ejemplo, el siguiente comando especifica la duración del bucle para un algoritmo y una ejecución específicos:

    • Filtro: metric.label."rl_run_id" == "run-42"
    • Filtro: metric.label."rl_algorithm" == "PPO"
    • Agrupar por: metric.label."rl_environment_name" para comparar el rendimiento en diferentes entornos.

Cómo ver seguimientos en Trace

Los registros de seguimiento distribuidos proporcionan una línea de tiempo de las operaciones y te ayudan a depurar el flujo de ejecución dentro de tu sistema de RL.

  1. En la consola de Cloud de Confiance , abre Explorador de seguimiento en la consola de Cloud de Confiance :

    Ir a la página Explorador de seguimiento

  2. Puedes consultar y filtrar seguimientos. Como estableciste "service.name": "rl-training-service" como un atributo de recurso, puedes filtrar los registros por resource.labels.service_name="rl-training-service".

    Los intervalos individuales dentro de un registro representan diferentes partes de tu carga de trabajo de AA. Estos intervalos pueden incluir llamadas a servicios externos o diferentes fases del bucle de RL, según cómo hayas instrumentado el seguimiento en la aplicación.

Convenciones semánticas y los indicadores clave de RL

En esta sección, se enumeran las métricas de OpenTelemetry que pueden ayudarte a identificar los problemas que se producen mientras se ejecuta la aplicación de RL en GKE.

Usa la información de esta sección para hacer lo siguiente:

  • Decide qué métricas y registros recopilar para tu aplicación.
  • Decide cómo ver y usar las métricas y los datos de seguimiento recopilados de tu aplicación.

Para supervisar de manera eficaz las cargas de trabajo de RL con OpenTelemetry, es útil enfocarse en los "indicadores dorados". Los indicadores clave son las cuatro métricas clave de un servicio que proporcionan una descripción general de alto nivel de su estado: Latencia, Tráfico, Errores y Saturación. Si instrumentas tu aplicación de AA con estas métricas, podrás comprender y depurar rápidamente los problemas de rendimiento.

En las siguientes secciones, se incluyen las convenciones semánticas y los nombres de las métricas categorizados según los indicadores clave de rendimiento que representan en un contexto de RL.

Convenciones semánticas de RL

A continuación, se indican los atributos de tus métricas. Estos atributos proporcionan contexto para el filtrado y el análisis en Monitoring.

  • RL_SYSTEM = "rl.system": Es el nombre del sistema o framework de RL (por ejemplo, "MyCustomRL").
  • RL_SYSTEM_VERSION = "rl.system.version": Es la versión del sistema de RL.
  • RL_RUN_ID = "rl.run.id": Es el identificador único de una ronda de entrenamiento específica.
  • RL_ALGORITHM = "rl.algorithm": Es el algoritmo de RL que se usa (por ejemplo, "PPO", "DQN").
  • RL_ENVIRONMENT_NAME = "rl.environment.name": Es el nombre del entorno de RL (por ejemplo, "CartPole-v1").
  • RL_MODEL_NAME = "rl.model.name": Es el nombre o identificador del modelo de política o valor.
  • RL_LOOP = "rl.loop": Es el identificador del bucle de entrenamiento principal.
  • RL_LOOP_ITERATION = "rl.loop.iteration": Es el número de iteración actual del bucle de RL.
  • RL_SAMPLE = "rl.sample": Contexto para la fase de muestreo.
  • RL_SAMPLE_EPISODES = "rl.sample.episodes": Es la cantidad de episodios incluidos en la muestra.
  • RL_SAMPLE_STEPS = "rl.sample.steps": Es la cantidad de pasos muestreados.
  • RL_SAMPLE_BATCH_SIZE = "rl.sample.batch_size": Tamaño del lote que se usa durante el muestreo.
  • RL_REWARD = "rl.reward": Es el contexto para el cálculo de la recompensa.
  • RL_REWARD_BATCH_SIZE = "rl.reward.batch_size": Tamaño del lote para el cálculo de la recompensa.
  • RL_REWARD_SANDBOX = "rl.reward.sandbox": Es el identificador de la zona de pruebas de cálculo de recompensas.
  • RL_TRAIN = "rl.train": Contexto para la fase de entrenamiento.
  • RL_TRAIN_STEPS = "rl.train.steps": Es la cantidad de pasos de entrenamiento.
  • RL_TRAIN_BATCH_SIZE = "rl.train.batch_size": Tamaño del lote que se usa durante el entrenamiento.
  • RL_TRAIN_TOKENS = "rl.train.tokens": Es la cantidad de tokens procesados durante el entrenamiento.
  • RL_SYNC = "rl.sync": Contexto para las operaciones de sincronización.
  • RL_SYNC_BYTES = "rl.sync.bytes": Bytes transferidos durante la sincronización.
  • RL_SYNC_SOURCE = "rl.sync.source": Es la fuente de la sincronización.
  • RL_SYNC_DESTINATION = "rl.sync.destination": Es el destino de la sincronización.

Indicadores clave y métricas de RL

En las siguientes secciones, se enumeran las métricas de RL relacionadas con los cuatro indicadores clave: Latencia, Tráfico, Errores y Saturación.

Para obtener detalles sobre los indicadores clave, consulta Los cuatro indicadores clave en el capítulo 6 del libro de ingeniería de confiabilidad de sitios (SRE) de Google.

Latencia

¿Cuánto tiempo lleva completar las operaciones clave? Una latencia alta puede indicar demoras en la finalización de operaciones clave. Las siguientes métricas pueden ayudarte a identificar cualquier problema de latencia que se produzca mientras tu aplicación de RL se ejecuta en GKE.

  • rl.loop.duration (Histograma): Una duración alta del bucle ralentiza todo el proceso de entrenamiento. Supervisar esto ayuda a identificar regresiones en el rendimiento en cualquier parte del ciclo de RL.
  • rl.sample.duration (Histograma): El muestreo lento afecta directamente la rapidez con la que se generan datos nuevos para el entrenamiento.
  • rl.reward.duration (Histograma): El cálculo de la recompensa puede ser complejo. Hacer un seguimiento de su latencia ayuda a optimizar este paso crítico.
  • rl.train.duration (Histograma): El tiempo de entrenamiento es fundamental para la velocidad de iteración. Los picos aquí pueden indicar problemas en el algoritmo de entrenamiento o el hardware.
  • rl.sync.duration (Histograma): La sincronización eficiente es vital en el RL distribuido. Los tiempos de sincronización prolongados pueden provocar datos inactivos y ralentizar el aprendizaje.
  • rl.step.duration (Histograma): Latencia detallada de los pasos individuales del entorno.

Tráfico y capacidad de procesamiento

¿Cuánto trabajo se está realizando? Una capacidad de procesamiento baja puede significar un uso ineficiente de los recursos. Las siguientes métricas pueden ayudarte a identificar cualquier problema con el tráfico o la capacidad de procesamiento que se produzca mientras tu aplicación de RL se ejecuta en GKE.

  • rl.sample.samples (contador): Representa el volumen de datos de experiencia recopilados. Una caída indica problemas en el proceso de muestreo.
  • rl.sample.episodes (contador): Registra la cantidad de episodios completos ejecutados.
  • rl.train.steps (contador): Mide el progreso del entrenamiento en términos de pasos de optimización.
  • rl.train.tokens (contador): Realiza un seguimiento de la cantidad total de tokens procesados. Esta métrica es relevante para el RL de modelos grandes.
  • rl.tokens.rate / rl.tokens.rate_per_gpu (medidor/tasa): Son medidas directas de la velocidad y la eficiencia del entrenamiento, en especial en los modelos basados en tokens.
  • rl.samples.rate / rl.samples.rate_per_gpu (medidor/tasa): Mide la rapidez con la que el sistema recopila muestras nuevas.

Errores

¿Hay errores de rendimiento o de ejecución? En el RL, los "errores" pueden manifestarse como un comportamiento inesperado o un rendimiento deficiente. Las siguientes métricas pueden ayudarte a identificar los errores que se producen cuando tu aplicación de RL se ejecuta en GKE.

  • rl.environment.reward.mean (Medidor): Si bien no es un error tradicional, una disminución drástica en la recompensa media es un indicador crítico de que algo anda mal con la interacción del agente o el entorno. Esta métrica refleja directamente el progreso del aprendizaje y el rendimiento del agente.
  • rl.environment.episode.length.mean (Medidor): Similar a la recompensa, los cambios inesperados en la duración del episodio pueden indicar problemas.
  • rl.train.loss (Medidor): Un aumento repentino o un comportamiento errático en la pérdida del entrenamiento indica que el modelo no está aprendiendo de manera eficaz. Es un indicador fundamental de la estabilidad y el éxito del entrenamiento.

Saturación

¿El sistema está sobrecargado? Una saturación alta puede provocar una degradación del rendimiento. La siguiente métrica puede ayudarte a identificar cualquier problema de saturación que se produzca mientras tu aplicación de RL se ejecuta en GKE.

  • rl.train.mfu (Medidor): Es la utilización de FLOPS del modelo (MFU). Indica la eficacia con la que se usan los recursos de procesamiento (como las GPU o las TPU) durante el entrenamiento. Un MFU bajo sugiere una subutilización o cuellos de botella.

¿Qué sigue?