הצג באתר TensorFlow.org | הפעל בגוגל קולאב | צפה במקור ב-GitHub | הורד מחברת |
לפני שאנחנו מתחילים
לפני שנתחיל, אנא הפעל את הפעולות הבאות כדי לוודא שהסביבה שלך מוגדרת כהלכה. אם אינך רואה ברכה, עיין התקנת המדריך לקבלת הוראות.
!pip install --quiet --upgrade tensorflow-federated-nightly
!pip install --quiet --upgrade nest-asyncio
import nest_asyncio
nest_asyncio.apply()
import tensorflow as tf
import tensorflow_federated as tff
בשנות ה סיווג התמונה ואת הדור הטקסט הדרכות, למדנו כיצד להגדיר צינורות מודל ונתונים עבור Federated למידה (FL), וביצע אימונים Federated דרך tff.learning
שכבת API של TFF.
זה רק קצה הקרחון כשמדובר במחקר FL. במדריך זה, אנו דנים כיצד ליישם אלגוריתמים של למידה Federated ללא דחיית אל tff.learning
API. אנו שואפים להשיג את הדברים הבאים:
מטרות:
- הבן את המבנה הכללי של אלגוריתמי למידה מאוחדים.
- חקור את Federated Core של TFF.
- השתמש ב-Federated Core כדי ליישם ממוצע פדרלי ישירות.
בעוד הדרכה זו היא עצמאית, אנו ממליצים בקריאה ראשונה את סיווג תמונה ואת טקסט דור ההדרכות.
הכנת נתוני הקלט
ראשית, אנו טוענים ומעבדים מראש את מערך הנתונים של EMNIST הכלול ב-TFF. לפרטים נוספים, ראה סיווג תמונת ההדרכה.
emnist_train, emnist_test = tff.simulation.datasets.emnist.load_data()
כדי להאכיל את הנתונים לתוך המודל שלנו, אנו לשטח את הנתונים, ולהמיר כל דוגמה לתוך tuple של הטופס (flattened_image_vector, label)
.
NUM_CLIENTS = 10
BATCH_SIZE = 20
def preprocess(dataset):
def batch_format_fn(element):
"""Flatten a batch of EMNIST data and return a (features, label) tuple."""
return (tf.reshape(element['pixels'], [-1, 784]),
tf.reshape(element['label'], [-1, 1]))
return dataset.batch(BATCH_SIZE).map(batch_format_fn)
כעת אנו בוחרים מספר קטן של לקוחות, ומחילים את העיבוד המקדים לעיל על מערכי הנתונים שלהם.
client_ids = sorted(emnist_train.client_ids)[:NUM_CLIENTS]
federated_train_data = [preprocess(emnist_train.create_tf_dataset_for_client(x))
for x in client_ids
]
הכנת הדגם
אנו משתמשים באותו מודל כמו סיווג התמונה הדרכה. מודל זה (מיושם באמצעות tf.keras
יש) בשכבה אחת חבויה, ואחריו שכבת softmax.
def create_keras_model():
initializer = tf.keras.initializers.GlorotNormal(seed=0)
return tf.keras.models.Sequential([
tf.keras.layers.Input(shape=(784,)),
tf.keras.layers.Dense(10, kernel_initializer=initializer),
tf.keras.layers.Softmax(),
])
על מנת להשתמש במודל זה TFF, אנו עוטפים את המודל Keras בתור tff.learning.Model
. זה מאפשר לנו לבצע את המודל לעבור קדימה בתוך TFF, ואת תפוקות מודל תמצית . לפרטים נוספים, גם לראות את סיווג תמונת ההדרכה.
def model_fn():
keras_model = create_keras_model()
return tff.learning.from_keras_model(
keras_model,
input_spec=federated_train_data[0].element_spec,
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])
בעוד השתמשנו tf.keras
ליצור tff.learning.Model
, TFF תומך הרבה מודלים כלליים יותר. למודלים אלה יש את התכונות הרלוונטיות הבאות המתעדות את משקלי המודל:
-
trainable_variables
: An iterable של טנזורים המתאים שכבות שאפשר לאלף. -
non_trainable_variables
: An iterable של טנזורים המתאים שכבות הלא שאפשר לאלף.
לענייננו, אנחנו רק נשתמש trainable_variables
. (מכיוון שלדגם שלנו יש רק כאלה!).
בניית אלגוריתם למידה מאוחדת משלך
בעוד tff.learning
API מאפשר אחד כדי ליצור גרסאות רבות של ממוצעים Federated, ישנם אלגוריתמים Federated אחרים שאינם מתאימים יפה לתוך מסגרת זו. לדוגמא, ייתכן שתרצה להוסיף הסדרה, גזיר, או אלגוריתמים מסובכים יותר כגון הכשרת גן Federated . ייתכן גם במקום יעניין Analytics Federated .
עבור אלגוריתמים מתקדמים יותר אלה, נצטרך לכתוב אלגוריתם מותאם אישית משלנו באמצעות TFF. במקרים רבים, לאלגוריתמים מאוחדים יש 4 מרכיבים עיקריים:
- שלב שידור שרת ללקוח.
- שלב עדכון לקוח מקומי.
- שלב העלאת לקוח לשרת.
- שלב עדכון שרת.
בשנת TFF, אנחנו מייצגים אלגוריתמים Federated בדרך כלל בתור tff.templates.IterativeProcess
(אשר אנו מתייחסים כאל סתם IterativeProcess
לאורך). זוהי מחלקה המכילה initialize
ו next
פונקציות. הנה, initialize
משמשת לאתחל את השרת, ואת next
תבצע סיבוב תקשורת אחד של אלגוריתם Federated. בואו נכתוב שלד של איך התהליך האיטרטיבי שלנו עבור FedAvg צריך להיראות.
ראשית, יש לנו פונקציה התחלתית שפשוט יוצר tff.learning.Model
, ומחזירה משקולות שאפשר לאלף שלה.
def initialize_fn():
model = model_fn()
return model.trainable_variables
פונקציה זו נראית טוב, אך כפי שנראה בהמשך, נצטרך לבצע שינוי קטן כדי להפוך אותה ל"חישוב TFF".
אנחנו גם רוצים לשרטט את next_fn
.
def next_fn(server_weights, federated_dataset):
# Broadcast the server weights to the clients.
server_weights_at_client = broadcast(server_weights)
# Each client computes their updated weights.
client_weights = client_update(federated_dataset, server_weights_at_client)
# The server averages these updates.
mean_client_weights = mean(client_weights)
# The server updates its model.
server_weights = server_update(mean_client_weights)
return server_weights
נתמקד ביישום ארבעת הרכיבים הללו בנפרד. תחילה אנו מתמקדים בחלקים שניתן ליישם ב- TensorFlow טהור, כלומר שלבי עדכון הלקוח והשרת.
TensorFlow Blocks
עדכון לקוח
נשתמש שלנו tff.learning.Model
לעשות אימונים הלקוח בעצם באותו אופן היית לאמן מודל TensorFlow. בפרט, נשתמש tf.GradientTape
לחשב את השיפוע על קבוצות של נתונים, ולאחר מכן להחיל שיפוע אלה באמצעות client_optimizer
. אנו מתמקדים רק במשקולות הניתנות לאימון.
@tf.function
def client_update(model, dataset, server_weights, client_optimizer):
"""Performs training (using the server model weights) on the client's dataset."""
# Initialize the client model with the current server weights.
client_weights = model.trainable_variables
# Assign the server weights to the client model.
tf.nest.map_structure(lambda x, y: x.assign(y),
client_weights, server_weights)
# Use the client_optimizer to update the local model.
for batch in dataset:
with tf.GradientTape() as tape:
# Compute a forward pass on the batch of data
outputs = model.forward_pass(batch)
# Compute the corresponding gradient
grads = tape.gradient(outputs.loss, client_weights)
grads_and_vars = zip(grads, client_weights)
# Apply the gradient using a client optimizer.
client_optimizer.apply_gradients(grads_and_vars)
return client_weights
עדכון שרת
עדכון השרת עבור FedAvg פשוט יותר מעדכון הלקוח. אנו ניישם מיצוע מאוחד "וניל", שבו פשוט נחליף את משקלי דגמי השרת בממוצע של משקלי דגמי הלקוח. שוב, אנו מתמקדים רק במשקולות הניתנות לאימון.
@tf.function
def server_update(model, mean_client_weights):
"""Updates the server model weights as the average of the client model weights."""
model_weights = model.trainable_variables
# Assign the mean client weights to the server model.
tf.nest.map_structure(lambda x, y: x.assign(y),
model_weights, mean_client_weights)
return model_weights
הקטע יכול להיות פשוט יותר פשוט על ידי חזרת mean_client_weights
. עם זאת, הטמעות מתקדמות יותר של שימוש ממוצעים Federated mean_client_weights
עם טכניקות מתוחכמות יותר, כגון תאוצה או adaptivity.
האתגר: ליישם גרסה של server_update
כי מעדכנת את משקולות השרת להיות נקודת האמצע של model_weights ו mean_client_weights. (הערה: סוג זה של "אמצע" גישת משול העבודה אחרונה על האופטימיזציה המשך הדרך !).
עד כה, כתבנו רק קוד TensorFlow טהור. זה בתכנון, שכן TFF מאפשר לך להשתמש בחלק גדול מהקוד של TensorFlow שאתה כבר מכיר. עם זאת, כעת אנו צריכים לציין את ההיגיון תזמור, כלומר, ההיגיון אומר, מה שידורי השרת ללקוח, ומה העלאות הלקוח לשרת.
זה ידרוש Core Federated של TFF.
מבוא ל-Federated Core
Federated Core (FC) הוא קבוצה של ממשקים ברמה נמוכים המשמשים כבסיס עבור tff.learning
API. עם זאת, ממשקים אלו אינם מוגבלים ללמידה. למעשה, הם יכולים לשמש עבור ניתוחים וחישובים רבים אחרים על פני נתונים מבוזרים.
ברמה גבוהה, הליבה המאוחדת היא סביבת פיתוח המאפשרת לוגיקה של תוכנית בעלת ביטוי קומפקטי לשלב קוד TensorFlow עם מפעילי תקשורת מבוזרים (כגון סכומים מבוזרים ושידורים). המטרה היא לתת לחוקרים ולעוסקים בשליטה מפורשת על התקשורת המבוזרת במערכות שלהם, מבלי להידרש לפרטי הטמעת המערכת (כגון ציון חילופי הודעות רשת מנקודה לנקודה).
נקודת מפתח אחת היא ש-TFF נועד לשמירה על הפרטיות. לכן, הוא מאפשר שליטה מפורשת על היכן נמצאים הנתונים, כדי למנוע הצטברות לא רצויה של נתונים במיקום השרת המרכזי.
נתונים מאוחדים
מושג מפתח ב-TFF הוא "נתונים מאוחדים", המתייחס לאוסף של פריטי נתונים המתארחים על פני קבוצת מכשירים במערכת מבוזרת (למשל מערכי נתונים של לקוח, או משקלי מודל השרת). אנחנו למדל את כל אוסף של פריטי נתונים בין כל המכשירים כערך Federated יחיד.
לדוגמה, נניח שיש לנו התקני לקוח שלכל אחד מהם יש ציפה המייצגת את הטמפרטורה של חיישן. אנחנו יכולים לייצג אותו בתור לצוף מאוחד על ידי
federated_float_on_clients = tff.FederatedType(tf.float32, tff.CLIENTS)
סוגי Federated מצוינים באמצעות סוג T
של מרכיבי החבר שלו (למשל. tf.float32
) וקבוצה G
של התקנים. אנו נתמקד במקרים בהם G
הוא או tff.CLIENTS
או tff.SERVER
. כזה סוג Federated מיוצג {T}@G
, כמוצג להלן.
str(federated_float_on_clients)
'{float32}@CLIENTS'
למה כל כך אכפת לנו מהמיקומים? מטרת מפתח של TFF היא לאפשר כתיבת קוד שניתן לפרוס על מערכת מבוזרת אמיתית. משמעות הדבר היא שחיוני לחשוב על אילו תת-קבוצות של מכשירים מבצעות איזה קוד, והיכן שוכנות פיסות נתונים שונות.
TFF מתמקדת בשלושה דברים: נתונים, בהם נתוני מושם, ואת אופן הצגת הנתונים מוסב. השניים הראשונים הם הגלום סוגים Federated, ואילו האחרון הוא כמוס ב חישובים Federated.
חישובים מאוחדים
TFF היא סביבת תכנות פונקציונלי מאוד-מוקלד שאת היחידות הבסיסיות הן חישובים Federated. אלו הם חלקי היגיון שמקבלים ערכים מאוחדים כקלט, ומחזירים ערכים מאוחדים כפלט.
לדוגמה, נניח שרצינו לממוצע את הטמפרטורות בחיישני הלקוח שלנו. נוכל להגדיר את הדברים הבאים (באמצעות הציפה המאוחדת שלנו):
@tff.federated_computation(tff.FederatedType(tf.float32, tff.CLIENTS))
def get_average_temperature(client_temperatures):
return tff.federated_mean(client_temperatures)
אתם עשויים לשאול, במה הוא שונה מן tf.function
מעצב ב TensorFlow? תשובת המפתח היא שהקוד שנוצר על ידי tff.federated_computation
אינו קוד TensorFlow ולא Python; זהו מפרט של מערכת מבוזרת בשפה דבקה תלוי בפלטפורמה פנימית.
למרות שזה אולי נשמע מסובך, אתה יכול לחשוב על חישובי TFF כעל פונקציות עם חתימות סוג מוגדרות היטב. ניתן לשאול ישירות את חתימות הסוג הללו.
str(get_average_temperature.type_signature)
'({float32}@CLIENTS -> float32@SERVER)'
זה tff.federated_computation
מקבל טיעונים מסוג Federated {float32}@CLIENTS
, וערכי תשואות של סוג Federated {float32}@SERVER
. חישובים מאוחדים עשויים לעבור גם משרת ללקוח, מלקוח ללקוח, או משרת לשרת. חישובים מאוחדים יכולים להיות מורכבים גם כמו פונקציות רגילות, כל עוד חתימות הסוג שלהם תואמות.
כדי לתמוך בפיתוח, TFF מאפשר לך לעורר tff.federated_computation
כפונקציה Python. למשל, אנחנו יכולים להתקשר
get_average_temperature([68.5, 70.3, 69.8])
69.53334
חישובים לא להוטים ו-TensorFlow
ישנן שתי מגבלות עיקריות שכדאי להיות מודע להן. ראשית, כאשר מתורגמן פיתון נתקל tff.federated_computation
מעצב, הפונקציה הוא אתר אחת בהמשכים לשימוש עתידי. בשל האופי המבוזר של פדרציית למידה, שימוש עתידי זה עשוי להתרחש במקום אחר, כגון סביבת ביצוע מרחוק. לכן, חישובי TFF שאינם להוטים מיסודה. התנהגות זו היא דומה למדי לזה של tf.function
מעצב ב TensorFlow.
שנית, חישוב Federated יכול להכיל מפעילי Federated בלבד (כגון tff.federated_mean
), הם לא יכולים להכיל פעולות TensorFlow. קוד TensorFlow חייב להיות מוגבל בלוקים מעוטרים tff.tf_computation
. רוב קוד TensorFlow הרגיל יכול להיות מעוצב באופן ישיר, כמו הפונקציה הבאה שלוקח מספר ומוסיף 0.5
אלי.
@tff.tf_computation(tf.float32)
def add_half(x):
return tf.add(x, 0.5)
גם אלה חתימות סוג, אך ללא מיקומים. למשל, אנחנו יכולים להתקשר
str(add_half.type_signature)
'(float32 -> float32)'
כאן אנו רואים הבדל חשוב בין tff.federated_computation
ו tff.tf_computation
. לראשון יש מיקומים מפורשים, בעוד שלאחרון אין.
אנו יכולים להשתמש tff.tf_computation
בלוקים בחישובים Federated ידי ציון מיקומים. בואו ניצור פונקציה שמוסיפה חצי, אבל רק לציפים מאוחדים אצל הלקוחות. אנחנו יכולים לעשות זאת באמצעות tff.federated_map
, אשר חל נתון tff.tf_computation
, תוך שמירה על המיקום.
@tff.federated_computation(tff.FederatedType(tf.float32, tff.CLIENTS))
def add_half_on_clients(x):
return tff.federated_map(add_half, x)
פונקציה זו היא כמעט זהה add_half
, למעט עובדה שהיא מקבלת רק ערכים עם השמת tff.CLIENTS
, וערכים חוזרים עם אותו המיקום. אנו יכולים לראות זאת בחתימת הסוג שלו:
str(add_half_on_clients.type_signature)
'({float32}@CLIENTS -> {float32}@CLIENTS)'
לסיכום:
- TFF פועל על פי ערכים מאוחדים.
- לכל ערך Federated סוג Federated, עם סוג כלשהו (למשל.
tf.float32
) והקצאה (למשל.tff.CLIENTS
). - ערכי Federated ניתן להפוך באמצעות חישובי Federated, אשר חייב להיות מעוטר
tff.federated_computation
וחתימת סוג Federated. - קוד TensorFlow חייב להיכלל בלוקים עם
tff.tf_computation
מעצבי. - לאחר מכן ניתן לשלב בלוקים אלה בחישובים מאוחדים.
בניית אלגוריתם למידה מאוחדת משלך, נבדק מחדש
כעת, לאחר שקיבלנו הצצה לליבה הפדרציה, אנו יכולים לבנות אלגוריתם למידה מאוחד משלנו. זכור כי לעיל, הגדרנו initialize_fn
ו next_fn
עבור האלגוריתם שלנו. next_fn
יהיה לעשות שימוש client_update
ו server_update
הגדרנו באמצעות קוד TensorFlow טהור.
עם זאת, על מנת להפוך את האלגוריתם שלנו חישוב מאוחד נצטרך הן next_fn
ו initialize_fn
לכל להיות tff.federated_computation
.
בלוקים מאוחדים של TensorFlow
יצירת חישוב האתחול
פונקציית האתחול תהיה די פשוט: אנו ניצור מודל באמצעות model_fn
. עם זאת, יש לזכור כי אנו חייבים להפריד את קוד TensorFlow שלנו באמצעות tff.tf_computation
.
@tff.tf_computation
def server_init():
model = model_fn()
return model.trainable_variables
אז אנו יכולים לעבור את זה ישירות לתוך החישוב Federated באמצעות tff.federated_value
.
@tff.federated_computation
def initialize_fn():
return tff.federated_value(server_init(), tff.SERVER)
יצירת next_fn
כעת אנו משתמשים בקוד עדכון הלקוח והשרת שלנו כדי לכתוב את האלגוריתם בפועל. נפנינו שלנו ראשון client_update
לתוך tff.tf_computation
שמקבל מערכי נתוני לקוח משקולות שרת, ו פלט מותח משקולת לקוח מעודכן.
נצטרך את הסוגים המתאימים כדי לקשט כראוי את הפונקציה שלנו. למרבה המזל, ניתן לחלץ את סוג משקלי השרת ישירות מהדגם שלנו.
whimsy_model = model_fn()
tf_dataset_type = tff.SequenceType(whimsy_model.input_spec)
הבה נסתכל על החתימה מסוג מערך הנתונים. זכור שצילמנו 28 על 28 תמונות (עם תוויות שלמים) והשטחנו אותן.
str(tf_dataset_type)
'<float32[?,784],int32[?,1]>*'
אנחנו יכולים גם לחלץ את סוג משקולות דגם באמצעות שלנו server_init
הפונקציה הנ"ל.
model_weights_type = server_init.type_signature.result
בבחינת חתימת הסוג, נוכל לראות את הארכיטקטורה של הדגם שלנו!
str(model_weights_type)
'<float32[784,10],float32[10]>'
כעת אנו יכולים ליצור שלנו tff.tf_computation
עבור עדכון הלקוח.
@tff.tf_computation(tf_dataset_type, model_weights_type)
def client_update_fn(tf_dataset, server_weights):
model = model_fn()
client_optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
return client_update(model, tf_dataset, server_weights, client_optimizer)
tff.tf_computation
גרסת העדכון בשרת יכולה להיות מוגדרת באופן דומה, תוך שימוש בסוגים כבר חלצנו.
@tff.tf_computation(model_weights_type)
def server_update_fn(mean_client_weights):
model = model_fn()
return server_update(model, mean_client_weights)
אחרונה, אך לא פחות חשוב, אנחנו צריכים ליצור את tff.federated_computation
שמביא כל זה ביחד. פונקציה זו תקבל שני ערכים Federated, אחד מתאים משקולות השרת (עם המיקום tff.SERVER
), והשני מתאים מערכי נתוני לקוח (עם המיקום tff.CLIENTS
).
שימו לב ששני הסוגים הללו הוגדרו לעיל! אנחנו פשוט צריכים לתת להם את המיקום הנכון באמצעות tff.FederatedType
.
federated_server_type = tff.FederatedType(model_weights_type, tff.SERVER)
federated_dataset_type = tff.FederatedType(tf_dataset_type, tff.CLIENTS)
זוכרים את 4 האלמנטים של אלגוריתם FL?
- שלב שידור שרת ללקוח.
- שלב עדכון לקוח מקומי.
- שלב העלאת לקוח לשרת.
- שלב עדכון שרת.
כעת, לאחר שבנו את האמור לעיל, כל חלק יכול להיות מיוצג בצורה קומפקטית כשורה אחת של קוד TFF. הפשטות הזו היא הסיבה שהיינו צריכים לנקוט משנה זהירות כדי לציין דברים כגון סוגים מאוחדים!
@tff.federated_computation(federated_server_type, federated_dataset_type)
def next_fn(server_weights, federated_dataset):
# Broadcast the server weights to the clients.
server_weights_at_client = tff.federated_broadcast(server_weights)
# Each client computes their updated weights.
client_weights = tff.federated_map(
client_update_fn, (federated_dataset, server_weights_at_client))
# The server averages these updates.
mean_client_weights = tff.federated_mean(client_weights)
# The server updates its model.
server_weights = tff.federated_map(server_update_fn, mean_client_weights)
return server_weights
עכשיו יש לנו tff.federated_computation
היא עבור אתחול האלגוריתם, ו להפעלת צעד אחד של האלגוריתם. כדי לסיים האלגוריתם שלנו, אנחנו עוברים אלה לתוך tff.templates.IterativeProcess
.
federated_algorithm = tff.templates.IterativeProcess(
initialize_fn=initialize_fn,
next_fn=next_fn
)
המבט באים בבית חתימת הסוג של initialize
ו next
הפונקציות של התהליך איטרטיבי שלנו.
str(federated_algorithm.initialize.type_signature)
'( -> <float32[784,10],float32[10]>@SERVER)'
זה משקף את העובדה federated_algorithm.initialize
הוא פונקציה לא-ARG המחזירה מודל שכבה אחת (עם מטריצה במשקל 784-by-10, ו 10 יחידות הטיה).
str(federated_algorithm.next.type_signature)
'(<server_weights=<float32[784,10],float32[10]>@SERVER,federated_dataset={<float32[?,784],int32[?,1]>*}@CLIENTS> -> <float32[784,10],float32[10]>@SERVER)'
כאן, אנו רואים כי federated_algorithm.next
מקבלת מודל שרת ונתוני לקוח, וחוזר מודל שרת מעודכן.
הערכת האלגוריתם
בואו נרוץ כמה סיבובים, ונראה איך ההפסד משתנה. ראשית, נגדיר פונקצית הערכה בגישה הריכוזית נדונה ההדרכה השנייה.
תחילה אנו יוצרים מערך נתונים הערכה מרכזי, ולאחר מכן מיישמים את אותו עיבוד מקדים בו השתמשנו עבור נתוני ההדרכה.
central_emnist_test = emnist_test.create_tf_dataset_from_all_clients()
central_emnist_test = preprocess(central_emnist_test)
לאחר מכן, אנו כותבים פונקציה שמקבלת מצב שרת, ומשתמשת ב-Keras כדי להעריך על מערך הנתונים של הבדיקה. אם אתה מכיר tf.Keras
, יהיה זה כל מראה מוכר, למרות הפתק השימוש set_weights
!
def evaluate(server_state):
keras_model = create_keras_model()
keras_model.compile(
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()]
)
keras_model.set_weights(server_state)
keras_model.evaluate(central_emnist_test)
כעת, בואו נאתחל את האלגוריתם שלנו ונבצע הערכה על ערכת הבדיקה.
server_state = federated_algorithm.initialize()
evaluate(server_state)
2042/2042 [==============================] - 2s 767us/step - loss: 2.8479 - sparse_categorical_accuracy: 0.1027
בואו נתאמן לכמה סיבובים ונראה אם משהו משתנה.
for round in range(15):
server_state = federated_algorithm.next(server_state, federated_train_data)
evaluate(server_state)
2042/2042 [==============================] - 2s 738us/step - loss: 2.5867 - sparse_categorical_accuracy: 0.0980
אנו רואים ירידה קלה בפונקציית ההפסד. בעוד שהקפיצה קטנה, ביצענו רק 15 סבבי אימון, ועל תת-קבוצה קטנה של לקוחות. כדי לראות תוצאות טובות יותר, ייתכן שנצטרך לעשות מאות אם לא אלפי סיבובים.
שינוי האלגוריתם שלנו
בשלב זה, בואו נעצור ונחשוב על מה שהשגנו. יישמנו ממוצע פדרלי ישירות על ידי שילוב קוד TensorFlow טהור (עבור עדכוני הלקוח והשרת) עם חישובים מאוחדים מה-Federated Core של TFF.
כדי לבצע למידה מתוחכמת יותר, אנחנו יכולים פשוט לשנות את מה שיש לנו למעלה. בפרט, על ידי עריכת קוד ה-TF הטהור למעלה, נוכל לשנות את האופן שבו הלקוח מבצע אימון, או כיצד השרת מעדכן את המודל שלו.
אתגר: הוסף גזיר שיפוע אל client_update
הפונקציה.
אם היינו רוצים לבצע שינויים גדולים יותר, יכולנו גם להחזיק את השרת ולשדר יותר נתונים. לדוגמה, השרת יכול גם לאחסן את קצב הלמידה של הלקוח, ולגרום לו להידרדר לאורך זמן! שים לב כי זה יחייב שינויים חתימות סוג המשמשים tff.tf_computation
קורא מעל.
אתגר Harder: ליישם ממוצעי Federated עם למידת ריקבון שיעור על הלקוחות.
בשלב זה, אתה עשוי להתחיל להבין כמה גמישות יש במה שאתה יכול ליישם במסגרת זו. לקבלת רעיונות (כולל מענה לאתגר קשה לעיל) אתה יכול לראות את קוד המקור עבור tff.learning.build_federated_averaging_process
, או לבדוק שונים פרויקטים מחקריים באמצעות TFF.