استخدم GPU

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

سيتم تشغيل نماذج tf.keras و tf.keras بشفافية على وحدة معالجة رسومات واحدة دون الحاجة إلى إجراء تغييرات في التعليمات البرمجية.

إن أبسط طريقة للتشغيل على وحدات معالجة رسومات متعددة ، على جهاز واحد أو عدة أجهزة ، هي استخدام استراتيجيات التوزيع .

هذا الدليل مخصص للمستخدمين الذين جربوا هذه الأساليب ووجدوا أنهم بحاجة إلى تحكم دقيق في كيفية استخدام TensorFlow لوحدة معالجة الرسومات. لمعرفة كيفية تصحيح أخطاء الأداء لسيناريوهات GPU الفردية والمتعددة ، راجع دليل تحسين أداء وحدة معالجة الرسومات 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" : تدوين مختصر لأول GPU بجهازك يكون مرئيًا لـ TensorFlow.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : اسم مؤهل بالكامل لوحدة معالجة الرسومات الثانية بجهازك المرئي لـ TensorFlow.

إذا كانت عملية TensorFlow تشتمل على تطبيقات لكل من وحدة المعالجة المركزية ووحدة معالجة الرسومات ، يتم بشكل افتراضي إعطاء الأولوية لجهاز GPU عند تعيين العملية. على سبيل المثال ، يحتوي tf.matmul على نواة CPU و GPU وعلى نظام به أجهزة CPU:0 و GPU:0 ، يتم تحديد جهاز GPU:0 لتشغيل tf.matmul ما لم تطلب صراحة تشغيله على جهاز آخر.

إذا لم يكن لعملية TensorFlow تنفيذ GPU مطابق ، فعندئذٍ تعود العملية إلى جهاز وحدة المعالجة المركزية. على سبيل المثال ، نظرًا لأن tf.cast يحتوي فقط على نواة وحدة المعالجة المركزية ، على نظام به أجهزة 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 op تم تنفيذه على 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 بتعيين كل ذاكرة GPU تقريبًا لجميع وحدات معالجة الرسومات (تخضع لـ 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 ، الذي يحاول تخصيص مساحة ذاكرة GPU فقط حسب الحاجة لتخصيصات وقت التشغيل: يبدأ بتخصيص القليل جدًا من الذاكرة ، وعندما يتم تشغيل البرنامج و هناك حاجة إلى المزيد من ذاكرة وحدة معالجة الرسومات ، يتم تمديد منطقة ذاكرة وحدة معالجة الرسومات لعملية 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 . هذا التكوين هو منصة محددة.

الطريقة الثانية هي تكوين جهاز 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

يكون هذا مفيدًا إذا كنت تريد حقًا ربط مقدار ذاكرة وحدة معالجة الرسومات المتاحة لعملية TensorFlow. هذه ممارسة شائعة للتطوير المحلي عندما تتم مشاركة 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)

استخدام العديد من وحدات معالجة الرسومات

سيسمح التطوير لوحدات معالجة الرسومات المتعددة للنموذج بالتوسع مع الموارد الإضافية. إذا كنت تقوم بالتطوير على نظام به وحدة معالجة رسومات واحدة ، فيمكنك محاكاة وحدات معالجة رسومات متعددة باستخدام أجهزة افتراضية. يتيح هذا الاختبار السهل لإعدادات وحدات معالجة الرسومات المتعددة دون الحاجة إلى موارد إضافية.

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)