השתמש ב- GPU

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

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

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

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

להכין

ודא שמותקנת אצלך את המהדורה האחרונה של TensorFlow gpu.

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" : המעבד של המחשב שלך.
  • "/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, במערכת עם התקנים 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 בדוגמה זו) ויעתיק אוטומטית טנסורים בין מכשירים במידת הצורך.

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

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

שימוש במספר 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))
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. לדוגמה:

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)