0. 연합학습이란
왼쪽 그림의 Cloud-based Machine Learning은 기존의 전통적인 머신러닝 학습 방식입니다. 이러한 학습 방식은 클라이언트가 가지고 있는 데이터를 중앙서버로 전달하여, 모델을 학습시킵니다. 이후 학습된 모델을 클라이언트에게 재배포하는 프로세스입니다.
하지만 연합학습은 기존의 전통적인 머신러닝 다르게 모델을 학습시킵니다. 연합학습은 클라이언트 내에서 유저의 데이터를 기반으로 학습한 후, 학습된 모델의 파라미터를 중앙 서버로 전달합니다. 전달된 파라미터를 기반으로 모델을 업데이트합니다. 이후, 업데이트된 모델은 클라이언트에게 재배포됩니다.
위는 연합학습의 FedAvg 알고리즘 pseudo code 입니다. 간단히 요약하면 다음과 같습니다.
1. 서버는 메인 모델을 준비합니다.
2. K개의 클라이언트들 중, 랜덤하게 m개를 고르고 서버에 있는 메인 모델을 보냅니다.
3. 각 클라이언트 내에서 클라이언트들이 가지고 있는 로컬 데이터를 이용하여 메인 모델을 학습합니다.
4. 학습 결과 weight를 다시 서버로 전달합니다.
5. 서버는 전달받은 weight들의 가중평균을 취해 서버의 모델을 업데이트합니다.
1. 연합학습 프레임워크
현재 존재하는 연합학습 프레임워크는 많습니다. 아래 링크는 다수의 연합학습 프레임워크를 비교한 블로그 포스팅입니다.
어떠한 프레임워크를 사용하면 좋을지 고민된다면, 아래를 참고해 주세요.
참고로 저는 FedML을 사용해서 연합학습을 진행했습니다.
https://medium.com/elca-it/flower-pysyft-co-federated-learning-frameworks-in-python-b1a8eda68b0d
2. Federated Optimizer (연합 최적화 알고리즘)
2.1. DecentralizedFL (DeFed)
DecentralizedFL은 중앙 서버 없이 분산된 장치 간에 모델을 조정하는 방식을 사용하는 연합 최적화 알고리즘입니다. 각 장치는 로컬 데이터로 모델을 업데이트하고 다른 장치와 직접 통신하여 모델 파라미터를 조정합니다. 중앙 서버의 역할이 없기 때문에 분산 환경에서 확장성을 가집니다.
2.2. FedAvg (Federated Averaging)
FedAvg는 연합 학습에서 가장 일반적으로 사용되는 연합 최적화 알고리즘 중 하나입니다. 중앙 서버가 로컬 모델 업데이트를 집계하고 평균화하여 전역 모델을 생성합니다. 이를 통해 모든 클라이언트에서 모델이 공평하게 학습되며, 수렴을 돕는 역할을 합니다.
2.3. FedNova
FedNova는 연합 학습에서 발생하는 노이즈와 불안정성에 대응하기 위한 최적화 알고리즘입니다. 불균형한 클라이언트 분포 및 노이즈에 강건한 모델 업데이트를 제공하며, 전역 모델과 로컬 모델 사이의 차이를 줄입니다.
2.4. FedOpt (Federated Optimization)
FedOpt는 연합 학습에서 데이터 분포의 불균형을 다루기 위한 최적화 기술입니다. 모델 업데이트 속도를 조절하여 클라이언트 간의 학습 불균형을 완화하고, 수렴 속도를 향상시킵니다.
2.5. HierarchicalFL (Hierarchical Federated Learning)
HierarchicalFL은 연합 학습을 계층적으로 구성하는 방식을 사용하는 최적화 알고리즘입니다. 중앙 서버와 하위 클러스터의 조합으로 구성되며, 계층적인 모델 업데이트를 통해 효율적인 학습을 지원합니다.
2.6. TurboAggregate
TurboAggregate는 연합 학습의 중요한 구성 요소 중 하나인 모델 집계 프로세스를 최적화하는 데 사용됩니다. 클라이언트에서 전송되는 모델 업데이트의 크기를 줄이고, 모델 업데이트를 효율적으로 집계하여 네트워크 대역폭을 절약합니다.
2.6. VerticalFL (Vertical Federated Learning)
VerticalFL은 다른 기관 또는 조직 간에 데이터를 공유하지 않고도 특정 기능 또는 열에 대한 연합 학습을 수행할 수 있도록 하는 최적화 알고리즘입니다. 수평적 연합 학습과 대조적으로 수직적 연합 학습에서는 특정 열의 정보만 공유됩니다.
3. Federated Learning simulation with a single process
아래 예제는 연합학습을 단일 프로세스에서 연합학습을 진행한 것입니다. 실험 환경은 다음과 같습니다.
- platform/scenario: Parrot (simulator)
- federated optimizer: FedAvg
- dataset: MNIST
- model: Logistic Regression
Step 1. setup Parameters
- fedml_config.yaml
common_args:
training_type: "simulation"
random_seed: 0
config_version: "release"
mlops_api_key: f5b88f5dca344e6faf17809139b89c48
mlops_project_name: sp_fedavg_test
mlops_run_name: fedml_torch_fedavg_mnist_lr_mlsys
data_args:
dataset: "mnist"
data_cache_dir: ~/fedml_data
partition_method: "hetero"
partition_alpha: 0.5
model_args:
model: "lr"
train_args:
federated_optimizer: "FedAvg"
client_id_list: "[]"
client_num_in_total: 10
client_num_per_round: 3
comm_round: 3 # 3 is for quick GitHub sanity check. please change this to your own hyper-parameters (e.g., 200)
epochs: 5
batch_size: 10
client_optimizer: sgd
learning_rate: 0.03
weight_decay: 0.001
validation_args:
frequency_of_the_test: 1
device_args:
using_gpu: false
gpu_id: 0
comm_args:
backend: "sp"
tracking_args:
enable_tracking: false
# When running on MLOps platform(open.fedml.ai), the default log path is at ~/fedml-client/fedml/logs/ and ~/fedml-server/fedml/logs/
enable_wandb: false
wandb_key: ee0b5f53d949c84cee7decbe7a629e63fb2f8408
wandb_entity: fedml-ai
wandb_project: simulation
run_name: fedml_torch_fedavg_mnist_lr
using_mlops: true
Step 2. training
- torch_fedavg_mnist_lr_step_by_step_example.py
import fedml
from fedml import FedMLRunner
if __name__ == "__main__":
# init FedML framework
args = fedml.init()
# init device
device = fedml.device.get_device(args)
# load data
dataset, output_dim = fedml.data.load(args)
# load model
model = fedml.model.create(args, output_dim)
# start training
fedml_runner = FedMLRunner(args, device, dataset, model)
fedml_runner.run()
Step 3. Run the example (step by step APIs)
python torch_fedavg_mnist_lr_step_by_step_example.py --cf fedml_config.yaml
Step 4. Output when the program is just running
실험 환경
터미널을 통해 Federated Learning simulation을 진행하였을 때 첫 번째로 확인할 수 있는 결과입니다. FedML 버전과 실행되는 경로를 확인할 수 있습니다. 또한 실험 환경 및 CPU, GPU config 등을 확인할 수 있습니다.
ROUND 0
round 0에서 클라이언트 993, 859, 298이 참여하는 것을 확인할 수 있습니다. 현재 클라이언트 수는 3개입니다. 이는 위의 fedml_config.yaml에서 client_num_in_total은 10으로 설정하여 10개가 생성되었지만, client_num_per_round를 3으로 설정하였기 때문에 각 라운드에 3개의 클라이언트가 참여할 수 있게 됩니다.
또한, 위에서 언급되었던 클라이언트 993, 859, 298가 학습을 진행하는 것을 확인할 수 있습니다. 각 클라이언트마다 학습을 통해 측정된 loss를 확인할 수 있습니다. 에포크가 5인 이유는 fedml_config.yaml에서 epochs를 5로 설정하였기 때문입니다.
모든 클라이언트에 대하여 로컬 테스트를 진행한 결과는 다음과 같습니다.
{'training_acc': 0.3007751686559419, 'training_loss': 2.1936331450220026}
{'test_acc': 0.3014516347849681, 'test_loss': 2.191970324341631}
ROUND 1
round 1에 참여한 클라이언트는 507, 818, 452입니다. round 0과 다른 클라이언트들이 참여한 것을 확인할 수 있습니다. 이는 총 생성된 클라이언트 수는 10개이지만, 이 중 3개씩 각 라운드에 참여하기 때문에 round 0과 round 1의 클라이언트가 다른 것입니다.
위에서 언급되었던 클라이언트 507, 818, 452가 학습을 진행하는 것을 확인할 수 있습니다. 각 클라이언트마다 학습을 통해 측정된 loss를 확인할 수 있습니다. 에포크가 5인 이유는 fedml_config.yaml에서 epochs를 5로 설정하였기 때문입니다.
모든 클라이언트에 대하여 로컬 테스트를 진행한 결과는 다음과 같습니다.
{'training_acc': 0.3396471198754541, 'training_loss': 2.1570696128821303}
{'test_acc': 0.34147334147334146, 'test_loss': 2.1553126818417954}
round 1이 round 0 보단 acc가 향상되었으며 loss가 줄어든 것을 확인할 수 있습니다.
ROUND 2
round 2에 참여한 클라이언트는 37, 726, 846입니다. round 0, round 1과 다른 클라이언트들이 참여한 것을 확인할 수 있습니다. 이는 총 생성된 클라이언트 수는 10개이지만, 이 중 3개씩 각 라운드에 참여하기 때문에 round 0, round 1의 클라이언트와 다른 것입니다.
위에서 언급되었던 클라이언트 37, 726, 846이 학습을 진행하는 것을 확인할 수 있습니다. 각 클라이언트마다 학습을 통해 측정된 loss를 확인할 수 있습니다. 에포크가 5인 이유는 fedml_config.yaml에서 epochs를 5로 설정하였기 때문입니다.
모든 클라이언트에 대하여 로컬 테스트를 진행한 결과는 다음과 같습니다.
{'training_acc': 0.4258400363258952, 'training_loss': 2.0993426254103236}
{'test_acc': 0.43128476461809795, 'test_loss': 2.097565456300978}
round 2이 round 1 보다 acc가 향상되었으며 loss가 줄어든 것을 확인할 수 있습니다.
4. 결론
단일 프로세스에서 연합학습 시뮬레이션을 진행해 보았습니다.
사용한 최적화 알고리즘은 FedAvg이며, 데이터셋은 MNIST, 모델은 Logistic Regression입니다.
하이퍼 파라미터는 다음과 같이 설정했습니다.
batch_size: 10
client_optimizer: sgd
learning_rate: 0.03
weight_decay: 0.001
총 3회의 라운드를 진행했습니다. 생성한 클라이언트의 수는 10개이며, 각 라운드마다 참여한 클라이언트는 3개입니다.
ROUND 0의 진행 결과는 다음과 같습니다.
{'training_acc': 0.3007751686559419, 'training_loss': 2.1936331450220026}
{'test_acc': 0.3014516347849681, 'test_loss': 2.191970324341631}
ROUND 1의 진행 결과는 다음과 같습니다.
{'training_acc': 0.3396471198754541, 'training_loss': 2.1570696128821303}
{'test_acc': 0.34147334147334146, 'test_loss': 2.1553126818417954}
ROUND 2의 진행 결과는 다음과 같습니다.
{'training_acc': 0.4258400363258952, 'training_loss': 2.0993426254103236}
{'test_acc': 0.43128476461809795, 'test_loss': 2.097565456300978}
따라서 라운드를 진행할수록 정확도를 향상되며, loss는 줄어든다는 것을 확인할 수 있습니다.
이는 모든 클라이언트에 대한 로컬 테스트를 하였을 때 모델 성능이 향상되었다는 것을 확인할 수 있습니다.
하지만 매 라운드에 참여한 클라이언트에서 측정된 loss를 확인하였을 때,
특정 클라이언트는 오히려 중앙 서버의 모델이 아닌 클라이언트 본인의 데이터를 기반으로 모델을 학습한 loss가 더 작은 것을 확인할 수 있습니다.
이러한 경우에는 중앙 서버의 모델이 아닌, 클라이언트 자체가 학습한 모델을 사용하는 것이 옳지 않을까 싶습니다.
5. 참고 레퍼런스
FedML Gitgub : https://github.com/FedML-AI/FedML/tree/master/python/examples\
FedML DOCUMENT : https://doc.fedml.ai/simulation/examples/sp_fedavg_mnist_lr_example.html