Prototyp do produkcji: rozproszone trenowanie w Vertex AI

1. Przegląd

W tym laboratorium użyjesz Vertex AI do uruchomienia rozproszonego zadania treningowego w Vertex AI Training przy użyciu TensorFlow.

Ten moduł jest częścią serii filmów Od prototypu do produkcji. Zanim rozpoczniesz ten moduł, wykonaj poprzednie moduły. Więcej informacji znajdziesz w powiązanej serii filmów:

.

Czego się dowiesz

Poznasz takie zagadnienia jak:

  • Uruchamianie trenowania rozproszonego na jednym komputerze z wieloma procesorami GPU
  • Uruchamianie trenowania rozproszonego na wielu komputerach

Całkowity koszt przeprowadzenia tego laboratorium w Google Cloud wynosi około 2 USD.

2. Wprowadzenie do Vertex AI

W tym module wykorzystujemy najnowszą ofertę produktów AI dostępną w Google Cloud. Vertex AI integruje oferty ML w Google Cloud, zapewniając płynne środowisko programistyczne. Wcześniej modele wytrenowane za pomocą AutoML i modele niestandardowe były dostępne w ramach osobnych usług. Nowa oferta łączy je w jeden interfejs API wraz z innymi nowymi usługami. Możesz też przeprowadzić migrację istniejących projektów do Vertex AI.

Vertex AI obejmuje wiele różnych usług, które obsługują kompleksowe przepływy pracy związane z uczeniem maszynowym. Ten moduł skupia się na wyróżnionych poniżej usługach: trenowanieWorkbench.

Omówienie usługi Vertex

3. Omówienie trenowania rozproszonego

Jeśli masz pojedynczy procesor GPU, TensorFlow użyje tego akceleratora, aby przyspieszyć trenowanie modelu bez dodatkowej pracy z Twojej strony. Jeśli jednak chcesz uzyskać dodatkowe korzyści z używania wielu procesorów GPU, musisz użyć modułu tf.distribute TensorFlow, który umożliwia uruchamianie obliczeń na wielu urządzeniach.

W pierwszej części tego laboratorium używamy tf.distribute.MirroredStrategy, które możesz dodać do aplikacji do trenowania, wprowadzając tylko kilka zmian w kodzie. Ta strategia tworzy kopię modelu na każdym procesorze GPU na Twoim komputerze. Kolejne aktualizacje gradientu będą przeprowadzane synchronicznie. Oznacza to, że każdy procesor GPU oblicza przejścia w przód i w tył przez model na innym wycinku danych wejściowych. Obliczone gradienty z każdego z tych wycinków są następnie agregowane na wszystkich procesorach GPU i uśredniane w procesie zwanym all-reduce. Parametry modelu są aktualizowane za pomocą tych uśrednionych gradientów.

Opcjonalna sekcja na końcu ćwiczenia korzysta z tf.distribute.MultiWorkerMirroredStrategy, które działa podobnie jak MirroredStrategy, ale na wielu maszynach. Każda z tych maszyn może mieć też kilka procesorów graficznych. Na przykład MirroredStrategy, MultiWorkerMirroredStrategy to synchroniczna strategia równoległości danych, której możesz używać po wprowadzeniu tylko kilku zmian w kodzie. Główna różnica między synchronicznym równoległym przetwarzaniem danych na 1 komputerze a na wielu komputerach polega na tym, że na końcu każdego kroku gradienty muszą być synchronizowane na wszystkich procesorach graficznych na danym komputerze i na wszystkich komputerach w klastrze.

Aby ukończyć ten moduł, nie musisz znać szczegółów, ale jeśli chcesz dowiedzieć się więcej o tym, jak działa trenowanie rozproszone w TensorFlow, obejrzyj poniższy film:

4. Konfigurowanie środowiska

Aby skonfigurować środowisko, wykonaj czynności opisane w module Trenowanie modeli niestandardowych z użyciem Vertex AI.

5. Trenowanie na jednej maszynie z wieloma procesorami graficznymi

Zadanie trenowania rozproszonego prześlesz do Vertex AI, umieszczając kod aplikacji do trenowania w kontenerze Dockera i przesyłając ten kontener do Google Artifact Registry. Dzięki temu możesz wytrenować model utworzony w dowolnym frameworku.

Zacznij od otwarcia okna terminala w menu Launchera notatnika Workbench utworzonego w poprzednich ćwiczeniach.

Otwórz terminal w notatniku

Krok 1. Napisz kod szkoleniowy

Utwórz nowy katalog o nazwie flowers-multi-gpu i przejdź do niego:

mkdir flowers-multi-gpu
cd flowers-multi-gpu

Uruchom to polecenie, aby utworzyć katalog na kod szkoleniowy i plik Pythona, do którego dodasz poniższy kod.

mkdir trainer
touch trainer/task.py

W katalogu flowers-multi-gpu/ powinny się teraz znajdować te pliki:

+ trainer/
    + task.py

Następnie otwórz utworzony plik task.py i skopiuj poniższy kod.

Musisz zastąpić {your-gcs-bucket}BUCKET_ROOT zasobnikiem Cloud Storage, w którym w ćwiczeniu 1 został zapisany zbiór danych kwiatów.

import tensorflow as tf
import numpy as np
import os

## Replace {your-gcs-bucket} !!
BUCKET_ROOT='/gcs/{your-gcs-bucket}'

# Define variables
NUM_CLASSES = 5
EPOCHS=10
BATCH_SIZE = 32

IMG_HEIGHT = 180
IMG_WIDTH = 180

DATA_DIR = f'{BUCKET_ROOT}/flower_photos'

def create_datasets(data_dir, batch_size):
  '''Creates train and validation datasets.'''

  train_dataset = tf.keras.utils.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="training",
    seed=123,
    image_size=(IMG_HEIGHT, IMG_WIDTH),
    batch_size=batch_size)

  validation_dataset = tf.keras.utils.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="validation",
    seed=123,
    image_size=(IMG_HEIGHT, IMG_WIDTH),
    batch_size=batch_size)

  train_dataset = train_dataset.cache().shuffle(1000).prefetch(buffer_size=tf.data.AUTOTUNE)
  validation_dataset = validation_dataset.cache().prefetch(buffer_size=tf.data.AUTOTUNE)

  return train_dataset, validation_dataset


def create_model():
  '''Creates model.'''

  model = tf.keras.Sequential([
    tf.keras.layers.Resizing(IMG_HEIGHT, IMG_WIDTH),
    tf.keras.layers.Rescaling(1./255, input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
    tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')
  ])
  return model

def main():  

  # Create distribution strategy
  strategy = tf.distribute.MirroredStrategy()

  # Get data
  GLOBAL_BATCH_SIZE = BATCH_SIZE * strategy.num_replicas_in_sync
  train_dataset, validation_dataset = create_datasets(DATA_DIR, BATCH_SIZE)

  # Wrap model creation and compilation within scope of strategy
  with strategy.scope():
    model = create_model()
    model.compile(optimizer=tf.keras.optimizers.Adam(),
                  loss=tf.keras.losses.SparseCategoricalCrossentropy(),
                  metrics=['accuracy'])

  history = model.fit(
    train_dataset,
    validation_data=validation_dataset,
    epochs=EPOCHS
  )

  model.save(f'{BUCKET_ROOT}/model_output')


if __name__ == "__main__":
    main()

Zanim utworzysz kontener, przyjrzyjmy się bliżej kodowi. Istnieje kilka komponentów, które są specyficzne dla trenowania rozproszonego.

  • W funkcji main() tworzony jest obiekt MirroredStrategy. Następnie umieść tworzenie zmiennych modelu w zakresie strategii. Ten krok informuje TensorFlow, które zmienne powinny być odzwierciedlane na wszystkich procesorach GPU.
  • Wielkość wsadu jest zwiększana o num_replicas_in_sync. Skalowanie wielkości wsadu jest sprawdzoną metodą w przypadku korzystania w TensorFlow ze strategii synchronicznego równoległego przetwarzania danych. Więcej informacji znajdziesz tutaj

Krok 2. Utwórz plik Dockerfile

Aby umieścić kod w kontenerze, musisz utworzyć plik Dockerfile. W pliku Dockerfile umieścisz wszystkie polecenia potrzebne do uruchomienia obrazu. Zainstaluje wszystkie niezbędne biblioteki i skonfiguruje punkt wejścia dla kodu trenowania.

W terminalu utwórz pusty plik Dockerfile w katalogu głównym katalogu flowers:

touch Dockerfile

W katalogu flowers-multi-gpu/ powinny się teraz znajdować te pliki:

+ Dockerfile
+ trainer/
    + task.py

Otwórz plik Dockerfile i skopiuj do niego ten kod:

FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-8

WORKDIR /

# Copies the trainer code to the docker image.
COPY trainer /trainer

# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.task"]

Krok 3. Utwórz kontener

W terminalu uruchom to polecenie, aby zdefiniować zmienną środowiskową dla projektu. Pamiętaj, aby zastąpić your-cloud-project identyfikatorem projektu:

PROJECT_ID='your-cloud-project'

Utwórz repozytorium w Artifact Registry. Użyjemy repozytorium utworzonego w pierwszym module.

REPO_NAME='flower-app'

Zdefiniuj zmienną z identyfikatorem URI obrazu kontenera w Artifact Registry:

IMAGE_URI=us-central1-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/flower_image_distributed:single_machine

Konfigurowanie Dockera

gcloud auth configure-docker \
    us-central1-docker.pkg.dev

Następnie utwórz kontener, uruchamiając to polecenie w katalogu głównym flowers-multi-gpu:

docker build ./ -t $IMAGE_URI

Na koniec prześlij go do Artifact Registry:

docker push $IMAGE_URI

Po przeniesieniu kontenera do Artifact Registry możesz rozpocząć zadanie trenowania.

Krok 4. Uruchom zadanie za pomocą pakietu SDK

W tej sekcji dowiesz się, jak skonfigurować i uruchomić zadanie trenowania rozproszonego za pomocą pakietu Vertex AI Python SDK.

W menu uruchamiania utwórz notatnik TensorFlow 2.

new_notebook

Zaimportuj pakiet Vertex AI SDK.

from google.cloud import aiplatform

Następnie określ CustomContainerTrainingJob.

Musisz zastąpić {PROJECT_ID}container_uri{YOUR_BUCKET}staging_bucket.

job = aiplatform.CustomContainerTrainingJob(display_name='flowers-multi-gpu',
                                            container_uri='us-central1-docker.pkg.dev/{PROJECT_ID}/flower-app/flower_image_distributed:single_machine',
                                            staging_bucket='gs://{YOUR_BUCKET}')

Po zdefiniowaniu zadania możesz je uruchomić. Ustaw liczbę akceleratorów na 2. Jeśli użyjemy tylko 1 procesora GPU, nie będzie to uznawane za trenowanie rozproszone. Trenowanie rozproszone na jednej maszynie to trenowanie z użyciem co najmniej 2 akceleratorów.

my_custom_job.run(replica_count=1,
                  machine_type='n1-standard-4',
                  accelerator_type='NVIDIA_TESLA_V100',
                  accelerator_count=2)

W konsoli możesz sprawdzić postęp zadania.

multigpu_job

6. [Opcjonalnie] Trenowanie z użyciem wielu procesów roboczych

Teraz, gdy masz już za sobą eksperymenty z trenowaniem rozproszonym na jednym komputerze z wieloma procesorami graficznymi, możesz przenieść swoje umiejętności trenowania rozproszonego na wyższy poziom, trenując na wielu komputerach. Aby obniżyć koszty, nie dodamy do tych maszyn żadnych procesorów graficznych, ale jeśli chcesz, możesz przeprowadzić eksperyment, dodając GPU.

Otwórz nowe okno terminala w instancji notatnika:

Otwórz terminal w notatniku

Krok 1. Napisz kod szkoleniowy

Utwórz nowy katalog o nazwie flowers-multi-machine i przejdź do niego:

mkdir flowers-multi-machine
cd flowers-multi-machine

Uruchom to polecenie, aby utworzyć katalog na kod szkoleniowy i plik Pythona, do którego dodasz poniższy kod.

mkdir trainer
touch trainer/task.py

W katalogu flowers-multi-machine/ powinny się teraz znajdować te pliki:

+ trainer/
    + task.py

Następnie otwórz utworzony plik task.py i skopiuj poniższy kod.

Musisz zastąpić {your-gcs-bucket}BUCKET_ROOT zasobnikiem Cloud Storage, w którym w ćwiczeniu 1 został zapisany zbiór danych kwiatów.

import tensorflow as tf
import numpy as np
import os

## Replace {your-gcs-bucket} !!
BUCKET_ROOT='/gcs/{your-gcs-bucket}'

# Define variables
NUM_CLASSES = 5
EPOCHS=10
BATCH_SIZE = 32

IMG_HEIGHT = 180
IMG_WIDTH = 180

DATA_DIR = f'{BUCKET_ROOT}/flower_photos'
SAVE_MODEL_DIR = f'{BUCKET_ROOT}/multi-machine-output'

def create_datasets(data_dir, batch_size):
  '''Creates train and validation datasets.'''

  train_dataset = tf.keras.utils.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="training",
    seed=123,
    image_size=(IMG_HEIGHT, IMG_WIDTH),
    batch_size=batch_size)

  validation_dataset = tf.keras.utils.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="validation",
    seed=123,
    image_size=(IMG_HEIGHT, IMG_WIDTH),
    batch_size=batch_size)

  train_dataset = train_dataset.cache().shuffle(1000).prefetch(buffer_size=tf.data.AUTOTUNE)
  validation_dataset = validation_dataset.cache().prefetch(buffer_size=tf.data.AUTOTUNE)

  return train_dataset, validation_dataset


def create_model():
  '''Creates model.'''

  model = tf.keras.Sequential([
    tf.keras.layers.Resizing(IMG_HEIGHT, IMG_WIDTH),
    tf.keras.layers.Rescaling(1./255, input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
    tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')
  ])
  return model

def _is_chief(task_type, task_id):
  '''Helper function. Determines if machine is chief.'''

  return task_type == 'chief'


def _get_temp_dir(dirpath, task_id):
  '''Helper function. Gets temporary directory for saving model.'''

  base_dirpath = 'workertemp_' + str(task_id)
  temp_dir = os.path.join(dirpath, base_dirpath)
  tf.io.gfile.makedirs(temp_dir)
  return temp_dir


def write_filepath(filepath, task_type, task_id):
  '''Helper function. Gets filepath to save model.'''

  dirpath = os.path.dirname(filepath)
  base = os.path.basename(filepath)
  if not _is_chief(task_type, task_id):
    dirpath = _get_temp_dir(dirpath, task_id)
  return os.path.join(dirpath, base)

def main():
  # Create distribution strategy
  strategy = tf.distribute.MultiWorkerMirroredStrategy()

  # Get data
  GLOBAL_BATCH_SIZE = BATCH_SIZE * strategy.num_replicas_in_sync
  train_dataset, validation_dataset = create_datasets(DATA_DIR, BATCH_SIZE)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model()
    model.compile(optimizer=tf.keras.optimizers.Adam(),
                  loss=tf.keras.losses.SparseCategoricalCrossentropy(),
                  metrics=['accuracy'])

  history = model.fit(
    train_dataset,
    validation_data=validation_dataset,
    epochs=EPOCHS
  )

  # Determine type and task of the machine from
  # the strategy cluster resolver
  task_type, task_id = (strategy.cluster_resolver.task_type,
                        strategy.cluster_resolver.task_id)

  # Based on the type and task, write to the desired model path
  write_model_path = write_filepath(SAVE_MODEL_DIR, task_type, task_id)
  model.save(write_model_path)

if __name__ == "__main__":
    main()

Zanim utworzysz kontener, przyjrzyjmy się bliżej kodowi. W kodzie jest kilka komponentów, które są niezbędne do tego, aby aplikacja do trenowania działała z MultiWorkerMirroredStrategy.

  • W funkcji main() tworzony jest obiekt MultiWorkerMirroredStrategy. Następnie umieść tworzenie zmiennych modelu w zakresie strategii. Ten ważny krok informuje TensorFlow, które zmienne powinny być odzwierciedlane w replikach.
  • Wielkość wsadu jest zwiększana o num_replicas_in_sync. Skalowanie wielkości wsadu jest sprawdzoną metodą w przypadku korzystania w TensorFlow ze strategii synchronicznego równoległego przetwarzania danych.
  • Zapisanie modelu jest nieco bardziej skomplikowane w przypadku wielu instancji roboczych, ponieważ miejsce docelowe musi być inne dla każdej z nich. Główny proces roboczy zapisze model w wybranym katalogu, a pozostałe procesy robocze zapiszą model w katalogach tymczasowych. Ważne jest, aby te katalogi tymczasowe były unikalne, aby zapobiec zapisywaniu danych w tym samym miejscu przez wielu pracowników. Zapisywanie może obejmować operacje zbiorowe, co oznacza, że wszyscy pracownicy muszą zapisać dane, a nie tylko kierownik. Funkcje _is_chief(), _get_temp_dir(), write_filepath()main() zawierają powtarzalny kod, który pomaga zapisać model.

Krok 2. Utwórz plik Dockerfile

Aby umieścić kod w kontenerze, musisz utworzyć plik Dockerfile. W pliku Dockerfile umieścisz wszystkie polecenia potrzebne do uruchomienia obrazu. Zainstaluje wszystkie niezbędne biblioteki i skonfiguruje punkt wejścia dla kodu trenowania.

W terminalu utwórz pusty plik Dockerfile w katalogu głównym katalogu flowers:

touch Dockerfile

W katalogu flowers-multi-machine/ powinny się teraz znajdować te pliki:

+ Dockerfile
+ trainer/
    + task.py

Otwórz plik Dockerfile i skopiuj do niego ten kod:

FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-8

WORKDIR /

# Copies the trainer code to the docker image.
COPY trainer /trainer

# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.task"]

Krok 3. Utwórz kontener

W terminalu uruchom to polecenie, aby zdefiniować zmienną środowiskową dla projektu. Pamiętaj, aby zastąpić your-cloud-project identyfikatorem projektu:

PROJECT_ID='your-cloud-project'

Utwórz repozytorium w Artifact Registry. Użyjemy repozytorium utworzonego w pierwszym module.

REPO_NAME='flower-app'

Zdefiniuj zmienną z identyfikatorem URI obrazu kontenera w Google Artifact Registry:

IMAGE_URI=us-central1-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/flower_image_distributed:multi_machine

Konfigurowanie Dockera

gcloud auth configure-docker \
    us-central1-docker.pkg.dev

Następnie utwórz kontener, uruchamiając to polecenie w katalogu głównym flowers-multi-machine:

docker build ./ -t $IMAGE_URI

Na koniec prześlij go do Artifact Registry:

docker push $IMAGE_URI

Po przeniesieniu kontenera do Artifact Registry możesz rozpocząć zadanie trenowania.

Krok 4. Uruchom zadanie za pomocą pakietu SDK

W tej sekcji dowiesz się, jak skonfigurować i uruchomić zadanie trenowania rozproszonego za pomocą pakietu Vertex AI Python SDK.

W menu uruchamiania utwórz notatnik TensorFlow 2.

new_notebook

Zaimportuj pakiet Vertex AI SDK.

from google.cloud import aiplatform

Następnie określ worker_pool_specs.

Vertex AI udostępnia 4 pule instancji roboczych, które obsługują różne typy zadań wykonywanych przez maszyny.

Pula instancji roboczych 0 konfiguruje instancję główną, główną, harmonogram lub „master”. W MultiWorkerMirroredStrategy wszystkie maszyny są oznaczone jako procesory robocze, czyli maszyny fizyczne, na których wykonywane są replikowane obliczenia. Oprócz tego, że każda maszyna jest pracownikiem, musi być jeden pracownik, który wykonuje dodatkowe zadania, takie jak zapisywanie punktów kontrolnych i zapisywanie plików podsumowujących w TensorBoard. Ta maszyna jest nazywana szefem. Zawsze jest tylko 1 główna instancja robocza, więc liczba instancji roboczych w puli instancji roboczych 0 będzie zawsze wynosić 1.

Pula instancji roboczych 1 to miejsce, w którym konfigurujesz dodatkowe instancje robocze dla klastra.

Pierwszy słownik na liście worker_pool_specs reprezentuje pulę instancji roboczych 0, a drugi słownik reprezentuje pulę instancji roboczych 1. W tym przykładzie obie konfiguracje są identyczne. Jeśli jednak chcesz trenować na 3 maszynach, dodaj dodatkowych pracowników do puli instancji roboczych 1, ustawiając wartość replica_count na 2. Jeśli chcesz dodać procesory GPU, musisz dodać argumenty accelerator_typeaccelerator_count do argumentu machine_spec w przypadku obu pul instancji roboczych. Pamiętaj, że jeśli chcesz używać procesorów graficznych z MultiWorkerMirroredStrategy, każda maszyna w klastrze musi mieć identyczną liczbę procesorów graficznych. W przeciwnym razie zadanie się nie powiedzie.

Musisz zastąpić {PROJECT_ID}image_uri.

# The spec of the worker pools including machine type and Docker image
# Be sure to replace PROJECT_ID in the "image_uri" with your project.

worker_pool_specs=[
     {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-4",
        },
        "container_spec": {"image_uri": "us-central1-docker.pkg.dev/{PROJECT_ID}/flower-app/flower_image_distributed:multi_machine"}
      },
      {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-4",
        },
        "container_spec": {"image_uri": "us-central1-docker.pkg.dev/{PROJECT_ID}/flower-app/flower_image_distributed:multi_machine"}
      }
          ]

Następnie utwórz i uruchom CustomJob, zastępując {YOUR_BUCKET} w staging_bucket zasobnikiem w projekcie na potrzeby przesyłania etapowego.

my_custom_job = aiplatform.CustomJob(display_name='flowers-multi-worker',
                                     worker_pool_specs=worker_pool_specs,
                                     staging_bucket='gs://{YOUR_BUCKET}')

my_custom_job.run()

W konsoli możesz sprawdzić postęp zadania.

multi_worker_job

🎉 Gratulacje! 🎉

Dowiedziałeś się, jak używać Vertex AI do:

  • Uruchamianie rozproszonych zadań trenowania za pomocą TensorFlow

Więcej informacji o różnych częściach Vertex znajdziesz w dokumentacji.

7. Czyszczenie

Skonfigurowaliśmy notatnik tak, aby po 60 minutach bezczynności przekraczał limit czasu, więc nie musimy się martwić o zamykanie instancji. Jeśli chcesz ręcznie wyłączyć instancję, kliknij przycisk Zatrzymaj w sekcji Vertex AI Workbench w konsoli. Jeśli chcesz całkowicie usunąć notatnik, kliknij przycisk Usuń.

Zatrzymaj instancję

Aby usunąć zasobnik Storage, w menu nawigacyjnym w konsoli Cloud otwórz Storage, wybierz zasobnik i kliknij Usuń:

Usuń miejsce na dane