הפרספטרון מאפס: מה נוירון מחשב
בונים פרספטרון ב-Python נקי, רואים אותו נכשל ב-XOR, ומבינים למה משפט ההתכנסות מבטיח הצלחה — לא שתזכו לראות אותה.
בעמוד הזה
יש מסוע במפעל. חלקים נעים עליו, ומישהו צריך להחליט אילו מהם נשלחים ואילו חוזרים אחורה. שני מספרים נמדדים לכל חלק: הרוחב שלו במילימטרים והמשקל שלו בגרמים. זה כל המידע שיש.
הדרך המתבקשת לאוטומציה היא לכתוב את הכלל. קבל אם הרוחב מתחת ל-22 מילימטרים. זה עובד עד שהספק משנה את הסגסוגת והמשקלים זזים. אז מוסיפים סעיף. אחר כך מנסחים מחדש את טווח הסבילות ומוסיפים עוד סעיף. שישה חודשים אחר כך הפונקציה באורך ארבעים שורות, אף אחד לא זוכר למה שורה 19 קיימת, והאדם שכתב אותה כבר עזב.
הדרך האחרת היא נושא הקורס הזה. אתם לא כותבים את הכלל. אתם כותבים את הצורה של הכלל — תבנית עם חורים — ונותנים לדוגמאות להחליט מה נכנס לחורים. ההיפוך הזה הוא כל מהות ה-machine learning, ובפרק הזה התבנית קטנה ככל שתבנית יכולה להיות: שני מספרים וסף.
בסוף הפרק תכתבו פרספטרון בכעשרים שורות Python, תראו אותו מצליח, תראו אותו נכשל, ותבינו את שניהם. הקובץ שתכתבו כאן אינו צעצוע שנזרק בפרק הבא: הוא ה-commit הראשון במאגר שבסופו, בעוד עשרים ותשעה פרקים, יהיה agent עם לולאת כלים ומודל הרשאות.
המודל: סכום משוקלל וקו
קישור למקטע: המודל: סכום משוקלל וקופרספטרון לוקח את המדידות, מכפיל כל אחת במספר שהוא שולט בו, מחבר אותן, מוסיף עוד מספר אחד, ומסתכל על הסימן.
נכתוב את המדידות של חלק אחד כווקטור — רוחב ומשקל. הפרספטרון מחזיק וקטור משקלים והטיה . הציון שלו הוא
והתשובה שלו היא הסימן של הציון הזה: לקבל אם , אחרת לדחות.
זה כל המודל. כל מה שהפרספטרון אי פעם ידע על המפעל חי בשלושה מספרים.
כדאי לעצור רגע על הגאומטריה, כי זו התמונה שממשיכה לעבוד בעשרים ותשעה הפרקים הבאים גם כשהמשוואות כבר לא נכנסות לשורה אחת. קבוצת הנקודות שבהן — המקום שבו הפרספטרון בדיוק לא החליט — היא קו ישר במישור. בצד אחד הציון חיובי והכול מתקבל; בצד השני הוא שלילי והכול נדחה. למידה, עבור פרספטרון, פירושה להזיז את הקו הזה.
שתי עובדות על הקו הזה נובעות ישירות מהאלגברה, ושתיהן יהיו חשובות בהמשך:
- מאונך לו. וקטור המשקלים אינו שוכב לאורך הגבול; הוא מצביע לרוחבו, לכיוון הצד המתקבל.
- מזיז אותו בלי לסובב אותו. בלי הטיה, הקו היה מוכרח לעבור דרך הראשית, וזה אילוץ מגוחך עבור מפעל שמודד מילימטרים וגרמים — המשמעות הייתה שחלק ברוחב אפס ובמשקל אפס יושב בדיוק על הגדר.
כלל הלמידה, ולמה הוא לא צריך חדו״א
קישור למקטע: כלל הלמידה, ולמה הוא לא צריך חדו״אהפרספטרון מתחיל בלי לדעת כלום: ו-. כל ציון הוא אפס, ולכן הוא מקבל הכול.
עכשיו מראים לו דוגמה אחת בכל פעם. מסמנים את החלקים שהתקבלו ב- ואת אלה שנדחו ב-. לכל דוגמה שואלים שאלה אחת: האם הסימן יצא נכון? הדרך הקומפקטית לכתוב את השאלה היא לבדוק אם חיובי — אם התווית והציון מסכימים בסימן, המכפלה שלהם חיובית, ואם הם לא מסכימים היא שלילית.
אם התשובה היא כן, לא משנים כלום. אם התשובה היא לא, נותנים דחיפה קטנה:
זה כל האלגוריתם, וכדאי להבין למה זו הדחיפה הנכונה במקום לשנן אותה. נניח שחלק היה אמור להתקבל () והציון יצא שלילי. הוספת ל- משנה את הציון על אותו חלק עצמו ב-
וזה מספר חיובי. הציון על החלק שבו הוא בדיוק טעה עולה למעלה, וזה הכיוון שאליו הוא היה צריך לזוז. הכלל אינו היוריסטיקה שמישהו ניחש; הוא השינוי הקטן ביותר שמשפר באופן ניתן להוכחה את המקרה שמולו. הוא כמובן עלול לשבור מקרה אחר, ולכן עוברים שוב.
שימו לב למה שחסר. אין כאן נגזרת בשום מקום. זו לא השמטה, וזה הרעיון החשוב באמת הראשון בקורס.
מה שהייתם רוצים לגזור הוא השגיאה — מספר החלקים שסווגו לא נכון. אבל המספר הזה הוא מדרגות: הוא נשאר שטוח על 4 בזמן שמזיזים מעט את הקו, ואז יורד ל-3 ברגע שהקו חוצה נקודה. הנגזרת שלו היא אפס כמעט בכל מקום ולא מוגדרת במדרגות. לחשבון דיפרנציאלי אין במה להיאחז. כלל הפרספטרון עוקף את זה בכך שהוא בכלל לא מבקש שיפוע: הוא שואל רק "נכון או לא נכון?", וזז בכיוון שהוא יכול להצדיק גאומטרית.
זה פתרון אמיתי, וזה גם מבוי סתום. בפרק 2 נרצה פונקציית הפסד שמגיעה ממקום כלשהו ולא פשוט נבחרת, בפרק 4 מודל שמדווח כמה בטוח הוא, ובפרק 5 משהו עם יותר משכבה אחת — ואף אחד מהם לא נגיש מכלל שיודע רק "לא נכון". החזרת שיפוע שימושי היא מה שמכריח את שני הפרקים הבאים. אבל לפרספטרון מותר לעשות משהו שאף אחד מיורשיו לא יכול: ללמוד בלי חדו״א בכלל.
כותבים את זה
קישור למקטע: כותבים את זהPython נקי, בלי NumPy. רשימות ולולאה. NumPy מגיע בפרק הבא, שבו האריתמטיקה כבר לא נכנסת ללולאה שהייתם רוצים לקרוא; להכניס אותו עכשיו היה מסתיר את האריתמטיקה מאחורי ספרייה בדיוק ברגע שבו אתם רוצים לראות אותה.
def score(w, b, x):
return w[0] * x[0] + w[1] * x[1] + b
def predict(w, b, x):
return 1 if score(w, b, x) >= 0 else -1
def train(data, epochs=200):
"""Returns (w, b, epoch_it_converged) — or None for the epoch if it never did."""
w, b = [0.0, 0.0], 0.0
for epoch in range(epochs):
mistakes = 0
for x, y in data:
if y * score(w, b, x) <= 0:
w[0] += y * x[0]
w[1] += y * x[1]
b += y
mistakes += 1
if mistakes == 0:
return w, b, epoch + 1
return w, b, Noneארבע השורות המודגשות הן האלגוריתם. כל השאר הוא ניהול ספרים.
והמסוע, עם שמונה חלקים שנמדדו ממנו — ארבעה שנשלחו וארבעה שחזרו:
BELT = [
((18.0, 47.0), +1), ((19.5, 52.0), +1), ((20.2, 49.0), +1), ((21.0, 55.0), +1),
((24.0, 61.0), -1), ((25.5, 66.0), -1), ((23.0, 70.0), -1), ((26.0, 58.0), -1),
]
w, b, epoch = train(BELT, epochs=200)
print(epoch, w, b)שמונת החלקים האלה כן ניתנים להפרדה בקו ישר — כל חלק שהתקבל הוא מתחת ל-22 מ״מ וכל חלק שנדחה הוא 23 מ״מ או יותר. גדר אנכית ב-22 מילימטרים עושה את העבודה. אז הפרספטרון אמור למצוא אותה.
מריצים:
None [-142.1, -13.0] 54.0מאתיים epochs, 454 תיקונים, והוא לא התכנס. המשקלים גדולים ובסימן הלא נכון. משהו לא בסדר — חוץ מזה ששום דבר לא לא בסדר, והסיבה היא הדבר הכי שימושי בפרק הזה.
משפט ההתכנסות, והמספר שהוא באמת נותן לכם
קישור למקטע: משפט ההתכנסות, והמספר שהוא באמת נותן לכםלפרספטרון יש הבטחה, שנוביקוף הוכיח ב-1962.1 אם אפשר להפריד את הנתונים בקו בכלל, האלגוריתם יבצע לכל היותר
תיקונים לפני שיפסיק לבצע תיקונים — כאשר הוא רדיוס הנתונים, האורך של וקטור הדוגמה הארוך ביותר, ו- הוא ה-margin: המרחק מההיפר-מישור המפריד לנקודה הקרובה ביותר במרחב המורחב שבו ההטיה היא קואורדינטה שלישית. זו הסיבה שמרכוז הנתונים משנה אותו, בעוד שהמרחק במילימטרים לא משתנה.
ההבטחה אינה מותנית והיא לא מזכירה epochs, קצבי למידה או מזל. היא גם לא מזכירה זמן, וההשמטה הזאת היא העניין.
נציב את המספרים שלנו. במדידה ישירה משמונת החלקים, כשההטיה מקופלת פנימה כמאפיין קבוע:
| רדיוס | margin | חסם | תיקונים שבוצעו בפועל | |
|---|---|---|---|---|
| מילימטרים וגרמים גולמיים | 73.69 | 0.045 | 2,633,550 | 29,870 |
| אחרי חיסור הממוצע | 12.82 | 0.989 | 168 | 1 |
המשפט מעולם לא הופר. הריצו את הגרסה הגולמית מספיק זמן והיא כן מתכנסת — ב-epoch 11,976, אחרי 29,870 תיקונים — בנוחות בתוך החסם שלה, 2,633,550, והפער הזה הוא עצמו העניין: המשפט חוסם את המקרה הגרוע ביותר, לא את הטיפוסי. הוא פשוט היה צריך פי שישים יותר epochs ממה שמישהו היה יושב לחכות לו.
השורה השנייה היא אותם שמונה חלקים, אותן עשרים שורות קוד, עם שלוש שורות שנוספו כדי להחסיר את רוחב הממוצע ואת משקל הממוצע מכל מדידה. זהו. זה כל השינוי. הוא מזיז את ענן הנקודות כך שהוא חוצה את הראשית במקום לצוף סביב (22, 57), וההשפעה על החסם היא פקטור של חמישה עשר אלף, כי שני האיברים משתפרים בבת אחת: יורד מ-74 ל-13 כי הנקודות כבר לא נמדדות מראשית רחוקה, ו- עולה מ-0.045 ל-0.989 כי ה-margin נמדד מול וקטור משקלים שכבר לא צריך לשאת הטיה ענקית כדי להגיע לנתונים.
mean_w = sum(x[0] for x, _ in BELT) / len(BELT) # 22.15
mean_g = sum(x[1] for x, _ in BELT) / len(BELT) # 57.25
CENTRED = [(((x[0] - mean_w), (x[1] - mean_g)), y) for x, y in BELT]
w, b, epoch = train(CENTRED, epochs=200)
print(epoch, w, b)2 [-4.15, -10.25] 1.0התכנס בשני epochs, אחרי שתיקן את עצמו בדיוק פעם אחת.
יש כאן שיעור אמיתי, והוא לא "זכרו לנרמל את הקלטים שלכם", אף שכדאי לעשות זאת. הוא שהבטחה לגבי השאלה אם אלגוריתם יסיים לא אומרת לכם כלום לגבי השאלה אם תהיו שם כשהוא יסיים, ושהפער בין השניים הוא בדרך כלל גאומטריה. זו ההופעה הראשונה של דפוס שתפגשו שוב בפרק 6 עם אתחול, בפרק 10 עם לוחות זמנים לקצב למידה, ובפרק 13 עם קוונטיזציה: המתמטיקה אומרת שהדבר אפשרי, וההנדסה מחליטה אם הוא מעשי. קורס שמלמד אתכם רק את המשפט נותן לכם מודל שמתאמן שלושה ימים ומאשים אתכם.
ארבע נקודות, קו אחד, אין פתרון
קישור למקטע: ארבע נקודות, קו אחד, אין פתרוןעכשיו הכישלון שסיים את העידן הראשון של רשתות נוירונים, והוא נכנס בארבע שורות.
עזבו את המפעל. קחו שני קלטים שכל אחד מהם הוא 0 או 1, ובקשו שהתשובה תהיה כאשר בדיוק אחד מהם הוא 1:
| 0 | 0 | |
| 0 | 1 | |
| 1 | 0 | |
| 1 | 1 |
זה XOR — או בלעדי. לפני שממשיכים, ציירו את ארבע הנקודות על נייר: שלוש פינות של ריבוע יחידה ואת הרביעית. סמנו את שתי הפינות האלכסוניות ו- כקבלה, ואת ו- כדחייה. עכשיו ציירו קו ישר אחד עם שתי הנקודות שהתקבלו בצד אחד ושתי הנקודות שנדחו בצד השני.
אי אפשר. זה לא שקשה, או שצריך אלגוריתם חכם יותר; הקו פשוט לא קיים. שלוש שורות של אלגברה מראות למה. אם פרספטרון היה מסווג נכון את כל הארבע, אז קריאת ארבע השורות לפי הסדר נותנת
חברו את שני אי-השוויונים האמצעיים: , ולכן . האחרון אומר . ביחד: , מה שמחייב , מה שמחייב . ואי-השוויון הראשון אומר . אין כזה, ולכן אין משקלים כאלה. שום פרספטרון, עם מספרים כלשהם, לא מסווג XOR.
מריצים בכל זאת, כי לראות אלגוריתם נכשל שווה יותר מלשמוע שהוא ייכשל:
100 epochs -> converged=None w=[0.0, 0.0] b=0.0 correct=2/4
1,000 epochs -> converged=None w=[0.0, 0.0] b=0.0 correct=2/4
100,000 epochs -> converged=None w=[0.0, 0.0] b=0.0 correct=2/4הוא לא מתבדר, והוא לא משתולל ליד תשובה סבירה. הוא מחזורי: הוא הולך בלולאה קצרה במרחב המשקלים וחוזר בדיוק למקום שבו התחיל, לנצח, עם שתיים מתוך ארבע נכונות — מה שהייתם מקבלים בניחוש. מאה אלף epochs ומאה נראים אותו דבר, כי האלגוריתם לא מתקדם באופן שריצה ארוכה יותר יכולה להשלים. השוו זאת למסוע, שנראה תקוע ב-200 epochs ולמעשה חרק בדרכו לתשובה אמיתית. מבחוץ השניים נראים דומים בשניות הראשונות. להבדיל ביניהם, בלי המשפט, בלתי אפשרי — וזה עוד טיעון בעד להכיר את המשפט.
מה מינסקי ופייפרט באמת אמרו
קישור למקטע: מה מינסקי ופייפרט באמת אמרוב-1969 פרסמו מרווין מינסקי וסימור פייפרט את Perceptrons, מחקר מתמטי באורך ספר על בדיוק מה המודל הזה יכול ולא יכול לייצג.2 XOR הוא התוצאה המצוטטת ביותר שלו, והציטוט בדרך כלל משמש כהאשמה: שהספר הרג את המחקר ברשתות נוירונים לחמש עשרה שנה מתוך יריבות או זדון.
המתמטיקה בספר נכונה, והיא מעניינת יותר מדוגמת XOR. מינסקי ופייפרט לא התעניינו בעיקר בשאלה אם פרספטרון יחיד יכול לבצע XOR; הם התעניינו במה שקורה כאשר לפרספטרונים נותנים שדות קליטה מוגבלים — כל יחידה רואה רק חלק מהקלט — והם הוכיחו שתכונות גלובליות מסוימות של תמונה, למשל האם צורה מחוברת, לא ניתנות לחישוב כך בלי קשר למספר היחידות שבהן משתמשים. זו תוצאה עמוקה באמת על מקומיות, ואין לה שום קשר לסיפור הפופולרי.
הסיפור הפופולרי גם שגוי היסטורית. מינסקי ופייפרט דנים במפורש בפרספטרונים מרובי שכבות ואומרים ששאלת הכוח שלהם פתוחה — הם חשדו שהרחבת התאוריה תהיה "עקרה", וזו תחזית, לא הוכחה, והיא הייתה שגויה. מה שהיה חסר ב-1969 לא היה רעיון ערימת השכבות; זו הייתה דרך לאמן ערימה. כלל הפרספטרון לא יכול לעשות זאת: הוא צריך לדעת עד כמה כל יחידה טועה, וליחידה שקבורה באמצע אין תווית להשוות מולה. הפער הזה נשאר פתוח עד ש-backpropagation נהפך לנפוץ ב-1986,3 וסגירתו היא מה שפרק 5 עושה.
אז הסיכום ההוגן הוא זה. הספר הוכיח מגבלה אמיתית של מודל אמיתי. לקריסת המימון של התחום בשנות השבעים היו סיבות רבות, שאחת מהן הייתה שההבטחות שניתנו לפרספטרונים בתחילת שנות השישים היו מופרזות. והמכשול הטכני היה פתיר, אבל לאף אחד עדיין לא היה הכלי.
מה שרד
קישור למקטע: מה שרדהפרספטרון בן שישים ושמונה, והרגע כתבתם אחד. כדאי לדייק אילו חלקים ממנו עדיין נמצאים במכונה שתסיימו איתה את הקורס, כי התשובה היא: יותר ממה שהייתם מנחשים.
עדיין כאן. הצורה — להכפיל במשקלים, לסכום, להוסיף הטיה, להפעיל פונקציה לא לינארית על התוצאה — היא בדיוק הצורה של יחידה אחת בכל רשת נוירונים בקורס הזה, כולל אלה שבתוך בלוק transformer בפרק 9. כלל העדכון-על-טעות הוא stochastic gradient descent בתחפושת: זה בדיוק מה שמקבלים כשמיישמים את השיטה של פרק 3 על פונקציית הפסד מסוימת. אימון הדרגתי — קומץ דוגמאות בכל פעם במקום כל מערך הנתונים בבת אחת — נשאר הדרך שבה מודלים מאומנים היום בכל קנה מידה. פרק 3 מודד איפה בדיוק נמצאת הפשרה הזאת.
נעלם. הסף עצמו: מוחלף בפרק 4 בפונקציה שמוציאה הסתברות במקום פסק דין, כי "דחה" ו-"דחה, אבל זה היה קרוב" הם פיסות מידע שונות והסימן זורק את ההבדל. השכבה היחידה, מוחלפת בפרק 5. וגם מאפיינים שנבחרו ידנית: מישהו בחר רוחב ו-משקל למסוע הזה, והבחירה הזאת עשתה יותר עבודה מהאלגוריתם. פרק 8 הוא המקום שבו המודל מתחיל לבחור את שלו.
לאן ממשיכים מכאן
קישור למקטע: לאן ממשיכים מכאןהפרספטרון נתקע על שני דברים בבת אחת, ומתברר שהם אותו הדבר.
הוא לא יכול לייצג XOR, כי קו אחד לא מספיק. כדי לתקן את זה צריך לערום שכבות — שכבה ראשונה שמכופפת את המרחב, שכבה שנייה שמציירת את הקו במרחב המכופף. זה פרק 5.
אבל אי אפשר לאמן ערימה עם כלל הפרספטרון, כי הוא יודע רק "לא נכון", וליחידה באמצע רשת אין תווית משלה שעליה היא יכולה לטעות. כדי לאמן ערימה צריך לדעת כמה לא נכון, ובאיזה כיוון, עבור כל משקל — צריך שיפוע. ולפונקציית השגיאה של הפרספטרון, גרם המדרגות, אין כזה.
אז לפני הערימה חייבת להיות פונקציית הפסד עם נגזרת שימושית. וגם לא כזו שנבחרה כי נוח לגזור אותה: כזו שמגיעה ממקום כלשהו, שאומרת משהו אמיתי על הנתונים, ושהגרדיאנט שלה נובע מהמשמעות הזאת במקום להיות מהונדס לאחור כדי להיראות מסודר.
זה פרק 2, והוא מתחיל בשאלה שהפרספטרון מעולם לא היה צריך לענות עליה: לא "האם החלק הזה טוב?", אלא "עד כמה סבירות המדידות האלה, אם זו האמת?"
מקורות ושיטה
קישור למקטע: מקורות ושיטהכדאי לקרוא לצד הפרק הזה גם את המאמר המקורי של רוזנבלט, The Perceptron: A Probabilistic Model for Information Storage and Organization in the Brain (Psychological Review 65(6), 1958), שהוא קריא יותר מהמוניטין שלו; את McCulloch and Pitts, A Logical Calculus of the Ideas Immanent in Nervous Activity (Bulletin of Mathematical Biophysics 5, 1943), המאמר שמידל לראשונה נוירון כסף מעל סכום משוקלל; את פרק הפרספטרון ב-A Course in Machine Learning של Hal Daumé III, שמגזר את אותו עדכון עם דגש אחר; ואת פרקים 2 ו-3 ב-Mathematics for Machine Learning של Deisenroth, Faisal and Ong לאלגברה הלינארית, אם התיבה למעלה השאירה אתכם רוצים יותר ממה שנתנה.
הפניות
קישור למקטע: הפניות-
Novikoff, A. B. J. On convergence proofs for perceptrons. Proceedings of the Symposium on the Mathematical Theory of Automata, vol. 12, pp. 615–622 (Polytechnic Institute of Brooklyn, 1962). הניסוח וההוכחה המקוריים של חסם הטעויות ששימש למעלה. ↩
-
Minsky, M. and Papert, S. Perceptrons: An Introduction to Computational Geometry (MIT Press, 1969; expanded edition 1988). תוצאת XOR היא אלמנטרית; התוצאות המהותיות עוסקות בפרדיקטים מוגבלי-סדר ובקישוריות. ↩
-
Rumelhart, D. E., Hinton, G. E. and Williams, R. J. Learning representations by back-propagating errors. Nature 323, pp. 533–536 (1986). ↩