TensorFlow, Keras ולמידה עמוקה (Deep Learning), ללא דוקטורט

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

המדריך הזה עודכן לגרסה 2.2 של Tensorflow!

74f6fbd758bf19e6.png

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

ב-Codelab הזה נשתמש במערך הנתונים MNIST, אוסף של 60,000 ספרות מתויגות שהעסיק דורות של דוקטורנטים במשך כמעט שני עשורים. תפתרו את הבעיה עם פחות מ-100 שורות של קוד Python / TensorFlow.

מה תלמדו

  • מהי רשת נוירונים ואיך מאמנים אותה
  • איך לבנות רשת נוירונים בסיסית עם שכבה אחת באמצעות tf.keras
  • איך מוסיפים עוד שכבות
  • איך מגדירים תזמון של קצב למידה
  • איך בונים רשתות נוירונים מלאכותיות (CNN)
  • איך משתמשים בטכניקות רגולריזציה: dropout, ‏ batch normalization
  • מהי התאמת יתר (overfitting)

הדרישות

רק דפדפן. אפשר להשתמש ב-Google Colaboratory כדי להשתתף בסדנה הזו.

משוב

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

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

ב-Lab הזה נעשה שימוש ב-Google Colaboratory, ולא נדרשת הגדרה מצדכם. אפשר להריץ אותו מ-Chromebook. כדאי לפתוח את הקובץ שלמטה ולהריץ את התאים כדי להכיר את מחברות Colab.

c3df49e90e5a654f.png Welcome to Colab.ipynb

הוראות נוספות מפורטות בהמשך:

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

hsy7H7O5qJNvKcRnHRiZoyh0IznlzmrO60wR1B6pqtfdc8Ie7gLsXC0f670zsPzGsNy3QAJuZefYv9CwTHmjiMyywG2pTpnMCE6Slkf3K1BeVmfpsYVw6omItm1ZneqdE31F8re-dA

בתפריט Colab, בוחרים באפשרות סביבת זמן הריצה > שינוי הסוג של סביבת זמן הריצה ואז בוחרים באפשרות GPU. החיבור לסביבת זמן הריצה יתבצע באופן אוטומטי בהרצה הראשונה, או שתוכלו להשתמש בלחצן 'Connect' בפינה השמאלית העליונה.

הרצת Notebook

evlBKSO15ImjocdEcsIo8unzEe6oDGYnKFe8CoHS_7QiP3sDbrs2jB6lbyitEtE7Gt_1UsCdU5dJA-_2IgBWh9ofYf4yVDE740PwJ6kiQwuXNOLkgktzzf0E_k5VN5mq29ZXI5wb7Q

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

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

OXeYYbtKdLCNnw_xovSMeMwSdD7CL_w25EfhnpRhhhO44bYp3zZpU72J5tKaSuo8wpas0GK5B2sTBlIMiFmdGxFRQ9NmwJ7JIRYy5XtpWKQCPdxQVRPy_0J_LshGIKjtw8P9fXozaA

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

תאים מוסתרים

GXTbXUO8xpPFKiGc6Q-cFwFHxHvOa105hHg3vk77EDpStyhU4AQMN3FYenbiBusHXUSk-yGXbRDcK-Cwx18XbDtyqB5WRr3_2jhnLvFxW8a7H_4cGvVDKrEMto_QxhfTeO0hwmrfng

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

‫3. אימון רשת נוירונים

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

c3df49e90e5a654f.png keras_01_mnist.ipynb

בזמן שמריצים את ה-notebook, מתמקדים בהדמיות. הסברים מופיעים בהמשך.

נתונים לאימון

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

ad83f98e56054737.png

רשת הנוירונים שנבנה תסווג את הספרות הכתובות בכתב יד ב-10 הכיתות שלהן (0, .., 9). הסיווג מתבצע על סמך פרמטרים פנימיים שצריכים להיות בעלי ערך נכון כדי שהסיווג יפעל בצורה טובה. הערך הנכון הזה נלמד בתהליך אימון שדורש 'מערך נתונים עם תוויות' שכולל תמונות ואת התשובות הנכונות שמשויכות אליהן.

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

הדרכה

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

3f7b405649301ea.png

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

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

ציר ה-X מייצג את מספר התקופות של זמן מערכת (epochs) או את מספר האיטרציות על פני מערך הנתונים כולו.

תחזיות

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

c0699216ba0effdb.png

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

טנסורים

הנתונים מאוחסנים במטריצות. תמונה בגווני אפור בגודל 28x28 פיקסלים מתאימה למטריצה דו-ממדית בגודל 28x28. אבל כדי להגדיר תמונה צבעונית, צריך להגדיר יותר ממד אחד. יש 3 ערכי צבע לכל פיקסל (אדום, ירוק, כחול), ולכן צריך טבלה תלת-ממדית עם המימדים [28, 28, 3]. כדי לאחסן קבוצה של 128 תמונות צבעוניות, צריך טבלה ארבע-ממדית עם המימדים [128, 28, 28, 3].

הטבלאות הרב-ממדיות האלה נקראות טנסורים, והרשימה של הממדים שלהן נקראת צורה.

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

על קצה המזלג

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

witch.png

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

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=[28, 28, 1]),
    tf.keras.layers.Dense(200, activation="relu"),
    tf.keras.layers.Dense(60, activation="relu"),
    tf.keras.layers.Dense(10, activation='softmax') # classifying into 10 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

שכבה צפופה אחת

ספרות בכתב יד במערך הנתונים MNIST הן תמונות בגווני אפור בגודל 28x28 פיקסלים. הגישה הפשוטה ביותר לסיווג שלהם היא להשתמש ב-784 הפיקסלים (28x28) כקלט לרשת נוירונים עם שכבה אחת.

Screen Shot 2016-07-26 at 12.32.24.png

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

התמונה שלמעלה מייצגת רשת נוירונים עם שכבה אחת ו-10 נוירונים של פלט, כי אנחנו רוצים לסווג ספרות ל-10 מחלקות (0 עד 9).

עם כפל מטריצות

כך אפשר לייצג שכבת רשת נוירונים שמבצעת עיבוד של אוסף תמונות באמצעות כפל מטריצות:

matmul.gif

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

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

לבסוף, אנחנו מפעילים פונקציית הפעלה, למשל softmax (מוסבר בהמשך), ומקבלים את הנוסחה שמתארת רשת נוירונים עם שכבה אחת, שמופעלת על 100 תמונות:

Screen Shot 2016-07-26 at 16.02.36.png

ב-Keras

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

tf.keras.layers.Dense(10, activation='softmax')

להעמיק

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

fba0638cc213a29.png

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

פונקציות הפעלה: relu, ‏ softmax ו-sigmoid

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

644f4213a4ee70e5.png

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

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

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

41fc82288c4aff5d.png

הפעלת Softmax לסיווג

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

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

הפלט של השכבה האחרונה, לפני ההפעלה, נקרא לפעמים "לוגיטים". אם הווקטור הזה הוא L = [L0, L1, L2, L3, L4, L5, L6, L7, L8, L9], אז:

ef0d98c0952c262d.png d51252f75894479e.gif

Cross-entropy loss

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

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

6dbba1bce3cadc36.png

ירידה הדרגתית

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

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

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

gradient descent2.png

Mini-batching and momentum

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

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

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

cc544924671fa208.png

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

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

מילון מונחים

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

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

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

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

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

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

logits: הפלט של שכבת נוירונים לפני החלת פונקציית ההפעלה נקרא logits. המונח הזה מגיע מהפונקציה הלוגיסטית, שנקראת גם פונקציית סיגמואיד, שהייתה פונקציית ההפעלה הכי פופולרית. השם 'Neuron outputs before logistic function' (פלט של נוירון לפני פונקציה לוגיסטית) קוצר ל-'logits'.

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

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

קידוד "חם-יחיד": מחלקה 3 מתוך 5 מקודדת כווקטור של 5 אלמנטים, כולם אפסים חוץ מהאלמנט השלישי שהוא 1.

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

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

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

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

5. בואו נצלול אל הקוד

חוזרים למחברת המחקר, והפעם קוראים את הקוד.

c3df49e90e5a654f.png keras_01_mnist.ipynb

בואו נעבור על כל התאים ב-notebook הזה.

התא 'פרמטרים'

כאן מוגדרים גודל האצווה, מספר התקופות של זמן המערכת והמיקום של קובצי הנתונים. קובצי הנתונים מאוחסנים בקטגוריה ב-Google Cloud Storage ‏ (GCS), ולכן הכתובת שלהם מתחילה ב-gs://

התא 'ייבואים'

כאן מייבאים את כל ספריות Python הנדרשות, כולל TensorFlow וגם matplotlib להדמיות.

תא visualization utilities [RUN ME]****

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

תא tf.data.Dataset: parse files and prepare training and validation datasets

בתא הזה נעשה שימוש ב-tf.data.Dataset API כדי לטעון את מערך הנתונים MNIST מקובצי הנתונים. לא צריך להשקיע יותר מדי זמן בתא הזה. אם אתם רוצים ללמוד על tf.data.Dataset API, תוכלו לעיין במדריך הבא: צינורות נתונים מהירים של TPU. בשלב הזה, התכונות הבסיסיות הן:

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

imagedataset = tf.data.FixedLengthRecordDataset(image_filename, 28*28, header_bytes=16)

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

def read_image(tf_bytestring):
    image = tf.io.decode_raw(tf_bytestring, tf.uint8)
    image = tf.cast(image, tf.float32)/256.0
    image = tf.reshape(image, [28*28])
    return image

אנחנו מפעילים את הפונקציה הזו על מערך הנתונים באמצעות .map ומקבלים מערך נתונים של תמונות:

imagedataset = imagedataset.map(read_image, num_parallel_calls=16)

אנחנו מבצעים קריאה ופענוח דומים של תוויות, ו.zip תמונות ותוויות יחד:

dataset = tf.data.Dataset.zip((imagedataset, labelsdataset))

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

dataset = dataset.cache()
dataset = dataset.shuffle(5000, reshuffle_each_iteration=True)
dataset = dataset.repeat()
dataset = dataset.batch(batch_size)
dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE)

ב-API ‏tf.data.Dataset יש את כל פונקציות השירות הדרושות להכנת מערכי נתונים:

.cache שומר במטמון את מערך הנתונים ב-RAM. זו קבוצת נתונים קטנה מאוד, אז היא תפעל. ‫.shuffle מערבב אותו עם מאגר של 5,000 רכיבים. חשוב שנתוני האימון יהיו מעורבבים היטב. ‫.repeat חוזר על מערך הנתונים. נאמן את המודל על הנתונים האלה מספר פעמים (מספר תקופות של זמן מערכת). ‫.batch מאגד כמה תמונות ותוויות לתוך קבוצת נתונים קטנה. לבסוף, .prefetch יכול להשתמש ב-CPU כדי להכין את האצווה הבאה בזמן שהאצווה הנוכחית עוברת אימון ב-GPU.

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

התא Keras Model

כל המודלים שלנו יהיו רצפים ישרים של שכבות, כדי שנוכל להשתמש בסגנון tf.keras.Sequential כדי ליצור אותם. בהתחלה, זו שכבה צפופה אחת. יש לה 10 נוירונים כי אנחנו מסווגים ספרות בכתב יד ל-10 מחלקות. הוא משתמש בהפעלה מסוג softmax כי הוא השכבה האחרונה בסיווג.

מודל Keras צריך לדעת גם את הצורה של הקלט שלו. אפשר להשתמש ב-tf.keras.layers.Input כדי להגדיר אותו. כאן, וקטורי הקלט הם וקטורים שטוחים של ערכי פיקסלים באורך 28*28.

model = tf.keras.Sequential(
  [
    tf.keras.layers.Input(shape=(28*28,)),
    tf.keras.layers.Dense(10, activation='softmax')
  ])

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

# print model layers
model.summary()

# utility callback that displays training curves
plot_training = PlotTraining(sample_rate=10, zoom=1)

הגדרת המודל מתבצעת ב-Keras באמצעות הפונקציה model.compile. בדוגמה הזו אנחנו משתמשים באופטימיזציה הבסיסית 'sgd' (Stochastic Gradient Descent). מודל סיווג דורש פונקציית אובדן של אנטרופיה צולבת, שנקראת 'categorical_crossentropy' ב-Keras. לבסוף, אנחנו מבקשים מהמודל לחשב את מדד 'accuracy', שהוא אחוז התמונות שסווגו בצורה נכונה.

‫Keras מציעה את כלי השירות model.summary() שמאפשר להדפיס את פרטי המודל שיצרתם. המדריך הנחמד שלך הוסיף את כלי השירות PlotTraining (מוגדר בתא visualization utilities) שיציג עקומות אימון שונות במהלך האימון.

התא Train and validate the model (אימון ואימות המודל)

בשלב הזה מתבצע האימון, על ידי קריאה ל-model.fit והעברה של מערכי הנתונים של האימון והאימות. כברירת מחדל, Keras מריץ סבב אימות בסוף כל תקופה.

model.fit(training_dataset, steps_per_epoch=steps_per_epoch, epochs=EPOCHS,
          validation_data=validation_dataset, validation_steps=1,
          callbacks=[plot_training])

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

התא 'הצגת תחזיות'

אחרי שמסיימים לאמן את המודל, אפשר לקבל ממנו תחזיות באמצעות הקריאה ל-model.predict():

probabilities = model.predict(font_digits, steps=1)
predicted_labels = np.argmax(probabilities, axis=1)

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

כדי להבין למה צריך את הפרמטר axis=1, חשוב לזכור שעיבדנו קבוצה של 128 תמונות, ולכן המודל מחזיר 128 וקטורים של הסתברויות. הצורה של טנסור הפלט היא [128, 10]. אנחנו מחשבים את argmax על פני 10 ההסתברויות שמוחזרות לכל תמונה, ולכן axis=1 (הציר הראשון הוא 0).

המודל הפשוט הזה כבר מזהה 90% מהספרות. לא רע, אבל עכשיו תשפר את זה באופן משמעותי.

396c54ef66fad27f.png

6. הוספת שכבות

godeep.png

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

Screen Shot 2016-07-27 at 15.36.55.png

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

41fc82288c4aff5d.png

לדוגמה, המודל יכול להיראות כך (אל תשכחו את הפסיקים, tf.keras.Sequential מקבל רשימה מופרדת בפסיקים של שכבות):

model = tf.keras.Sequential(
  [
      tf.keras.layers.Input(shape=(28*28,)),
      tf.keras.layers.Dense(200, activation='sigmoid'),
      tf.keras.layers.Dense(60, activation='sigmoid'),
      tf.keras.layers.Dense(10, activation='softmax')
  ])

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

5236f91ba6e07d85.png

נראה שההפסד גם עלה בצורה משמעותית. נראה שמשהו לא בסדר.

7. טיפול מיוחד ברשתות עמוקות

הרגע חוויתם רשתות עצביות, כפי שאנשים נהגו לעצב אותן בשנות ה-80 וה-90. לא פלא שהם ויתרו על הרעיון, מה שהוביל למה שמכונה "חורף הבינה המלאכותית". למעשה, ככל שמוסיפים שכבות, לרשתות עצביות קשה יותר ויותר להתכנס.

מסתבר שרשתות עצביות עמוקות עם הרבה שכבות (20, 50 ואפילו 100 היום) יכולות לפעול בצורה טובה מאוד, בתנאי שמשתמשים בכמה טריקים מתמטיים כדי לגרום להן להתכנס. הגילוי של הטריקים הפשוטים האלה הוא אחת הסיבות לתחייה של למידה עמוקה בעשור השני של המאה ה-21.

הפעלת RELU

relu.png

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

1abce89f7143a69c.png

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

כלי אופטימיזציה משופר

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

הפעלות אקראיות

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

אין צורך לבצע שום פעולה, כי Keras כבר עושה את הפעולה הנכונה.

NaN ???

הנוסחה של האנטרופיה הצולבת כוללת לוגריתם, והלוגריתם של 0 הוא לא מספר (NaN, קריסה מספרית אם תרצו). האם הקלט של האנטרופיה הצולבת יכול להיות 0? הקלט מגיע מ-softmax, שהוא למעשה פונקציה אקספוננציאלית, ופונקציה אקספוננציאלית אף פעם לא שווה לאפס. אז אנחנו בטוחים!

באמת? בעולם היפה של המתמטיקה, היינו בטוחים, אבל בעולם המחשבים, exp(-150), שמיוצג בפורמט float32, הוא אפס לכל דבר, והאנטרופיה הצולבת קורסת.

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

הצלחה?

e1521c9dd936d9bc.png

עכשיו רמת הדיוק צריכה להיות 97%. המטרה בסדנה הזו היא להגיע לשיעור גבוה משמעותית מ-99%, אז בואו נמשיך.

אם נתקעתם, הנה הפתרון בשלב הזה:

c3df49e90e5a654f.png keras_02_mnist_dense.ipynb

8. הפחתה של קצב הלמידה

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

הגברת המהירות לא עוזרת במיוחד, ומה זה כל הרעש הזה?

d4fd66346d7c480e.png

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

slow down.png

הפתרון הטוב הוא להתחיל מהר ולהקטין את קצב הלמידה באופן אקספוננציאלי. ב-Keras, אפשר לעשות את זה באמצעות הקריאה החוזרת tf.keras.callbacks.LearningRateScheduler.

קוד שימושי להעתקה והדבקה:

# lr decay function
def lr_decay(epoch):
  return 0.01 * math.pow(0.6, epoch)

# lr schedule callback
lr_decay_callback = tf.keras.callbacks.LearningRateScheduler(lr_decay, verbose=True)

# important to see what you are doing
plot_learning_rate(lr_decay, EPOCHS)

אל תשכחו להשתמש בlr_decay_callback שיצרתם. מוסיפים אותו לרשימת ההתקשרויות החוזרות ב-model.fit:

model.fit(...,  callbacks=[plot_training, lr_decay_callback])

ההשפעה של השינוי הקטן הזה היא מדהימה. אפשר לראות שרוב הרעשים נעלמו ודיוק הבדיקה עכשיו מעל 98% באופן קבוע.

8c1ae90976c4a0c1.png

9. Dropout, overfitting

נראה שהמודל מתכנס עכשיו בצורה טובה. ננסה להתעמק עוד יותר.

האם זה עזר?

e36c09a3088104c6.png

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

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

dropout.png

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

זה עבד?

43fd33801264743f.png

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

נראה שהפתרון של השמטת נוירונים לא היה נכון, או שאולי 'התאמת יתר' היא מושג מורכב יותר וחלק מהגורמים שלה לא ניתנים לתיקון באמצעות השמטת נוירונים?

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

overfitting.png

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

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

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

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

אם נתקעתם, הנה הפתרון בשלב הזה:

c3df49e90e5a654f.png keras_03_mnist_dense_lrdecay_dropout.ipynb

10. ‫[INFO] רשתות קונבולוציה

על קצה המזלג

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

convolutional.gif

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

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

model = tf.keras.Sequential([
    tf.keras.layers.Reshape(input_shape=(28*28,), target_shape=(28, 28, 1)),
    tf.keras.layers.Conv2D(kernel_size=3, filters=12, activation='relu'),
    tf.keras.layers.Conv2D(kernel_size=6, filters=24, strides=2, activation='relu'),
    tf.keras.layers.Conv2D(kernel_size=6, filters=32, strides=2, activation='relu'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(10, activation='softmax')
])

688858c21e3beff2.png

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

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

Screen Shot 2016-07-29 at 16.02.37.png

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

d1b557707bcd1cb9.png

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

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

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

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

2b2d4263bb8470b.gif

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

השכבה האחרונה

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

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

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

a44aa392c7b0e32a.png

בקטע הבא נבנה רשת קונבולוציונית לבעיה שלפנינו.

11. רשת קונבולוציה

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

e1a214a170957da1.png

שימו לב שהשכבות השנייה והשלישית של הקונבולוציה הן בעלות צעד של שתיים, ולכן הן מצמצמות את מספר ערכי הפלט מ-28x28 ל-14x14 ואז ל-7x7.

עכשיו נכתוב את הקוד של Keras.

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

tf.keras.layers.Reshape(input_shape=(28*28,), target_shape=(28, 28, 1))

אפשר להשתמש בשורה הזו במקום בשכבת tf.keras.layers.Input שהייתה לכם עד עכשיו.

ב-Keras, התחביר של שכבת קונבולוציה עם הפעלה מסוג relu הוא:

140f80336b0e653b.png

tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu')

כדי להגדיר קונבולוציה עם דילוג, כותבים:

tf.keras.layers.Conv2D(kernel_size=6, filters=24, padding='same', activation='relu', strides=2)

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

tf.keras.layers.Flatten()

ובשביל שכבה צפופה, התחביר לא השתנה:

tf.keras.layers.Dense(200, activation='relu')

האם המודל שלך עבר את מחסום הדיוק של 99%? כמעט… אבל כדאי להסתכל על עקומת הירידה בערכי האימות. האם זה נשמע לך מוכר?

ecc5972814885226.png

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

37e4cbd3f390c89e.png

אם נתקעתם, הנה הפתרון בשלב הזה:

c3df49e90e5a654f.png keras_04_mnist_convolutional.ipynb

12. נשירה נוספת

האימון הקודם מראה סימנים ברורים של התאמת יתר (overfitting) (ועדיין לא מגיע לדיוק של 99%). רוצה לנסות שוב להפסיק את הלימודים?

איך היה הפעם?

63e0cc982cee2030.png

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

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

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

13. נורמליזציה באצווה

oggEbikl2I6_sOo7FlaX2KLdNeaYhJnVSS8GyG8FHXid75PVJX73CRiOynwpMZpLZq6_xAy69wgyez5T-ZlpuC2XSlcmjk7oVcOzefKKTFhTEoLO3kljz2RDyKcaFtHvtTey-I4VpQ

לבסוף, ננסה להוסיף נורמליזציה של קבוצות.

זו התיאוריה, אבל בפועל, צריך לזכור רק כמה כללים:

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

# Modify each layer: remove the activation from the layer itself.
# Set use_bias=False since batch norm will play the role of biases.
tf.keras.layers.Conv2D(..., use_bias=False),
# Batch norm goes between the layer and its activation.
# The scale factor can be turned off for Relu activation.
tf.keras.layers.BatchNormalization(scale=False, center=True),
# Finish with the activation.
tf.keras.layers.Activation('relu'),

מה רמת הדיוק עכשיו?

ea48193334c565a1.png

עם שינויים קלים (BATCH_SIZE=64, פרמטר של ירידה בקצב הלמידה 0.666, שיעור הנשירה בשכבה הצפופה 0.3) ומעט מזל, אפשר להגיע ל-99.5%. התאמות של קצב הלמידה והנשירה בוצעו בהתאם לשיטות המומלצות לשימוש בנורמליזציה של אצווה:

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

ה-notebook של הפתרון כולל הרצת אימון של 99.5%:

c3df49e90e5a654f.png keras_05_mnist_batch_norm.ipynb

14. אימון בענן על חומרה עוצמתית: AI Platform

d7d0282e687bdad8.png

גרסה של הקוד שמוכנה לשימוש בענן נמצאת בתיקייה mlengine ב-GitHub, יחד עם הוראות להרצה שלה ב-Google Cloud AI Platform. כדי להריץ את החלק הזה, צריך ליצור חשבון Google Cloud ולהפעיל את החיוב. המשאבים שנדרשים להשלמת המעבדה צריכים לעלות פחות מכמה דולרים (בהנחה של שעת אימון אחת ב-GPU אחד). כדי להכין את החשבון:

  1. יוצרים פרויקט ב-Google Cloud Platform‏ ( http://cloud.google.com/console).
  2. מפעילים את החיוב.
  3. מתקינים את כלי שורת הפקודה של GCP ( GCP SDK כאן).
  4. יוצרים קטגוריה של Google Cloud Storage (במיקום us-central1). הקטגוריה תשמש להכנת קוד האימון ולאחסון המודל שאומן.
  5. מפעילים את ממשקי ה-API הנדרשים ומבקשים את המכסות הנדרשות (מריצים את פקודת ההדרכה פעם אחת, ואמורות להופיע הודעות שגיאה שמציינות מה צריך להפעיל).

15. מעולה!

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

cliffs notes tensorflow lab.png

השלבים הבאים

  • אחרי רשתות קונבולוציה ורשתות מחוברות באופן מלא, כדאי לעיין ברשתות נוירונים חוזרות.
  • כדי להריץ את האימון או את ההסקת המסקנות בענן בתשתית מבוזרת, אפשר להשתמש ב-AI Platform של Google Cloud.
  • בסופו של דבר, נשמח לקבל משוב. נשמח לדעת אם משהו לא בסדר בשיעור ה-Lab הזה או אם יש לך רעיונות לשיפור. אנחנו מטפלים במשוב באמצעות בעיות ב-GitHub [ קישור למשוב].

HR.png

Martin Görner ID small.jpgהמחבר: Martin GörnerTwitter: @martin_gorner

זכויות היוצרים על כל התמונות המצוירות ב-Lab הזה: alexpokusay / 123RF stock photos