7️⃣LLM Mergekit

Mergekit: 2개 이상의 LLM 합치기

Merge 알고리즘

1. SLERP

Spherical Linear Interpolation (SLERP)

두 벡터 사이를 부드럽게 보간하는 데 사용되는 방법이다. 이 방법은 일정한 변화율을 유지하며 벡터가 위치한 구형 공간의 기하학적 특성을 보존한다. 기존 선형 보간보다 SLERP를 선호하는 데에는 몇 가지 이유가 있는데 고차원 공간에서 선형 보간을 사용하면 보간된 벡터의 크기가 감소할 수 있다.(즉, 가중치의 배율이 감소). 게다가 가중치의 방향 변화는 변화의 크기보다 더 의미 있는 정보(예: 특징 학습 및 표현)를 나타내는 경우가 많다.

SLERP는 다음 단계에 따라 구현:

  1. 입력 벡터를 단위 길이로 정규화하여 크기가 아닌 방향을 나타내도록 한다.

  2. 벡터의 도트 곱을 사용해 벡터 사이의 각도를 계산한다.

  3. 벡터가 거의 선형에 가까우면 효율성을 위해 기본적으로 선형 보간을 사용한다. 그렇지 않으면 보간 계수 t(t=0 = 첫 번째 벡터의 100%, t=1 = 모델 2의 100%)와 벡터 사이의 각도를 기준으로 SLERP가 스케일 인자를 계산한다.

  4. 이러한 요소는 원본 벡터의 가중치를 부여하는 데 사용되며, 이 가중치를 합산하여 보간된 벡터를 얻는다.

SLERP는 현재 가장 널리 사용되는 병합 방법이지만 한 번에 두 개의 모델만 결합할 수 있다는 제한이 있다. Mistral-7B-Merge-14-v0.1에서 볼 수 있듯이 여러 모델을 계층적으로 결합하는 것은 여전히 가능하다.

Example

보간 계수 t에 대한 값의 기울기를 입력한다. Self attention 및 MLP 레이어의 매개 변수는 OpenPipe/mistral-ft-optimized-1218mlabonne/NeuralHermes-2.5-Mistral-7B의 서로 다른 조합을 사용한다. 다른 레이어는 두 모델을 50/50으로 혼합하여 사용

slices:
	- sources:
		- model: OpenPipe/mistral-ft-optimized-1218
		layer_range: [0, 32]
		- model: mlabonne/NeuralHermes-2.5-Mistral-7B
layer_range: [0, 32]
merge_method: slerp
base_model: OpenPipe/mistral-ft-optimized-1218
parameters:
	t:
		- filter: self_attn
		value: [0, 0.5, 0.3, 0.7, 1]
		- filter: mlp
		value: [1, 0.5, 0.7, 0.3, 0]
		- value: 0.5
dtype: bfloat16

2. TIES

TIES-Merging은 여러 작업별 모델을 하나의 멀티태스크 모델로 효율적으로 병합하도록 설계되어 모델 병합의 두 가지 주요 과제를 해결한다.

  • 모델 매개변수의 중복성: 작업별 모델 내에서 중복되는 매개변수를 식별하고 제거합니다. 이는 미세 조정 중에 이루어진 변경 사항에 집중하여 상위 k%에 해당하는 가장 중요한 변경 사항을 식별하고 나머지는 폐기함으로써 달성한다.

  • 매개변수 기호 간의 불일치: 서로 다른 모델이 동일한 매개변수에 대해 서로 반대되는 조정을 제안할 때 충돌이 발생한다. TIES 병합은 모든 모델에서 가장 지배적인 변화 방향을 나타내는 통일된 부호 벡터를 생성하여 이러한 충돌을 해결

TIES 병합은 다음 세 단계로 구축:

  1. Trim: 가장 중요한 매개변수(밀도 매개변수)를 일부만 유지하고 나머지는 0으로 재설정하여 작업별 모델의 중복성을 줄인다.

  2. Elect Sign: 누적 크기 측면에서 가장 우세한 방향(양수 또는 음수)을 기준으로 통일된 부호 벡터를 생성하여 여러 모델 간의 부호 충돌을 해결한다.

  3. Disjoint Merge: 0 값을 제외하고 통합 부호 벡터와 일치하는 매개변수 값의 평균을 구한다.

Example

이 구성에서는 Mistral-7B를 기본 모델로 사용하여 델타 가중치를 계산한다. 동일한 두 모델, 즉 mistral-ft-optimized-1218(50%)NeuralHermes-2.5-Mistral-7B(30%)를 정규화와 함께 병합한다. 여기서 밀도는 각 모델의 매개 변수의 50%만 유지한다는 것을 의미한다.(나머지 절반은 기본 모델에서 가져옴).

이 구성에서 가중치의 합은 1이 아니지만 normalize: true 매개 변수가 내부적으로 가중치를 자동으로 정규화한다는 점에 유의. 이 구성은 OpenHermes-2.5-neural-chat-7b-v3-1-7B의 작성자가 제공한 매개변수를 참고했다.

models:
	- model: mistralai/Mistral-7B-v0.1
# no parameters necessary for base model
	- model: OpenPipe/mistral-ft-optimized-1218
	parameters:
		density: 0.5
		weight: 0.5
	- model: mlabonne/NeuralHermes-2.5-Mistral-7B
		parameters:
		density: 0.5
		weight: 0.3
merge_method: ties
base_model: mistralai/Mistral-7B-v0.1
parameters:
	normalize: true
dtype: float16

3. DARE

DARE는 두 가지 주요 차이점을 제외하고 TIES와 유사한 접근 방식을 사용:

  • Pruning: DARE는 미세 조정된 가중치를 원래 값(기본 모델의 가중치)으로 무작위로 재설정한다.

  • Rescaling: DARE는 모델 출력에 대한 기대치를 거의 변경하지 않도록 가중치를 재조정한다. 두 모델(또는 그 이상)의 재조정된 가중치를 기본 모델의 가중치에 스케일 팩터와 함께 더한다.

Mergekit의 이 메서드 구현에는 부호 선택 단계가 TIES(dare_ties)인 경우와 없는 경우(dare_linear)의 두 가지 버전이 있다.

models:
	- model: mistralai/Mistral-7B-v0.1
	# No parameters necessary for base model
	- model: samir-fama/SamirGPT-v1
	  parameters:
		density: 0.53
		weight: 0.4
	- model: abacusai/Slerp-CM-mist-dpo
	  parameters:
		density: 0.53
		weight: 0.3
	- model: EmbeddedLLM/Mistral-7B-Merge-14-v0.2
	  parameters:
		density: 0.53
		weight: 0.3
merge_method: dare_ties
base_model: mistralai/Mistral-7B-v0.1
parameters:
	int8_mask: true
dtype: bfloat16

이 구성에서는 dare_ties를 사용하여 Mistral-7B를 기반으로 세 가지 다른 모델을 병합한다. 이번에는 합이 1이 되는 가중치를 선택(합은 0.9에서 1.1 사이여야 함). 밀도 매개변수는 논문에서 권장하는 값(0.5 미만)보다 약간 높지만, 일관되게 더 나은 결과를 제공하는 것으로 보인다. Huggingface 허브의 mlabonne/Daredevil-7B에서 찾을 수 있다. 또한 이 문서에서 가장 우수한 병합 모델이며, 심지어 Marcoro14-7B-slerp보다 성능이 뛰어나다.

4. Passthrough

패스스루 방식은 이전 방식과 크게 다르다. 서로 다른 LLM의 레이어를 연결하여 매개변수 수가 특이한 모델을 생성할 수 있다.(예: 7B 매개변수 모델 2개가 있는 9B). 이러한 모델은 커뮤니티에서 종종 "프랑켄머지" 또는 "프랑켄슈타인 모델"이라고 불린다.

이 기법은 매우 실험적이지만, 두 개의 llma2-70B 모델을 사용하여 goliath-120b와 같은 인상적인 모델을 만들 수 있다. 최근 출시된 SOLAR-10.7B-v1.0도 논문에서 뎁스업 스케일링이라고 하는 동일한 아이디어를 사용한다.

slices:
	- sources:
		- model: OpenPipe/mistral-ft-optimized-1218
		  layer_range: [0, 32]
	- sources:
		- model: mlabonne/NeuralHermes-2.5-Mistral-7B
		  layer_range: [24, 32]
merge_method: passthrough
dtype: bfloat16

결과 프랭큰머지에는 첫 번째 모델의 32개 레이어와 두 번째 모델의 8개 추가 레이어가 모두 포함된다. 이렇게 하면 총 40개의 레이어와 8.99억 개의 파라미터가 있는 프랭큰머지가 생성됩니다. 이 구성은 GML-Mistral-merged-v1에서 영감을 얻음


Mergekit 실행하기

0. 최초 설치 시

!git clone https://github.com/cg123/mergekit.git
%cd mergekit
%pip install -e .

1. Parameter 설정

  • 기본 모델에서 토큰화기를 복사하는 copy-tokenizer

  • allow-crimesout-shard-size는 모델을 RAM이 적은 CPU에서 계산할 수 있는 작은 샤드로 분할

  • lazy-unpickle 메모리 사용량을 낮추기 위해 실험적인 지연 피클러를 활성화

  • 또한 일부 모델에는 trust_remote_code 플래그가 필요 함(Mistral-7B는 해당되지 않음).

OUTPUT_PATH = "./merged/XGen-Llama-7B"  # merge 모델 저장 경로
LORA_MERGE_CACHE = "/tmp"  # LoRa 캐시 임시 경로
CONFIG_YML = "./config/xgen_gradient-slerp.yml"  # config.yml 경로 지정
COPY_TOKENIZER = True  # tokenizer 사용 여부
LAZY_UNPICKLE = False  # low-memory model loader 사용 여부
LOW_CPU_MEMORY = False  # VRAM 사용 여부

2. Config 설정

  • {mergekit/example} 디렉토리에 샘플을 참고하여 작성하고 별도의 이름으로 저장

  • 아래는 작성 예시

slices:
  - sources:
      - model: dalyaff/phi2-sql
        layer_range: [0, -1]
      - model: nakcnx/phi-2-sql-v1
        layer_range: [0, -1]
# or, the equivalent models: syntax:
# models:
#   - model: psmathur/orca_mini_v3_13b
#   - model: garage-bAInd/Platypus2-13B
merge_method: slerp
base_model: nakcnx/phi-2-sql-v1
parameters:
  t:
    - filter: self_attn
      value: [0, 0.5, 0.3, 0.7, 1]
    - filter: mlp
      value: [1, 0.5, 0.7, 0.3, 0]
    - value: 0.5 # fallback for rest of tensors
dtype: float16

3. Merge 실행

# actually do merge
import torch
import yaml

from mergekit.config import MergeConfiguration
from mergekit.merge import MergeOptions, run_merge

with open(CONFIG_YML, "r", encoding="utf-8") as fp:
    merge_config = MergeConfiguration.model_validate(yaml.safe_load(fp))

run_merge(
    merge_config,
    out_path=OUTPUT_PATH,
    options=MergeOptions(
        lora_merge_cache=LORA_MERGE_CACHE,
        cuda=torch.cuda.is_available(),
        copy_tokenizer=COPY_TOKENIZER,
        lazy_unpickle=LAZY_UNPICKLE,
        low_cpu_memory=LOW_CPU_MEMORY,
        trust_remote_code=True
    ),
)
print("Done!")

4. Huggingface repository에 Push 하기

from huggingface_hub import HfApi

username = "kubwa"
MODEL_NAME = "{Your merged Model name}"

# Defined in the secrets tab in Google Colab
api = HfApi(token="{your_huggingface_token}")

api.create_repo(
    repo_id=f"{username}/{MODEL_NAME}",
    repo_type="model"
)
api.upload_folder(
    repo_id=f"{username}/{MODEL_NAME}",
    folder_path="{saved-model-path}",
)

Last updated