בניית מודל ראייה ממוחשבת עם TensorFlow

1. לפני שמתחילים

ב-codelab זה תיצרו דגם של ראייה ממוחשבת שיכול לזהות פריטי לבוש עם TensorFlow.

דרישות מוקדמות

  • ידע מעמיק ב-Python
  • מיומנויות תכנות בסיסיות

מה תלמדו

במעבדה זו, תוכלו:

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

מה תיצור

  • רשת נוירונים שמזהה פריטי לבוש

מה צריך?

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

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

2. התחלת הקידוד

קודם כול, עיינו בפנקס ההפעלה של Colab.

כדי להתחיל, יש לייבא את TensorFlow.

import tensorflow as tf
print(tf.__version__)

תאמנו רשת נוירונים כדי לזהות פריטי לבוש ממערך נתונים משותף בשם אופנה MNIST. יש בה 70,000 פריטי לבוש ב-10 קטגוריות שונות. כל פריט לבוש מופיע בתמונה בגווני אפור של 28x28. ניתן לראות כאן כמה דוגמאות:

התוויות המשויכות למערך הנתונים הן:

תווית

תיאור

0

לחולצות טי

1

מכנסיים

2

סוודר

3

שמלה

4

מעיל

5

סנדל

6

חולצה

7

נעל ספורט

8

תיק

9

מגפי קרסול

נתוני האופנה של MNIST זמינים ב-API של tf.keras.datasets. ניתן לטעון אותו באופן הבא:

mnist = tf.keras.datasets.fashion_mnist

קריאה ל-load_data באובייקט הזה מספקת שתי קבוצות של שתי רשימות: ערכי training וערכי test (בדיקות), שמייצגים גרפיקה שמציגה פריטי לבוש והתוויות שלהם.

(training_images, training_labels), (test_images, test_labels) = mnist.load_data()

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

import matplotlib.pyplot as plt
plt.imshow(training_images[0])
print(training_labels[0])
print(training_images[0])

הדפסת הנתונים של הפריט 0 נראית כך:

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

training_images  = training_images / 255.0
test_images = test_images / 255.0

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

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

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

3. עיצוב המודל

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

model = tf.keras.models.Sequential([tf.keras.layers.Flatten(), 
                                    tf.keras.layers.Dense(128, activation=tf.nn.relu), 
                                    tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
  • Sequential מגדיר רצף של שכבות ברשת הנוירונים.
  • Flatten הופכת לריבוע ומגדירה אותו לווקטור חד-ממדי.
  • Dense מוסיף שכבה של נוירונים.
  • הפונקציות של Activation מציינות לכל שכבה של נוירונים מה לעשות. יש אפשרויות רבות, אבל כדאי להשתמש בהן בשלב זה:
  • הפונקציה Relu פירושה שאם X גדול מ-0 מחזירה X, יש להחזיר את הערך 0. היא מעבירה ערכים של 0 ומעלה רק לשכבה הבאה ברשת.
  • Softmax מקבל קבוצה של ערכים, ובוחר בפועל את הערך הגדול ביותר. לדוגמה, אם הפלט של השכבה האחרונה נראה כך: [0.1, 0.1, 0.05, 0.1, 9.5, 0.1, 0.05, 0.05, 0.05], הוא חוסך לכם את הצורך למיין את הערך הגדול ביותר — הוא מחזיר [0,0,0,0,1,0,0,0].

4. הידור ואימון המודל

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

שימו לב לשימוש ב-metrics= כפרמטר, שמאפשר ל-TenororFlow לדווח על דיוק האימון על ידי בדיקת התוצאות החזויות מול התשובות הידועות (התוויות).

model.compile(optimizer = tf.keras.optimizers.Adam(),
              loss = 'sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(training_images, training_labels, epochs=5)

כשהחשבון model.fit יבוצע, תהיה לך אפשרות לראות את הדיוק וההפסדים:

Epoch 1/5
60000/60000 [=======] - 6s 101us/sample - loss: 0.4964 - acc: 0.8247
Epoch 2/5
60000/60000 [=======] - 5s 86us/sample - loss: 0.3720 - acc: 0.8656
Epoch 3/5
60000/60000 [=======] - 5s 85us/sample - loss: 0.3335 - acc: 0.8780
Epoch 4/5
60000/60000 [=======] - 6s 103us/sample - loss: 0.3134 - acc: 0.8844
Epoch 5/5
60000/60000 [=======] - 6s 94us/sample - loss: 0.2931 - acc: 0.8926

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

5. בדיקת המודל

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

model.evaluate(test_images, test_labels)

הנה הפלט:

10000/10000 [=====] - 1s 56us/sample - loss: 0.3365 - acc: 0.8789
[0.33648381242752073, 0.8789]

הדוגמה הזו החזירה דיוק .8789, כלומר היא הייתה מדויקת ב-88%. (ייתכן שיהיו לכם ערכים שונים מעט).

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

לשלב הבא כדאי לנסות את התרגילים בשלב הבא.

6. תרגילי חקירה

תרגיל 1

עבור תרגיל ראשון זה, הפעילו את הקוד הבא:

classifications = model.predict(test_images)
print(classifications[0])

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

אפשר לנסות להריץ print(test_labels[0]) ואז לקבל #. האם זה עוזר לכם להבין למה הרשימה נראית?

הפלט של המודל הוא רשימה של 10 מספרים. המספרים האלה הם סבירות שהערך המסווג הוא התווית המתאימה. לדוגמה, הערך הראשון ברשימה הוא ההסתברות שהבגדים מסווגים בקטגוריה 0, והערך הבא הוא 1. חשוב לשים לב שהסבירות לכך נמוכה מאוד. כמו כן, בגלל Softmax, כל ההסתברות ברשימה הוא 1.0.

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

פעילות 2

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

אילו תוצאות אתם מקבלים לגבי אובדן וזמן אימון? למה זה קרה לדעתכם?

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

פעילות גופנית 3

מה יקרה אם תסיר את השכבה Flatten(). למה זה קרה לדעתכם?

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

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

תרגיל 4

יש לשקול את השכבות הסופיות (פלט). למה יש 10 מהן? מה היה קורה אם היה לך סכום שונה מ-10?

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

תרגיל 5

חשוב על ההשפעות של שכבות נוספות ברשת. מה יקרה אם מוסיפים שכבה נוספת בין השכבה 512 לבין השכבה הסופית עם 10?

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

תרגיל 6

לפני האימון, נורמלתם את הנתונים מעבר לערכים מ-0 עד 255 לערכים מ-0 עד 1. מה תהיה ההשפעה של הסרת התוכן הזה? זהו הקוד המלא כדי לנסות אותו (שימו לב לכך ששתי השורות מנורמלות את הנתונים, מודגשות).

למה לדעתך אתם מקבלים תוצאות שונות? יש תשובה מצוינת כאן ב-Stack Overflow.

import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
#training_images=training_images/255.0
#test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])

7. התקשרות חזרה

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

כמו בכל תוכנית אחרת, גם כאן התקשרות חזרה! אפשר לראות אותם בפעולה:

import tensorflow as tf

class myCallback(tf.keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs={}):
    if(logs.get('accuracy')>0.95):
      print("\nReached 95% accuracy so cancelling training!")
      self.model.stop_training = True

callbacks = myCallback()
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images/255.0
test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5, callbacks=[callbacks])

8. מזל טוב

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