ליבה פדרית

מסמך זה מציג את שכבת הליבה של 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.type_at_clients(tf.float32))
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 שעשויים לייצג נקודה במישור . ניתן לקנן tuples כמו גם לערבב עם סוגים אחרים, למשל, <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 set or not set, בהתאמה.

    לדוגמה:

    • {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 decorator. תמיד יש להם טיפוסים פונקציונליים, ובניגוד לפונקציות ב-TensorFlow, הם יכולים לקחת פרמטרים מובנים או להחזיר תוצאות מובנות מסוג רצף.

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

    @tff.tf_computation(tff.SequenceType(tf.int32))
    def add_up_integers(x):
      return x.reduce(np.int32(0), lambda x, y: x + y)
    
  • Intrinsics או אופרטורים מאוחדים ( 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.type_at_clients(tf.float32))
    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 .