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 seguimientos clave para 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:

  • Instrumentar la aplicación de RL para emitir métricas y seguimientos. La instrumentación que se usa es para métricas y seguimientos que siguen el formato de OpenTelemetry.
  • Recopilar métricas y seguimientos cuando la aplicación se ejecuta en GKE. Los datos se recopilan con OpenTelemetry administrado para GKE (vista previa).
  • Ver las métricas recopiladas en Cloud Monitoring y los seguimientos en Cloud Trace.
  • Identificar y comprender las métricas de RL críticas basadas en las convenciones semánticas de OpenTelemetry y los indicadores clave. Los indicadores clave son las cuatro métricas clave de un servicio que proporcionan una descripción general 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 Google Cloud proyecto con la facturación habilitada.

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

  4. Habilita las siguientes Google Cloud APIs:

    • container.googleapis.com (GKE)
    • monitoring.googleapis.com (Monitoring)
    • cloudtrace.googleapis.com (Trace)
    • 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
    

    Es posible que también necesites bibliotecas de instrumentación para cualquier framework que use tu app de RL, por ejemplo, opentelemetry-instrumentation-flask.

Costos

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

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

Instrumenta tu aplicación con OpenTelemetry

Instrumenta el código de la aplicación de RL de 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 las convenciones semánticas pertinentes como atributos.

    Usa la lista de convenciones semánticas y los indicadores clave para determinar qué métricas 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, tú puedes usar OpenTelemetry administrado para GKE (vista previa). Esta función recopila datos de telemetría, como métricas y seguimientos, 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 donde 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 indicarle al SDK de OpenTelemetry 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 OpenTelemetry administrado para GKE.

    En su lugar, agrega la siguiente sección env a la especificación del contenedor en tu 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 ejecuta en el clúster de GKE, las métricas y los seguimientos se envían 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 OpenTelemetry administrado 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 métricas que comiencen con prometheus.googleapis.com/. Las métricas disponibles corresponden a las que instrumentaste en la aplicación. Algunos ejemplos de estas métricas podrían incluir los siguientes:

    • 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, lo siguiente especifica la duración del bucle para una ejecución y un algoritmo 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.

Visualiza seguimientos en Trace

Los seguimientos distribuidos proporcionan una cronología de las operaciones y te ayudan a depurar el flujo de ejecución dentro de tu sistema de RL.

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

    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 seguimientos por resource.labels.service_name="rl-training-service".

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

Convenciones semánticas y métricas clave de RL

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

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

  • Decide qué métricas y seguimientos 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 clave". Los indicadores clave son las cuatro métricas clave de un servicio que proporcionan una descripción general de su estado: Latencia, Tráfico, Errores y Saturación. Si instrumentas tu aplicación de RL con estas métricas, puedes 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 por los indicadores clave que representan en un contexto de RL.

Convenciones semánticas de RL

A continuación, se muestran 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 ejecución 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 el 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": Es el contexto para la fase de muestreo.
  • RL_SAMPLE_EPISODES = "rl.sample.episodes": Es la cantidad de episodios muestreados.
  • RL_SAMPLE_STEPS = "rl.sample.steps": Es la cantidad de pasos muestreados.
  • RL_SAMPLE_BATCH_SIZE = "rl.sample.batch_size": Es el tamaño del lote que se usa durante el muestreo.
  • RL_REWARD = "rl.reward": Es el contexto para el cálculo de recompensas.
  • RL_REWARD_BATCH_SIZE = "rl.reward.batch_size": Es el tamaño del lote para el cálculo de recompensas.
  • RL_REWARD_SANDBOX = "rl.reward.sandbox": Es el identificador del entorno de pruebas de cálculo de recompensas.
  • RL_TRAIN = "rl.train": Es el 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": Es el 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": Es el contexto para las operaciones de sincronización.
  • RL_SYNC_BYTES = "rl.sync.bytes": Son los 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 que se relacionan 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 ingeniería de confiabilidad de sitios (SRE) de Google.

Latencia

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

  • rl.loop.duration (Histograma): Una duración de bucle alta ralentiza todo el proceso de entrenamiento. La supervisión de esto ayuda a identificar regresiones de 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 recompensas puede ser complejo. El seguimiento de su latencia ayuda a optimizar este paso fundamental.
  • 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 la RL distribuida. Los tiempos de sincronización largos pueden causar datos obsoletos y ralentizar el aprendizaje.
  • rl.step.duration (Histograma): Es la 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 ocurra cuando se ejecuta tu aplicación de RL en GKE.

  • rl.sample.samples (Contador): Representa el volumen de datos de experiencia recopilados. Una disminución indica problemas en el proceso de muestreo.
  • rl.sample.episodes (Contador): Realiza un seguimiento de 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 los tokens totales procesados. Esta métrica es relevante para la RL de modelos grandes.
  • rl.tokens.rate / rl.tokens.rate_per_gpu (Indicador/Tasa): Son medidas directas de la velocidad y la eficiencia del entrenamiento, en especial en modelos basados en tokens.
  • rl.samples.rate / rl.samples.rate_per_gpu (Indicador/Tasa): Mide la rapidez con la que el sistema recopila muestras nuevas.

Errores

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

  • rl.environment.reward.mean (Indicador): Si bien no es un error tradicional, una disminución drástica en la recompensa media es una señal crítica 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 (Indicador): Al igual que la recompensa, los cambios inesperados en la duración del episodio pueden indicar problemas.
  • rl.train.loss (Indicador): Un aumento repentino o un comportamiento errático en la pérdida de 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 con la saturación que ocurra cuando se ejecuta tu aplicación de RL en GKE.

  • rl.train.mfu (Indicador): Es la utilización de Flops del modelo (MFU). Indica la eficacia con la que se usan los recursos de procesamiento (como las GPUs o las TPUs) durante el entrenamiento. Una MFU baja sugiere una subutilización o cuellos de botella.

¿Qué sigue?