날짜를 저장하십시오! Google I / O가 5 월 18 일부터 20 일까지 반환됩니다. 지금 등록
이 페이지는 Cloud Translation API를 통해 번역되었습니다.
Switch to English

나만의 연합 학습 알고리즘 구축

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

시작하기 전에

시작하기 전에 다음을 실행하여 환경이 올바르게 설정되었는지 확인하십시오. 인사말이 표시되지 않으면 설치 안내서를 참조하십시오.

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

import nest_asyncio
nest_asyncio.apply()
import collections
import attr
import functools
import numpy as np
import tensorflow as tf
import tensorflow_federated as tff

np.random.seed(0)

이미지 분류텍스트 생성 자습서에서 Federated Learning (FL)을위한 모델 및 데이터 파이프 라인을 설정하는 방법을 배우고 TFF의 tff.learning API 계층을 통해 연합 교육을 수행했습니다.

이것은 FL 연구와 관련하여 빙산의 일각에 불과합니다. 이 튜토리얼에서는 tff.learning API로 연기 하지 않고 연합 학습 알고리즘을 구현하는 방법에 대해 설명합니다. 우리는 다음을 달성하고자합니다.

목표 :

  • 연합 학습 알고리즘의 일반적인 구조를 이해합니다.
  • TFF의 Federated Core 를 살펴보세요.
  • Federated Core를 사용하여 Federated Averaging을 직접 구현합니다.

이 자습서는 독립적이지만 먼저 이미지 분류텍스트 생성 자습서를 읽는 것이 좋습니다.

입력 데이터 준비

먼저 TFF에 포함 된 EMNIST 데이터 세트를로드하고 전처리합니다. 자세한 내용은 이미지 분류 자습서를 참조하세요.

emnist_train, emnist_test = tff.simulation.datasets.emnist.load_data()

데이터 세트를 모델에 공급하기 위해 데이터를 평면화하고 각 예제를 (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 = np.random.choice(emnist_train.client_ids, size=NUM_CLIENTS, replace=False)

federated_train_data = [preprocess(emnist_train.create_tf_dataset_for_client(x))
  for x in client_ids
]

모델 준비

이미지 분류 자습서에서와 동일한 모델을 사용합니다. 이 모델 ( tf.keras 를 통해 구현 tf.keras )에는 단일 히든 레이어와 tf.keras 레이어가 있습니다.

def create_keras_model():
  return tf.keras.models.Sequential([
      tf.keras.layers.Input(shape=(784,)),
      tf.keras.layers.Dense(10, kernel_initializer='zeros'),
      tf.keras.layers.Softmax(),
  ])

TFF에서이 모델을 사용하기 위해 tff.learning.Model 모델을 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 : 훈련 가능한 레이어에 해당하는 텐서의 이터 러블입니다.
  • non_trainable_variables : 학습 불가능한 레이어에 해당하는 텐서의 반복 가능 항목입니다.

목적을 위해 trainable_variables 만 사용합니다. (우리 모델에는 그것들 만 있습니다!).

나만의 연합 학습 알고리즘 구축

tff.learning API를 사용하면 Federated Averaging의 많은 변형을 만들 수 있지만이 프레임 워크에 잘 맞지 않는 다른 연합 알고리즘이 있습니다. 예를 들어 정규화, 클리핑 또는 연합 GAN 훈련 과 같은 더 복잡한 알고리즘을 추가 할 수 있습니다. 대신 통합 분석에 관심이있을 수도 있습니다.

이러한 고급 알고리즘의 경우 TFF를 사용하여 자체 사용자 지정 알고리즘을 작성해야합니다. 대부분의 경우 연합 알고리즘에는 4 가지 주요 구성 요소가 있습니다.

  1. 서버-클라이언트 브로드 캐스트 단계.
  2. 로컬 클라이언트 업데이트 단계.
  3. 클라이언트-서버 업로드 단계.
  4. 서버 업데이트 단계.

TFF에서는 일반적으로 연합 알고리즘을 tff.templates.IterativeProcess (전체적으로 IterativeProcess )로 표현합니다. initializenext 함수가 포함 된 클래스입니다. 여기서, initialize 서버를 초기화하는데 사용되며, next 연합 알고리즘의 하나의 통신 라운드를 수행한다. FedAvg에 대한 우리의 반복 프로세스가 어떻게 생겼는지에 대한 골격을 작성해 보겠습니다.

먼저 tff.learning.Model 생성하고 훈련 가능한 가중치를 반환하는 초기화 함수가 있습니다.

def initialize_fn():
  model = model_fn()
  return model.trainable_variables

이 함수는보기에는 좋지만 나중에 보 겠지만 "TFF 계산"이되도록 약간 수정해야합니다.

next_fn 도 스케치하고 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 블록

클라이언트 업데이트

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 Averaging의 고급 구현에서는 운동량 또는 적응성과 같은보다 정교한 기술과 함께 mean_client_weights 를 사용합니다.

과제 : 서버 가중치를 model_weights 및 mean_client_weights의 중간 점이되도록 업데이트하는 server_update 버전을 구현하십시오. (참고 : 이러한 종류의 "중간 점"접근 방식은 Lookahead Optimizer 에 대한 최근 작업과 유사합니다!).

지금까지 순수한 TensorFlow 코드 만 작성했습니다. TFF를 사용하면 이미 익숙한 TensorFlow 코드를 많이 사용할 수 있으므로 이는 의도적으로 설계된 것입니다. 그러나 이제는 오케스트레이션 로직 , 즉 서버가 클라이언트에 브로드 캐스트하는 내용과 클라이언트가 서버에 업로드하는 내용을 지정하는 로직을 지정해야합니다.

이를 위해서는 TFF의 Federated Core 가 필요합니다.

연합 코어 소개

연합 코어 (FC)는 tff.learning API의 기반 역할을하는 하위 레벨 인터페이스 세트입니다. 그러나 이러한 인터페이스는 학습에만 국한되지 않습니다. 실제로 분산 데이터에 대한 분석 및 기타 많은 계산에 사용할 수 있습니다.

상위 수준에서 연합 코어는 간결하게 표현 된 프로그램 로직을 사용하여 TensorFlow 코드를 분산 통신 연산자 (예 : 분산 합계 및 브로드 캐스트)와 결합 할 수있는 개발 환경입니다. 목표는 시스템 구현 세부 사항 (예 : 지점 간 네트워크 메시지 교환 지정)을 요구하지 않고 연구자와 실무자에게 시스템의 분산 통신에 대한 신속한 제어를 제공하는 것입니다.

한 가지 요점은 TFF가 개인 정보 보호를 위해 설계되었다는 것입니다. 따라서 중앙 집중식 서버 위치에서 원하지 않는 데이터 축적을 방지하기 위해 데이터가있는 위치를 명시 적으로 제어 할 수 있습니다.

연합 데이터

TFF의 핵심 개념은 분산 시스템의 장치 그룹 (예 : 클라이언트 데이터 세트 또는 서버 모델 가중치)에서 호스트되는 데이터 항목 모음을 나타내는 "연합 데이터"입니다. 우리는 모든 장치에서 데이터 항목의 전체 컬렉션을 하나의 연합 값 으로 모델링합니다.

예를 들어, 센서의 온도를 나타내는 부동 소수점이있는 클라이언트 장치가 있다고 가정합니다. 우리는 그것을 연합 된 float 로 표현할 수 있습니다.

federated_float_on_clients = tff.FederatedType(tf.float32, tff.CLIENTS)

연합 유형은 구성원 구성 요소의 유형 T (예 : tf.float32 ) 및 장치 그룹 G 로 지정됩니다. Gtff.CLIENTS 또는 tff.SERVER 경우에 초점을 맞출 것입니다. 이러한 통합 유형은 아래와 같이 {T}@G 로 표시됩니다.

str(federated_float_on_clients)
'{float32}@CLIENTS'

게재 위치에 관심이 많은 이유는 무엇입니까? TFF의 핵심 목표는 실제 분산 시스템에 배포 할 수있는 코드를 작성하는 것입니다. 즉, 장치의 하위 집합이 어떤 코드를 실행하고 다른 데이터 조각이 어디에 있는지 추론하는 것이 중요합니다.

TFF는 데이터 , 데이터가있는 위치 및 데이터가 변환 되는 방법의 세 가지에 중점을 둡니다. 처음 두 개는 연합 유형으로 캡슐화되고 마지막 두 개는 연합 계산에 캡슐화됩니다.

통합 계산

TFF는 기본 단위가 연합 계산 인 강력한 형식의 함수형 프로그래밍 환경입니다. 이들은 연합 값을 입력으로 받아들이고 연합 값을 출력으로 반환하는 논리 조각입니다.

예를 들어 클라이언트 센서의 온도를 평균화하고 싶다고 가정합니다. 다음을 정의 할 수 있습니다 (페더레이션 된 float 사용).

@tff.federated_computation(tff.FederatedType(tf.float32, tff.CLIENTS))
def get_average_temperature(client_temperatures):
  return tff.federated_mean(client_temperatures)

이것이 TensorFlow의 tf.function 데코레이터와 어떻게 다른지 물어볼 수 있습니다. 핵심 대답은 tff.federated_computation 에 의해 생성 된 코드가 TensorFlow도 아니고 Python 코드도 아니라는 것입니다. 내부 플랫폼 독립적 인 글루 언어로 된 분산 시스템의 사양입니다.

복잡하게 들릴 수 있지만 TFF 계산은 잘 정의 된 형식 서명이있는 함수로 생각할 수 있습니다. 이러한 유형 서명은 직접 쿼리 할 수 ​​있습니다.

str(get_average_temperature.type_signature)
'({float32}@CLIENTS -> float32@SERVER)'

tff.federated_computation 연합 형의 인수를 받아들이는 {float32}@CLIENTS 및 연합 유형의 반환 값 {float32}@SERVER . 연합 계산은 서버에서 클라이언트로, 클라이언트에서 클라이언트로 또는 서버에서 서버로 이동할 수도 있습니다. 연합 계산은 유형 서명이 일치하는 한 일반 함수처럼 구성 할 수도 있습니다.

개발을 지원하기 위해 TFF를 사용하면 tff.federated_computation 을 Python 함수로 호출 할 수 있습니다. 예를 들어

get_average_temperature([68.5, 70.3, 69.8])
69.53334

열망하지 않는 계산 및 TensorFlow

알아야 할 두 가지 주요 제한 사항이 있습니다. 첫째, Python 인터프리터가 tff.federated_computation 데코레이터를 만나면 함수가 한 번 추적되고 나중에 사용하기 위해 직렬화됩니다. 페더레이션 된 학습의 분산 된 특성으로 인해 이러한 향후 사용은 원격 실행 환경과 같은 다른 곳에서 발생할 수 있습니다. 따라서 TFF 계산은 근본적 으로 열망이 아닙니다 . 이 동작은 TensorFlow의 tf.function 데코레이터와 다소 유사합니다.

둘째, 연합 계산은 연합 연산자 (예 : tff.federated_mean )로만 구성 될 수 있으며 TensorFlow 작업을 포함 할 수 없습니다. TensorFlow 코드는 tff.tf_computation 장식 된 블록으로 제한되어야합니다. 숫자를 받아 0.5 를 더하는 다음 함수와 같이 대부분의 일반적인 TensorFlow 코드는 직접 데코레이션 할 수 있습니다.

@tff.tf_computation(tf.float32)
def add_half(x):
  return tf.add(x, 0.5)

또한 유형 서명이 있지만 배치는 없습니다 . 예를 들어

str(add_half.type_signature)
'(float32 -> float32)'

여기에서 tff.federated_computationtff.tf_computation 의 중요한 차이점을 볼 수 있습니다. 전자는 명시 적 배치가있는 반면 후자는 그렇지 않습니다.

배치를 지정하여 연합 계산에서 tff.tf_computation 블록을 사용할 수 있습니다. 절반을 더하는 함수를 만들어 보겠습니다. 그러나 클라이언트에서 연합 된 float에만 적용됩니다. 배치를 유지하면서 주어진 tff.tf_computation 을 적용하는 tff.federated_map 을 사용하여 tff.federated_map 수행 할 수 있습니다.

@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는 연합 값에서 작동합니다.
  • 각 연합 값은 유형 (예.와 연합 형 갖는다 tf.float32 ) 및 위치 (예. tff.CLIENTS ).
  • 연합 값은 연합 계산을 사용하여 변환 될 수 있으며, tff.federated_computation 및 연합 유형 서명으로 장식되어야합니다.
  • TensorFlow 코드는 tff.tf_computation 데코레이터가있는 블록에 포함되어야합니다.
  • 그런 다음 이러한 블록을 통합 계산에 통합 할 수 있습니다.

나만의 연합 학습 알고리즘 구축, 재검토

이제 연합 코어를 살펴 보았으므로 자체 연합 학습 알고리즘을 구축 할 수 있습니다. 위에서 우리는 알고리즘에 initialize_fnnext_fn 을 정의했습니다. next_fn 은 순수한 TensorFlow 코드를 사용하여 정의한 client_updateserver_update 를 사용합니다.

그러나, 우리의 알고리즘 연합 계산하게하기 위해, 우리는 둘 다 필요합니다 next_fninitialize_fn 각각 수에 tff.federated_computation .

TensorFlow 연합 블록

초기화 계산 만들기

initialize 함수는 매우 간단합니다. model_fn 사용하여 모델을 생성합니다. 그러나 tff.tf_computation 사용하여 TensorFlow 코드를 분리해야합니다.

@tff.tf_computation
def server_init():
  model = model_fn()
  return model.trainable_variables

그런 다음 tff.federated_value 사용하여 tff.federated_value 연합 계산에 직접 전달할 수 있습니다.

@tff.federated_computation
def initialize_fn():
  return tff.federated_value(server_init(), tff.SERVER)

next_fn 만들기

이제 클라이언트 및 서버 업데이트 코드를 사용하여 실제 알고리즘을 작성합니다. 우리는 먼저 우리의 켜집니다 client_updatetff.tf_computation 클라이언트 데이터 셋 및 서버 가중치를 받아들이고, 업데이트 된 클라이언트 무게 텐서를 출력합니다.

함수를 적절하게 꾸미려면 해당 유형이 필요합니다. 다행히도 서버 가중치 유형은 모델에서 직접 추출 할 수 있습니다.

whimsy_model = model_fn()
tf_dataset_type = tff.SequenceType(whimsy_model.input_spec)

데이터 세트 유형 서명을 살펴 보겠습니다. 28 x 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 을 생성해야합니다. 이 함수는 두 개의 연합 값 을 허용 합니다 . 하나는 서버 가중치에 해당하고 (배치 tff.SERVER ) 다른 하나는 클라이언트 데이터 세트에 해당합니다 (배치 tff.CLIENTS ).

이 두 유형 모두 위에 정의되어 있습니다! tff.FederatedType 사용하여 적절한 위치를 지정하기 tff.FederatedType 됩니다.

federated_server_type = tff.FederatedType(model_weights_type, tff.SERVER)
federated_dataset_type = tff.FederatedType(tf_dataset_type, tff.CLIENTS)

FL 알고리즘의 4 가지 요소를 기억하십니까?

  1. 서버-클라이언트 브로드 캐스트 단계.
  2. 로컬 클라이언트 업데이트 단계.
  3. 클라이언트-서버 업로드 단계.
  4. 서버 업데이트 단계.

이제 위의 내용을 작성 했으므로 각 부분을 한 줄의 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.IterativeProcesstff.templates.IterativeProcess 합니다.

federated_algorithm = tff.templates.IterativeProcess(
    initialize_fn=initialize_fn,
    next_fn=next_fn
)

반복 프로세스의 initializenext 함수의 유형 시그니처 를 살펴 보겠습니다.

str(federated_algorithm.initialize.type_signature)
'( -> <float32[784,10],float32[10]>@SERVER)'

이는 federated_algorithm.initialize 가 단일 레이어 모델 (784x10 가중치 행렬 및 10 개의 바이어스 단위 포함)을 반환하는 인수가없는 함수라는 사실을 반영합니다.

str(federated_algorithm.next.type_signature)
'(<<float32[784,10],float32[10]>@SERVER,{<float32[?,784],int32[?,1]>*}@CLIENTS> -> <float32[784,10],float32[10]>@SERVER)'

여기에서 federated_algorithm.next 는 서버 모델과 클라이언트 데이터를 받아들이고 업데이트 된 서버 모델을 반환합니다.

알고리즘 평가

몇 라운드를 실행하여 손실이 어떻게 변하는 지 살펴 보겠습니다. 먼저 두 번째 튜토리얼에서 논의한 중앙 집중식 접근 방식을 사용하여 평가 기능을 정의합니다.

먼저 중앙 집중식 평가 데이터 세트를 만든 다음 훈련 데이터에 사용한 것과 동일한 전처리를 적용합니다.

주 우리는 것을 take 계산 효율성을 이유로 처음 1000 개 요소가 있지만, 일반적으로 우리는 전체 테스트 데이터 세트를 사용하십시오.

central_emnist_test = emnist_test.create_tf_dataset_from_all_clients().take(1000)
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)
50/50 [==============================] - 0s 2ms/step - loss: 2.3026 - sparse_categorical_accuracy: 0.0910

몇 라운드 동안 훈련하고 변경 사항이 있는지 살펴 보겠습니다.

for round in range(15):
  server_state = federated_algorithm.next(server_state, federated_train_data)
evaluate(server_state)
50/50 [==============================] - 0s 1ms/step - loss: 2.1706 - sparse_categorical_accuracy: 0.2440

손실 함수가 약간 감소합니다. 점프는 작지만, 우리는 10 번의 훈련 라운드와 소수의 클라이언트에 대해서만 수행했습니다. 더 나은 결과를 보려면 수천 번은 아니더라도 수백 번을해야 할 수도 있습니다.

알고리즘 수정

이 시점에서 멈추고 우리가 성취 한 것에 대해 생각해 봅시다. 순수 TensorFlow 코드 (클라이언트 및 서버 업데이트 용)를 TFF의 Federated Core의 연합 계산과 결합하여 Federated Averaging을 직접 구현했습니다.

보다 정교한 학습을 ​​수행하기 위해 위에있는 것을 간단히 변경할 수 있습니다. 특히 위의 순수 TF 코드를 편집하여 클라이언트가 학습을 수행하는 방법 또는 서버가 모델을 업데이트하는 방법을 변경할 수 있습니다.

과제 : client_update 함수에 그라디언트 클리핑 을 추가 합니다 .

더 큰 변경을 원할 경우 서버에 더 많은 데이터를 저장하고 브로드 캐스트하도록 할 수도 있습니다. 예를 들어, 서버는 또한 클라이언트 학습률을 저장할 수 있으며 시간이 지남에 따라 감소합니다! 위의 tff.tf_computation 호출에 사용 된 유형 서명을 변경해야합니다.

더 어려운 과제 : 클라이언트의 학습률 하락과 함께 Federated Averaging을 구현하십시오.

이 시점에서이 프레임 워크에서 구현할 수있는 것이 얼마나 많은 유연성이 있는지 깨닫기 시작할 수 있습니다. 아이디어 (위의 어려운 과제에 대한 답변 포함)를 보려면 tff.learning.build_federated_averaging_process 의 소스 코드를 tff.learning.build_federated_averaging_process TFF를 사용하는 다양한 연구 프로젝트 를 확인할 수 있습니다.