ליבה פדרית

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

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

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

סקירה כללית

מטרות, שימושים מיועדים והיקף

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

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

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

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

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

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

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

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

שפה

ממשק פייתון

TFF משתמש בשפה פנימית כדי לייצג חישובים מאוחדים, שהתחביר שלהם מוגדר על ידי הייצוג הניתן לסידרה ב- computation.proto . עם זאת, משתמשי FC API בדרך כלל לא יצטרכו לקיים אינטראקציה עם שפה זו ישירות. במקום זאת, אנו מספקים Python API (מרחב השמות tff ) שעוטף אותו כדרך להגדיר חישובים.

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

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

@tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS))
def get_average_temperature(sensor_readings):
  return tff.federated_mean(sensor_readings)

קוראים המכירים את TensorFlow הלא-להוטים ימצאו את הגישה הזו מקבילה לכתיבת קוד Python המשתמש בפונקציות כגון tf.add או tf.reduce_sum בקטע של קוד Python המגדיר גרף TensorFlow. למרות שהקוד מתבטא טכנית ב-Python, מטרתו היא לבנות ייצוג הניתן לסידרה של tf.Graph שמתחתיו, וזהו הגרף, לא קוד Python, שמבוצע באופן פנימי על ידי זמן הריצה של TensorFlow. באופן דומה, אפשר לחשוב על tff.federated_mean כעל הכנסת אופ פדרצי לחישוב מאוחד המיוצג על ידי get_average_temperature .

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

זה מצריך שפה ומערכת טיפוסים שתופסים את רעיון ההפצה.

הקלד מערכת

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

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

  • סוגי טנסור ( tff.TensorType ). בדיוק כמו ב-TensorFlow, לאלה יש dtype shape . ההבדל היחיד הוא שאובייקטים מסוג זה אינם מוגבלים למופעי tf.Tensor ב-Python המייצגים פלטים של TensorFlow ops בגרף TensorFlow, אלא עשויים לכלול גם יחידות של נתונים שניתן להפיק, למשל, כפלט של מבוזר פרוטוקול צבירה. לפיכך, סוג הטנזור TFF הוא פשוט גרסה מופשטת של ייצוג פיזי קונקרטי מסוג כזה ב-Python או TensorFlow.

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

    הסימון הקומפקטי עבור סוגי טנסור הוא dtype או dtype[shape] . לדוגמה, int32 ו- int32[10] הם סוגי המספרים השלמים ו-int vectors, בהתאמה.

  • סוגי רצף ( tff.SequenceType ). אלה הם המקבילה המופשטת של TFF לתפיסה הקונקרטית של TensorFlow של tf.data.Dataset s. ניתן לצרוך אלמנטים של רצפים באופן רציף ויכולים לכלול סוגים מורכבים.

    הייצוג הקומפקטי של סוגי רצף הוא T* , כאשר T הוא סוג האלמנטים. לדוגמה int32* מייצג רצף מספר שלם.

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

    הסימון הקומפקטי עבור tuples עם שם הוא <n_1=T_1, ..., n_k=T_k> , כאשר n_k הם שמות אלמנטים אופציונליים, ו- T_k הם סוגי אלמנטים. לדוגמה, <int32,int32> הוא סימון קומפקטי עבור זוג מספרים שלמים ללא שם, ו- <X=float32,Y=float32> הוא סימון קומפקטי עבור זוג מצופים בשם X ו- Y שעשויים לייצג נקודה במישור . ניתן לקנן טפולים כמו גם לערבב עם סוגים אחרים, למשל, <X=float32,Y=float32>* יהיה סימון קומפקטי עבור רצף נקודות.

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

    הסימון הקומפקטי עבור פונקציות הוא (T -> U) , כאשר T הוא סוג של ארגומנט, ו- U הוא סוג התוצאה, או ( -> U) אם אין ארגומנט (אם כי פונקציות ללא ארגומנט הן מנוון מושג שקיים בעיקר רק ברמת Python). לדוגמה (int32* -> int32) הוא סימון עבור סוג של פונקציות שמקטינות רצף של מספר שלם לערך שלם בודד.

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

  • סוג מיקום . סוג זה עדיין לא נחשף ב-API הציבורי מלבד בצורת 2 ליטרלים tff.SERVER ו- tff.CLIENTS שאתה יכול לחשוב עליהם כעל קבועים מסוג זה. עם זאת, הוא נמצא בשימוש פנימי ויוצג בממשק ה-API הציבורי במהדורות עתידיות. הייצוג הקומפקטי של סוג זה הוא placement .

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

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

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

    הסימון הקומפקטי עבור סוג ערכים מאוחד הכולל פריטים (מרכיבי חבר) מסוג T , כל אחד מתארח בקבוצה (מיקום) G הוא T@G או {T}@G עם ה- all_equal bit מוגדר או לא מוגדר, בהתאמה.

    לדוגמה:

    • {int32}@CLIENTS מייצג ערך מאוחד המורכב מקבוצה של מספרים שלמים פוטנציאליים שונים, אחד לכל מכשיר לקוח. שים לב שאנו מדברים על ערך מאוחד אחד כמקיף מספר פריטי נתונים המופיעים במספר מיקומים ברחבי הרשת. אחת הדרכים לחשוב על זה היא כמעין טנזור עם ממד "רשת", אם כי אנלוגיה זו אינה מושלמת מכיוון ש-TFF אינו מאפשר גישה אקראית למרכיבים חברים בעלי ערך מאוחד.

    • {<X=float32,Y=float32>*}@CLIENTS מייצג מערך נתונים מאוחד , ערך המורכב מרצפים מרובים של קואורדינטות XY , רצף אחד לכל התקן לקוח.

    • <weights=float32[10,5],bias=float32[5]>@SERVER מייצג טופל בעל שם של משקל וטנסורים בשרת. מאז שהורדנו את הפלטה המסולסלת, זה מצביע על ה- all_equal bit מוגדר, כלומר, יש רק tuple בודד (ללא קשר לכמה העתקים של שרת עשויים להיות באשכול המארח את הערך הזה).

אבני בניין

השפה של Core Federated היא צורה של למבדה-calculus , עם כמה אלמנטים נוספים.

הוא מספק את הפשטות התכנות הבאות הנחשפות כעת ב-API הציבורי:

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

    הנה דוגמה אחת, חישוב TF מסוג (int32* -> int) המשתמש באופרטור tf.data.Dataset.reduce כדי לחשב סכום של מספרים שלמים:

    @tff.tf_computation(tff.SequenceType(np.int32))
    def add_up_integers(x):
      return x.reduce(np.int32(0), lambda x, y: x + y)
    
  • אופרטורים פנימיים או מאוחדים ( tff.federated_... ). זוהי ספריית פונקציות כגון tff.federated_sum או tff.federated_broadcast המהוות את עיקר ה-API של FC, רובם מייצגים מפעילי תקשורת מבוזרת לשימוש עם TFF.

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

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

    לדוגמה, ניתן לחשוב על tff.federated_broadcast כמפעיל תבנית מסוג פונקציונלי T@SERVER -> T@CLIENTS .

  • ביטויי למדה ( tff.federated_computation ). ביטוי למבדה ב-TFF הוא המקבילה ל- lambda או def ב-Python; הוא מורכב משם הפרמטר, וגוף (ביטוי) המכיל הפניות לפרמטר זה.

    בקוד Python, ניתן ליצור אלה על ידי עיטור פונקציות Python ב- tff.federated_computation והגדרת ארגומנט.

    הנה דוגמה לביטוי למבדה שכבר הזכרנו קודם לכן:

    @tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS))
    def get_average_temperature(sensor_readings):
      return tff.federated_mean(sensor_readings)
    
  • מילולי מיקום . לעת עתה, רק tff.SERVER ו- tff.CLIENTS כדי לאפשר הגדרת חישובי שרת-לקוח פשוטים.

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

    לדוגמה:

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

    • tff.federated_mean(sensor_readings) מייצג הפניה של אופרטור הממוצע המאוחד על sensor_readings . סוג הביטוי הזה הוא float32@SERVER (בהנחה של הקשר מהדוגמה למעלה).

  • יצירת tuples ובחירת האלמנטים שלהם. ביטויי פייתון מהצורה [x, y] , x[y] או xy המופיעים בגוף הפונקציות המעוטרות ב- tff.federated_computation .