Optimiser plusieurs objectifs

Logo Colab Exécuter ce tutoriel sous forme de notebook dans Colab Logo GitHubAfficher le notebook sur GitHub

Ce tutoriel explique comment effectuer une optimisation multi-objectif à l'aide d'AI Platform Optimizer.

Objectif

L'objectif consiste à minimiser (minimize) la métrique d'objectif : y1 = r*sin(theta)

tout en maximisant (maximize) la métrique d'objectif : y2 = r*cos(theta)

que vous allez évaluer sur l'espace des paramètres :

  • r dans l'espace [0,1],

  • theta dans l'espace [0, pi/2].

Coûts

Ce tutoriel utilise des composants facturables de Google Cloud :

  • AI Platform Training
  • Cloud Storage

Découvrez les tarifs d'entraînement d'AI Platform et de Cloud Storage, et utilisez le simulateur de coût pour générer une estimation des coûts en fonction de votre utilisation prévue.

Packages d'installation PIP et dépendances

Installez des dépendances supplémentaires qui ne sont pas déjà installées dans l'environnement du notebook.

  • Utilisez la dernière version principale en disponibilité générale du framework.
! pip install -U google-api-python-client
! pip install -U google-cloud
! pip install -U google-cloud-storage
! pip install -U requests
! pip install -U matplotlib

# Restart the kernel after pip installs
import IPython
app = IPython.Application.instance()
app.kernel.do_shutdown(True)

Configurer un projet Google Cloud

Les étapes suivantes sont nécessaires, quel que soit l'environnement de votre notebook.

  1. Sélectionnez ou créez un projet Google Cloud.

  2. Assurez-vous que la facturation est activée pour votre projet.

  3. Activez les API AI Platform

  4. Pour une exécution en local sur votre propre ordinateur, installez le SDK Google Cloud.

  5. Saisissez l'ID de votre projet dans la cellule ci-dessous. Ensuite, exécutez la cellule pour vérifier que le SDK Cloud utilise le bon projet pour toutes les commandes de ce notebook.

Remarque : Jupyter exécute des lignes comportant le préfixe ! en tant que commandes d'interface système. Il effectue également une interpolation des variables Python précédées du préfixe $ dans ces commandes.

PROJECT_ID = "[project-id]" #@param {type:"string"}
! gcloud config set project $PROJECT_ID

Authentifier votre compte Google Cloud

Si vous utilisez des notebooks AI Platform, votre environnement est déjà authentifié. Vous pouvez ignorer ces étapes.

import sys

# If you are running this notebook in Colab, run this cell and follow the
# instructions to authenticate your Google Cloud account. This provides access
# to your Cloud Storage bucket and lets you submit training jobs and prediction
# requests.

if 'google.colab' in sys.modules:
    from google.colab import auth as google_auth
    google_auth.authenticate_user()

# If you are running this tutorial in a notebook locally, replace the string
# below with the path to your service account key and run this cell to
# authenticate your Google Cloud account.
else:
    %env GOOGLE_APPLICATION_CREDENTIALS your_path_to_credentials.json

# Log in to your account on Google Cloud
!gcloud auth login

Importer des bibliothèques

import json
import time
import datetime
from googleapiclient import errors

Tutoriel

Prérequis

Cette section définit certains des paramètres et méthodes permettant d'appeler les API AI Platform Optimizer. Pour commencer, veuillez remplir les champs suivants.

# Update to your username
USER = '[user-id]' #@param {type: 'string'}

# These will be automatically filled in.
STUDY_ID = '{}_study_{}'.format(USER, datetime.datetime.now().strftime('%Y%m%d_%H%M%S')) #@param {type: 'string'}
REGION = 'us-central1'
def study_parent():
  return 'projects/{}/locations/{}'.format(PROJECT_ID, REGION)

def study_name(study_id):
  return 'projects/{}/locations/{}/studies/{}'.format(PROJECT_ID, REGION, study_id)

def trial_parent(study_id):
  return study_name(study_id)

def trial_name(study_id, trial_id):
  return 'projects/{}/locations/{}/studies/{}/trials/{}'.format(PROJECT_ID, REGION,
                                                                study_id, trial_id)

def operation_name(operation_id):
  return 'projects/{}/locations/{}/operations/{}'.format(PROJECT_ID, REGION, operation_id)

print('USER: {}'.format(USER))
print('PROJECT_ID: {}'.format(PROJECT_ID))
print('REGION: {}'.format(REGION))
print('STUDY_ID: {}'.format(STUDY_ID))

Créer le client API

La cellule suivante crée le client API généré automatiquement à l'aide du service de découverte d'API Google. Le schéma de l'API au format JSON est hébergé dans un bucket Cloud Storage.

from google.cloud import storage
from googleapiclient import discovery

_OPTIMIZER_API_DOCUMENT_BUCKET = 'caip-optimizer-public'
_OPTIMIZER_API_DOCUMENT_FILE = 'api/ml_public_google_rest_v1.json'

def read_api_document():
  client = storage.Client(PROJECT_ID)
  bucket = client.get_bucket(_OPTIMIZER_API_DOCUMENT_BUCKET)
  blob = bucket.get_blob(_OPTIMIZER_API_DOCUMENT_FILE)
  return blob.download_as_string()

ml = discovery.build_from_document(service=read_api_document())
print('Successfully built the client.')

Créer la configuration d'étude

Voici un exemple de configuration d'étude, créée sous la forme d'un dictionnaire Python hiérarchique. Il est déjà rempli. Exécutez la cellule pour configurer l'étude.

# Parameter Configuration
param_r = {
    'parameter': 'r',
    'type' : 'DOUBLE',
    'double_value_spec' : {
        'min_value' : 0,
        'max_value' : 1
    }
}

param_theta = {
    'parameter': 'theta',
    'type' : 'DOUBLE',
    'double_value_spec' : {
        'min_value' : 0,
        'max_value' : 1.57
    }
}

# Objective Metrics
metric_y1 = {
    'metric' : 'y1',
    'goal' : 'MINIMIZE'
}

metric_y2 = {
    'metric' : 'y2',
    'goal' : 'MAXIMIZE'
}

# Put it all together in a study configuration
study_config = {
    'algorithm' : 'ALGORITHM_UNSPECIFIED',  # Let the service choose the `default` algorithm.
    'parameters' : [param_r, param_theta,],
    'metrics' : [metric_y1, metric_y2,],
}

study = {'study_config': study_config}
print(json.dumps(study, indent=2, sort_keys=True))

Créer l'étude

À présent, créez l'étude que vous exécuterez ensuite pour optimiser les deux objectifs.

# Creates a study
req = ml.projects().locations().studies().create(
    parent=study_parent(), studyId=STUDY_ID, body=study)
try :
  print(req.execute())
except errors.HttpError as e:
  if e.resp.status == 409:
    print('Study already existed.')
  else:
    raise e

Fonctions d'évaluation des métriques

Ensuite, définissez des fonctions pour évaluer les métriques des deux objectifs.

import math

# r * sin(theta)
def Metric1Evaluation(r, theta):
  """Evaluate the first metric on the trial."""
  return r * math.sin(theta)

# r * cose(theta)
def Metric2Evaluation(r, theta):
  """Evaluate the second metric on the trial."""
  return r * math.cos(theta)

def CreateMeasurement(trial_id, r, theta):
  print(("=========== Start Trial: [{0}] =============").format(trial_id))

  # Evaluate both objective metrics for this trial
  y1 = Metric1Evaluation(r, theta)
  y2 = Metric2Evaluation(r, theta)
  print('[r = {0}, theta = {1}] => y1 = r*sin(theta) = {2}, y2 = r*cos(theta) = {3}'.format(r, theta, y1, y2))
  metric1 = {'metric': 'y1', 'value': y1}
  metric2 = {'metric': 'y2', 'value': y2}

  # Return the results for this trial
  measurement = {'step_count': 1, 'metrics': [metric1, metric2,]}
  return measurement

Définir les paramètres de configuration pour l'exécution des essais

client_id : identifiant du client qui envoie la requête de suggestion. Si plusieurs requêtes d'essai de suggestion partagent le même élément client_id, le service renvoie le même essai suggéré si cet essai est dans l'état PENDING et fournit un nouvel essai si le dernier essai suggéré est terminé.

suggestion_count_per_request : nombre de suggestions (essais) demandées dans une seule requête.

max_trial_id_to_stop : nombre d'essais à explorer avant d'arrêter l'étude. Il est défini sur 4 afin d'écourter le délai d'exécution du code. Ne vous attendez donc pas à atteindre un état de convergence. Pour cela, il faudrait probablement le définir sur 20 (une bonne règle de base est de multiplier la dimensionnalité totale par 10).

client_id = 'client1' #@param {type: 'string'}
suggestion_count_per_request =  5 #@param {type: 'integer'}
max_trial_id_to_stop =  50 #@param {type: 'integer'}

print('client_id: {}'.format(client_id))
print('suggestion_count_per_request: {}'.format(suggestion_count_per_request))
print('max_trial_id_to_stop: {}'.format(max_trial_id_to_stop))

Exécuter des essais AI Platform Optimizer

Exécutez les essais.

trial_id = 0
while trial_id < max_trial_id_to_stop:
  # Requests trials.
  resp = ml.projects().locations().studies().trials().suggest(
    parent=trial_parent(STUDY_ID),
    body={'client_id': client_id, 'suggestion_count': suggestion_count_per_request}).execute()
  op_id = resp['name'].split('/')[-1]

  # Polls the suggestion long-running operations.
  get_op = ml.projects().locations().operations().get(name=operation_name(op_id))
  while True:
      operation = get_op.execute()
      if 'done' in operation and operation['done']:
        break
      time.sleep(1)

  for suggested_trial in get_op.execute()['response']['trials']:
    trial_id = int(suggested_trial['name'].split('/')[-1])
    # Featches the suggested trials.
    trial = ml.projects().locations().studies().trials().get(name=trial_name(STUDY_ID, trial_id)).execute()
    if trial['state'] in ['COMPLETED', 'INFEASIBLE']:
      continue

    # Parses the suggested parameters.
    params = {}
    for param in trial['parameters']:
      if param['parameter'] == 'r':
        r = param['floatValue']
      elif param['parameter'] == 'theta':
        theta = param['floatValue']

    # Evaluates trials and reports measurement.
    ml.projects().locations().studies().trials().addMeasurement(
        name=trial_name(STUDY_ID, trial_id),
        body={'measurement': CreateMeasurement(trial_id, r, theta)}).execute()
    # Completes the trial.
    ml.projects().locations().studies().trials().complete(
        name=trial_name(STUDY_ID, trial_id)).execute()

[EXPÉRIMENTAL] Visualiser le résultat

Cette section propose un module permettant de visualiser les essais de l'étude ci-dessus.

max_trials_to_annotate = 20

import matplotlib.pyplot as plt
trial_ids = []
y1 = []
y2 = []
resp = ml.projects().locations().studies().trials().list(parent=trial_parent(STUDY_ID)).execute()
for trial in resp['trials']:
  if 'finalMeasurement' in trial:
    trial_ids.append(int(trial['name'].split('/')[-1]))
    metrics = trial['finalMeasurement']['metrics']
    try:
        y1.append([m for m in metrics if m['metric'] == "y1"][0]['value'])
        y2.append([m for m in metrics if m['metric'] == "y2"][0]['value'])
    except:
        pass

fig, ax = plt.subplots()
ax.scatter(y1, y2)
plt.xlabel("y1=r*sin(theta)")
plt.ylabel("y2=r*cos(theta)");
for i, trial_id in enumerate(trial_ids):
  # Only annotates the last `max_trials_to_annotate` trials
  if i > len(trial_ids) - max_trials_to_annotate:
    try:
        ax.annotate(trial_id, (y1[i], y2[i]))
    except:
        pass
plt.gcf().set_size_inches((16, 16))

Nettoyer

Pour nettoyer toutes les ressources Google Cloud utilisées dans ce projet, vous pouvez supprimer le projet Google Cloud que vous avez utilisé dans ce tutoriel.