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

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

המדריך הזה עודכן ל-Tensorflow 2.2 !

74f6fbd758bf19e6.png

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

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

מה תלמדו

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

למה תזדקק?

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

משוב

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

2. התחלה מהירה של Google Colaboratory

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

c3df49e90e5a654f.png Welcome to Colab.ipynb

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

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

hsy7H7O5qJNvKcRnHRiZoyh0IznlzmrO60wR1B6pqtfdc8Ie7gLsXC0f670zsPzGsNy3QAJuZefYv9CwTHmjiMyywG2pTpnMCE6Slkf3K1V

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

ביצוע Notebook

evlBKSO15ImjocdEcsIo8unzEe6oDGYnKFe8CoHS_7QiP3sDbrs2jB6lbyitEtE7Gt_1UsCdU5dJA-_2IgBWh9ofYf4yVDE740PwJ6kiQwuXNOLkgktzzf0E_k5VN5mq29ZXI5wb7Q

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

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

OXeYYbtKdLCNnw_xovSMeMwSdD7CL_w25EfhnpRhhhO44bYp3zZpU72J5tKaSuo8wpas0GK5B2sTBlIMiFmdGxFRQ9NmwJ7JIRYy5XtpWKQCPdxQVRPy_0J_LshGIKjtw8P9fXozaA

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

תאים מוסתרים

GXTbXUO8xpPFKiGc6Q-cFwFHxHvOa105hHg3vk77EDpStyhU4AQMN3FYenbiBusHXUSk-yGXbRDcK-Cwx18XbDtyqB5WRr3_2jhnLvFxW8a7H_4cGvVDKrEMto_QxhfTeO0hwmrfng

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

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

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

c3df49e90e5a654f.png keras_01_mnist.ipynb

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

נתוני אימון

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

ad83f98e56054737.png

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

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

הדרכה

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

3f7b405649301ea.png

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

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

ציר ה-X מייצג את מספר ה"תקופות" או איטרציות על כל מערך הנתונים.

חיזויים

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

c0699216ba0effdb.png

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

חיישנים

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

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

4. [מידע]: רשתות נוירונים בשלב 101

בקצרה

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

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 פיקסלים. הגישה הפשוטה ביותר לסיווג שלהם היא להשתמש בפיקסלים 28x28=784 פיקסלים כקלט לרשת נוירונים עם שכבה אחת.

צילום מסך מתאריך 2016-07-26 בשעה 12.32.24.png

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

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

עם כפל במטריצה

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

matmul.gif

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

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

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

צילום מסך מתאריך 26-07-2016 בשעה 16.02.36.png

ב-Keras

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

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

ניתוח מעמיק

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

fba0638cc213a29.png

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

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

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

644f4213a4ee70e5.png

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

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

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

41fc82288c4aff5d.png

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

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

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

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

ef0d98c0952c262d.png d51252f75894479e.gif

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

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

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

6dba1bce3cadc36.png

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

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

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

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

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

מיני-אצווה ומומנטום

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

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

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

cc544924671fa208.png

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

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

מילון מונחים

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

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

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

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

labels: שם אחר ל-"classes" או נכונות תשובות בעייתיות בסיווג בפיקוח

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

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

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

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

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

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

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

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

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

5. קדימה, מתחילים

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

c3df49e90e5a654f.png keras_01_mnist.ipynb

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

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

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

ייבוא תא

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

התא "כלים להצגה חזותית [RUN ME]****"

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

תא "tf.data.Dataset: ניתוח קבצים והכנת מערכי נתונים של אימון ואימות"

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

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

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

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

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

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

תא 'אימון ואימות של המודל'

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

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

396c54ef66fad27f.png

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

godeep.png

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

צילום מסך משנת 2016-07-27 בגודל 15.36.55.png

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

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

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

הפעלה של RELU

relu.png

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

1abce89f7143a69c.png

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

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

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

אתחולים אקראיים

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

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

NaN ...

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

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

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

הצלחת?

e1521c9dd936d9bc.png

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

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

c3df49e90e5a654f.png keras_02_mnist_dense.ipynb

8. דעיכה לאורך קצב הלמידה

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

נראה שמעבר מהיר יותר לא עוזר הרבה, ומה קורה עם כל הרעש הזה?

d4fd66346d7c480e.png

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

האטה

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

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

זה עוזר?

e36c09a3088104c6.png

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

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

dropout.png

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

זה עבד?

43fd33801264743f.png

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

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

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

overfitting.png

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

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

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

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

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

c3df49e90e5a654f.png keras_03_mnist_dense_lrdecay_dropout.ipynb

10. [מידע] רשתות קונבולוציה

בקצרה

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

convolutional.gif

איור: סינון תמונה עם שני פילטרים עוקבים שמורכבים מ-48 x 4 x 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 בתמונת הקלט.

צילום מסך מתאריך 2016-07-29 בשעה 16.02.37.png

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

d1b557707bcd1cb9.png

איור: רשת עצבית מתקפלת משנה 'קוביות' של נתונים ל"קוביות" אחרות של נתונים.

קיפולים (קונבולציות) ברצף, צבירה מקסימלית

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

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

2b2d4263bb8470b.gif

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

השכבה הסופית

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

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

במקום להשתמש בשכבה צפופה ויקרה, אנחנו יכולים גם לפצל את הנתונים הנכנסים ב"קובייה" לחלקים רבים ככל האפשר, יש ממוצע של הערכים שלהם ולהזין אותם באמצעות פונקציית הפעלה מסוג Softmax. בשיטה הזו של בניית ראש הסיווג, עולה 0 משקלים. ב-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 הספרות של הבדיקה מזוהות בצורה נכונה. נשארו רק כ-41⁄2 שורות של זיהוי שגוי (כ-110 ספרות מתוך 10,000)

37e4cbd3f390c89e.png

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

c3df49e90e5a654f.png keras_04_mnist_convolutional.ipynb

12. עזיבה חוזרת

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

איך היה?

63e0cc982cee2030.png

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

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

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

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%. שיעור הלמידה וההתאמות שבוצעו בהתאם ל'שיטות המומלצות' לשימוש בנורמה באצווה:

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

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

c3df49e90e5a654f.png keras_05_mnist_batch_norm.ipynb

14. מאמנים את הענן בחומרה חזקה: AI Platform

d7d0282e687bdad8.png

גרסה מותאמת לענן של הקוד מופיעה בתיקיית mlengine ב-GitHub והוראות להרצה של הקוד ב-Google Cloud AI Platform. כדי להריץ את החלק הזה צריך ליצור חשבון Google Cloud ולהפעיל את החיוב. המשאבים הדרושים להשלמת שיעור ה-Lab צריכים להיות קטנים משני דולרים (בהנחה של שעה אחת של זמן אימון על 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, בגרסה מצוירת. אפשר להשתמש בו כדי לזכור את מה שלמדתם:

צוקים הערות tensorflow lab.png

השלבים הבאים

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

HR.png

Martin Görner ID Small.jpgהמחבר: מרטין גורנרטוויטר: @martin_gorner

כל התמונות המצוירות שנמצאות בשיעור ה-Lab הזה: alexpokusay / 123RF תמונות ממאגר