תמונה על ידי Deepmind on Unsplash
כפל מטריצה היא פעולה בסיסית המשמשת במערכות רבות, מרשתות עצביות ועד לשגרות מחשוב מדעיות. מציאת אלגוריתמים יעילים ונכונים להוכחה לכפל מטריצה יכולה להיות בעלת השפעה עצומה על הפיכת החישוב למהיר ויעיל יותר, אך היא משימה מאתגרת מאוד. המרחב של האלגוריתמים האפשריים הוא עצום, ושיטות מסורתיות לגילוי אלגוריתמים, כמו היוריסטיות בתכנון אנושי או חיפוש קומבינטורי, לרוב אינן אופטימליות.
Deepmindהפתרון שהוצע לאחרונה מבוסס AI לחיפוש אוטומטי חורג הרבה מעבר לאינטואיציה האנושית. הפתרון מורכב מסוכן למידת חיזוק עמוק בשם AlphaTensor, בנוי על גבי אלפא אפס. סוכן זה מאומן לשחק משחק לשחקן יחיד, TensorGame, כאשר המטרה היא לגלות אלגוריתמים יעילים מבחינה חישובית לכפל מטריצות.
AlphaTensor טובה במיוחד בטיפול במטריצות גדולות על ידי פירוק מכפלות מטריצות גדולות לכפלים קטנים יותר. יתר על כן, AlphaTensor יכול לשמש כדי להשיג ביצועים מתקדמים עבור כפל מטריצה לאחר כוונון עדין על התקן חומרה ספציפי.
ל- AlphaTensor יש פוטנציאל גדול להאצת מחשוב למידה עמוקה. בלמידה עמוקה, ניתן למפות פעולות רבות שגוזלות זמן לכפל מטריצות. על ידי שימוש ב-AlphaTensor כדי לייעל את הפעולות הללו, ניתן לשפר משמעותית את הביצועים הכוללים של מודלים של למידה עמוקה.
לאחרונה, OpenAlphaTensor, ה יישום קוד פתוח ראשון של AlphaTensor, שוחרר, שיכול לחולל מהפכה בכוח החישוב של מודלים של למידה עמוקה.
טנסור מכפל מטריצה
עבור לא מומחים באופטימיזציה של כפל מטריצה, ייתכן שלא יהיה פשוט להבין כיצד ניתן למפות פעולה כגון כפל מטריצה בטנזור תלת מימדי. אנסה להסביר זאת במילים פשוטות ובדוגמאות.
הבה ניקח בחשבון את המכפלה C = A*B, כאשר לשם הפשטות הן A ו-B הן מטריצות מרובעות בגודל N. ניתן למפות את פעולת הכפל בטנזור תלת מימדי של צורה (N^3, N^2, N^2). ממד הטנזור הראשון מייצג את המטריצה השטוחה A, הממד השני את המטריצה השטוחה B והממד השלישי את המטריצה השטוחה C.
לטנזור יש רק ערכים בינאריים (או 1 או 0) עבור כל ערך. שימו לב שהטנזור מייצג את פעולת הכפל, ולכן הוא בלתי תלוי בערכי המטריצות A ו-B.
כל כניסה של הטנזור תואמת את מקדם הפעולה. לדוגמה, כדי לחשב את C[1,1], יש צורך להכפיל את A[1,1] ו-B[1,1]. לכן, לכניסת הטנזור [0,0,0], המקבילה ל-A[1,1], B[1,1] ו-C[1,1], יהיה ערך 1. לעומת זאת, לחשב את C[1,1 ,2,1], A[1] אין צורך. לפיכך, שורת הטנזור T[N+0, :, XNUMX] תכיל רק אפסים.
התמונה למטה מציגה דוגמה של טנזור עבור N=2.
תמונה של DeepMind's מאמר פורסם ב טבע
כפי שמוצג ב-(ב) ו-(ג) באיור לעיל, ניתן ליישם אלגוריתם לחישוב המוצר באמצעות פירוק של הטנזור התלת-ממדי. ליתר דיוק, האלגוריתם שלהלן יכול לשמש להמרת פירוק טנזור (המטריצות U, V, W) לאלגוריתם של כפל מטריצה.
מטא-אלגוריתם פרמטר לחישוב תוצר המטריצה C=AB שהוצג ב-DeepMind's מאמר
המשחק Tensor
הבעיה של מציאת אלגוריתמים יעילים לכפל מטריצה היא מאתגרת ביותר מכיוון שמספר האלגוריתמים האפשריים שיש לקחת בחשבון גדול בהרבה ממספר האטומים ביקום, אפילו במקרים קטנים של כפל מטריצה.
DeepMind המירה את הבעיה הזו למשחק של שחקן יחיד, וקראה לה TensorGame. במשחק זה, השחקן בוחר כיצד לשלב ערכים שונים של מטריצות כדי להכפיל אותם. ניקוד מוקצה על סמך מספר הפעולות הנדרשות להשגת תוצאת הכפל הנכונה. המשחק מסתיים כאשר מגיעים לטנזור האפס או כאשר בוצע מספר המהלכים המרבי. הפירוק הסופי מוערך על סמך הערכה של הדירוג השיורי וקריטריוני אופטימיזציה מסוימים, כגון מורכבות זמן אסימפטוטית או זמן ריצה מעשי.
המיקום ההתחלתי ב-TensorGame מתאים לטנסור הכפל המטריצה המובע על בסיס אקראי כלשהו.
בכל שלב t של המשחק, השחקן רושם שלושה וקטורים
, המפרט את הטנזורים בדרגה 1 . מצב המשחק מתעדכן על ידי הפחתת הוקטורים שנבחרו על ידי השחקן:
איפה
הוא טנסור הכפל המטריצה.אם המשחק מסתיים בשלבים p, זה אומר שטנסור הכפל המטריצה
ניתן לפרק לטנזורים דרגה 1 , כלומר יש לו לפחות דרגה p.לאחר מכן ניתן לפרש את TensorGame כאלגוריתם של פירוק דירוג וניתן לראות את AlphaTensor כאלגוריתם להערכת דירוג הטנזור.
ארכיטקטורת AlphaTensor
עד כה למדנו על TensorGame והבהרנו כיצד ניתן לראות את הפתרון שלו כאלגוריתם של כפל מטריצה. כעת נחקור את המושגים העיקריים של AlphaTensor, האלגוריתם המשמש למשחק.
ארכיטקטורת AlphaTensor היא בעצם ארכיטקטורת שנאי מקודד-מפענח שבה:
- המקודד מקבל כקלט את מצב המשחק , n הפעולות הקודמות שבוצעו על ידי המודל (בדרך כלל n=7), ואינדקס הזמן t של הפעולה הנוכחית. מידע מוערם יחד בטנזור עם צורה (n+1, N^2, N^2, N^2). לאחר מכן טנזור זה עובר צורה ושינוי (באמצעות שלוש שכבות ליניאריות) בטנזור של צורה (N^2, N^2, c) כאשר c הוא הממד הפנימי של המודל.
- המפענח יוצר את פעולות n_steps מהווקטור המוטבע שניתן על ידי המקודד באופן אוטומטי רגרסיבי. כל פעולה מתאימה לאסימון של השלשות מייצג את אחת השלשות המפרקות את טנזור המשחק (כלומר הפחתת דרגתו)
המודל מאומן על ידי ריבוי אחורי ומשחק מודל לסירוגין. משחק מודל משמש ליצירת נתונים המשמשים לאחר מכן לאימון המודל. בפועל, המודל מאומן עם תערובת של נתונים שנוצרו באופן סינתטי ונתונים שנוצרו על ידי המודל במהלך המשחק. שלב המשחק נעשה על ידי נטילת טנזור תלת מימד המתאים לפעולת מטריצה ומשחקי n_actors עליו. כל שחקן משחק משחק או על בסיס סטנדרטי או על בסיס חלופי (שינוי הבסיס מיושם בהסתברות נתונה). לאחר מכן נאספות התוצאות וניתן להשתמש בהן בשלב האימון עם הנתונים הסינתטיים.
שלב המשחק מבוסס על חיפוש העצים של מונטה קרלו (MCTS) של AlphaZero, שונה לתמיכה במרחבי פעולה גדולים. בקיצור, לפני בחירת הפעולה, נתיבי n_sims נחקרים מפלט המודל עם חקירה עתידית מקסימלית של 5 שלבים. ההסתברויות שנוצרות על ידי המודל מותאמות לאחר מכן תוך התחשבות בנתיבים שנוצרו. ואז הפעולה עם הנתיב/ים העתידיים המבטיחים ביותר נבחרה כדי להמשיך את המשחק.
בזמן אימון המודל, הפרס הוא למעשה פרס שלילי (עונש). הערך המוחלט שלו עולה עם כל שלב נוסף הנדרש לפתרון המשחק. אם המודל נוקט M שלבים כדי לפתור TensorGame, התגמול הקשור למשחק הוא r=-m. אם המודל אינו מסוגל לפתור את TensorGame בשלבים max_rank, התגמול מחושב על ידי הערכת הדירוג של הטנזור הנותר. הדרגה נאמדת כסכום דרגות המטריצות המרכיבות את הטנזור. האומדן הוא גבול עליון לדרגה האמיתית של הטנזור.
בעת כוונון עדין של המודל, פרס העונש במצב הסופי צריך לקחת בחשבון גם את ההשהיה של האלגוריתם שמפיק המודל. נוסחת התגמול הופכת ל-rt'=rt+λbt, כאשר rt הוא סכימת התגמול שתוארה קודם לכן, bt הוא התגמול של המדד (לא אפס רק במצב הסופי), וכן λ הוא מקדם שצוין על ידי המשתמש.
העלאת מהירות (%) של אלגוריתמים שהתגלו ב-AlphaTensor המותאמים ל-GPU ו-TPU, שחולצו מהמאמר של DeepMind. המהירות נמדדת ביחס למטריצת הכפל הסטנדרטית (למשל cuBLAS עבור ה-GPU) על אותה חומרה ובהשוואה ל- אלגוריתם מרובע של שטראסן. מקור: Deepmind.
שחררתי לאחרונה OpenAlphaTensor, יישום הקוד הפתוח הראשון של AlphaTensor. בחלק זה אעבור על היישום. כפי שדיברנו קודם, ארכיטקטורת AlphaTensor היא פשוטה למדי, מבוססת על שנאי סטנדרטי עם ארכיטקטורת מקודד-מפענח. הרכיבים המעניינים ביותר של AlphaTensor הם השכבה הראשונה בחלק המקודד והדרך בה נדגמים הפעולות.
נתחיל עם שכבת הקידוד הראשונה.
# x.size = (N, T, S, S, S)
# scalars.size = (N, s)
batch_size = x.shape[0]
S = x.shape[-1]
T = x.shape[1]
x1 = x.permute(0, 2, 3, 4, 1).reshape(batch_size, S, S, S * T)
x2 = x.permute(0, 4, 2, 3, 1).reshape(batch_size, S, S, S * T)
x3 = x.permute(0, 3, 4, 2, 1).reshape(batch_size, S, S, S * T)
input_list = [x1, x2, x3]
for i in range(3): temp = self.linears_1[i](scalars).reshape(batch_size, S, S, 1) input_list[i] = torch.cat([input_list[i], temp], dim=-1) input_list[i] = self.linears_2[i](input_list[i])
x1, x2, x3 = input_list
בקטע שלמעלה, אנו מראים כיצד טנסור הקלט מפורק לשלושה טנסורים, המשמשים לאחר מכן ככניסות שאילתה, מפתח וערך של שכבת השנאי.
- על פני שלושת ממדי הטנזור המייצגים את המטריצות השטוחות (A, B, C), טנזור הקלט משוטח לאורך כל מימד יחד עם הממד המייצג את הפעולות הקודמות. בדרך זו, בכל עותק שטוח של טנזור הקלט, הממד הנבחר הוא צבירה של ערכי T-1 האחרונים והערך בפועל, עבור כל ערכי ה-S של הממד הנבחר, כאשר S=N^2. מבחינה פילוסופית, זה כאילו, עבור כל מימד, אנו מתמקדים במה שקרה בפעולות הקודמות בממד זה.
- הסקלרים ממופים בשלושה חללים שונים של ממד S^2, ולאחר מכן מעוצבים מחדש כך שיושרו עם הטנזורים שהושגו בנקודה הקודמת. מבחינה קונספטואלית, הסקלרים ממופים למרחב מוטמע של ממד S^2, ואז המידע המוטבע מנותק ל-S וקטורים ונערם יחדיו, בדומה למה שקורה לטקסט כאשר הוא מאוזן.
- אסימונים סקלריים משורשרים עם טנזור הקלט המחודש ואז ניתנים כקלט לשכבה ליניארית למיפוי מידע הפוקוס הסקלרים+היסטוריית ערוץ בממד הפנימי של המודל.
ניתן לפרש את שלושת השלבים הללו כדרך לתת למודל הן מידע על הסקלרים (כמו בשלב הזמן של TensorGame) והן התמקדות בפעולות הקודמות עבור כל ערוץ.
לגבי אופן הפקת הפעולות, מעניין לציין ש-AlphaTensor מייצר כפלט את הטריפלט u, v, w, שמטרתו להפחית את דירוג הטנזור. לשלושת הוקטורים יש גודל S ומכיוון שהם משורשרים על המודל לייצר וקטור בגודל 3*S. AlphaTensor מאומן עם אלגוריתם RL, כך שכל הפעולות האפשריות חייבות להתבטא במונחים של הסתברויות במרחב מסופר, כלומר המודל מייצר הסתברות על הפעולות השונות. המשמעות היא שכל וקטור במרחב 3S צריך להיות ממופה לפעולה אחרת. כתוצאה מכך נוצר מרחב פעולה בגודל |F|^(3S), כאשר |F| הוא מספר הערכים השונים שהרכיב של u, v, w יכול לקחת. בדרך כלל, הערכים מוגבלים ל-(-2, -1, 0, 1, 2), וכתוצאה מכך קרדינליות של 5 אלמנטים.
כאן מגיע אתגר גדול: כדי ליצור את הסתברויות הפעולה עבור מכפלת מטריצה של מטריצות בגודל 5, נצטרך זיכרון של 5^75 * 4 בתים, כלומר ~10^44 ג'יגה-בייט של זיכרון. ברור שאיננו יכולים לנהל מרחב פעולה כה גדול.
איך פותרים את הבעיה? כדי לצמצם את טביעת הרגל של הזיכרון של הסתברויות הפעולה נוכל לפצל את השלשות לנתחים קטנים יותר, "לסמן" אותם, ולהתייחס לנתחים כאל אסימונים שנוצרו בארכיטקטורת השנאי, כלומר האסימונים ניתנים כקלט למפענח ברגרסיבית אוטומטית. דֶרֶך. בדוגמה שלמעלה נוכל לפצל את השלשות ל-15 נתחים, להפחית את צריכת הזיכרון ל-15*5^(75/15)*4, כלומר 187.5 KB.
def _eval_forward(self, e: torch.Tensor): bs = e.shape[0] future_g = ( torch.zeros((bs, self.n_samples, self.n_steps)).long().to(e.device) ) ps = torch.ones((bs, self.n_samples)).to(e.device) e = e.unsqueeze(1).repeat(1, self.n_samples, 1, 1) future_g = future_g.view(-1, self.n_steps) ps = ps.view(-1) e = e.view(-1, e.shape[-2], e.shape[-1]) for i in range(self.n_steps): o_s, z_s = self.core(future_g[:, : i + 1], e) future_g[:, i], p_i = sample_from_logits(o_s[:, i]) ps *= p_i future_g = future_g.view(bs, self.n_samples, self.n_steps) ps = ps.view(bs, self.n_samples) return ( future_g, ps, z_s[:, 0].view(bs, self.n_samples, *z_s.shape[2:]).mean(1), )
למעלה אנו מציגים את קטע הקוד ליצירת הפעולה המלאה. בקוד, self.core מכיל את שכבת המפענח והטנסור e מייצג את הפלט של שכבת המקודד. אפס יכול להיחשב כ- אסימון במודלים של NLP ופעולות n_steps המייצגות את נתחי n_steps נוצרות בצורה מתקדמת.
המודל מחזיר שלוש כמויות:
- הפעולות שנוצרו
- ההסתברות הקשורה לפעולה המלאה
- הלוגיטים שנוצרו ליצירת הפעולה הראשונה (הנתח הראשון) שתשמש לחישוב ערך המודל.
כדאי להשקיע כמה מילים על הפרמטר n_samples. הפרמטר משמש לשלב המשחק והוא מאפשר למודל ליצור גרסאות שונות של השלשות שישמשו לאחר מכן לחקר מרחב הפעולה באלגוריתם חיפוש העץ של מונטה קרלו המשמש בתהליך המשחק. הפעולות השונות של n_samples נדגמות בהתאם למדיניות שנוצרת על ידי המודל.
שלב משחק
החלק המסובך ביותר בכל האלגוריתם הוא כנראה שלב ה-Acting המשמש לפתרון TensorGame. האלגוריתם אינו מוסבר לעומק במאמר AlphaTensor, מכיוון שהוא מבוסס על מספר מאמרים קודמים של DeepMind, שצוטטו ונמסרו כידוע. כאן, אשחזר את כל החלקים החסרים ואסביר צעד אחר צעד את היישום שלנו.
אנו יכולים לארגן את שלבי המשחק בשלושה מרכיבים שונים:
- חיפוש עצי מונטה-קרלו
- הדמיית המשחק
- חישוב מדיניות משופר
הבה ננתח אותם אחד אחד.
מונטה-קרלו חיפוש עצים (MCTS)
חיפוש עץ מונטה קרלו (MCTS) היא טכניקת בינה מלאכותית בשימוש נרחב למשחקים, במיוחד במשחקי לוח ומשחקי וידאו. האלגוריתם יוצר עץ משחק המדמה מהלכים ותוצאות פוטנציאליים ומשתמש בדגימה אקראית כדי להעריך את התגמול הצפוי עבור כל מהלך. לאחר מכן האלגוריתם בוחר באופן איטרטיבי את המהלך עם התגמול הצפוי הגבוה ביותר ומדמה תוצאות עד שהוא מגיע למצב סופני או תנאי עצירה מוגדר. ההדמיות משמשות להערכת ההסתברות לזכייה בכל מהלך ומנחות את תהליך קבלת ההחלטות. MCTS הוכח כיעיל במשחקים מורכבים שבהם מספר המהלכים והתוצאות האפשריים גדול, והוא שימש במערכות בינה מלאכותית מצליחות למשחקים, כגון AlphaGo.
ב-AlphaTensor נעשה שימוש בגרסה שונה של ה-MCTS המקורי. בפרט, במקום בחירה אקראית בפעולה מכל מרחב הפעולה, הפעולה נבחרת בין תת-קבוצה שנוצרה ישירות על ידי המודל (באמצעות n_samples שהוצגו לפני). לאחר מכן, התיקון לשדרוג המדיניות מיושם בשלב חישוב המדיניות המשופרת.
בהטמעה שלנו, החלטנו לשמור את כל המידע על עץ מונטה-קרלו במילון בעל גרסת ה-hash של מצב TensorGame כמפתח וכערכים את המידע הקשור למדינה עצמה. כל צעד מונטה-קרלו מתחיל מצומת ומדמה מיני-משחקים של n_sim, חוקר את העתיד עם אופק של 5 מהלכים. אם הצומת כבר נחקר בסימולציות קודמות, n_sim מותאם בהתחשב במספר הגישושים הקודמים. עבור כל צומת מספר הביקורים מאוחסן בטנזור N_s_a, שכן טנזור זה מכיל את מספר הביקורים לכל פעולת ילד של צומת (בין אלו שנדגמו על ידי המודל).
def monte_carlo_tree_search( model: torch.nn.Module, state: torch.Tensor, n_sim: int, t_time: int, n_steps: int, game_tree: Dict, state_dict: Dict,
): """Runs the monte carlo tree search algorithm. Args: model (torch.nn.Module): The model to use for the simulation. state (torch.Tensor): The initial state. n_sim (int): The number of simulations to run. t_time (int): The current time step. n_steps (int): The maximum number of steps to simulate. game_tree (Dict): The game tree. state_dict (Dict): The dictionary containing the states. """ state_hash = to_hash(extract_present_state(state)) if state_hash in state_dict: with torch.no_grad(): N_s_a = state_dict[state_hash][3] n_sim -= int(N_s_a.sum()) n_sim = max(n_sim, 0) for _ in range(n_sim): simulate_game(model, state, t_time, n_steps, game_tree, state_dict) # return next state possible_states_dict, _, repetitions, N_s_a, q_values, _ = state_dict[ state_hash ] possible_states = _recompose_possible_states(possible_states_dict) next_state_idx = select_future_state( possible_states, q_values, N_s_a, repetitions, return_idx=True ) next_state = possible_states[next_state_idx] return next_state
הקוד למעלה מציג את היישום שלנו של האלגוריתם. לעניין של פשטות הקוד, תיקון המדיניות מתבצע בפונקציית simulate_game.
סימולציית משחק
הפונקציה simulate_game אחראית לחקור את העץ המורכב מצמתים המייצגים מצב מסוים של TensorGame. הוא גם מריץ את המודל בכל פעם שנתקל בצומת עלים והוא מאחסן את כל מידע הצומת במילון state_dict. בואו נסתכל לעומק על יישומו:
@torch.no_grad()
def simulate_game( model, state: torch.Tensor, t_time: int, max_steps: int, game_tree: Dict, states_dict: Dict, horizon: int = 5,
): """Simulates a game from a given state. Args: model: The model to use for the simulation. state (torch.Tensor): The initial state. t_time (int): The current time step. max_steps (int): The maximum number of steps to simulate. game_tree (Dict): The game tree. states_dict (Dict): The states dictionary. horizon (int): The horizon to use for the simulation. """ idx = t_time max_steps = min(max_steps, t_time + horizon) state_hash = to_hash(extract_present_state(state)) trajectory = [] # selection while state_hash in game_tree: ( possible_states_dict, old_idx_to_new_idx, repetition_map, N_s_a, q_values, actions, ) = states_dict[state_hash] possible_states = _recompose_possible_states(possible_states_dict) state_idx = select_future_state( possible_states, q_values, N_s_a, repetition_map, return_idx=True ) trajectory.append((state_hash, state_idx)) # state_hash, action_idx future_state = extract_present_state(possible_states[state_idx]) state = possible_states[state_idx] state_hash = to_hash(future_state) idx += 1 # expansion if idx = max_steps: trajectory.append((state_hash, None)) if not game_is_finished(extract_present_state(state)): state = state.to(model.device) scalars = get_scalars(state, idx).to(state.device) actions, probs, q_values = model(state, scalars) ( possible_states, cloned_idx_to_idx, repetitions, not_dupl_indexes, ) = extract_children_states_from_actions( state, actions, ) not_dupl_actions = actions[:, not_dupl_indexes].to("cpu") not_dupl_q_values = torch.zeros(not_dupl_actions.shape[:-1]).to( "cpu" ) N_s_a = torch.zeros_like(not_dupl_q_values).to("cpu") present_state = extract_present_state(state) states_dict[to_hash(present_state)] = ( _reduce_memory_consumption_before_storing(possible_states), cloned_idx_to_idx, repetitions, N_s_a, not_dupl_q_values, not_dupl_actions, ) game_tree[to_hash(present_state)] = [ to_hash(extract_present_state(fut_state)) for fut_state in possible_states ] leaf_q_value = q_values else: leaf_q_value = -int(torch.linalg.matrix_rank(state).sum()) # backup backward_pass(trajectory, states_dict, leaf_q_value=leaf_q_value)
כל סימולציה מחולקת לשלושה חלקים:
- בחירה
- הרחבה
- גיבוי
בחלק הבחירה ההדמיה מופעלת על צמתי העצים שכבר נוצרו, והצומת הבא נבחר באמצעות הפונקציה הבאה:
def select_future_state( possible_states: List[torch.Tensor], q_values: torch.Tensor, N_s_a: torch.Tensor, repetitions: Dict[int, list], c_1: float = 1.25, c_2: float = 19652, return_idx: bool = False,
) -> torch.Tensor: """Select the future state maximizing the upper confidence bound."""
# q_values (1, K, 1) pi = torch.tensor( [ len(repetitions[i]) for i in range(len(possible_states)) if i in repetitions ] ).to(q_values.device) ucb = q_values.reshape(-1) + pi * torch.sqrt( torch.sum(N_s_a) / (1 + N_s_a) ) * (c_1 + torch.log((torch.sum(N_s_a) + c_2 + 1) / c_2)) if return_idx: return ucb.argmax() return possible_states[ucb.argmax()]
בפועל, הפעולה הממקסמת את פונקציית ucb:
עבור המצב הנתון נבחר. כאן Q מייצג את ערכי ה-Q שנוצרו על ידי המודל ו-π מייצג את ההתפלגות האקראית על הפעולות שנדגמו באמצעות מדיניות המודל. N(s, a) מייצג את מספר הביקורים של הצומת לפעולה a מצומת s.
ברגע ששלב הבחירה מגיע לצומת עלה, אם הסימולציה לא הגיעה למצב סופני (במונחים של חקירה מקסימלית, כלומר אופק עתידי, או סיום משחק), המודל משמש לבחירת צמתים חלופיים n_samples (הם יהיו עלה צמתים באיטרציה העוקבת). זה נקרא שלב ההרחבה, מכיוון שנוספים צמתים חדשים לעץ. לאחר מכן, לא נחקר צומת נוסף בסימולציה הנוכחית, אלא העלה q_value נשלח לשלב הסימולציה הבא: הגיבוי.
גיבוי הוא השלב האחרון של כל סימולציה. במהלך הגיבוי, אם צומת העלה היה מצב סופני, התגמול הסופי מחושב; אחרת ערך העלה q משמש כתגמול משוער. אז התגמול מופץ בחזרה במסלול הסימולציה תוך עדכון של מצבי q_values ועדכון מונה הביקורים N(s, a). בקטע שלמטה אנו מציגים את הקוד להפצת התגמול חזרה.
def backward_pass(trajectory, states_dict, leaf_q_value: torch.Tensor): """Backward pass of the montecarlo algorithm"""
reward = 0 for idx, (state, action_idx) in enumerate(reversed(trajectory)): if action_idx is None: # leaf node reward += leaf_q_value else: ( _, old_idx_to_new_idx, _, N_s_a, q_values, _, ) = states_dict[state] if isinstance(reward, torch.Tensor): reward = reward.to(q_values.device) action_idx = int(action_idx) if action_idx in old_idx_to_new_idx: not_dupl_index = old_idx_to_new_idx[int(action_idx)] else: not_dupl_index = action_idx reward -= 1 q_values[:, not_dupl_index] = ( N_s_a[:, not_dupl_index] * q_values[:, not_dupl_index] + reward ) / (N_s_a[:, not_dupl_index] + 1) N_s_a[:, not_dupl_index] += 1
חישוב מדיניות משופר
לאחר שכל הסימולציות הופעלו וה-MCTS מציע תמונת מצב מעניינת של העתיד הקרוב הגיע הזמן לעדכן את המדיניות הקשורה לצמתים החזויים ולהחזיר אותם, כך שניתן יהיה להשתמש בהם במהלך האימון. המדיניות המשופרת, בהתאם לשיטה המתוארת ב Hubert et al, משמש לניהול מרחבי פעולה גדולים. למעשה, עבור שטח חיפוש קטן, ניתן במהלך MCTS לדגום פעולה באופן אקראי ממרחב הפעולה ולהעריך את השפעתה. גישה דומה במרחב פעולה גדול בהרבה תוביל לכך שכל המסלולים יתפצלו בנתיבים שונים והיא תצטרך כמות אינסופית של מסלולים כדי לקבל נתונים סטטיסטיים משמעותיים ולאחר מכן לעדכן את המדיניות. מכיוון שכאן אנו משתמשים ב-sample-MCTS כדי למנוע את הפיזור, כלומר פעולות n_samples נדגמות בהתאם למדיניות המודל ואז MCTS פשוט בוחר באחת מהפעולות שנדגמו תוך כדי חקירת העץ, עלינו לקחת בחשבון את תיקון הדגימה בעת החישוב המדיניות המעודכנת הסופית שתשמש בעת אימון המודל.
בפועל, הפוליסה המשופרת מחושבת כ
איפה
def compute_improved_policy( state_dict: Dict, states: List[str], model_n_steps: int, model_n_logits: int, N_bar: int,
): """Compute the improved policy given the state_dict, the list of states. The improved policy is computed as (N_s_a / N_s_a.sum())^(1/tau) where tau is (log(N_s_a.sum()) / log(N_bar)) if N_s_a.sum() > N_bar else 1. """ policies = torch.zeros(len(states), model_n_steps, model_n_logits) N_bar = torch.tensor(N_bar) for idx, state in enumerate(states): N_s_a = state_dict[state][3] actions = state_dict[state][5] if N_s_a.sum() > N_bar: tau = (torch.log(N_s_a.sum()) / torch.log(N_bar)).item() else: tau = 1 N_s_a = N_s_a ** (1 / tau) improved_policy = N_s_a / N_s_a.sum() for sample_id in range(actions.shape[1]): action_ids = actions[0, sample_id] for step_id, action_id in enumerate(action_ids): policies[idx, step_id, action_id] += improved_policy[ 0, sample_id ] return policies
שים לב שביישום שלנו לאחר חישוב המדיניות מהטנסור N_s_a עלינו למפות אותה בחזרה לטנסור הפעולה המקורי. למעשה, N_s_a רק מחשיב את הפעולות שנדגמו על ידי המודל, בעוד שהמדיניות הסופית חייבת להכיל הסתברויות גם עבור הפעולות שלא נחקרו.
הבדלים ביחס לאלגוריתם אימון ChatGPT
AlphaTensor הוא החבר האחרון במשפחת AlphaGo/AlphaZero של שיטות בינה מלאכותית של DeepMind. שיטות אלו מבוססות על אלגוריתם Monte Carlo Tree Search (MCTS), אשר שוכלל ושופר על ידי DeepMind כדי להתמודד עם משימות מורכבות יותר ויותר. מערכת בינה מלאכותית נוספת, ChatGPT של OpenAI, שגרמה להרבה באזז בגלל הביצועים המדהימים שלה, הוכשרה בגישה אחרת, שנקראת למידה של חיזוק עם משוב אנושי (RLHF).
RLHF היא טכניקת כוונון עדין המשמשת לכוונון מודלים של שפה לפי סדרה של הוראות כתובות. היא משתמשת בהעדפות אנושיות כאות תגמול כדי לכוונן את המודל, ובכך ליישר את ההתנהגות של מודל השפה עם ההעדפות המוצהרות של קבוצה מסוימת של אנשים, במקום מושג רחב יותר של 'ערכים אנושיים'.
לעומת זאת, MCTS הוא אלגוריתם חיפוש מבוסס עץ המשמש לקביעת המהלכים האופטימליים במשחקים. הוא מדמה מהלכים פוטנציאליים ומעדכן את הערכים של כל מהלך על סמך התוצאות שלהם, ומנחה את הבחירה של המהלך הטוב ביותר.
RLHF אוספת נתונים מהדגמות שנכתבו על ידי אדם והשוואות עם תווית אנושית בין מודלים של בינה מלאכותית, ומכשירה מודל תגמול כדי לחזות את ההעדפות של קבוצת אנשים נתונה. מודל התגמול משמש לאחר מכן לכוונון עדין של דגמי הבינה המלאכותית. MCTS, לעומת זאת, משתמשת בסימולציות והערכות כדי לקבוע את ההחלטה הטובה ביותר.
למרות שמדובר בגישות שונות, ל-RLHF ול-MCTS יש קווי דמיון. שתי טכניקות הבינה המלאכותית משתמשות בשיטות קבלת החלטות ופתרון בעיות, ושתיהן משתמשות בגישת ניסוי וטעייה כדי לחקור אפשרויות שונות ולקבל החלטות על סמך מידע זמין. שניהם גם תהליכים איטרטיביים המשתפרים עם הזמן ככל שנצברים יותר מידע וניסיון.
הבחירה בין RLHF ל-MCTS תלויה במשימה שעל הפרק. RLHF הוא אידיאלי כאשר אין מדד ברור להערכת ביצועי המודל, בעוד ש-MCTS הוכיח את עצמו כיעיל במשימות דמויות משחק שבהן ידע וחקר העתיד מעניקים למודל יתרון משמעותי.
אופטימיזציית קוד לאימון AlphaTensor
יישום אלגוריתם האימון של AlphaTensor דורש מציאת הפשרה המושלמת בין מהירות האימון וצריכת הזיכרון. כפי שניתן לראות בסעיף המודל, עצם התחשבות באסימוני הפעולה יכולה לחסוך הרבה זיכרון, אבל צמצום שטח פעולה אגרסיבי מדי יכול להוביל גם לירידה ברמת הדיוק וגם לביצועים איטיים יותר. זה האחרון קורה מכיוון שכל האסימונים נוצרים ברצף בצורה אוטורגרסיבית על ידי מפענח הדגם. לכן, זמן ההסקה גדל באופן ליניארי עם מספר האסימונים לכל פעולה ברגע שה-softmax במרחב הפעולה אינו צוואר הבקבוק יותר.
בעת הקמת אימון AlphaTensor, נמצאו הקשיים העיקריים בהתמודדות עם תהליך המשחק. אם הטנסורים אינם מאוחסנים בפורמט הנכון, ה-MCTS יכול בקלות לגרום לצמיחה בלתי מבוקרת בשימוש בזיכרון. מצד שני, אם מספר הטנזורים המאוחסנים במהלך כל סימולציה מצטמצם מדי, ה-MCTS יכול להשקיע אינסוף זמן בחישוב מחדש של המצבים הנדרשים.
בואו ניקח דוגמה לשלב הדמיית המשחק, שבו המשחק נחקר על ידי הסתכלות על תרחישים עתידיים אפשריים. עבור כל מצב, אם לא נשמור את הפעולות שנוצרו על ידי המודל ונחליט לשמור רק את הזרע האקראי המשמש לדגימת הפעולות מהמדיניות, אז בכל פעם שנחקור צומת עץ נצטרך לחשב מחדש את המדיניות ו ואז לדגום את הפעולות. ברור שהחלטנו לאחסן את הפעולות שנדגמו כדי לחסוך זמן וכדי למנוע צורך לנהל שיתוף מודלים בין תהליכים שונים במקרה של מקבילות מחקר MCTS. עם זאת, רק שמירת הפעולות לא הספיקה כדי לקבל שלב פעולה יעיל מספיק. למעשה, הזמן להמרת פעולות n_steps לטריפלט (u, v, w), הפחתת מצב טנסור המשחק ויצירת טנסור 3D החדשים מפעולות n_samples יהיה בקלות צוואר בקבוק עבור כל האימון. שנית, לא רצינו לאחסן את כל המצבים העתידיים האפשריים עבור כל פעולה שנדגמה, שכן לכך תהיה השפעה עצומה על הזיכרון המשמש את האלגוריתם. נניח שהגדרנו n_samples=32, n=7 ו-N=5, ובואו נזכור ש-N הוא גודל מכפלת המטריצה המרובעת שאנו רוצים להקטין ו-n הוא מספר הפעולות הקודמות שזכורות המודל. במצב זה, לכל טנזור מדינה תהיה הצורה (8, 25, 25, 25), שכפול ב-32 יביא ל-3282525254 בתים לכל צומת בגרף. כעת, בהתחשב בכך שכל סימולציה בשלב ההרחבה מייצרת צומת חדש (ו-n_sim=200), תהיה לנו צריכת זיכרון סופית של 200328252525*4 = 3.2GB עבור צומת ה-MCTS הראשון בלבד. בתרחיש הגרוע ביותר, תוך בחינת צמתי max_rank פועלים (כאשר max_rank=150), הדבר יביא לצריכת זיכרון כוללת של 150 * 3.2GB = 480GB בזיכרון RAM (או זיכרון GPU אם כל הטנזורים היו מאוחסנים ב-GPU) . הרצנו את ההדרכה בתחנת העבודה שלנו עם 128 ג'יגה-בייט של זיכרון RAM ו-48 ג'יגה-בייט של זיכרון GPU, אז נאלצנו להפחית את צריכת הזיכרון.
מכיוון שלא רצינו להגדיל את זמן הביצוע, אימצנו אופטימיזציה שמנצלת את היתירות בטנסורי המדינה המיוצרים. למעשה, לטנזורים יש n-1 פעולות קודמות משותפות, שאותן ניתן לאחסן פעם אחת ולא לחזור על כל טנזור מאוחסן. זה מביא להפחתת זיכרון של 2/7~28%, כלומר, במקרה הגרוע ניתן לאחסן 137GB. בשלב זה, פשוט על ידי גיזום החלק הלא בשימוש של העץ (כגון המסלולים הלא נבחרים) ואחסון הטנזורים בזיכרון המעבד, הצלחנו להימנע מכל שגיאת זיכרון במהלך האימון.
מכיוון ש-OpenAlphaTensor הוא כעת קוד פתוח, נפתחות מספר דרכים מרגשות לפיתוח נוסף.
התקדמות טבעית היא כוונון עדין של OpenAlphaTensor בהתקני חומרה יעד. זה צפוי להוביל לביצועים חישוביים תחרותיים מאוד. אני אפרסם עוד על הביצועים של OpenAlphaTensor על חומרות שונות GitHub. בזמן כתיבת מאמר זה, OpenAlphaTensor עבר הכשרה.
התקדמות חשובה נוספת תהיה התמיכה בהידור מרחוק, המאפשרת למשתמשים לבנות אלגוריתמים מותאמים למכשירי קצה. ניתן להשיג זאת על ידי אחסון מודל OpenAlphaTensor בשרת, בעוד שאלגוריתם הכפל המטריצה מוערך על חומרה שונה.
זה יכול להיות גם חשוב להרחיב את התמיכה במהדרים שונים כדי לחשב את תיקון התגמול מבוסס השהייה. מהדרים שונים יכולים להוביל לאלגוריתמים אופטימליים שונים בחומרה נתונה. לדוגמה, מאמר DeepMind הראה תוצאות מבטיחות באמצעות JAX ו-XLA מהדר על TPU ו-Nvidia GPUs. יהיה מעניין להעריך זאת באמצעות NCCL ב-Nvidia או LLVM במעבדים.
לבסוף, הרחבת אלגוריתם המודל וההדרכה לתמיכה בגדלים גדולים יותר של מטריקס נותרה אתגר פתוח גדול. נכון לעכשיו, OpenAlphaTensor תומך בגודל מטריצה מרבי של 5, אך ניתן ליישם אותו על ידי פיצול מכפלות מטריצות גדולות יותר לקבוצות של MMs זעירים בגודל קטן מ-5. גישה זו אינה אופטימלית, וביצוע ההפחתה ישירות על הטנזור הגדול המתאים ל- MM מלא יכול תיאורטית להוביל לתוצאות טובות יותר.
דייגו פיורי הוא ה-CTO של Nebuly AI, חברה המחויבת להפוך את אופטימיזציית AI לחלק מערך הכלים של כל מפתח.
- הפצת תוכן ויחסי ציבור מופעל על ידי SEO. קבל הגברה היום.
- Platoblockchain. Web3 Metaverse Intelligence. ידע מוגבר. גישה כאן.
- מקור: https://www.kdnuggets.com/2023/03/first-open-source-implementation-deepmind-alphatensor.html?utm_source=rss&utm_medium=rss&utm_campaign=first-open-source-implementation-of-deepminds-alphatensor
- :הוא
- ][עמ'
- $ למעלה
- 1
- 3d
- 8
- a
- יכול
- אודות
- מֵעַל
- מוּחלָט
- מאיצה
- פי
- לפיכך
- חֶשְׁבּוֹן
- דיוק
- להשיג
- הושג
- פעולה
- פעולות
- למעשה
- הוסיף
- נוסף
- מותאם
- מאומץ
- לקדם
- יתרון
- לאחר
- סוֹכֵן
- - צבירה
- תוֹקפָּנִי
- AI
- מערכות AI
- מטרות
- אַלגוֹרִיתְם
- אלגוריתמים
- תעשיות
- מאפשר
- מאפשר
- לבד
- כְּבָר
- חלופה
- בין
- כמות
- לנתח
- ו
- אחר
- יישומית
- גישה
- גישות
- ארכיטקטורה
- ARE
- מאמר
- מלאכותי
- בינה מלאכותית
- AS
- שהוקצה
- המשויך
- At
- אוטומטי
- זמין
- הימנעות
- בחזרה
- גיבוי
- מבוסס
- בעיקרון
- בסיס
- BE
- כי
- הופך להיות
- לפני
- להיות
- להלן
- בנצ 'מרק
- הטוב ביותר
- מוטב
- בֵּין
- מעבר
- לוּחַ
- משחקי לוח
- קשור
- רחב
- BT
- לִבנוֹת
- נבנה
- by
- נקרא
- CAN
- לא יכול
- מקרה
- לגרום
- גרם
- מסוים
- לאתגר
- אתגר
- שינוי
- ערוץ
- ChatGPT
- ילד
- בחירה
- בחירה
- נבחר
- מצוטט
- ברור
- בבירור
- קוד
- אוסף
- לשלב
- מְחוּיָב
- Common
- חברה
- לעומת
- תחרותי
- מורכב
- מורכבות
- רכיבים
- מורכב
- פשרה
- חישוב
- כוח חישובי
- לחשב
- מחשוב
- מושגים
- מבחינה רעיונית
- מצב
- אמון
- לשקול
- נחשב
- בהתחשב
- רואה
- צְרִיכָה
- מכיל
- להמשיך
- לעומת זאת
- הומר
- ליבה
- תוֹאֵם
- מתכתב
- יכול
- דלפק
- CPU
- יוצר
- יוצרים
- הקריטריונים
- ראש אגף טכנולוגיה
- נוֹכְחִי
- כיום
- נתונים
- התמודדות
- להחליט
- החליט
- החלטה
- קבלת החלטות
- החלטות
- עמוק
- למידה עמוקה
- Deepmind
- תלוי
- מְתוּאָר
- לקבוע
- מפתח
- צעצועי התפתחות
- מכשיר
- התקנים
- DICT
- אחר
- קשיים
- מֵמַד
- ממדים
- ישירות
- לגלות
- מגלה
- נָדוֹן
- הפצה
- מחולק
- מטה
- ירידה
- בְּמַהֲלָך
- e
- כל אחד
- מוקדם יותר
- בקלות
- אדג '
- אפקטיבי
- יעיל
- או
- אלמנט
- אלמנטים
- מוטבע
- מסתיים
- משופר
- עֲנָקִי
- מספיק
- כניסה
- שגיאה
- לְהַעֲרִיך
- מוערך
- Ether (ETH)
- להעריך
- העריך
- הערכה
- הערכות
- אֲפִילוּ
- כל
- דוגמה
- דוגמאות
- מרגש
- הוצאת להורג
- הרחבה
- צפוי
- ניסיון
- להסביר
- מוסבר
- מעללים
- חקירה
- לחקור
- חקר
- היכרות
- ביטא
- להאריך
- מאריך
- מאוד
- למדי
- משפחה
- מהר יותר
- מָשׁוֹב
- מעטים
- תרשים
- סופי
- מציאת
- ראשון
- לָצוּף
- להתמקד
- לעקוב
- הבא
- עָקֵב
- בעד
- טופס
- פוּרמָט
- נוסחה
- מצא
- החל מ-
- מלא
- פונקציה
- יסודי
- נוסף
- פיתוח עתידי
- עתיד
- מִשְׂחָק
- משחקים
- ליצור
- נוצר
- מייצר
- יצירת
- לקבל
- מקבל
- לתת
- נתן
- נתינה
- מטרה
- Goes
- טוב
- GPU
- GPUs
- גרף
- גדול
- קְבוּצָה
- קבוצה
- גדל
- צמיחה
- מדריך
- יד
- טיפול
- קרה
- קורה
- חומרה
- מכשיר חומרה
- התקני חומרה
- יש
- יש
- כאן
- הגבוה ביותר
- אופק
- איך
- איך
- אולם
- HTTPS
- עצום
- בן אנוש
- i
- חולה
- אידאל
- IDX
- תמונה
- פְּגִיעָה
- ליישם
- הפעלה
- חשוב
- לשפר
- משופר
- in
- להגדיל
- עליות
- יותר ויותר
- עצמאי
- מדד
- מידע
- בתחילה
- קלט
- במקום
- הוראות
- מוֹדִיעִין
- מעניין
- פנימי
- הציג
- אינטואיציה
- IT
- איטרציה
- שֶׁלָה
- עצמו
- jpg
- KDnuggets
- שמור
- מפתח
- ידע
- ידוע
- שפה
- גָדוֹל
- גדול יותר
- אחרון
- חֶבִיוֹן
- האחרון
- שכבה
- שכבות
- עוֹפֶרֶת
- למד
- למידה
- לינקדין
- רשימה
- נראה
- הסתכלות
- מגרש
- עשוי
- ראשי
- גדול
- לעשות
- עשייה
- לנהל
- ניהול
- רב
- מַפָּה
- מיפוי
- מַטרִיצָה
- דבר
- מקסימום
- משמעות
- משמעותי
- אומר
- חבר
- זכרון
- שיטה
- שיטות
- מטרי
- חסר
- תַעֲרוֹבֶת
- מודל
- מודלים
- שונים
- מודול
- יותר
- יותר יעיל
- יתר על כן
- רוב
- המהלך
- מהלכים
- מוכפל
- טבעי
- טבע
- ליד
- הכרחי
- צורך
- נחוץ
- שלילי
- רשתות
- עצביים
- רשתות עצביות
- חדש
- הבא
- NLP
- צומת
- צמתים
- לא מומחים
- רעיון
- מספר
- Nvidia
- מושג
- of
- המיוחדות שלנו
- on
- ONE
- לפתוח
- קוד פתוח
- OpenAI
- מבצע
- תפעול
- אופטימלי
- אופטימיזציה
- מטב
- אופטימיזציה
- אפשרויות
- מְקוֹרִי
- אחר
- אַחֶרֶת
- תפוקה
- מקיף
- מאמר
- ניירות
- פרמטר
- חלק
- מסוים
- במיוחד
- חלקים
- אֲנָשִׁים
- ביצועים
- ביצוע
- שלב
- חתיכות
- אפלטון
- מודיעין אפלטון
- אפלטון נתונים
- לְשַׂחֵק
- שחקן
- משחק
- נקודה
- מדיניות
- מדיניות
- עמדה
- אפשרי
- פוטנציאל
- כּוֹחַ
- מעשי
- תרגול
- לחזות
- חזה
- העדפות
- מוצג
- קודם
- הסתברות
- כנראה
- בעיה
- תהליך
- תהליכים
- לייצר
- מיוצר
- המוצר
- התקדמות
- פרוגרסיבי
- מבטיח
- מוּצָע
- מוכח
- מוכח
- לפרסם
- לאור
- RAM
- אקראי
- דרגות
- במקום
- הגיע
- מגיע
- לאחרונה
- להפחית
- מופחת
- הפחתה
- מעודן
- למידה חיזוק
- שוחרר
- נותר
- שְׂרִידִים
- ראוי לציון
- לזכור
- מרחוק
- חזר
- המייצג
- מייצג
- נדרש
- דורש
- אחראי
- מוגבל
- תוצאה
- וכתוצאה מכך
- תוצאות
- לַחֲזוֹר
- החזרות
- לְחוֹלֵל מַהְפֵּכָה
- לגמול
- שׁוּרָה
- rt
- הפעלה
- s
- אותו
- שמור
- חסכת
- תרחיש
- תרחישים
- תכנית
- חיפוש
- שְׁנִיָה
- סעיף
- זרע
- נבחר
- בחירה
- מבחר
- עצמי
- סט
- הצבה
- כמה
- צוּרָה
- שיתוף
- קצר
- צריך
- לְהַצִיג
- הראה
- הופעות
- לאותת
- משמעותי
- באופן משמעותי
- דומה
- הדמיון
- פָּשׁוּט
- פשטות
- בפשטות
- הדמיה
- since
- מצב
- מידה
- גדל
- קטן
- קטן יותר
- תמונת בזק
- So
- פִּתָרוֹן
- לפתור
- פותר
- כמה
- מָקוֹר
- מֶרחָב
- רווחים
- ספציפי
- במיוחד
- מפורט
- מְהִירוּת
- לבלות
- הוצאה
- לפצל
- מרובע
- מְגוּבָּב
- התמחות
- תֶקֶן
- התחלה
- התחלות
- מדינה
- מדינה-of-the-art
- אמור
- הברית
- סטטיסטיקה
- שלב
- צעדים
- סְתִימָה
- חנות
- מאוחסן
- חנויות
- פשוט
- מוצלח
- כזה
- תמיכה
- תומך
- סינטטי
- נתונים סינתטיים
- באופן סינתטי
- מערכת
- מערכות
- מותאם
- לקחת
- לוקח
- נטילת
- יעד
- המשימות
- משימות
- טכניקות
- מסוף
- מונחים
- זֶה
- אל האני
- העתיד
- הגרף
- המידע
- המדינה
- שֶׁלָהֶם
- אותם
- בכך
- לכן
- אלה
- שְׁלִישִׁי
- שְׁלוֹשָׁה
- תלת-ממדי
- דרך
- זמן
- דורש זמן רב
- ל
- יַחַד
- אסימון
- טוקניזציה
- token
- מטבעות
- גַם
- ארגז כלים
- חלק עליון
- לפיד
- סה"כ
- מסורתי
- רכבת
- מְאוּמָן
- הדרכה
- רכבות
- מסלול
- טרנספורמציה
- טיפול
- נָכוֹן
- להבין
- עולם
- לא בשימוש
- עדכון
- מְעוּדכָּן
- עדכונים
- עדכון
- שדרוג
- us
- נוֹהָג
- להשתמש
- משתמשים
- בְּדֶרֶך כְּלַל
- ערך
- ערכים
- שונים
- גרסה
- וִידֵאוֹ
- משחקי וידאו
- לְבַקֵר
- ביקורים
- W
- דֶרֶך..
- מה
- אשר
- בזמן
- באופן נרחב
- ויקיפדיה
- יצטרך
- זכייה
- עם
- מילים
- תחנת עבודה
- ראוי
- היה
- כתיבה
- כתוב
- X
- זפירנט
- אפס