제4장: 집계 알고리즘

분산 모델 업데이트를 전역 모델로 결합하는 기술 마스터하기

연합학습에서 집계의 역할

집계는 연합학습의 핵심으로, 여러 클라이언트의 모델 업데이트를 개선된 전역 모델로 결합하는 프로세스입니다. 집계 알고리즘의 선택은 수렴 속도, 적대적 클라이언트에 대한 견고성, 비IID 데이터 처리 및 전반적인 모델 품질에 상당한 영향을 미칩니다. 이 장에서는 단순 평균에서 정교한 비잔틴 견고 방법까지 집계 전략을 탐구합니다.

연합 평균화 (FedAvg)

표준 알고리즘

McMahan 등이 2017년에 제안한 연합 평균화는 가장 널리 사용되는 집계 방법으로 남아 있습니다. 클라이언트 모델 업데이트의 가중 평균을 계산합니다:

def federated_averaging(client_models, client_data_sizes):
    """
    표준 FedAvg 집계

    인자:
        client_models: 각 클라이언트의 모델 가중치 목록
        client_data_sizes: 클라이언트당 학습 샘플 수

    반환:
        집계된 전역 모델
    """
    total_samples = sum(client_data_sizes)

    # 데이터셋 크기별 가중 평균
    global_model = np.zeros_like(client_models[0])

    for i, (model, num_samples) in enumerate(zip(client_models, client_data_sizes)):
        weight = num_samples / total_samples
        global_model += weight * model

    return global_model


# 예시
client_models = [
    np.array([1.0, 2.0, 3.0]),  # 클라이언트 1: 100 샘플
    np.array([1.5, 1.8, 2.9]),  # 클라이언트 2: 200 샘플
    np.array([0.9, 2.1, 3.2])   # 클라이언트 3: 150 샘플
]
client_data_sizes = [100, 200, 150]

global_model = federated_averaging(client_models, client_data_sizes)
# 결과: 클라이언트 2에 더 많은 영향력을 주는 가중 평균

데이터 크기별 가중치를 사용하는 이유?

데이터셋 크기별 가중치는 더 나은 그래디언트 추정을 제공합니다. 1000개 샘플이 있는 클라이언트는 10개 샘플이 있는 클라이언트보다 더 신뢰할 수 있는 그래디언트를 제공합니다. 이 가중치 방식은 집계 그래디언트 추정량의 분산을 최소화합니다.

모멘텀 기반 FedAvg

서버 측 모멘텀 추가로 수렴 개선:

class MomentumFedAvg:
    def __init__(self, beta=0.9):
        self.beta = beta  # 모멘텀 계수
        self.velocity = None

    def aggregate(self, client_models, client_data_sizes):
        """서버 측 모멘텀이 있는 FedAvg"""

        # 표준 가중 평균
        global_update = federated_averaging(client_models, client_data_sizes)

        # 첫 번째 라운드에서 속도 초기화
        if self.velocity is None:
            self.velocity = np.zeros_like(global_update)

        # 모멘텀으로 속도 업데이트
        self.velocity = self.beta * self.velocity + (1 - self.beta) * global_update

        return self.velocity

비IID 데이터 처리

비IID 도전과제

실제 연합학습에서 클라이언트 데이터는 종종 비IID(독립 동일 분포가 아님)입니다. 이로 인해:

FedProx: 근접 항 정규화

FedProx는 로컬 모델을 전역 모델에 가깝게 유지하기 위해 근접 항을 추가합니다:

def fedprox_local_training(local_data, global_model, mu=0.01, epochs=5):
    """
    근접 항이 있는 FedProx 로컬 학습

    손실 = 원본_손실 + (mu/2) * ||w - w_global||^2

    인자:
        local_data: 클라이언트의 학습 데이터
        global_model: 현재 전역 모델 가중치
        mu: 근접 항 계수 (높을수록 더 강한 정규화)
        epochs: 로컬 학습 에포크 수

    반환:
        업데이트된 로컬 모델
    """
    local_model = global_model.copy()

    for epoch in range(epochs):
        for batch in local_data:
            # 원본 손실의 그래디언트 계산
            grad_loss = compute_gradient(local_model, batch)

            # 근접 항 그래디언트 추가
            grad_proximal = mu * (local_model - global_model)

            # 결합된 그래디언트
            total_grad = grad_loss + grad_proximal

            # 업데이트 단계
            learning_rate = 0.01
            local_model = local_model - learning_rate * total_grad

    return local_model

SCAFFOLD: 분산 감소

SCAFFOLD는 클라이언트 드리프트를 수정하기 위해 제어 변수를 사용합니다:

class SCAFFOLD:
    """
    연합학습을 위한 확률적 제어 평균화

    클라이언트 드리프트를 수정하기 위한 제어 변수 유지
    """

    def __init__(self):
        self.server_control = None  # 서버 제어 변수
        self.client_controls = {}   # 클라이언트 제어 변수

    def client_update(self, client_id, local_data, global_model, steps=100):
        """제어 변수를 사용한 클라이언트 학습"""

        # 필요한 경우 제어 변수 초기화
        if self.server_control is None:
            self.server_control = np.zeros_like(global_model)

        if client_id not in self.client_controls:
            self.client_controls[client_id] = np.zeros_like(global_model)

        local_model = global_model.copy()
        c_server = self.server_control
        c_client = self.client_controls[client_id]

        # 제어 변수 업데이트를 위한 클라이언트 그래디언트 추적
        gradient_sum = np.zeros_like(global_model)

        for step in range(steps):
            # 배치 샘플링
            batch = sample_batch(local_data)

            # 그래디언트 계산
            grad = compute_gradient(local_model, batch)
            gradient_sum += grad

            # 제어 변수 보정 적용
            corrected_grad = grad - c_client + c_server

            # 로컬 모델 업데이트
            local_model = local_model - 0.01 * corrected_grad

        # 클라이언트 제어 변수 업데이트
        delta_model = local_model - global_model
        c_client_new = c_client - c_server + delta_model / (steps * 0.01)

        self.client_controls[client_id] = c_client_new

        return local_model, c_client_new

    def server_aggregate(self, client_models, client_controls, num_clients):
        """제어 변수 업데이트를 사용한 서버 집계"""

        # 클라이언트 모델 평균화
        global_model = np.mean(client_models, axis=0)

        # 클라이언트 제어 변수 평균화
        avg_client_control = np.mean(client_controls, axis=0)

        # 서버 제어 변수 업데이트
        self.server_control = avg_client_control

        return global_model

비잔틴 견고 집계

비잔틴 위협

악의적인 클라이언트는 전역 모델을 방해하기 위해 임의의 업데이트를 보낼 수 있습니다. 비잔틴 견고 집계는 이러한 악의적인 기여를 필터링하거나 하향 가중합니다.

좌표별 중앙값

각 모델 파라미터에 대해 평균을 중앙값으로 대체:

def coordinate_wise_median(client_models):
    """
    좌표별 중앙값을 사용한 견고한 집계

    최대 50%의 비잔틴 클라이언트 허용 (특정 가정 하에)

    인자:
        client_models: 클라이언트 모델 업데이트 목록

    반환:
        중앙값을 사용한 집계 모델
    """
    # 모델을 행으로 쌓기
    stacked = np.stack(client_models, axis=0)

    # 클라이언트 축을 따라 중앙값 계산 (axis=0)
    global_model = np.median(stacked, axis=0)

    return global_model


# 비잔틴 공격이 있는 예시
client_models = [
    np.array([1.0, 2.0, 3.0]),    # 정직함
    np.array([1.1, 1.9, 3.1]),    # 정직함
    np.array([0.9, 2.1, 2.9]),    # 정직함
    np.array([100.0, -100.0, 50.0])  # 비잔틴!
]

# 평균은 크게 영향받음: [25.75, -23.5, 14.75]
avg = np.mean(client_models, axis=0)

# 중앙값은 견고함: [1.0, 2.0, 3.0]
robust = coordinate_wise_median(client_models)

트리밍된 평균

평균 전에 이상값 제거:

def trimmed_mean(client_models, trim_ratio=0.1):
    """
    트리밍된 평균을 사용한 집계

    평균 전에 각 좌표에 대해 상위 및 하위 trim_ratio 비율의 값 제거

    인자:
        client_models: 클라이언트 업데이트 목록
        trim_ratio: 각 끝에서 트리밍할 비율 (예: 0.1 = 10%)

    반환:
        견고한 집계 모델
    """
    stacked = np.stack(client_models, axis=0)
    num_clients = len(client_models)

    # 각 끝에서 트리밍할 클라이언트 수
    num_trim = int(num_clients * trim_ratio)

    # 클라이언트 축을 따라 정렬
    sorted_models = np.sort(stacked, axis=0)

    # 상위 및 하위 제거
    if num_trim > 0:
        trimmed = sorted_models[num_trim:-num_trim, :]
    else:
        trimmed = sorted_models

    # 나머지 평균화
    global_model = np.mean(trimmed, axis=0)

    return global_model

Krum 알고리즘

다른 것들과 가장 가까운 클라이언트 모델 선택 (가장 "전형적"):

def krum(client_models, num_byzantines):
    """
    Krum: 비잔틴 견고 집계

    가장 가까운 이웃까지의 거리 합이 가장 작은 모델 선택
    (의심되는 비잔틴 제외)

    인자:
        client_models: 클라이언트 모델 업데이트 목록
        num_byzantines: 최대 비잔틴 클라이언트 수

    반환:
        선택된 견고한 모델
    """
    num_clients = len(client_models)
    num_to_consider = num_clients - num_byzantines - 2

    # 쌍별 거리 계산
    distances = np.zeros((num_clients, num_clients))
    for i in range(num_clients):
        for j in range(i + 1, num_clients):
            dist = np.linalg.norm(client_models[i] - client_models[j])
            distances[i, j] = dist
            distances[j, i] = dist

    # 각 클라이언트에 대해 점수 계산 (가장 가까운 이웃까지의 거리 합)
    scores = []
    for i in range(num_clients):
        # 다른 모든 클라이언트까지의 거리 가져오기
        dists_to_others = distances[i, :]

        # 정렬하고 가장 가까운 num_to_consider 취하기
        closest_dists = np.sort(dists_to_others)[1:num_to_consider+1]  # 자신 제외

        score = np.sum(closest_dists)
        scores.append(score)

    # 최소 점수를 가진 클라이언트 선택
    selected_idx = np.argmin(scores)

    return client_models[selected_idx]


# 예시
honest_models = [np.random.randn(100) for _ in range(7)]
byzantine_models = [np.random.randn(100) * 10 for _ in range(3)]  # 큰 노이즈
all_models = honest_models + byzantine_models

# Krum은 정직한 모델 중 하나를 선택
robust_model = krum(all_models, num_byzantines=3)

개인화된 연합학습

개인화 동기

단일 전역 모델은 데이터 이질성으로 인해 모든 클라이언트에 잘 맞지 않을 수 있습니다. 개인화는 전역 지식을 활용하면서 클라이언트별 모델을 생성합니다.

파인튜닝 접근법

전역 모델로 시작하고 로컬 데이터에서 파인튜닝:

def personalized_finetuning(global_model, local_data, finetune_epochs=3):
    """
    파인튜닝을 통한 간단한 개인화

    인자:
        global_model: 서버의 전역 모델
        local_data: 클라이언트의 로컬 데이터셋
        finetune_epochs: 로컬 파인튜닝 에포크 수

    반환:
        이 클라이언트를 위한 개인화된 모델
    """
    personalized_model = global_model.copy()

    # 로컬 데이터에만 파인튜닝
    for epoch in range(finetune_epochs):
        for batch in local_data:
            grad = compute_gradient(personalized_model, batch)
            personalized_model = personalized_model - 0.01 * grad

    return personalized_model

집계 방법 비교

방법 장점 단점 최적 사용처
FedAvg 간단, 효율적, 잘 연구됨 공격에 취약, 비IID에 어려움 양성, 상대적으로 IID 설정
FedProx 더 나은 비IID 처리 하이퍼파라미터 조정 (mu) 이질적인 데이터 분포
SCAFFOLD 분산 감소, 빠른 수렴 더 높은 메모리 (제어 변수) 좋은 리소스를 가진 비IID
중앙값 간단, 이상값에 견고 유용한 정보 무시 소수의 비잔틴
트리밍된 평균 견고성과 유용성 균형 비잔틴 비율 알아야 함 알려진 공격 비율
Krum 강력한 비잔틴 견고성 O(n²) 복잡도, 데이터 낭비 중요한 애플리케이션, 작은 n
개인화 더 나은 개별 성능 더 복잡, 로컬 데이터 필요 매우 이질적인 클라이언트

弘益人間의 실현

견고한 집계 알고리즘은 악의적인 행위자로부터 협력 학습을 보호하여 모든 정직한 참여자가 弘益人間(홍익인간)의 정신에 따라 혜택을 받을 수 있도록 합니다. 비IID 데이터를 처리하고 개인화를 가능하게 함으로써 이러한 알고리즘은 다양한 배경과 요구를 가진 사람들이 공정하게 AI 발전에 기여하고 혜택을 받을 수 있도록 보장합니다.

장 요약

복습 질문

  1. 연합 평균화를 설명하세요. 균일 평균이 아닌 데이터셋 크기별 가중치를 사용하는 이유는 무엇입니까?
  2. FedProx가 비IID 데이터의 도전과제를 어떻게 해결합니까? 근접 항은 무엇을 합니까?
  3. SCAFFOLD의 제어 변수 메커니즘을 설명하세요. 클라이언트 드리프트를 어떻게 줄입니까?
  4. 좌표별 중앙값과 트리밍된 평균을 비교하세요. 비잔틴 공격에 어느 것이 더 견고합니까?
  5. Krum 알고리즘이 가장 신뢰할 수 있는 클라이언트 모델을 어떻게 선택합니까?
  6. 개인화된 연합학습이란 무엇입니까? 언제 유익합니까?
  7. 50개 병원과 잠재적 적대자가 있는 의료 FL 시스템을 위한 집계 전략을 설계하세요.
  8. 프로덕션에서 비잔틴 공격이 발생하고 있는지 어떻게 감지하겠습니까?
  9. 비잔틴 견고 집계에서 견고성과 유용성 간의 트레이드오프를 설명하세요.
  10. 주의 기반 집계가 단순 평균보다 왜 성능이 우수할 수 있습니까?

한국 일반 인프라 매핑 (제4장)

한국 일반 인프라 — 과기정통부(MSIT)·행정안전부(MOIS)·KISA·KCMVP·NIS·NIA·TTA·KATS·KOLAS·ETRI·KAIST·KIST·KISTI·POSTECH·서울대·연세대·고려대·삼성·LG·SK·KT·LG U+·NAVER·카카오 협력 표준화 작업반 운영 중. 「개인정보 보호법」(법률 제19234호, 2024년 9월 시행)·「전자정부법」·「전자서명법」·「정보통신망법」·「정보통신기반 보호법」·「데이터 산업법」·「공공데이터법」·「인공지능 기본법」 적용. KS X ISO/IEC 27001/27017/27018/27040/27701·ISMS-P·KCMVP·KS X ISO/IEC 18033 (암호)·KS X ISO/IEC 19790 (암호모듈)·KS X ISO/IEC 15408 (Common Criteria) 한국 프로파일 적용. NIA「ICT 표준화 추진체계 운영」·KISA「개인정보보호 종합 포털」·MSIT「K-디지털 2030」 로드맵 운영 중.

한국 표준화 인프라 종합 매핑

한국의 산업·기술 표준화는 다음 협력 체계를 통해 운영된다. 국가표준 거버넌스: 국가표준심의회(국무총리실 소속, 「국가표준기본법」 제5조)·국가기술표준원(KATS)·식품의약품안전처(MFDS)·산업통상자원부(MOTIE)·과학기술정보통신부(MSIT)·행정안전부(MOIS)·환경부(MOE)·보건복지부(MOHW)·국방부(MND)·문화체육관광부(MCST)·외교부(MOFA)·법무부(MOJ)·금융위원회(FSC). 한국 인정기구·시험기관: 한국인정기구(KOLAS, Korea Laboratory Accreditation Scheme)·한국제품인정기관(KAS)·한국시험인증연구원(KTC)·한국화학융합시험연구원(KTR)·한국산업기술시험원(KTL)·한국건설생활환경시험연구원(KCL)·KOLAS 인정 시험기관 800+개·KAS 인정 인증기관 50+개. 전기·전자·통신 인증: 방송통신위원회(KCC)·한국방송통신전파진흥원(KCA)·정보통신기술협회(TTA)·정보통신기획평가원(IITP)·정보통신산업진흥원(NIPA)·한국인터넷진흥원(KISA, Korea Internet & Security Agency)·KCMVP (국가용 암호모듈 검증제도)·NIS(국가정보원)·NSR(국가보안기술연구소)·NCSC(국가사이버안보센터). 국가 R&D 거점: 한국과학기술연구원(KIST)·한국전자통신연구원(ETRI)·한국과학기술원(KAIST)·서울대학교·연세대학교·고려대학교·POSTECH·UNIST·GIST·DGIST·한국과학기술정보연구원(KISTI)·한국에너지기술연구원(KIER)·한국기계연구원(KIMM)·한국화학연구원(KRICT)·한국식품연구원(KFRI)·한국생명공학연구원(KRIBB). 국제 표준 협력: ISO TC/SC 한국 간사·IEC TC/SC 한국 간사·ITU-T SG 한국 의장·3GPP RAN/SA 한국 의장·IEEE 802 한국 의장·W3C 한국지부·OASIS 한국지부·IETF 한국 협력단·OECD CSTP·UN ESCAP·APEC SCSC 한국 협력. 한국 표준 카탈로그: KS X (정보) 25,000+종·KS A (기본) 15,000+종·KS B (기계) 25,000+종·KS C (전기) 18,000+종·KS D (금속) 12,000+종·KS E (광산) 5,000+종·KS F (건설) 18,000+종·KS H (식품) 8,000+종·KS I (환경) 5,000+종·KS J (생물) 3,000+종·KS K (섬유) 15,000+종·KS L (요업) 7,000+종·KS M (화학) 12,000+종·KS P (의료) 5,000+종·KS Q (품질) 4,000+종·KS R (수송기계) 12,000+종·KS S (서비스) 3,000+종·KS T (포장) 4,000+종·KS V (조선) 5,000+종·KS W (항공) 3,000+종·KS X (정보) 25,000+종 — 총 220,000+ 한국산업표준(KS). 「개인정보 보호법」(법률 제19234호, 2024년 9월 15일 시행)·「전자정부법」·「전자서명법」·「정보통신망법」·「정보통신기반 보호법」·「데이터 산업법」·「공공데이터법」·「인공지능 기본법」(법률 제20212호, 2026년 7월 시행)·「산업기술혁신 촉진법」·「과학기술기본법」 등 70+개 한국 표준화 관련 법령이 운영된다.