1. לפני שמתחילים
ב-codelab הזה נסביר על קונבולוציות ולמה הן כל כך שימושיות בתרחישים של ראייה ממוחשבת.
ב-codelab הקודם יצרתם רשת נוירונים עמוקה (DNN) פשוטה לראייה ממוחשבת של פריטי אופנה. ההגבלה הזו הייתה קיימת כי נדרש שפריט הלבוש יהיה הדבר היחיד בתמונה, והוא היה צריך להיות ממוקם במרכז.
ברור שזה לא תרחיש ריאליסטי. חשוב שהרשת העצבית העמוקה תוכל לזהות את פריט הלבוש בתמונות עם אובייקטים אחרים, או בתמונות שבהן הפריט לא ממוקם במרכז. כדי לעשות את זה, צריך להשתמש בקונבולוציות.
דרישות מוקדמות
ה-codelab הזה מבוסס על עבודה שהושלמה בשני חלקים קודמים: הכרת 'שלום עולם' של למידת מכונה ויצירת מודל של ראייה ממוחשבת. צריך להשלים את ה-codelabs האלה לפני שממשיכים.
מה תלמדו
- מהן קונבולוציות
- איך יוצרים מפת תכונות
- מה זה שיתוף משאבים
מה תפַתחו
- מפת תכונות של תמונה
מה תצטרכו
אפשר למצוא את הקוד של שאר ה-codelab ב-Colab.
תצטרכו גם להתקין את TensorFlow ואת הספריות שהתקנתם ב-codelab הקודם.
2. מהן קונבולוציות?
קונבולוציה היא מסנן שמועבר על תמונה, מעבד אותה ומחלץ את התכונות החשובות.
נניח שיש לכם תמונה של אדם שנועל נעלי ספורט. איך תזהה נוכחות של נעלי ספורט בתמונה? כדי שהתוכנה תוכל לזהות את התמונה כסניקרס, צריך לחלץ את התכונות החשובות ולטשטש את התכונות הלא חיוניות. הפעולה הזו נקראת מיפוי תכונות.
תהליך מיפוי התכונות הוא פשוט מבחינה תיאורטית. המערכת תסרוק כל פיקסל בתמונה ואז תבדוק את הפיקסלים הסמוכים לו. מכפילים את הערכים של הפיקסלים האלה במשקלים המקבילים במסנן.
לדוגמה:

במקרה הזה, מצוינת מטריצת קונבולוציה בגודל 3x3, או גרעין של תמונה.
הערך הנוכחי של הפיקסל הוא 192. כדי לחשב את הערך של הפיקסל החדש, בודקים את הערכים של הפיקסלים השכנים, מכפילים אותם בערכים שצוינו במסנן וקובעים את הערך של הפיקסל החדש כסכום הסופי.
עכשיו נסביר איך פיתולים עובדים על ידי יצירת פיתול בסיסי על תמונה דו-ממדית בגווני אפור.
נשתמש בתמונה של עלייה מ-SciPy כדי להדגים את זה. זו תמונה מובנית יפה עם הרבה זוויות וקווים.
3. מתחילים לתכנת
מתחילים בייבוא של כמה ספריות Python ותמונה של עלייה:
import cv2
import numpy as np
from scipy import misc
i = misc.ascent()
לאחר מכן, משתמשים בספריית Pyplot matplotlib כדי לצייר את התמונה ולראות איך היא נראית:
import matplotlib.pyplot as plt
plt.grid(False)
plt.gray()
plt.axis('off')
plt.imshow(i)
plt.show()

אפשר לראות שזו תמונה של חדר מדרגות. יש הרבה תכונות שאפשר לנסות ולבודד. לדוגמה, יש קווים אנכיים חזקים.
התמונה מאוחסנת כמערך NumPy, כך שאפשר ליצור את התמונה שעברה שינוי פשוט על ידי העתקת המערך הזה. המשתנים size_x ו-size_y יכילו את מידות התמונה, כך שתוכלו להשתמש בהם בלולאה בהמשך.
i_transformed = np.copy(i)
size_x = i_transformed.shape[0]
size_y = i_transformed.shape[1]
4. יצירת מטריצת הקונבולוציה
קודם כול, יוצרים מטריצת קונבולוציה (או ליבה) כמערך 3x3:
# This filter detects edges nicely
# It creates a filter that only passes through sharp edges and straight lines.
# Experiment with different values for fun effects.
#filter = [ [0, 1, 0], [1, -4, 1], [0, 1, 0]]
# A couple more filters to try for fun!
filter = [ [-1, -2, -1], [0, 0, 0], [1, 2, 1]]
#filter = [ [-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
# If all the digits in the filter don't add up to 0 or 1, you
# should probably do a weight to get it to do so
# so, for example, if your weights are 1,1,1 1,2,1 1,1,1
# They add up to 10, so you would set a weight of .1 if you want to normalize them
weight = 1
עכשיו מחשבים את פיקסלי הפלט. מבצעים איטרציה על התמונה, משאירים שוליים של פיקסל אחד, ומכפילים כל אחד מהפיקסלים השכנים של הפיקסל הנוכחי בערך שמוגדר במסנן.
כלומר, השכן של הפיקסל הנוכחי שנמצא מעליו ומשמאלו יוכפל בפריט הימני העליון במסנן. לאחר מכן, מכפילים את התוצאה במשקל ומוודאים שהתוצאה היא בטווח 0 עד 255.
לבסוף, טוענים את הערך החדש לתמונה שעברה שינוי:
for x in range(1,size_x-1):
for y in range(1,size_y-1):
output_pixel = 0.0
output_pixel = output_pixel + (i[x - 1, y-1] * filter[0][0])
output_pixel = output_pixel + (i[x, y-1] * filter[0][1])
output_pixel = output_pixel + (i[x + 1, y-1] * filter[0][2])
output_pixel = output_pixel + (i[x-1, y] * filter[1][0])
output_pixel = output_pixel + (i[x, y] * filter[1][1])
output_pixel = output_pixel + (i[x+1, y] * filter[1][2])
output_pixel = output_pixel + (i[x-1, y+1] * filter[2][0])
output_pixel = output_pixel + (i[x, y+1] * filter[2][1])
output_pixel = output_pixel + (i[x+1, y+1] * filter[2][2])
output_pixel = output_pixel * weight
if(output_pixel<0):
output_pixel=0
if(output_pixel>255):
output_pixel=255
i_transformed[x, y] = output_pixel
5. בדיקת התוצאות
עכשיו, משרטטים את התמונה כדי לראות את ההשפעה של העברת המסנן מעליה:
# Plot the image. Note the size of the axes -- they are 512 by 512
plt.gray()
plt.grid(False)
plt.imshow(i_transformed)
#plt.axis('off')
plt.show()

כדאי להביא בחשבון את ערכי המסנן הבאים ואת ההשפעה שלהם על התמונה.
השימוש בערכים [-1,0,1,-2,0,2,-1,0,1] יוצר קבוצה חזקה מאוד של קווים אנכיים:

השימוש בערכים [-1,-2,-1,0,0,0,1,2,1] יוצר קווים אופקיים:

אפשר לנסות ערכים שונים. כדאי גם לנסות מסננים בגדלים שונים, כמו 5x5 או 7x7.
6. הסבר על שיתוף משאבים
אחרי שזיהית את המאפיינים החשובים של התמונה, מה עושים? איך משתמשים במפת התכונות שמתקבלת כדי לסווג תמונות?
בדומה לקונבולוציות, איגום עוזר מאוד בזיהוי תכונות. שכבות איגום מקטינות את כמות המידע הכוללת בתמונה, תוך שמירה על התכונות שמזוהות כקיימות.
יש כמה סוגים שונים של שיתוף משאבים, אבל אתם תשתמשו בסוג שנקרא שיתוף משאבים מקסימלי (Max).
מבצעים איטרציה על התמונה, ובכל נקודה בודקים את הפיקסל ואת השכנים הקרובים שלו מימין, מתחת ומימין למטה. בוחרים את הגדול מביניהם (ומכאן השם max pooling) ומטעינים אותו לתמונה החדשה. לכן, הגודל של התמונה החדשה יהיה רבע מהגודל של התמונה הישנה. 
7. כתיבת קוד לאיגום
הקוד הבא יציג איגום (pooling) של (2, 2). מריצים את הפקודה כדי לראות את הפלט.
אפשר לראות שהתמונה היא בגודל של רבע מהתמונה המקורית, אבל כל התכונות נשמרו.
new_x = int(size_x/2)
new_y = int(size_y/2)
newImage = np.zeros((new_x, new_y))
for x in range(0, size_x, 2):
for y in range(0, size_y, 2):
pixels = []
pixels.append(i_transformed[x, y])
pixels.append(i_transformed[x+1, y])
pixels.append(i_transformed[x, y+1])
pixels.append(i_transformed[x+1, y+1])
pixels.sort(reverse=True)
newImage[int(x/2),int(y/2)] = pixels[0]
# Plot the image. Note the size of the axes -- now 256 pixels instead of 512
plt.gray()
plt.grid(False)
plt.imshow(newImage)
#plt.axis('off')
plt.show()

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