클라이언트 구성#

모델 파라미터와 함께 Flower는 설정 값을 클라이언트에 전송할 수 있습니다. 구성 값은 다양한 용도로 사용할 수 있습니다. 예를 들어 서버에서 클라이언트 측 하이퍼파라미터를 제어하는 데 널리 사용되는 방법입니다.

구성 값#

구성 값은 str 키와 bool, bytes, double``(64비트 정밀도 정수), ``int 또는 ``str``(또는 다른 언어의 동등한 유형) 유형의 값으로 구성된 사전으로 표현됩니다. 다음은 Python의 구성 사전 예제입니다:

config_dict = {
    "dropout": True,        # str key, bool value
    "learning_rate": 0.01,  # str key, float value
    "batch_size": 32,       # str key, int value
    "optimizer": "sgd",     # str key, str value
}

Flower는 이러한 구성 dictionaries(또는 줄여서 config dict)를 ProtoBuf 표현으로 직렬화하고, gRPC를 사용하여 클라이언트로 전송한 다음 다시 Python dictionaries로 역직렬화합니다.

참고

현재 구성 사전에서 컬렉션 유형(예: Set, List, Map)을 값으로 직접 전송하는 기능은 지원되지 않습니다. 컬렉션을 지원되는 값 유형 중 하나로 변환한 다음 클라이언트 측에서 다시 변환하여 값으로 보내는 몇 가지 해결 방법이 있습니다.

예를 들어 부동 소수점 숫자 목록을 JSON 문자열로 변환한 다음 구성 dictionary을 사용하여 JSON 문자열을 전송한 다음 클라이언트에서 다시 부동 소수점 숫자 목록으로 변환할 수 있습니다.

기본 제공 전략을 통한 구성#

클라이언트에 구성 값을 보내는 가장 쉬운 방법은 :code:`FedAvg`와 같은 기본 제공 전략을 사용하는 것입니다. 기본 제공 전략은 소위 구성 함수를 지원합니다. 구성 함수는 내장 전략이 현재 단계의 구성 사전을 가져오기 위해 호출하는 함수입니다. 그런 다음 해당 단계 동안 선택된 모든 클라이언트에 구성 사전을 전달합니다.

간단한 예부터 시작하겠습니다. (a) 클라이언트가 사용해야 하는 배치 크기, (b) 현재 글로벌 연합 라운드, (c) 클라이언트 측에서 학습할 에포크 수를 전송하고 싶다고 가정해 보겠습니다. 구성 함수는 다음과 같습니다:

def fit_config(server_round: int):
    """Return training configuration dict for each round."""
    config = {
        "batch_size": 32,
        "current_round": server_round,
        "local_epochs": 2,
    }
    return config

기본 제공 전략이 이 함수를 사용하도록 하려면 초기화 중에 매개 변수 :code:`on_fit_config_fn`을 사용하여 ``FedAvg``에 이 함수를 전달하면 됩니다:

strategy = FedAvg(
    ...,                          # Other FedAvg parameters
    on_fit_config_fn=fit_config,  # The fit_config function we defined earlier
)

클라이언트 측에서는 ``fit``으로 구성 dictionary을 받습니다:

class FlowerClient(flwr.client.NumPyClient):
    def fit(parameters, config):
        print(config["batch_size"])  # Prints `32`
        print(config["current_round"])  # Prints `1`/`2`/`...`
        print(config["local_epochs"])  # Prints `2`
        # ... (rest of `fit` method)

평가를 구성하는 `on_evaluate_config_fn`도 있으며, 같은 방식으로 작동합니다. 다른 배치 크기를 사용하기 위해 다른 구성 값을 `evaluate`로 보내려고 할 수 있기 때문에 이 함수는 별도의 함수입니다.

기본 제공 전략은 매 라운드마다 이 함수를 호출합니다(즉, Strategy.configure_fit 또는 `Strategy.configure_evaluate`가 실행될 때마다). 매 라운드마다 `on_evaluate_config_fn`을 호출하면 연속된 라운드에서 config dict를 변경/변경할 수 있습니다. 예를 들어 이후 라운드에서 로컬 에포크 수를 늘리기 위해 하이퍼파라미터 일정을 구현하려면 다음과 같이 할 수 있습니다:

def fit_config(server_round: int):
    """Return training configuration dict for each round."""
    config = {
        "batch_size": 32,
        "current_round": server_round,
        "local_epochs": 1 if server_round < 2 else 2,
    }
    return config

FedAvg 전략은 이 함수를 매 라운드마다 호출합니다.

개별 클라이언트 구성#

경우에 따라 다른 구성 값을 다른 클라이언트에 보내야 하는 경우도 있습니다.

이는 기존 전략을 사용자 지정하거나 implementing a custom strategy from scratch <how-to-implement-strategies>`를 통해 수행할 수 있습니다. 다음은 사용자 지정 `”hello“‘를 추가하여 FedAvg`를 사용자 지정하는 무의미한 예입니다: "world"` 구성 키/값 쌍을 *단일 클라이언트*의 config dict에 추가합니다(목록의 첫 번째 클라이언트만, 이 라운드의 다른 클라이언트는 이 “특별한” 구성 값을 수신하지 않음):

class CustomClientConfigStrategy(fl.server.strategy.FedAvg):
    def configure_fit(
        self, server_round: int, parameters: Parameters, client_manager: ClientManager
    ) -> List[Tuple[ClientProxy, FitIns]]:
        client_instructions = super().configure_fit(server_round, parameters, client_manager)

        # Add special "hello": "world" config key/value pair,
        # but only to the first client in the list
        _, fit_ins = client_instructions[0]  # First (ClientProxy, FitIns) pair
        fit_ins.config["hello"] = "world"  # Change config for this client only

        return client_instructions

# Create strategy and run server
strategy = CustomClientConfigStrategy(
    # ... (same arguments as plain FedAvg here)
)
fl.server.start_server(strategy=strategy)