1. סקירה כללית
יחידות TPU הן מהירות מאוד. הזרם של נתוני האימון צריך להתאים למהירות האימון. בשיעור ה-Lab הזה תלמדו איך לטעון נתונים מ-GCS באמצעות tf.data.Dataset API כדי להזין אותם ל-TPU.
שיעור ה-Lab הזה הוא חלק 1 בסדרה Keras on TPU. אפשר לבצע אותן בסדר הבא או בנפרד.
- [הסדנה הזו] צינורות עיבוד נתונים במהירות TPU: tf.data.Dataset ו-TFRecords
- המודל הראשון של Keras, עם למידת העברה
- רשתות נוירונים מתקפלות, עם Keras ו-TPU
- רשתות עצביות קונבולוציוניות מודרניות, squeezenet, Xception, עם Keras ו-TPU

מה תלמדו
- כדי להשתמש ב-tf.data.Dataset API לטעינת נתוני אימון
- שימוש בפורמט TFRecord כדי לטעון נתוני אימון ביעילות מ-GCS
משוב
אם נתקלתם בבעיה כלשהי ב-Code Lab הזה, נשמח לשמוע על כך. אפשר לשלוח משוב דרך הבעיות ב-GitHub [ קישור למשוב].
2. מדריך למתחילים ב-Google Colaboratory
ב-Lab הזה נעשה שימוש ב-Google Collaboratory, ולא נדרשת הגדרה מצדכם. Colaboratory היא פלטפורמת מחברות אונליין למטרות חינוכיות. הוא מציע הדרכה בחינם בנושא CPU, GPU ו-TPU.

אתם יכולים לפתוח את מחברת הדוגמה הזו ולהריץ כמה תאים כדי להכיר את Colaboratory.
בחירת TPU backend

בתפריט Colab, בוחרים באפשרות Runtime > Change runtime type (זמן ריצה > שינוי הסוג של זמן הריצה) ואז בוחרים באפשרות TPU. בשיעור ה-Lab הזה תשתמשו ב-TPU (Tensor Processing Unit) עוצמתי שמגובה באימון מואץ באמצעות חומרה. החיבור לסביבת זמן הריצה יתבצע באופן אוטומטי בהרצה הראשונה, או שתוכלו להשתמש בלחצן 'Connect' בפינה השמאלית העליונה.
הרצת Notebook

מריצים כל תא בנפרד על ידי לחיצה על תא והקשה על Shift-ENTER. אפשר גם להריץ את כל ה-notebook באמצעות סביבת זמן הריצה > הפעלת הכול.
תוכן העניינים

לכל מחברת יש תוכן עניינים. אפשר לפתוח אותו באמצעות החץ השחור שמימין.
תאים מוסתרים

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

אם תבצעו אימות באמצעות חשבון מורשה, תוכלו לגשת ב-Colab לקטגוריות הפרטיות שלכם ב-Google Cloud Storage. קטע הקוד שלמעלה יפעיל תהליך אימות.
3. [INFO] מהם Tensor Processing Units (TPUs)?
על קצה המזלג

הקוד לאימון מודל ב-TPU ב-Keras (עם חזרה ל-GPU או ל-CPU אם TPU לא זמין):
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
אנחנו נשתמש היום ב-TPU כדי לבנות ולבצע אופטימיזציה של מסווג פרחים במהירויות אינטראקטיביות (דקות לכל הרצת אימון).

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

איור: שכבת רשת נוירונים צפופה כהכפלה של מטריצה, עם אצווה של שמונה תמונות שעוברות עיבוד ברשת הנוירונים בו-זמנית. כדאי לבצע כפל של שורה אחת בעמודה אחת כדי לוודא שהפעולה היא אכן סכום משוקלל של כל ערכי הפיקסלים של תמונה. אפשר לייצג שכבות קונבולוציה גם כמכפלות מטריצות, אבל זה קצת יותר מסובך ( הסבר כאן, בקטע 1).
החומרה
MXU ו-VPU
ליבת TPU v2 מורכבת מיחידת כפל מטריצות (MXU) שמבצעת כפל מטריצות, ומיחידת עיבוד וקטורי (VPU) לכל שאר המשימות, כמו הפעלות, softmax וכו'. יחידת ה-VPU מטפלת בחישובים של float32 ו-int32. לעומת זאת, ה-MXU פועל בפורמט נקודה צפה (floating point) של 16-32 ביט עם דיוק מעורב.

נקודה צפה עם דיוק מעורב ו-bfloat16
ה-MXU מחשב מכפלות מטריצות באמצעות קלט bfloat16 ופלט float32. הצבירות הביניים מתבצעות בדיוק float32.

בדרך כלל, אימון של רשת נוירונים עמיד לרעשי רקע שנוצרים כתוצאה מדיוק מופחת של נקודה צפה. יש מקרים שבהם רעשי רקע אפילו עוזרים לכלי האופטימיזציה להגיע לפתרון. באופן מסורתי, נעשה שימוש בדיוק של נקודה צפה של 16 ביט כדי להאיץ חישובים, אבל לפורמטים float16 ו-float32 יש טווחים שונים מאוד. הפחתת הדיוק מ-float32 ל-float16 בדרך כלל מובילה לערכי הצפה (overflow) וערכי חוסר (underflow). יש פתרונות, אבל בדרך כלל נדרשת עבודה נוספת כדי להשתמש ב-float16.
לכן Google הציגה את הפורמט bfloat16 ב-TPU. bfloat16 הוא float32 קטום עם אותם ביטים של מעריך ואותו טווח כמו float32. בנוסף, יחידות ה-TPU מבצעות חישובי מטריצות כפל בדיוק מעורב עם נתוני קלט מסוג bfloat16 ונתוני פלט מסוג float32. לכן, בדרך כלל לא צריך לשנות את הקוד כדי ליהנות משיפורי הביצועים שמתקבלים מדיוק מופחת.
מערך סיסטולי
ה-MXU מבצע כפל מטריצות בחומרה באמצעות ארכיטקטורה שנקראת 'מערך סיסטולי', שבה רכיבי נתונים זורמים דרך מערך של יחידות חישוב בחומרה. (במונח 'סיסטולי' ברפואה מתייחסים להתכווצויות הלב ולזרימת הדם, וכאן לזרימת הנתונים).
הפעולה הבסיסית במכפלת מטריצות היא מכפלה סקלרית בין שורה ממטריצה אחת לבין עמודה מהמטריצה השנייה (ראו את האיור בראש הקטע הזה). עבור הכפלת מטריצות Y=X*W, רכיב אחד של התוצאה יהיה:
Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]
ב-GPU, מתכנתים את המכפלה הסקלרית הזו ב'ליבה' של ה-GPU, ואז מריצים אותה על כמה שיותר 'ליבות' במקביל כדי לנסות לחשב את כל הערכים של המטריצה שמתקבלת בבת אחת. אם המטריצה שמתקבלת היא בגודל 128x128, יידרשו 128x128=16K ליבות זמינות, וזה בדרך כלל לא אפשרי. במעבדי ה-GPU הגדולים ביותר יש כ-4,000 ליבות. לעומת זאת, TPU משתמש במינימום הנדרש של חומרה ליחידות החישוב ב-MXU: רק bfloat16 x bfloat16 => float32 יחידות כפל-צבירה, שום דבר אחר. הן כל כך קטנות, עד שאפשר להטמיע 16K מהן ב-MXU בגודל 128x128 ולעבד את הכפלת המטריצות הזו בבת אחת.

איור: מערך סיסטולי של MXU. רכיבי החישוב הם יחידות של מכפלה וצבירה. הערכים של מטריצה אחת נטענים למערך (הנקודות האדומות). הערכים של המטריצה האחרת עוברים דרך המערך (הנקודות האפורות). הקווים האנכיים מעבירים את הערכים למעלה. הקווים האופקיים מעבירים סכומים חלקיים. המשתמש צריך לוודא שכשהנתונים זורמים דרך המערך, התוצאה של הכפלת המטריצה יוצאת מהצד הימני.
בנוסף, בזמן החישוב של המכפלות הסקלריות ב-MXU, סכומי הביניים פשוט עוברים בין יחידות חישוב סמוכות. אין צורך לאחסן אותם ולאחזר אותם מהזיכרון או מקובץ רישום. התוצאה הסופית היא שלארכיטקטורת המערך הסיסטולי של TPU יש יתרון משמעותי בצפיפות ובצריכת החשמל, וגם יתרון במהירות שלא ניתן להתעלם ממנו בהשוואה ל-GPU, כשמחשבים מכפלות מטריצות.
Cloud TPU
כשמבקשים Cloud TPU v2 אחד ב-Google Cloud Platform, מקבלים מכונה וירטואלית (VM) עם לוח TPU שמחובר ל-PCI. לוח ה-TPU כולל ארבעה שבבי TPU עם ליבה כפולה. כל ליבת TPU כוללת VPU (יחידת עיבוד וקטורי) ו-MXU (יחידת כפל מטריצות) בגודל 128x128. לאחר מכן, ה-Cloud TPU הזה בדרך כלל מחובר דרך הרשת ל-VM שביקש אותו. כך נראה התמונה המלאה:

איור: המכונה הווירטואלית עם מאיץ Cloud TPU שמחובר לרשת. "Cloud TPU" עצמו מורכב ממכונה וירטואלית עם לוח TPU שמחובר ל-PCI, עם ארבעה שבבי TPU בעלי ליבה כפולה.
TPU pods
במרכזי הנתונים של Google, יחידות ה-TPU מחוברות לחיבור הדדי (interconnect) של מחשוב עתיר ביצועים (HPC), שיכול לגרום להן להיראות כמאיץ גדול מאוד. Google קוראת להם pods, והם יכולים לכלול עד 512 ליבות TPU v2 או 2048 ליבות TPU v3.

איור: אשכול TPU v3 Pod. לוחות ומתלים של TPU שמחוברים באמצעות HPC interconnect.
במהלך האימון, הגרדיאנטים מועברים בין ליבות ה-TPU באמצעות אלגוריתם all-reduce ( הסבר טוב על all-reduce זמין כאן). המודל שעובר אימון יכול לנצל את היתרונות של החומרה על ידי אימון על גדלים גדולים של אצווה.

איור: סנכרון של גרדיאנטים במהלך אימון באמצעות אלגוריתם all-reduce ברשת HPC של רשת טורואידית דו-ממדית של Google TPU.
התוכנה
אימון עם גודל אצווה גדול
גודל האצווה האידיאלי ל-TPU הוא 128 פריטי נתונים לכל ליבת TPU, אבל אפשר להשיג ניצול טוב של החומרה כבר מ-8 פריטי נתונים לכל ליבת TPU. חשוב לזכור שלכל Cloud TPU יש 8 ליבות.
בשיעור ה-Lab הזה נשתמש ב-Keras API. ב-Keras, גודל הקבוצה שאתם מציינים הוא גודל הקבוצה הגלובלי לכל ה-TPU. הקבוצות יפוצלו אוטומטית ל-8 ויפעלו על 8 ליבות ה-TPU.

טיפים נוספים לשיפור הביצועים מפורטים במדריך לשיפור הביצועים של TPU. במקרים של גודל אצווה גדול מאוד, יכול להיות שיהיה צורך בטיפול מיוחד בחלק מהמודלים. פרטים נוספים זמינים במאמר בנושא LARSOptimizer.
הפרטים הטכניים: XLA
תוכניות Tensorflow מגדירות גרפים של חישובים. ה-TPU לא מריץ קוד Python ישירות, אלא מריץ את גרף החישוב שמוגדר על ידי תוכנית TensorFlow. מתחת לפני השטח, קומפיילר בשם XLA (קומפיילר מואץ של אלגברה לינארית) הופך את גרף Tensorflow של צמתי החישוב לשפת מכונה של TPU. הקומפיילר הזה גם מבצע אופטימיזציות מתקדמות רבות בקוד ובפריסת הזיכרון. הקומפילציה מתבצעת אוטומטית כשהעבודה נשלחת ל-TPU. אין צורך לכלול את XLA בשרשרת הבנייה באופן מפורש.

איור: כדי להריץ ב-TPU, תרשים החישוב שמוגדר בתוכנית Tensorflow מתורגם קודם לייצוג XLA (מהדר אלגברה לינארית מואצת), ואז עובר קומפילציה על ידי XLA לשפת מכונה של TPU.
שימוש במעבדי TPU ב-Keras
החל מ-Tensorflow 2.1, יש תמיכה ב-TPU דרך Keras API. התמיכה ב-Keras פועלת במעבדי TPU וב-TPU pods. דוגמה שפועלת ב-TPU, במעבד גרפי ובמעבד:
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
בקטע הקוד הזה:
-
TPUClusterResolver().connect()מאתר את ה-TPU ברשת. הוא פועל ללא פרמטרים ברוב המערכות של Google Cloud (משימות של AI Platform, Colaboratory, Kubeflow, מכונות וירטואליות של Deep Learning שנוצרו באמצעות כלי השירות ctpu up). המערכות האלה יודעות איפה נמצא ה-TPU שלהן בזכות משתנה הסביבה TPU_NAME. אם יוצרים TPU באופן ידני, צריך להגדיר את משתנה הסביבה TPU_NAME במכונה הווירטואלית שבה משתמשים בו, או לקרוא ל-TPUClusterResolverעם פרמטרים מפורשים:TPUClusterResolver(tp_uname, zone, project) -
TPUStrategyהוא החלק שמיישם את ההפצה ואת האלגוריתם של סנכרון הגרדיאנטים 'all-reduce'. - האסטרטגיה מוחלת באמצעות היקף. צריך להגדיר את המודל בתוך היקף האסטרטגיה scope().
- הפונקציה
tpu_model.fitמצפה לקבל אובייקט tf.data.Dataset כקלט לאימון TPU.
משימות נפוצות להעברת קוד ל-TPU
- יש הרבה דרכים לטעון נתונים במודל Tensorflow, אבל כשמשתמשים ב-TPU, חובה להשתמש ב-
tf.data.DatasetAPI. - יחידות TPU הן מהירות מאוד, והטמעת נתונים הופכת לעיתים לצוואר הבקבוק כשמריצים עליהן נתונים. במדריך הביצועים של TPU יש כלים שיעזרו לכם לזהות צווארי בקבוק בנתונים וטיפים נוספים לשיפור הביצועים.
- מספרים מסוג int8 או int16 נחשבים למספרים מסוג int32. ל-TPU אין חומרה של מספרים שלמים שפועלת על פחות מ-32 ביט.
- חלק מהפעולות של TensorFlow לא נתמכות. הרשימה זמינה כאן. החדשות הטובות הן שהמגבלה הזו חלה רק על קוד האימון, כלומר על המעבר קדימה ואחורה דרך המודל. עדיין אפשר להשתמש בכל הפעולות של TensorFlow בצינור להזנת נתונים, כי הן יבוצעו במעבד (CPU).
- אין תמיכה ב-
tf.py_funcב-TPU.
4. טעינת נתונים

נשתמש במערך נתונים של תמונות פרחים. המטרה היא ללמוד איך לסווג אותם ל-5 סוגי פרחים. טעינת הנתונים מתבצעת באמצעות tf.data.Dataset API. קודם כל, נכיר את ה-API.
מעשי
צריך לפתוח את ה-notebook הבא, להריץ את התאים (Shift-ENTER) ולפעול לפי ההוראות בכל מקום שבו מופיעה התווית WORK REQUIRED (נדרשת עבודה).
Fun with tf.data.Dataset (playground).ipynb
מידע נוסף
מידע על מערך הנתונים 'פרחים'
מערך הנתונים מאורגן ב-5 תיקיות. כל תיקייה מכילה פרחים מסוג אחד. שמות התיקיות הם חמניות, חינניות, שן הארי, צבעונים ושושנים. הנתונים מתארחים בקטגוריה ציבורית ב-Google Cloud Storage. קטע:
gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg
למה tf.data.Dataset?
Keras ו-Tensorflow מקבלים מערכי נתונים בכל פונקציות האימון וההערכה שלהם. אחרי שמעלים נתונים למערך נתונים, ה-API מציע את כל הפונקציות הנפוצות ששימושיות לנתוני אימון של רשת נוירונים:
dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training
במאמר הזה מפורטים טיפים לשיפור הביצועים ושיטות מומלצות לשימוש בקבוצות נתונים. מאמרי העזרה זמינים כאן.
היסודות של tf.data.Dataset
הנתונים מגיעים בדרך כלל בכמה קבצים, כמו תמונות. אפשר ליצור מערך נתונים של שמות קבצים באמצעות הקריאה:
filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.
לאחר מכן, 'ממפים' פונקציה לכל שם קובץ, שבדרך כלל תטען ותפענח את הקובץ לנתונים בפועל בזיכרון:
def decode_jpeg(filename):
bits = tf.io.read_file(filename)
image = tf.io.decode_jpeg(bits)
return image
image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)
כדי לבצע איטרציה על מערך נתונים:
for data in my_dataset:
print(data)
מערכי נתונים של טאפלים
בלמידה מונחית, מערך נתוני האימון מורכב בדרך כלל מזוגות של נתוני אימון ותשובות נכונות. כדי לאפשר זאת, פונקציית הפענוח יכולה להחזיר טאפלים. לאחר מכן תקבלו מערך נתונים של טאפלים, והטאפלים יוחזרו כשמבצעים איטרציה על המערך. הערכים שמוחזרים הם טנסורים של TensorFlow שמוכנים לשימוש במודל שלכם. אפשר לקרוא ל-.numpy() כדי לראות את הערכים הגולמיים:
def decode_jpeg_and_label(filename):
bits = tf.read_file(filename)
image = tf.io.decode_jpeg(bits)
label = ... # extract flower name from folder name
return image, label
image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs
for image, label in dataset:
print(image.numpy().shape, label.numpy())
מסקנה:טעינת תמונות אחת אחרי השנייה היא איטית!
במהלך האיטרציה על מערך הנתונים הזה, תראו שאפשר לטעון בערך תמונה אחת או שתיים בשנייה. זה איטי מדי! מאיצי החומרה שבהם נשתמש לאימון יכולים לשמור על קצב גבוה פי כמה. בקטע הבא מוסבר איך נשיג את זה.
המוצר
מחברת הפתרון אתם יכולים להשתמש בו אם אתם נתקעים.
Fun with tf.data.Dataset (solution).ipynb
מה נכלל
- 🤔 tf.data.Dataset.list_files
- 🤔 tf.data.Dataset.map
- 🤔 מערכי נתונים של טאפלים
- 😀 iterating through Datasets
כדאי להקדיש רגע כדי לעבור על רשימת המשימות הבאה.
5. טעינת נתונים במהירות
מאיצי החומרה של Tensor Processing Unit (TPU) שבהם נשתמש בשיעור ה-Lab הזה הם מהירים מאוד. האתגר הוא בדרך כלל לספק להם נתונים מספיק מהר כדי שהם יהיו עסוקים. ל-Google Cloud Storage (GCS) יש יכולת לשמור על קצב העברה גבוה מאוד, אבל כמו בכל מערכות אחסון בענן, יצירת חיבור כרוכה בהעברת נתונים הלוך ושוב ברשת. לכן, אחסון הנתונים שלנו באלפי קבצים נפרדים הוא לא אידיאלי. נאגד אותם למספר קטן יותר של קבצים ונשתמש ביכולות של tf.data.Dataset כדי לקרוא מכמה קבצים במקביל.
קריאה ראשונה
הקוד שמעמיס קובצי תמונה, משנה את הגודל שלהם לגודל משותף ואז מאחסן אותם ב-16 קובצי TFRecord מופיע במחברת הבאה. כדאי לקרוא אותו במהירות. אין צורך להריץ את הפקודה הזו כי נספק נתונים בפורמט TFRecord תקין בהמשך ה-codelab.
Flower pictures to TFRecords.ipynb
פריסת נתונים אידיאלית להעברת נתונים אופטימלית ב-GCS
פורמט הקובץ TFRecord
פורמט הקובץ המועדף של TensorFlow לאחסון נתונים הוא פורמט TFRecord שמבוסס על protobuf. פורמטים אחרים של סריאליזציה יעבדו גם כן, אבל אפשר לטעון מערך נתונים מקובצי TFRecord ישירות על ידי כתיבת:
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
כדי לשפר את הביצועים, מומלץ להשתמש בקוד המורכב הבא כדי לקרוא מכמה קובצי TFRecord בו-זמנית. הקוד הזה יקרא מ-N קבצים במקביל ויתעלם מסדר הנתונים כדי להגדיל את מהירות הקריאה.
AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
מדריך מקוצר לשימוש ב-TFRecord
אפשר לאחסן ב-TFRecords שלושה סוגי נתונים: מחרוזות בייטים (רשימה של בייטים), מספרים שלמים של 64 ביט ומספרים עשרוניים של 32 ביט. הם תמיד מאוחסנים כרשימות, ורכיב נתונים יחיד יהיה רשימה בגודל 1. אפשר להשתמש בפונקציות העזר הבאות כדי לאחסן נתונים ב-TFRecords.
כתיבת מחרוזות בייט
# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))
כתיבת מספרים שלמים
def _int_feature(list_of_ints): # int64
return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))
כתיבת צפים
def _float_feature(list_of_floats): # float32
return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))
כתיבת TFRecord באמצעות כלי העזר שלמעלה
# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
feature = {
"image": _bytestring_feature([my_img_bytes]), # one image in the list
"class": _int_feature([my_class]), # one class in the list
"size": _int_feature([my_height, my_width]), # fixed length (2) list of ints
"float_data": _float_feature(my_floats) # variable length list of floats
}
tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
out_file.write(tf_record.SerializeToString())
כדי לקרוא נתונים מ-TFRecords, צריך קודם להצהיר על הפריסה של הרשומות ששמרתם. בהצהרה, אפשר לגשת לכל שדה עם שם כרשימה באורך קבוע או כרשימה באורך משתנה:
קריאה מ-TFRecords
def read_tfrecord(data):
features = {
# tf.string = byte string (not text string)
"image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
"class": tf.io.FixedLenFeature([], tf.int64), # shape [] means scalar, i.e. a single item
"size": tf.io.FixedLenFeature([2], tf.int64), # two integers
"float_data": tf.io.VarLenFeature(tf.float32) # a variable number of floats
}
# decode the TFRecord
tf_record = tf.io.parse_single_example(data, features)
# FixedLenFeature fields are now ready to use
sz = tf_record['size']
# Typical code for decoding compressed images
image = tf.io.decode_jpeg(tf_record['image'], channels=3)
# VarLenFeature fields require additional sparse.to_dense decoding
float_data = tf.sparse.to_dense(tf_record['float_data'])
return image, sz, float_data
# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)
קטעי קוד שימושיים:
קריאת רכיבי נתונים בודדים
tf.io.FixedLenFeature([], tf.string) # for one byte string
tf.io.FixedLenFeature([], tf.int64) # for one int
tf.io.FixedLenFeature([], tf.float32) # for one float
קריאה של רשימות של רכיבים בגודל קבוע
tf.io.FixedLenFeature([N], tf.string) # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64) # list of N ints
tf.io.FixedLenFeature([N], tf.float32) # list of N floats
קריאה של מספר משתנה של פריטי נתונים
tf.io.VarLenFeature(tf.string) # list of byte strings
tf.io.VarLenFeature(tf.int64) # list of ints
tf.io.VarLenFeature(tf.float32) # list of floats
VarLenFeature מחזיר וקטור דליל, ונדרש שלב נוסף אחרי פענוח ה-TFRecord:
dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])
אפשר גם להשתמש בשדות אופציונליים ב-TFRecords. אם מציינים ערך ברירת מחדל כשקוראים שדה, ערך ברירת המחדל מוחזר במקום שגיאה אם השדה חסר.
tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional
מה נכלל
- 🤔 פיצול קובצי נתונים כדי לאפשר גישה מהירה מ-GCS
- 😓 איך לכתוב TFRecords. (שכחת את התחביר? זה בסדר, אפשר להוסיף את הדף הזה לסימניות כדף עזר)
- 🤔 טעינת מערך נתונים מ-TFRecords באמצעות TFRecordDataset
כדאי להקדיש רגע כדי לעבור על רשימת המשימות הבאה.
6. מעולה!
עכשיו אפשר להזין נתונים ל-TPU. צריך להמשיך לשיעור ה-Lab הבא
- [הסדנה הזו] צינורות עיבוד נתונים במהירות TPU: tf.data.Dataset ו-TFRecords
- המודל הראשון של Keras, עם למידת העברה
- רשתות נוירונים מתקפלות, עם Keras ו-TPU
- רשתות עצביות קונבולוציוניות מודרניות, squeezenet, Xception, עם Keras ו-TPU
מעבדי TPU בפועל
מעבדי TPU ו-GPU זמינים ב-Cloud AI Platform:
- ב-Deep Learning VMs
- ב-AI Platform Notebooks
- במשימות של AI Platform Training
בסופו של דבר, נשמח לקבל משוב. נשמח לדעת אם משהו לא בסדר בשיעור ה-Lab הזה או אם יש לך רעיונות לשיפור. אפשר לשלוח משוב דרך הבעיות ב-GitHub [ קישור למשוב].

|
|

