런타임 모델 변환(Model Surgery)¶
런타임 모델 변환은 체크포인트를 로드하는 동안 YAML로 정의한 가중치 연산을 적용합니다. 모델을 재학습하거나 변환된 체크포인트를 새로 쓰지 않고 가중치에 직접 개입해 동작을 바꿉니다. 사용자에게 노출되는 주된 진입점은 --surgery <FILE>이며 YAML 파이프라인을 읽어 모델 그래프를 구성하기 전에 메모리 안의 WeightMap에 가중치 연산을 순서대로 적용합니다.
선택한 텐서의 배율을 바꾸거나, 태스크 벡터를 더하거나, 구조 일부를 가지치기하거나, 참조 체크포인트의 텐서로 교체하거나, 두 참조 체크포인트를 보간하는 실험에 사용할 수 있습니다.
목차¶
사용할 때¶
로드 시점 모델 변환은 변경을 텐서 연산으로 표현할 수 있을 때 적합합니다.
- 모델 산술: 선택한 가중치에 태스크 벡터를 더합니다.
- 모델 병합: 두 참조 체크포인트를 LERP 또는 SLERP로 보간합니다.
- 제거 실험(ablation): 선택한 계층, 어텐션 헤드, MLP 채널을 0으로 마스킹합니다.
- 부분 패치: 하나 이상의 텐서를 다른 체크포인트의 텐서로 교체합니다.
- 증폭률 제어: 선택한 사영이나 정규화 매개변수의 배율을 조정합니다.
이는 프롬프트 엔지니어링, 언어 편향, 구조화 출력과 다릅니다. 그 기능들은 프롬프트 또는 디코딩 시점에서 동작합니다. 런타임 모델 변환은 로드된 가중치 자체를 바꾸므로 이후 요청은 프로세스가 종료되거나 서버가 재시작될 때까지 수정된 모델을 사용합니다.
실행 방식¶
--surgery는 mlxcel generate와 mlxcel serve에서 사용할 수 있습니다. 같은 값은 MLXCEL_SURGERY 환경 변수로도 제공할 수 있습니다.
mlxcel generate \
--model ./models/qwen3-4b-4bit \
--surgery ./surgery.yaml \
--prompt "Explain this model change in one paragraph."
MLXCEL_SURGERY=./surgery.yaml \
mlxcel serve \
--model ./models/qwen3-4b-4bit \
--host 0.0.0.0 \
--port 8080
변환 파이프라인은 모델 로딩이 시작되기 전에 해석됩니다. 파일이 없거나, YAML 형식이 잘못되었거나, 글롭 패턴이 유효하지 않거나, 참조 파일이 없으면 큰 모델 가중치를 읽기 전에 실패합니다.
텍스트 모델에서는 묶인 임베딩 복원, 양자화 체크포인트 정규화 같은 기본 가중치 정제 이후이자 Apple Silicon의 bf16→f16 변환 이전에 훅이 실행됩니다. VLM에서는 공통 VLM 가중치 로더 안에서 모델 계열별 키 재매핑 이전에 실행됩니다. 실제 설정을 작성할 때는 체크포인트에 있는 텐서 키 또는 텍스트 로더의 기본 정제 이후 보이는 키를 기준으로 패턴을 작성하십시오.
연산은 YAML에 적힌 순서대로 적용됩니다. 어떤 연산이라도 실패하면 모델 로딩이 실패하며 부분적으로 수정된 모델로 계속 진행하지 않습니다.
YAML 스키마¶
변환 설정 파일은 version: 1과 순서가 있는 operations 목록을 가집니다.
version: 1
operations:
- op: scale
pattern: "model.layers.*.self_attn.o_proj.weight"
factor: 1.2
- op: add
pattern: "model.layers.*.mlp.down_proj.weight"
source: "./task_vectors/friendly.safetensors"
alpha: 0.5
상대 경로로 지정한 source, source_a, source_b는 YAML 파일이 있는 디렉터리를 기준으로 해석됩니다. 절대 경로는 그대로 사용됩니다.
파일은 serde-saphyr가 YAML 1.2 의미 규칙으로 파싱합니다. 한 매핑 안에서 같은 필드를 두 번 쓰면 거부되며, 잘못된 입력에 대한 오류 메시지는 이 파서가 만듭니다.
연산¶
| 연산 | 목적 | 주요 필드 |
|---|---|---|
scale | 일치한 실효 텐서에 스칼라를 곱합니다. 아핀 양자화 가중치는 압축 정수 코드를 건드리지 않고 .scales와 .biases의 배율을 조정합니다. | pattern, factor |
add | 태스크 벡터를 더합니다: base[key] += alpha * source[key]. 참조 텐서는 SafeTensors에서 로드하고 같은 키로 대응시킵니다. | pattern, source, alpha(기본값 1.0) |
prune | 텐서 형태를 유지한 채 선택한 구조를 0으로 마스킹합니다. 전체 계층, Q 어텐션 헤드, MLP 채널을 지원합니다. | granularity, pattern, layer_ids, head_ids, channel_ids |
replace | 일치한 기준 텐서를 참조 SafeTensors 파일의 호환 텐서로 교체합니다. pattern과 source_key 사이에 위치 기반 * 와일드카드 캡처를 지원합니다. | pattern, source, source_key |
interpolate | 두 참조 체크포인트의 텐서를 lerp 또는 slerp로 섞고 결과를 기준 가중치 맵에 씁니다. | pattern, source_a, source_b, ratio(0.0 이상 1.0 이하), method |
scale¶
scale은 증폭률 실험에 유용합니다. 양자화 아핀 배치에서 .weight 키가 일치하면 압축 정수 가중치를 직접 바꾸지 않고 인접한 .scales와 .biases 메타데이터를 바꿔 역양자화된 실효 텐서의 배율을 조정합니다.
add¶
version: 1
operations:
- op: add
pattern: "model.layers.*.mlp.down_proj.weight"
source: "./task_vectors/domain_delta.safetensors"
alpha: 0.5
add는 태스크 벡터 연산입니다. 참조 파일은 일치한 기준 텐서와 같은 키와 형태를 가진 텐서를 포함해야 합니다. 필요한 경우 부동소수점 참조 텐서는 기준 자료형으로 변환됩니다. 압축 정수 기준 텐서는 직접 수정하지 않습니다. 양자화 체크포인트에서는 .scales, .biases 같은 부동소수점 메타데이터를 대상으로 삼거나 부동소수점 체크포인트를 사용하십시오.
prune¶
version: 1
operations:
- op: prune
granularity: attention_head
pattern: "model.layers.12.self_attn.*"
head_ids: [3, 7]
prune은 텐서 형태를 유지하면서 선택한 구조를 0으로 마스킹하므로 모델 아키텍처를 다시 만들 필요가 없습니다. 지원되는 세분도는 다음과 같습니다.
| 세분도 | 필요한 ID 필드 | 동작 |
|---|---|---|
layer | layer_ids | 지정한 Transformer 블록 안에서 일치한 텐서 전체를 0으로 만듭니다. |
attention_head | head_ids | 지정한 Q 헤드에 대해 Q 사영 출력 조각과 O 사영 입력 조각을 0으로 만듭니다. GQA 안전성을 위해 K/V 사영은 건너뜁니다. |
mlp_channel | channel_ids | 상향·게이트·하향 사영에서 해당 중간 채널을 0으로 만듭니다. 양자화된 down_proj는 채널 하나가 패킹된 열 너비보다 좁아 거부됩니다. |
replace¶
version: 1
operations:
- op: replace
pattern: "model.layers.*.self_attn.q_proj.weight"
source: "./donors/patch.safetensors"
source_key: "donor.layers.*.attention.q.weight"
replace는 특정 텐서를 다른 체크포인트의 텐서로 바꾸는 기능입니다. pattern과 source_key의 * 와일드카드 개수는 같아야 합니다. 양자화 텐서는 .weight, .scales, .biases 짝이 존재하면 함께 원자적으로 교체되며 참조 텐서의 형태와 자료형이 일치해야 합니다.
interpolate¶
version: 1
operations:
- op: interpolate
pattern: "model.layers.*.*"
source_a: "./donors/model_a.safetensors"
source_b: "./donors/model_b.safetensors"
ratio: 0.3
method: slerp
interpolate는 두 참조 체크포인트에서 일치하는 텐서를 섞으며, ratio는 source_b의 가중치입니다(ratio: 0.3이면 source_a를 70% 유지). ratio는 0.0 이상 1.0 이하의 유한한 수여야 하고 method는 생략할 수 없습니다. method: lerp는 선형 보간을 사용합니다. method: slerp는 구면 보간을 사용하며 거의 평행하거나 크기가 0인 텐서에서는 LERP로 되돌아갑니다. 보간은 부동소수점 텐서에 정의되어 있으므로 압축된 양자화 텐서는 역양자화하거나 다른 연산으로 다루십시오.
예시¶
무연산 설정 실행¶
빈 연산 목록은 유효하며 모델 변환을 사용하지 않았을 때와 같은 결과를 내야 합니다.
배포 연결이 제대로 되었는지 확인할 때 유용합니다.
여러 연산 조합¶
연산은 순서대로 적용되므로, 뒤의 연산은 앞의 연산 결과를 봅니다.
version: 1
operations:
- op: scale
pattern: "model.layers.*.self_attn.o_proj.weight"
factor: 0.95
- op: add
pattern: "model.layers.*.mlp.down_proj.weight"
source: "./task_vectors/domain_delta.safetensors"
alpha: 0.25
모델 변환을 적용해 서버 시작¶
해당 프로세스가 처리하는 모든 요청은 메모리에서 수정된 가중치를 사용합니다. 변환 설정을 바꾸려면 다른 YAML 파일로 서버를 다시 시작하십시오.
다른 기능과의 관계¶
언어 편향은 디코딩 시점의 로그잇 제어입니다. 가중치를 바꾸지 않고 샘플링할 때 특정 언어나 문자권의 토큰 집합을 억제하거나 장려합니다. 원하는 변경이 텐서 조작이 아니라 출력 언어 정책이라면 언어 편향을 사용하십시오.
LoRA 어댑터도 가중치 공간을 합성하지만 전용 --adapter 경로와 PEFT 형식 어댑터 디렉터리를 사용합니다. 현재 어댑터 경로는 미리 로드한 가중치용 별도 경로에서 LoRA 가중치를 융합하며 --surgery 파이프라인을 실행하지 않습니다. 정확한 로딩 경로를 검증하지 않았다면 한 번에 하나의 로드 시점 합성 경로만 사용하십시오.
구조화 출력은 제약 디코딩입니다. response_format: {"type": "json_schema", ...}는 샘플링 전에 유효하지 않은 토큰을 마스킹하지만 가중치는 바꾸지 않습니다.
파이프라인·텐서 병렬 런타임은 지원되는 계열에서 공통 텍스트 가중치 로더를 사용하므로 해당 경로가 통합 로더를 호출할 때 모델 변환 훅을 사용할 수 있습니다. 지원되지 않는 특수 로드 경로는 이를 우회할 수 있습니다.
제한 사항¶
- 모델 변환은 모델 로드 시 한 번만 적용됩니다. 실행 중 교체는 지원하지 않습니다.
- 수정된 가중치는 메모리에만 존재합니다. 체크포인트 파일을 새로 쓰지 않습니다.
- 패턴은 로더가 보는 실제 가중치 맵의 텐서 키와 일치해야 합니다.
add와interpolate는 호환되는 텐서 형태가 필요합니다. 보간은 부동소수점 텐서용입니다.replace는 형태와 자료형이 정확히 일치해야 합니다.- 가지치기는 텐서 조각을 0으로 만들지만 모델 차원을 줄이지 않습니다. 따라서 연산 형태를 줄이는 기능이 아니라 제거 실험과 동작 제어에 적합합니다.
문제 해결¶
모델 로딩 전에 설정이 실패합니다. YAML 문법, version: 1, 연산 이름, 글롭 패턴, 참조 파일 경로를 확인하십시오. 상대 경로는 YAML 파일의 디렉터리를 기준으로 해석됩니다.
패턴이 텐서와 하나도 일치하지 않습니다. 체크포인트 텐서 이름을 확인하십시오. VLM 계열 로더는 공통 로더 이후에 키 재매핑을 수행할 수 있으므로 VLM 변환 패턴은 보통 원본 체크포인트 키를 대상으로 작성해야 합니다.
양자화 텐서에서 자료형 오류가 납니다. 해당 연산이 양자화 배치를 명시적으로 지원하지 않는 한 압축 정수 .weight 텐서에 산술 연산을 적용하지 마십시오. 태스크 벡터 덧셈은 .scales, .biases 같은 부동소수점 메타데이터를 대상으로 하거나 부동소수점 체크포인트를 사용하십시오.
서버 출력이 바뀌지 않습니다. 서버를 --surgery와 함께 재시작했는지, 로그에 변환 파이프라인 로드가 표시되는지, 일치한 텐서가 실제 사용 중인 모델 경로에 있는지 확인하십시오.