עזרה להגן על שונית המחסום הגדולה עם TensorFlow על Kaggle הצטרפו אתגר

השתמש ב- GPU

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

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

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

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

להכין

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

הגבלת צמיחת זיכרון 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)