Использовать графический процессор

Посмотреть на TensorFlow.org Запустить в Google Colab Посмотреть исходный код на GitHub Скачать блокнот

Код tf.keras и модели tf.keras будут прозрачно работать на одном графическом процессоре без необходимости изменения кода.

Самый простой способ запуска на нескольких графических процессорах, на одной или нескольких машинах — это использование стратегий распределения .

Это руководство предназначено для пользователей, которые опробовали эти подходы и обнаружили, что им нужен детальный контроль над тем, как TensorFlow использует графический процессор. Чтобы узнать, как устранять проблемы с производительностью для сценариев с одним и несколькими графическими процессорами, см. руководство по оптимизации производительности графического процессора TensorFlow .

Настраивать

Убедитесь, что у вас установлена ​​последняя версия графического процессора TensorFlow.

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

Обзор

TensorFlow поддерживает выполнение вычислений на различных типах устройств, включая ЦП и ГП. Они представлены строковыми идентификаторами, например:

  • "/device:CPU:0" : ЦП вашей машины.
  • "/GPU:0" : сокращенное обозначение первого графического процессора вашей машины, который виден TensorFlow.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : полное имя второго графического процессора вашего компьютера, который виден TensorFlow.

Если операция TensorFlow имеет реализации как ЦП, так и ГП, по умолчанию при назначении операции приоритет отдается устройству ГП. Например, tf.matmul имеет ядра как CPU, так и GPU, и в системе с устройствами CPU:0 и GPU:0 для запуска tf.matmul выбирается устройство GPU:0 , если вы явно не запросите его запуск на другом устройстве.

Если операция TensorFlow не имеет соответствующей реализации графического процессора, операция возвращается к устройству ЦП. Например, поскольку tf.cast имеет только ядро ​​ЦП, в системе с устройствами CPU:0 и GPU:0 для запуска tf.cast выбирается устройство CPU:0 , даже если запрашивается запуск на устройстве GPU:0 .

Размещение регистрирующего устройства

Чтобы узнать, каким устройствам назначены ваши операции и тензоры, поместите tf.debugging.set_log_device_placement(True) в качестве первого оператора вашей программы. Включение ведения журнала размещения устройств приводит к печати любых выделений или операций Tensor.

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)

Приведенный выше код напечатает указание, что MatMul была выполнена на GPU:0 .

Размещение устройства вручную

Если вы хотите, чтобы конкретная операция выполнялась на устройстве по вашему выбору, а не на том, что автоматически выбирается для вас, вы можете использовать with tf.device для создания контекста устройства, и все операции в этом контексте будут выполняться на одном и том же назначенном устройстве. .

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)

Вы увидите, что теперь a и b назначены CPU:0 . Поскольку устройство не было указано явно для операции MatMul , среда выполнения TensorFlow выберет его на основе операции и доступных устройств (в этом примере GPU:0 ) и при необходимости автоматически скопирует тензоры между устройствами.

Ограничение роста памяти графического процессора

По умолчанию TensorFlow отображает почти всю память графического процессора всех графических процессоров (с учетом CUDA_VISIBLE_DEVICES ), видимых для процесса. Это сделано для более эффективного использования относительно ценных ресурсов памяти графического процессора на устройствах за счет уменьшения фрагментации памяти. Чтобы ограничить TensorFlow определенным набором графических процессоров, используйте метод tf.config.set_visible_devices .

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

В некоторых случаях желательно, чтобы процесс выделял только подмножество доступной памяти или увеличивал использование памяти только по мере необходимости. TensorFlow предоставляет два метода управления этим.

Первый вариант — включить увеличение памяти, вызвав tf.config.experimental.set_memory_growth , который пытается выделить ровно столько памяти графического процессора, сколько необходимо для выделения во время выполнения: сначала он выделяет очень мало памяти, а по мере запуска программы и требуется больше памяти графического процессора, область памяти графического процессора расширяется для процесса TensorFlow. Память не освобождается, так как это может привести к фрагментации памяти. Чтобы включить увеличение памяти для определенного графического процессора, используйте следующий код перед выделением любых тензоров или выполнением любых операций.

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

Другой способ включить эту опцию — установить для переменной окружения TF_FORCE_GPU_ALLOW_GROWTH значение true . Эта конфигурация зависит от платформы.

Второй метод заключается в настройке виртуального устройства с графическим процессором с помощью tf.config.set_logical_device_configuration и установке жесткого ограничения на общий объем памяти, выделяемой на графическом процессоре.

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

Это полезно, если вы хотите по-настоящему ограничить объем памяти графического процессора, доступный для процесса TensorFlow. Это обычная практика для локальной разработки, когда GPU используется совместно с другими приложениями, такими как графический интерфейс рабочей станции.

Использование одного графического процессора в системе с несколькими графическими процессорами

Если в вашей системе более одного графического процессора, по умолчанию будет выбран графический процессор с наименьшим идентификатором. Если вы хотите работать на другом графическом процессоре, вам нужно явно указать предпочтение:

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

Если указанное вами устройство не существует, вы получите RuntimeError : .../device:GPU:2 unknown device .

Если вы хотите, чтобы TensorFlow автоматически выбирал существующее и поддерживаемое устройство для выполнения операций, если указанное не существует, вы можете вызвать 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)

Использование нескольких графических процессоров

Разработка для нескольких графических процессоров позволит масштабировать модель с дополнительными ресурсами. При разработке в системе с одним графическим процессором вы можете моделировать несколько графических процессоров с помощью виртуальных устройств. Это позволяет легко тестировать установки с несколькими графическими процессорами, не требуя дополнительных ресурсов.

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

Когда для среды выполнения доступно несколько логических графических процессоров, вы можете использовать несколько графических процессоров с помощью tf.distribute.Strategy или с ручным размещением.

С tf.distribute.Strategy

Лучшей практикой для использования нескольких графических процессоров является использование tf.distribute.Strategy . Вот простой пример:

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

Эта программа будет запускать копию вашей модели на каждом графическом процессоре, разделяя входные данные между ними, что также известно как « параллелизм данных ».

Для получения дополнительной информации о стратегиях распространения ознакомьтесь с руководством здесь .

Размещение вручную

tf.distribute.Strategy работает «под капотом», копируя вычисления между устройствами. Вы можете вручную реализовать репликацию, создав свою модель на каждом графическом процессоре. Например:

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)