Bu öğretici, TFF'de rastgele gürültü üretimi için önerilen en iyi uygulamaları tartışacaktır. Rastgele gürültü üretimi, örneğin diferansiyel gizlilik gibi birleşik öğrenme algoritmalarındaki birçok gizlilik koruma tekniğinin önemli bir bileşenidir.
TensorFlow.org'da görüntüleyin | Google Colab'da çalıştırın | Kaynağı GitHub'da görüntüleyin | Not defterini indir |
Başlamadan Önce
İlk olarak, dizüstü bilgisayarın ilgili bileşenlerin derlenmiş olduğu bir arka uca bağlı olduğundan emin olalım.
!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
TFF ortamının doğru şekilde kurulduğundan emin olmak için aşağıdaki "Merhaba Dünya" örneğini çalıştırın. İşe yaramazsa, bakınız Kurulum talimatları için rehber.
@tff.federated_computation
def hello_world():
return 'Hello, World!'
hello_world()
b'Hello, World!'
İstemcilerde rastgele gürültü
İstemcilerde gürültü ihtiyacı genellikle iki duruma düşer: özdeş gürültü ve iid gürültüsü.
- Özdeş gürültü için tavsiye edilen model istemcilere yayınlayabilir sunucuda bir tohum, korumak ve kullanmaktır
tf.random.stateless
gürültü üreten fonksiyonları. - iid gürültüsü için, TF'nin tf.random.<distribution> işlevlerinden kaçınma önerisine uygun olarak, istemcide from_non_deterministic_state ile başlatılan bir tf.random.Generator kullanın.
İstemci davranışı sunucudan farklıdır (daha sonra tartışılacak olan tuzaklardan etkilenmez), çünkü her istemci kendi hesaplama grafiğini oluşturacak ve kendi varsayılan tohumunu başlatacaktır.
İstemcilerde aynı gürültü
# 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.
İstemciler üzerinde bağımsız gürültü
@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.
Sunucuda rastgele gürültü
Cesareti kullanımı: Doğrudan kullanılarak tf.random.normal
TF1.x API'ler gibi tf.random.normal
rastgele gürültü nesil için şiddetle göre TF2 caydırılmıştır TF rastgele gürültü nesil öğretici . Bu API'ler ile birlikte kullanıldığında Şaşırtıcı davranış ortaya çıkabilir tf.function
ve tf.random.set_seed
. Örneğin, aşağıdaki kod her çağrıda aynı değeri üretecektir. Bu şaşırtıcı davranış TF için beklenen ve açıklama bulunabilir belgelenmesi 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'de işler biraz farklı. Biz gürültü oluşumunu sarın Eğer tff.tf_computation
yerine tf.function
, belirli olmayan rasgele gürültü oluşacaktır. Bu kodun parçacığı birden çok kez çalıştırmak Ancak, farklı seti (n1, n2)
her zaman oluşturulur. TFF için küresel bir rastgele tohum belirlemenin kolay bir yolu yoktur.
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
Ayrıca, açıkça bir tohum ayarlamadan TFF'de deterministik gürültü üretilebilir. Fonksiyon return_two_noise
aşağıdaki kodda döndürür iki özdeş gürültü değerleri pasajı. Bu beklenen davranıştır çünkü TFF, yürütmeden önce hesaplama grafiğini oluşturacaktır. Ancak bu kullanıcıların kullanımına ilişkin ödeme dikkatine beslemesini önerdi tf.random.normal
TFF'nin.
@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
Dikkatle Kullanımı: tf.random.Generator
Biz kullanabilirsiniz tf.random.Generator
önerildiği şekilde TF öğretici .
@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
Ancak, kullanıcıların kullanımı konusunda dikkatli olmaları gerekebilir.
-
tf.random.Generator
kullanantf.Variable
RNG algoritmaları için durumlarını korumak için. TFF, bir iç jeneratör contruct önerilirtff.tf_computation
; ve jeneratör arasında durumuna geçmesi zordurtff.tf_computation
fonksiyonları. - önceki kod parçacığı, aynı zamanda, oluşturuculardaki tohumların dikkatlice ayarlanmasına da dayanır. Biz beklenen ama şaşırtıcı sonuçlar (deterministik alacak
n1==n2
) Kullandığımız takdirdetf.random.Generator.from_non_deterministic_state()
yerine.
Genel olarak TFF fonksiyonel operasyonlar tercih eder ve biz kullanımını sergileyecek tf.random.stateless_*
aşağıdaki bölümlerde fonksiyonlar.
Birleştirilmiş öğrenme için TFF'de, genellikle skalerler yerine iç içe yapılarla çalışırız ve önceki kod parçacığı doğal olarak iç içe yapılara genişletilebilir.
@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)]
Önerilen kullanım: tf.random.stateless_*
Bir yardımcı ile
TFF'nin genel öneri işlevsel kullanmaktır tf.random.stateless_*
rastgele gürültü nesil için fonksiyonlar. Bu işlevler alır seed
(şekilli bir Tensörü [2]
veya tuple
rastgele gürültü oluşturmak için açık bir giriş bağımsız değişken olarak iki sayısal tansörleri). Tohumu sözde durum olarak tutmak için önce bir yardımcı sınıf tanımlıyoruz. Yardımcı RandomSeedGenerator
bir devlet içinde devlet-out moda fonksiyonel operatörler vardır. Bunun için sözde devlet olarak bir sayaç kullanmak mantıklı tf.random.stateless_*
bu işlevler olarak karıştırmak istatistiksel ilintisiz ilişkili tohum ürettiği gürültü yapmak için kullanmadan önce tohum.
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)
Şimdi bize yardımcı sınıf ve kullanmasına izin tf.random.stateless_normal
(iç içe geçmiş yapısı) TFF rasgele gürültü üretecek. Aşağıdaki kod parçası bir TFF iteratif süreç gibi çok Görmekten görünüyor simple_fedavg TFF iteratif süreç olarak federe öğrenme algoritmasını ifade eden bir örnek olarak. Rastgele gürültü nesil için buraya sahte tohum durumudur tf.Tensor
kolayca TFF ve TF işlevlerinde taşınabilmektedir.
@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)]