טכני קל

ייצור דאטה טבלאי ע”י שימוש ב- Conditional Tabular GAN

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

נכתב על ידי yuval schreiber

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

דאטה טבלאי

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

הגדרת הבעיה- נניח דאטה טבלאי T שמכיל Nd עמודות בדידות ו-Nc עמודות רציפות, המטרה הינה לאמן מחולל G ללמוד לייצר דאטה טבלאי סינתטי מ-T שיקרא Tsyn
כדי להעריך את ביצועי המחולל מפצלים את T לאימון ומבחן, ובוחנים שני היבטים:

  1. התאמת הנתונים ב- Tsyn להתפלגות הנתונים ב- Ttrain
  2. השוואת מודל סיווג/רגרסיה מאומן על Tsyn עם מודל מאומן על Ttrain, מבחינת ביצועים על Ttest

GANGenerative Adversarial Network

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

התאמות שנעשות ב-CTGAN

השימוש ב-GAN רגיל לייצור דאטה טבלאי יוצר שתי בעיות שההתאמות ב-CTGAN באות לפתור:

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

לכל משתנה רציף תחילה מתאימים VGM (variational Gaussian mixture model), GM רגיל מנסה למצוא את k הגאוסיאנים שמייצגים הכי טוב את הנתונים דרך שימוש ב-EM, לעומת זאת VGM-ים יכולים להחליט מהו ה-k הכי מתאים לנתונים דרך סף משקולות.
לאחר שנמצאו k (בדוגמה מעלה k=3) ההתפלגויות שממדלות הכי טוב את המשתנה הרציף (בדוגמה מעלה עמודה i), מעריכים את ההסתברויות (בדוגמה מעלה ρ1,ρ23) להשתייכות הדגימה (בדוגמה מעלה j) לכל אחת מההתפלגויות, מהן דוגמים את ההתפלגות הנבחרת (מסומנת ב- β), ואז מייצגים את ערך הדגימה בתוך ההתפלגות שלה (כמה היא חשובה בתוך הגאוסיאן שלה) ע״י שימוש ב-α , כאשר η הינו השכיח ו-φ הינה סטיית התקן של ההתפלגות.
כעת עבור כל דגימה המודל יקבל במקום הערכים הרציפים,שרשור של α ו-β  של כל העמודות הרציפות, עם וקטורי האחד חם של העמודות הבדידות.

2. דגימה הוגנת של משתנים בדידים– באימון GAN רעש הקלט מיוצר מהתפלגות פריורית (לרוב גאוסיאנית מרובת משתנים), דגימה זו עבור משתנים בדידים עשויה להחמיץ מידע על התפלגותם ולשמר את חוסר האיזון בדאטה, נרצה לבצע דגימה מחדש בדרך שמאפשרת דגימה שווה בין ערכים דיסקרטיים שונים בזמן האימון, ושחזור ההתפלגות האמיתית בזמן המבחן.
הפתרון המוצע מורכב מ-3 אלמנטי מפתח:
a. וקטור מותנה– וקטור אשר מכיל מידע על המשתנים הבדידים, ומשתמשים בו כדי לכפות על המחולל לייצר דגימות משתנים בדידים עם התפלגות דומה לנתוני האימון.
הוקטור מכיל שרשור של כל וקטורי אחד חם של העמודות הבדידות, כך שכל הערכים הינם 0 מלבד קטגוריה אחת מאחת העמודות הבדידות, והוא מאלץ את המחולל לייצר דגימה מקטגוריה נבחרת זו.
b. הפסד המחולל– כדי לוודא שהאילוץ אכן מתקיים מענישים את פונקציית ההפסד של המחולל ע”י הוספת CE בין החלק של העמודה בה יש 1 בוקטור המותנה, לחלק של אותה עמודה בדגימה המיוצרת.
c. אימון לפי דגימה– דוגם את התנאים לפיהם נוצר הוקטור המותנה, כך שההתפלגויות הנוצרות ע”י המחולל יתאימו להתפלגויות המשתנים הבדידים בנתוני האימון.
אימון לפי דגימה מתבצע כך:

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

קוד
חבילת פייתון רלוונטית והסבר על אופן השימוש בה

קישורים רלוונטיים

One Hot Encoding
EM
CTGAN

Posted by yuval schreiber in deep

הכרות פרקטית ל 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

מערכת לזיהוי דובר מבוססת למידה עמוקה

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

נכתב על ידי bar madar

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

מוטיבציה

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

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

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

הגדרת הבעיה

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

את בעיית זיהוי הדובר מקובל לחלק ל2 תתי בעיות:

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

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

בכתבה, נתייחס לבעיית זיהוי הדובר כאל בעיית אימות דובר.

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

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

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

מערכת לזיהוי דובר מבוססת למידה עמוקה

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

1. הוצאת פיצ’רים לדאטה הגולמי.

2. אימון מודל רשת נוירונים לסיווג דוברים מקבוצה סגורה.

3. הוצאת ווקטור זהות לכל דובר “נרשם למערכת” או “מועמד” על ידי למידת מעבר מהמודל שאימנו בשלב הקודם.

4. הוצאת תוצאת תאימות עבור 2 קטעי דיבור.

5. קבלת החלטה.

ניתן לראות את סכימת המערכת הבסיסית באיור הבא:

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

1. הוצאת פיצ’רים

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

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

להוצאת הפיצ’רים נשתמש באלגוריתם ה(MFCC(Mel Frequency Cepstrum Coefficient אשר נפוץ מאוד גם בעולם זיהוי הדיבור. הייחודיות באלגוריתם זה היא העבודה במרחב התדר של האות וההתחקות אחר הדרך הפיזיולוגית בה האוזן האנושית מדגישה את מנעד התדרים ע”י שימוש בסולם MEL  (מתייחס לתדר או גובה הצליל הנשמעים על ידי האוזן האנושית ביחס לערכים הנמדדים בפועל. לבני האדם הרבה יותר קל להבחין בשינויים קטנים בגובה הצליל בתדרים נמוכים)

לאלגוריתם הMFCC מספר שלבים:

1. אות הדיבור הרציף נדגם ונחתך לפריימים נחפפים בעלי גודל זהה.

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

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

4. קבלת פיצ’רי הMFCC תהיה על ידי הפעלת התמרת קוסינוס בדידה (Discrete Cosine Transform) על ווקטורי הפיצ’רים, שנועדה לייצר דה-קורלציה בין הפיצ’רים בווקטור.

לאחר הוצאת הפיצ’רים עבור כל פריים, מתבצע סינון פריימים שבהם אין דיבור (Voice Activity Detection).

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

2. אימון מודל לסיווג דוברים מקבוצה סגורה

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

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

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

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

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

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

המודל המסווג בנוי מ3 חלקים:

1. שכבות ייצוג פריים (frame-level)– לחלק הזה ייכנסו סדרות של פיצ’רים המייצגים את הפריימים שמרכיבים את קטע הדיבור. במאמר https://www.danielpovey.com/files/2018_icassp_xvectors.pdf שהציג לראשונה את שיטת ה x-vector שהפכה לSOTA בתחום, נעשה שימוש בארכיטקטורת Time Delay Neural Network (מופיעה באיור) שהיא אימפלמנטציה של רשת קונבולוציה חד מימדית, כאשר הקלט לרשת הוא שרשור של פריים במקום ה-t, יחד עם מספר קבוע של פריימים עוקבים ואוחרים לו. בכל שכבה יש קונטקסט קבוע בין הייצוגים של הפריימים (ניתן להתייחס אל זה כאל פילטר בגודל ספציפי) וככל שמעמיקים ברשת ככה הקונטקסט גדל (ניתן לראות בתמונה את הקווים האדומים שמסמנים את הקונטקסט בכל שכבה). בצורה הזאת, אנחנו גם מרוויחים ניצול מיטבי של המידע עבור כל פריים וגם מתאפשר חישוב בצורה יעילה (מבלי לחשב קשרים בין פריימים רחוקים ללא קורלציה).

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

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

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

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

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

3. חילוץ ווקטור זהות דובר מהמודל המסווג

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

בתמונה, ניתן לראות מודל מחלץ שמאומן ע”י דאטה סגור של T דוברים. ווקטור הזהות מחולץ מאחת משכבות הembedding.

4. תוצאת תאימות עבור 2 קטעי דיבור

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

תוצאת התאימות המתאימה ביותר למקרה שלנו היא יחס הlikelihood בין 2 היפותזות:

* H_0– 2 קטעי הדיבור שייכים לאותו הדובר

* H_1– 2 קטעי הדיבור שייכים לדוברים שונים

כאשר x_1,x_2 מסמלים את ווקטורי הזהות שחולצו ל 2 קטעי הדיבור. ניתן לראות שהתוצאה נעה בין 1 (קטעים זהים) ל 0.

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

אבל במצב הריאלי, כאשר אין מספיק דאטה ברשותנו, נרצה להשתמש במודל סטטיסטי חכם אשר מאומן ע”י צמדים של קטעי דיבור בעלי תיוג של שייכות לאותו דובר. מודל הPLDA(Probability Linear Discriminant Analysis) עושה שימוש במטריצות הפיזור של בתוך הקלאס ומחוץ לקלאס

(between-class and within-class scatter matrix), אשר מחושבות ע”י צמדי קטעי האימונים, ומגדיר משתנה חבוי שהוא משתנה הקלאס שיוגדר להיות משתנה אקראי גאוסי (רציף לעומת הבדיד במודל הGMM). בעזרת משתנים אלו, מודל הPLDA ממדל את ההסתברות לדובר כלשהו וגם את ההסתברות המותנת של קטע דיבור בהנתן דובר כלשהו. בעזרת התפלגויות אלה, ונוסחאת ההסברות השלמה, ניתן עבור 2 קטעי דיבור, לחשב את תוצאת התאימות ביניהם.

בהסבר הקצרצר כאן חסכתי לכם את הפיתוחים המתמטיים של המודל, אבל מידע נוסף למתעניינים נמצא בקישור הבא: https://link.springer.com/content/pdf/10.1007/11744085_41.pdf

קבלת החלטה

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

בעולם זיהוי הדובר קיימות 2 שגיאות:

* שגיאת קבלה (False Alarm)– כאשר 2 הקטעים שייכים לדוברים שונים אבל המערכת מחליטה שהם שייכים לאותו הדובר

* שגיאת דחייה (False reject)– כאשר 2 הקטעים שייכים לאותו דובר אבל המערכת מחליטה שהם שייכים לדוברים שונים

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

הערכת ביצועי המערכת

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

על מנת למדוד את ביצועי מערכת זיהוי הדובר, נשתמש בדאטה אבלואציה ובכלי גרפי שנקרא Detection Error Tradeoff Curve.

דאטה האבלואציה יורכב מצמדי “מבחן” של קטעי דיבור, ותיוג האם הם שייכים לאותו דובר או לא (target \ non-target). בגרף, הצירים מייצגים את יחסי שגיאות המערכת עבור סט אבלואציה של צמדי קטעי קול המתוייגיםכtarget  או non-target.

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

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

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

בגרף הבא, ניתן לראות השוואה בין 4 מערכות שונות שנבדקו על אותו דאטה סט, הנקודות על הגרפים הן נקודות הEER:

לסיכום

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

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

Barmadar13@gmail.com

linkedin.com/in/bar-madar-838b15160

Posted by bar madar in deep

אתגר רפאל–פתרון בלמידת חיזוקים End-to-End

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

נכתב על ידי binyamin manela

הקדמה על האתגר:

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

המטרה במשחק היא להגן על שתי ערים מרקטות המשוגרות אליהן בעזרת משגר יירוט (ראה Figure 1).

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

בכל צעד ניתן לבצע אחת מ4 פעולות:

  1. לא לעשות כלום
  2. להזיז קצת את המיירט עם כיוון השעון
  3. להזיז קצת את המיירט נגד כיוון השעון
  4. לירות טיל יירוט

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

המשחק מכיל מספר אתגרים מרכזיים:

  1. הdynamics של המשחק מורכבים לאלגוריתם hand-coded
  2. ה state space של המשחק לא קבוע– כמות הרקטות וטילי היירוט משתנה כל הזמן.
  3. Sparse reward– הסיכוי לירי מוצלח קטן משמעותית מהסיכוי לפספס. כלומר, סביר שהסוכן ילמד מהר שעדיף להימנע מירי.
  4. Reward assigning– גם במקרה והסוכן ירה נכון, התגמול על ירי מוצלח מגיע רק בדיעבד ויהיה לסוכן קשה להבין מה גרם לאותו משוב חיובי. בנוסף, פגיעה של רקטה בעיר גוררת תגמול שלילי גדול באופן מידי, ותגרום לסוכן לחשוב שהוא עשה משהו רע בצעד שלפני הפגיעה (פצצה עוינת=רקטה, טיל כיפת ברזל=טיל).

פתרון Model Free

בכדי להימנע מהגדרות מדוייקות של המערכת, החלטתי לאמן את הסוכן ע”י reinforcement learning. לצורך כך, השתמשתי באלגוריתם PPO עם מימוש הזה. הגדרתי סבב של למידה (cycle) כ10 episodes (10000 תצפיות) ואז למידה עליהם של 10 epochs. לצורך נוחות, בניתי wrapper למשחק כך שהסביבה תתפקד כמו סביבת RL סטנדרטית. את התגמול הגדרתי להיות השינוי בscore. לצורך האימון יצרתי שתי סביבות:Train env ו Test_env.

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

ייצוג רקטות וטילים

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

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

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

של 40X100 פיקסלים (כל פיקסל מתאר גודל של 100X100 מטר) ומתארת את המצב הנוכחי של המערכת מבחינת רקטות / טילים בהתאמה (ראה figure 2).

בכל רגע נתון החזקתי את שלושת המפות האחרונות של הסביבה (כל מפה בchannel אחר) על מנת לאפשר הבנה של המהירות והתאוצה. כלומר, המצב של הרקטות והטילים תואר על ידי שני tensors בגודל של 40X100X3. מעכשיו אקרא לטנזוריםהאלה ‘תמונת רקטות’ ו’תמונת טילים’. כפי שציינתי, הניתוח של שתי התמונות דומה מבחינת כישורים שהרשת צריכה לפתח. לפיכך, בניתי רשת CNNאחת אליה הזנתי את תמונת הרקטות ותמונת הטילים בנפרד.

לאחר העיבוד של התמונות עם רשת הCNN, הכנסתי את הפלט של שתי התמונות לשכבת Dense עם אקטיבצייתtanh שאמורה להוציא עיבוד מוכן של מיקומי הרקטות והטילים ולפלט זה הצמדתי גם את שאר הקלט. מאחר והממדים של שאר הקלטים קבועים (מיקום הערים, זווית המיירט והמשתנה שמודיע האם ניתן לירות), אין בעיה להכניס אותו ללא עיבוד (מלבד נרמול של הערכים לטווח [1,1-]). את כל הקלט המעובד העברתי בשכבת Dense אחת. הפלט של השכבה מתאר את המצב הכולל של המערכת ואותו הזנתי לרשתות הactorוהcritic-. היתרון של שיטה זו היא שבעקבות שיתוף המשקלים (ומאחר ורשת הCNN צריכה לעשות עבודה דומה עבור שתי התמונות), הרשתות אמורות ללמוד מהר יותר. את הגרפים של רשת הActor וה-CNN ניתן לראות בfigure3.

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

החלטתי להימנע משילוב של רשת CNN באלגוריתם הRL. הבעיה קשה מספיק גם ככה, הלמידה של הייצוג כנראה “שברה” את הסוכן. החלטתי להשתמש בvariational auto-encoder(VAE) ללמוד ייצוג יעיל של המפות (תזכורת – מפה היא המצב הנוכחי של הטילים/רקטות). אימנתי את הVAE על 150K מפות של הסביבה (75K מפות של רקטות ו 75K של טילים) והגדרתי את המימד של ווקטור הייצוג להיות בגודל 100. כלומר, הVAE צריך היה ללמוד לייצג תמונה של 40X100X1 כווקטור עם 100 מימדים ולשחזר ממנו את התמונה המקורית. הניסיון הראשון לא הצליח. מאחר והרוב מוחלט של הפיקסלים הם 0, הVAE התכנס לאופטימום לוקאלי בו הוא פשוט מחזיר תמונה ריקה ונמנע לחלוטין מלנסות ולהגדיר איפה יש טילים. בכדי לתקן זאת, החלטתי לייצג את המצב כheat-map סביב הטילים והרקטות. גם כאן, יצרתי מפה נפרדת לטילים ולרקטות (ראה figure 4).

בכדי ליצור את ה heat-maps פשוט הרצתי את המפות המקוריות שיצרתי דרך קונבולוציה עם פילטרים קבועים של מטריצת אחדות בגדלים [7,5,3,1] וstrides=1, וסכמתי את התוצאות. כל קונבולוציה כזו יוצרת ריבוע של אחדות סביב הטיל בגודל מתאים וסכימה שלהם יוצרת פירמידה

סביב הטיל. כעת, לאחר אימון, הVAE הצליח לייצר ייצוג לא רע של הטילים (ראה Figure 4,5).

אחרי שאימנתי את הVAE, החלפתי את שכבות הCNN בשכבת Dense פשוטה. שכבה זו מקבלת מקבץ של שלושה ווקטורים באורך 100 (שוב, הייצוג של המערכת לאורך 3 [1]timesteps) ומצמצמת אותם לווקטור של 128 מימדים. השתמשתי בשכבה זו עבור הרקטות והטילים בנפרד. את הפלט איחדתי לווקטור של 256 מימדים, והזנתי לעוד שכבת Dense עם אקטיבצייתtanh ופלט של 128 מימדים שמתאר את כל המצב של המערכת מבחינת רקטות וטילים. שאר הרשתות נשארו כמקודם (איור 2). גם כעת הביצועים לא היו מדהימים, אבל לפחות יש לי מסגרת לריצות. כעת הגיע הזמן לחשוב קצת יותר במונחים של למידת חיזוקים ואיך להקל על הסוכן.

Sparse Rewards

הסיכוי שירי של הסוכן יוביל למשוב חיובי הוא די נמוך. לפיכך, הסוכן לומד בשלב מוקדם שירי זו פעולה לא משתלמת, ונמנע ממנה לחלוטין. על מנת לתקן את הרושם הזה, החלטתי להשתמש בשיטה של Curriculum learning. בסביבה שסופקה על ידי רפאל יש פרמטר בשם prox_radius (פרמטר זה מגדיר את המרחק הנדרש בין הטיל לרקטה על מנת שהרקטה תתפוצץ כשהערך המקורי עומד על 150 מטר). על ידי שינוי של ערך זה, אני יכול להקל או להקשות על הסוכן. על מנת ללמד את הסוכן שירי זה דבר חיובי, אני מתחיל את האימון עם prox_radius=2000. רדיוס כל כך גדול מלמד את הסוכן שלירות זה דבר חיובי, אך לא מלמד אותו לכוון. על מנת לתקן את זה, כל פעם שהסוכן מגיע לרמת ביצועים מסויימת (אני הגדרתי את הגבול להיות score ממוצע גדול מ0 על פני 10 episodes) אני מכפיל את הרדיוס בפאקטור דעיכה (0.9) עד שהרדיוס יגיע חזרה ל150. שינוי כזה הוא חוקי כי לאחר הלמידה, הסוכן יכול לשחק בסביבה המקורית ללא שינוי.

Reward Assigning

פונקציית התגמול הישירה (השינוי בscore) לא כל כך יעילה, כי מאוד קשה לסוכן לדעת איזו פעולה אחראית לכל תגמול (גם חיובי וגם שלילי), מאחר והתגמול על ירי מוצלח מגיע רק לאחר מספר צעדים ומוצמד לפעולה שלא השפיעה עליו כלל. בנוסף, גם העונש על פגיעה בעיר הוא לא אינפורמטיבי, מאחר והוא מוצמד לפעולה שלא יכלה למנוע אותה. לפיכך, החלטתי לעצב פונקציית תגמול משלי (גם זה שינוי חוקי, מאחר ובמהלך הtest אין כלל התייחסות לתגמול). הוספתי לאובייקט world רשימה בשם reward שנבנתה במהלך הפרק ובסוף (לאחר 1000 צעדים) הוחזרה לסוכן. השינוי הראשון והבסיסי ביותר היה להכניס את התגמול על יירוט מוצלח לreward של הstep בו הטיל נורה. בכדי לעשות זאת, הוספתי לכל טיל שדה נוסף בו שמרתי את הצעד בו הוא נורה ובמידה והיה יירוט, עידכנתי את רשימת הrewards בindex המתאים.

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

בעיה נוספת שהיתה היא המגבלות על הירי. הסוכן יכול לירות רקטה רק אחת לכל 8 צעדים (הטעינה לוקחת 3 שניות). מאחר ואין לסוכן שום אינדיקציה מתי הוא יכול לירות ומתי לא, זה מוסיף variance לvalue שהסוכן מנסה ללמוד. ההגדרה במשחק היא מאוד מדוייקת ואין שום סיבה למנוע את הידע הזה מהסוכן. לצורך כך הגדרתי קלט נוסף –can_shoot, ששווה 1 אם הסוכן יכול לירות (עברו 7 צעדים מאז הירי האחרון) ו0 אחרת. היתרון של קלט כזה הוא שהוא מוריד את האקראיות מבחינת הסוכן ומאפשר אומדן מדוייק יותר של התוצאה של פעולות.

[1]על מנת להגביר את ההבדל בין הווקטורים, החלטתי לא להשתמש במצבים עוקבים, אלא בקפיצות של 3 time-steps. כלומר, הזנתי את הווקטור של המצב הנוכחי, לפני 3 צעדים ולפני 6 צעדים.

_______________________________

[1]על מנת להגביר את ההבדל בין הווקטורים, החלטתי לא להשתמש במצבים עוקבים, אלא בקפיצות של 3 time-steps. כלומר, הזנתי את הווקטור של המצב הנוכחי, לפני 3 צעדים ולפני 6 צעדים.

עם זאת, עדיין הסוכן לא למד מספיק טוב. הסוכן תמיד קיבל ציון גבוה באזור ה300 בשני הסבבים הראשונים של אימון בהם רדיוס הפגיעה עמד על 2000 ו 1800 (אחרי הכל, הוא יירט כמעט את כל הרקטות), אבל אחרי בערך שני סבבי למידה הוא ירד באופן מידי לאזור ה-500. הפעלתי את הrender וגיליתי שהסוכן פשוט מחליט משום מה להימנע לחלוטין מירי. אחרי כמה ניסויים גיליתי שאם אני הופך את הloss של הactor ואומר לו למזער את ה advantage, הסוכן דווקא מצליח לא רע בכלל ומגיע עד לרדיוס של בערך 400 עם ציונים גבוהים (50-100 ומעלה) ואז מתחיל להיכשל. פה חשדתי.

אחרי בערך 45 דקות של בהייה בתקרה, חשיבה ב over-clocking ודמיון אישי מודרך בו אני מנסה לראות את העולם מנקודת מבטו של הסוכן, הגעתי להארה!

 

PPO לא אוהב Curriculum Learning!!!!!

כן, אני יודע, זה קצת הלם, אבל תכלס זה הגיוני. אם רוצים לעבוד עם PPO (ולצורך העניין, כל אלגוריתם שמבוסס על Advantage) ביחד עם Curriculum learning, צריך לעשות את זה מאוד בזהירות. אני אסביר – הactor מחליט אילו פעולות לתעדף על ידי השאלה האם הם הניבו תוצאה טובה מהמצופה או לא. אם הcritic התאמן בעולם פשוט יותר בו קל יותר לקבל משוב גבוה (כמו עולם בו הרדיוס של הטילים גדול יותר וקל לפגוע ברקטות), הוא יגיד לactor שהצפי גדול יותר ממה שהוא אמור להיות, ולפיכך נקבל שהadvantageעל ירי יהיה כמעט תמיד שלילי. ככל שפעולה היתה מתגמלת יותר בעולם הקודם, כך צפויה לcritic אכזבה חמורה יותר. הcritic התאכזב מאוד מהתוצאה של ירי וגרם לactor להימנע ממנו לחלוטין. כשחושבים על זה, זה לא כל כך מפתיע. כמו שאומרים, “כגודל הצפייה, כך גודל האכזבה” ולכן גם נרמול של הAdvantage  לא עזר כאן (האכזבה מירי היתה גדולה מהאכזבה מהימנעות מירי).

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

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

באיחור נורא, החלטתי לבדוק את המימוש של PPO שלקחתי מgithub. מסתבר שהמימוש הזה די גרוע ונכשל אפילו בפתרון בעיות סטנדרטיות של Gym…

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

אם היה לי עוד כמה ימים, השיפורים העיקריים שהייתי בודק היו:

  1. כמובן, חיפוש מימוש אחר.
  2. שיפור של הרפרזנטציה. אולי אימון נוסף של הVAE על יותר נתונים עם פחות תלות בניהם. הכנסתי לסט שלי רק תמונה אחת כל 50 timesteps מפוצלת ל3 מפות), אבל בדיעבד קלטתי שתמונת המצב מכילה 3 מפות עוקבות, מה שיצר סטים מאוד דומים אחד לשני. הייתי מתקן את זה ומכניס רק את המצב הנוכחי של המערכת במקום את 3 המצבים האחרונים.

בנוסף, אני חושב שבעתיד אבחן 2 כיוונים נוספים “בשביל הספורט”. דבר ראשון, הייתי רוצה להחליף את הרפרזנטציה בשכבה של Deep sets. כלומר, להכניס כל אחד מהטילים לרשת קטנה (שכבה או שתיים) עם output של נניח 50 נוירונים ואז לאחד את הפלט של כל הטילים בעזרת max pooling (או משהו בסגנון) על כל אחד מהממדים.

כיוון נוסף הוא לעזוב את הפתרון של end2end. יכול להיות מעניין לפצל את הבעיה ל2 סוכנים שונים:

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

חוץ מזה, אני חושב הגיע הזמן לעבור לPytorch. חוץ ממימוש הbaselines שבלתי אפשרי לעבוד איתו, כמעט וכל המימושים הטובים הם בPytorch.

לסיכום, היה לא קל, מתסכל ואפילו מייאש לעיתים, אבל כחוק, RL זה פשוט תענוג!

 

אם מישהו מעוניין בפרטים נוספים / קוד, שידבר איתי בפרטי 😊  0526429005

Posted by binyamin manela in deep

מבוא למערכת המלצות ומדדי דיוק מקובלים בתחום

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

נכתב על ידי David Kohav

איך מערכת המלצות עובדת ?

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

מאיפה הנתונים על המשתמש מגיעים ?

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

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

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

ארכיטקטורה נפוצה היא ה TOP-N – בו המערכת מצליחה לזהות את N פריטים (לדוגמה N=10) שהמשתמש הכי מתעניין בהם.

ארכיטקטורה כללית

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

 

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

בסיסי הנתונים בעולם האמיתי יהיו לדוגמא mongodb, קסנדרה או Memcached. בסיסי נתונים אלו מספקים כמות נתונים גדולה בשאילתות פשוטות, באופן אידיאלי הנתונים מנורמלים באמצעות טכניקות כמו mean centering או z-scores כדי להבטיח שהנתונים דומים בין המשתמשים אבל בעולם האמיתי לעיתים קרובות הנתונים שלנו דלילים מכדי לנרמל אותם ביעילות.

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

דוגמה:

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

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

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

  1. בשלב הבא נעבור לדירוג מועמדים – candidate ranking.

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

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

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

  1. שלב הסינון – Filtering – יהיה צורך בסינון כלשהו לפני הצגת רשימת המועמדים הסופית המומלצת למשתמש.
  • שלב הסינון הוא המקום בו אנו עשויים לוותר על המלצות פריטים שהמשתמש כבר דירג, מכיוון שאיננו רוצים להמליץ על פריטים שהמשתמש כבר ראה.
  • אנו עשויים להחיל כאן רשימת עצירה (stop list) כדי להסיר פריטים שיכולים להעליב את המשתמש או להסיר פריטים שנמצאים מתחת לציון איכות או סף מינימלי מסויים.
  • זה המקום בו אנו מיישמים את מספר ההמלצות, N המלצות, הכי רלוונטיות למשתמש לדוגמה 10 ההמלצות הכי רלוונטיות.
  1. הפלט למשתמש (אזור תצוגת הסרטים למטה בתמונה) – הפלט משלב הסינון עובר לשלב תצוגת המשתמש, על ידי יישומון וכו’.

הדיאגרמה הזו היא גרסה מפוענחת של מה שמכנים סינון שיתופי מבוסס פריטים (item-based collaborative filtering). החלק הקשה הוא בניית הדמיון בין הפריטים.

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

 

הערכה – אימון \ מבחן בדיקה ואימות צולב

Evaluating – Train/Test and cross-validation

אימון ומבחן

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

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

 

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

תהליך עם נתוני אימון ומבחן

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

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

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

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

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

k-fold cross-validation -תהליך אימות צולב

ניתן לשפר את שיטת פיצול נתונים של אימון ומבחן ע”י שיטת  k-fold cross-validation.

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

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

  • החיסרון זה יותר כוח חישוב
  • היתרון שאתה נמנע מ overfitting אל מול קבוצה בודדת של נתוני אימון.

מסקנה, מטרת מערכת המלצות

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

סקירת מדדי הדיוק של מערכת ממליצים

  1. mean absolute error – MAE – שגיאה ממוצעת בערך מוחלט

התמונה מ https://www.dataquest.io/blog/understanding-regression-error-metrics/

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

  1. שגיאה ממוצעת בשורש הריבועי, root mean square error- RMSE

התמונה מ https://medium.com/analytics-vidhya/calculating-accuracy-of-an-ml-model-8ae7894802e

מדד זה מעניש כאשר החיזוי רחוק מהתוצאה האמיתית ומעניש פחות כשאתה קרוב בחיזוי מהתוצאה האמיתית.

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

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

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

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

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

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

מדדי דיוק לרשימת המלצות עליונות

  1. hit rate , אחוזי הצלחה – מדידת דיוק של רשימות עליונות ( TOP N ) עבור משתמשים בודדים.

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

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

התמונה מ https://slideplayer.com/slide/9347453/

 

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

לעומת בדיקת דיוק כמו MSE ו RMSE שאיתם מדדנו את דיוק הדירוג האישי של המשתמשים, פה אנו מודדים את דיוק הרשימות הראשוניות top n עבור משתמשים בודדים.

בעזרת שיטת leave-one-out cross-validation אנו נבצע את המדידה, אז כמו שאמרתי במדידה זו מחשבים את ההמלצות העליונות עבור כל משתמש בנתוני האימון שלנו אבל אנחנו נסיר בכוונה אחד מאותם פריטים מנתוני האימון מכל משתמש למען מערך נתוני המבחן, שיטה זו נקראת leave-one-out.

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

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

  1. ARHR – average reciprocal hit rate – השפעה ממוצעת על אחוזי ההצלחה.

הוא מאוד דומה ל hit rate אך המדד ARHR מציג היכן נמצא המיקום של הפריט ברשימת הפריטים העליונים (top n) של המשתמש:

התמונה מ https://medium.com/@arthurlee_73761/recsys-16-local-item-item-models-for-top-n-recommendation-753555b5c1c

זה אומר שכאשר המערכת מצליחה להמליץ על פריטים עליונים יותר ברשימה זו נחשבת ל HIT מאשר

המלצה על מיקום פריטים נמוכים יותר מרשימת המומלצים.

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

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

Reciprocal rank Rank
1/3 3
1/2 2
1 1

וכך אנו “מענישים” יותר את מה שאנחנו פחות רוצים להמליץ.

  1. cumulative hit rank – cHR – הצטברות של אחוזי הצלחה

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

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

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

Predicted Rating Hit Rank
5.0 4
3.0 2
5.0 1
2.0 10
  1. Rating hit rate – rHR – שיעור צפיות בדירוג

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

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

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

מדדים להערכת תפקוד מערכת המלצות

  1. Coverage – זהו מדד הכיסוי המודד את אחוז ההמלצות האפשריות שהמערכת מסוגלת לספק.

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

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

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

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

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

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

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

בערכי הדמיון האלו כדי למדוד את הגיוון.

S = avg similarity between recommendation pairs

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

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

  1. Novelty – מדד ממוצע לפופולריות של פריטים ברשימת ההמלצות העליונות.

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

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

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

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

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

מטרת מערכת המלצות היא פריטי השירות מה שנקרא תאוריית הזנב הארוך.

לפי ויקיפדיה:

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

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

לפי הגרף, בזנב הארוך ציר ה Y הוא מספר המכירות או הפופולריות, וציר ה X מייצג את המוצרים.

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

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

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

  1. Churn rate – מדד קצב הנטישה

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

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

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

  1. Responsiveness – מדד היענות.

מודד באיזו מהירות משפיעה התנהגות המשתמש על רשימת ההמלצות.

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

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

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

  1. בדיקות A/B באופן מקוון, כדי לכוון את מערכת הממליצים.

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

בדיקות ה A/B הוא מדד מצויין כדי להבין מה קורה בעולם האמיתי ואפילו יכולת לתת מסקנות אשר יכולות להוריד את מידת המורכבות של המערכת.

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

 

By David Kohav

Linkedin: https://www.linkedin.com/in/davidkochav/

GitHub: https://github.com/DavidKohav/recommender-systems

Posted by David Kohav in deep

סיכום מיטאפ – Reinforcement Learning

בשבוע שעבר ערכנו מיטאפ וירטואלי של AI-ML מבית IsraelClouds ו-Ai-Blog, כאשר התמקדנו בנושא: Taxi Navigation with Q-Learning.

במהלך האירוע הועברו שתי הרצאות מקצועיות, כאשר ההרצאה הראשונה היוותה תיאוריה ומבוא ל-Q-Learning, וההרצאה השנייה הייתה Live Hands-On דמו עם דגש מעשי, עבור יישום של Q-Learning ב-Jupyter.

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

מילות פתיחה  ע”י צוות IsraelClouds והצגת ה-Moderator, איילת ספירשטיין

הרצאה 1: Q-Learning for Beginners

תמיר נווה, Algorithms Expert, Ai-Blog הסביר על התאוריה של Reinforcement Learning.

הרצאה 2: Teach a Taxi to navigate with Watson Studio

טל נאמן, Developer Advocate, IBM Center, העביר דמו ב-Live על יישום של Reinforcement Q-Learning תוך שימוש ב – Jupyter Notebook וב- OpenAI Gym toolkit.

מאת: מערכת Ai-Blog

Posted by Stav Altfiru in כנסים

איך מתקינים מה שצריך עבור Deep Learning עם Anaconda ?

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

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

הדרך הכי נוחה ונטולת התקנות לפתח Machine Learning & Deep Learning זה השירות Colab שהינו שירות חינמי של גוגל שמספק מחשב עם GPU לכל דורש והוא מאוד מומלץ למשחקים וללימודים. כשרוצים לפתח משהו קצת יותר גדול ומורכב המגבלות של Colab באות לידי ביטוי: זמן מוגבל של סשן, חוסר יכולת לשים break points על הקוד, החרדות שהקוד שלי יושב בשרתי גוגל (ולפעמים בפרויקטים בטחוניים בכלל אין לנו חיבור לרשת החיצונית) וכו’…

אז אנחנו רוצים לפתח קוד שממש יישב אצלנו, על המחשב שלנו ואנחנו מאוד חוששים מההתקנות המייגעות… (קצת בצדק…)

אם יש GPU צריך להתקין Cuda ואם חלילה אין תאימות בין הגירסאות נבין את זה אחרי המתנה של שעות התקנה שירדו לטימיון, אם בטעות בחרנו פייתון 32bits פתאום נגלה את זה אחרי שכבר סיימנו את ההתקנה כי איזשהיא package  לא מתאימה, ועוד ועוד צרות מייגעות…

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

מהן סביבות עבודה ?

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

אז למעשה סביבה היא תיקייה בה נשמרים כל החבילות בגירסותיהן השונות עם המפרש (Python interpreter)  שמאפשר להריץ קוד פייתון. גם למפרש יש הרי גירסאות שונות ואפשר להחזיק סביבת פייתון 2 וסביבת פייתון 3 במקביל.

מה עושים שלב אחרי שלב ?

מורידים Anaconda מהקישור הבא:

https://www.anaconda.com/distribution/

אחרי שמתקינים נוצר לנו Anacoda Prompt שזה כמו ה Command line הרגיל רק שמשמאל ל path הנוכחי מופיע בסוגריים שם הסביבה הנוכחית (ברירת המחדל הינה base):

אם רוצים לקבל את רשימת הסביבות הקיימות רושמים:

conda info –envs

ומקבלים (מה שיש אצלי כרגע):

אם רוצים לעבור לסביבה אחרת:

ניתן לראות ששם הסביבה הנוכחית השתנה ל (tf_gpu).

אם רוצים לקבל את רשימת החבילות המותקנות בסביבה הנוכחית:

conda list

ואם רוצים ליצור סביבה חדשה:

conda create –name XXX

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

התקנה חדשה תיעשה ע”י

conda install XXX

או גם בדרך המוכרת:

pip install XXX

מחיקת סביבה:

conda remove –name old_name –all

שינוי שם של סביבה אי אפשר, אבל אפשר לשכפל בשם אחר ואז למחוק:

conda create –name new_name –clone old_name

conda remove –name old_name –all

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

conda create –offline –name $NAME

 

אז לאחר שהתקנו Anaconda ויצרנו סביבה והתקנו בה את החבילות שאנחנו רוצים (למשל TensorFlow, Keras, Numpy)

השלב הבא הוא לבחור סביבת פיתוח (IDE) ולקשר אותה לסביבות העבודה אותם יצרנו ב Anaconda.

אז אדגים זאת על Pycharm, ראשית נתקין את גירסת ה-Community החינמית: (או הגירסה המקצועית בתשלום)

https://www.jetbrains.com/pycharm/download/#section=windows

אחרי שהתקנו נלחץ על new project  ובעקרון נוכל להתחיל לכתוב קוד. אבל כפי שהסברנו יש לשייך סביבה לפרויקט או במילים אחרות להחליט איזה מפרש (python interpreter) על חבילותיו השונות נרצה שיריץ את הקוד שלנו ?

אז סביבה כבר הגדרנו בAnaconda Prompt  ומה שנותר זה להגדיר ל PyCharm היכן יושבת הסביבה שהגדרנו מקודם. אז נלך ל Settings שם מצד שמאל נראה Project: project_name (אצלי שם הפרויקט הוא desktop)

ונלחץ על Project Interpreter:

ואז על Add ז”א הוספת סביבת עבודה:

פה נבחר סביבת Anaconda  קיימת ונזין את מיקום ה Interpreter כפי שהופיע לנו כשבנינו את הסביבה ב Anaconda Prompt (ואם שכחנו אפשר לכתו where python ב anaconda prompt  בכדי לקבל זאת שוב)

ורצוי לשים וי על Make available to all projects כדי שהסביבה הזו תהיה מוכרת לכל פרויקט עתידי גם.

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

תחת Run-Edit Configuration נבחר סביבת עבודה לפרויקט שלנו מתוך הסביבות הקיימות (אותן הגדרנו בעבר):

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

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

5 שאלות על פונקציות אקטיבציה שעלולות להופיע בראיון העבודה הבא שלך

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

נכתב על ידי Ayelet Sapirshtein

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

מדוע משתמשים בפונקציות אקטיבציה לא לינאריות?

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

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

z^{[1]}=W^{[1]}x+b^{[1]}

נשתמש בפונקציית הזהות בתור פונקציית אקטיבציה:

a^{[1]}=id\left ( z^{[1]} \right )=W^{[1]}x+b^{[1]}

נחשב את האקטיבציה של השכבה הבאה: 

z^{[2]}=W^{[2]}a^{[1]}+b^{[2]}

\inline a^{[2]}&=id\left ( \right z^{[2]})=W^{[2]}a^{[1]}+b^{[2]} =W^{[2]}\left ( W^{[1]}x+b^{[1]}\right )+b^{[2]} =\left (W^{[2]}W^{[1]}\right )x+\left ( W^{[2]}b^{[1]}+b^{[2]} \right )=\acute{W}x+\acute{b}

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

פונקציית האקטיבציה הראשונה שהייתה בשימוש ברשתות הייתה סיגמואיד 

סיגמואיד:

 

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

Saturation (רוויה)- הרוויה הורגת את הגרדיאנט. כאשר השיפוע מתיישר הגרדיאנט שואף ל-0 ולכן פעפוע לאחור לא יוכל לעדכן את המשקלים.

לא ממורכז סביב ה0 אם נסתכל על הגרדיאנט של וקטור המשקלים w, כל המשקלים בו יהיו בעלי אותו סימן חיוביים או שליליים. לדוגמא עבור w ממימד 2

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

חישוב האקספוננט לוקח זמן רב 

כדי לפתור את הבעייה שנוצרה מכך שסיגמואיד לא ממורכז סביב ה-0 עברו להשתמש בפונקציית tanh.

(טנגנס היפרבולי) tanh

 tanh מתנהגת כמו סיגמואיד שעבר הזזה והכפלה בקבוע. גרסה אחרת של tanh נראית כך: tanh(x)=2\sigma(x)-1. tanh ממורכזת סביב ה-0 מכווץ את המספרים לטווח של [1,1-].

Saturation (רוויה)-  בדומה לסיגמואיד tanh סובל מבעייה של דעיכת גרדיאנטים (vanishing gradient) בגלל רוויה.

חישוב tanh לוקח זמן רב 

כיום tanh שימושי בעיקר עבור רשתות rnn.

ReLU

AlexNet הייתה הרשת הראשונה שהחליפה את פונקציית האקטיבציה ל-ReLU, וגרמה לרשת להתכנס פי 6 יותר מהר.

ReLU מהיר לחישוב ביחס לסיגמואיד ו-tanh.

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

 

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

Leaky ReLU

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

Maxout

לא נכנסת לסטורציה אבל מכפילה את מספר המשקלים ברשת, במקום w יש לנו עכשיו w1 וw2. מסיבה זו היא לא פרקטית

ELU

 

חישוב אקספוננט לוקח זמן רב.

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

מה אפשר לעשות כדי למנוע מנוירונים ברשת למות ?

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

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

עם זאת בחירת learning rate נמוך מדי יאט את קצב ההתכנסות.
דרכים נוספות כדי למנוע מנוירונים למות הן pruning או dropout, ו-batch normalization.

מתכוננים לראיונות עבודה? ענו על השאלות הבאות בנושא:

  1. מדוע אנחנו זקוקים לפונקציות אקטיבציה?
  2. כתוב את פונקציית סיגמואיד ושרטט אותה?
  3. מה הנגזרת של פונקציית סיגמואיד?
  4. מה הבעיות בשימוש בפונקציית סיגמואיד בתור פונקציית אקטיבציה?
  5. מה גורם לתופעת ה vanishing gradient ברשתות, ובאילו דרכים אפשר להתמודד איתה?

כתבו את תשובותיכם בתגובות וקבלו מאיתנו פידבק. תפגיזו בראיונות!

מקורות:

046003, Spring 2019 טכניון
cs231n_2019  7 מצגת

Activation Functions (C1W3L06)

Why Non-linear Activation Functions (C1W3L07)

Lecture 0204 Gradient descent in practice II: Learning rate

 

[contact-form][contact-field label=”Name” type=”name” required=”true” /][contact-field label=”Email” type=”email” required=”true” /][contact-field label=”Website” type=”url” /][contact-field label=”Message” type=”textarea” /][/contact-form]

 

Posted by Ayelet Sapirshtein in deep

A/B Testing

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

נכתב על ידי raya_belinsky

מאמר זה משלב:

  • סיכום של קורס A/B Testing של Google ב- Udacity,
  • קוד פייתון ממקורות באינטרנט
  • דוגמאות והסברים מניסיון אישי

 

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

האם אתה יכול להשתמש ב- A / B לכל שינוי?
שאל את עצמך לפני שאתה מתחיל:

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

הבדלים בין מבחני A / B בתחומים שונים?

  1. בניסוי רפואי הבוחן קיום או היעדר תכונה של הנבדקים משתתפים 10-50 משתתפים, ואנו יודעים על כל משתתף: גיל, משקל, מצב משפחתי, גובה, האם יש להם רישיון נהיגה ועוד.
  2. אנו רוצים ליצור שינוי של 5-10-15% כדי לראות שינוי מהותי בין קבוצת קונטרול וטסט. מדובר על חיי בני אדם, וגם על הוצאות גבוהות ליצור תהליכים או תרופות, לכן אנו מחפשים שינוי גבוה.במחקר שרץ אונליין יש לנו מיליוני משתמשים, מאות אלפי קליקים, מגיבים, אך אנו לא יודע כל כך הרבה על מי נמצא בקצה השני של הנתונים האלו. זה יכול להיות אדם יחיד, מספר אנשים (זוג) או מחשב בבית קפה אינטרנטי. יש אפשרות לרכוש אותם ממקורות נוספים, אך לפעמים הם חסרים.

שינוי של 1-2% ב”הסתברות לקליק” הוא די גדול. לא נרשמת השקעה רבה ליצירת השינוי וגם חשיפה לאלפי או מיליוני אנשים יוצרת הכנסות מאוד גדולות.

מטריקות פופולאריות

Click Through Rate = Total number of clicks / Total number of views

שיעור/קצב לקליק = סה”כ קליקים / סה”כ מספר צפיות

אנו משתמשים במטריקה זאת כאשר רוצים למדוד את השימושיות באתר

Click Through Probability = Unique visitors who clicked / Unique visitors who viewed

הסתברות לקליק = סה”כ מספר משתמשים יוניקים שהקלילו  / סה”כ מספר משתמשים יוניקים שצפו בשינוי

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

 התפלגות הנתונים

למה חשוב לנו לדעת את ההתפלגות?

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

התפלגות בינומית שונה מהתפלגות נורמלית. אם גודל המדגם יהיה גדול מספיק, הצורות יהיו דומות למדי. ההבדל העיקרי הוא שהתפלגות בינומית היא דיסקרטית, לא רציפה. במילים אחרות, לא ניתן למצוא ערך נתונים בין שני ערכי הנתונים. ההתפלגות הנורמלית נחשבת בדרך כלל כקירוב לא רע להתפלגות הבינומית כאשר np ≥ 5 ו- n (1 – p) ≥ 5.

השערת האפס והשערה אלטרנטיבית

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

בסוף הניסוי יש לנו שתי אופציות: לדחות את השערת האפס, או שלא לדחות אותה

 

מובהקות סטטיסטית או רמת מובהקות – α

רמת מובהקות – היא הסיכוי שבעת ביצוע מבחן סטטיסטי לבדיקת השערות נדחה את ההשערה על אף שהיא נכונה.

המוסכמה המקובלת במדעי החברה היא להשתמש ב-α=0.05. ככל שה- α שנבחר קטנה יותר, כך ההחלטה שלנו תהיה שמרנית יותר.

עוצמת המבחן – תרצה שהיא תהיה כמה שיותר גבוהה – לעתים קרובות משתמשים ב- 80%)

מדגם קטן – אלפא נמוך, בטא גבוה

מדגם גדול – אלפא אותו דבר, בטא נמוך יותר

דוגמה:

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

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

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

בניית הטסט:

נניח בדף הנחיתה הנוכחי שלנו מבקרים 1000 אנשים, 73 לוחצים על “תתחיל עכשיו”. אנו רוצים להריץ במקביל ניסוי בו נשנה רק את הרקע של “תתחיל עכשיו” מירוק לאדום ונרצה שאחוז ההמרה יהיה גבוהה יותר ברמת מובהקות של 5%.

H0: CTR = 7.3%

H1: CTR > 7.3%

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

אפשר לעשות זאת בעזרת מחשבון ברשת

או לכתוב קוד פייתון

או ע”י הנוסחה:

אפיון ובחירה של המטריקות (KPI)

ערכים שלא משתנים – הם הערכים שלא אמורים להשתנות במהלך הניסוי.

מטריקות – סה”כ הכנסות, מספר הפקדות, מספר FTD, STD

מטריקות משולבות – שילוב של מספר מטריקות.

שימו לב כשאתם משתמשים במשתנים אקטיבים, כמו משתמשים פעילים ב-24 שעות האחרונות? משתמשים פעילים ב-7 ימים האחרונים. FTD – משתמש חדש שביצע רכישה ראשונה ביום הביקור הראשון או משתמש קיים שהפקיד בפעם הראשונה. היכנסו לעומק והגדירו מדדים במדויק, זה מאוד חשוב!

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

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

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

Additional Techniques for Brainstorming and Validating Metrics

  • חשוב להבין אילו שינויים במערכת שלך יכולים לקרות – האם שינוי של 10% בשיעור הקליקים זה מציאותי, כדי לעקוב כל שעה, יממה על איך הניסוי רץ ואם יש תקלה טכנית לעצור בזמן – בנה את האינטואיציה שלך לגבי המטריקות!
  • לדוגמה, pings JavaScript, עם בעיה בדפדפנים ותיקים מאוד, אינם מיישמים JavaScript בכלל וקליקים נעלמים. לדפדפנים אחרים, כלומר IE לעומת ספארי, יהיו שיעורי כישלון שונים ב- JavaScript. זו יכולה להיות הסיבה לשיעור קליקים שונה בדפדפנים ופלטפורמות שונות.
  • בדרך כלל אנו מחשבים את שיעור הקליקים כמבקרים ייחודיים שלחצו חלקי מספר אורחים ייחודיים שצפו. נסו להוסיף תקופת זמן – שיעור קליקים במהלך 5 דקות, שיעור קליקים במהלך 30 דקות, שיעור קליקים במהלך 60 דקות, זה יכול להביא תובנות חדשות.
  • לפעמים המתחרים שלך בודקים את האתר שלך ולוחצים על כל דבר. או מספר משתמשים שנכנסו מבית קפה אינטרנטי או אלגוריתמים שנכנסים ולוחצים על כפתור הקסם שלך. תנסה לבנות אלגוריתמים שמסננים יוזרים כאלו. כדי להימנע ממצב זה, צור ערכי בסיסי עבור המטריקות שלך, קבוצות לפי מדינה, שפה, פלטפורמה; תסתכל שבוע מול שבוע או יום מול יום.
  • כאשר מטריקה שלך מודדת זמן פעולה כלשהי כמו, זמן הטעינה של סרטון, זמן עד הקליק הראשון, משך ההפעלה. עבור אותם אירועים השתמש בחציון, האחוזון ה -25, האחוזון ה -70, האחוזון ה -90, פחות בממוצע.
  • אם מתאפשר, תבדוק את ההיסטוגרמה של המדד בשתי הקבוצות, לראות עד כמה המדד רגיש.על ציר ה- x יש לך את כל הערכים השונים עבור המדד שלך. בציר ה- Y הולכת להיות התדירות. אם התפלגות היא נורמלית, אז ממוצע או חציון זה יעבוד בשביל המדד הזה. ככל שההתפלגות יותר נוטה לאחד הצדדים, ייתכן שתרצה ללכת יותר על ה -25, או ה -75 או האחוזון ה -90.

 

ניסוי A/A

מתי אנו משתמשים בו?

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

 

תכנון הניסוי

ראו תבנית מומלצת:

Experiment design template

 

ניתוח תוצאות ניסוי A / B

בדקו אם אתם קיבלתם אוכלוסיות דומות בשתי הקבוצות.
קבוצת בקרה: 64,454 משתמשים

קבוצת מבחן: 61,818 משתמשים

האם יש הבדל בין הקבוצות?

חישבו סטיית תקן בינומית עם הסתברות 0.5 להצלחה
[SD = sqrt (0.50.5 / (64454 + 61818))] = 0.0014

הכפלו במספר Z כדי לקבל את שולי השגיאה.
0.0014*1.96 = 0.0027

חישוב מרווח הביטחון סביב 0.5.
0.4973 עד 0.5027

בדקו האם התוצאה נמצאת בתוך רווח בטחון
.p = 64454 / (64454 + 61818) = 0.5104

0.5104 גדול משמעותית מ- 0.5027 , כך

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

אנא הבינו מדוע הבדיקה הראשונית שלכם נכשלה לפני שתתחילו בניתוח בדיקת A/B.

אם קיבלתם אוכלוסיות דומות בשתי הקבוצות.

לקוח מ https://www.dataquest.io/wp-content/uploads/2018/09/sanity-check-invariants.png

 

 

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

מחשבון אונליין: https://abtesting.glitch.me/

לקוח מ https://www.dataquest.io/wp-content/uploads/2018/09/ab-testing-results.png

 

כך ניתן לפרש את התוצאות:

d̂ – m > dmin

קבוצת הניסוי נותנת ביצועים שעולים על ביצועי קבוצת הביקורת (משמעות סטטיסטית ומעשית)=> שנה לגרסה חדשה.
d̂ – m>0
תוצאות הניסוי נותנים ביצועים שעולים על הביצועי קבוצת הביקורת (משמעות סטטיסטית בלבד). זה המקרה בדוגמה שלנו. כדי לקבל משמעות מעשית גם ביחד עם הסטטיסטית, אתם יכולים לתת לניסוי להימשך לרוץ עוד זמן. ביחד עם זאת, אתם יכולים להתייעץ ולהחליט ללכת עם הגרסה  החדשה.
d̂ – m <0
אם לא ניתן לומר שגרסת הניסוי עולה על קבוצת הביקורת עם ביצועים טובים יותר אז שמור על הגרסה המקורית וצור השערות חדשות.

לסיום

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

מה השלב הבא?
– המשיכו להתפתח בנושא – עוד קצת על בדיקות A/B
להבין מה זה בדיוק טעות מסוג ראשון ושני

בהצלחה!

Posted by raya_belinsky in deep

על דיאגרמת וורונוי, ואיך היית נראה בתור קורי עכביש?

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

נכתב על ידי Ayelet Sapirshtein

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

                                                                                     אחרי                                                                                                          לפני

תודה ל Photo by Alexandre Debiève on Unsplash

מהי דיאגרמת וורונוי?

בלונדון של 1854 התפרצות כולרה הרגה 10% מהאוכלוסייה. הרופאים של אותה תקופה חשבו שהמחלה מופצת על ידי “אוויר רע” הנובע מהביוב הפתוח המסריח. אבל לרופא אחד, ג’ון סנואו, האמין שהמשאבה הספציפית שברחוב ברוד היא מקור המחלה.

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

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

מי אמר שלא היה DataSciense פעם 🙂

תודה ל – https://plus.maths.org/content/uncovering-cause-cholera

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

תודה ל – Balu Ertl wikipedia

לחובבי האלגוריתמים – איך מחשבים דיאגרמת וורונוי ?

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

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

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

 

Connecting the triangulation's circumcenters gives the Voronoi diagram.

תודה ל -Hferee

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

כיוון שכך, ניתן לחשב את דיאגרמת וורונוי באמצעות אלגוריתמים למציאת טריאנגולציית דלאוני כמו Bowyer–Watson .Bowyer–Watson הוא אלגוריתם אינקרמנטלי. האלגוריתם מתבצע על ידי הוספת נקודה אחת בכל פעם ומעדכן את הטרנגולצייה של תת הקבוצה לאחר כל הוספה. זמן הריצה הממוצע של האלגוריתם הוא O(n\cdot log\left ( n \right )), אך קיימים מקרים בהם זמן הריצה גדול מO(n^{2}).

ויש גם אלגוריתמים יעילים למציאת דיאגרמת וורונוי ללא קשר לבעיה הדואלית. למשל בעזרת אלגוריתם שנקרא פורצ’ן (Fortune’s algorithm) ניתן למצוא את דיאגרמת וורונוי של n מרכזים בזמן O(n\cdot log\left ( n \right )) :

By Mnbayazit – https://en.wikipedia.org/wiki/File:Fortunes-algorithm.gif, Public Domain, https://commons.wikimedia.org/w/index.php?curid=32553992

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

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

בכל אופן כפי שתראו בקוד שלי אני משתמשת בפונקציה מוכנה של scipy.

איך זה עוזר לי להפוך לספיידרמן?

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

בוחרים תמונה ובשלב ראשון הופכים אותה לגווני אפור:

Photo by Alexandre Debiève on Unsplash

להלן מימוש בפייתון:

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

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

שומרים במערך את הקורדינטות של הנקודות השחורות בתמונה:

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

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

וקיבלנו עכביש מקורי עכביש:

לסיום

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


[fvplayer id=”1″]

נסו את הקוד הזה על התמונות שלכם ושלחו לנו את התוצאות בתגובה.

רוצים לשמוע יותר על ציור בעזרת מתמטיקה? בואו להרצאה איך מציירים מתמטיקה.

Posted by Ayelet Sapirshtein in deep

סדר בניהול הריצות Machine Learning

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

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

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

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

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

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

מהו Neptune

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

כמובן שהכל מגובה ומאובטח.

איך משתמשים ?

ראשית נרשמים כאן ומקבליםtoken  אישי, מגדירים את ה token כמשתנה מערכת:


NEPTUNE_API_TOKEN=”…”

ואז הגישה יכולה להיות מ R או פייתון, אדגים עם פייתון.

מתקינים:


pip install neptune-client

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

 

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

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

לצורך כך הוסיפו שורות שכאלו:

neptune.send_metric(‘Variable I want to store’,var1)

neptune.send_image(‘Image I want to see while training’,img1)

כשהקוד ירוץ תתווסף שורה לרשימת ה experiments ב dashboard של Neptune עם כל המאפיינים:

התגיות מועילות כי בעוד חודש שנשכח למשל שבדקנו איך dropout הישפיע על הביצועים נחפש את כל הריצות עם התגית הזו, עוד שנה שננסה להיזכר מה הייתה הריצה הכי טובה עם מודל ה Xception למשל נחפש תגיות (שאנחנו כתבנו בשורת ה  neptune.create_experiment עם המילים best, xception)

גישה לתמונות ולגרפים

כדי לראות את נתוני הריצה נלחץ על ה experiment  הרצוי ושם כל אלמנט ששלחנו יוצג (משתנים\תמונות\גרפים וכו’). לחיצה על כל אחד תציג אותו:

השוואות בין ריצות

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

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

לסיכום

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

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

איך מחוללים טקסט ומי מפחד מפייק ניוז ?

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

נכתב על ידי Vered Shwartz

בתחילת השנה OpenAI הכריזה על GPT-2, מודל שפה שפיתחה שמסוגל לג׳נרט (לחולל) טקסט שנראה כאילו נכתב ע״י אנשים. בעוד שבדרך כלל הכרזות כאלה מלוות בשחרור של מודל מאומן, OpenAI בחרו שלא לפרסם את המודל שלהם בטענה שהמודל ״מסוכן מדי״ ועלול לשמש לייצור של פייק ניוז. המהלך גרר ביקורת בטענה שהמטרה הייתה יחצ״נות למודל (אכן, הרשת דיווחה על המודל בהגזמה, כפי שבדרך כלל קורה), אך גם עורר דיונים מעניינים באתיקה ובאחריות של המפתחים לשימוש לרעה במודל שפיתחו. המודל המלא שוחרר לבסוף רק לאחרונה, כחצי שנה לאחר הפרסום. ברשומה זו אדבר על ג׳נרוט אוטומטי (generation) של טקסטים באמצעות מודלי שפה – איך מודלים כאלה מאומנים, איך משתמשים בהם לג׳נרט טקסט, והאם הם באמת מסוכנים?

מה זה מודל שפה?

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

למה כולם מדברים פתאום על מודלי שפה?

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

איך מג׳נרטים טקסט?

בהנחה שיש ברשותנו מודל שפה מאומן, איך מג׳נרטים באמצעותו טקסט? נניח שנתון לנו טקסט התחלתי w1 … wn (הטקסט ההתחלתי לא הכרחי, לצורך העניין n יכול להיות אפס). תהליך הג׳נרוט מתבצע מילה-מילה: מייצרים את המילה ה-n+1 כתלות ב-n המילים הקודמות, ואז את המילה ה-n+2 כתלות ב-n+1 המילים הקודמות (הטקסט ההתחלתי והטקסט שהמודל ג׳נרט) וכן הלאה. איך ״מג׳נרטים״ מילה?

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

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

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

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

איך מאמנים מודל שפה?

שימו לב שאנחנו מדברים ספציפית על מודל שפה מבוסס רשתות נוירונים. מודל שפה מאומן באופן עצמוני (״self-supervised״), והדאטה שהוא צריך עבור האימון הוא פשוט קורפוס טקסט (למשל, כל וויקיפדיה). בזמן האימון, עוברים על הקורפוס משפט-משפט. עבור משפט נתון w1 … wn, ועבור כל מילה במשפט wi, המודל מנסה לחזות את wi בהינתן ההקשר (במודל פשוט ההקשר יהיה התחילית w1 … wi-1) ומעדכנים את הפרמטרים של המודל בהתאם.[2]

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

ארכיטקטורות שונות

ישנן מודלי שפה שפונקציית העלות שלהם שונה. למשל, BERT של גוגל מאומן לחזות מילים רנדומליות מתוך המשפט שהוחלפו ב״מסכה״, והוא דו-כיווני, כלומר הוא מסתמך גם על מילים שהופיעו אחרי המסכה. עם זאת, בגלל הדרך שבה אומן, BERT לא מאפשר לג׳נרט טקסט אלא רק לייצג טקסט קיים. מאידך, קיימים מודלים אחרים לג׳נרוט טקסט שאינם מודלי שפה. דוגמה לכך היא מודלים מבוססי GAN, בהם ה-Generator מייצר טקסט ותפקידו של ה-Discriminator לזהות שמדובר בטקסט מיוצר ולא ״אמיתי״. על אף ההצלחה האדירה של GANים על תמונות ווידאו, ההצלחה שלו על טקסט נכון לעכשיו יחסית מוגבלת, כנראה בגלל שבניגוד לוידאו ותמונות, טקסט הוא בדיד. ספציפית, מודלים מבוססי GAN כרגע פחות מוצלחים בג׳נרוט טקסט מאשר מודלי שפה.

איך מודדים את האיכות של מודל לג׳נרוט טקסט?

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

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

אז… יש לנו ממה לחשוש?

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

למודלים אין אג׳נדה

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

טקסט מג׳ונרט שונה מטקסט אנושי

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

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

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

קריאה נוספת:

Text Generation (אותה הכתבה באנגלית, מהבלוג שלי)

[1] רוב מודלי השפה היום לא מבוססי מילה אלא תו או רצפי תווים (חלקי מילה). לצורך פשטות, ברשומה זו נעסוק במודל שפה מבוסס מילה.

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

Posted by Vered Shwartz in deep

אסטרטגיה אבולוציונית

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

נכתב על ידי Nevo Agmon

הקדמה

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

מטרה

המטרה של אסטרטגיה אבולוציונית דומה לזו של למידה חיזוקית (Reinforcement Learning) ובאופן מדויק יותר לזו של Q-Learning. המטרה היא, בהינתן עולם וסוכן למצוא את המדיניות (Policy) שעל פיה הסוכן צריך לפעול כדי להצליח בצורה הטובה ביותר לעמוד ביעדים שניתנו לו. הסוכן יכול להיות למשל שחקן במשחק מחשב ,רובוט שמנקה את הבית או טייס של מטוס קרב והיעדים יכולים להיות לנצח במשחק בציון גבוהה ככל הניתן, לנקות את הבית כמה שיותר מהר בלי לפספס אף חלק או להפיל כמה שיותר מטוסי אוייב. כדי להבין את הכוונה ב״מדיניות״ אפשר לחשוב על מודל כזה:

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

אז איך זה עובד?

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

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

קצת יותר פרטים

עכשיו כשהבנו באופן בסיסי איך עובד האלגוריתם נתאר אותו בצורה קצת יותר מתמטית (אם לא בא לכם אפשר לקפוץ ישר לחלק הבא). נסמן ב -θ את המדיניות, F תהיה הפונקציה שמעריכה את ביצועי המדיניות על העולם, λ מייצגת את גודל האוכלוסיה ו -μ מייצגת את גודל המטא-אוכלוסיה. נאתחל את המדיניות בערכים רנדומליים ובכל שלב המוטציה תהיה הוספת דגימה אקראית מהסתברות נורמלית כפול גודל צעד הלימוד שנסמנו σ (ניתן לחשוב עליו כ Learning Rate). על מנת לחשב את מדיניות הבסיס החדשה עבור האיטרציה הבאה נבצע ממוצע משוכלל של μ הצאצאים הטובים ביותר, צעד זה מתבצע ע״י שימוש בפרמטר  wi שהוא סקלר המתפקד כמעיין נרמול. נכפיל את הממוצע בצעד  הלימוד σ ונחבר זאת למדיניות הבסיס של הצעד הנוכחי. כעת יש בידינו את כל החלקים הדרושים ע״מ להבין את האלגוריתם המלא:

https://arxiv.org/pdf/1802.08842.pdf

למה זה טוב?

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

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

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

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

דוגמא לביצועי האלגוריתם ניתן לראות בוידאו הבא:

בוידאו רואים שחקן של משחק המחשב Qbert שאומן למשך 5 שעות בלבד בשימוש באוכלוסיה בגודל 400 ופיתח שיטת משחק מעניינת מאוד .ראשית ניתן לראות ב 6:24 שהשחקן קופץ ממקום למקום ומחכה שהיריב יזוז  לכיוונו כדי שיוכל לנצח במשחק כלומר השחקן למד ״להטעות״ את היריב .ולאחר מכן ב 6:27 ניתן לראות באג שהשחקן גילה במשחק שלא היה ידוע עד כה שמאפשר לשחקן לקבל אינסוף נקודות במשחק.

קישורים

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

Posted by Nevo Agmon in deep

ערוכים לזה: עריכת וידאו בעזרת AI

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

נכתב על ידי Ayelet Sapirshtein

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

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

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

להלן דוגמה של וידאו מקורי ומשעמם באורך 1:25 (הלקוח מאגר וידאוים לבעיית התימצות: tvsum)

ולהלן הוידאו המתומצת שלו באורך 12 שניות כפלט מאלגוריתם הזה (רק שיניתי אותו בזה שהחלפתי את הרשת שמקודדים איתה את הפריימים inception v3 במקוםinception v1)

איך קובעים את מידת החשיבות של פריים?

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

איך יוצרים רשת שמדרגת את החשיבות של כל פריים?

בניגוד לתמונה, רמת העניין של פריים תלויה ברצף הפריימים ומיקומו בתוך הוידאו. בשביל לתת ביטוי למיקום הפריים ברצף, משתמשים ברשתות נוירונים ממשפחת (Recurrent Neural Network (RNN או Self-Attention אשר נועדו לפענח מידע סדרתי. רשתות אלו יכולות לקבל מידע סדרתי בכל אורך, לצורך עניינינו סרטונים עם מספר פריימים שונה. בנוסף לכך הן כוללות מרכיב של זיכרון – כך שהרשת “יודעת להתחשב” בהיסטוריה.

רשת RNN בסיסית

תודה ל https://en.wikipedia.org/wiki/Recurrent_neural_network#/media/File:Recurrent_neural_network_unfold.svg

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

Xt הוא הקלט ה-t ברצף הזמן, במקרה שלנו הפריים ה -t

ht הוא מצב נסתר (hidden state) בזמן t, ה”זיכרון” של הרשת. ht מחושב על סמך המצב הנסתר הקודם (ht-1) והקלט בשלב הנוכחי (Xt).

ot הפלט של זמן t, במקרה שלנו התחזית של הרשת לגבי כמה מעניין הפריים ה-t.

בעיות זיכרון

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

  1. Down-Sampling לסרטון. במקום להתחשב ב-30 פריימים לשנייה אפשר להסתכל רק על 2, תחת ההנחה שאין הבדל גדול בין פריימים עוקבים.
  2. במקום לקחת את הפריימים עצמם, מתמצתים את המידע שנמצא בתמונה. דבר זה מתבצע על ידי הוצאת מאפיינים בעזרת רשתות קונבולוציה (CNN) שאומנו למטרות סיווג תמונות (כגון VGG, GoogLeNet, ResNet)

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

איך בוחרים אילו מקטעים לקחת? (בעיית תרמיל הגב)

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

בעייה זו שקולה לבעייה מפורסמת מאוד במדעי המחשב שנקראת בעיית תרמיל הגב (Knapsack problem) .

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

בעייה זו מוגדרת כבעייה np-קשה, עם זאת, כאשר משקלי כל הפריטים שלמים, ניתן לפתור אותה בעזרת תכנון דינאמי בסיבוכיות זמן (O(Wn, כאשר W הוא המשקל המירבי שניתן לסחוב ו-n כמות הפריטים. במקרה שלנו המשקלים הם מספר הפריימים בכל מקטע, כלומר מספרים שלמים.

איך אומדים את טיב הסרטון?

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

Recall = TP/(TP+FN)

 וב-

Precision = TP/(TP+FP)

כאשר TP=True Positive זה כשהאלגוריתם חזה שהקטע מעניין וצדק

ו FN=False Negative זה כשהאלגוריתם חזה שהקטע לא מעניין וטעה

ו FP=False Positive זה כשהאלגוריתם חזה שהקטע מעניין וטעה.

תודה ל https://en.wikipedia.org/wiki/F1_score#/media/File:Precisionrecall.svg

 מדד  F-score  מוגדר באופן הבא:

סיכום

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

  1. מייצגים כל פריים על ידי וקטור פיצ’רים, באמצעות רשת קונבולוציה.
  2. מחלקים את הוידאו לסצנות באמצעות אלגוריתם למציאת נק’ שינוי המקבל כקלט את וקטורי הפיצ’רים של הפריימים
  3. מורידים את ה-(fps (frame per second של הסרטון
  4. מכניסים את וקטורי הפיצ’רים לרשת מבוססת RNN שמחזירה את החשיבות של כל פריים.
  5. משתמשים בתכנון דינאמי לבעיית תרמיל הגב בשביל לבחור אילו מקטעים להכניס לסרט המקוצר בהתאם להגבלת אורך שהגדרנו.

הפוסט מבוסס ברובו על האלגוריתם המוצע במאמר Summarizing Videos with Attention שמבצע למידה מונחית (supervised)

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

קישורים

Posted by Ayelet Sapirshtein in deep

רשתות סיאמיות – להצליח איפה שדיפ לרנינג נכשל – חלק א

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

נכתב על ידי thebeancounter

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

ובכל זאת, אנחנו רואים בתעשיה חברות רבות שמנסות ליישם דיפ לרנינג, בזמן שהאלגוריתמים המרכזיים שלהן מיישמים שיטות “קלאסיות” יותר, עצי החלטה, RBF, SVM והלאה, שיטות אלו נחשבות “חלשות” לעומת דיפ לרנינג ועדין נמצאות בשימוש – כן, גם בחברות שנפתחו הרבה אחרי שכל סטודנט ידע להריץ Keras.

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

מה עושים כשאין מספיק DATA ?

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

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

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

רשתות סיאמיות

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

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

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

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

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

דוגמית קוד

להלן דוגמה ממומשת מעל tf.keras

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

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

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

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

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

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

 

 

 

 

 

 

Posted by thebeancounter in deep

TensorFlow 2 –מה נשתנה ?

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

נכתב על ידי Moti Gadian

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

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

לפי האתר הרשמי של גוגל (tensorflow.org) פורסם שבגרסה החדשה, גוגל שמה לה למטרה מספר דברים מרכזיים:

  • להקל על המתכנתים את החיים
  • להפוך את צורת הכתיבה ליותר “פייתונית” (פחות להתעסק עם גרף האופרציות)
  • להוסיף יותר תמיכה ב High Level .
  • להוסיף ולשפר כלים למחקר
  • לעשות סדר בכל תתי הספריות והמודולים הרשמיים וגם באלו של הקהילה (Contrib)
  • תמיכה חזקה בכל מה שקשור לפרודקשיין בכל פלטפורמה.

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

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

tensorflow models

https://medium.com/tensorflow/whats-coming-in-tensorflow-2-0-d3663832e9b8

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

  1. מודולים וספריות של אימון
  2. מודולים וספריות של פרודקשיין (או גם “פריסת המודל” ושימושו בפועל באפליקציות )

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

מה עם קצת קוד ??

אז לחלק שמעניין את כולנו – קוד.

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

גוגל הפכה רשמית את מצב ברירת המחדל שלה ל Eager מאשר Graph – עד עכשיו כדי להגדיר מודל היינו צריכים להגדיר את האופרציות, המשתנים, והקבועים שלנו מראש ואז להריץ פעולות ע”י שימוש ב Session. אם היינו רוצים להריץ פעולות ישירות ללא הידור מקדים של הגרף היינו צריכים להפעיל מצב מיוחד ע”י הפקודה tf.enable_eager_execution  , כעת מצב זה הינו מצב ברירת המחדל, מצב זה בעצם מאפשר לכתוב פעולות בקונוטציה של פונקציות בפייתון ולהריץ אותם ישירות.

(ניתן לקרוא הכל בפרוטרוט בבלוג הרשמי באנגלית כאן)

Tensorflow בגרסה החדשה דוחפת יותר לכיוון של שימוש בספריית המעטפת Keras ע”י הוספת תמיכה בשלושה סוגי קונסטרוקציות:

  • Sequential Model– בנייה של מודל בצורה סדרתית שכבה על שכבה.

Sequential Model

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

Functional API

  • Model Subclassing– מצב זה הינו די חדש לגרסה 2.0 בו בעצם ניתן “לדרוס” (או לבצע ירושה לחובבי ה OOP) את מבנה המודל הכללי של Keras אך לשמור על ההתנהגות שלנו וכך בעצם ליצור מודלים הרבה יותר מורכבים אשר יכולים להכיל כל מיני אופרציות סף שלTensorflow עצמה.

Model Subclassing

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

חידושים בתחום הProduction

  • Distribution Strategiesאסטרטגיות ותצורות הפצה מובנות מראש של אופרציות באימון מפוצל (אימון שמתחלק בין כמה וכמה מחשבים או כרטיסי GPU) ללא צורך בשינוי הקוד או התאמתו לאימון מרובה.
  • Tensorflow Serving מודול המאפשר “הגשה” של רשתות (מודלים) בכל סביבה שהיא (שרת או ענן) לצורך ביצוע קריאות אל המודל וקבלת תשובה ללא התעסקות עם קונפיגורציות מסובכות.
  • Tensorflow Lite מודול המאפשר הגשה של רשתות על מכשירים דלי כוח חישובי כגון סמארטפונים, מכשירי ,IOTוכדו’.
  • jsמודול המאפשר הגשה של רשתות ע”י דפדפן פשוט בשפת Javascript.

 

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

מקווה שנהניתם… מוזמנים להגיב לשאול שאלות או לבקש בקשות לפוסטים ספציפיים בתגובות 😊

Posted by Moti Gadian in deep

מודל DeViSE – משלב הבנת שפה עם הבנת תמונה

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

נכתב על ידי Nadavpo

כשהתחלתי להיכנס לעולם הלמידה העמוקה, טיפסתי באותם השלבים שאני מאמין שרובנו טיפסנו בהם (ואם לא, אני ממליץ בחום על הספר האלקטרוני החינמי של Michael Nielsen בתור התחלה): רשת עם שכבת FC נסתרת אחת, רשת עמוקה, היפר פרמטרים, שכבות קונבולוציה, AlexNet,  VGG, Inception וכו’.

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

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

לצורך הסקופ הזה אני רוצה להתעניין בשאלה איך ניתן לגרום לרשת לסווג קטגוריות שאליהן היא לא נחשפה מעולם או נחשפה רק פעם אחת (zero\one shot detection למתעניינים) על ידי תיאור מילולי בלבד של הקטגוריות? או איך ניתן לגרום לרשת לכך שגם כאשר היא תטעה בסיווג של תמונה, התוצאה תהיה בעלת קשר סמנטי לאמת?

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

בארכיטקטורות המוכרות, אלה הכוללות שכבות קונבולוציה, pooling layers ולבסוף שכבת softmax קשה לגרום לרשת להצליח במשימות האלו. בכל תהליך האימון הרשתות מקבלות פידבק של כמה הן רחוקות מהאמת האחת והיחידה (ה-one hot encoding), אין כל דרך להבין קשר בין קטגוריות שונות. במילים אחרות, המימד של תגיות התמונות (ה-labels) מורכב מוקטורים אורתוגונליים חסרי כל קשר אחד עם השני ולכן לא ניתן להעריך כמה חמור דומה לסוס למשל. דוגמה נוספת היא מקרה שבו המאגר שעליו התאמנה הרשת לא מכיל תמונות של זברות אך בזמן שימוש ברשת, לאחר גמר האימון, נרצה לנסות לסווג תמונות של זברות. ב-VGG למשל זה לא יהיה אפשרי.

רשתות המבוססות על embedding vectors פותרות בדיוק בעיות כאלו. לצורך העניין נתמקד במאמר המציג רשת בשם DeVise.

רשת זו בנויה משתי רשתות נפרדות. הרשת הראשונה מבצעת את תהליך ה-word2vec ומאומנת על מסד נתונים טקסטואלי גדול ככל האפשר (ויקיפדיה במקרה שלנו), ואילו החלק השני יהיה CNN להוצאת מידע חזותי מהתמונה כאשר שכבת ה-softmax הוסרה ממנו, מעין transfer learning, במקרה שלנו רשת ה-CNN הינה ה-AlexNet (בכל זאת מאמר מ-2013).

המחשת מבנה הרשת. בצד שמאל רשת CNN, בצד ימין מודל skip-gram ובאמצע שילוב של שניהם כפי שמתבצע בתהליך האימון. (לקוח מ DeViSE: A Deep Visual-Semantic Embedding Model)

מה הקשר בין word2vec לבין AlexNet אתם שואלים?

פה טמון הסוד. בשלב האימון תג (label) התמונה נכנס לתוך רשת ה-word2vec ומקודד לוקטור במימד 500 או 1000 שאותו ניתן למקם כנקודה במרחב רב ממדי, וכעת נקבל שתגים מאותה הקטגוריה ימוקמו סמוכים האחד לשני (בנוסף נקבל גם קשרים דומים בין תגים עם אותו הקשר – למשל וקטור המחבר בין כלב לכלבלב יהיה דומה מאד לזה המחבר בין חתול וחתלתול – אבל זה נושא לפוסט אחר). במקביל, התמונה עצמה נכנסת ל-CNN כאשר במוצא ה-CNN ישנו וקטור באותו המימד של ה-word2vec. את שני המוצאים האלו מכניסים לפונקציית המחיר (זכרו שכעת התג מיוצג על ידי 500, או 1000, מספרים ולא רק על ידי אחד והמון אפסים כמו ב-one hot encoding) המשלבת אבחנה בין כמה קרוב היה הוקטור במוצא ה-CNN לוקטור לוקטור המתאים לתג התמונה ובנוסף אבחנה כמה רחוק היה הוקטור במוצא ה-CNN משאר הוקטורים שנלמדו במודל ה-skip-gram. בשלב ה-test נכנסת תמונה לרשת והתיוג יהיה זה בעל ה-embedding vector (הוקטור מה-word2vec) הקרוב ביותר לזה שיצא מרשת ה-CNN. שיטה זאת מאפשרת לנו לנצל את המידע הסמנטי מהמרחב הטקסטואלי לשימוש במרחב החזותי על ידי כך שאנו מלמדים את רשת ה-CNN לספק וקטורים קרובים מבחינה מרחבית לתמונות בעלות תיוג עם קשר סמנטי. בכך גם כאשר הרשת שלנו תשגה בתיוג התמונה, ישנו סיכוי גבוה לכך שלטעות יהיה קשר סמנטי לאובייקט שבתמונה.

דוגמה למרחב טקסטואלי על פי קטגוריות שנוצר בארכיטקטורת skip-gram ובו ניתן לראות מקבצים של דוגמאות אימון על פי קטגוריה (לקוח מ DeViSE: A Deep Visual-Semantic Embedding Model)

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

תוצאות הרשת היו קרובות לאלו שהושגו עם ה-CNN בלבד, אך ככל שבוחנים יותר תיוגים עבור כל תמונת מבחן (משמע, לא בודקים האם הרשת צדקה רק על ידי בדיקת התג שהיה הכי קרוב לוקטור שהופק בזמן המבחן, אלא בודקים את ה-2,3 ואפילו 20 הוקטורים הקרובים ביותר) רשת ה-DeVise השיגה תוצאות קצת יותר טובות מה-CNN המקורית. אומנם לא נראה שיפור בתוצאות אך לפחות לעניות דעתי הכיוון שהוצג במאמר בהחלט מקרב אותנו עוד קצת לכיוון של רשתות ש”מבינות”  קצת יותר את העולם הויזואלי שסביבן.

Posted by Nadavpo in deep

ניתוח תלת מימד של CT לצורך ניבוי סרטן ריאות

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

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

בכתבה זו אספר על בעיית עיבוד סריקות CT (שהינן תמונות תלת מימדיות) ובפרט אספר על תחרות ה-Kaggle לזיהוי סרטן ריאות: Data Sciense Bowl 2017 ועל הפתרונות המנצחים בתחרות זו מתוך ה-1972 צוותים שהשתתפו בתחרות.

האלגוריתם שזכה מקום ראשון (של צוות grt123 בתוצאה של loss=0.39975) נמצא כאן וכמובן הוציאו על זה מאמר.

תיאור הבעיה

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

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

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

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

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

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

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

לקוח מ Evaluate the Malignancy of Pulmonary Nodules Using the 3D Deep Leaky Noisy-or Network

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

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

על ה-DB

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

כל מכונת סריקה מייצרת סריקה בקצב דגימה שונה בציר העומק ולכן המרווח בין זוג תמונות חתך עוקבות (slice thickness) הוא שונה. וזו תופעה איתה יש להתמודד (בשלב העיבוד המקדים Pre-Processing).

הגושים (Nodules) אותם יש לחפש הינם בגודל טיפוסי של 1x1x1 סמ”ר  בעוד סריקת CT ממוצעת הינה בגודל 30x30x40 סמ”ר ולכן מדובר בחיפוש מחט בערימת שחת. אם נשווה לעולם היותר מוכר (לי) של דו מימד, זה כמו לחפש אוביקט בעל שטח של בערך 30 פיקסלים (ז”א בערך 5×5 פיקסלים) בתמונה בגודל 1000×1000. התיוג של ה DB מבוסס על שקלול אבחנות של כמה רופאים.

הרחבת DB תלת מימדי (Augmentation)

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

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

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

אם יש בקוביה גוש, גם יהיה גוש בכל אחת מה 48 סיבובים\היפוכים שלה:

תודה ל Дейка2

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

על הפתרון שזכה במקום הראשון

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

עיבוד מקדים (Pre-Processing)

לפני השלב הראשון יש כמו תמיד עיבוד מקדים שמטרתו לייצר אחידות בין הסריקות ולהסיר את כל מה שמחוץ לריאות. העיבוד המקדים כולל המרת התמונות ל- (Hounsfield Scale=HU) שהינו נירמול רמות הצבע כמקובל בסריקות CT, המרה לתמונה בינארית (לפי סף) ומחיקת כל מה שאינו בתוך ה- Connected Component  העיקרי בתמונה (שהינו הריאות). כמו כן פעולות מורפולוגיות בכדי ליצור מסיכה (mask) שבעזרתה ניקח מהתמונה המקורית רק את אזור הריאות.

שלב ראשון – גילוי מועמדים

השלב הראשון ממומש באמצעות מה שהכותבים מכנים N-Net = Nodule Net שהינה רשת 3D RPN מבוססת U-Net אשר מחזירה מלבנים (Bounding Boxes) סביב הגושים עם סף גילוי נמוך כדי לקבל כמה שיותר מועמדים גם אם אינם משמעותיים להחלטה הסופית. רשת זו מאמנים עם הרבה אוגמנטציות (Augmentation) של היפוכים (Flips), סיבובים, שינויי גודל והזזות קטנות. אגב, על רשת ה U-Net ניתן לקרוא בבלוג זה כאן.

בשלב השני לוקחים את חמשת הגושים החשודים ביותר שאותרו בשלב הראשון ובאמצעות אלגוריתםLeaky noisy-or model (יוסבר בהמשך) מחשבים פרדיקציה לקיום המחלה. אלגוריתם זה מניח שיש “זליגה” קלה של הסתברות לקיום האירוע (המחלה) גם אם אין אף תופעה (גוש) המרמז על כך.

חפיפה בין המודלים

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

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

לקוח מ Evaluate the Malignancy of Pulmonary Nodules Using the 3D Deep Leaky Noisy-or Network

חלק עליון בתרשים (a):

לוקחים את החלק המרכזי (Crop בגודל 96x96x96) מתמונת הגוש (הקוביה) שיצא מהשלב הראשון מזינים אותו לרשת ה N-Net (המודל הראשון) ולוקחים את השכבת הקונבולוציה האחרונה שלו כפיצ’ר בגודל 24x24x24x128 ממנו לוקחים רק את המרכז בגודל 2x2x2x128 עושים עליו max-pooling ונשארים עם פיצ’ר וקטור בגודל 128 לכל גוש מועמד.

חלק תחתון בתרשים (b):

ומשם עוד Fully-connected, Max-pooling, Sigmoid activation בכדי להגיע לפרדיקציה הסופית (המשקללת את המידע מחמשת הפיצ’רים של הגושים העיקריים).

שלב שני – שיקלול הנתונים של כל גוש (Leaky Noisy-or Method)

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

שיקלול שכן לוקח בחשבון את סך הפרדיקציות מכל גוש הינו Noisy-Or ההופכי למכפלת ההסתברויות של העדר סרטן: (ההסתברות שהראשון מעיד על סרטן או שהשני או שהשלישי…)

אך מה קורה אם גוש ממאיר ביותר התפספס בגילוי בשלב הראשון ?

לצורך כך משתמשים במודל ה- Leaky Noisy-or method שמניח שייתכן והפרדיקציה חיובית על אף שאף גוש לא ניבא זאת. הפרמטר Pd נלמד גם כן בשלב האימון. (ז”א הוא תלוי תמונה ולא תלוי גוש)

זה אכן המודל שהביא לתוצאה הטובה ביותר.

באימון המודלים משתמשים בין השאר ב Gradient clipping וב- Batch normalization.

על הפתרון שזכה במקום השני

לאלגוריתם (ולצוות) שלקח את המקום השני בתחרות יש שתי כתבות מפורטות של כל אחד מהמפתחים  Daniel Hammackו Julian de Wit.

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

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

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

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

מה שהם עשו זה השתמשו במאגר נתונים המקורי שממנו נגזר המאגר של התחרות שנקרא LIDC-IDRI שמכיל בנוסף לסריקות ולגושים אותם איבחנו רופאים, גם מאפיינים אותם איבחנו הרופאים לכל גוש. למשל גודל, מידת הממאירות, חיספוס וכו’… מידע זה שהוסר מהמאגר שבתחרות היווה נקודת מפתח להצלחה.

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

לקוח מ 2nd place solution for the 2017 national datascience bowl

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

טכניקת אימון אותה שווה להזכיר בה הם השתמשו נקראת Curriculum Learning. הרעיון הוא קודם לאמן דגימות קטנות ופשוטות ואז לאמן עם הדוגמאות הקשות. גישה זו אינטואיטיבית לנו הלומדים האנושיים כי תמיד הורגלנו ללמוד את הפשוט (כיתה א’) ואז כשזה מוטמע במוחנו, ללמוד את הנושאים היותר מסובכים (כיתה ב’ וכו’…). לפי התיאור שלהם הם קודם אימנו עם קוביות בגודל 32x32x32 ואז אימנו עם קוביות בגודל 64x64x64.

קישורים

  1. למי שמחפש מאגרי נתונים ובעיות בתחום הרפואי חייבים להכיר את: Grand-Challenges
  2. LUNA16  הינה תחרות לזיהוי גושים (Nodules) בכמעט אלף תמונות CT
  3. מאגר LIDC-IDRI בתחום סרטן הריאות
  4. MicroDicom – כלי חינמי מומלץ לראות Dicoms

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

למידת מכונה? לא לגאונים בלבד

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

נכתב על ידי Moti Gadian

תמיד חלמת ללמוד Machine Learning  או  Deep Learning  אבל נבהלת מכל הנוסחאות? , חיפשת דוגמאות קוד והתבלבלת מכל המושגים הטכניים? חושב שהנושא של למידת מכונה מיועד רק למתמטיקאים או מדענים? זה בדיוק המאמר בשבילך!

תחום ה Deep Learning צבר תאוצה בשנים האחרונות, וכולם רוצים לקחת חלק בטכנולוגיה הזו.

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

במאמר זה נתייחס לספרייה Keras (למרות שהיא יותר קרובה להיות Framework) שהינה ספרייה עילית לבניית מודלי בינה מלאכותית או בשמם המדעי Neural Networks .

ככלל, הFlow  של תהליך Deep Learning מורכב מ-3 חלקים עיקריים:

  1. הכנת המידע   (Data)
  2. הגדרת מודל
  3. בניית המודל
  4. אימון של המודל – הזנת
  5. המידע אליו והפעלת האלגוריתמים
  6. חיזוי (Prediction)  – שימוש במודל ובחינה שלו

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

ניתן להכין את המודל לשלב ה-Production אולם אנחנו נעסוק בעיקר בחלק שבו אנו בונים מודל ומאמנים אותו.

מוכנים? אז בואו נתחיל!

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

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

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

המבנה הפשוט של רשת נוירונים מורכב מ-3 חלקים (שכבות) :

  • קלט
  • שכבות ביניים (hidden) עליהם מבוצעים החישובים
  • פלט

די עם ההקדמות תן לכתוב קוד!

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

שלב ראשון – התקנת הספריות:

פתחו את הטרמינל (שורת הפקודה) והקלידו את הפקודה הבאה

Pip install tensorflow

חכו כמה דק’ עד שהספרייה תתוקן.

(אנחנו בעצם מתקינים את הספריהTensorflow  מבית Google אולם Keras  כבר כלול בה כשכבת אבסטרקציה)

שלב 2  –  הכנת ה Data

אנו נעזר ב data שכבר הוכן ונוקה עבורנו לצורכי למידה באדיבות  Keras אנו נשתמש בDataset שנקרא Mnist, זה בעצם אוסף של תמונות שחור לבן המכילות ספרות בכתב יד.

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

שימו לב שחילקנו את הdata  שלנו שלני חלקים:

  • החלק המרכזי שעליו נאמן את המודל (train)
  • החלק שעליו נעשה test וכך נוכל לבחון את הביצועים של המודל עבור מידע שעדיין הוא לא ראה ואומן עליו.

שלב 3 – בניית המודל , קונפיגורציה והזנת המידע (אימון)

שלב 4  – מדידת ביצועים

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

בסוף הריצה אנו אמורים לקבל משהו דומה לזה:

evaluation result: loss(0.10702921551428735) | accuracy(0.9663)

זהוו !! – כל הכבוד בניתם את המודל הראשון שלכם.

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

Posted by Moti Gadian in deep

טנזורים או נקודות במרחב ? סקירת מאמרים על ענני נקודות בלמידה עמוקה

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

נכתב על ידי Yizhak Ben-Shabat

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

הקדמה

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

  • רשתות קונבולוציה
  • נתונים – מאגרי תמונות עצומים הפכו לזמינים ופתוחים לכולם.
  • כוח חישוב

הזמינות של מידע תלת מימדי מתחילה לגדול בקצב מסחרר. בין אם מדובר בחלקי תיב”ם (CAD תכנון וייצור באמצעות מחשב) שתוכננו על ידי אדם או על מידע שנסרק על ידי חיישן LiDAR או מצלמת עומק (RGBD) – ענני נקודות נמצאים בכל מקום !

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

אתגרים

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

אתגרי רשתות הנוירונים:

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

אתגרי אופי הנתונים:

  • מידע חסר: העצמים הסרוקים בדרך כלל מוסתרים בחלקם ולכן חלק מהמידע חסר
  • רעש: כל החיישנים רועשים. יש מספר סוגים של רעש הכוללים פרטורבציות (לכל נקודה סרוקה יש הסתברות מסויימת להמצא סביב הנקודה האמיתית בתוך ספרה בעלת רדיוס בגודל מסויים) ונקודות חריגות outliers (נקודה המופיעה במיקום אקראי במרחב).
  • סיבובים: לאותו האוביקט יהיה ענן נקודות שונה אם הוא באוריינטציה שונה אפילו אם נסרקו בו אותם הנקודות, למשל ענני נקודות של מכונית שפונה ימינה או שמאלה.
  • ההרחבה ה”מיידית” להפעלת למידה עמוקה על ענני נקודות היא להעביר את הענן לייצוג נפחי (ווקסלים), ז”א איפה שאין דגימה שמים אפס ואיפה שיש דגימה שמים אחד. כך, נוכל לאמן רשת קונבולוציה עם פילטרים תלת מימדיים ולהימנע מכל האתגרים שקשורים לרשתות נוירונים על ענני נקודות (סריג הווקסלים פותר את בעיית המידע הלא סדור, ההמרה לווקסלים פותרת את בעיית הפרמוטציות ומספר הווקסלים קבוע ומוגדר מראש). אולם, לגישה זו יש חסרונות משמעותיים. ייצוג נפחי הופך להיות גדול מאד, מהר מאד. למשל, עבור תמונה אופיינית בגודל 256×256= 65536 פיקסלים נוסיף את מימד הנפח ונקבל 256X256X256=16777216 ווקסלים. זה הרבה מאד מידע (אפילו לכרטיסים גראפיים חדשים שכמות הזיכרון בהם גדל מאד בשנים האחרונות). מלבד גודל הזיכרון לאחסון, המשמעות של נתונים רבים כל כך היא זמן עיבוד איטי מאד. לכן, בהרבה מקרים “מתפשרים” ולוקחים רזולוציה נפחית נמוכה יותר (בחלק מהשיטות 64X64X64) שעולה לנו במחיר של שגיאת קוואנטיזציה.

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

הדטסט

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

אני אתמקד ב ModelNet40 מבית היוצר של פרינסטון. הוא מכיל 12311 מודלי תיבם עם 40 קטגוריות של אובייקטים (מטוסים, שולחנות, צמחים וכ’) ומיוצג על ידי רשתות משולשים Triangle mesh (קירוב של משטח חלק על ידי אוסף של מישורים הנפוץ בעולם הגראפיקה). מחלקים את הסט ל9843 מודלים לאימון ו 0135 לבדיקה. ביצעתי קצת ויזואליזציות של הדטסט עם קוד הגיטהאב שפותח עבור שיטת PointNet (תודה לצ’ארלס)

קטגוריות מדטסט ModelNet40

סקר ספרות

בפוסט הזה אסקור 3 שיטות שמבצעות למידה ישירות על ענני נקודות.

אבל שניה לפני זה אני רוצה להראות גרף עמודות המסכם מספר שיטות עדכניות (נכון לתחילת 2018) ובאיזה סוג נתונים כל אחת משתמשת. אפשר לראות שב-2015 רוב השיטות עבדו על תמונות דו מימדיות של אובייקט תלת מימדי שצולמו ממספר נקודות מבט שונות (Multi-View), ב-2016 מספר גדול יותר של שיטות השתמשו בייצוג נפחי עם PointNet החלוצה שהתחילה לעבוד על ענני נקודות ושב-2017 חלה עליה בשיטות המנסות לעבוד ישירות על ענני נקודות.

פרסומים אחרים לסיווג תלת מימדי (דיוק, שנה וסוג הנתונים)

PointNet – CVPR 2017

המאמר פורסם ב arXiv בסוף 2016 ומיד משך תשומת לב רבה. הגישה לפיתרון פשוטה מאד והם הציגו הסברים תיאורטיים למה היא עובדת טוב. הם אימנו פרספטרון רק שכבתי (MLP) על כל נקודה בנפרד (עם משקלים משותפים בין הנקודות השונות). כל נקודה “הוטלה” למרחב ממימד 1024. אחר כך פתרו את בעיית סדר הנקודות על ידי הפעלת פונקציה סימטרית (מקסימום) על כל הנקודות. התוצאה היא ווקטור באורך 1024 שניתן להתייחס אליו כמתאר (פיצ’ר) גלובאלי לכל ענן נקודות. את המתאר הזה הם הזינו למסווג לא לינארי (רשת fully connected). הם גם פתרו את בעיית הרוטציה על ידי הוספת תת רשת קטנה (T-net). תת הרשת הזו לומדת לשערך מטריצת טרנספורמציה על הנקודות (3×3) ועל מתארים ממימד ביניים (64×64). לקרוא לרשת זו “תת רשת” זה קצת מטעה כי כי גודלה קרוב לגודל הרשת הראשית. בנוסף, בגלל העלייה המשמעותית במספר הפרמטרים הם הוסיפו לפונקציית המחיר אילוץ שגורם למטריצת הטרנספורמציה לשאוף לארותוגונליות.

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

והם גם עשו סגמנטציה סמנטית על סצנות.

והם גם עשו שיערוך נורמאלים.

עבודה מדהימה! אני מאד ממליץ לקרוא (או אפילו לצפות בסרטון המצגת)

התוצאה שלהם עם ModelNet40 היתה 89.2% דיוק.

תודה ל https://arxiv.org/pdf/1612.00593.pdf

Cite: Charles R. Qi, Hao Su, Kaichun Mo, and Leonidas J. Guibas. Pointnet: Deep learning on point sets for 3d classication and segmentation. In The IEEE Conference on Computer Vision and Pattern Recognition (CVPR), July 2017.

הקוד זמין בגיטהאב: PointNet code 

Deep Sets – NIPS2017 ICLR2017

החבר’ה האלה מ CMU פרסמו את העבודה הזאת מספר שבועות לפני PointNet. הרעיון הכללי מאד דומה (לא לוקח צד בויכוח מי חשב עליו קודם). המיקוד של המאמר הזה הוא ייצור שכבה שמקבילה לקונבולוציה שפועלת על סטים (סט של נקודות במקרה שלנו) שנקראת שכבת ה”שקילות לפרמוטציות” ( permutation equivariance = PE) שזמן החישוב שלה הוא לינארי ביחס לגודל הסט. הם טוענים ששכבת ה PE היא הצורה הטובה לשיתוף משקלים למטרה זו. הניסויים מראים ביצועים משופרים לסיווג ענני נקודות (90%).

הם גם עושים חיזוי לסכום ספרות MNIST.

הם גם עושים זיהוי אנומליות בסטים.

עבודה מאד מעניינת, מאד ממליץ לקרוא למי שיותר מוכוון תיאוריות בשיטות למידה.

Cite: Ravanbakhsh, Siamak, Jeff Schneider, and Barnabas Poczos. “Deep learning with sets and point clouds.” arXiv preprint arXiv:1611.04500 (2016).

Zaheer, M., Kottur, S., Ravanbakhsh, S., Poczos, B., Salakhutdinov, R. R., & Smola, A. J. (2017). Deep sets. In Advances in Neural Information Processing Systems (pp. 3394-3404).

הקוד זמין בגיטהאב: Deep sets code

Pointnet++ – NIPS 2017

כשקראתי לראשונה את PointNet היה דבר אחד שמאד הטריד אותי – למה הם לא משתמשים בשכנויות מקומיות ? אז, אני מניח שזה הטריד גם אותם כי לא עבר זמן רב והם הוציאו לאויר העולם את PointNet++. זאת למעשה גירסה הירארכית של המקור. לכל שכבה יש שלושה תתי שלבים : דגימה, איסוף ופינטנוט (pointnetting). בשלב הראשון, הם בוחרים מרכזים, בשלב השני הם יוצרים אוסף של תתי עננים מקומיים מהשכנים של כל מרכז (ברדיוס נתון). לאחר מכן הם מזינים אותם לפוינטנט ומקבלים ייצוג מסדר גבוהה של תת הקבוצה. לאחר מכן הם חוזרים על התהלים (דוגמים מרכזים, מוצאים שכנים, ומריצים פוינטנט על הייצוג ממימד גבוהה יותר כדי לקבל ייצוג ממימד גבוהה עוד יותר). הם ביצעו שימוש ב3 שכבות כאלה (3 רמות הירארכיה). הם גם בחנו מספר שיטות איסוף על מנת להתגבר על בעיות הקשורות לצפיפות ענן הנקודות (בעיות שקיימות כשמשתמשים בכל חיישן תלת מימדי = נקודות צפופות קרוב לחיישן ודלילות רחוק מהחיישן). הם השיגו שיפור על המקור עם דיוק של 90.7% על ModelNet40 (שיפור גבוה יותר התקבל כשהשתמשו בווקטורי הנורמל לכל נקודה).

תודה ל https://arxiv.org/pdf/1706.02413.pdf


Cite: Charles R Qi, Li Yi, Hao Su, and Leonidas J Guibas. Pointnet++: Deep hierarchical feature learning on point sets in a metric space. arXiv preprint arXiv:1706.02413, 2017

Kd-Network – ICCV 2017

המאמר הזה משתמש במבנה הנתונים הידוע Kd-tree כדי ליצור סדר בענן הנקודות. לאחר הכנסת הענן למבנה, הם לומדים משקלים לכל צומת בעץ (שמייצגת חלוקה של המרחב בציר מסויים). המשקלים משותפים לכל ציר בכל רמה בודדת בעץ (כל הירוקים בתמונה למטה יש משקלים משותפים כי כולם מחלקים את המרחב בציר x). הם בחנו תת חלוקה ראנדומאלית ודטרמיניסטית של המרחב ומדווחים שהגישה הראנדומלית עובדת טוב יותר. הם מדווחים גם על מספר חסרונות. הגישה רגישה לסיבוב (כי רוטציה משנה את מבנה העץ) ורעש (במידה והוא משנה את מבנה העץ). אני מצאתי חיסרון נוסף – מספר הנקודות: לכל קלט בעל מספר נקודות שונה צריך לבצע דגימה מחדש למספר הנקודות שעליו הרשת אומנה או לחלופין לאמן רשת חדשה שתתאים למספר הנקודות הנתון.

הם מדווחים דיוק של 90.6% עבור 1024 נקודות בענן (עץ בעומק 10) ודיוק של 91.8 עבור ~32K נקודות (עץ בעומק 15) על ModelNet40.

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

הם גם עשו סגמנטציה לחלקים ו Shape Retrieval.

תודה ל https://arxiv.org/pdf/1704.01222.pdf

Cite: Roman Klokov and Victor Lempitsky. Escape from cells: Deep kd-networks for the recognition of 3d point cloud models. arXiv preprint arXiv:1704.01222, 2017.

סיכום

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

אפשר לראות שהתוצאות יחסית קרובות אחת לשניה ויש הרבה השפעות של פרמטרים וגורמים שונים. לכן, אני מוצא עניין רב בהבנה של אופן הפעולה של כל שיטה. PointNet ואחותה הגדולה PointNet++ עושים שימוש בפונקציות סימטריות כדי לפתור את בעיית הסדר בעוד שKd-Network עושה שימוש בעץ Kd. העץ גם פתר את בעיית הסדר בעוד שבפוינטים הפרספטרון אומן על כל נקודה בנפרד.

אני פיתחתי שיטה משלי (יחד עם המנחים שלי בטכניון כמובן) תוצרת כחול לבן לפתרון הבעיה הנקראת 3DmFV-Net. ארחיב עליה בפוסט הבא. למי שאין סבלנות מוזמן לקרוא את המאמר, להיכנס לפוסט המסביר על השיטה בבלוג שלי, לצפות בסרטון היוטיוב בנושא ולהשתמש בקוד. השיטה פורסמה בכנס 2018 IROS ובעיתון Robotics and Aautomation Letters.

Posted by Yizhak Ben-Shabat

AdaNet – איך לומדים איך ללמוד

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

נכתב על ידי Ori Cohen

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

אופטימיזציה של מודלים

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

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

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

כלומר, כמו כל בעיה שעליה אנו עובדים במדעי הנתונים – אם אנחנו לא יודעים לפתור את הבעיה ננסה להשתמש בלמידת מכונה כדי לפתור אותה…

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

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

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

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

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


לקוח מ introducing-adanet-fast-and-flexible

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

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

תוצאות מדווחות

התוצאות של מודל זה מרשימות במיוחד. ע”י שימוש ברשתות נוירונים פשוטות (Fully-connected feed forward) המערכת הצליחה ללמוד מודלים שמשתווים, או אפילו עולים עליהם בביצועיהם, בדר”כ ע”י שימוש בפחות פרמטרים מהמודלים הטובים ביותר שבנויות מאותו סוג רשת.

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

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

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

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

צלילה קלה לקוד

 עבור המעוניינים, את הקוד המלא למערכת (כולל הוראות התקנה ודוגמות) ניתן למצוא ב- https://github.com/tensorflow/adanet .

ניתן להתקין בקלות:

$ pip install adanet

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

head = tf.contrib.estimator.multi_class_head(10)

estimator = adanet.Estimator(
    head=head,
    subnetwork_generator=CNNGenerator(),
    max_iteration_steps=max_iteration_steps,
    evaluator=adanet.Evaluator(
        input_fn=adanet_input_fn,
        steps=None),
    adanet_loss_decay=.99)

כאשר head מגדיר שכבת ה-softmax במוצא הרשת המשולבת. (למשל 10 מחלקות)

CNNGenerator הינה ירושה של המחלקה adanet.subnetwork.Generator שמחזירה כמה רשתות מועמדות לכל איטרציה ומבוססת על מחלקה שיורשת מ-adanet.subnetwork.Builder

ההפעלה עצמה מתבצעת ע”י קריאה ל-

tf.estimator.train_and_evaluate()

למעשה, גם את הקופסה השחורה הזו ניתן להבין די בקלות, במיוחד עבור אלו שמכירים High level APIs כדוגמת Keras. הממשק Estimator מתפקד כמו כל פונקציית fit אחרת, ומתאים את הפרמטרים בהתאם לפונקצית המחיר, שבמקרה זה ניתנת בפרמטר evaluator. הייחוד בקריאה זו לממשק הוא שאנו נותנים לרשת לבחור את תתי הרשתות בצורה דינמית מתוך האופציות שאנו מספקים בפונקציה subnetwork_generator. למי שמעוניין, ממשק זה נמצא בשימוש גם באופן כללי ב- Tensorflow וניתן ללמוד עליו כאן.

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

Posted by Ori Cohen

מיני-פרויקט בלמידה חיזוקית (Reinforcement Learning)

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

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

אז אחרי שבניתי את הרובוט הזה (ראו את התמונה בעמוד הראשי של כל הכתבות) אני רוצה להכניס לו קצת בינה ודעת…

מטרתי הייתה ללמוד ולהתנסות ב Reinforcement Learning כי זה תחום מאוד מסקרן, בטח אחרי כל משחקי האטארי המפוצחים ע”י אלגוריתם (חודשים של התמכרות כשהייתי בן שבע 🙂 מעניין איך המחשב משחק בזה ? ? ?)

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

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

קצת טרמינולוגית RL

תודה ל https://becominghuman.ai/the-very-basics-of-reinforcement-learning-154f28a79071

State = מצב בו נמצא הסוכן (סך המידע הגלוי לו על הסביבה שלו). אפשר שמצבים יחשבו כראשוניים או כסופיים (ז”א תחילת\סוף משחק). במקרה של המשחק המתואר, מצב הינו: מיקומו של הסוכן על לוח המשבצות, מיקומו של הכדור על לוח המשבצות, ומשתנה בינארי שמשמעותו אם הכדור מוחזק ע”י הסוכן או לא.

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

Episode = אפיזודה\משחק שלם. ז”א שרשרת של מעברים ממצב ראשוני כלשהוא למצב סופי כלשהוא. במקרה של המשחק המתואר זה שרשרת המצבים מתחילת המשחק עד שהכדור מוחזק ע”י הסוכן והסוכן מגיע למשבצות האדומות.

Reward = תגמול אותו מקבל הסוכן כתוצאה מצמד (פעולה, מצב קודם). במקרה של המשחק המתואר החלטתי לתת תגמול גבוה  במקרה של נצחון, תגמול נמוך במקרה של הגעה של הסוכן למיקום הכדור והרמתו. ערכי התגמולים הם פרמטרים איתם שיחקתי (למשל בקוד כפי שתוכלו לראות זה כרגע 20, 5). כמו כן שיחקתי עם אפשרות לתת תגמול שלילי (ז”א עונש) על כל תור שחולף. שיטה זו בעצם גורמת לסוכן להתאמן על לנצח מהר ולא סתם לנצח. כי בכל תור בו עשה פעולה מיותרת הוא משלם מחיר…

π=Policy = מדיניות לפיה מחליט הסוכן איזו פעולה לבחור בכל מצב. למעשה פונקציה המקבלת מצב ומחזירה פעולה. בקוד תוכלו לראות שתי גישות אותן ניסיתי (ε-Greedy או Softmax Action Selection).

Return=G = סכום התגמולים שנתקבלו החל מצמד (פעולה, מצב) ועד לסיומה של האפיזודה

Quality=Q = טבלת הערך לכל צמד (פעולה, מצב). מחושב למשל כממוצע של כל ה-G שנתקבלו עבור על צמד (פעולה, מצב). המשמעות הינה כמה מוצלחת הפעולה הזו בהינתן המצב הזה?

Value=V = טבלת הערך לכל מצב. (לעיתים משתמשים ב V ולעיתים ב Q) המשמעות הינה עד כמה כדאי להימצא במצב הזה ? (מבחינת אפשרויות לנצחון)

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

אילו יש בידינו (בידי הסוכן) את הערכים האופטימליים לכל מצב\פעולה אז ישנן מדינויות  (Policies) לפעול כמו ε-greedy או softmax action selection. הרחבה על נושא זה תמצאו בכתבה הזו.

בכתבה זו נעסוק במספר שיטות לעידכון פונקציות הערך Q או V.

שיטת מונטה קרלו

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

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

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

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

שיטת Q-Learning

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

הערך Q עבור בחירת פעולה מסויימת At במצב מסויים St (בזמן\תור t) הינו הערך שהיה ועוד קומבינציה לינארית בין התגמול שנתקבל מפעולה זו לבין הערך הגבוה ביותר שניתן לקבל בעבור המצב הבא. (ע”י השוואה בין כל הפעולות האפשריות מהמצב החדש)

ראו כתבה קודמת ממוקדת על שיטה זו.

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

ניתן לראות בבירור שלאחר 100,000 משחקונים האלגוריתם כבר בנה טבלת Q מוצלחת כך שמצליח לפתור כל משחק במעט תורות.

שיטת Deep Q-Learning

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

גם כאן ניתן לפעול לפי מדיניות כלשהיא, למשל ε-Greedy או Softmax Action Selection או כל מדיניות אחרת שמשתמשת ב Q שהרשת מספקת לכל מצב. ואת הלימוד (back propagate) של הרשת מבצעים באופן דומה ל Q Learning, תוך כדי המשחק. התהליך כולו (עליו חוזרים לאורך אפיסודות\משחקים רבים) נראה כך:

  • מזינים את המצב הנוכחי לרשת ומקבלים וקטור q1 (ערך לכל פעולה אפשרית). הפעלת זו של הרשת הינה רק קדימה ז”א ללא אימון BackPropagation.
  • בוחרים פעולה ומשחקים אותה (או בעלת הערך הגבוה ממה שיצא ברשת או אקראי תלוי במדיניות)
  • מזינים את המצב הנוכחי (שהוא החדש) לרשת ומקבלים וקטור q2 (זו שוב הפעלת הרשת קדימה ז”א ללא אימון עדיין)
  • בונים וקטור פרדיקציה (שישמש לשלב האימון) באופן הבא:

לוקחים את הווקטור q1 כאשר מחליפים בו את האלמנט של הפעולה בה בחרנו ושמים שם ערך חדש לפי נוסחת ה- Q-Learning:

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

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

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

כשאימנתי לפי שיטה זו היו דרושים יותר משחקי אימון (מאשר בשיטת Q-Learning) כדי להגיע להצלחה, אני מניח שזה מכיוון שזה קצת overkill לבעיה. היתרון הגדול בשימוש ב CNN לבעיות כאלו הם כשהמצב (state) הינו תמונה (כמו במשחקי אטארי) ולא וקטור או מטריצה (תמציתית) המתארת את המצב הנוכחי במשחק. במקרים שהמצב הוא תמונה, לתחזק טבלת ערכים לכל מצב אינו ריאלי.

טיפים לניפוי הקוד

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

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

  • חישוב והצגה של גרף של כמות האיטרציות כפונקציה של מספר האפיזודות (המשחקים) אליהן אומן הסוכן אמור להיות גרף יורד. מדד זה סיפק לי מידע אם אני בכיוון הנכון בכל הרצה. במילים אחרות: ככל שהסוכן מתאמן יותר, הוא אמור לנצח יותר מהר במשחק.
  • להשוות ביצועים של סוכן שמתנהג בצורה אקראית לגמרי (כמה תורות בממוצע ינצח במשחק ?) לעומת מודל מאומן.
  • לייצר ויזואליזציה של המשחק (זה מומלץ בכל domain), לאפשר לי משחק אינטראקטיבי (ז”א שאוכל לשחק כנגדו) שיגרום לי להבין מה בכל זאת למד המודל. למשל למד אסטרטגיות כאלו שמביאות אותו לפעולות מחזוריות ולכן לתקיעות. בכל צעד שהמודל “משחק” להציג את השיקולים שלו (ז”א את ערכי ה Q  לאותו המצב)
  • להתחיל במקרה פשוט ולאט לאט לסבך אותו (זה גם מומלץ בכל domain). במקרה זה התחלתי בלוח פשוט ביותר של 2×2 כאשר מצב הפתיחה קבוע. ואז מצב פתיחה אקראי, ואז הגדלת גודל לוח המשחק, וכו’

הסבר על הקוד

את הקוד תמצאו ב GitHub שלי !

Solve_game.py זהו הקוד הראשי שפותר את המשחק לפי כל אחת מהשיטות (זה הקוד שיש להריץ).

Game.py המחלקה המממשת את המשחק עצמו, מאפשרת לאתחל משחק לפי פרמטרים שונים, להקליט משחק, לשחק (לא משנה אם אדם או אלגוריתם), להציג לוח משחק ועוד… שימו לב למטודה state_as_tensor שמחזירה את מצב המשחק כטנזור בגודל nxnx2. כאשר n הוא גודל לוח המשבצות וערוץ אחד עבור מיקום הסוכן והערוץ השני עבור מיקום הכדור ומצבו (מוחזק או לא מוחזק ע”י הסוכן)

interactive_play.py מאפשר למשתמש (אנושי) לשחק במשחק

policies.py מאפשר מדיניות משחק: אפסילון החמדן (Greedy Epsilon) או Softmax Selection. בפרט שליטה על דעיכת הפרמטר אפסילון (ε).

Deep_Q_learning.py מימוש שיטת Deep-Q Learning כמוסבר מעלה.

tabular_learning.py מימוש שיטות מונטה קרלו או Q-Learning כמוסבר מעלה.

לסיכום

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

ראו סרטון שמדגים את תהליך הלמידה: (בהתחלה משחק אקראי וככל שמתקדם האימון משחק יותר ויותר בהגיון):


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

אשמח לשאלות ופידבקים!

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

ניקוי רקע מתמונות (מודל ה- Tiramisu) – חלק ב’

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

נכתב על ידי shgidi

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

מודל ה Tiramisu והאימון

השם המלא של המודל נקרא: 100 layers Tiramisu , והוא מכיל 9 מיליון פרמטרים (לשם השוואה VGG מכיל 130 מיליון פרמטרים).

המודל מבוסס על ארכיטקטורת DenseNet שבה כל השכבות מחוברות זו לזו. מודל ה Tiramisu מוסיף גם חיבורי מעקפים לשכבות ה Up-sampling כמו רשת ה Unet.

https://arxiv.org/pdf/1611.09326.pdf

אימנו את המודל הזה על המאגר (המקוצץ) שלנו עם תמונות שהקטנו לגודל של 224×224 עם המאפיינים הבאים (כמו שמתואר במאמר המקורי):

פונקציית מחיר הינה  Cross Entropy Lossסטנדרטית, האופטימייזר הינו RMSProp עם Learning Rate=1e-3, גודל ה-Batch הינו 500 תמונות כאשר חילקנו את המאגר של ה-11 אלף תמונות ל 70% אימון (Training) , 10% בדיקה (Testing) ו 20% אימות (Validation).

סוגיות שעלו

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

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

http://cocodataset.org/#home

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

http://cocodataset.org/#home

Ground Truth גס מידי – התמונות במאגר COCO לא תויגו פיקסל, פיקסל אלא עם מצולעים (polygons), מה שפגע באימון.

http://cocodataset.org/#home

תוצאות

אחרי בערך 300 epochs (יותר מזה כבר הגענו ל Overfit) התוצאות שלנו היו משביעות רצון אך לא מושלמות, הגענו ל 84.6 IOU על קבוצת התמונות לבדיקה (Testing Set). כאשר נכון לכתיבת שורות אלו (2017) התוצאה הטובה ביותר (State of the art) לסגמנטציה של בני אדם הינה 85 IOU. לאובייקטים אחרים התוצאות כמובן טובות יותר או פחות, למשל לבתים וכבישים ניתן להגיע ל 90 IOU, לעומת זאת לעצים מגיעים ל 60 IOU.

להלן דוגמאות מוצלחות:

שמאל: תמונה מקורית, אמצע: ground truth, ימין: התוצאה שלנו http://cocodataset.org/#home

ניפוי ורישום (Debugging & Logging)

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

  1. בעיות מוקדמות – המודל לא מצליח להתכנס. יכול להיות מכל מיני סיבות כמו למשל באג בעיבוד מקדים (Pre-processing). הצגת התוצאות באופן ויזואלי עוזרת לפתור זאת. ראו פוסט זה בנושא.
  2. לדבג (לנפות) את הרשת עצמה – המדד העיקרי שלנו להצלחה היה IOU (ולא ה Loss), מה שעוזר זה להציג פרדיקציות (תוצאת סגמנטציה של הרשת) כל כמה איטרציות אימון (Epochs). בפוסט הזה תוכלו לקרוא עוד על איך לדבג מודלים.
  3. ניהול גירסאות – כשמאמנים מודל יש המון פרמטרים. חייב להודות שעוד לא מצאנו את השיטה האידיאלית מלבד פשוט לרשום את הקונפיגורציה ולשמור את המודלים\אימונים המוצלחים (*).
  4. כלי דיבוג (ניפוי) – כדי לשלב את הכול יצרנו Jupyter Notebook שאיפשרה לנו בצורה חלקה לטעון כל מודל וכל תמונה במהרה וכך לבחון כל תוצאה, כך יכולנו להשוות ולזהות בעיות.

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

http://cocodataset.org/#home

(*) שמירה אוטומטית של המודל הכי טוב עד עתה (לפי מדד IOU) עם פונקציית Keras  נוחה:

callbacks = [keras.callbacks.ModelCheckpoint(hist_model, verbose=1,save_best_only =True, monitor= ’val_IOU_calc_loss’), plot_losses]

שמנו לב שישנם שגיאות שניתן לצפות כמו תמונות עם חלקי גוף “חתוכים”, בגדים מאוד כהים או מאוד בהירים (לעיתים מתפרשים כרקע), תמונות בתנאי תאורה או איכות ירודה ועוד…

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

אל תנסו את האפליקציה שלנו בלילה J http://cocodataset.org/#home

Matting

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

http://cocodataset.org/#home

בעיית ה Matting הינה בעיה קשה והקלט שלה כולל גם את התמונה וגם תמונת  Trimapשהינה קווי מתאר של ה Egdes שלה (ראה בתרשים למעלה), מה שהופך אותה לבעיית מונחית למחצה (Semi-supervised).

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

לסיכום

כמו שציינתי בהתחלה, המטרה שלנו הייתה ליצור מוצר deep learning משמעותי. ואכן הצלחנו ולמדנו מכך המון.

בעיקר למדנו ש deployment של מודל הוא הרבה יותר פשוט ממה שחשבנו בהתחלה, אך אימון מודל הוא עדיין תהליך מאתגר – שדורש תכנון, הבנה, תיעוד ותחקור משמעותי.

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

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

נשמח לדיונים ולענות לשאלות!

Posted by shgidi in deep

ניקוי רקע מתמונות (מודל ה- Tiramisu) – חלק א’

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

נכתב על ידי shgidi

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

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

במהלך 2017, עשיתי את קורס fast.ai יחד עם אלון בורג, וקיבלנו הזדמנות לעשות מוצר AI: ההתקדמות המשמעותית של ה Deep Learning איפשרו לבצע דברים שלא היו אפשריים קודם, וכלים חדשים אפשרו לפתח מודלים ואפשר גישה אליהם בקלות הרבה יותר גדולה מבעבר.

המטרות שהגדרנו עבור המוצר הן:

  • מוצר מגניב ושימושי
  • מוצר שלא נעשה עדיין (או שלא נעשה כמו שצריך)
  • מוצר שלא יהיה קשה מדי לתכנן ולממש – תכננו להקדיש לעבודה יום בשבוע במהלך מספר חודשים
  • ממשק משתמש פשוט מושך וכיפי
  • דאטה לאימון זמין ונגיש
  • מוצר שישתמש בטכנולוגיות המתקדמות ביותר של deep learning
  • יוכל להפוך למוצר B2C אמיתי

להלן הרשמים שלי מהפרויקט.

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

תודה ל http://www.worldbuzzhub.com/cute-animals-selfies/

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

פילוח סמנטי (Semantic Segmentation)

פילוח סמנטי (Semantic Segmentation) היא אחת משלושת הבעיות הידועות ביותר בראייה ממוחשבת  יחד עם סיווג תמונות (Image Classification), וזיהוי אוביקטים (Object Detection). בעיית הפילוח הסמנטי היא למעשה גם בעיית קלאסיפיקציה למחלקות אבל של כל פיקסל בתמונה (ולא של התמונה כולה).

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

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

בפוסט הזה ניתן לראות רשת סגמנטציה מבוססת VGG:

http://warmspringwinds.github.io/tensorflow/tf-slim/2016/11/22/upsampling-and-image-segmentation-with-tensorflow-and-tf-slim/

http://warmspringwinds.github.io/tensorflow/tf-slim/2016/11/22/upsampling-and-image-segmentation-with-tensorflow-and-tf-slim/

ואחרי Bilinear Upsampling:

http://warmspringwinds.github.io/tensorflow/tf-slim/2016/11/22/upsampling-and-image-segmentation-with-tensorflow-and-tf-slim/

סגמנטציה מבוססת FCN

במאמר FCN= Fully Convolutional Networks for Semantic Segmentation החוקרים שיפרו את השיטה ע”י הוספת חיבורים נוספים בין השכבות. החיבורים בין שכבות מההתחלה, האמצע והסוף מגבירות את הדיוק של הפרטים הקטנים בתמונה.

האיור הבא מתאר את הארכיטקטורה אך מציג רק שכבות Pooling, Prediction, שאר השכבות מושמטות:

תודה ל-“Fully Convolutional Networks for Semantic Segmentation”

והתוצאות של שיטה זו אכן לא רעות בכלל:

תודה ל-“Fully Convolutional Networks for Semantic Segmentation”

הצלחה זו פתחה פתח לחוקרים נוספים לפתח מודלים נוספים ומשופרים לבעיית הסגמנטציה שמבוססים גם הם על Up-sampling ומעקפים Skip-connections. להלן קישורים רלוונטיים: 1, 2, 3.

ניסיון ראשון עם UNET  ו Tiramisu

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

(על רשת ה UNET תוכלו לקרוא גם בעברית פה)

מודל ה FCN לא נתן לנו תוצאות מספיק טובות אפילו בתור התחלה, מודל ה Tiramisu שאומן על מאגר התמונות  CamVid היה נראה מבטיח מבחינת תוצאות, ולמודל ה UNET יש את יתרון הקומפקטיות והמהירות. אז התבססנו על המימוש הזה של מודל ה Tiramisu

Semantic Object Classes in Video: A High-Definition Ground Truth Database (pdf) Pattern Recognition Letters (to appear) Brostow, Fauqueur, Cipolla (bibtex)

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

בחירה והכנה של ה DB לאימון

לבעיית הסגמנטציה יותר קשה לתייג ולכן למצוא מאגרי תמונות (מתוייגות). הפופולארי ביותר הינו מאגר  COCO המכיל 80K תמונות מ-90 קטגוריות שונות, מאגר VOC Pascal המכיל 11K תמונות מ-20 מחלקות שונות, ומאגר חדש יותר בשם  ADE20K. בחרנו לעבוד על COCO כי הוא מכיל יותר תמונות עם קטגוריית “אדם” (Person) מה שרלוונטי לבעיה שלנו.

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

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

אז השתמשנו ב API של מאגר COCO וקיצצנו את המאגר ל 11 אלף תמונות בהם השתמשנו לאימון, באופן הבא:

סינון רק תמונות שיש בהם אנשים (נשארנו עם 40K  תמונות) ואז סינון רק לתמונות המכילות 1-2 אנשים לכל היותר (כמו בתמונות סלפי),

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

דוגמאות לסינון שלנו:

שמאל: תמונה טובה לנו, אמצע: יותר מידי אנשים, ימין: דמות אדם קטנה מידי http://cocodataset.org/#home

עיברו לכתבת ההמשך כדי ללמוד על המודל שבחרנו ועל כל ההרפתקאות שבדרך לאימון המודל…

Posted by shgidi in deep

רשת ה U-Net: סגמנטציה של תמונות מיקרוסקופיות

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

נכתב על ידי Hen Grinberg

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

תודה ל MathWorks https://www.mathworks.com/help/vision/ug/semantic-segmentation-basics.html

שני בסיסי הנתונים (datasets) הנפוצים עבור משימה זו הם VOC2012 ו MSCOCO .

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

רשתות קונבולוציה מלאות (fully convolutional networks)

בשנת 2014 הופיעה פרדיגמה / ארכיטקטורה חדשה שפותחה על ידי מספר חוקרים באוניברסיטת ברקלי שנקראת “רשתות קונבולוציוניות מלאות” (FCN=fully convolutional networks). פרדיגמה זו שונה מכל מה שהיה לפניה בכך שהיא מחליפה  שכבות מחוברות באופן מלא (fully connected layers) בשכבות קונבולוציה וע”י כך מאפשרת לקבל בכניסה לרשת תמונות בגדלים שונים. כמו כן היא גם הרבה יותר מהירה משיטת סיווג קטעי תמונה. מאז, כמעט כל השיטות שהביאו לביצועים הטובים ביותר עבור בעיה זו השתמשו בארכיטקטורה זו.

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

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

תודה ל U-Net: Convolutional Networks for Biomedical
Image Segmentation

כיצד עובדת רשת U-Net?

הרשת מורכבת משני חלקים  – החלק המצמצם (החלק השמאלי בתרשים) והחלק המרחיב (החלק הימני בתרשים). החלק המצמצם בנוי לפי ארכיטקטורה קונבולוציונית טיפוסית, פרוצדורות  של 2 קונבולוציות בגודל 3×3  ללא שכבת אפסים מסביב לתמונה (padding) שאחריהן באה פונקציית אקטיבציה מסוג RELU, כאשר לאחר הקונבולוציה השניה מפעילים שכבת max pooling בגודל 2×2 עם קפיצות של 2 פיקסלים בכל פעם (stride=2) שמחזירה את הערך הגבוה ביותר בכל ריבוע בגודל 2×2 בתמונה. המטרה של שכבת הmax pooling  הינה להקטין את גודל התמונה. אחרי כל פרוצדורה מספר מפות הפיצ’רים (feature maps) גדל פי 2 וגודל התמונה קטן פי 2.

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

בשלב הבא משרשרים בין מפות פיצ’רים מקבילות של המפענח והמקודד (skip connections) כאשר מקטינים את גודלן של כל מפות הפיצ’רים של המקודד (encoder) על מנת שיהיו בעלות גודל זהה לאילו של המפענח (decoder). מטרת פעולת השרשור הינה לשפר את משימת המיקום של הפיקסלים בתמונה המורחבת (localization). בשלב הבא ישנן 2 קונבולוציות בגודל 3×3  ולאחר כל אחת מהן ישנה פונקציית אקטיבציה מסוג RELU. 

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

האימון והתוצאות

את הרשת הם מאמנים עם מאגר תמונות מתויגות (ז”א לאיזו מחלקה שייך כל פיקסל) עם פונקציית מחיר softmax cross entropy כאשר נותנים משקל גבוה יותר לפיקסלים בגבולות של המחלקות ומשקל המאזן תדירויות פיקסלים ממחלקות שונות:

w_{c}(x) נועד לאזן פיקסלים ממחלקות בתדירויות שונות, ו d_{1}(x), d_{2}(x) הינם המרחק מפיקסל x לגבול של המחלקה הקרובה ביותר או השניה הקרובה ביותר בהתאמה.

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

קישורים

הסברים, קוד ומודל להורדה של U-Net:

https://lmb.informatik.uni-freiburg.de/people/ronneber/u-net/

מימוש של רשתU-Net  ב Tensorflow:

https://www.kaggle.com/vijaybj/basic-u-net-using-tensorflow

Posted by Hen Grinberg in deep