Exécuter ce tutoriel sous forme de notebook dans Colab | Afficher le notebook sur GitHub |
Ce tutoriel explique comment effectuer une optimisation d'objectif conditionnelle à l'aide d'AI Platform Optimizer.
Dataset
Dans cet exemple d'entraînement, l'ensemble de données "Revenu selon le recensement" est hébergé dans le dépôt de machine learning de l'Université de Californie à Irvine.
En s'appuyant sur des données de recensement telles que l'âge, l'éducation, l'état civil et la profession (les caractéristiques), l'objectif consiste à prédire si une personne gagne plus de 50 000 dollars par an (étiquette cible). Vous allez entraîner un modèle de régression logistique qui, en fonction des informations concernant un individu, génère un nombre compris entre 0 et 1. Ce nombre peut être interprété comme la probabilité que l'individu perçoive un revenu annuel supérieur à 50 000 dollars.
Objectif
Ce tutoriel explique comment optimiser la recherche d'hyperparamètres pour des modèles de machine learning à l'aide d'AI Platform Optimizer.
Cet exemple met en œuvre une démonstration d'apprentissage automatique afin d'optimiser un modèle de classification sur un ensemble de données de recensement à l'aide d'AI Platform Optimizer et des algorithmes intégrés à l'API Training d'AI Platform. Vous utilisez AI Platform Optimizer pour obtenir les valeurs suggérées des hyperparamètres et envoyer des tâches d'entraînement de modèle selon ces valeurs via les algorithmes intégrés de l'API Training d'AI Platform.
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
# Automatically restart kernel after 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.
Assurez-vous que la facturation est activée pour votre projet.
Si vous exécutez ce notebook en local, vous devez installer le SDK Google Cloud.
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.
La cellule ci-dessous exige de s'authentifier deux fois.
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 application-default login
! 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'}
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.')
Configuration de l'étude
Dans ce tutoriel, AI Platform Optimizer crée une étude et demande des essais. Pour chaque essai, vous allez créer une tâche d'algorithme intégré à l'API Training d'AI Platform pour entraîner le modèle à l'aide des hyperparamètres suggérés. Pour chaque essai, une mesure indique la précision du modèle (accuracy
).
Les caractéristiques correspondant au paramètre conditionnel, fournies par AI Platform Optimizer, définissent un espace de recherche d'hyperparamètres sous forme d'arborescence. L'hyperparamètre de premier niveau est model_type
. Il est défini entre LINEAR
et WIDE_AND_DEEP
. Chaque type de modèle possède des hyperparamètres de second niveau correspondants qui doivent être réglés :
- Si
model_type
est défini surLINEAR
, le paramètrelearning_rate
est réglé. - Si
model_type
est défini surWIDE_AND_DEEP
, les paramètreslearning_rate
etdnn_learning_rate
sont réglés.
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.
param_learning_rate = {
'parameter': 'learning_rate',
'type' : 'DOUBLE',
'double_value_spec' : {
'min_value' : 0.00001,
'max_value' : 1.0
},
'scale_type' : 'UNIT_LOG_SCALE',
'parent_categorical_values' : {
'values': ['LINEAR', 'WIDE_AND_DEEP']
},
}
param_dnn_learning_rate = {
'parameter': 'dnn_learning_rate',
'type' : 'DOUBLE',
'double_value_spec' : {
'min_value' : 0.00001,
'max_value' : 1.0
},
'scale_type' : 'UNIT_LOG_SCALE',
'parent_categorical_values' : {
'values': ['WIDE_AND_DEEP']
},
}
param_model_type = {
'parameter': 'model_type',
'type' : 'CATEGORICAL',
'categorical_value_spec' : {'values': ['LINEAR', 'WIDE_AND_DEEP']},
'child_parameter_specs' : [param_learning_rate, param_dnn_learning_rate,]
}
metric_accuracy = {
'metric' : 'accuracy',
'goal' : 'MAXIMIZE'
}
study_config = {
'algorithm' : 'ALGORITHM_UNSPECIFIED', # Let the service choose the `default` algorithm.
'parameters' : [param_model_type,],
'metrics' : [metric_accuracy,],
}
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 l'objectif.
# 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
Définir les paramètres d'entrée et de sortie
Définissez ensuite les paramètres de sortie suivants.
OUTPUT_BUCKET
et OUTPUT_DIR
correspondent au bucket Cloud Storage et au répertoire utilisés en tant que "job_dir" pour les tâches de l'API Training AI Platform. OUTPUT_BUCKET
doit correspondre à un bucket dans votre projet et OUTPUT_DIR
au nom que vous souhaitez attribuer au dossier de sortie de votre bucket.
job_dir
doit être défini au format "gs://$OUTPUT_BUCKET/$OUTPUT_DIR/".
TRAINING_DATA_PATH
correspond au chemin d'accès à l'ensemble de données d'entrée d'entraînement.
# `job_dir` will be `gs://${OUTPUT_BUCKET}/${OUTPUT_DIR}/${job_id}`
OUTPUT_BUCKET = '[output-bucket-name]' #@param {type: 'string'}
OUTPUT_DIR = '[output-dir]' #@param {type: 'string'}
TRAINING_DATA_PATH = 'gs://caip-optimizer-public/sample-data/raw_census_train.csv' #@param {type: 'string'}
print('OUTPUT_BUCKET: {}'.format(OUTPUT_BUCKET))
print('OUTPUT_DIR: {}'.format(OUTPUT_DIR))
print('TRAINING_DATA_PATH: {}'.format(TRAINING_DATA_PATH))
# Create the bucket in Cloud Storage
! gcloud storage buckets create gs://$OUTPUT_BUCKET/ --project=$PROJECT_ID
Évaluation des métriques
Cette section définit les méthodes d'évaluation des essais.
Pour chaque essai, vous envoyez une tâche d'algorithme intégré à AI Platform pour entraîner le modèle de machine learning à l'aide des hyperparamètres suggérés par AI Platform Optimizer. Une fois terminée, chaque tâche écrit le fichier de résumé du modèle dans Cloud Storage. Vous pouvez récupérer la précision du modèle à partir du répertoire des tâches et l'enregistrer en tant qu'élément final_measurement
de l'essai.
import logging
import math
import subprocess
import os
import yaml
from google.cloud import storage
_TRAINING_JOB_NAME_PATTERN = '{}_condition_parameters_{}_{}'
_IMAGE_URIS = {'LINEAR' : 'gcr.io/cloud-ml-algos/linear_learner_cpu:latest',
'WIDE_AND_DEEP' : 'gcr.io/cloud-ml-algos/wide_deep_learner_cpu:latest'}
_STEP_COUNT = 'step_count'
_ACCURACY = 'accuracy'
def EvaluateTrials(trials):
"""Evaluates trials by submitting training jobs to AI Platform Training service.
Args:
trials: List of Trials to evaluate
Returns: A dict of <trial_id, measurement> for the given trials.
"""
trials_by_job_id = {}
mesurement_by_trial_id = {}
# Submits a AI Platform Training job for each trial.
for trial in trials:
trial_id = int(trial['name'].split('/')[-1])
model_type = _GetSuggestedParameterValue(trial, 'model_type', 'stringValue')
learning_rate = _GetSuggestedParameterValue(trial, 'learning_rate',
'floatValue')
dnn_learning_rate = _GetSuggestedParameterValue(trial, 'dnn_learning_rate',
'floatValue')
job_id = _GenerateTrainingJobId(model_type=model_type,
trial_id=trial_id)
trials_by_job_id[job_id] = {
'trial_id' : trial_id,
'model_type' : model_type,
'learning_rate' : learning_rate,
'dnn_learning_rate' : dnn_learning_rate,
}
_SubmitTrainingJob(job_id, trial_id, model_type, learning_rate, dnn_learning_rate)
# Waits for completion of AI Platform Training jobs.
while not _JobsCompleted(trials_by_job_id.keys()):
time.sleep(60)
# Retrieves model training result(e.g. global_steps, accuracy) for AI Platform Training jobs.
metrics_by_job_id = _GetJobMetrics(trials_by_job_id.keys())
for job_id, metric in metrics_by_job_id.items():
measurement = _CreateMeasurement(trials_by_job_id[job_id]['trial_id'],
trials_by_job_id[job_id]['model_type'],
trials_by_job_id[job_id]['learning_rate'],
trials_by_job_id[job_id]['dnn_learning_rate'],
metric)
mesurement_by_trial_id[trials_by_job_id[job_id]['trial_id']] = measurement
return mesurement_by_trial_id
def _CreateMeasurement(trial_id, model_type, learning_rate, dnn_learning_rate, metric):
if not metric[_ACCURACY]:
# Returns `none` for trials without metrics. The trial will be marked as `INFEASIBLE`.
return None
print(
'Trial {0}: [model_type = {1}, learning_rate = {2}, dnn_learning_rate = {3}] => accuracy = {4}'.format(
trial_id, model_type, learning_rate,
dnn_learning_rate if dnn_learning_rate else 'N/A', metric[_ACCURACY]))
measurement = {
_STEP_COUNT: metric[_STEP_COUNT],
'metrics': [{'metric': _ACCURACY, 'value': metric[_ACCURACY]},]}
return measurement
def _SubmitTrainingJob(job_id, trial_id, model_type, learning_rate, dnn_learning_rate=None):
"""Submits a built-in algo training job to AI Platform Training Service."""
try:
if model_type == 'LINEAR':
subprocess.check_output(_LinearCommand(job_id, learning_rate), stderr=subprocess.STDOUT)
elif model_type == 'WIDE_AND_DEEP':
subprocess.check_output(_WideAndDeepCommand(job_id, learning_rate, dnn_learning_rate), stderr=subprocess.STDOUT)
print('Trial {0}: Submitted job [https://console.cloud.google.com/ai-platform/jobs/{1}?project={2}].'.format(trial_id, job_id, PROJECT_ID))
except subprocess.CalledProcessError as e:
logging.error(e.output)
def _GetTrainingJobState(job_id):
"""Gets a training job state."""
cmd = ['gcloud', 'ai-platform', 'jobs', 'describe', job_id,
'--project', PROJECT_ID,
'--format', 'json']
try:
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, timeout=3)
except subprocess.CalledProcessError as e:
logging.error(e.output)
return json.loads(output)['state']
def _JobsCompleted(jobs):
"""Checks if all the jobs are completed."""
all_done = True
for job in jobs:
if _GetTrainingJobState(job) not in ['SUCCEEDED', 'FAILED', 'CANCELLED']:
print('Waiting for job[https://console.cloud.google.com/ai-platform/jobs/{0}?project={1}] to finish...'.format(job, PROJECT_ID))
all_done = False
return all_done
def _RetrieveAccuracy(job_id):
"""Retrices the accuracy of the trained model for a built-in algorithm job."""
storage_client = storage.Client(project=PROJECT_ID)
bucket = storage_client.get_bucket(OUTPUT_BUCKET)
blob_name = os.path.join(OUTPUT_DIR, job_id, 'model/deployment_config.yaml')
blob = storage.Blob(blob_name, bucket)
try:
blob.reload()
content = blob.download_as_string()
accuracy = float(yaml.safe_load(content)['labels']['accuracy']) / 100
step_count = int(yaml.safe_load(content)['labels']['global_step'])
return {_STEP_COUNT: step_count, _ACCURACY: accuracy}
except:
# Returns None if failed to load the built-in algo output file.
# It could be due to job failure and the trial will be `INFEASIBLE`
return None
def _GetJobMetrics(jobs):
accuracies_by_job_id = {}
for job in jobs:
accuracies_by_job_id[job] = _RetrieveAccuracy(job)
return accuracies_by_job_id
def _GetSuggestedParameterValue(trial, parameter, value_type):
param_found = [p for p in trial['parameters'] if p['parameter'] == parameter]
if param_found:
return param_found[0][value_type]
else:
return None
def _GenerateTrainingJobId(model_type, trial_id):
return _TRAINING_JOB_NAME_PATTERN.format(STUDY_ID, model_type, trial_id)
def _GetJobDir(job_id):
return os.path.join('gs://', OUTPUT_BUCKET, OUTPUT_DIR, job_id)
def _LinearCommand(job_id, learning_rate):
return ['gcloud', 'ai-platform', 'jobs', 'submit', 'training', job_id,
'--scale-tier', 'BASIC',
'--region', 'us-central1',
'--master-image-uri', _IMAGE_URIS['LINEAR'],
'--project', PROJECT_ID,
'--job-dir', _GetJobDir(job_id),
'--',
'--preprocess',
'--model_type=classification',
'--batch_size=250',
'--max_steps=1000',
'--learning_rate={}'.format(learning_rate),
'--training_data_path={}'.format(TRAINING_DATA_PATH)]
def _WideAndDeepCommand(job_id, learning_rate, dnn_learning_rate):
return ['gcloud', 'ai-platform', 'jobs', 'submit', 'training', job_id,
'--scale-tier', 'BASIC',
'--region', 'us-central1',
'--master-image-uri', _IMAGE_URIS['WIDE_AND_DEEP'],
'--project', PROJECT_ID,
'--job-dir', _GetJobDir(job_id),
'--',
'--preprocess',
'--test_split=0',
'--use_wide',
'--embed_categories',
'--model_type=classification',
'--batch_size=250',
'--learning_rate={}'.format(learning_rate),
'--dnn_learning_rate={}'.format(dnn_learning_rate),
'--max_steps=1000',
'--training_data_path={}'.format(TRAINING_DATA_PATH)]
Configuration pour l'envoi de requêtes de suggestions/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 = 2 #@param {type: 'integer'}
max_trial_id_to_stop = 4 #@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))
Demander et exécuter des essais AI Platform Optimizer
Exécutez les essais.
current_trial_id = 0
while current_trial_id < max_trial_id_to_stop:
# Request 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)
# Featches the suggested trials.
trials = []
for suggested_trial in get_op.execute()['response']['trials']:
trial_id = int(suggested_trial['name'].split('/')[-1])
trial = ml.projects().locations().studies().trials().get(name=trial_name(STUDY_ID, trial_id)).execute()
if trial['state'] not in ['COMPLETED', 'INFEASIBLE']:
print("Trial {}: {}".format(trial_id, trial))
trials.append(trial)
# Evaluates trials - Submit model training jobs using AI Platform Training built-in algorithms.
measurement_by_trial_id = EvaluateTrials(trials)
# Completes trials.
for trial in trials:
trial_id = int(trial['name'].split('/')[-1])
current_trial_id = trial_id
measurement = measurement_by_trial_id[trial_id]
print(("=========== Complete Trial: [{0}] =============").format(trial_id))
if measurement:
# Completes trial by reporting final measurement.
ml.projects().locations().studies().trials().complete(
name=trial_name(STUDY_ID, trial_id),
body={'final_measurement' : measurement}).execute()
else:
# Marks trial as `infeasbile` if when missing final measurement.
ml.projects().locations().studies().trials().complete(
name=trial_name(STUDY_ID, trial_id),
body={'trial_infeasible' : True}).execute()
[FACULTATIF] Créer des essais en utilisant vos propres paramètres
L'API AI Platform Optimizer permet aux utilisateurs de demander des suggestions (méthode suggest
) de paramètres au service, mais également de créer des essais (méthode create
) à l'aide de leurs propres paramètres. AI Platform Optimizer vous permet de conserver une trace des tests effectués par les utilisateurs et d'exploiter ces informations pour générer de nouvelles suggestions.
Par exemple, si vous exécutez une tâche d'entraînement de modèle en utilisant vos propres paramètres model_type
et learning_rate
au lieu de ceux suggérés par AI Platform Optimizer, vous pouvez créer un essai afin de tester cette tâche dans le cadre de l'étude.
# User has to leave `trial.name` unset in CreateTrial request, the service will
# assign it.
custom_trial = {
"clientId": "client1",
"finalMeasurement": {
"metrics": [
{
"metric": "accuracy",
"value": 0.86
}
],
"stepCount": "1000"
},
"parameters": [
{
"parameter": "model_type",
"stringValue": "LINEAR"
},
{
"floatValue": 0.3869103706121445,
"parameter": "learning_rate"
}
],
"state": "COMPLETED"
}
trial = ml.projects().locations().studies().trials().create(
parent=trial_parent(STUDY_ID), body=custom_trial).execute()
print(json.dumps(trial, indent=2, sort_keys=True))
Répertorier les essais
Répertoriez les résultats de chaque essai d'optimisation d'entraînement.
resp = ml.projects().locations().studies().trials().list(parent=trial_parent(STUDY_ID)).execute()
print(json.dumps(resp, indent=2, sort_keys=True))
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.