word2vec

מודל 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

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

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

נכתב על ידי Vered Shwartz

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

מספרים במקום מילים

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

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

ייצוג לפי אינדקס (One-hot Vector)

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

כל מילה יושבת באינדקס נומרי מסוים ב-V, למשל יכול להיות ש”חתול” יהיה באינדקס 1242 ו”מחשב” באינדקס 1587. בניגוד למילון שבו כל מילה מופיעה בצורתה הבסיסית ובלי הטיות, באוצר המילים שלנו מופיעה כל צורה כמילה נפרדת. למשל, יכול להיות ש”חתולים” יהיה באינדקס 454. 

בייצוג one-hot-vector אנחנו מייצגים כל מילה באמצעות האינדקס שלה ב-V. מילה w באינדקס i מיוצגת ע”י וקטור שאורכו כגודל אוצר המילים – |V|, וכל ערכיו 0 פרט לאינדקס i שערכו 1. ככה ייראו וקטורים של כמה מילים לדוגמה:

nlp

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

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

ייצוג מבוסס שכנים (Distributional Vectors)

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

הרעיון הוא שווקטור של מילה w יהיה כעת עדיין באורך |V|, אבל המשמעות של כל כניסה בווקטור תהיה שונה. הערך של כניסה u בווקטור של w יהיה פרופורציונלי למס’ הפעמים ש-w ו-u הופיעו ביחד בקורפוס האימון. ההגדרה של “הופיעו יחד” גמישה, אבל באופן הפשוט נניח הופעה של u בחלון של k מילים (למשל k=5) סביב w. הערך עצמו יכול להיות מספר ההופעות המשותפות, מספר מנורמל (הסתברות), או מדד כמו PMI, המפחית את ההשפעה של השכיחות של כל מילה בפני עצמה.

שיטות ספירה (Count-based Vectors)

הדבר הפשוט ביותר לעשות יהיה לעבור על קורפוס האימון, ולבנות את מטריצת ההופעות המשותפות (בגודל |V|x|V|) של כל מילה w עם מילה u בחלון בגודל k. השורות של המטריצה משמשות בתור ווקטורי מילים, ואותן אפשר לנרמל (למשל באמצעות PMI). ככה יראו עכשיו הווקטורים של המילים לדוגמה. נראה יותר טוב, לא?

nlp

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

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

שיכוני מילים (Word Embeddings)

אז איך אפשר להשיג ווקטורים דחוסים ממימד נמוך ששומרים על התכונה הטובה של הייצוג מבוסס השכנים? נקפוץ כמה שנים קדימה (ונדלג על פתרון הביניים – הפעלת אלגוריתם להורדת מימדים כגון SVD על מטריצת ההופעות המשותפות). במקום לספור הופעות משותפות, אפשר להחליט מראש על מימד קטן כלשהו D (בדר”כ 50-1000, הכי נפוץ 300) ולחזות ווקטורים באורך D שישמרו על התכונה הזו – כלומר, שלמילים שמופיעות באותם ההקשרים יהיו ווקטורים דומים. למרות שהרעיון הזה כבר הוצע ב-2003 עי בנגיו וקולגות, הוא זכה לפופולריות רק ב-2013 כשמיקולוב וקולגות פרסמו את word2vec (שהמימוש שלו היה יעיל, והתוצאות מרשימות). ככה ייראו הווקטורים, קטני מימדים ודחוסים, ועדיין שומרים על תכונת הדמיון:

nlp

הרעיון של word2vec הוא ללמוד מטריצה בגודל |V| על D, שכל שורה בה מייצגת מילה. זאת המטריצה של מילות היעד (target). כעזר, מחזיקים מטריצה נוספת באותם המימדים שמייצגת מילה כמילת הקשר (context). שתי המטריצות מאותחלות אקראית. בזמן האימון, האלגוריתם עובר על כל הקורפוס, מילה-מילה, כאשר בכל פעם מילה אחת נחשבת ליעד והמילים המקיפות אותה בחלון נחשבות למילות ההקשר. יש שתי גרסאות לאלגוריתם: באחת (CBOW = continuous bag of words), מנסים לחזות את מילת היעד ממילות ההקשר, ובשנייה (skip-gram), מנסים באמצעות מילת היעד לחזות את מילות ההקשר. כפועל יוצא של החיזוי הזה, הווקטור של מילת היעד (ממטריצת היעד) מתקרב לווקטורים של מילות ההקשר (ממטריצת ההקשר). נוסף על כך, ווקטור היעד צריך להתרחק מווקטורי ההקשר של המילים שלא הופיעו בחלון. בגרסה היעילה יותר (negative sampling), דוגמים k מילים אקראיות כלשהן (שכנראה לא הופיעו בחלון) ומוסיפים לפונקציית המטרה גורם דומה לחיזוי של מילות ההקשר אבל עם המילים האקראיות ומוכפל במינוס 1.

חוץ מ-word2vec יש עוד לא מעט אלגוריתמים שונים ללמידה של word embeddings ע”י חיזוי, הנפוצים מביניהם GloVe של סטנפורד ו-FastText של פייסבוק. בשנים האחרונות הם משמשים כקלט לכל אלגוריתם למידה בתחום עיבוד שפה, בין אם בשימוש בווקטורים המאומנים שפורסמו עם השיטות האלה או באימון מחדש על קורפוס אחר. בהקשר של משימת סיווג הטקסטים שלנו, נוכל עדיין לייצג מסמך ע”י סכום או ממוצע וקטורי המילים. וקטור מסמך יהיה כעת באורך D והפיצ’רים שלו יהיו חבויים, אבל מסמכים עם מילים דומות עדיין יקבלו ייצוג דומה ויסווגו לאותו הנושא, ובמחיר חישובי נמוך יותר. המטרה הושגה!

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

nlp

תודה ל https://www.kdnuggets.com/2016/05/amazing-power-word-vectors.html

בתור מדד איכותי, נהוג לחשב הטלה של הווקטורים למימד 2 ע”י t-SNE או PCA ולצייר גרף מילים שממנו ניתן לראות שמילים דומות סמנטית ממוקמות זו לצד זו ב(הטלה למימד 2 של ה)מרחב הווקטורי. הנה דוגמת קוד לחישוב הזה, וכך למשל נראה חלק קטן מהגרף המתקבל כשמפעילים t-SNE על GloVe (מאומן מראש, בגודל 50):

nlp

העתיד של ייצוגי מילים

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

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

Posted by Vered Shwartz in deep