רשתות נוירונים מלאכותיות, עם Keras ומעבדי TPU

1. סקירה כללית

בשיעור ה-Lab הזה תלמדו איך להרכיב שכבה קונבולוציה למודל של רשת נוירונים שיכולה לזהות פרחים. הפעם תבנו את המודל בעצמכם ותשתמשו בעוצמה של TPU כדי לאמן אותו תוך שניות ולחזור על העיצוב שלו.

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

שיעור ה-Lab הזה הוא חלק 3 בסדרה 'Keras ב-TPU'. אפשר לבצע אותן בסדר הבא או בנפרד.

ca8cc21f6838eccc.png

מה תלמדו

  • כדי לפתח מסַווג תמונות קונבולוציה באמצעות מודל רצף Keras.
  • איך מארגנים אימון של מודל Keras ב-TPU
  • כדי לבצע כוונון עדין של המודל באמצעות בחירה טובה של שכבות עיבוד קוונטי.

משוב

אם תיתקלו בבעיה במעבדת הקוד הזו, נשמח לשמוע על כך. אפשר לשלוח משוב דרך בעיות ב-GitHub [קישור למשוב].

2. מדריך למתחילים ב-Google Colaboratory

הסדנה הזו מתבססת על Google Collaboratory ואין צורך לבצע הגדרות כלשהן. Colaboratory היא פלטפורמה של מחברת אונליין למטרות חינוכיות. התוכנית כוללת הכשרה בחינם לגבי מעבדים (CPU), מעבדי GPU ו-TPU.

688858c21e3beff2.png

אתם יכולים לפתוח את מסמך ה-notebook לדוגמה הזה ולעיין בכמה תאים כדי להכיר את Colaboratory.

c3df49e90e5a654f.png Welcome to Colab.ipynb

בחירת קצה עורפי של TPU

8832c6208c99687d.png

בתפריט Colab, בוחרים באפשרות סביבת זמן הריצה > שינוי הסוג של סביבת זמן הריצה ואז בוחרים באפשרות TPU. בשיעור ה-Lab הזה תלמדו איך להשתמש ב-TPU (יחידת עיבוד טרנספורמציות טילר) חזקה עם תמיכה באימון שמואץ בחומרה. החיבור לסביבת זמן הריצה יתבצע באופן אוטומטי בביצוע הראשון. אפשר גם ללחוץ על הלחצן Connect (התחברות) בפינה הימנית העליונה.

ביצוע Notebook

76d05caa8b4db6da.png

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

תוכן העניינים

429f106990037ec4.png

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

תאים מוסתרים

edc3dba45d26f12a.png

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

אימות

cdd4b41413100543.png

ל-Colab יש אפשרות לגשת לקטגוריות הפרטיות שלך ב-Google Cloud Storage בתנאי שביצעת אימות באמצעות חשבון מורשה. קטע הקוד שלמעלה יפעיל תהליך אימות.

3. [INFO] מהם מעבדי Tensor Processing Unit‏ (TPU)?

בקצרה

f88cf6facfc70166.png

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

688858c21e3beff2.png

למה דווקא מעבדי TPU?

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

8eb3e718b8e2ed08.png

איור: שכבה של רשת נוירונים צפופה ככפל של מטריצה, עם אצווה של שמונה תמונות שמעובדות דרך רשת הנוירונים בבת אחת. עליך לבצע כפל של שורה אחת x עמודה אחת כדי לוודא שבאמת מתבצעת סכימה משוקללת של כל ערכי הפיקסלים בתמונה. אפשר לייצג שכבות מתקפלות בתור הכפלות של מטריצות, אבל התהליך קצת יותר מורכב ( הסבר כאן, בסעיף 1).

החומרה

MXU ו-VPU

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

7d68944718f76b18.png

נקודה צפה (floating-point) מעורבת ו-bfloat16

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

19c5fc432840c714.png

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

לכן Google הציגה את הפורמט bfloat16 ב-TPUs.‏ 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, יהיה צורך ב-16,000 "ליבות" (128x128=16,000) שיהיו זמינות, וזה בדרך כלל לא אפשרי. למעבדי ה-GPU הגדולים ביותר יש כ-4,000 ליבות. מצד שני, TPU משתמש במינימום הנדרש של החומרה עבור יחידות המחשוב ב-MXU: רק bfloat16 x bfloat16 => float32 מכפילים, שום דבר אחר. היחידה הזו קטנה כל כך ש-TPU יכול להטמיע 16,000 יחידות כאלה ב-MXU בגודל 128x128 ולעבד את הכפלת המטריצות הזו בבת אחת.

f1b283fc45966717.gif

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

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

Cloud TPU

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

dfce5522ed644ece.png

איור: המכונה הווירטואלית עם מואץ Cloud TPU שמחובר לרשת. ‫'Cloud TPU' עצמו מורכב ממכונה וירטואלית עם לוח TPU שמחובר ל-PCI, עם ארבעה צ'יפים של TPU עם שני ליבות.

TPU pods

במרכזי הנתונים של Google, מערכות ה-TPU מחוברות לחיבור מחשוב בעל ביצועים גבוהים (HPC), שיכול לגרום להן להופיע כמאיץ אחד גדול מאוד. Google מכנה אותם pods, והם יכולים לכלול עד 512 ליבות TPU v2 או 2,048 ליבות TPU v3.

2ec1e0d341e7fc34.jpeg

איור: אשכול TPU v3. לוחות וכוורות של TPU שמחוברים דרך חיבור HPC.

במהלך האימון, הדרגתיות מוחלפת בין ליבות TPU באמצעות אלגוריתם הצמצום כולו ( הסבר טוב על ההפחתה המלאה) המודל שמאמנים יכול לנצל את היתרונות של החומרה על ידי אימון בקבוצות גדולות.

d97b9cc5d40fdb1d.gif

איור: סנכרון של שיפועים במהלך אימון באמצעות אלגוריתם all-reduce ברשת HPC של Google TPU עם רשת טורואידית דו-ממדית של רשתות.

התוכנה

הדרכה לקבוצות גדולות

גודל אצווה אידיאלי למעבדי TPU הוא 128 פריטי נתונים לכל ליבת TPU, אבל החומרה כבר יכולה להראות ניצול טוב מ-8 פריטי נתונים לכל ליבת TPU. חשוב לזכור של-Cloud TPU אחד יש 8 ליבות.

בשיעור ה-Lab הזה נשתמש ב-Keras API. ב-Keras, המקבץ שאתם מציינים הוא גודל האצווה הגלובלי של כל ה-TPU. האצוות יפוצלו אוטומטית ל-8 ויפעלו על 8 ליבות ה-TPU.

da534407825f01e3.png

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

טיפול יסודי: XLA

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

edce61112cd57972.png

איור: כדי לרוץ ב-TPU, תרשים החישוב שהוגדר על ידי תוכנית Tensorflow מתורגם קודם לייצוג XLA (מהידר אלגברה מואצת) ואז הידור באמצעות XLA לקוד מכונה של TPU.

שימוש במעבדי TPU ב-Keras

החל מ-Tensorflow 2.1 יש תמיכה במעבדי TPU דרך Keras API. התמיכה ב-Keras פועלת ב-TPU וב-TPU Pods. דוגמה שפועלת ב-TPU, ב-GPU וב-CPU:

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,‏ מכונות וירטואליות ללמידת עומק שנוצרו באמצעות הכלי 'ctpu up'). המערכות האלה יודעות איפה נמצא ה-TPU שלהן בזכות משתנה הסביבה TPU_NAME. אם יוצרים TPU באופן ידני, צריך להגדיר את משתנה הסביבה TPU_NAME ב-VM שבו משתמשים בו, או להפעיל את TPUClusterResolver עם פרמטרים מפורשים: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy הוא החלק שמיישם את ההתפלגות ואת האלגוריתם לסנכרון הדרגתי של "all-reduce".
  • האסטרטגיה חלה באמצעות היקף. המודל חייב להיות מוגדר בתוך ההיקף() של האסטרטגיה.
  • הפונקציה tpu_model.fit מצפה לאובייקט tf.data.Dataset כקלט לאימון TPU.

משימות נפוצות להעברת קוד ל-TPU

  • יש הרבה דרכים לטעון נתונים במודל Tensorflow, אבל ב-TPUs צריך להשתמש ב-tf.data.Dataset API.
  • TPUs הם מהירים מאוד, ולרוב צוואר הבקבוק בזמן ההרצה שלהם הוא הטמעת הנתונים. במדריך לביצועים של TPU מפורטים כלים שאפשר להשתמש בהם כדי לזהות צווארי בקבוק בנתונים וטיפים נוספים לשיפור הביצועים.
  • מספרים מסוג int8 או int16 נחשבים כ-int32. ל-TPU אין חומרה של מספרים שלמים שפועלת בפחות מ-32 ביט.
  • אין תמיכה בחלק מהפעולות של Tensorflow. הרשימה מופיעה כאן. החדשות הטובות הן שהמגבלה הזו חלה רק על קוד האימון, כלומר על המעבר קדימה ואחורה דרך המודל. עדיין תוכלו להשתמש בכל הפעולות של Tensorflow בצינור עיבוד הנתונים להזנת נתונים, כי הפעולות האלה יבוצעו ב-CPU.
  • tf.py_func לא נתמך ב-TPU.

4. [INFO] מבוא למסווגים של רשתות נוירונים

בקצרה

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

עבור מודלים שנוצרו כרצף של שכבות, Keras מציעה את Sequential API. לדוגמה, אפשר לכתוב ב-Keras סיווג תמונות באמצעות שלוש שכבות צפופות כך:

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
    tf.keras.layers.Dense(500, activation="relu"),
    tf.keras.layers.Dense(50, activation="relu"),
    tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])

# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy']) # % of correct answers

# train the model
model.fit(dataset, ... )

688858c21e3beff2.png

רשת נוירונים צפופה

זו רשת הנוירונים הפשוטה ביותר לסיווג תמונות. הוא עשוי מ"נוירונים" שמסודרים בשכבות. השכבה הראשונה מעבדת נתוני קלט ומזינה את הפלטים בשכבות אחרות. היא נקראת 'דחוס' כי כל נוירונים מחובר לכל נוירונים בשכבה הקודמת.

c21bae6dade487bc.png

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

נוירונים, הפעלות, RELU

'נוירון' מחשב סכום משוקלל של כל הקלט שלו, מוסיף ערך שנקרא 'הטיה' ומעביר את התוצאה דרך 'פונקציית הפעלה'. המשקולות וההטיה לא ידועים בהתחלה. הם יופעלו באופן אקראי ו"ילמדו" על ידי אימון רשת הנוירונים על הרבה נתונים ידועים.

644f4213a4ee70e5.png

פונקציית ההפעלה הפופולרית ביותר נקראת RELU עבור Rectified Linear Unit (יחידה לינארית מתוקנת). זוהי פונקציה פשוטה מאוד, כפי שאפשר לראות בתרשים שלמעלה.

הפעלה של Softmax

הרשת שלמעלה מסתיימת בשכבה של 5 נוירונים מכיוון שאנחנו מסווגים את הפרחים ל-5 קטגוריות (ורד, צבעוני, שן הארי, חיננית, חמנית). נוירונים בשכבות ביניים מופעלים באמצעות פונקציית ההפעלה הקלאסית של RELU. עם זאת, בשכבה האחרונה אנחנו רוצים לחשב מספרים בין 0 ל-1 שמייצגים את ההסתברות שהפרח הזה הוא ורד, צבעוני וכו'. לשם כך, נשתמש בפונקציית הפעלה שנקראת softmax.

אפשר להחיל softmax על וקטור

ef0d98c0952c262d.png d51252f75894479e.gif

הפסד חוצה-אנטרופיה

עכשיו, כשרשת העצבים שלנו מייצרת תחזיות מתמונות קלט, אנחנו צריכים למדוד את מידת הדיוק שלהן, כלומר את המרחק בין מה שהרשת אומרת לנו לבין התשובות הנכונות, שנקראות לרוב 'תוויות'. חשוב לזכור שיש לנו תוויות נכונות לכל התמונות במערך הנתונים.

כל מרחק יכול להתאים, אבל במקרה של בעיות סיווג, "מרחק באנטרופיה חוצה" הוא היעיל ביותר. נקרא לפונקציה הזו פונקציית השגיאה או פונקציית 'הפסד':

7bdf8753d20617fb.png

ירידה בגרדינט

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

ה-cross-entropy הוא פונקציה של משקולות, הטיות, פיקסלים של תמונת האימון והסיווג הידוע שלה.

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

הדרגתיות של ירידה2.png

קבוצות קטנות של בקשות ותגובה מהירה לשינויים

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

לשיטה הזו, שנקראת לפעמים "ירידה הדרגתית סטוכסטית", יש יתרון נוסף, פרגמטי יותר: עבודה עם אצוות פירושה גם עבודה עם מטריצות גדולות יותר, ובדרך כלל קל יותר לבצע אופטימיזציה שלהן במעבדי GPU ובמעבדי TPU.

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

52e824fe4716c4a0.png

איור: נקודת אוכף. שיפוע של 0, אבל הוא לא מינימום בכל הכיוונים. (שיוך תמונה Wikimedia: By Nicoguaro - Own work, CC BY 3.0)

הפתרון הוא להוסיף קצת תנע לאלגוריתם האופטימיזציה כדי שהוא יוכל לשוט מעבר לכל נקודות האופל בלי לעצור.

מילון מונחים

אצווה או מיני-אצווה: האימון תמיד מתבצע על קבוצות של נתוני אימון ותוויות. הפעולה הזו עוזרת לאלגוריתם להתמזג. המאפיין 'אצווה' הוא בדרך כלל המאפיין הראשון של מזנוני הנתונים. לדוגמה, טינסור בפורמט [100, 192, 192, 3] מכיל 100 תמונות בגודל 192x192 פיקסלים עם שלושה ערכים לכל פיקסל (RGB).

אובדן אנטרופי חוצה: פונקציית אובדן מיוחדת שמשמשת לרוב בסווגים.

שכבה צפופה: שכבה של נוירונים שבה כל נוירונים מחובר לכל נוירונים בשכבה הקודמת.

תכונות: ערכי הקלט של רשת נוירונים נקראים לפעמים 'תכונות'. היכולת להבין אילו חלקים של מערך נתונים (או שילובי חלקים) להזין ברשת נוירונים כדי לקבל תחזיות טובות נקראת 'הנדסת תכונות'.

labels: שם אחר ל'כיתות' או תשובות נכונות בבעיה של סיווג בפיקוח

שיעור הלמידה: חלק מהמדריגנט שבו משקולות ונטיות מועדכנים בכל חזרה של לולאת האימון.

logits: הפלט של שכבת תאי עצב לפני החלת פונקציית ההפעלה נקרא 'logits'. המונח מגיע מהפונקציה הלוגיסטית, שנקראת גם פונקציית sigmoid, שהייתה בעבר פונקציית ההפעלה הפופולרית ביותר. 'פלט נוירונים לפני פונקציה לוגיסטי' קוצר ל-'logits'.

loss (הפסד): פונקציית השגיאה שמשווה בין פלטי רשת נוירונים לתשובות הנכונות

נוירון: מחשב את הסכום המשוקלל של הקלט שלו, מוסיף הטיה ומעביר את התוצאה דרך פונקציית הפעלה.

קידוד one-hot: הכיתה 3 מתוך 5 מקודדת כוקטור של 5 רכיבים, כולם אפס מלבד הרכיב השלישי שהוא 1.

relu: יחידה לינארית מתוקנת. פונקציית הפעלה פופולרית לנוירונים.

sigmoid: פונקציית הפעלה נוספת שבעבר הייתה פופולרית ועדיין שימושית במקרים מיוחדים.

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

tensor: 'tensor' דומה למטריצה, אבל עם מספר שרירותי של מימדים. טינסור בעל מימד אחד הוא וקטור. מפריד דו-ממדי הוא מטריצה. לאחר מכן יכולים להיות רכיבי Tensor עם 3, 4, 5 או יותר מאפיינים.

5. [מידע חדש] רשתות נוירונים מלאכותיות (CNN)

בקצרה

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

convolutional.gif

איור: סינון תמונה באמצעות שני מסננים רצופים שמכילים 48 משקלים ללמידה בכל אחד מהם (4x4x3=48).

כך נראית רשת נוירונים מלאכותית פשוטה ב-Keras:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

688858c21e3beff2.png

מבוא לרשתות נוירונים מלאכותיות (CNN)

בשכבה של רשת נוירונים קונבולוציונית, "נוירון" אחד מבצע סכום משוקלל של הפיקסלים שמעליו, באזור קטן בתמונה בלבד. הוא מוסיף הטיה ומזין את הסכום באמצעות פונקציית הפעלה, בדיוק כמו שנירון בשכבה רגילה וצפיפות. לאחר מכן הפעולה הזו חוזרת על עצמה בכל התמונה תוך שימוש באותם משקלים. זכרו שבשכבות צפופות, לכל נוירון יש משקולות משלו. כאן, "תיקון" אחד של משקולות מחליק על התמונה בשני הכיוונים ("קובולציה"). הפלט כולל ערכים רבים ככל האפשר בתמונה (מספר הפיקסלים בתמונה (עם זאת, יש צורך במרווח פנימי מסוים בקצוות). זוהי פעולת סינון, שמשתמשת במסנן של 48 משקולות (4x4x3).

עם זאת, 48 משקלים לא יספיקו. כדי להוסיף עוד דרגות חופש, אנחנו חוזרים על אותה פעולה עם קבוצת משקולות חדשה. כך נוצרת קבוצה חדשה של תוצאות מסנן. נקרא לזה 'ערוץ' של פלטים באמצעות אנלוגיה עם ערוצי R,G,B בתמונת הקלט.

Screen Shot 2016-07-29 at 16.02.37.png

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

d1b557707bcd1cb9.png

איור: רשת נוירונים מלאכותית (CNN) ממירה 'קוביות' של נתונים ל'קוביות' אחרות של נתונים.

קיפולים (קונבולציות) עם צעד, יצירת מאגרים מקסימליים

ביצוע המצטברים עם צעד של 2 או 3 מאפשר גם לכווץ את קוביית הנתונים שמתקבלת בממדים האופקיים שלה. יש שתי דרכים נפוצות לעשות זאת:

  • עיבוד נתונים סטריידי (Strided convolution): מסנן הזזה כמו למעלה, אבל עם צעד (stride) גדול מ-1
  • קיבוץ מקסימלי: חלון הזזה שמבצע את הפעולה MAX (בדרך כלל בתיקונים בגודל 2x2, שחוזר על עצמו כל 2 פיקסלים)

2b2d4263bb8470b.gif

איור: החלקת חלון המחשוב ב-3 פיקסלים תוביל לפחות ערכי פלט. עיבוד נתונים בשיטת Strided convolution או שיטת Max pooling (max בחלון 2x2 שנע בצעדים של 2) הם דרכים לצמצום של קוביית הנתונים במאפיינים האופקיים.

מסנן קונבולוציה

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

4a61aaffb6cba3d1.png

איור: סיווג תמונות באמצעות שכבות convolutional ו-softmax. הוא משתמש במסננים בגודל 3x3 ובגודל 1x1. השכבות של maxpool מחשבות את הערך המקסימלי של קבוצות של נקודות נתונים בגודל 2x2. 'הראש' של הסיווג מיושם באמצעות שכבה צפופה עם הפעלה של softmax.

ב-Keras

אפשר לכתוב ב-Keras את הערימה המתקפלת שמתוארת למעלה כך:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)    
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

6. המרה מותאמת אישית

הדרכה מעשית

נלמד איך יוצרים ומאמנים רשת נוירונים מלאכותית (CNN) מאפס. השימוש ב-TPU יאפשר לנו לבצע איטרציות במהירות רבה. עליך לפתוח את ה-notebook הבא, להריץ את התאים (Shift-ENTER) ולפעול לפי ההוראות בכל מקום שבו מופיעה התווית 'נדרשת עבודה'.

c3df49e90e5a654f.png Keras_Flowers_TPU (playground).ipynb

המטרה היא לשפר את רמת הדיוק של 75% של מודל למידת ההעברה. למודל הזה יש יתרון: הוא עבר אימון מראש על מערך נתונים של מיליוני תמונות, ויש לנו כאן רק תמונות ב-3670. האם תוכלו לפחות להתאים אותה?

מידע נוסף

כמה שכבות, מה הגודל?

בחירת גודל השכבות היא יותר אומנות מאשר מדע. צריך למצוא את האיזון הנכון בין שימוש בפחות מדי פרמטרים לבין יותר מדי פרמטרים (משקולות והטיות). אם יש מעט מדי משקולות, רשת העצבים לא יכולה לייצג את המורכבות של צורות הפרחים. אם יש יותר מדי תמונות, המערכת עלולה להיכנס למצב של 'התאמה יתר', כלומר התמקדות בתמונות האימון ואי יכולת להכליל. יש הרבה פרמטרים, לכן גם אימון המודל יהיה איטי. ב-Keras, הפונקציה model.summary() מציגה את המבנה ואת ספירת הפרמטרים של המודל שלכם:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 192, 192, 16)      448       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 192, 192, 30)      4350      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 96, 96, 30)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 96, 96, 60)        16260     
_________________________________________________________________
 ... 
_________________________________________________________________
global_average_pooling2d (Gl (None, 130)               0         
_________________________________________________________________
dense (Dense)                (None, 90)                11790     
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 455       
=================================================================
Total params: 300,033
Trainable params: 300,033
Non-trainable params: 0
_________________________________________________________________

כמה טיפים:

  • שכבות מרובות הן מה שהופך רשתות נוירונים "עמוקות" ליעילות. לפתרון הבעיה הפשוטה הזו של זיהוי פרחים, מומלץ להוסיף 5 עד 10 שכבות.
  • להשתמש במסננים קטנים. בדרך כלל, מסננים בגודל 3x3 מתאימים בכל מקום.
  • אפשר גם להשתמש במסננים בגודל 1x1, והם זולים. הם לא באמת 'מסננים' שום דבר, אלא מחשבים שילובים לינאריים של ערוצים. כדאי להחליף אותם במסננים אמיתיים. (מידע נוסף על "קונבולציות של 1x1" מופיע בקטע הבא).
  • במקרה של בעיית סיווג כזו, מומלץ להוריד את הדגימה בתדירות גבוהה באמצעות שכבות מאגר מקסימלי (או קונבולוציות עם צעדים >1). לא מעניין אתכם איפה נמצא הפרח, אלא רק אם מדובר בשושנה או בשן-ארי, ולכן אובדן המידע על הקואורדינטות X ו-Y לא חשוב, וסינון של אזורים קטנים יותר זול יותר.
  • מספר המסננים בדרך כלל דומה למספר המחלקות בסוף הרשת (למה? ראה למטה הטריק "מאגר ממוצע גלובלי"). אם אתם מסווגים את התמונות למאות כיתות, מומלץ להגדיל את מספר המסננים באופן פרוגרסיבי בשכבות עוקבות. במערך הנתונים של הפרחים עם 5 כיתות, סינון באמצעות 5 מסננים בלבד לא יספיק. אפשר להשתמש באותו מספר מסננים ברוב השכבות, למשל 32, ולהקטין אותו לקראת הסוף.
  • השכבות הדחוסות הסופיות יקרות. יכול להיות שיש להם יותר משקלים מאשר לכל שכבות הקוונטילציה יחד. לדוגמה, גם עם פלט סביר מאוד מקובץ הנתונים האחרון של 24x24x10 נקודות נתונים, שכבה צפופה של 100 נוירונים תעלה 24x24x10x100=576,000 משקלים!!! כדאי לחשוב על זה, או לנסות את ה-global average pooling (ראו בהמשך).

מאגר ממוצע גלובלי

במקום להשתמש בשכבה צפופה יקרה בקצה של רשת עצבית מתקפלת, אתם יכולים לפצל את ה'קובייה' של הנתונים הנכנסים לכמה חלקים ככל שיש לכם מחלקות, לחשב ממוצע של הערכים שלהם ולהזין אותם באמצעות פונקציית הפעלה מסוג softmax. הדרך הזו לבניית 'הראש' של הסיווג לא כוללת עלות של משקולות. ב-Keras, התחביר הוא tf.keras.layers.GlobalAveragePooling2D().

93240029f59df7c2.png

פתרון

כאן מופיע מסמך הפתרון. אפשר להשתמש בו אם נתקעת.

c3df49e90e5a654f.png Keras_Flowers_TPU (solution).ipynb

אילו נושאים דיברנו?

  • 🤔 שיחקתי עם שכבות עיבוד קוונטי
  • 🤓 התנסות באיסוף מקסימום, צעדים, קיבוץ ממוצע עולמי, ...
  • 😀 ביצענו חזרה על מודלים בעולם האמיתי במהירות, באמצעות TPU

כדאי להקדיש כמה רגעים כדי לעבור בראש את רשימת המשימות הזו.

7. מעולה!

יצרתם את רשת העצבים הקוונטית המודרנית הראשונה שלכם, אימנתם אותה לרמת דיוק של יותר מ-80% וביצעתם שינויים בארכיטקטורה שלה תוך דקות ספורות, בזכות מעבדי ה-TPU. מומלץ להמשיך לשיעור ה-Lab הבא כדי ללמוד על ארכיטקטורות נוירוניות מודרניות:

מעבדי TPU בפועל

מעבדי TPU ומעבדי GPU זמינים ב-Cloud AI Platform:

לבסוף, אנחנו אוהבים לקבל משוב. אם משהו לא נראה תקין בסדנה הזו או אם לדעתכם יש מקום לשיפור, נשמח לשמוע מכם. אפשר לשלוח משוב דרך 'בעיות ב-GitHub' [feedback link].

HR.png

Martin Görner ID small.jpg
המחבר: מרטין גורנר (Martin Görner)
Twitter: ‎@martin_gorner

tensorflow logo.jpg
www.tensorflow.org