시뮬레이션 실행

Federated 학습 워크로드 시뮬레이션은 다양한 사용 사례에 유용합니다. 대규모 클라이언트 집단에서 워크로드를 실행하되 많은 수의 물리적 장치를 소싱, 구성 및 관리할 필요가 없는 경우, 복잡한 설정 과정을 거치지 않고도 액세스 가능한 컴퓨팅 시스템에서 최대한 빠르게 FL 워크로드를 실행하려는 경우, 다양한 수준의 데이터 및 시스템 이질성, 클라이언트 가용성, 개인정보 예산 등의 다양한 시나리오에서 알고리즘을 검증하려는 경우 등 여러 가지 사용 사례에 유용합니다. 이러한 사례는 FL 워크로드 시뮬레이션이 적합한 사용 사례 중 일부입니다. Flower는 VirtualClientEngine 또는 VCE를 통해 이러한 시나리오를 수용할 수 있습니다.

The VirtualClientEngine schedules, launches and manages virtual clients. These clients are identical to non-virtual clients (i.e. the ones you launch via the command flwr.client.start_client) in the sense that they can be configure by creating a class inheriting, for example, from flwr.client.NumPyClient and therefore behave in an identical way. In addition to that, clients managed by the VirtualClientEngine are:

  • resource-aware: 이는 각 클라이언트가 시스템에서 컴퓨팅 및 메모리의 일부를 할당받는다는 것을 의미합니다. 사용자는 시뮬레이션을 시작할 때 이를 제어할 수 있으며, 이를 통해 Flower FL 시뮬레이션의 병렬 처리 정도를 제어할 수 있습니다. 클라이언트당 리소스가 적을수록 동일한 하드웨어에서 더 많은 클라이언트를 동시에 실행할 수 있습니다.

  • self-managed: this means that you as a user do not need to launch clients manually, instead this gets delegated to VirtualClientEngine’s internals.

  • ephemeral: 이는 클라이언트가 FL 프로세스에서 필요할 때만 구체화됨을 의미합니다(예: `fit() <ref-api-flwr.html#flwr.client.Client.fit>`_을 수행하기 위해). 객체는 나중에 소멸되어 할당된 리소스를 해제하고 다른 클라이언트가 참여할 수 있도록 허용합니다.

The VirtualClientEngine implements virtual clients using Ray, an open-source framework for scalable Python workloads. In particular, Flower’s VirtualClientEngine makes use of Actors to spawn virtual clients and run their workload.

Flower 시뮬레이션 시작

Flower 시뮬레이션을 실행하려면 여전히 클라이언트 클래스, 전략 및 유틸리티 함수를 정의하여 데이터 세트를 다운로드하고 로드(및 파티션)해야 합니다. 이 작업을 마친 후 시뮬레이션을 시작하려면 `start_simulation <ref-api-flwr.html#flwr.simulation.start_simulation>`_을 사용하면 되며, 최소한의 예시는 다음과 같습니다:

import flwr as fl
from flwr.server.strategy import FedAvg


def client_fn(cid: str):
    # Return a standard Flower client
    return MyFlowerClient().to_client()


# Launch the simulation
hist = fl.simulation.start_simulation(
    client_fn=client_fn,  # A function to run a _virtual_ client when required
    num_clients=50,  # Total number of clients available
    config=fl.server.ServerConfig(num_rounds=3),  # Specify number of FL rounds
    strategy=FedAvg(),  # A Flower strategy
)

VirtualClientEngine 리소스

By default the VCE has access to all system resources (i.e. all CPUs, all GPUs, etc) since that is also the default behavior when starting Ray. However, in some settings you might want to limit how many of your system resources are used for simulation. You can do this via the ray_init_args input argument to start_simulation which the VCE internally passes to Ray’s ray.init command. For a complete list of settings you can configure check the ray.init documentation. Do not set ray_init_args if you want the VCE to use all your system’s CPUs and GPUs.

import flwr as fl

# Launch the simulation by limiting resources visible to Flower's VCE
hist = fl.simulation.start_simulation(
    # ...
    # Out of all CPUs and GPUs available in your system,
    # only 8xCPUs and 1xGPUs would be used for simulation.
    ray_init_args={"num_cpus": 8, "num_gpus": 1}
)

클라이언트 리소스 할당

By default the VirtualClientEngine assigns a single CPU core (and nothing else) to each virtual client. This means that if your system has 10 cores, that many virtual clients can be concurrently running.

대부분의 경우 FL 워크로드의 복잡성(즉, 컴퓨팅 및 메모리 사용량)에 따라 클라이언트에 할당되는 리소스를 조정하고 싶을 것입니다. 시뮬레이션을 시작할 때 client_resources argument를 `start_simulation <ref-api-flwr.html#flwr.simulation.start_simulation>`_로 설정하여 이를 수행할 수 있습니다. Ray는 내부적으로 두 개의 키를 사용하여 워크로드(이 경우 Flower 클라이언트)를 스케줄링하고 스폰합니다:

  • num_cpus indicates the number of CPU cores a client would get.

  • num_gpus indicates the ratio of GPU memory a client gets assigned.

몇 가지 예를 살펴보겠습니다:

import flwr as fl

# each client gets 1xCPU (this is the default if no resources are specified)
my_client_resources = {"num_cpus": 1, "num_gpus": 0.0}
# each client gets 2xCPUs and half a GPU. (with a single GPU, 2 clients run concurrently)
my_client_resources = {"num_cpus": 2, "num_gpus": 0.5}
# 10 client can run concurrently on a single GPU, but only if you have 20 CPU threads.
my_client_resources = {"num_cpus": 2, "num_gpus": 0.1}

# Launch the simulation
hist = fl.simulation.start_simulation(
    # ...
    client_resources=my_client_resources  # A Python dict specifying CPU/GPU resources
)

While the client_resources can be used to control the degree of concurrency in your FL simulation, this does not stop you from running dozens, hundreds or even thousands of clients in the same round and having orders of magnitude more dormant (i.e. not participating in a round) clients. Let’s say you want to have 100 clients per round but your system can only accommodate 8 clients concurrently. The VirtualClientEngine will schedule 100 jobs to run (each simulating a client sampled by the strategy) and then will execute them in a resource-aware manner in batches of 8.

리소스가 FL 클라이언트를 예약하는 데 사용되는 방법과 사용자 지정 리소스를 정의하는 방법에 대한 모든 복잡한 세부 사항을 이해하려면 ‘Ray 문서 <https://docs.ray.io/en/latest/ray-core/scheduling/resources.html>’를 참조하세요.

시뮬레이션 예제

Tensorflow/Keras와 파이토치에서 바로 실행할 수 있는 몇 가지 Flower 시뮬레이션 예제는 `Flower 레포지토리 <https://github.com/adap/flower>`_에서 제공됩니다. Google Colab에서도 실행할 수 있습니다:

멀티 노드 Flower 시뮬레이션

Flower’s VirtualClientEngine allows you to run FL simulations across multiple compute nodes. Before starting your multi-node simulation ensure that you:

  1. 모든 노드에서 동일한 Python 환경을 유지합니다.

  2. 모든 노드에 코드 사본(예: 전체 레포지토리)을 보관하세요.

  3. 모든 노드에 데이터 세트의 사본을 보유하세요(자세한 내용은 :ref:`simulation considerations <considerations-for-simulations>`에서 확인하세요)

  4. Pass ray_init_args={"address"="auto"} to start_simulation so the VirtualClientEngine attaches to a running Ray instance.

  5. Start Ray on you head node: on the terminal type ray start --head. This command will print a few lines, one of which indicates how to attach other nodes to the head node.

  6. Attach other nodes to the head node: copy the command shown after starting the head and execute it on terminal of a new node: for example ray start --address='192.168.1.132:6379'

위의 모든 작업이 완료되면 단일 노드에서 시뮬레이션을 실행할 때와 마찬가지로 헤드 노드에서 코드를 실행할 수 있습니다.

Once your simulation is finished, if you’d like to dismantle your cluster you simply need to run the command ray stop in each node’s terminal (including the head node).

멀티 노드 시뮬레이션에 대해 알아두면 좋은 사항

여기에서는 멀티 노드 FL 시뮬레이션을 실행할 때 흥미로운 몇 가지 기능을 나열합니다:

User ray status to check all nodes connected to your head node as well as the total resources available to the VirtualClientEngine.

When attaching a new node to the head, all its resources (i.e. all CPUs, all GPUs) will be visible by the head node. This means that the VirtualClientEngine can schedule as many virtual clients as that node can possible run. In some settings you might want to exclude certain resources from the simulation. You can do this by appending –num-cpus=<NUM_CPUS_FROM_NODE> and/or –num-gpus=<NUM_GPUS_FROM_NODE> in any ray start command (including when starting the head)

시뮬레이션 시 고려 사항

참고

Flower 시뮬레이션으로 모든 FL 워크로드를 간편하게 실행할 수 있도록 이러한 측면에서 적극적으로 노력하고 있습니다.

현재 VCE를 사용하면 개인 노트북에서 간단한 시나리오를 프로토타이핑하든, 여러 고성능 GPU 노드에서 복잡한 FL 파이프라인을 훈련하든 상관없이 시뮬레이션 모드에서 Federated 학습 워크로드를 실행할 수 있습니다. VCE에 더 많은 기능을 추가하는 동안, 아래에서는 Flower로 FL 파이프라인을 설계할 때 염두에 두어야 할 몇 가지 사항을 강조합니다. 또한 현재 구현에서 몇 가지 제한 사항을 강조합니다.

GPU 리소스

The VCE assigns a share of GPU memory to a client that specifies the key num_gpus in client_resources. This being said, Ray (used internally by the VCE) is by default:

  • not aware of the total VRAM available on the GPUs. This means that if you set num_gpus=0.5 and you have two GPUs in your system with different (e.g. 32GB and 8GB) VRAM amounts, they both would run 2 clients concurrently.

  • 관련 없는(즉, VCE에 의해 생성되지 않은) 다른 워크로드가 GPU에서 실행되고 있는지 알지 못합니다. 여기서 두 가지 시사점을 얻을 수 있습니다:

    • 집계 후 ‘글로벌 모델’을 평가하려면 Flower 서버에 GPU가 필요할 수 있습니다(예: `evaluate method <how-to-implement-strategies.html#the-evaluate-method>`_를 사용할 때)

    • If you want to run several independent Flower simulations on the same machine you need to mask-out your GPUs with CUDA_VISIBLE_DEVICES="<GPU_IDs>" when launching your experiment.

In addition, the GPU resource limits passed to client_resources are not enforced (i.e. they can be exceeded) which can result in the situation of client using more VRAM than the ratio specified when starting the simulation.

GPU를 사용한 TensorFlow

TensorFlow와 함께 GPU를 사용 <https://www.tensorflow.org/guide/gpu>`_하면 프로세스에 보이는 모든 GPU의 거의 전체 GPU 메모리가 매핑됩니다. 이는 최적화 목적으로 TensorFlow에서 수행됩니다. 그러나 GPU를 여러 개의 ‘가상’ 클라이언트로 분할하려는 FL 시뮬레이션과 같은 설정에서는 이는 바람직한 메커니즘이 아닙니다. 다행히도 ‘메모리 증가 활성화’를 통해 이 기본 동작을 비활성화할 수 있습니다.

This would need to be done in the main process (which is where the server would run) and in each Actor created by the VCE. By means of actor_kwargs we can pass the reserved key “on_actor_init_fn” in order to specify a function to be executed upon actor initialization. In this case, to enable GPU growth for TF workloads. It would look as follows:

import flwr as fl
from flwr.simulation.ray_transport.utils import enable_tf_gpu_growth

# Enable GPU growth in the main thread (the one used by the
# server to quite likely run global evaluation using GPU)
enable_tf_gpu_growth()

# Start Flower simulation
hist = fl.simulation.start_simulation(
    # ...
    actor_kwargs={
        "on_actor_init_fn": enable_tf_gpu_growth  # <-- To be executed upon actor init.
    },
)

이것이 바로`Tensorflow/Keras Simulation <https://github.com/adap/flower/tree/main/examples/simulation-tensorflow>`_ 예제에서 사용된 메커니즘입니다.

멀티 노드 설정

  • VCE는 현재 특정 ‘가상’ 클라이언트를 어느 노드에서 실행할지 제어하는 방법을 제공하지 않습니다. 즉, 클라이언트가 실행하는 데 필요한 리소스가 하나 이상의 노드에 있는 경우 해당 노드 중 어느 노드에나 클라이언트 워크로드가 예약될 수 있습니다. FL 프로세스 후반부(즉, 다른 라운드에서)에는 동일한 클라이언트가 다른 노드에서 실행될 수 있습니다. 클라이언트가 데이터 세트에 액세스하는 방식에 따라 모든 노드에 모든 데이터 세트 파티션의 복사본을 보유하거나 데이터 중복을 피하기 위해 데이터 세트 제공 메커니즘(예: nfs, 데이터베이스 사용)을 사용해야 할 수 있습니다.

  • 정의상 가상 클라이언트는 임시적 특성으로 인해 ‘상태 없음’입니다. 클라이언트 상태는 Flower 클라이언트 클래스의 일부로 구현할 수 있지만, 사용자는 이를 영구 저장소(예: 데이터베이스, 디스크)에 저장하여 나중에 실행 중인 노드와 관계없이 동일한 클라이언트가 검색할 수 있도록 해야 합니다. 이는 어떤 식으로든 클라이언트의 데이터 세트가 일종의 ‘상태’로 볼 수 있기 때문에 위의 요점과도 관련이 있습니다.