Unsupervised Learning

הכרות פרקטית ל Machine Learning מומחשת עם בעיה מהעולם הפיננסי

מיועד ל- מתחילים (כתבה קצת טכנית)

נכתב על ידי תמיר נווה

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

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

נניח שיש לנו מאפיינים של לקוח בבנק שמבקש הלוואה ועלינו להחליט אם כדי לאשר לו הלוואה או לא. המאפיינים הינם בין השאר: גובה ההלוואה המבוקשת, יש\אין משכנתא על הבית, הכנסה שנתית, ועוד ועוד… (סה”כ 86 מאפיינים כפי שנראה בהמשך בדוגמת הקוד)

אילו היינו מנסים לנבא את סיכוי החזר ההלוואה שלא באמצעות Machine Learning היינו בונים כנראה כמה תנאים המבוססים על הידע שלנו כבני אדם או יותר טוב כאנשי מקצוע פיננסיים. (מה שנקרא Feature Engineering)

למשל: אם גובה ההלוואה גדול מ 100,000 ש”ח וההכנסה השנתית של מבקש ההלוואה קטנה מ 80,000 ש”ח אז הסיכוי 0.5, אחרת הסיכוי תלוי גם במאפיינים נוספים ולכן נבדוק גם את ממוצע עיסקאות האשראי ואז אם…

ז”א אנחנו נבנה מן סט של תנאים המבוססים על הידע שלנו כדי לנבא יכולת החזר הלוואה.

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

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

כשמאמנים מודל Machine Learning על Database שכזה זה נקרא Supervised Learning (לימוד מפוקח) כיוון שאנחנו כאילו “מפקחים” על המודל בזמן הלמידה. אם אלו המאפיינים של מבקש ההלוואה אזי זה מה שקרה איתו (החזיר\לא החזיר את ההלוואה). אילו היו בידינו את המאפיינים ולא את התוצאה (החזיר\לא החזיר) אז היינו בעולם ה Unsupervised Learning.

בעולם ה Supervised Learning (ז”א כשיש לנו את התשובות הנכונות) ישנם מודלים רבים המסוגלים ללמוד את הנתונים ואז לקבל נתונים חדשים (קרי מבקש הלוואה חדש שאיננו יודעים אם אכן יחזיר או לא) ואז המודל ינבא את יכולת ההחזר הלוואה שלו. כמובן יש מודלים המצליחים יותר ויש פחות – אין כמעט אף פעם 100% הצלחה. אבל אם מודל מאומן מנבא בהצלחה של נניח 70% זה כבר עשוי לחסוך כסף רב לבנק. (בטח לעומת החלופה של לאשר לכולם הלוואה)

אז כעת נכיר שני מודלים פשוטים ופופולאריים בעולם ה Supervised learning שנקראים KNN ו Logistic Regression. אך לפני זה נכתוב בצורה מפורשת איך נראים הנתונים שלנו.

הכרת הנתונים

כאמור בדוגמה שלנו הנתונים שלנו הם אוסף של מבקשי הלוואות ולכל אחד מהם 86 מאפיינים (את זה נהוג לסמן ב X1,X2,X3,…,X86 או פשוט כוקטור X) ולכל מבקש הלוואה כזה את התשובה הנכונה (שנקראת ה label ואותה נהוג לסמן ב Y) ז”א האם החזיר את ההלוואה (ניתן לזה ערך 1) או לא החזיר את ההלוואה (ניתן לזה ערך 0). הטבלה הבאה ממחישה נתונים לדוגמא:

משכורת חודשית (X1)גובה משכנתא (X2)גיל (X3)ותק בבנק (X86)החזיר\לא החזיר (Y)
10,000350,000374.51
17,00004121
13,000100,0003530

מודל KNN

השם המלא של המודל הינו K Nearest Neighbor והשם מלמד על הרעיון שבו: ניבוי באמצעות הצבעה של K דוגמאות דומות לדוגמה הנבדקת.

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

נקבע את K  להיות ערך שלם כלשהוא, נניח 5.

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

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

למי שקצת יודע לכתוב קוד אז פייתון היא שפת התיכנות אולי הכי פופולארית בעולם ה Machine Learning וספציפית יש חבילה שנקראת Sklearn שבה ממומש KNN ועוד מודלים רבים של Machine Learning.

אז שתי שורות קוד מבצעות את הרעיון הנ”ל:

model = KNeighborsClassifier(n_neighbors=5)

model.fit(x, y)

אותו K ממקודם נקרא מספר השכנים n_neighbors השכנים, הנתונים שברשותינו נקראים x והתשובות הנכונות שברשותינו נקראים y.

שתי שורות הקוד הנ”ל הם ההכנה ונקראות התאמת או אימון המודל לנתונים. ושורת הקוד הבאה משתמשת במודל המאומן כדי לנבא החזר או אי החזר הלוואה על מבקש הלוואה חדש x_new:

model.predict(x_new)

מודל Logistic Regression

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

logistic regression

(אקספוננט של צירוף לינארי על הנתונים עם מקדמים β‘s ייתן את היחס בין ההסתברות להחזר ההלוואה לבין אי החזר ההלוואה)

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

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

ושוב ניתן להשתמש בזה באופן דומה למקודם באמצעות שתי שורות קוד בפייתון (עם חבילת Sklearn), אימון המודל (קרי מציאת המקדמים על בסיס נתונים ולייבלים קיימים x,y):

()model = LogisticRegression

model.fit(x, y)

ושימוש במודל כדי לנבא יכולת החזר של מבקש הלוואה חדש:

model.predict(x_new)

דוגמת קוד

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

להלן עיקרי הקוד עם הסברים:

  1. חבילות פייתון שיש להשתמש בהם

import pandas as pd

from sklearn.preprocessing import StandardScaler

from sklearn.linear_model import LogisticRegression

from sklearn.neighbors import KNeighborsClassifier

2. טעינת הנתונים

train_df = pd.read_csv(Path(‘2019loans.csv’))

test_df = pd.read_csv(Path(‘2020Q1loans.csv’))

טכניקה שקיימת בכל עולם ה Machine Learning הינה פיצול הנתונים שלנו לשתי קבוצות:  קבוצת האימון (train) וקבוצת הבדיקה\ואלידציה (test).

בנתונים מקבוצת האימון נשתמש לאמן את המודל ובנתונים מקבוצת הבדיקה נשתמש לבחון את הצלחת המודל המאומן.

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

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

3. שליפת הנתונים והלייבלים

הנתונים שלנו לקוחים מקבצי אקסל ועלינו להפריד בין מאפייני מבקשי ההלוואות (x) לבין התשובה הנכונה (ה label שלהם) ז”א האם אישרו להם הלוואה בסופו של דבר או לא  (y).

y_train = train_df[“loan_status”]                       # Take target feature for training data

X_train = train_df.drop(columns = [“loan_status”])      # Drop target from training data

:Same for testing #

y_test = test_df[“loan_status”]

X_test = test_df.drop(columns = [“loan_status”])

4. המרת משתנים קטגוריאליים

חלק מאותם 86 מאפיינים לכל מבקש הלוואה אינם משתנים מספריים אלא קטגוריאליים. ז”א הערך הוא אחד מבין כמה ערכים מוגדרים מראש. למשל מאפיין בעלות הבית (home_ownership) הינו אחד מבין: MORTGAGE, OWN  או RENT.

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

X_train = pd.get_dummies(X_train) 

X_test = pd.get_dummies(X_test)

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

home_ownershiphome_ownership_RENThome_ownership_MORTGAGEhome_ownership_OWN
RENT100
MORTGAGE010
OWN001

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

5. נירמול הנתונים

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

הסיבות לזה הם בעיקר נומריות, והנירמול גורם למודלים רבים להתכנס יותר טוב:

()scaler = StandardScaler

scaler.fit(X_train)

X_train_scaled = scaler.transform(X_train)

X_test_scaled = scaler.transform(X_test)

6. אימון המודלים ובדיקתם

נתחיל במודל KNN כפי שראינו מקודם, הגדרת המודל:

model = KNeighborsClassifier(n_neighbors=12)

אימון המודל:

model.fit(X_train_scaled, y_train)

בדיקת המודל על קבוצת האימון:

train_accuracy = model.score(X_train_scaled, y_train)

ויותר חשוב מזה, בדיקת המודל על קבוצת הבדיקה:

test_accuracy = model.score(X_test_scaled, y_test)

ובאותו אופן מודל ה Logistic Regression הגדרה, אימון ובדיקות:

model = LogisticRegression(max_iter=1000)

model.fit(X_train_scaled, y_train)

train_accuracy = model.score(X_train_scaled, y_train)

test_accuracy = model.score(X_test_scaled, y_test)

7. תוצאות הבדיקות

תוצאות מודל KNN הינן:

Train Accuracy: 0.708128078817734

Test Accuracy: 0.5133985538068907

דיוק הפרדיקציה (הסתברות החזר ההלוואה) בקבוצת האימון הינה בערך 70% ובקבוצת הבדיקה 51%. ז”א שהמודל אכן למד משהו (כי 70% הצלחה זה לא מקרי) אבל זה לא עוזר לנו בכלום כי על מבקשי הלוואה אחרים שלא השתמשנו בהם באימון הוא כלל לא מצליח (מצליח ב 50% שזה כמו לנחש סתם).

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

לעומת זאת, תוצאות מודל ה Logistic Regression הינן:

Train Accuracy: 0.7128899835796387

Test Accuracy: 0.7205444491705657

וכאן התוצאות טובות יותר, אומנם גם סביבות ה 70% הצלחה אבל גם על קבוצת האימון וגם על קבוצת הבדיקה, מה שאומר שהמודל גם יחסית מצליח על דוגמאות שלא “ראה” בזמן האימון.

בזאת סיימתי לתת כניסה קלה ופרקטית לעולם ה Machine Learning, אם היה מוצלח ומועיל בעינכם ותרצו עוד כאלו, מוזמנים להגיב בהתאם 😊

Posted by תמיר נווה in deep

מהו Variational AutoEncoders?

מיועד ל- מטיבי לכת (כתבה מאוד טכנית)

נכתב על ידי avraham raviv

כדי להבין היטב את אופן הפעולה של Variational Autoencoders (VAE), נדבר מעט על הורדת מימדים, לאחר מכן נסביר מהו Autoencoders, כיצד הוא עובד ומה החסרונות שלו, ומשם נעבור ל-VAE.

Dimensionality Reduction

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

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

תהליך האימון הוא דו שלבי: דאטה x\in R^{n} עובר דרך encoder, ולאחריו מתקבל e(x)\in R^{m} , כאשר m<n לאחר מכן התוצאה מוכנסת ל-decoder בכדי להחזיר אותה למימד המקורי, ולבסוף מתקבל d(e(x)) \in R^{^{n}} אם לאחר התהליך מתקיים x=d(e(x)) אז למעשה לא נאבד שום מידע בתהליך, אך אם לעומת זאת x\neq d(e(x)) אז מידע מסוים אבד עקב הורדת המימד ולא היה ניתן לשחזר אותו במלואו בפענוח. באופן אינטואיטיבי, אם אנו מצליחים לשחזר את הקלט המקורי מהייצוג של במימד נמוך בדיוק טוב מספיק, כנראה שהייצוג במימד נמוך הצליח להפיק את הפיצ’רים המשמעותיים של הדאטה המקורי.

 

איור 1. ארכיטקטורת encoder ו-decoder.

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

(e^{*},d^{*})=\underset{(e,d)\in ExD}{argmin}\epsilon (x,d(e(x)))

כאשר \epsilon (x,d(e(x))) הוא שגיאת השחזור שבין הדאטה המקורי לבין הדאטה המשוחזר.

אחת השיטות השימושיות להורדת מימד שאפשר להסתכל עליה בצורה הזו היא Principal Components Analysis (PCA). בשיטה זו מטילים (בצורה לינארית) דאטה ממימד n למימד m על ידי מציאת בסיס אורתוגונלי במרחב ה-m מימדי בו המרחק האוקלידי בין הדאטה המקורי לדאטה המשוחזר מהייצוג החדש הוא מינימלי.

איור 2. דוגמא להורדת מימד בשיטת PCA.

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

Autoencoders (AE)

ניתן לקחת את המבנה של ה- encoder-decoder המתואר בפרק הקודם ולהשתמש ברשת נוירונים עבור בניית הייצוג החדש ועבור השחזור. מבנה זה נקרא Autoencoder:

איור 3. Autoencoder – שימוש ברשתות נוירונים עבור הורדת המימד והשחזור.

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

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

איור 4. דוגמא לשימוש ב-Autoencoder.

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

Variational AutoEncoders (VAE)

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

כדי להתמודד עם בעיה זו, ניתן להשתמש ב-Variational AutoEncoders (VAE). בשונה מ-AE שלוקח דאטה ובונה לו ייצוג ממימד נמוך, VAE קובע התפלגות פריורית למרחב הלטנטי z – למשל התפלגות נורמלית עם תוחלת 0 ומטריצת  II covariance. בהינתן התפלגות זו, ה-encoder מאמן רשת המקבלת דאטה x ומוציאה פרמטרים של התפלגות פוסטריורית z|x , מתוך מטרה למזער כמה שניתן את ההפרש בין ההתפלגויות z ו- z|x . לאחר מכן דוגמים וקטורים מההתפלגות הפוסטריורית z|x (הנתונה על ידי הפרמטרים המחושבים ב-encoder), ומעבירים אותם דרך ה-decoder כדי לייצר פרמטרים של ההתפלגות z|x . חשוב להבהיר שאם הדאטה המקורי הוא תמונה המורכבת מאוסף של פיקסלים, אזי במוצא יתקבל x|z לכל פיקסל בנפרד ומההתפלגות הזו דוגמים נקודה והיא תהיה ערך הפיקסל בתמונה המשוחזרת. באופן הזה, הלמידה דואגת לא רק להורדת המימד, אלא גם להתפלגות המושרית על המרחב הלטנטי. כאשר ההתפלגות המותנית במוצא x|z טובה, קרי קרובה להתפלגות המקורית של x, ניתן בעזרתה גם ליצור דוגמאות חדשות, ובעצם מתקבל מודל גנרטיבי. כאמור, ה-encoder מנסה לייצג את הדאטה המקורי באמצעות התפלגות במימד נמוך יותר, למשל התפלגות נורמלית עם תוחלת ומטריצת covariance:z\sim p(z|x)=N(\mu _{z},\sigma _{x})

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

 

איור 5. ארכיטקטורה של VAE.

לאחר שהוצג המבנה הכללי של VAE, ניתן לתאר את תהליך הלמידה, ולשם כך נפריד בשלב זה בין שני החלקים של ה-VAE. ה-encoder מאמן רשת שמקבלת דוגמאות מסט האימון, ומנסה להפיק מהן פרמטרים של התפלגות  הקרובים כמה שניתן להתפלגות פריורית , שכאמור נקבעה מראש. מההתפלגות הנלמדת הזו דוגמים וקטורים חדשים ומעבירים ל-decoder. ה- decoderמבצע את הפעולה ההפוכה – לוקח וקטור שנדגם מהמרחב הלטנטי , ומייצר באמצעותו דוגמא חדשה הדומה לדאטה המקורי. תהליך האימון יהיה כזה שימזער את השגיאה של שני חלקי ה-VAE – גם  שבמוצא יהיה כמה שיותר קרוב ל- המקורי, וגם ההתפלגות  תהיה כמה שיותר קרובה להתפלגות הפריורית z. נתאר באופן פורמלי את בעיית האופטימיזציה ש-VAE מנסה לפתור. נסמן את הווקטורים של המרחב הלטנטי ב-z, את הפרמטרים של ה-decoder ב-\theta , ואת הפרמטרים של ה-encoder ב-\lambda. כדי למצוא את הפרמטרים האופטימליים של שתי הרשתות, נרצה להביא למקסימום את p(\widehat{x}=x;\theta) , כלומר למקסם את הנראות המרבית של סט האימון תחת \theta . כיוון שפונקציית log מונוטונית, נוכל לקחת את לוג ההסתברות:

L(\theta)=log(p(x;\theta ))

אם נביא למקסימום את הביטוי הזה, נקבל את ה- \theta האופטימלי. כיוון שלא ניתן לחשב במפורש את p(x;\theta ) , יש להשתמש בקירוב. נניח וה -encoder הוא בעל התפלגות מסוימת q(z;\lambda ) (מה ההסתברות לקבל את z בהינתן x  בכניסה). כעת ניתן לחלק ולהכפיל את L(\theta )ב – q(z;\lambda ):

log[p(x;\theta )]=log \underset{z}{\Sigma}p(x,z;\theta )=log\underset{z}{\Sigma}q(z;\lambda )\frac{p(x,z;\theta)}{q(z;\lambda)}\geqslant \underset{z}{\Sigma}q(z;\lambda)log\frac{p(x,z_{i};\theta)}{q(z;\lambda)}

כאשר אי השוויון האחרון נובע מאי-שוויון ינסן, והביטוי שמימין לאי השיוויון נקרא Evidence Lower BOund ELBO(\theta,\lambda). ניתן להוכיח שההפרש בין ה-ELBO לבין הערך שלפני הקירוב הוא המרחק בין שתי ההתפלגויות p(z|x),q(z) , והוא נקרא Kullback–Leibler divergence ומסומן ב- D_{KL}:

log[p(x;\theta)]=ELBO(\theta,\lambda)+D_{KL}(q(z;\lambda)||p(z|x;\theta))

אם שתי ההתפלגויות זהות, אזי מרחק D_{KL} ביניהן הוא 0 ומתקבל שוויון: log[p(x;\theta)]=ELBO(\theta,\lambda) . כזכור, אנחנו מחפשים למקסם את פונקציית המחיר log[p(x;\theta)] , וכעת בעזרת הקירוב ניתן לרשום:

L(\theta)=log[p(x;\theta)]\geqslant ELBO(\theta,\lambda)

\rightarrow \theta_{ML}=arg\underset{\theta}{max}L(\theta)=arg\underset{\theta}{max}\underset{\lambda}{max}ELBO(\theta,\lambda)

כעת ניתן בעזרת שיטת GD למצוא את האופטימום של הביטוי, וממנו להפיק את הפרמטרים האופטימליים של ה-encoder ושל ה-decoder. נפתח יותר את ה-ELBO(\theta,\lambda) עבור VAE, ביחס לשתי התפלגויות: p(x|z;\theta) – ההסתברות ש-decoder עם סט פרמטרים \theta יוציא x  בהינתן z. q(z|x;\lambda) – ההסתברות ש-encoder עם סט פרמטרים \lambda יוציא את z_{i} בהינתן x בכניסה לפי הגדרה:

ELBO(\theta, \lambda)=\underset{z}{\Sigma}q(z|x;\lambda)log[p(x,z;\theta)]-\underset{z}{\Sigma}q(z|x;\lambda)log[q(z|x;\lambda)

את הביטוי log[p(x,z;\theta)] ניתן לפתוח לפי בייס:

p(x,z)=p(x|z)\cdot p(z)

={\underset{z }{\sum}}q(z|x;\lambda)(log[p(x|z;\theta)]+log[p(z;\theta))])-{\underset{z }{\sum}}q(z|x;\lambda)log[q(z|x;\lambda)]

={\underset{z }{\sum}}q(z|x;\lambda)(log[p(x|z;\theta)]-{\underset{z }{\sum}}q(z|x;\lambda)(log[q(z|x;\lambda)]-log[p(z;\theta)])

={\underset{z }{\sum}}q(z|x;\lambda)(log[p(x|z;\theta)]-{\underset{z }{\sum}}q(z|x;\lambda)\frac{log[q(z|x;\lambda]}{log[p(z;\theta]}])

הביטוי השני לפי הגדרה שווה ל-D_{KL}(q(z|x;\lambda)||p(z;\theta)), לכן מתקבל:

=\underset{z}{\sum}q(z|x;\lambda)log[p(x|z;\theta)]-D_{KL}(q(z|x;\lambda)||p(z))

הביטוי הראשון הוא בדיוק התוחלת של log[p(x|z;\theta)]. תחת ההנחה ש-z מתפלג נורמלית, ניתן לרשום:

=E_{q(z|x;\lambda)}logN(x;\mu_{\theta}(z),\sigma_{\theta}(z))-D_{kl}(N(\mu_{\lambda}(x),\sigma_{\lambda}(x))||N(0,I)))

כדי לחשב את התוחלת ניתן פשוט לדגום דוגמאות מההתפלגות z|x\sim N(\mu_{\theta}(x),\sigma_{\theta}(x))) ולקבל:

E_{q(z|x;\lambda)}logN(x;\mu_{\theta}(z),\sigma_\theta(z))\approx logN(x;\mu_{\theta}(z),\sigma_{\theta}(z))

ועבור הביטוי השני יש נוסחה סגורה:

D_{KL}(N(\mu,\sigma^{2})||N(0,I))=\frac{1}{2}(\mu^2+\sigma^2-log \sigma^2)

כעת משיש בידינו נוסחה לחישוב פונקציית המחיר, נוכל לבצע את תהליך הלמידה. יש לשים לב שפונקציית המחיר המקורית הייתה תלויה רק ב-\theta, , אך באופן שפיתחנו אותה היא למעשה דואגת גם למזעור ההפרש בין הכניסה למוצא, וגם למזעור ההפרש בין ההתפלגות הפריורית z לבין ההתפלגות z|x שבמוצא ה-encoder.

איור 6. תהליך הלמידה של VAE.

כאשר נתון סט דוגמאות , ניתן להעביר כל דוגמא x_{t} ב-encoder ולקבל עבורה את \mu _{\lambda },\sigma _{\lambda }. לאחר מכן דוגמים וקטור לטנטי z מההתפלגות עם פרמטרים, מעבירים אותו ב-decoder ומקבלים את \inline \mu _{\theta},\sigma _{\theta}. לאחר התהליך ניתן להציב את הפרמטרים המתקבלים ב-ELBO ולחשב את ה-Loss. ניתן לשים לב שה-ELBO מורכב משני איברים – האיבר הראשון מחשב את היחס בין הדוגמא שבכניסה לבין ההתפלגות שמתקבלת במוצא, והאיבר השני מבצע רגולריזציה להתפלגות הפריורית במרחב הלטנטי. הרגולריזציה גורמת לכך שההתפלגות במרחב הלטנטי z|x תהיה קרובה עד כמה שניתן להתפלגות הפריורית z. אם ההתפלגות במרחב הלטנטי קרובה להתפלגות הפריורית, אז ניתן בעזרת ה-decoder ליצור דוגמאות חדשות, ובמובן הזה ה-VAE הוא מודל גנרטיבי.

הדגימה של z מההתפלגות במרחב הלטנטי יוצרת קושי בחישוב הגרדיאנט של ה-ELBO, לכן בדרך כלל מבצעים Reparameterization trick – דוגמים z_{0} מהתפלגות נורמלית סטנדרטית, ואז כדי לקבל את z משתמשים בפרמטרים של ה-encoder:

z=z_{0}\sigma _{\lambda}(x)+\mu _{\lambda }(x)

.forward-backwardבגישה הזו כל התהליך נהיה דטרמיניסטי – מגרילים מראש z_{0} ואז רק נשאר לחשב באופן סכמתי את ה

 

Reference:

https://towardsdatascience.com/understanding-variational-autoencoders-vaes-f70510919f73

 

Posted by avraham raviv in deep

למידה לא מונחית לשערוך עומק לתמונה – Unsupervised Learning for Depth Estimation

מיועד ל- כל אחד (כתבה לא טכנית)

נכתב על ידי TzviLederer

תחומים במערכות לומדות

נהוג לחלק את עולם ה-machine learning לשלושה תחומים – למידה מונחית (supervised learning), למידה לא-מונחית (unsupervised learning) ולמידה בעזרת חיזוקים (reinforcement learning). ההבדל הבסיסי בין התחומים הוא סוג המידע בו משתמשים. בלמידה מונחית יש לנו גישה למידע מתוייג, למשל במטלה של זיהוי וסיווג אובייקטים בדרך כלל אנו מחזיקים בתמונות מתוייגות (בין אם מדובר בתיוג של כל התמונה, Bounding box, תמונות סגמנטציה וכדו’). למידה לא מונחית היא למידה בעזרת מידע ללא תיוג, הוצאת תובנות או מידע שלא נגיש לנו בעזרת הרבה מידע אך ללא ידע מקדים עליו. דוגמה קלאסית לזה היא אישכול (clustering) של וקטורים, כלומר חלוקה של דגימות לקבוצות בעלות משמעות (למשל חלוקה של כתבות באתר חדשות לפי נושאים בצורה אוטומטית). למידה באמצעות חיזוקים היא למידה של קבלת החלטות נכונה כאשר המשוב יכול להגיע גם באיחור, כלומר יכול להיות שיעבור זמן עד שנדע האם צדקנו בקבלת ההחלטות שלנו או לא. דוגמאות קלאסיות לאתגרים בתחום זה הם אלגוריתם המשחק במשחק מחשב, בו השחקן יכול לבחור בכל שלב איך לפעול אך לעיתים הוא ידע אם קבלת ההחלטות שלו הייתה נכונה רק בשלב מאוחר יותר (אם ינצח את השלב או יפסיד בו).

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

תמונות סטריאו

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

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

לקוח מ https://stackoverflow.com/questions/17607312/difference-between-disparity-map-and-disparity-image-in-stereo-matching

רשת בלתי מונחית (Unsupervised) לחישוב עומק

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

השיטה ה”נאיבית” היא ליצור dataset של תמונות סטריאו ומפות הפרשים וללמד את הרשת לחזות את מפת ההפרשים של התמונה על פי מפות ההפרשים שחישבנו בשיטות הקלאסיות. הבעיה העיקרית היא שאין כל כך הרבה data לאימון. בנוסף האלגוריתמים הקלאסיים לחישוב מפת הפרשים לא מושלמים ולכן קשה ליצור דאטאסטים גדולים עם תמונות עומק באיכות טובה בכמות מספקת לאימון. וכאן נכנסת שיטה נוספת – שיטה שמשתמשת בלמידה לא מונחית!

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

סיכום

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

מאמר בנושא:

https://arxiv.org/pdf/1609.03677.pdf

Posted by TzviLederer