השתמש ב- GPU

צפה ב- TensorFlow.org הפעל בגוגל קולאב צפה במקור ב- GitHub הורד מחברת

קוד TensorFlow, ו tf.keras דגמים יפעלו בצורה שקופה על GPU אחד עם צורך בביצוע שינויים בקוד.

הדרך הפשוטה ביותר לרוץ על GPUs מרובים, על מכונות אחת או רבות, היא באמצעות אסטרטגיות הפצה .

מדריך זה מיועד למשתמשים שניסו גישות אלה ומצאו כי הם זקוקים לשליטה דקה באופן השימוש ב- TensorFlow ב- GPU. כדי ללמוד כיצד באגים בעיות ביצועים עבור תרחישים בודדים ורב-GPU, לראות את ביצועי GPU מטב TensorFlow המדריך.

להכין

ודא שהתקנת גרסת ה- GPU האחרונה של TensorFlow.

import tensorflow as tf
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))
2021-07-28 01:21:13.690704: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
Num GPUs Available:  1
2021-07-28 01:21:14.839090: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
2021-07-28 01:21:15.456858: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:15.457781: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-28 01:21:15.457813: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-28 01:21:15.461458: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-07-28 01:21:15.461551: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
2021-07-28 01:21:15.462602: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcufft.so.10
2021-07-28 01:21:15.462912: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcurand.so.10
2021-07-28 01:21:15.463978: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusolver.so.11
2021-07-28 01:21:15.464895: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusparse.so.11
2021-07-28 01:21:15.465062: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-07-28 01:21:15.465195: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:15.466136: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:15.467011: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0

סקירה כללית

TensorFlow תומך בהפעלת חישובים על מגוון סוגי מכשירים, כולל מעבד ו- GPU. הם מיוצגים עם מזהי מחרוזות למשל:

  • "/device:CPU:0" : המעבד של המחשב שלך.
  • "/GPU:0" : סימון קצר יד עבור ה- GPU הראשון של המחשב שלך כי הוא גלוי TensorFlow.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : שם מלא של ה- GPU השני של המחשב שלך כי הוא גלוי TensorFlow.

אם לפעולה של TensorFlow יש גם יישומי מעבד וגם GPU, כברירת מחדל, מכשיר ה- 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 מכשיר .

מיקום מכשיר רישום

כדי לגלות אילו מכשירים התפעול tensors שלך מוקצים, put 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)
2021-07-28 01:21:15.477558: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-07-28 01:21:15.478028: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:15.478891: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-28 01:21:15.478976: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:15.479838: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:15.480744: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-07-28 01:21:15.480791: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-28 01:21:16.059272: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1258] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-07-28 01:21:16.059307: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1264]      0 
2021-07-28 01:21:16.059314: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1277] 0:   N 
2021-07-28 01:21:16.059497: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:16.060447: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:16.061335: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-28 01:21:16.062148: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1418] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14646 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
2021-07-28 01:21:16.327119: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)
2021-07-28 01:21:16.695767: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11

הקוד לעיל ידפיס אינדיקציה לכך 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 בדוגמה זו) ובאופן אוטומטי להעתיק tensors בין התקנים במידת הצורך.

הגבלת צמיחת זיכרון GPU

כברירת מחדל, TensorFlow ממפה כמעט כל זיכרון GPU של כל GPUs (בכפוף CUDA_VISIBLE_DEVICES ) גלוי בתהליך. זה נעשה כדי להשתמש ביעילות רבה יותר במשאבי זיכרון ה- GPU היקרים יחסית במכשירים על ידי צמצום פיצול הזיכרון. כדי להגביל TensorFlow קבוצה ספציפית של GPUs, להשתמש tf.config.experimental.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.experimental.set_virtual_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 משותף עם יישומים אחרים כגון ממשק משתמש של תחנת עבודה.

שימוש ב- 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 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 MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

שימוש במספר GPUs

פיתוח עבור מספר GPUs יאפשר למודל להתמקד עם המשאבים הנוספים. אם אתה מתפתח במערכת עם GPU יחיד, אתה יכול לדמות מספר GPUs עם מכשירים וירטואליים. זה מאפשר בדיקה קלה של הגדרות מרובות 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

ברגע שיש GPUs הלוגי המרובה לרשות הריצה, אתה יכול לנצל את GPUs המרובה עם tf.distribute.Strategy או עם הצבה ידנית.

עם tf.distribute.Strategy

השיטה המומלצת באמצעות GPUs המרובה היא להשתמש 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))
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
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 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 Add 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 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 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 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 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 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. לדוגמה:

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 MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)