Gunakan GPU

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Kode TensorFlow, dan model tf.keras akan berjalan secara transparan pada satu GPU tanpa memerlukan perubahan kode.

Cara paling sederhana untuk berjalan di beberapa GPU, pada satu atau banyak mesin, adalah menggunakan Strategi Distribusi .

Panduan ini ditujukan untuk pengguna yang telah mencoba pendekatan ini dan mendapati bahwa mereka memerlukan kontrol yang cermat tentang cara TensorFlow menggunakan GPU. Untuk mempelajari cara men-debug masalah performa untuk skenario tunggal dan multi-GPU, lihat panduan Mengoptimalkan Performa GPU TensorFlow .

Mempersiapkan

Pastikan Anda telah menginstal rilis GPU TensorFlow terbaru.

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

Ringkasan

TensorFlow mendukung komputasi yang berjalan pada berbagai jenis perangkat, termasuk CPU dan GPU. Mereka diwakili dengan pengidentifikasi string misalnya:

  • "/device:CPU:0" : CPU mesin Anda.
  • "/GPU:0" : Notasi singkat untuk GPU pertama mesin Anda yang terlihat oleh TensorFlow.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : Nama yang sepenuhnya memenuhi syarat dari GPU kedua mesin Anda yang terlihat oleh TensorFlow.

Jika operasi TensorFlow memiliki implementasi CPU dan GPU, secara default, perangkat GPU diprioritaskan saat operasi ditetapkan. Misalnya, tf.matmul memiliki kernel CPU dan GPU dan pada sistem dengan perangkat CPU:0 dan GPU:0 , perangkat GPU:0 dipilih untuk menjalankan tf.matmul kecuali Anda secara eksplisit meminta untuk menjalankannya di perangkat lain.

Jika operasi TensorFlow tidak memiliki implementasi GPU yang sesuai, maka operasi akan kembali ke perangkat CPU. Misalnya, karena tf.cast hanya memiliki kernel CPU, pada sistem dengan perangkat CPU:0 dan GPU:0 , perangkat CPU:0 dipilih untuk menjalankan tf.cast , bahkan jika diminta untuk dijalankan pada perangkat GPU:0 .

Penempatan perangkat logging

Untuk mengetahui perangkat mana yang ditetapkan untuk operasi dan tensor Anda, masukkan tf.debugging.set_log_device_placement(True) sebagai pernyataan pertama program Anda. Mengaktifkan logging penempatan perangkat menyebabkan alokasi atau operasi Tensor dicetak.

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)

Kode di atas akan mencetak indikasi operasi MatMul dijalankan pada GPU:0 .

Penempatan perangkat manual

Jika Anda ingin operasi tertentu berjalan pada perangkat pilihan Anda alih-alih apa yang dipilih secara otomatis untuk Anda, Anda dapat menggunakan with tf.device untuk membuat konteks perangkat, dan semua operasi dalam konteks itu akan berjalan pada perangkat yang ditunjuk yang sama .

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)

Anda akan melihat bahwa sekarang a dan b ditugaskan ke CPU:0 . Karena perangkat tidak secara eksplisit ditentukan untuk operasi MatMul , runtime TensorFlow akan memilih satu berdasarkan operasi dan perangkat yang tersedia ( GPU:0 dalam contoh ini) dan secara otomatis menyalin tensor antar perangkat jika diperlukan.

Membatasi pertumbuhan memori GPU

Secara default, TensorFlow memetakan hampir semua memori GPU dari semua GPU (berdasarkan CUDA_VISIBLE_DEVICES ) yang terlihat oleh proses. Ini dilakukan untuk lebih efisien menggunakan sumber daya memori GPU yang relatif berharga pada perangkat dengan mengurangi fragmentasi memori. Untuk membatasi TensorFlow ke kumpulan GPU tertentu, gunakan metode 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

Dalam beberapa kasus, diinginkan proses untuk hanya mengalokasikan sebagian dari memori yang tersedia, atau hanya meningkatkan penggunaan memori yang diperlukan oleh proses. TensorFlow menyediakan dua metode untuk mengontrol ini.

Opsi pertama adalah mengaktifkan pertumbuhan memori dengan memanggil tf.config.experimental.set_memory_growth , yang mencoba mengalokasikan hanya memori GPU sebanyak yang diperlukan untuk alokasi runtime: ia mulai mengalokasikan sangat sedikit memori, dan saat program dijalankan dan lebih banyak memori GPU diperlukan, wilayah memori GPU diperluas untuk proses TensorFlow. Memori tidak dilepaskan karena dapat menyebabkan fragmentasi memori. Untuk mengaktifkan pertumbuhan memori untuk GPU tertentu, gunakan kode berikut sebelum mengalokasikan tensor apa pun atau menjalankan operasi apa pun.

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

Cara lain untuk mengaktifkan opsi ini adalah dengan menyetel variabel lingkungan TF_FORCE_GPU_ALLOW_GROWTH menjadi true . Konfigurasi ini khusus untuk platform.

Metode kedua adalah mengonfigurasi perangkat GPU virtual dengan tf.config.set_logical_device_configuration dan menetapkan batas keras pada total memori yang akan dialokasikan pada GPU.

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

Ini berguna jika Anda ingin benar-benar mengikat jumlah memori GPU yang tersedia untuk proses TensorFlow. Ini adalah praktik umum untuk pengembangan lokal ketika GPU digunakan bersama dengan aplikasi lain seperti GUI workstation.

Menggunakan satu GPU pada sistem multi-GPU

Jika Anda memiliki lebih dari satu GPU di sistem Anda, GPU dengan ID terendah akan dipilih secara default. Jika Anda ingin menjalankan pada GPU yang berbeda, Anda harus menentukan preferensi secara eksplisit:

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

Jika perangkat yang Anda tentukan tidak ada, Anda akan mendapatkan RuntimeError : .../device:GPU:2 unknown device .

Jika Anda ingin TensorFlow secara otomatis memilih perangkat yang ada dan yang didukung untuk menjalankan operasi jika yang ditentukan tidak ada, Anda dapat memanggil 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)

Menggunakan beberapa GPU

Mengembangkan untuk beberapa GPU akan memungkinkan model untuk diskalakan dengan sumber daya tambahan. Jika mengembangkan pada sistem dengan satu GPU, Anda dapat mensimulasikan beberapa GPU dengan perangkat virtual. Hal ini memungkinkan pengujian pengaturan multi-GPU dengan mudah tanpa memerlukan sumber daya tambahan.

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

Setelah ada beberapa GPU logis yang tersedia untuk runtime, Anda dapat menggunakan beberapa GPU dengan tf.distribute.Strategy atau dengan penempatan manual.

Dengan tf.distribute.Strategy

Praktik terbaik untuk menggunakan beberapa GPU adalah dengan menggunakan tf.distribute.Strategy . Berikut adalah contoh sederhana:

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 ini akan menjalankan salinan model Anda di setiap GPU, membagi data input di antara mereka, juga dikenal sebagai " paralelisme data ".

Untuk informasi lebih lanjut tentang strategi distribusi, lihat panduannya di sini .

Penempatan manual

tf.distribute.Strategy bekerja di bawah tenda dengan mereplikasi komputasi di seluruh perangkat. Anda dapat mengimplementasikan replikasi secara manual dengan membuat model Anda di setiap GPU. Sebagai contoh:

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)