Migrer de l'API Estimator vers l'API TPUEstimator

Ce tutoriel explique comment convertir un programme de modèle utilisant l'API Estimator en un programme utilisant l'API TPUEstimator.

Avertissement : L'API TPUEstimator n'est compatible qu'avec TensorFlow 1.x. Si vous écrivez un modèle avec TensorFlow 2.x, utilisez plutôt Keras.

Présentation

Les programmes de modèle utilisant l'API TPUEstimator peuvent bénéficier pleinement des Tensor Processing Units (TPU), tout en restant compatibles avec les processeurs et les GPU.

Après avoir terminé ce tutoriel, vous saurez :

  • convertir votre code utilisant l'API Estimator en un code utilisant l'API TPUEstimator ;
  • exécuter des prédictions sur Cloud TPU.

Avant de commencer

Avant de commencer ce tutoriel, vérifiez que votre projet Google Cloud est correctement configuré.

Ce tutoriel utilise des composants facturables de Google Cloud. Consultez la grille tarifaire de Cloud TPU pour estimer vos coûts. Veillez à nettoyer les ressources que vous avez créées lorsque vous avez terminé, afin d'éviter des frais inutiles.

Configurer vos ressources

Cette section fournit des informations sur la configuration des ressources de stockage Cloud Storage, des ressources de VM et des ressources Cloud TPU pour les tutoriels.

Créer un bucket Cloud Storage

Vous avez besoin d'un bucket Cloud Storage pour stocker les données permettant d'entraîner votre modèle et les résultats de l'entraînement. La commande gcloud utilisée dans ce tutoriel configure les autorisations par défaut du compte de service Cloud TPU. Si vous souhaitez utiliser des autorisations plus précises, vérifiez les autorisations de niveau d'accès.

L'emplacement du bucket doit se trouver dans la même région que votre machine virtuelle (VM) et votre nœud TPU. Les VM et les nœuds TPU sont situés dans des zones spécifiques, qui sont des subdivisions au sein d'une région.

  1. Accédez à la page Cloud Storage de Google Cloud Console.

    Accéder à la page Cloud Storage

  2. Créez un bucket en spécifiant les options suivantes :

    • Un nom unique de votre choix
    • Sélectionnez Region pour le type d'emplacement et us-central1 pour l'emplacement (zone).
    • Classe de stockage par défaut : Standard
    • Emplacement : spécifiez un emplacement de bucket dans la région où vous prévoyez de créer votre nœud TPU. Consultez la section Types et zones des TPU pour savoir où les différents types de TPU sont disponibles.

Créer un TPU et une VM

Les ressources TPU sont composées d'une machine virtuelle (VM) et d'un Cloud TPU portant le même nom. Ces ressources doivent se trouver dans la même région/zone que le bucket que vous venez de créer.

Vous pouvez configurer la VM et vos ressources TPU à l'aide des commandes gcloud ou de la console Cloud. Pour en savoir plus sur la gestion des ressources TPU, consultez la page Créer et supprimer des TPU.

  1. Ouvrez une fenêtre Cloud Shell.

    Ouvrir Cloud Shell

  2. Configurez gcloud pour utiliser votre projet.

    $ gcloud config set project your-project
    projet dans lequel vous souhaitez créer Cloud TPU.

  3. Lancez une VM Compute Engine et Cloud TPU à l'aide de la commande gcloud.

    $ gcloud compute tpus execution-groups create \
     --name=tpu-name \
     --zone=europe-west4-a \
     --tf-version=2.12.0 \
     --machine-type=n1-standard-1 \
     --accelerator-type=v3-8

    Description des options de commande

    name
    Nom du Cloud TPU à créer.
    zone
    Zone dans laquelle vous prévoyez de créer votre Cloud TPU.
    tf-version
    Version de Tensorflow que la commande gcloud installe sur votre VM.
    machine-type
    Type de machine de la VM Compute Engine à créer.
    accelerator-type
    Le type de Cloud TPU à créer.

    Pour en savoir plus sur la commande gcloud, consultez la documentation de référence de gcloud.

  4. Une fois l'exécution de la commande gcloud compute tpus execution-groups terminée, vérifiez que l'invite de l'interface système est passée de username@projectname à username@vm-name. Cette modification indique que vous êtes maintenant connecté à votre VM Compute Engine.

    gcloud compute ssh tpu-name --zone=europe-west4-a

À mesure que vous appliquez ces instructions, exécutez chaque commande commençant par (vm)$ dans la fenêtre de session de la VM.

Installer des pandas

Installez ou mettez à niveau des pandas à l'aide de la commande suivante :

pip install pandas

Définir les hyperparamètres

Dans cette section de code, vous ajoutez plusieurs hyperparamètres requis par les TPU. Vous ajoutez ces hyperparamètres en tant qu'options à votre script d'entraînement, ce qui vous permet de les modifier au moment de l'exécution.

Les paramètres que vous ajoutez sont les suivants :

  • tpu. Ce paramètre identifie le nom ou l'adresse IP du nœud TPU sur lequel le modèle doit être exécuté.
  • model_dir. Il s'agit du chemin d'accès pour sauvegarder les points de contrôle du modèle. Ce chemin d'accès doit être un bucket Cloud Storage.
  • iterations. Il s'agit du nombre d'itérations par boucle d'entraînement.
  • use_tpu. Indique si vous souhaitez exécuter le modèle sur des TPU ou des GPU/CPU en fonction de la disponibilité.

API Estimator

# Model specific parameters
tf.flags.DEFINE_integer("batch_size",
    default=50,
    help="Batch size.")
tf.flags.DEFINE_integer("train_steps",
    default=1000,
    help="Total number of training steps.")
FLAGS = tf.flags.FLAGS

API TPUEstimator

# Cloud TPU Cluster Resolver flags
tf.flags.DEFINE_string(
    "tpu", default=None,
    help="The Cloud TPU to use for training. This should be the name used when "
    "creating the Cloud TPU. To find out the name of TPU, either use command "
    "'gcloud compute tpus list --zone=<zone-name>', or use "
    "'ctpu status --details' if you have created your Cloud TPU using 'ctpu up'.")

# Model specific parameters
tf.flags.DEFINE_string(
    "model_dir", default="",
    help="This should be the path of storage bucket which will be used as "
    "model_directory to export the checkpoints during training.")
tf.flags.DEFINE_integer(
    "batch_size", default=128,
    help="This is the global batch size and not the per-shard batch.")
tf.flags.DEFINE_integer(
    "train_steps", default=1000,
    help="Total number of training steps.")
tf.flags.DEFINE_integer(
    "eval_steps", default=4,
    help="Total number of evaluation steps. If `0`, evaluation "
    "after training is skipped.")

# TPU specific parameters.
tf.flags.DEFINE_bool(
    "use_tpu", default=True,
    help="True, if want to run the model on TPU. False, otherwise.")
tf.flags.DEFINE_integer(
    "iterations", default=500,
    help="Number of iterations per TPU training loop.")

Charger les données

Cette section de code spécifie comment lire et charger les données.

Les TPU prennent en charge les types de données suivants :

  • tf.float32
  • tf.complex64
  • tf.int64
  • tf.bool
  • tf.bfloat64

API Estimator

def load_data(y_name='Species'):
  """Returns the iris dataset as (train_x, train_y), (test_x, test_y)."""
  train_path, test_path = maybe_download()

  train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
  train_x, train_y = train, train.pop(y_name)

  test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
  test_x, test_y = test, test.pop(y_name)

  return (train_x, train_y), (test_x, test_y)

API TPUEstimator

def load_data(y_name='Species'):
  """Returns the iris dataset as (train_x, train_y), (test_x, test_y)."""
  train_path, test_path = maybe_download()

  train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0,
                      dtype={'SepalLength': pd.np.float32,
                             'SepalWidth': pd.np.float32,
                             'PetalLength': pd.np.float32,
                             'PetalWidth': pd.np.float32,
                             'Species': pd.np.int32})
  train_x, train_y = train, train.pop(y_name)

  test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0,
                     dtype={'SepalLength': pd.np.float32,
                            'SepalWidth': pd.np.float32,
                            'PetalLength': pd.np.float32,
                            'PetalWidth': pd.np.float32,
                            'Species': pd.np.int32})
  test_x, test_y = test, test.pop(y_name)

  return (train_x, train_y), (test_x, test_y)

Définir les fonctions d'entrée

Une différence essentielle entre l'API Estimator et l'API TPUEstimator réside dans la signature de la fonction des fonctions d'entrée. Avec l'API Estimator, vous pouvez écrire des fonctions d'entrée avec un nombre quelconque de paramètres. Avec l'API TPUEstimator, les fonctions d'entrée ne peuvent intégrer qu'un seul paramètre, params. Cette valeur params contient toutes les paires clé/valeur de l'objet TPUEstimator, ainsi que des clés supplémentaires telles que batch_size.

Une façon de remédier à cette différence consiste à utiliser les fonctions lambda lors de l'appel des fonctions d'entrée. Avec les fonctions lambda, vous ne devez apporter que des modifications mineures aux fonctions d'entrée existantes.

Les sections suivantes montrent comment mettre à jour vos fonctions d'entrée. Vous verrez plus tard comment utiliser les fonctions lambda pour convertir ces fonctions d'entrée afin qu'elles fonctionnent avec l'API TPUEstimator.

Fonction d'entrée d'entraînement

Avec l'API TPUEstimator, votre fonction d'entrée pour l'entraînement, train_input_fn, doit renvoyer un nombre d'échantillons d'entrées pouvant être divisé par le nombre de cœurs Cloud TPU. Par exemple, si vous utilisez 8 cœurs, chaque taille de lot doit être divisible par 8.

Pour ce faire, le code précédent utilise la fonction dataset.batch(batch_size, drop_remainder=True). Cette fonction effectue des traitements par lot à l'aide du paramètre batch_size et élimine le reste.

API Estimator

def train_input_fn(features, labels, batch_size):
  """An input function for training"""

  # Convert the inputs to a Dataset.
  dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

  # Shuffle, repeat, and batch the examples.
  dataset = dataset.shuffle(1000).repeat().batch(batch_size)

  # Return the dataset.
  return dataset

API TPUEstimator

def train_input_fn(features, labels, batch_size):
  """An input function for training."""

  # Convert the inputs to a Dataset.
  dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

  # Shuffle, repeat, and batch the examples.
  dataset = dataset.shuffle(1000).repeat()

  dataset = dataset.batch(batch_size, drop_remainder=True)

  # Return the dataset.
  return dataset

Fonction d'entrée d'évaluation

Au cours de cette étape, vous mettez à jour la fonction d'entrée d'évaluation eval_input_fn pour vous assurer que le nombre d'échantillons d'entrée peut être divisé par le nombre de cœurs TPU. Pour ce faire, utilisez la fonction dataset.batch(batch_size, drop_remainder=True).

API Estimator

def eval_input_fn(features, labels, batch_size):
  """An input function for evaluation or prediction"""
  features=dict(features)
  if labels is None:
      # No labels, use only features.
      inputs = features
  else:
      inputs = (features, labels)

  # Convert the inputs to a Dataset.
  dataset = tf.data.Dataset.from_tensor_slices(inputs)

  # Batch the examples
  assert batch_size is not None, "batch_size must not be None"
  dataset = dataset.batch(batch_size)

  # Return the dataset.
  return dataset

API TPUEstimator

 def eval_input_fn(features, labels, batch_size):
    """An input function for evaluation."""
    features = dict(features)
    inputs = (features, labels)

    # Convert the inputs to a Dataset.
    dataset = tf.data.Dataset.from_tensor_slices(inputs)
    dataset = dataset.shuffle(1000).repeat()

    dataset = dataset.batch(batch_size, drop_remainder=True)

    # Return the dataset.
    return dataset

Fonction d'entrée de prédiction

Pour les prédictions dans TPUEstimators, l'ensemble de données d'entrée doit comporter des tenseurs ayant pour dimension externe supplémentaire le paramètre batch_size. Par conséquent, vous devez ajouter une fonction d'entrée de prédiction, qui utilise les paramètres features et batch_size. Cette fonction vous permet d'avoir moins d'échantillons d'entrée qu'avec le paramètre batch_size.

Si vous utilisez l'API Estimator, la fonction d'entrée de prédiction est facultative.

API Estimator

Une fonction d'entrée de prédiction est facultative pour l'API Estimator, car la fonction d'évaluation eval_input_fn effectue cette tâche.

API TPUEstimator

  def predict_input_fn(features, batch_size):
    """An input function for prediction."""

    dataset = tf.data.Dataset.from_tensor_slices(features)
    dataset = dataset.batch(batch_size)
    return dataset

Mettre à jour la fonction de modèle personnalisé

Votre prochaine tâche consiste à mettre à jour la fonction de modèle personnalisé :

  • Remplacez les instances de tf.estimator.EstimatorSpec pour utiliser tf.contrib.tpu.TPUEstimatorSpec.
  • Supprimez toutes les instances de tf.summary. L'API TPUEstimator ne prend pas en charge les résumés personnalisés pour Tensorboard. Cependant, les résumés de base sont automatiquement enregistrés dans les fichiers d'événements du répertoire du modèle.
  • Encapsulez l'optimiseur à l'aide de tf.contrib.tpu.CrossShardOptimizer. CrossShardOptimizer comporte un paramètre allreduce permettant d'agréger les gradients et de diffuser le résultat à chaque segment. CrossShardOptimizer n'étant pas compatible avec l'entraînement local, vous devez également vérifier l'indicateur use_tpu.

API Estimator

def my_model(features, labels, mode, params):
  """DNN with three hidden layers, and dropout of 0.1 probability."""

  # Create three fully connected layers each layer having a dropout
  # probability of 0.1.
  net = tf.feature_column.input_layer(features, params['feature_columns'])
  for units in params['hidden_units']:
      net = tf.layers.dense(net, units=units, activation=tf.nn.relu)

  # Compute logits (1 per class).
  logits = tf.layers.dense(net, params['n_classes'], activation=None)

  # Compute predictions.
  predicted_classes = tf.argmax(logits, 1)
  if mode == tf.estimator.ModeKeys.PREDICT:
      predictions = {
          'class_ids': predicted_classes[:, tf.newaxis],
          'probabilities': tf.nn.softmax(logits),
          'logits': logits,
      }
      return tf.estimator.EstimatorSpec(mode, predictions=predictions)

  # Compute loss.
  loss = tf.losses.sparse_softmax_cross_entropy(labels=labels,
                                                logits=logits)

  # Compute evaluation metrics.
  accuracy = tf.metrics.accuracy(labels=labels,
                                 predictions=predicted_classes,
                                 name='acc_op')
  metrics = {'accuracy': accuracy}
  tf.summary.scalar('accuracy', accuracy[1])
  if mode == tf.estimator.ModeKeys.EVAL:
      return tf.estimator.EstimatorSpec(
          mode, loss=loss, eval_metric_ops=metrics)

  # Create training op.
  if mode == tf.estimator.ModeKeys.TRAIN
      optimizer = tf.train.AdagradOptimizer(learning_rate=0.1)
      train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
      return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

API TPUEstimator

def my_model(features, labels, mode, params):
  """Deep Neural Network(DNN) model.

  This is a DNN Model with 3 hidden layers. First 2 hidden layers are having
  10 neurons in each. And number of neurons in the last layer is equal to the
  number of output classes. This is a densely connected network where each
  neuron of previous layer is connected to each neuron of next layer.

  Args:
    features: Feature values for input samples.
    labels: label/class assigned to the corresponding input sample.
    mode: "TRAIN"/"EVAL"/"PREDICT"
    params: Dictionary used to pass extra parameters to model function from
      the main function.

  Returns:
    TPUEstimatorSpec object.

  """

  # Create three fully connected layers.
  net = tf.feature_column.input_layer(features, params["feature_columns"])
  for units in params["hidden_units"]:
    net = tf.layers.dense(net, units=units, activation=tf.nn.relu)

  # Compute logits (1 per class).
  logits = tf.layers.dense(net, params["n_classes"], activation=None)

  # Compute predictions.
  predicted_classes = tf.argmax(logits, 1)
  if mode == tf.estimator.ModeKeys.PREDICT:
    predictions = {
        "class_ids": predicted_classes[:, tf.newaxis],
        "probabilities": tf.nn.softmax(logits),
        "logits": logits,
    }
    return tf.contrib.tpu.TPUEstimatorSpec(mode, predictions=predictions)

  # Compute loss.
  loss = tf.losses.sparse_softmax_cross_entropy(labels=labels,
                                                logits=logits)

  if mode == tf.estimator.ModeKeys.EVAL:
    return tf.contrib.tpu.TPUEstimatorSpec(
        mode=mode, loss=loss, eval_metrics=(metric_fn, [labels, logits]))

  # Create training op.
  if mode == tf.estimator.ModeKeys.TRAIN:
    optimizer = tf.train.AdagradOptimizer(learning_rate=0.1)
    if FLAGS.use_tpu:
      optimizer = tf.contrib.tpu.CrossShardOptimizer(optimizer)
    train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
    return tf.contrib.tpu.TPUEstimatorSpec(mode, loss=loss, train_op=train_op)

Ajouter une fonction de métrique d'évaluation

L'API Estimator et l'API TPUEstimator se différencient également dans leur mode de gestion des métriques. L'API Estimator permet de transmettre des métriques comme un dictionnaire normal, alors que l'API TPUEstimator requiert l'utilisation d'une fonction.

API Estimator

Facultatif. La fonction my_model génère les statistiques.

API TPUEstimator

  def metric_fn(labels, logits):
    """Function to return metrics for evaluation."""

    predicted_classes = tf.argmax(logits, 1)
    accuracy = tf.metrics.accuracy(labels=labels,
                                   predictions=predicted_classes,
                                   name="acc_op")
    return {"accuracy": accuracy}

Mettre à jour la fonction principale

Configurer les TPU

Au cours de cette étape, vous allez configurer le cluster TPU.

Pour configurer le cluster, vous pouvez utiliser les valeurs attribuées aux hyperparamètres. Consultez la section Définir des hyperparamètres pour obtenir plus d'informations. De plus, vous devez définir les valeurs suivantes :

  • allow_soft_placement. Lorsqu'il est défini sur "true", ce paramètre permet à TensorFlow d'utiliser un appareil GPU si un TPU n'est pas disponible. Si un appareil GPU est également indisponible, un appareil CPU est utilisé.
  • log_device_placement. Indique que TensorFlow doit consigner les emplacements des appareils.

API Estimator

Non requis, car cette section de code concerne uniquement les TPU.

API TPUEstimator

# Resolve TPU cluster and runconfig for this.
tpu_cluster_resolver = tf.contrib.cluster_resolver.TPUClusterResolver(
    FLAGS.tpu)

run_config = tf.contrib.tpu.RunConfig(
    model_dir=FLAGS.model_dir,
    cluster=tpu_cluster_resolver,
    session_config=tf.ConfigProto(
        allow_soft_placement=True, log_device_placement=True),
    tpu_config=tf.contrib.tpu.TPUConfig(FLAGS.iterations),
)

Ajouter des paramètres spécifiques de TPU au classificateur

Dans cette section du code, vous mettez à jour la variable de classificateur pour utiliser la classe TPUEstimator. Cette modification nécessite que vous ajoutiez les paramètres suivants :

  • use_tpu
  • train_batch_size
  • eval_batch_size
  • predict_batch_size
  • config

API Estimator

  # Build 2 hidden layer DNN with 10, 10 units respectively.
  classifier = tf.estimator.Estimator(
      model_fn=my_model,
      params={
          'feature_columns': my_feature_columns,
          # Two hidden layers of 10 nodes each.
          'hidden_units': [10, 10],
          # The model must choose between 3 classes.
          'n_classes': 3,
      })

API TPUEstimator

  # Build 2 hidden layer DNN with 10, 10 units respectively.
  classifier = tf.contrib.tpu.TPUEstimator(
      model_fn=my_model,
      use_tpu=FLAGS.use_tpu,
      train_batch_size=FLAGS.batch_size,
      eval_batch_size=FLAGS.batch_size,
      predict_batch_size=FLAGS.batch_size,
      config=run_config,
      params={
          # Name of the feature columns in the input data.
          "feature_columns": my_feature_columns,
          # Two hidden layers of 10 nodes each.
          "hidden_units": [10, 10],
          # The model must choose between 3 classes.
          "n_classes": 3,
          "use_tpu": FLAGS.use_tpu,
      })

Appeler la méthode d'entraînement

Le prochain changement consiste à mettre à jour la méthode d'entraînement. Notez l'utilisation d'une fonction lambda pour appeler la fonction train_input_fn. Cette méthodologie facilite l'utilisation de vos fonctions existantes avec l'API TPUEstimator.

En outre, vous devez modifier le paramètre steps (pas) par max_steps. Dans la section suivante, réaffectez le paramètre Steps pour spécifier le nombre d'étapes d'évaluation.

API Estimator

  # Train the Model.
  classifier.train(
      input_fn=lambda:iris_data.train_input_fn(
          train_x, train_y, FLAGS.batch_size),
      steps=FLAGS.train_steps)

API TPUEstimator

  # Train the Model.
  classifier.train(
      input_fn=lambda params: iris_data.train_input_fn(
          train_x, train_y, params["batch_size"]),
      max_steps=FLAGS.train_steps)

Appeler la méthode d'évaluation

Ce changement est identique à celui que vous avez apporté à la méthode d'entraînement. Là encore, l'utilisation d'une fonction lambda facilite l'utilisation d'une fonction d'entrée d'évaluation existante.

En outre, vous devez remplacer le paramètre steps par la valeur définie à partir de l'indicateur de ligne de commande eval_steps.

API Estimator

  # Evaluate the model.
  eval_result = classifier.evaluate(
      input_fn=lambda:iris_data.eval_input_fn(
          test_x, test_y, FLAGS.batch_size))

  print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result))

API TPUEstimator

  # Evaluate the model.
  eval_result = classifier.evaluate(
      input_fn=lambda params: iris_data.eval_input_fn(
          test_x, test_y, params["batch_size"]),
      steps=FLAGS.eval_steps)

Appeler la méthode de prédiction

Comme pour les méthodes d'entraînement et d'évaluation, vous devez mettre à jour la méthode de prédiction. Là encore, l'utilisation d'une fonction lambda facilite l'utilisation d'une fonction d'entrée d'évaluation existante.

API Estimator

  # Generate predictions from the model
  predictions = classifier.predict(
      input_fn=lambda: iris_data.eval_input_fn(
          iris_data.PREDICTION_INPUT_DATA,
          labels=None,
          batch_size=FLAGS.batch_size))

  for pred_dict, expec in zip(predictions, iris_data.PREDICTION_OUTPUT_DATA):
      template = ('\nPrediction is "{}" ({:.1f}%), expected "{}"')

      class_id = pred_dict['class_ids'][0]
      probability = pred_dict['probabilities'][class_id]

      print(template.format(iris_data.SPECIES[class_id],
                            100 * probability, expec))

API TPUEstimator

  # Generate predictions from the model
  predictions = classifier.predict(
      input_fn=lambda params: iris_data.predict_input_fn(
          iris_data.PREDICTION_INPUT_DATA, params["batch_size"]))

  for pred_dict, expec in zip(predictions, iris_data.PREDICTION_OUTPUT_DATA):
    template = ("\nPrediction is \"{}\" ({:.1f}%), expected \"{}\"")

    class_id = pred_dict["class_ids"][0]
    probability = pred_dict["probabilities"][class_id]

    print(template.format(iris_data.SPECIES[class_id],
                          100 * probability, expec))

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans cet article soient facturées sur votre compte GCP, suivez les étapes ci-dessous :

  1. Déconnectez-vous de la VM Compute Engine :

    (vm)$ exit

    Votre invite devrait maintenant être username@projectname, indiquant que vous êtes dans Cloud Shell.

  2. Dans Cloud Shell, exécutez la commande ctpu delete avec l'option --zone utilisée lors de votre configuration Cloud TPU pour supprimer votre VM Compute Engine et votre Cloud TPU :

    $ ctpu delete [optional: --zone]
  3. Exécutez ctpu status pour vérifier qu'il ne reste aucune instance allouée afin d'éviter des frais inutiles liés à l'utilisation des ressources TPU. La suppression peut prendre plusieurs minutes. Si vous n'avez plus d'instances allouées, une réponse de ce type s'affiche :

    $ ctpu status --zone=europe-west4-a
    2018/04/28 16:16:23 WARNING: Setting zone to "--zone=europe-west4-a"
    No instances currently exist.
        Compute Engine VM:     --
        Cloud TPU:             --
  4. Exécutez gsutil comme indiqué, en remplaçant bucket-name par le nom du bucket Cloud Storage que vous avez créé pour ce tutoriel :

    $ gsutil rm -r gs://bucket-name

Étapes suivantes

Pour en savoir plus sur l'API Estimator et l'API TPUEstimator, consultez les rubriques suivantes :