Estimator API에서 TPUEstimator API로 마이그레이션

이 자습서에서는 Estimator API를 사용하는 모델 프로그램을 TPUEstimator API를 사용하는 모델 프로그램으로 변환하는 방법을 설명합니다.

주의 TPUEstimator API는 Tensorflow 1.x에서만 지원됩니다. Tensorflow 2.x로 모델을 작성하는 경우에는 대신 Keras를 사용하세요.

개요

TPUEstimator API를 사용하는 모델 프로그램은 CPU 및 GPU와 호환되는 상태를 유지하면서 텐서 처리 장치(TPU)를 최대한 활용할 수 있습니다.

이 자습서를 마치면 다음을 익히게 됩니다.

  • Estimator API 사용부터 TPUEstimator API 사용까지 코드 변환 방법
  • Cloud TPU에서 예측 실행 방법

시작하기 전에

이 튜토리얼을 시작하기 전에 Google Cloud 프로젝트가 올바르게 설정되었는지 확인하세요.

이 둘러보기에서는 비용이 청구될 수 있는 Google Cloud 구성요소를 사용합니다. 예상 비용은 Cloud TPU 가격 책정 페이지에서 확인하세요. 리소스 사용을 마쳤으면 불필요한 비용이 청구되지 않도록 생성한 리소스를 삭제하세요.

리소스 설정

이 섹션에서는 가이드에 사용할 Cloud Storage 스토리지, VM, Cloud TPU 리소스를 설정하는 방법을 설명합니다.

Cloud Storage 버킷 생성

모델 학습에 사용할 데이터 및 학습 결과를 저장할 Cloud Storage 버킷이 필요합니다. 이 튜토리얼에서 사용하는 gcloud 명령어는 Cloud TPU 서비스 계정에 대한 기본 권한을 설정합니다. 권한을 더 세분화해야 하는 경우 액세스 수준 권한을 참조하세요.

버킷 위치는 가상 머신(VM) 및 TPU 노드와 동일한 리전에 있어야 합니다. VM 및 TPU 노드는 리전 내 구획인 특정 영역에 있습니다.

  1. Google Cloud 콘솔에서 Cloud Storage 페이지로 이동합니다.

    Cloud Storage 페이지로 이동

  2. 다음 옵션을 지정하여 새 버킷을 만듭니다.

    • 원하는 고유한 이름
    • 위치 유형에 Region, 위치(영역)에 us-central1을 선택합니다.
    • 기본 스토리지 클래스: Standard
    • 위치: TPU 노드를 만들려는 리전에 버킷 위치를 지정합니다. 다양한 TPU 유형을 사용할 수 있는 위치는 TPU 유형 및 영역을 참조하세요.

TPU 및 VM 만들기

TPU 리소스는 동일한 이름을 갖는 가상 머신(VM) 및 Cloud TPU로 구성됩니다. 이러한 리소스는 방금 생성한 버킷과 동일한 리전/영역에 있어야 합니다.

gcloud 명령어 또는 Cloud Console을 사용하여 VM 및 TPU 리소스를 설정할 수 있습니다. TPU 리소스 관리에 대한 자세한 내용은 TPU 만들기 및 삭제를 참조하세요.

  1. Cloud Shell 창을 엽니다.

    Cloud Shell 열기

  2. 프로젝트를 사용하도록 gcloud를 구성합니다.

    $ gcloud config set project your-project
    
    Cloud TPU를 만들려는 프로젝트입니다.

  3. Compute Engine VM 및 Cloud TPU를 실행하려면 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
    

    명령어 플래그 설명

    name
    생성할 Cloud TPU의 이름입니다.
    zone
    Cloud TPU를 생성하려는 영역입니다.
    tf-version
    gcloud 명령어가 VM에 설치하는 TensorFlow 버전입니다.
    machine-type
    생성할 Compute Engine VM의 머신 유형입니다.
    accelerator-type
    생성할 Cloud TPU의 유형입니다.

    gcloud 명령어에 대한 자세한 내용은 gcloud 참조를 확인하세요.

  4. gcloud compute tpus execution-groups 명령어 실행이 끝나면 셸 프롬프트가 username@projectname에서 username@vm-name으로 변경되었는지 확인합니다. 변경되었다면 Compute Engine VM에 로그인되었다는 의미입니다.

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

안내를 계속 따르면서 (vm)$으로 시작하는 각 명령어를 VM 세션 창에서 실행합니다.

Pandas 설치

다음 명령어를 입력하여 pandas를 설치 또는 업그레이드합니다.

pip install pandas

초매개변수 정의

이 코드 섹션에서는 TPU에 필요한 여러 초매개변수를 추가합니다. 이러한 초매개변수는 학습 스크립트에 플래그로 추가되며 런타임에서 변경될 수 있습니다.

추가하는 매개변수는 다음과 같습니다.

  • TPU 이 매개변수는 모델을 실행할 TPU 노드의 이름 또는 IP 주소를 식별합니다.
  • model_dir. 모델 체크포인트를 저장하는 경로입니다. 이 경로는 Cloud Storage 버킷이어야 합니다.
  • 반복 학습 루프당 반복 횟수입니다.
  • use_tpu. 가용성에 따라 TPU 또는 GPU/CPU에서 모델 실행 여부를 지정합니다.

Estimator API

# 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

TPUEstimator API

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

데이터 로드

이 코드 섹션에서는 데이터를 읽고 로드하는 방법을 지정합니다.

TPU는 다음과 같은 데이터 유형을 지원합니다.

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

Estimator API

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)

TPUEstimator API

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)

입력 함수 정의

Estimator API와 TPUEstimator API의 주요 차이점은 입력 함수의 함수 서명입니다. Estimator API를 사용하면 원하는 수의 매개변수로 입력 함수를 작성할 수 있습니다. TPUEstimator API를 사용하면 입력 함수는 단일 매개변수인 params만 사용할 수 있습니다. params에는 batch_size와 같은 추가 키와 함께 TPUEstimator 객체의 모든 키-값 쌍이 있습니다.

이러한 차이점을 해결하는 한 가지 방법은 람다 함수를 사용하여 입력 함수를 호출하는 것입니다. 람다 함수를 사용하면 기존 입력 함수를 약간만 변경하면 됩니다.

다음 섹션에서는 입력 함수를 업데이트하는 방법을 설명합니다. 뒷부분에서 람다 함수를 사용하여 이러한 입력 함수를 TPUEstimator API와 작동하도록 변환하는 방법을 보여줍니다.

학습 입력 함수

TPUEstimator API에서 학습 입력 함수 train_input_fn은 Cloud TPU 코어의 수로 분할할 수 있는 입력 샘플 수를 반환해야 합니다. 예를 들어 코어를 8개 사용하는 경우, 각 배치 크기는 8의 배수여야 합니다.

이를 위해 앞의 코드에서는 dataset.batch(batch_size, drop_remainder=True) 함수를 사용합니다. 이 함수는 batch_size 매개변수를 사용해 일괄 처리하고 나머지를 버립니다.

Estimator API

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

TPUEstimator API

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

평가 입력 함수

이 단계에서는 입력 샘플을 TPU 코어 수만큼 분할할 수 있도록 평가 입력 함수 eval_input_fn을 업데이트합니다. 이 작업을 수행하려면 dataset.batch(batch_size, drop_remainder=True) 함수를 호출합니다.

Estimator API

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

TPUEstimator API

 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

예측 입력 함수

TPUEstimator의 예측에서 입력 데이터세트는 추가 외부 크기 batch_size과 텐서가 있어야 합니다. 따라서 featuresbatch_size를 매개변수로 삼는 예측 입력 함수를 추가해야 합니다. 이 함수를 사용하면 입력 샘플 수가 batch_size보다 적어도 됩니다.

개발자가 Estimator API를 사용하는 경우, 예측 입력 함수는 선택사항입니다.

Estimator API

예측 입력 함수는 Estimator API의 선택사항입니다. 평가 함수 eval_input_fn이 이 작업을 수행하기 때문입니다.

TPUEstimator API

  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

커스텀 모델 함수 업데이트

다음 작업은 커스텀 모델 함수를 업데이트하는 것입니다.

  • tf.estimator.EstimatorSpec의 인스턴스를 tf.contrib.tpu.TPUEstimatorSpec을 사용하도록 교체합니다.
  • tf.summary의 모든 인스턴스를 삭제합니다. TPUEstimator API는 텐서보드의 커스텀 요약을 지원하지 않습니다. 그러나 기본 요약은 모델 디렉터리의 이벤트 파일에 자동으로 기록됩니다.
  • tf.contrib.tpu.CrossShardOptimizer를 사용해 옵티마이저 래핑 CrossShardOptimizerallreduce를 사용해 경사를 집계하고 각 샤드에 결과를 브로드캐스트합니다. CrossShardOptimizer는 로컬 학습과 호환되지 않으므로 use_tpu 플래그도 확인해야 합니다.

Estimator API

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)

TPUEstimator API

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)

평가 측정항목 함수 추가

Estimator API와 TPUEstimator API의 또 다른 차이점은 측정항목 처리 방법입니다. Estimator API를 사용하면 측정항목을 일반 사전으로 전달할 수 있습니다. TPUEstimator API의 경우에는 함수를 대신 사용해야 합니다.

Estimator API

선택사항 my_model 함수는 측정항목을 생성합니다.

TPUEstimator API

  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}

기본 함수 업데이트

TPU 구성

이 단계에서는 TPU 클러스터를 구성합니다.

초매개변수에 할당된 값을 사용하여 클러스터를 구성할 수 있습니다. 자세한 내용은 초매개변수 정의를 참조하세요. 또한 다음 값을 설정해야 합니다.

  • allow_soft_placement: 이 매개변수를 `true`로 설정한 경우, TPU를 사용할 수 없으면 TensorFlow가 GPU 기기를 사용하도록 허용합니다. GPU 기기도 사용할 수 없으면 CPU 기기가 사용됩니다.
  • log_device_placement: TensorFlow가 기기 배치를 로깅해야 함을 나타냅니다.

Estimator API

이 코드 섹션은 TPU에만 영향을 주므로 필수사항이 아닙니다.

TPUEstimator API

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

TPU 관련 매개변수를 분류자에 추가

코드의 이 섹션에서는 TPUEstimator 클래스를 사용하도록 분류자 변수를 업데이트합니다. 이러한 변경을 위해 다음 매개변수를 추가해야 합니다.

  • use_tpu
  • train_batch_size
  • eval_batch_size
  • predict_batch_size
  • config

Estimator API

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

TPUEstimator API

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

학습 메서드 호출

다음 변경은 학습 메서드를 업데이트하는 것입니다. 람다 함수를 사용하여 train_input_fn 함수를 호출해야 한다는 점에 유의하세요. 이렇게 하면 더욱 간편하게 기존 함수를 TPUEstimator API와 함께 사용할 수 있습니다.

또한 steps 매개 변수를 max_steps로 변경해야 합니다. 다음 섹션에서는 steps 매개변수의 용도를 변경하여 평가 단계 수를 지정합니다.

Estimator API

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

TPUEstimator API

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

평가 메서드 호출

이 변경은 학습 메서드의 변경사항과 유사합니다. 다시 람다 함수를 사용하면 더욱 간편하게 기존의 평가 입력 함수를 사용할 수 있습니다.

또한 steps 매개변수를 eval_steps 명령줄 플래그의 값 집합으로 변경해야 합니다.

Estimator API

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

TPUEstimator API

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

예측 메서드 호출

학습 및 평가 메서드와 마찬가지로 예측 메서드를 업데이트해야 합니다. 다시 람다 함수를 사용하면 더욱 간편하게 기존의 평가 입력 함수를 사용할 수 있습니다.

Estimator API

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

TPUEstimator API

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

삭제

이 항목에서 사용한 리소스 비용이 GCP 계정에 청구되지 않도록 다음을 수행합니다.

  1. Compute Engine VM의 연결을 해제합니다.

    (vm)$ exit
    

    프롬프트가 username@projectname으로 바뀌면 Cloud Shell에 있는 것입니다.

  2. Cloud Shell에서 Cloud TPU를 설정할 때 사용한 --zone 플래그로 ctpu delete를 실행하여 Compute Engine VM과 Cloud TPU를 삭제합니다.

    $ ctpu delete [optional: --zone]
    
  3. TPU 사용에 대한 불필요한 요금 청구를 방지하기 위해 ctpu status를 실행하여 할당된 인스턴스가 없는지 확인합니다. 삭제하는 데 몇 분 정도 걸릴 수 있습니다. 다음과 같은 응답이 나타나면 더 이상 할당된 인스턴스가 없다는 의미입니다.

    $ 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. 아래와 같이 gsutil을 실행하여 bucket-name을 이 튜토리얼에서 만든 Cloud Storage 버킷 이름으로 바꿉니다.

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

다음 단계

Estimator와 TPUEstimator API에 대한 자세한 내용은 다음 주제를 참조하세요.