운영용 모델 파일(.pt, .pth, .pkl, .pickle, .joblib)은 Git 저장소에 두지 않습니다. Backend가 모델 artifact를 S3에 업로드하고, AI API에는 S3 URI와 라운드/클러스터/버전 metadata만 전달합니다. AI 서버는 필요한 artifact를 MODEL_LOCAL_DIR(기본 /tmp/models)에 임시 다운로드해서 처리한 뒤, 생성된 global model, cluster model, evaluation report를 다시 S3에 업로드합니다.
필수 런타임 환경변수:
AWS_REGION=ap-northeast-2
ARTIFACT_BUCKET=mlops-artifacts-995370109104-ap-northeast-2
MODEL_LOCAL_DIR=/tmp/modelsECS 운영 환경에서는 IAM task role로 S3 권한을 부여하며, AWS access key/secret key는 코드나 .env에 넣지 않습니다.
POST /clients/fl-model/aggregate
Content-Type: application/json{
"scope": "all_clients",
"roundId": "fl-sync-20260613-001",
"clusterId": "0",
"modelVersion": "v20260613-001",
"expectedClientCount": 3,
"outputPrefixUri": "s3://mlops-artifacts-995370109104-ap-northeast-2/models/clusters/fl-sync-20260613-001",
"models": [
{
"clientId": "CA_1_FOODS_3",
"sampleCount": 13004,
"modelArtifactUri": "s3://mlops-artifacts-995370109104-ap-northeast-2/updates/fl-sync-20260613-001/clients/CA_1_FOODS_3.pt"
},
{
"clientId": "CA_2_FOODS_7",
"sampleCount": 9821,
"modelArtifactUri": "s3://mlops-artifacts-995370109104-ap-northeast-2/updates/fl-sync-20260613-001/clients/CA_2_FOODS_7.pt"
}
]
}응답은 로컬 파일 경로가 아니라 S3 URI metadata를 반환합니다.
{
"ok": true,
"roundId": "fl-sync-20260613-001",
"clusterId": "0",
"modelVersion": "v20260613-001",
"receivedClientCount": 2,
"aggregatedModelUri": "s3://mlops-artifacts-995370109104-ap-northeast-2/models/clusters/fl-sync-20260613-001/cluster-0.pt",
"aggregation": "sample_count_weighted_fedavg"
}s3://{ARTIFACT_BUCKET}/models/global/{modelVersion}/global.pt
s3://{ARTIFACT_BUCKET}/models/clusters/{roundId}/cluster-{clusterId}.pt
s3://{ARTIFACT_BUCKET}/updates/{roundId}/clients/{clientId}.pt
s3://{ARTIFACT_BUCKET}/reports/{roundId}/evaluation.json
POST /clients/fl-model/batch는 Backend DB bytea 기반 전달을 위한 multipart 호환 API입니다. 수신 파일은 Git repo가 아니라 MODEL_LOCAL_DIR/{round_id}/clients 아래에 임시 저장되며, 응답에는 로컬 path를 포함하지 않습니다.
운영 환경에서는 metadata에 modelOutputPrefixUri 또는 outputPrefixUri를 넣어 수신 모델을 즉시 S3에 업로드할 수 있습니다. 이 모드에서는 응답의 modelArtifactUris를 다음 aggregation 호출의 modelArtifactUri로 넘기고, AI 서버는 업로드 후 로컬 임시 파일을 삭제합니다.
Docker 이미지는 ECS CPU 런타임 기준으로 PyTorch CPU wheel(torch==2.5.1+cpu)을 사용합니다. GPU 런타임이 아닌 환경에서 CUDA wheel을 포함하면 이미지가 과도하게 커져 ECR push와 ECS pull 시간이 크게 늘어납니다.
이 저장소는 Fedstock 서비스의 중앙 서버 측 연합학습(FL) 시스템 모듈을 포함하고 있습니다. 연합학습 전체 라운드를 오케스트레이션하고 모델 가중치를 집계하는 FL Server 및 EMD 기반 매장 버블 군집화 코어를 제공합니다.
Note
중앙 백엔드 API 서비스(Spring Boot)는 별도의 저장소인 Fedstock-Backend에서 독립적으로 관리 및 개발되고 있습니다.
├── outputs/ # 글로벌 및 버블 모델 가중치, 클러스터링 이력 리소스
└── src/ # 서버 측 핵심 파이썬 소스코드
├── fl/
│ ├── server.py # BubbleServer 연합학습 오케스트레이터 및 FedAvg 집계
│ └── server_clustering.py # EMD 거리 계산 및 Davies-Bouldin Index 기반 최적 클러스터링 (k*)
├── models/
│ └── lstm.py # 글로벌/버블 가중치 관리용 Lightweight LSTM 모델 정의 (공유)
└── losses.py # HuberSMAPELoss 정의
중앙 백엔드 API 서버의 소스코드 및 구동 방법은 별도의 저장소인 Fedstock-Backend를 참고해 주시기 바랍니다.
Flower 프레임워크와 PyTorch를 결합하여 버블 단위의 FedAvg 연합학습을 학습 라운드별로 조정하고 동적으로 매장을 버블로 재군집화(Dynamic Reclustering)합니다.
src/fl/server_clustering.py를 실행하여 초기 EMD 거리 계산 및 클러스터 할당을 수행할 수 있습니다.src/fl/server.py내의BubbleServer클래스가 전체 communication round와 parameter aggregation을 오케스트레이션합니다.
- 서버 예측 API는 시나리오 기준에 맞춰 다음날 판매량을 예측합니다.
- 입력 CSV에
target_1d가 있으면 해당 값을 우선 사용합니다. target_1d가 없으면client_id와item_id단위로 정렬된sales.shift(-1)값을 계산해 다음날 판매량 target으로 사용합니다.- 응답의
forecastQty,forecastHorizonDays,forecastTarget,forecastUnit은 각각 다음날 판매량,1,target_1d,next_day_sales기준입니다.
POST /ai/clients/cluster-assignment는NEW_API_SPEC_KO.md의 초기 클러스터링 배정 API 구현입니다.- 호환을 위해
POST /clients/cluster-assignment도 같은 handler로 제공합니다. - 인증은
Authorization: Bearer <token>헤더를 사용하며, 서버 기대 토큰은API_BEARER_TOKEN환경변수로 설정해야 합니다. scope=single_client는 제출된featureImportance를 기존feature_importances.json,clustering_results.json기준으로 즉시 배정합니다.scope=all_clients는roundId와expectedClientCount기준으로 요청을 큐에 모았다가 전체 클라이언트가 도착하면 초기 클러스터링을 수행합니다.featureNames는 서버의selectedFeatures와 같은 집합이어야 하며, 순서가 달라도 서버 기준 순서로 재정렬합니다.
POST /ai/clients/{client_id}/fl-model은NEW_API_SPEC_KO.md의 할당 클러스터 FL 모델 다운로드 API 구현입니다.- 호환을 위해
POST /clients/{client_id}/fl-model도 같은 handler로 제공합니다. - 인증은 클러스터 배정 API와 동일하게
Authorization: Bearer <token>및API_BEARER_TOKEN을 사용합니다. - 요청은
multipart/form-data이며model_file,client_id,scope,round_id,sample_weight를 받습니다. scope=single_client는 업로드된.pt를 검증/저장한 뒤, 배정 클러스터의bubble_<clusterId>.pt를 우선 반환하고 없으면 client 모델 또는 업로드 모델로 fallback합니다.scope=all_clients는round_id와clusterId기준으로 클러스터 구성원 모델을 모아sample_weight가중 평균 모델을 생성한 뒤 반환합니다.- 응답은
application/octet-stream이며X-Fedstock-Client-Id,X-Fedstock-Cluster-Id,X-Fedstock-Model-Scope,X-Fedstock-Storage-Path헤더를 포함합니다.
중앙 데이터베이스 스키마 및 테이블 생성 등은 백엔드 시스템에 종속되어 있습니다. 세부적인 데이터베이스 구성 및 스키마에 대해서는 Fedstock-Backend 저장소를 참고하여 주시기 바랍니다.