سيناقش هذا البرنامج التعليمي أفضل الممارسات الموصى بها لتوليد الضوضاء العشوائية في TFF. يعد توليد الضوضاء العشوائية مكونًا مهمًا للعديد من تقنيات حماية الخصوصية في خوارزميات التعلم الموحد ، على سبيل المثال ، الخصوصية التفاضلية.
عرض على TensorFlow.org | تشغيل في Google Colab | عرض المصدر على جيثب | تحميل دفتر |
قبل أن نبدأ
أولاً ، دعونا نتأكد من توصيل الكمبيوتر الدفتري بالواجهة الخلفية التي تم تجميع المكونات ذات الصلة بها.
!pip install --quiet --upgrade tensorflow_federated_nightly
!pip install --quiet --upgrade nest_asyncio
import nest_asyncio
nest_asyncio.apply()
import numpy as np
import tensorflow as tf
import tensorflow_federated as tff
قم بتشغيل مثال "Hello World" التالي للتأكد من إعداد بيئة TFF بشكل صحيح. إذا كان لا يعمل، يرجى الرجوع إلى تركيب دليل للتعليمات.
@tff.federated_computation
def hello_world():
return 'Hello, World!'
hello_world()
b'Hello, World!'
ضوضاء عشوائية على العملاء
تنقسم الحاجة إلى الضوضاء على العملاء عمومًا إلى حالتين: ضوضاء متطابقة وضوضاء iid.
- للضوضاء متطابقة، ونمط الموصى به هو الحفاظ على البذور على الخادم، ونقله إلى العملاء، واستخدام
tf.random.stateless
وظائف لتوليد الضجيج. - بالنسبة لضوضاء iid ، استخدم tf.random.Generator مهيأ على العميل باستخدام from_non_deterministic_state ، تمشيا مع توصية TF لتجنب وظائف tf.random. <distribution>.
يختلف سلوك العميل عن الخادم (لا يعاني من المزالق التي تمت مناقشتها لاحقًا) لأن كل عميل سيُنشئ الرسم البياني الحسابي الخاص به ويهيئ البداية الافتراضية الخاصة به.
ضوضاء متطابقة على العملاء
# Set to use 10 clients.
tff.backends.native.set_local_python_execution_context(num_clients=10)
@tff.tf_computation
def noise_from_seed(seed):
return tf.random.stateless_normal((), seed=seed)
seed_type_at_server = tff.type_at_server(tff.to_type((tf.int64, [2])))
@tff.federated_computation(seed_type_at_server)
def get_random_min_and_max_deterministic(seed):
# Broadcast seed to all clients.
seed_on_clients = tff.federated_broadcast(seed)
# Clients generate noise from seed deterministicly.
noise_on_clients = tff.federated_map(noise_from_seed, seed_on_clients)
# Aggregate and return the min and max of the values generated on clients.
min = tff.aggregators.federated_min(noise_on_clients)
max = tff.aggregators.federated_max(noise_on_clients)
return min, max
seed = tf.constant([1, 1], dtype=tf.int64)
min, max = get_random_min_and_max_deterministic(seed)
assert min == max
print(f'Seed: {seed.numpy()}. All clients sampled value {min:8.3f}.')
seed += 1
min, max = get_random_min_and_max_deterministic(seed)
assert min == max
print(f'Seed: {seed.numpy()}. All clients sampled value {min:8.3f}.')
Seed: [1 1]. All clients sampled value 1.665. Seed: [2 2]. All clients sampled value -0.219.
ضوضاء مستقلة على العملاء
@tff.tf_computation
def nondeterministic_noise():
gen = tf.random.Generator.from_non_deterministic_state()
return gen.normal(())
@tff.federated_computation(seed_type_at_server)
def get_random_min_and_max_nondeterministic(seed):
noise_on_clients = tff.federated_eval(nondeterministic_noise, tff.CLIENTS)
min = tff.aggregators.federated_min(noise_on_clients)
max = tff.aggregators.federated_max(noise_on_clients)
return min, max
min, max = get_random_min_and_max_nondeterministic(seed)
assert min != max
print(f'Values differ across clients. {min:8.3f},{max:8.3f}.')
new_min, new_max = get_random_min_and_max_nondeterministic(seed)
assert new_min != new_max
assert new_min != min and new_max != max
print(f'Values differ across rounds. {new_min:8.3f},{new_max:8.3f}.')
Values differ across clients. -1.810, 1.079. Values differ across rounds. -1.205, 0.851.
ضجيج عشوائي على الخادم
استخدام المحبطين: مباشرة باستخدام tf.random.normal
TF1.x مثل واجهات برمجة التطبيقات tf.random.normal
وتثبيط لتوليد الضجيج العشوائي بقوة في TF2 وفقا ل عشوائية توليد الضجيج تعليمي في TF . قد يحدث السلوك المستغرب عندما تستخدم واجهات برمجة التطبيقات جنبا إلى جنب مع tf.function
و tf.random.set_seed
. على سبيل المثال ، ستولد الشفرة التالية نفس القيمة مع كل مكالمة. هذا هو السلوك المتوقع من المستغرب لTF، ويمكن العثور عليها التفسير في توثيق tf.random.set_seed
.
tf.random.set_seed(1)
@tf.function
def return_one_noise(_):
return tf.random.normal([])
n1=return_one_noise(1)
n2=return_one_noise(2)
assert n1 == n2
print(n1.numpy(), n2.numpy())
0.3052047 0.3052047
في TFF ، الأمور مختلفة قليلاً. إذا كنا التفاف الجيل الضوضاء كما tff.tf_computation
بدلا من tf.function
، سيتم إنشاء الضجيج العشوائي غير حتمية. ومع ذلك، إذا كان لنا أن تشغيل هذه التعليمات البرمجية المتكررة عدة مرات، مجموعة مختلفة من (n1, n2)
سيتم إنشاء في كل مرة. لا توجد طريقة سهلة لتعيين بذرة عشوائية عالمية لـ TFF.
tf.random.set_seed(1)
@tff.tf_computation
def return_one_noise(_):
return tf.random.normal([])
n1=return_one_noise(1)
n2=return_one_noise(2)
assert n1 != n2
print(n1, n2)
1.3283143 0.45740178
علاوة على ذلك ، يمكن إنشاء ضوضاء حتمية في TFF دون تحديد البذور بشكل صريح. وظيفة return_two_noise
في التعليمة البرمجية التالية مقتطف عوائد قيمتين الضوضاء متطابقة. هذا هو السلوك المتوقع لأن TFF ستنشئ رسمًا بيانيًا حسابيًا مسبقًا قبل التنفيذ. ومع ذلك، وهذا يشير المستخدمين تولي اهتماما لعن استخدام tf.random.normal
في TFF.
@tff.tf_computation
def tff_return_one_noise():
return tf.random.normal([])
@tff.federated_computation
def return_two_noise():
return (tff_return_one_noise(), tff_return_one_noise())
n1, n2=return_two_noise()
assert n1 == n2
print(n1, n2)
-0.15665223 -0.15665223
استخدام بحذر: tf.random.Generator
يمكننا استخدام tf.random.Generator
النحو المقترح في TF البرنامج التعليمي .
@tff.tf_computation
def tff_return_one_noise(i):
g=tf.random.Generator.from_seed(i)
@tf.function
def tf_return_one_noise():
return g.normal([])
return tf_return_one_noise()
@tff.federated_computation
def return_two_noise():
return (tff_return_one_noise(1), tff_return_one_noise(2))
n1, n2 = return_two_noise()
assert n1 != n2
print(n1, n2)
0.3052047 -0.38260338
ومع ذلك ، قد يتعين على المستخدمين توخي الحذر عند استخدامها
-
tf.random.Generator
يستخدمtf.Variable
للحفاظ على دولتين لخوارزميات RNG. في TFF، فمن المستحسن في contruct المولد داخلtff.tf_computation
. وأنه من الصعب أن يمر المولد وحالته بينtff.tf_computation
الوظائف. - يعتمد مقتطف الكود السابق أيضًا على وضع البذور بعناية في المولدات. ونحن سوف تحصل متوقع ولكن نتائج مذهلة (القطعية
n1==n2
) إذا أردنا استخدامtf.random.Generator.from_non_deterministic_state()
بدلا من ذلك.
بشكل عام، TFF يفضل العمليات الوظيفية وسنعرض استخدام tf.random.stateless_*
وظائف في الأقسام التالية.
في TFF للتعلم الموحد ، غالبًا ما نعمل مع الهياكل المتداخلة بدلاً من الحجميات ويمكن أن يمتد مقتطف الشفرة السابق بشكل طبيعي إلى الهياكل المتداخلة.
@tff.tf_computation
def tff_return_one_noise(i):
g=tf.random.Generator.from_seed(i)
weights = [
tf.ones([2, 2], dtype=tf.float32),
tf.constant([2], dtype=tf.float32)
]
@tf.function
def tf_return_one_noise():
return tf.nest.map_structure(lambda x: g.normal(tf.shape(x)), weights)
return tf_return_one_noise()
@tff.federated_computation
def return_two_noise():
return (tff_return_one_noise(1), tff_return_one_noise(2))
n1, n2 = return_two_noise()
assert n1[1] != n2[1]
print('n1', n1)
print('n2', n2)
n1 [array([[0.3052047 , 0.5671378 ], [0.41852272, 0.2326421 ]], dtype=float32), array([1.1675092], dtype=float32)] n2 [array([[-0.38260338, -0.47804865], [-0.5187485 , -1.8471988 ]], dtype=float32), array([-0.77835274], dtype=float32)]
استخدام الموصى به: tf.random.stateless_*
مع مساعد
توصية عامة في TFF هو استخدام الوظيفية لل tf.random.stateless_*
وظائف لتوليد الضجيج العشوائي. هذه المهام تأخذ seed
(أ التنسور مع شكل [2]
أو tuple
اثنين التنسورات العددية) كحجة مساهمة صريحة لتوليد الضجيج العشوائي. نحدد أولاً فئة المساعدة للحفاظ على البذرة كحالة زائفة. المساعد RandomSeedGenerator
ديه مشغلي الوظيفية بطريقة الدولة في وللدولة بها. فمن المعقول أن استخدام عداد كدولة الزائفة ل tf.random.stateless_*
لأن هذه الوظائف يتبارى البذور قبل استخدامه لجعل الضوضاء الناتجة عن بذور المترابطة غير مترابطة إحصائيا.
def timestamp_seed():
# tf.timestamp returns microseconds as decimal places, thus scaling by 1e6.
return tf.math.cast(tf.timestamp() * 1e6, tf.int64)
class RandomSeedGenerator():
def initialize(self, seed=None):
if seed is None:
return tf.stack([timestamp_seed(), 0])
else:
return tf.constant(self.seed, dtype=tf.int64, shape=(2,))
def next(self, state):
return state + tf.constant([0, 1], tf.int64)
def structure_next(self, state, nest_structure):
"Returns seed in nested structure and the next state seed."
flat_structure = tf.nest.flatten(nest_structure)
flat_seeds = [state + tf.constant([0, i], tf.int64) for
i in range(len(flat_structure))]
nest_seeds = tf.nest.pack_sequence_as(nest_structure, flat_seeds)
return nest_seeds, flat_seeds[-1] + tf.constant([0, 1], tf.int64)
الآن دعونا استخدام فئة مساعد و tf.random.stateless_normal
لتوليد (بنية متداخلة من) الضجيج العشوائي في TFF. فيما يلي مقتطف الشفرة يتطلع الكثير مثل عملية تكرارية TFF، انظر simple_fedavg كمثال للتعبير عن خوارزمية التعلم الاتحادية كما عملية تكرارية TFF. الدولة البذور الزائفة هنا لتوليد الضجيج العشوائي هي tf.Tensor
التي يمكن نقلها بسهولة في وظائف TFF وTF.
@tff.tf_computation
def tff_return_one_noise(seed_state):
g=RandomSeedGenerator()
weights = [
tf.ones([2, 2], dtype=tf.float32),
tf.constant([2], dtype=tf.float32)
]
@tf.function
def tf_return_one_noise():
nest_seeds, updated_state = g.structure_next(seed_state, weights)
nest_noise = tf.nest.map_structure(lambda x,s: tf.random.stateless_normal(
shape=tf.shape(x), seed=s), weights, nest_seeds)
return nest_noise, updated_state
return tf_return_one_noise()
@tff.tf_computation
def tff_init_state():
g=RandomSeedGenerator()
return g.initialize()
@tff.federated_computation
def return_two_noise():
seed_state = tff_init_state()
n1, seed_state = tff_return_one_noise(seed_state)
n2, seed_state = tff_return_one_noise(seed_state)
return (n1, n2)
n1, n2 = return_two_noise()
assert n1[1] != n2[1]
print('n1', n1)
print('n2', n2)
n1 [array([[-0.21598858, -0.30700883], [ 0.7562299 , -0.21218438]], dtype=float32), array([-1.0359321], dtype=float32)] n2 [array([[ 1.0722181 , 0.81287116], [-0.7140338 , 0.5896157 ]], dtype=float32), array([0.44190162], dtype=float32)]