Model Merging (모델 병합)¶
메타 정보¶
| 항목 | 내용 |
|---|---|
| 분류 | Transfer Learning / Multi-Task Learning / Model Composition |
| 핵심 논문 | "Model Soups" (Wortsman et al., ICML 2022), "Editing Models with Task Arithmetic" (Ilharco et al., ICLR 2023), "TIES-Merging" (Yadav et al., NeurIPS 2023), "Language Models are Super Mario" (Yu et al., ICML 2024 - DARE), "AdaMerging" (Yang et al., ICLR 2024), "Evolutionary Optimization of Model Merging Recipes" (Akiba et al., Nature MI 2025) |
| 주요 저자 | Mitchell Wortsman (Model Soups), Gabriel Ilharco (Task Arithmetic), Prateek Yadav (TIES), Takuya Akiba (Evolutionary Merging) |
| 핵심 개념 | 동일 사전학습 모델에서 파인튜닝된 여러 모델의 파라미터를 추가 학습 없이 결합하여 멀티태스크 능력을 확보하는 기법 |
| 관련 분야 | Transfer Learning, Multi-Task Learning, Continual Learning, Knowledge Distillation, Ensemble Methods |
정의¶
Model Merging은 동일 아키텍처와 사전학습 가중치를 공유하는 여러 파인튜닝 모델의 파라미터를 직접 결합하여 하나의 다목적 모델을 생성하는 기법이다. 앙상블과 달리 추론 시 단일 모델만 사용하므로 메모리와 연산 비용이 증가하지 않으며, 추가 학습 데이터나 GPU 학습 없이도 다중 태스크 능력을 획득할 수 있다.
Model Merging의 핵심 구조:
사전학습 모델 (theta_pre)
|
+-- fine-tune on Task A --> theta_A
|
+-- fine-tune on Task B --> theta_B
|
+-- fine-tune on Task C --> theta_C
Task Vector:
tau_A = theta_A - theta_pre
tau_B = theta_B - theta_pre
tau_C = theta_C - theta_pre
병합:
theta_merged = theta_pre + lambda * f(tau_A, tau_B, tau_C)
f: 병합 함수 (average, TIES, DARE, SLERP 등)
lambda: 스케일링 계수
결과: 단일 모델로 Task A, B, C 모두 수행
핵심 원리¶
1. Task Vector (태스크 벡터)¶
파인튜닝 전후의 가중치 차이로, 특정 태스크에 대한 학습된 지식을 인코딩한다.
import torch
from typing import Dict, List
def compute_task_vector(
pretrained: Dict[str, torch.Tensor],
finetuned: Dict[str, torch.Tensor]
) -> Dict[str, torch.Tensor]:
"""
Task vector = finetuned - pretrained
해당 태스크에 특화된 지식 방향을 나타냄
"""
return {
k: finetuned[k] - pretrained[k]
for k in pretrained.keys()
}
# Task Vector의 산술 연산
# 덧셈: 능력 추가
# theta_merged = theta_pre + lambda * (tau_A + tau_B)
# 뺄셈: 능력 제거 (예: 유해성 제거)
# theta_merged = theta_pre - lambda * tau_toxic
# 유추(analogy): 도메인 전이
# theta_merged = theta_pre + tau_A - tau_B + tau_C
2. 병합 시 발생하는 문제¶
| 문제 | 설명 | 영향 |
|---|---|---|
| Sign Conflict | 동일 위치의 파라미터가 태스크별로 반대 방향 | 상쇄되어 정보 손실 |
| Redundant Parameters | 큰 값의 파라미터가 소수, 대부분은 노이즈 | 노이즈 누적 |
| Task Interference | 태스크 간 요구하는 가중치 변화가 상충 | 모든 태스크 성능 저하 |
| Catastrophic Forgetting | 특정 태스크 지식이 다른 태스크에 의해 덮어쓰기 | 태스크 불균형 |
3. Linear Mode Connectivity¶
Model Merging이 작동하는 이론적 근거:
동일 사전학습 모델에서 출발한 파인튜닝 모델들은
가중치 공간(weight space)에서 동일한 loss basin에 위치할 확률이 높다.
Loss
|
| . theta_A
| / \
| / \
| . . theta_B
| /. .\
|/ . . \
+--+-----+----> weight space
theta_pre
동일 basin 내의 선형 보간(linear interpolation)은
loss barrier 없이 이동 가능 --> 병합이 유효함
조건:
1. 공통 초기화 (같은 pre-trained checkpoint)
2. 유사한 학습 설정 (lr, optimizer)
3. 과도한 학습 없음 (basin 이탈 방지)
주요 기법¶
1. Weight Averaging (Model Soups)¶
theta_merged = (1/T) * sum_{t=1}^{T} theta_ft^(t)
변형:
- Uniform Soup: 균등 평균
- Greedy Soup: 검증 성능 기준으로 순차 추가
- Learned Soup: 학습된 가중치로 평균
| 장점 | 단점 |
|---|---|
| 가장 단순한 구현 | Sign conflict 해결 불가 |
| 계산 비용 O(d) | 태스크 수 증가 시 성능 저하 |
| 단일 태스크 앙상블에 효과적 | 이질적 태스크 병합에 부적합 |
2. Task Arithmetic¶
theta_merged = theta_pre + lambda * sum_{t=1}^{T} tau_t
lambda: 스케일링 계수 (보통 0.3 ~ 1.0)
핵심 연산:
- Addition: 능력 추가
theta_new = theta_pre + 0.5 * (tau_NLI + tau_sentiment)
- Negation: 능력 제거
theta_new = theta_pre - 0.3 * tau_toxic
- Analogy: 도메인 전이
theta_new = theta_pre + tau_en_to_fr - tau_en_to_de + tau_de_to_it
3. TIES-Merging¶
Task Interference 해결을 위한 3단계 파이프라인:
Step 1: TRIM (가지치기)
- 각 task vector에서 절대값 기준 하위 (1-k)% 파라미터를 0으로 설정
- 기본 k=20 (상위 20%만 유지)
- 불필요한 노이즈 제거
Step 2: ELECT SIGN (부호 선출)
- 각 파라미터 위치에서 모든 task vector의 부호를 확인
- 다수결(majority vote)로 해당 위치의 최종 부호 결정
- Sign conflict 해결
Step 3: DISJOINT MEAN (분리 평균)
- 선출된 부호와 일치하는 task vector 값만 평균
- 불일치하는 값은 무시
- 간섭 최소화
def ties_merge(
task_vectors: List[Dict[str, torch.Tensor]],
trim_ratio: float = 0.8, # 제거 비율 (80% 제거, 20% 유지)
scaling_coef: float = 0.5
) -> Dict[str, torch.Tensor]:
"""TIES-Merging 구현"""
merged = {}
for key in task_vectors[0].keys():
tensors = torch.stack([tv[key] for tv in task_vectors])
# tensors shape: (T, *param_shape)
# Step 1: Trim
for t in range(len(task_vectors)):
threshold = torch.quantile(
tensors[t].abs().flatten(), trim_ratio
)
tensors[t][tensors[t].abs() < threshold] = 0.0
# Step 2: Elect Sign
sign_sum = torch.sign(tensors).sum(dim=0)
elected_sign = torch.sign(sign_sum)
# tie인 경우 (sign_sum == 0) 양수로 처리
elected_sign[elected_sign == 0] = 1.0
# Step 3: Disjoint Mean
mask = (torch.sign(tensors) == elected_sign.unsqueeze(0))
valid_count = mask.sum(dim=0).clamp(min=1)
merged_value = (tensors * mask).sum(dim=0) / valid_count
merged[key] = merged_value * scaling_coef
return merged
4. DARE (Drop And REscale)¶
대부분의 delta 파라미터는 중복(redundant)하다는 관찰에 기반:
DARE 과정:
1. Drop: 각 task vector의 파라미터를 확률 p로 랜덤 제거
m_t ~ Bernoulli(1 - p) (보통 p = 0.9, 즉 90% 제거)
tau_t_sparse = tau_t * m_t
2. Rescale: 기대값 보존을 위해 스케일 복원
tau_t_rescaled = tau_t_sparse / (1 - p)
3. Merge: rescaled task vector를 병합 (averaging, TIES 등과 결합 가능)
theta_merged = theta_pre + lambda * merge(tau_1_rescaled, ..., tau_T_rescaled)
| DARE + 기법 | 설명 |
|---|---|
| DARE-TIES | DARE 적용 후 TIES-Merging |
| DARE-Task Arithmetic | DARE 적용 후 Task Arithmetic |
| DARE-SLERP | DARE 적용 후 SLERP |
def dare_sparsify(
task_vector: Dict[str, torch.Tensor],
drop_rate: float = 0.9
) -> Dict[str, torch.Tensor]:
"""DARE: Drop And REscale"""
sparse_tv = {}
for key, param in task_vector.items():
# 랜덤 마스크 생성
mask = torch.bernoulli(
torch.ones_like(param) * (1 - drop_rate)
)
# Drop & Rescale
sparse_tv[key] = param * mask / (1 - drop_rate)
return sparse_tv
5. SLERP (Spherical Linear Interpolation)¶
두 모델 간의 구면 보간 -- 방향(direction)을 보존하면서 보간:
SLERP(theta_A, theta_B, t):
omega = arccos(cos_sim(theta_A, theta_B))
theta_merged = sin((1-t)*omega)/sin(omega) * theta_A
+ sin(t*omega)/sin(omega) * theta_B
일반 선형 보간(LERP)과의 차이:
LERP: 크기(magnitude)가 중간에 줄어듦
SLERP: 크기를 유지하면서 방향만 회전
제한: 2개 모델 간 병합에만 적용 가능 (N개는 반복 적용)
6. AdaMerging (Adaptive Model Merging)¶
테스트 데이터의 엔트로피를 최소화하여 병합 계수를 자동 최적화:
Task-wise AdaMerging:
theta_merged = theta_pre + sum_{t=1}^{T} lambda_t * tau_t
lambda_t를 entropy minimization으로 학습
Layer-wise AdaMerging:
theta_merged^(l) = theta_pre^(l) + sum_{t=1}^{T} lambda_t^(l) * tau_t^(l)
각 레이어(l)별, 태스크(t)별로 별도 계수
def adamerging_optimize(
pretrained_state: Dict[str, torch.Tensor],
task_vectors: List[Dict[str, torch.Tensor]],
test_loader,
model_class,
n_iters: int = 1000,
lr: float = 1e-3
) -> List[float]:
"""AdaMerging: 엔트로피 최소화로 병합 계수 학습"""
T = len(task_vectors)
# 학습 가능한 병합 계수
lambdas = torch.nn.Parameter(torch.ones(T) * 0.3)
optimizer = torch.optim.Adam([lambdas], lr=lr)
for i in range(n_iters):
# 현재 계수로 모델 병합
merged_state = {k: v.clone() for k, v in pretrained_state.items()}
for t, tv in enumerate(task_vectors):
for key in merged_state:
merged_state[key] += lambdas[t] * tv[key]
# 병합된 모델로 테스트 데이터 추론
model = model_class()
model.load_state_dict(merged_state)
# 엔트로피 최소화 (unlabeled data)
total_entropy = 0
for x in test_loader:
logits = model(x)
probs = torch.softmax(logits, dim=-1)
entropy = -(probs * probs.log()).sum(dim=-1).mean()
total_entropy += entropy
optimizer.zero_grad()
total_entropy.backward()
optimizer.step()
return lambdas.data.tolist()
7. Evolutionary Model Merging¶
진화 알고리즘(CMA-ES)으로 병합 레시피를 자동 탐색:
탐색 공간:
1. Parameter Space: 레이어별 병합 계수 (DARE-TIES 파라미터 포함)
2. Data Flow Space: 레이어 순서 재배치 (frankenmerging)
진화 과정:
Population: 병합 설정(레시피)들의 집합
Fitness: 검증 데이터 성능
Selection: 상위 레시피 선택
Mutation: 계수 변이
Crossover: 레시피 간 조합
결과:
- EvoLLM-JP: 일본어 수학 추론 모델 (추가 학습 없이 SOTA)
- EvoVLM-JP: 비전-언어 모델 (도메인 간 병합)
기법 비교¶
| 기법 | 모델 수 | 추가 데이터 | 최적화 | 복잡도 | 성능 (ViT-L, 8 tasks) |
|---|---|---|---|---|---|
| Weight Averaging | N | 불필요 | 불필요 | O(d) | 65.3% |
| Task Arithmetic | N | 불필요 | lambda 1개 | O(Td) | 69.8% |
| Fisher Merging | N | 검증 세트 | 불필요 | O(Td) | 68.5% |
| TIES-Merging | N | 불필요 | lambda + k | O(Td) | 73.1% |
| DARE-TIES | N | 불필요 | lambda + p + k | O(Td) | 74.2% |
| SLERP | 2 | 불필요 | t 1개 | O(d) | 71.0% (2-model) |
| AdaMerging | N | 테스트 세트 | 반복 최적화 | O(Td + iter) | 76.8% |
| Evolutionary | N | 검증 세트 | CMA-ES | O(Td * pop * gen) | 78.5% |
(성능 수치는 대표적 벤치마크 기준 상대 비교)
실전 적용 가이드¶
병합 가능 조건¶
필수 조건:
1. 동일 아키텍처 (파라미터 형상 일치)
2. 공통 사전학습 가중치 (같은 checkpoint 출발)
권장 조건:
3. 유사한 학습 설정 (lr, optimizer, epoch)
4. 태스크 간 적절한 다양성 (너무 유사하면 이득 없음)
5. 과도한 학습 회피 (loss basin 이탈 방지)
기법 선택 가이드¶
Q: 모델이 몇 개인가?
|
+-- 2개 --> SLERP (방향 보존, 단순)
|
+-- 3개 이상
|
Q: 테스트 데이터가 있는가?
|
+-- Yes --> AdaMerging (최적 계수 자동 탐색)
| --> Evolutionary (최고 성능, 계산 비용 높음)
|
+-- No
|
Q: 태스크 간 간섭이 심한가?
|
+-- Yes --> DARE-TIES (redundancy 제거 + sign conflict 해결)
| --> TIES-Merging (sign conflict 해결)
|
+-- No --> Task Arithmetic (단순, 효과적)
--> Weight Averaging (가장 단순)
HuggingFace + mergekit 활용¶
# mergekit (Charles Goddard): 실전 LLM 병합 도구
# pip install mergekit
# merge_config.yaml 예시
"""
models:
- model: mistralai/Mistral-7B-v0.1
# base model (no parameters = used as base for task vectors)
- model: WizardLM/WizardMath-7B-V1.1
parameters:
weight: 0.5
- model: Intel/neural-chat-7b-v3-1
parameters:
weight: 0.3
merge_method: dare_ties
base_model: mistralai/Mistral-7B-v0.1
parameters:
density: 0.5 # DARE: 유지 비율 (1 - drop_rate)
weight: 1.0 # 전체 스케일링
dtype: float16
"""
# 실행
# mergekit-yaml merge_config.yaml ./output-model --cuda
# Python API로 직접 병합
from transformers import AutoModelForCausalLM
import torch
def merge_llms(
base_name: str,
expert_paths: list,
method: str = "dare_ties",
scaling: float = 0.5,
dare_density: float = 0.5,
ties_density: float = 0.2
):
"""LLM 병합 파이프라인"""
# 1. Base 모델 로드
base = AutoModelForCausalLM.from_pretrained(
base_name, torch_dtype=torch.float16
)
base_state = base.state_dict()
# 2. Task vectors 계산
task_vectors = []
for path in expert_paths:
expert = AutoModelForCausalLM.from_pretrained(
path, torch_dtype=torch.float16
)
tv = {
k: expert.state_dict()[k] - base_state[k]
for k in base_state.keys()
}
task_vectors.append(tv)
del expert # 메모리 해제
# 3. DARE 적용 (선택적)
if "dare" in method:
task_vectors = [
dare_sparsify(tv, drop_rate=1.0 - dare_density)
for tv in task_vectors
]
# 4. TIES 병합
if "ties" in method:
merged_tv = ties_merge(
task_vectors,
trim_ratio=1.0 - ties_density,
scaling_coef=scaling
)
else:
# Simple average
merged_tv = {}
for key in task_vectors[0]:
merged_tv[key] = scaling * torch.stack(
[tv[key] for tv in task_vectors]
).mean(dim=0)
# 5. 최종 병합
merged_state = {
k: base_state[k] + merged_tv[k]
for k in base_state.keys()
}
base.load_state_dict(merged_state)
return base
LLM에서의 Model Merging¶
Open Source LLM 커뮤니티의 활용¶
Model Merging이 LLM 생태계에서 폭발적으로 성장한 이유:
1. 학습 비용 절감
- 7B 모델 풀 파인튜닝: 수십~수백 GPU hours
- 모델 병합: 수 분 (CPU에서도 가능)
2. Open LLM Leaderboard 상위권
- 2024년 상반기, 상위 모델의 상당수가 병합 모델
- mergekit 도구로 누구나 시도 가능
3. 능력 조합
- 수학 전문 모델 + 코딩 전문 모델 + 대화 모델
--> 범용 능력을 갖춘 단일 모델
주요 성공 사례:
- NeuralBeagle: 여러 Mistral 파인튜닝 모델 병합
- Goliath-120B: 2개의 70B 모델 layer stacking
- EvoLLM-JP: 진화 알고리즘으로 일본어 모델 병합 (Nature MI 2025)
병합 전략별 적합한 시나리오¶
| 시나리오 | 권장 기법 | 이유 |
|---|---|---|
| 같은 태스크의 다양한 학습 설정 | Model Soups | 동일 목적, 다른 하이퍼파라미터 |
| 서로 다른 태스크 전문가 결합 | DARE-TIES | 간섭 최소화 필요 |
| 2개 모델 스타일 블렌딩 | SLERP | 방향 보존, t로 비율 조절 |
| 유해성 제거 | Task Arithmetic (뺄셈) | 특정 능력 선택적 제거 |
| 도메인 전이 | Evolutionary | 최적 레시피 자동 탐색 |
2025-2026 최근 동향¶
1. G-Merging (ICLR 2026)¶
그래프 기반 멀티태스크 모델 병합. 태스크 간 관계를 그래프로 모델링하여 최적 병합 계수를 결정한다. 파라미터 효율적 멀티태스크 통합에 초점.
2. What Matters for Model Merging at Scale (NeurIPS 2025)¶
1B~64B 규모에서 병합 기법을 체계적으로 평가. 모델 규모가 클수록 단순한 averaging도 효과적이며, 8개 이상의 전문 모델 병합 시 성능 포화가 발생함을 밝힘.
3. Evolutionary Merging (Nature Machine Intelligence 2025)¶
Sakana AI의 진화 알고리즘 기반 병합. CMA-ES로 레이어별 병합 계수와 데이터 흐름을 동시 최적화. 일본어 VLM (EvoVLM-JP)에서 도메인 간 병합 성공.
4. Localize-and-Stitch (TMLR 2025)¶
Sparse Task Arithmetic -- 태스크별로 중요한 파라미터를 먼저 식별(localize)한 뒤, 해당 부분만 선택적으로 결합(stitch). 전체 파라미터 병합보다 간섭이 적음.
5. DivMerge (NeurIPS 2025)¶
Divergence 기반 병합. 태스크별 파라미터 분포의 divergence를 측정하여 충돌 영역을 식별하고, 태스크별 전문 영역을 분리 유지.
한계와 향후 방향¶
알려진 한계¶
| 한계 | 설명 | 완화 방법 |
|---|---|---|
| 공통 초기화 필요 | 다른 사전학습 모델 간 병합 어려움 | Weight matching, permutation alignment |
| 태스크 수 한계 | 8개 이상 병합 시 성능 포화 | Modular merging, task clustering |
| 이론적 이해 부족 | 왜 작동하는지 완전히 규명되지 않음 | Linear mode connectivity 연구 |
| LoRA와의 결합 | 어댑터 병합 시 추가 고려사항 | LoRA merging 전용 기법 개발 중 |
| 평가 어려움 | 병합 후 모든 태스크 평가 비용 | 자동화된 벤치마크 도구 |
향후 연구 방향¶
- Cross-Architecture Merging: 서로 다른 아키텍처 간 병합 (weight matching + permutation)
- Continual Merging: 순차적 태스크 학습과 병합의 통합
- Modular Merging: 전체 모델이 아닌 모듈(레이어, 어텐션 헤드) 단위 선택적 병합
- Theoretical Foundations: Loss landscape geometry와 병합 성공 조건의 수학적 규명
- Multimodal Merging: Vision + Language + Audio 전문 모델의 통합
참고 자료¶
| 자료 | 유형 | 링크 |
|---|---|---|
| Model Soups | ICML 2022 | arxiv.org/abs/2203.05482 |
| Task Arithmetic | ICLR 2023 | arxiv.org/abs/2212.04089 |
| TIES-Merging | NeurIPS 2023 | arxiv.org/abs/2306.01708 |
| DARE | ICML 2024 | arxiv.org/abs/2311.03099 |
| AdaMerging | ICLR 2024 | arxiv.org/abs/2310.02575 |
| Evolutionary Merging | Nature MI 2025 | arxiv.org/abs/2403.13187 |
| Model Merging Survey | ACM Computing Surveys 2026 | dl.acm.org/doi/10.1145/3787849 |
| mergekit | 도구 | github.com/arcee-ai/mergekit |
| Cameron Wolfe Survey | 튜토리얼 | cameronrwolfe.substack.com/p/model-merging |
| Awesome Model Merging | 자료 모음 | github.com/EnnengYang/Awesome-Model-Merging-Methods-Theories-Applications |