tff.federated_select를 사용하여 특정 클라이언트에 다른 데이터 보내기

TensorFlow.org에서 보기 Google Colab에서 실행 GitHub에서 소스 보기 노트북 다운로드

이 자습서는 다른 클라이언트에 다른 데이터를 보내야 하는 사용자 지정 연합 알고리즘을 TFF에서 구현하는 방법을 보여줍니다. 이미 익숙 할 tff.federated_broadcast 모든 클라이언트에 하나의 서버에 위치 값을 전송합니다. 이 튜토리얼은 서버 기반 값의 다른 부분이 다른 클라이언트로 전송되는 경우에 초점을 맞춥니다. 이것은 전체 모델을 단일 클라이언트에 보내는 것을 피하기 위해 여러 클라이언트에 걸쳐 모델의 일부를 나누는 데 유용할 수 있습니다.

하자 모두 가져 시작 tensorflow 하고 tensorflow_federated .

!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
tff.backends.native.set_local_python_execution_context()

클라이언트 데이터를 기반으로 다른 값 보내기

일부 클라이언트 배치 데이터를 기반으로 각 클라이언트에 몇 가지 요소를 보내려는 서버 배치 목록이 있는 경우를 고려하십시오. 예를 들어, 서버의 문자열 목록과 클라이언트의 다운로드할 인덱스 목록은 쉼표로 구분됩니다. 다음과 같이 구현할 수 있습니다.

list_of_strings_type = tff.TensorType(tf.string, [None])
# We only ever send exactly two values to each client. The number of keys per
# client must be a fixed number across all clients.
number_of_keys_per_client = 2
keys_type = tff.TensorType(tf.int32, [number_of_keys_per_client])
get_size = tff.tf_computation(lambda x: tf.size(x))
select_fn = tff.tf_computation(lambda val, index: tf.gather(val, index))
client_data_type = tf.string

# A function from our client data to the indices of the values we'd like to
# select from the server.
@tff.tf_computation(client_data_type)
@tff.check_returns_type(keys_type)
def keys_for_client(client_string):
  # We assume our client data is a single string consisting of exactly three
  # comma-separated integers indicating which values to grab from the server.
  split = tf.strings.split([client_string], sep=',')[0]
  return tf.strings.to_number([split[0], split[1]], tf.int32)

@tff.tf_computation(tff.SequenceType(tf.string))
@tff.check_returns_type(tf.string)
def concatenate(values):
  def reduce_fn(acc, item):
    return tf.cond(tf.math.equal(acc, ''),
                   lambda: item,
                   lambda: tf.strings.join([acc, item], ','))
  return values.reduce('', reduce_fn)

@tff.federated_computation(tff.type_at_server(list_of_strings_type), tff.type_at_clients(client_data_type))
def broadcast_based_on_client_data(list_of_strings_at_server, client_data):
  keys_at_clients = tff.federated_map(keys_for_client, client_data)
  max_key = tff.federated_map(get_size, list_of_strings_at_server)
  values_at_clients = tff.federated_select(keys_at_clients, max_key, list_of_strings_at_server, select_fn)
  value_at_clients = tff.federated_map(concatenate, values_at_clients)
  return value_at_clients

그런 다음 서버에 배치된 문자열 목록과 각 클라이언트에 대한 문자열 데이터를 제공하여 계산을 시뮬레이션할 수 있습니다.

client_data = ['0,1', '1,2', '2,0']
broadcast_based_on_client_data(['a', 'b', 'c'], client_data)
[<tf.Tensor: shape=(), dtype=string, numpy=b'a,b'>,
 <tf.Tensor: shape=(), dtype=string, numpy=b'b,c'>,
 <tf.Tensor: shape=(), dtype=string, numpy=b'c,a'>]

각 클라이언트에 무작위 요소 보내기

또는 서버 데이터의 임의 부분을 각 클라이언트에 보내는 것이 유용할 수 있습니다. 먼저 각 클라이언트에서 임의의 키를 생성한 다음 위에서 사용한 것과 유사한 선택 프로세스를 수행하여 이를 구현할 수 있습니다.

@tff.tf_computation(tf.int32)
@tff.check_returns_type(tff.TensorType(tf.int32, [1]))
def get_random_key(max_key):
  return tf.random.uniform(shape=[1], minval=0, maxval=max_key, dtype=tf.int32)

list_of_strings_type = tff.TensorType(tf.string, [None])
get_size = tff.tf_computation(lambda x: tf.size(x))
select_fn = tff.tf_computation(lambda val, index: tf.gather(val, index))

@tff.tf_computation(tff.SequenceType(tf.string))
@tff.check_returns_type(tf.string)
def get_last_element(sequence):
  return sequence.reduce('', lambda _initial_state, val: val)

@tff.federated_computation(tff.type_at_server(list_of_strings_type))
def broadcast_random_element(list_of_strings_at_server):
  max_key_at_server = tff.federated_map(get_size, list_of_strings_at_server)
  max_key_at_clients = tff.federated_broadcast(max_key_at_server)
  key_at_clients = tff.federated_map(get_random_key, max_key_at_clients)
  random_string_sequence_at_clients = tff.federated_select(
      key_at_clients, max_key_at_server, list_of_strings_at_server, select_fn)
  # Even though we only passed in a single key, `federated_select` returns a
  # sequence for each client. We only care about the last (and only) element.
  random_string_at_clients = tff.federated_map(get_last_element, random_string_sequence_at_clients)
  return random_string_at_clients

우리 때문에 broadcast_random_element 함수가 클라이언트에 위치 데이터를 고려하지 않습니다, 우리는 사용에 대한 고객의 기본 번호로 TFF 시뮬레이션 런타임을 구성해야합니다 :

tff.backends.native.set_local_python_execution_context(default_num_clients=3)

그런 다음 선택을 시뮬레이션할 수 있습니다. 우리는 변경 default_num_clients 상기 다른 랜덤 출력을 생성하는 연산을 실행하는 재 단순히 다른 결과를 생성하거나 아래 스트링의리스트.

broadcast_random_element(tf.convert_to_tensor(['foo', 'bar', 'baz']))