از GPU استفاده کنید

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

کد tf.keras و مدل‌های tf.keras به طور شفاف روی یک GPU واحد اجرا می‌شوند و نیازی به تغییر کد نیستند.

ساده ترین راه برای اجرا بر روی چندین GPU، در یک یا چند ماشین، استفاده از استراتژی های توزیع است.

این راهنما برای کاربرانی است که این رویکردها را امتحان کرده‌اند و دریافته‌اند که به کنترل دقیق نحوه استفاده TensorFlow از GPU نیاز دارند. برای یادگیری نحوه اشکال زدایی مشکلات عملکرد برای سناریوهای تک و چند GPU، به راهنمای عملکرد GPU Optimize TensorFlow مراجعه کنید.

برپایی

مطمئن شوید که آخرین نسخه GPU TensorFlow را نصب کرده اید.

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

بررسی اجمالی

TensorFlow از اجرای محاسبات بر روی انواع مختلف دستگاه ها، از جمله CPU و GPU پشتیبانی می کند. آنها با شناسه های رشته ای به عنوان مثال نشان داده می شوند:

  • "/device:CPU:0" : CPU دستگاه شما.
  • "/GPU:0" : نماد کوتاه برای اولین GPU دستگاه شما که برای TensorFlow قابل مشاهده است.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : نام کاملا واجد شرایط دومین GPU دستگاه شما که برای TensorFlow قابل مشاهده است.

اگر یک عملیات TensorFlow دارای هر دو اجرای CPU و GPU باشد، به طور پیش‌فرض، دستگاه GPU در زمان اختصاص داده شدن عملیات در اولویت قرار می‌گیرد. به عنوان مثال، tf.matmul دارای هر دو هسته CPU و GPU است و در سیستمی با دستگاه های CPU:0 و GPU:0 ، دستگاه GPU:0 برای اجرای tf.matmul انتخاب می شود، مگر اینکه صریحاً درخواست اجرای آن را در دستگاه دیگری داشته باشید.

اگر یک عملیات TensorFlow فاقد اجرای GPU متناظر باشد، این عملیات به دستگاه CPU بازمی گردد. به عنوان مثال، از آنجایی که tf.cast فقط هسته CPU دارد، در سیستمی با دستگاه‌های CPU:0 و GPU:0 ، دستگاه CPU:0 برای اجرای tf.cast انتخاب می‌شود، حتی اگر درخواست شود روی دستگاه 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 در این مثال) یکی را انتخاب می کند و در صورت نیاز به طور خودکار تانسورها را بین دستگاه ها کپی می کند.

محدود کردن رشد حافظه GPU

به‌طور پیش‌فرض، TensorFlow تقریباً تمام حافظه GPU همه پردازنده‌های گرافیکی (با توجه به CUDA_VISIBLE_DEVICES ) را برای فرآیند قابل مشاهده نقشه‌برداری می‌کند. این کار برای استفاده مؤثرتر از منابع حافظه نسبتاً ارزشمند GPU در دستگاه ها با کاهش تکه تکه شدن حافظه انجام می شود. برای محدود کردن TensorFlow به مجموعه خاصی از GPU ها، از روش 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 ، رشد حافظه را روشن کنید، که سعی می کند تنها به اندازه حافظه GPU مورد نیاز برای تخصیص زمان اجرا تخصیص دهد: با تخصیص حافظه بسیار کمی شروع می شود، و با اجرای برنامه و حافظه GPU بیشتری مورد نیاز است، منطقه حافظه GPU برای فرآیند TensorFlow گسترش می یابد. حافظه آزاد نمی شود زیرا می تواند منجر به تکه تکه شدن حافظه شود. برای روشن کردن رشد حافظه برای یک GPU خاص، قبل از تخصیص هر تانسور یا اجرای عملیات از کد زیر استفاده کنید.

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 . این پیکربندی مخصوص پلتفرم است.

روش دوم پیکربندی یک دستگاه GPU مجازی با tf.config.set_logical_device_configuration و تعیین محدودیت سخت برای کل حافظه برای تخصیص به 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

اگر می‌خواهید واقعاً مقدار حافظه GPU موجود را به فرآیند TensorFlow محدود کنید، این کار مفید است. هنگامی که GPU با برنامه های کاربردی دیگر مانند GUI ایستگاه کاری به اشتراک گذاشته می شود، این روش معمول برای توسعه محلی است.

استفاده از یک GPU واحد در یک سیستم چند GPU

اگر بیش از یک GPU در سیستم خود دارید، GPU با کمترین شناسه به طور پیش فرض انتخاب می شود. اگر می‌خواهید روی یک 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)

استفاده از چندین پردازنده گرافیکی

توسعه برای چندین GPU به یک مدل اجازه می دهد تا با منابع اضافی مقیاس شود. اگر روی یک سیستم با یک GPU توسعه می‌دهید، می‌توانید چندین GPU را با دستگاه‌های مجازی شبیه‌سازی کنید. این امکان تست آسان تنظیمات چند GPU را بدون نیاز به منابع اضافی فراهم می کند.

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

هنگامی که چندین پردازنده گرافیکی منطقی برای زمان اجرا در دسترس هستند، می توانید از چندین GPU با tf.distribute.Strategy یا با قرار دادن دستی استفاده کنید.

با tf.distribute.Strategy

بهترین روش برای استفاده از چندین GPU استفاده از 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

این برنامه یک کپی از مدل شما را بر روی هر GPU اجرا می کند و داده های ورودی را بین آنها تقسیم می کند که به " موازی داده ها " نیز معروف است.

برای اطلاعات بیشتر در مورد استراتژی های توزیع، راهنمای اینجا را بررسی کنید.

قرار دادن دستی

tf.distribute.Strategy با تکثیر محاسبات در دستگاه‌ها زیر پوشش کار می‌کند. شما می توانید با ساخت مدل خود بر روی هر GPU، Replication را به صورت دستی پیاده سازی کنید. مثلا:

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)