Surveiller les charges de travail d'apprentissage par renforcement sur GKE

Ce document explique comment émettre, collecter et afficher les métriques et les traces clés pour les applications d'apprentissage par renforcement (RL) basées sur Python et exécutées sur Google Kubernetes Engine (GKE).

Ce document vous explique comment :

  • Instrumentez l'application RL pour émettre des métriques et des traces. L'instrumentation utilisée concerne les métriques et les traces qui suivent le format OpenTelemetry.
  • Collectez des métriques et des traces lorsque l'application s'exécute sur GKE. Les données sont collectées à l'aide d'OpenTelemetry géré pour GKE (aperçu).
  • Affichez les métriques collectées dans Cloud Monitoring et les traces dans Cloud Trace.
  • Identifier et comprendre les métriques de RL critiques en fonction des conventions sémantiques OpenTelemetry et des signaux clés. Les signaux clés sont les quatre métriques clés d'un service qui fournissent un aperçu général de son état : latence, trafic, erreurs et saturation.

Avant de commencer

  1. Assurez-vous de disposer d'une application RL basée sur Python que vous souhaitez surveiller à l'aide de métriques et de données de trace.

  2. Assurez-vous de disposer d'un projet Google Cloud pour lequel la facturation est activée.

  3. Vous avez besoin d'un cluster GKE exécutant la version 1.34.1-gke.2178000 ou ultérieure de GKE, qui sont les versions dans lesquelles Managed OpenTelemetry pour GKE (preview) est disponible.

  4. Activez les API Google Cloud suivantes :

    • container.googleapis.com (GKE)
    • monitoring.googleapis.com (Surveillance)
    • cloudtrace.googleapis.com (Trace)
    • telemetry.googleapis.com (API Telemetry OpenTelemetry)

    Vous pouvez activer ces API à l'aide de gcloud :

    gcloud services enable \
        container.googleapis.com \
        monitoring.googleapis.com \
        cloudtrace.googleapis.com \
        telemetry.googleapis.com
    
  5. Installez le SDK OpenTelemetry : dans l'environnement de votre application Python RL, installez le SDK OpenTelemetry et l'exportateur OTLP :

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

    Vous aurez peut-être également besoin de bibliothèques d'instrumentation pour tous les frameworks utilisés par votre application RL, par exemple opentelemetry-instrumentation-flask.

Coûts

Lorsque vous envoyez des données de télémétrie à Google Cloud, vous êtes facturé en fonction du volume d'ingestion. Les métriques sont facturées selon les tarifs de Google Cloud Managed Service pour Prometheus, les journaux selon les tarifs de Cloud Logging et les traces selon les tarifs de Cloud Trace.

Pour en savoir plus sur les coûts associés à l'ingestion de traces, de journaux et de métriques Google Cloud Managed Service pour Prometheus, consultez Tarifs de Google Cloud Observability.

Instrumenter votre application avec OpenTelemetry

Instrumentez le code de votre application Python RL afin qu'il puisse émettre des métriques OpenTelemetry. Pour instrumenter l'application, procédez comme suit :

  1. Initialisez OpenTelemetry en ajoutant le code suivant à votre application :

    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. Créez des instruments pour chaque métrique et enregistrez les valeurs que vous souhaitez que l'application émette. Ajoutez les conventions sémantiques pertinentes en tant qu'attributs.

    Utilisez la liste des conventions sémantiques et des signaux clés pour déterminer les métriques à instrumenter pour votre application.

    Voici un exemple d'instruments pour des métriques spécifiques :

    # 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()
    

Maintenant que vous avez initialisé OpenTelemetry et créé des instruments pour des métriques spécifiques, l'application émet les données de télémétrie spécifiées lorsqu'elle s'exécute.

Activer la collecte des métriques et des données de trace dans GKE

Pour collecter les données de télémétrie émises par l'application lors de son exécution, vous pouvez utiliser Managed OpenTelemetry pour GKE (aperçu). Cette fonctionnalité collecte des données de télémétrie, telles que des métriques et des traces, et les envoie à Google Cloud Observability.

Pour activer et configurer Managed OpenTelemetry pour GKE, procédez comme suit :

  1. Activez Managed OpenTelemetry pour GKE sur le cluster sur lequel l'application s'exécute. Pour ce faire, suivez les étapes décrites dans Activer Managed OpenTelemetry pour GKE dans un cluster.

  2. Ajoutez des variables d'environnement à votre déploiement d'application pour indiquer au SDK OpenTelemetry d'envoyer des données de télémétrie au point de terminaison OTLP du collecteur géré. Pour une application d'apprentissage par renforcement basée sur Python, vous ne pouvez pas utiliser la fonctionnalité de configuration automatique de Managed OpenTelemetry pour GKE.

    Ajoutez plutôt la section env suivante à la spécification de votre conteneur dans le fichier manifeste de votre déploiement :

    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
    

Maintenant que l'application est instrumentée et que le collecteur géré est activé et configuré, lorsque l'application s'exécute sur le cluster GKE, les métriques et les traces sont envoyées à Google Cloud Observability.

Vous pouvez afficher ces données de télémétrie dans Monitoring et Trace.

Afficher les métriques dans Monitoring

Une fois votre application RL exécutée sur GKE avec Managed OpenTelemetry activé, les métriques sont envoyées à Monitoring. Les métriques sont généralement disponibles sous le domaine prometheus.googleapis.com/.

Pour afficher vos métriques RL personnalisées dans Monitoring, procédez comme suit :

  1. Pour afficher les métriques de RL dans un tableau de bord, vous pouvez effectuer l'une des opérations suivantes :

  2. Dans le champ Métrique du tableau de bord, recherchez les métriques commençant par prometheus.googleapis.com/. Les métriques disponibles correspondent à celles que vous avez instrumentées dans l'application. Voici quelques exemples de ces métriques :

    • prometheus.googleapis.com/rl_loop_duration_histogram/
    • prometheus.googleapis.com/rl_sample_samples_total/
    • prometheus.googleapis.com/rl_environment_reward_mean_total/
  3. Filtrer et regrouper : vous pouvez utiliser les filtres de l'explorateur de métriques pour exploiter les conventions sémantiques que vous avez ajoutées en tant qu'attributs. Par exemple, ce qui suit spécifie la durée de la boucle pour une exécution et un algorithme spécifiques :

    • Filtre : metric.label."rl_run_id" == "run-42"
    • Filtre : metric.label."rl_algorithm" == "PPO"
    • Regrouper par : metric.label."rl_environment_name" pour comparer les performances dans différents environnements.

Afficher les traces dans Trace

Les traces distribuées fournissent un calendrier des opérations et vous aident à déboguer le flux d'exécution dans votre système RL.

  1. Dans la console Google Cloud , ouvrez l'explorateur Trace dans la console Google Cloud  :

    Accéder à la page "Explorateur Trace"

  2. Vous pouvez interroger et filtrer les traces. Comme vous avez défini "service.name": "rl-training-service" comme attribut de ressource, vous pouvez filtrer les traces par resource.labels.service_name="rl-training-service".

    Les portées individuelles d'une trace représentent différentes parties de votre charge de travail RL. Ces étendues peuvent inclure des appels à des services externes ou différentes phases de la boucle RL, selon la façon dont vous avez instrumenté le traçage dans l'application.

Conventions sémantiques et signaux clés pour le RL

Cette section liste les métriques OpenTelemetry qui peuvent vous aider à identifier les problèmes qui surviennent lorsque l'application RL s'exécute sur GKE.

Utilisez les informations de cette section pour effectuer les opérations suivantes :

  • Décidez des métriques et des traces à collecter pour votre application.
  • Décidez comment afficher et utiliser les métriques et les données de trace collectées à partir de votre application.

Pour surveiller efficacement les charges de travail RL à l'aide d'OpenTelemetry, il est utile de se concentrer sur les "signaux d'or". Les signaux clés sont les quatre métriques clés d'un service qui fournissent un aperçu général de son état : latence, trafic, erreurs et saturation. En instrumentant votre application RL avec ces métriques, vous pouvez rapidement comprendre et déboguer les problèmes de performances.

Les sections suivantes présentent les conventions sémantiques et les noms de métriques classés par signaux d'or qu'ils représentent dans un contexte de RL.

Conventions sémantiques RL

Voici les attributs de vos métriques. Ces attributs fournissent un contexte pour le filtrage et l'analyse dans Monitoring.

  • RL_SYSTEM = "rl.system" : nom du système ou du framework de RL (par exemple, "MyCustomRL").
  • RL_SYSTEM_VERSION = "rl.system.version": version du système RL.
  • RL_RUN_ID = "rl.run.id" : identifiant unique d'une exécution d'entraînement spécifique.
  • RL_ALGORITHM = "rl.algorithm" : algorithme de RL utilisé (par exemple, "PPO", "DQN").
  • RL_ENVIRONMENT_NAME = "rl.environment.name" : nom de l'environnement RL (par exemple, "CartPole-v1").
  • RL_MODEL_NAME = "rl.model.name" : nom ou identifiant du modèle de stratégie/valeur.
  • RL_LOOP = "rl.loop" : identifiant de la boucle d'entraînement principale.
  • RL_LOOP_ITERATION = "rl.loop.iteration" : numéro d'itération actuel de la boucle RL.
  • RL_SAMPLE = "rl.sample" : contexte de la phase d'échantillonnage.
  • RL_SAMPLE_EPISODES = "rl.sample.episodes" : nombre d'épisodes échantillonnés.
  • RL_SAMPLE_STEPS = "rl.sample.steps" : nombre d'étapes échantillonnées.
  • RL_SAMPLE_BATCH_SIZE = "rl.sample.batch_size" : taille du lot utilisé lors de l'échantillonnage.
  • RL_REWARD = "rl.reward" : contexte pour le calcul de la récompense.
  • RL_REWARD_BATCH_SIZE = "rl.reward.batch_size" : taille du lot pour le calcul de la récompense.
  • RL_REWARD_SANDBOX = "rl.reward.sandbox" : identifiant du bac à sable de calcul des récompenses.
  • RL_TRAIN = "rl.train" : contexte de la phase d'entraînement.
  • RL_TRAIN_STEPS = "rl.train.steps" : nombre d'étapes d'entraînement.
  • RL_TRAIN_BATCH_SIZE = "rl.train.batch_size" : taille du lot utilisé pendant l'entraînement.
  • RL_TRAIN_TOKENS = "rl.train.tokens" : nombre de jetons traités pendant l'entraînement.
  • RL_SYNC = "rl.sync" : contexte pour les opérations de synchronisation.
  • RL_SYNC_BYTES = "rl.sync.bytes" : octets transférés lors de la synchronisation.
  • RL_SYNC_SOURCE = "rl.sync.source": source de la synchronisation.
  • RL_SYNC_DESTINATION = "rl.sync.destination": destination de la synchronisation.

Signaux clés et métriques RL

Les sections suivantes listent les métriques RL liées aux quatre signaux clés : latence, trafic, erreurs et saturation.

Pour en savoir plus sur les signaux clés, consultez Les quatre signaux clés au chapitre 6 du livre Google sur l'ingénierie en fiabilité des sites (SRE).

Latence

Combien de temps faut-il pour effectuer les opérations clés ? Une latence élevée peut indiquer des retards lors de l'exécution d'opérations clés. Les métriques suivantes peuvent vous aider à identifier les problèmes de latence qui se produisent lorsque votre application RL s'exécute sur GKE.

  • rl.loop.duration (histogramme) : une durée de boucle élevée ralentit l'ensemble du processus d'entraînement. Le suivi de cette métrique permet d'identifier les régressions de performances dans n'importe quelle partie du cycle RL.
  • rl.sample.duration (histogramme) : l'échantillonnage lent a un impact direct sur la vitesse à laquelle de nouvelles données sont générées pour l'entraînement.
  • rl.reward.duration (histogramme) : le calcul de la récompense peut être complexe. Le suivi de sa latence permet d'optimiser cette étape essentielle.
  • rl.train.duration (histogramme) : la durée d'entraînement est essentielle pour la vitesse d'itération. Les pics peuvent indiquer des problèmes dans l'algorithme d'entraînement ou le matériel.
  • rl.sync.duration (Histogramme) : une synchronisation efficace est essentielle dans l'apprentissage par renforcement distribué. Des temps de synchronisation longs peuvent entraîner des données obsolètes et ralentir l'apprentissage.
  • rl.step.duration (histogramme) : latence précise des étapes individuelles de l'environnement.

Trafic et débit

Quelle quantité de travail est effectuée ? Un faible débit peut signifier une utilisation inefficace des ressources. Les métriques suivantes peuvent vous aider à identifier les problèmes de trafic ou de débit qui se produisent lorsque votre application RL s'exécute sur GKE.

  • rl.sample.samples (compteur) : représente le volume de données d'expérience collectées. Une baisse indique des problèmes dans le processus d'échantillonnage.
  • rl.sample.episodes (compteur) : suit le nombre d'épisodes complets exécutés.
  • rl.train.steps (compteur) : mesure la progression de l'entraînement en termes d'étapes d'optimisation.
  • rl.train.tokens (compteur) : suit le nombre total de jetons traités. Cette métrique est pertinente pour le RL des grands modèles.
  • rl.tokens.rate / rl.tokens.rate_per_gpu (jauge/taux) : mesures directes de la vitesse et de l'efficacité de l'entraînement, en particulier dans les modèles basés sur les jetons.
  • rl.samples.rate / rl.samples.rate_per_gpu (Gauge/Rate) : mesure la vitesse à laquelle le système collecte de nouveaux échantillons.

Erreurs

Des erreurs de performances ou d'exécution sont-elles détectées ? En RL, les "erreurs" peuvent se manifester par un comportement inattendu ou de mauvaises performances. Les métriques suivantes peuvent vous aider à identifier les erreurs qui se produisent lorsque votre application RL s'exécute sur GKE.

  • rl.environment.reward.mean (Gauge) : bien qu'il ne s'agisse pas d'une erreur traditionnelle, une chute spectaculaire de la récompense moyenne est un signal critique indiquant qu'un problème est survenu dans l'interaction entre l'agent et l'environnement. Cette métrique reflète directement la progression de l'apprentissage et les performances de l'agent.
  • rl.environment.episode.length.mean (jauge) : semblable à une récompense, les changements inattendus de la durée de l'épisode peuvent signaler des problèmes.
  • rl.train.loss (Gauge) : une augmentation soudaine ou un comportement erratique de la perte d'entraînement indiquent que le modèle n'apprend pas efficacement. Indicateur fondamental de la stabilité et de la réussite de l'entraînement.

Saturation

Le système est-il surchargé ? Une saturation élevée peut entraîner une dégradation des performances. La métrique suivante peut vous aider à identifier les problèmes de saturation qui se produisent lorsque votre application RL s'exécute sur GKE.

  • rl.train.mfu (Jauge) : utilisation des FLOPS du modèle (MFU, Model Flop Utilization). Indique l'efficacité avec laquelle les ressources de calcul (telles que les GPU ou les TPU) sont utilisées pendant l'entraînement. Une faible MFU suggère une sous-utilisation ou des goulots d'étranglement.

Étapes suivantes