כוונון אגרגציות מומלצות ללמידה

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

tff.learning מודול מכיל מספר דרכי udpates מודל המצרפי עם תצורת ברירת מחדל מומלצת:

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


!pip install --quiet --upgrade tensorflow-federated-nightly
!pip install --quiet --upgrade nest-asyncio

import nest_asyncio
nest_asyncio.apply()
import math
import tensorflow_federated as tff
tff.federated_computation(lambda: 'Hello, World!')()
b'Hello, World!'

שיטות צבירה מיוצגות על ידי חפצים שיכולים להיות מועברים tff.learning.build_federated_averaging_process כמו שלה model_update_aggregation_factory טיעון מילות מפתח. ככזה, הצוברים דנו כאן ניתן להשתמש ישירות לשנות קודם הדרכה על למידת Federated.

קו הבסיס משוקלל ממוצע מן FedAvg האלגוריתם יכול לבוא לידי ביטוי באמצעות tff.aggregators.MeanFactory כדלקמן:

mean = tff.aggregators.MeanFactory()
iterative_process = tff.learning.build_federated_averaging_process(
    ...,
    model_update_aggregation_factory=mean)

הטכניקות בהן ניתן להשתמש כדי להרחיב את הממוצע המשוקלל המכוסה במדריך זה הן:

  • מאפס
  • גֶזֶר
  • פרטיות דיפרנציאלית
  • דְחִיסָה
  • צבירה מאובטחת

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

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

טכניקות

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

התאמת כמות

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

median_estimate = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0, target_quantile=0.5, learning_rate=0.2)

טכניקות שונות המשתמשות באלגוריתם הערכת הכמות ידרשו ערכים שונים של פרמטרי האלגוריתם, כפי שנראה. באופן כללי, הגדלת learning_rate אמצעי פרמטר הסתגלות מהירה יותר בחמישון הנכונה, אך עם שונות גבוהות. no_noise תהליך התאמת classmethod בונה החמישון כי אינו מוסיף רעש לפרטיות ההפרש.

מאפס

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

כדי לחשב ממוצע של ערכים לנורמות L-אינסוף גדול יותר ZEROING_CONSTANT מאופס-אאוט, אנחנו לעטוף tff.aggregators.MeanFactory עם tff.aggregators.zeroing_factory שמבצע את מתאפס:

zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=tff.aggregators.MeanFactory())

כאן אנו לעטוף MeanFactory עם zeroing_factory כי אנחנו רוצים את (אגרגציה מראש) ההשפעות של zeroing_factory לחול על הערכים לקוחות לפני שהם מועברים אל הפנימי MeanFactory עבור צבירה באמצעות מיצוע.

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

zeroing_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=10.0,
    target_quantile=0.98,
    learning_rate=math.log(10),
    multiplier=2.0,
    increment=1.0)
zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=zeroing_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# zeroing_mean = tff.learning.robust_aggregator(clipping=False)

הפרמטרים נבחרו כך מסתגל התהליך מהר מאוד (גדול יחסית learning_rate ) לערך קצת יותר גדול הערכים הגדולים שראו עד כה. לקבלת אומדן החמישון Q , סף לשמש ג לאיפוס יהיה Q * multiplier + increment .

גזירה לנורמת L2 מאוגדת

חיתוך עדכוני לקוח (הקרנה על כדור L2) יכול לשפר את החוסן לחריגות. tff.aggregators.clipping_factory בנויה בדיוק כמו tff.aggregators.zeroing_factory שנדונו לעיל, והוא יכול לקחת גם קבוע או tff.templates.EstimationProcess כמו שלה clipping_norm טיעון. השיטה המומלצת המומלצת היא להשתמש בגזירה שמסתגלת במהירות בינונית לנורמה גבוהה למדי, כדלקמן:

clipping_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0,
    target_quantile=0.8,
    learning_rate=0.2)
clipping_mean = tff.aggregators.clipping_factory(
    clipping_norm=clipping_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# clipping_mean = tff.learning.robust_aggregator(zeroing=False)

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

פרטיות דיפרנציאלית

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

dp_mean = tff.aggregators.DifferentiallyPrivateFactory.gaussian_adaptive(
    noise_multiplier=0.1, clients_per_round=100)

# Equivalent to:
# dp_mean = tff.learning.dp_aggregator(
#   noise_multiplier=0.1, clients_per_round=100, zeroing=False)

הדרכה על איך להגדיר את noise_multiplier הטיעון ניתן למצוא הדרכה DP TFF .

דחיסה אבודה

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

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

t = round((t - min(t)) / (max(t) - min(t)) * (2**quantizaton_bits - 1)),

וכתוצאה מכך ערכים שלמים בטווח של [0, 2**quantizaton_bits-1] . הערכים הכומתיים נארזים ישירות לסוג מספר שלם לשידור, ולאחר מכן מופעלת הטרנספורמציה ההפוכה.

אנו ממליצים על הגדרת quantizaton_bits שווה ל 8 ו threshold שווה ל 20,000:

compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))

# Equivalent to:
# compressed_mean = tff.learning.compression_aggregator(zeroing=False, clipping=False)

הצעות כוונון

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

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

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

סיביות קוונטיזציה. ערך ברירת המחדל של 8 עבור quantization_bits אמור להיות בסדר עבור רוב המשתמשים. אם 8 עובד טוב ואתה רוצה לסחוט קצת יותר ביצועים, אתה יכול לנסות להוריד אותו ל-7 או 6. אם המשאבים מאפשרים חיפוש רשת קטן, אנו ממליצים לך לזהות את הערך שעבורו האימון הופך לא יציב או איכות הדגם הסופית מתחילה להתדרדר, ולאחר מכן להגדיל את הערך בשניים. לדוגמה, אם הגדרת quantization_bits כדי 5 עבודות, אבל להגדיר אותה ל 4 מדרדרת את המודל, היינו ממליצים שברירת המחדל היא 6 להיות "בצד הבטוח".

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

צבירה מאובטחת

לפי Secure Aggregation (SecAgg) אנו מתייחסים לפרוטוקול קריפטוגרפי שבו עדכוני לקוח מוצפנים בצורה כזו שהשרת יכול רק לפענח את הסכום שלהם. אם מספר הלקוחות המדווחים בחזרה אינו מספיק, השרת לא ילמד דבר כלל - ובשום מקרה השרת לא יוכל לבדוק עדכונים בודדים. זה ממומש באמצעות tff.federated_secure_sum_bitwidth המפעיל.

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

כדי לחשב ממוצע משוקלל עם ערכים סיכם באמצעות SecAgg עם MY_SECAGG_BOUND כמו גזיר כבול, לעבור SecureSumFactory כדי MeanFactory כמו:

secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(MY_SECAGG_BOUND))

כדי לעשות את אותו הדבר תוך קביעת גבולות באופן אדפטיבי:

secagg_bound = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=50.0,
    target_quantile=0.95,
    learning_rate=1.0,
    multiplier=2.0)
secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(secagg_bound))

# Equivalent to:
# secure_mean = tff.learning.secure_aggregator(zeroing=Fasle, clipping=False)

הצעות כוונון

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

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

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

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

secure_mean = tff.aggregators.MeanFactory(
    value_sum_factory=tff.aggregators.SecureSumFactory(secagg_bound),
    weight_sum_factory=tff.aggregators.SecureSumFactory(
        upper_bound_threshold=MAX_WEIGHT, lower_bound_threshold=0.0))

טכניקות הלחנה

ניתן לשלב טכניקות בודדות להרחבת ממוצע שהוצג לעיל.

אנו ממליצים להיות בסדר שבו טכניקות אלו מיושמות אצל לקוחות

  1. מאפס
  2. גֶזֶר
  3. טכניקות אחרות

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

# Compression is innermost because its pre-aggregation effects are last.
compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))
# Compressed mean is inner aggregator to clipping...
clipped_compressed_mean = tff.aggregators.clipping_factory(
    clipping_norm=MY_CLIPPING_CONSTANT,
    inner_agg_factory=compressed_mean)
# ...which is inner aggregator to zeroing, since zeroing happens first.
final_aggregator = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=clipped_compressed_mean)

הערה כי מבנה זה תואם את צוברי מחדל ללימוד אלגוריתמים.

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