Pomoc chronić Wielkiej Rafy Koralowej z TensorFlow na Kaggle Dołącz Wyzwanie

Użyj GPU

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

Kod TensorFlow i tf.keras modele będą przejrzyście prowadzony na pojedynczym GPU wymagane żadne zmiany kodu.

Najprostszym sposobem, aby uruchomić na wielu GPU, na jednym lub wielu komputerach, używa strategii dystrybucji .

Ten przewodnik jest przeznaczony dla użytkowników, którzy wypróbowali te podejścia i odkryli, że potrzebują precyzyjnej kontroli nad sposobem, w jaki TensorFlow korzysta z GPU. Aby dowiedzieć się, jak do debugowania problemów z wydajnością do pojedynczych i multi-GPU scenariuszy, zobacz Optymalizacja wydajności GPU TensorFlow instrukcji.

Ustawiać

Upewnij się, że masz zainstalowaną najnowszą wersję procesora graficznego TensorFlow.

import tensorflow as tf
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))
Num GPUs Available:  1

Przegląd

TensorFlow obsługuje uruchamianie obliczeń na różnych typach urządzeń, w tym CPU i GPU. Są one reprezentowane przez identyfikatory ciągów, na przykład:

  • "/device:CPU:0" : CPU Twojego urządzenia.
  • "/GPU:0" : Krótki notacja używana w pierwszym GPU komputerze, który jest widoczny dla TensorFlow.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : W pełni kwalifikowana nazwa drugiego GPU komputerze, który jest widoczny dla TensorFlow.

Jeśli operacja TensorFlow ma implementacje zarówno procesora CPU, jak i GPU, domyślnie urządzenie GPU ma priorytet, gdy operacja jest przypisywana. Na przykład, tf.matmul ma zarówno CPU i GPU jądra i na systemie z urządzeniami CPU:0 i GPU:0 The GPU:0 urządzenie jest wybrane do uruchomienia tf.matmul chyba że wyraźnie zażądać, aby uruchomić go na innym urządzeniu.

Jeśli operacja TensorFlow nie ma odpowiedniej implementacji GPU, operacja powraca do urządzenia CPU. Na przykład, ponieważ tf.cast ma tylko jądro procesora, w systemie z urządzeniami CPU:0 i GPU:0 The CPU:0 urządzenie jest wybrane, aby uruchomić tf.cast , nawet jeżeli są wymagane do uruchamiania na GPU:0 urządzenie .

Umieszczenie urządzenia rejestrującego

Aby dowiedzieć się, które urządzenia twoje operacje i tensory są przypisane, umieścić tf.debugging.set_log_device_placement(True) jako pierwszego zestawienia programu. Włączenie rejestrowania rozmieszczenia urządzeń powoduje, że wszystkie alokacje lub operacje Tensora zostaną wydrukowane.

tf.debugging.set_log_device_placement(True)

# Create some tensors
a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
c = tf.matmul(a, b)

print(c)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

Powyższy kod wypisze wskazanie MatMul op nie został wykonany na GPU:0 .

Ręczne umieszczanie urządzenia

Jeśli chcesz konkretnej operacji, aby uruchomić na urządzeniu z wyboru, a nie to, co automatycznie wybrane dla ciebie, możesz skorzystać with tf.device stworzyć kontekst urządzenia, a wszystkie operacje w tym kontekście będzie działać na tym samym urządzeniu wyznaczonego .

tf.debugging.set_log_device_placement(True)

# Place tensors on the CPU
with tf.device('/CPU:0'):
  a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
  b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])

# Run on the GPU
c = tf.matmul(a, b)
print(c)
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

Przekonasz się, że teraz i a b są przypisane do CPU:0 . Ponieważ urządzenie nie zostało wyraźnie określone dla MatMul pracy, środowisko wykonawcze TensorFlow wybiorą jedną opartą na pracy i dostępnych urządzeń ( GPU:0 w tym przykładzie) i automatycznie kopiować tensory pomiędzy urządzeniami w razie potrzeby.

Ograniczenie wzrostu pamięci GPU

Domyślnie TensorFlow odwzorowuje prawie wszystkie pamięci GPU (GPU wszystkich podlegających CUDA_VISIBLE_DEVICES ) Visible do procesu. Ma to na celu bardziej efektywne wykorzystanie stosunkowo cennych zasobów pamięci GPU na urządzeniach poprzez zmniejszenie fragmentacji pamięci. Aby ograniczyć TensorFlow do konkretnego zestawu procesorów graficznych, użyj tf.config.set_visible_devices metody.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  # Restrict TensorFlow to only use the first GPU
  try:
    tf.config.set_visible_devices(gpus[0], 'GPU')
    logical_gpus = tf.config.list_logical_devices('GPU')
    print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPU")
  except RuntimeError as e:
    # Visible devices must be set before GPUs have been initialized
    print(e)
1 Physical GPUs, 1 Logical GPU

W niektórych przypadkach pożądane jest, aby proces alokował tylko podzbiór dostępnej pamięci lub zwiększał użycie pamięci tylko w miarę potrzeb procesu. TensorFlow udostępnia dwie metody kontrolowania tego.

Pierwsza opcja jest z kolei na wzrost pamięci wywołując tf.config.experimental.set_memory_growth , który próbuje przydzielić tylko tyle pamięci GPU jako niezbędnego do alokacji uruchomieniowych: zaczyna się przydzielanie bardzo mało pamięci, jak i program zostanie uruchomiony i potrzebna jest większa ilość pamięci GPU, region pamięci GPU zostaje rozszerzony dla procesu TensorFlow. Pamięć nie jest uwalniana, ponieważ może prowadzić do fragmentacji pamięci. Aby włączyć przyrost pamięci dla określonego GPU, użyj poniższego kodu przed przydzieleniem jakichkolwiek tensorów lub wykonaniem jakichkolwiek operacji.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  try:
    # Currently, memory growth needs to be the same across GPUs
    for gpu in gpus:
      tf.config.experimental.set_memory_growth(gpu, True)
    logical_gpus = tf.config.list_logical_devices('GPU')
    print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
  except RuntimeError as e:
    # Memory growth must be set before GPUs have been initialized
    print(e)
Physical devices cannot be modified after being initialized

Innym sposobem, aby włączyć tę opcję, jest ustawienie zmiennej środowiskowej na TF_FORCE_GPU_ALLOW_GROWTH na true . Ta konfiguracja jest specyficzna dla platformy.

Druga metoda jest skonfigurowanie urządzenia wirtualnego procesora graficznego ze tf.config.set_logical_device_configuration i ustawić twardego limit całkowitej pamięci alokowania na graficznego.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  # Restrict TensorFlow to only allocate 1GB of memory on the first GPU
  try:
    tf.config.set_logical_device_configuration(
        gpus[0],
        [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])
    logical_gpus = tf.config.list_logical_devices('GPU')
    print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
  except RuntimeError as e:
    # Virtual devices must be set before GPUs have been initialized
    print(e)
Virtual devices cannot be modified after being initialized

Jest to przydatne, jeśli chcesz naprawdę ograniczyć ilość pamięci GPU dostępnej dla procesu TensorFlow. Jest to powszechna praktyka w przypadku programowania lokalnego, gdy procesor graficzny jest współużytkowany z innymi aplikacjami, takimi jak graficzny interfejs użytkownika stacji roboczej.

Korzystanie z jednego procesora graficznego w systemie z wieloma procesorami graficznymi

Jeśli masz więcej niż jeden procesor GPU w swoim systemie, domyślnie wybrany zostanie procesor GPU o najniższym identyfikatorze. Jeśli chcesz pracować na innym GPU, musisz wyraźnie określić preferencje:

tf.debugging.set_log_device_placement(True)

try:
  # Specify an invalid GPU device
  with tf.device('/device:GPU:2'):
    a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
    b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
    c = tf.matmul(a, b)
except RuntimeError as e:
  print(e)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0

Jeśli urządzenie podałeś nie istnieje, dostaniesz RuntimeError : .../device:GPU:2 unknown device .

Jeśli chciałbyś TensorFlow aby automatycznie wybrać istniejący i obsługiwanego urządzenia do prowadzenia operacji w przypadku określonego jeden nie istnieje, można zadzwonić tf.config.set_soft_device_placement(True) .

tf.config.set_soft_device_placement(True)
tf.debugging.set_log_device_placement(True)

# Creates some tensors
a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
c = tf.matmul(a, b)

print(c)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

Korzystanie z wielu procesorów graficznych

Programowanie dla wielu procesorów graficznych pozwoli na skalowanie modelu z dodatkowymi zasobami. W przypadku programowania w systemie z jednym procesorem GPU można symulować wiele procesorów GPU za pomocą urządzeń wirtualnych. Umożliwia to łatwe testowanie konfiguracji z wieloma procesorami graficznymi bez konieczności korzystania z dodatkowych zasobów.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  # Create 2 virtual GPUs with 1GB memory each
  try:
    tf.config.set_logical_device_configuration(
        gpus[0],
        [tf.config.LogicalDeviceConfiguration(memory_limit=1024),
         tf.config.LogicalDeviceConfiguration(memory_limit=1024)])
    logical_gpus = tf.config.list_logical_devices('GPU')
    print(len(gpus), "Physical GPU,", len(logical_gpus), "Logical GPUs")
  except RuntimeError as e:
    # Virtual devices must be set before GPUs have been initialized
    print(e)
Virtual devices cannot be modified after being initialized

Raz istnieje wiele logicznych procesorów graficznych dostępnych dla wykonywania, można korzystać z wielu procesorów graficznych z tf.distribute.Strategy lub z ręcznym umieszczeniu.

z tf.distribute.Strategy

Najlepszym rozwiązaniem dla korzystania z wielu procesorów graficznych jest użycie tf.distribute.Strategy . Oto prosty przykład:

tf.debugging.set_log_device_placement(True)
gpus = tf.config.list_logical_devices('GPU')
strategy = tf.distribute.MirroredStrategy(gpus)
with strategy.scope():
  inputs = tf.keras.layers.Input(shape=(1,))
  predictions = tf.keras.layers.Dense(1)(inputs)
  model = tf.keras.models.Model(inputs=inputs, outputs=predictions)
  model.compile(loss='mse',
                optimizer=tf.keras.optimizers.SGD(learning_rate=0.2))
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op RandomUniform in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Sub in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Mul in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AddV2 in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Fill in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Fill in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Fill in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0

Program ten będzie realizowany kopię modelu na każdym GPU, podział danych wejściowych między nimi, znany również jako „ równoległości danych ”.

Aby uzyskać więcej informacji na temat strategii dystrybucji, sprawdź przewodnik tutaj .

Ręczne umieszczanie

tf.distribute.Strategy pracuje pod maską przez replikację obliczeń różnych urządzeniach. Możesz ręcznie zaimplementować replikację, konstruując model na każdym GPU. Na przykład:

tf.debugging.set_log_device_placement(True)

gpus = tf.config.list_logical_devices('GPU')
if gpus:
  # Replicate your computation on multiple GPUs
  c = []
  for gpu in gpus:
    with tf.device(gpu.name):
      a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
      b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
      c.append(tf.matmul(a, b))

  with tf.device('/CPU:0'):
    matmul_sum = tf.add_n(c)

  print(matmul_sum)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)