클라이언트 구성

모델 파라미터와 함께 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 문자열을 전송한 다음 클라이언트에서 다시 부동 소수점 숫자 목록으로 변환할 수 있습니다.

기본 제공 전략을 통한 구성

The easiest way to send configuration values to clients is to use a built-in strategy like FedAvg. Built-in strategies support so-called configuration functions. A configuration function is a function that the built-in strategy calls to get the configuration dictionary for the current round. It then forwards the configuration dictionary to all the clients selected during that round.

간단한 예부터 시작하겠습니다. (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

To make the built-in strategies use this function, we can pass it to FedAvg during initialization using the parameter on_fit_config_fn:

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

The FedAvg strategy will call this function every round.

개별 클라이언트 구성

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

This can be achieved by customizing an existing strategy or by implementing a custom strategy from scratch. Here’s a nonsensical example that customizes FedAvg by adding a custom "hello": "world" configuration key/value pair to the config dict of a single client (only the first client in the list, the other clients in this round to not receive this “special” config value):

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)