Ottimizzazione di un modello di machine learning

Logo Colab Esegui questo tutorial come blocco note in Colab Logo di GitHubVisualizza il blocco note su GitHub

Questo tutorial illustra l'ottimizzazione degli obiettivi condizionali di AI Platform Analyzer.

Set di dati

Il set di dati sul reddito del censimento utilizzato da questo campione per l'addestramento è ospitato dal repository di machine learning di UC Irvine.

Utilizzando dati del censimento che contengono l'età, l'istruzione, lo stato civile e l'occupazione di una persona (le caratteristiche), l'obiettivo sarà prevedere se la persona guadagna o meno più di 50.000 dollari all'anno (etichetta target). Dovrai addestrare un modello di regressione logistica che, date le informazioni di un individuo, restituisce un numero compreso tra 0 e 1. Questo valore può essere interpretato come la probabilità che un individuo abbia un reddito annuo superiore a 50.000 dollari.

Scopo

Questo tutorial illustra come utilizzare AI Platform Ottimizzatore per ottimizzare la ricerca di iperparametri per i modelli di machine learning.

Questo esempio implementa una demo di apprendimento automatico che ottimizza un modello di classificazione su un set di dati di censimento utilizzando AI Platform Ottimizzatore con algoritmi integrati AI Platform Training. Utilizzerai AI Platform Ottimizzatore per ottenere i valori degli iperparametri suggeriti e inviare job di addestramento dei modelli con i valori degli iperparametri suggeriti tramite gli algoritmi integrati di AI Platform Training.

Costi

Questo tutorial utilizza i componenti fatturabili di Google Cloud:

  • AI Platform Training
  • Cloud Storage

Scopri di più sui prezzi di AI Platform Training e sui prezzi di Cloud Storage e utilizza il Calcolatore prezzi per generare una stima dei costi in base all'utilizzo previsto.

Pacchetti di installazione e dipendenze PIP

Installa le dipendenze aggiuntive non installate nell'ambiente del blocco note.

  • Utilizzare la versione GA principale più recente del 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)

Configura il tuo progetto Google Cloud

I passaggi seguenti sono obbligatori, indipendentemente dall'ambiente del blocco note.

  1. Seleziona o crea un progetto Google Cloud.

  2. Assicurati che la fatturazione sia abilitata per il progetto.

  3. Abilita le API AI Platform.

  4. Se esegui questo blocco note in locale, devi installare Google Cloud SDK.

  5. Inserisci l'ID progetto nella cella seguente. Poi esegui la cella per assicurarti che Cloud SDK usi il progetto corretto per tutti i comandi in questo blocco note.

Nota: Jupyter esegue le righe con prefisso ! come comandi della shell e interpola le variabili Python con prefisso $ in questi comandi.

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

Autentica l'account Google Cloud

Se utilizzi AI Platform Notebooks, il tuo ambiente è già autenticato. Salta questi passaggi.

La cella seguente richiederà l'autenticazione due volte.

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

Importa librerie

import json
import time
import datetime
from googleapiclient import errors

Tutorial

Configurazione

Questa sezione definisce alcuni parametri e metodi util per chiamare le API AI Platform Analyzer. Inserisci le seguenti informazioni per iniziare.

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

Crea il client API

La cella seguente crea il client API generato automaticamente utilizzando il servizio di rilevamento delle API di Google. Lo schema API in formato JSON è ospitato in 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.')

Configurazione dello studio

In questo tutorial, AI Platform ottimizzato crea uno studio e richiede prove. Per ogni prova, creerai un job con algoritmo integrato di AI Platform Training per eseguire l'addestramento del modello utilizzando gli iperparametri suggeriti. Una misurazione per ogni prova viene riportata come modello accuracy.

Le funzionalità dei parametri condizionali fornite da AI Platform Ottimizzatore definiscono uno spazio di ricerca ad albero per gli iperparametri. L'iperparametro di primo livello è model_type e viene deciso tra LINEAR e WIDE_AND_DEEP. A ogni tipo di modello corrispondono iperparametri di secondo livello da ottimizzare:

  • Se model_type è LINEAR, learning_rate è ottimizzato.
  • Se model_type è WIDE_AND_DEEP, learning_rate e dnn_learning_rate sono ottimizzati.

Un albero decisionale in cui model_type è LINEAR o WIDE_AND_DEEP; LINEAR punta al tasso di apprendimento e WIDE_AND_DEEP punta sia al tasso di apprendimento sia a dnn_learning_rate

Di seguito è riportato un esempio di configurazione di studio, creato come dizionario Python gerarchico. È già compilato. Esegui la cella per configurare lo studio.

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

Crea lo studio

Poi crea lo studio, che eseguirai in seguito per ottimizzare l'obiettivo.

# 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

Impostare parametri di input/output

Quindi, imposta i seguenti parametri di output.

OUTPUT_BUCKET e OUTPUT_DIR sono il bucket e la directory Cloud Storage utilizzati come "job_dir" per i job di AI Platform Training. OUTPUT_BUCKET deve essere un bucket nel progetto e OUTPUT_DIR è il nome che vuoi assegnare alla cartella di output nel bucket.

job_dir avrà il formato "gs://$OUTPUT_BUCKET/$OUTPUT_DIR/"

TRAINING_DATA_PATH è il percorso per il set di dati di addestramento degli input.

# `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
! gsutil mb -p $PROJECT_ID gs://$OUTPUT_BUCKET/

Valutazione delle metriche

Questa sezione definisce i metodi per eseguire la valutazione delle prove.

Per ogni prova, invia un job con algoritmo integrato di AI Platform per addestrare un modello di machine learning utilizzando gli iperparametri suggeriti dall'ottimizzatore di AI Platform. Al termine, ogni job scrive il file di riepilogo del modello in Cloud Storage. Puoi recuperare l'accuratezza del modello dalla directory del job e segnalarla come final_measurement della prova.

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)]

Configurazione per richiedere suggerimenti/prove

client_id: l'identificatore del cliente che richiede il suggerimento. Se più richieste SuggestTrialsRequest hanno lo stesso client_id, il servizio restituisce la prova identica suggerita se la prova è PENDING e fornisce una nuova prova se l'ultima prova suggerita è stata completata.

suggestion_count_per_request: il numero di suggerimenti (prove) richiesti in una singola richiesta.

max_trial_id_to_stop: il numero di prove da esplorare prima di fermarsi. È impostato su 4 per ridurre il tempo di esecuzione del codice, quindi non aspettarti convergenza. Per la convergenza, sarebbe probabilmente necessario essere circa 20 (una buona regola generale è moltiplicare la dimensionalità totale per 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))

Richiedere ed eseguire prove dell'ottimizzazione di AI Platform

Esegui le prove.

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

[FACOLTATIVO] Crea prove utilizzando i tuoi parametri

Oltre a richiedere suggerimenti (il metodo suggest) per i parametri al servizio, l'API di AI Platform Ottimizzatore consente anche agli utenti di creare prove (il metodo create) utilizzando i propri parametri. Lo strumento di ottimizzazione di AI Platform ti aiuterà a tenere traccia degli esperimenti effettuati dagli utenti e a utilizzare le conoscenze per generare nuovi suggerimenti.

Ad esempio, se esegui un job di addestramento di modelli utilizzando i tuoi model_type e learning_rate anziché quelli suggeriti dall'ottimizzatore di AI Platform, puoi creare una prova come parte dello studio.

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

Elenca le prove

Elenca i risultati di ogni addestramento di prova per l'ottimizzazione.

resp = ml.projects().locations().studies().trials().list(parent=trial_parent(STUDY_ID)).execute()
print(json.dumps(resp, indent=2, sort_keys=True))

Eseguire la pulizia

Per eseguire la pulizia di tutte le risorse Google Cloud utilizzate in questo progetto, puoi eliminare il progetto Google Cloud che hai utilizzato per il tutorial.