가중치 공간 프로그래밍 (Weight-space programming)
작은 오픈 모델의 가중치를 옵티마이저 없이 직접 편집하여 목표 성능을 향상시킵니다. 이는 "Sparks of Weight-Space Programming" (Takehi, Teoh, Zhang, Khattab, MIT CSAIL, 2026년 11월 2일)의 실험 8을 따릅니다: Qwen3.5-0.8B의 사고 루프(thinking loop)는 레이어 15와 19의 MLP가 작성한 하나의 잔차 방향(residual direction)으로 추적되었고, 레이어당 64개의 down_proj 열을 순위-1 편집한 결과 MATH-500 점수가 7.9%에서 48.1%로 향상되었습니다.
아래 빠른 경로(fast path)를 순서대로 따르십시오. 모든 스크립트는 scripts/ 디렉토리에 포함되어 있으며 테스트되었습니다. 단계가 실패하지 않는 한 파이프라인을 재설계하거나 새로운 도구를 작성하지 마십시오.
이 스킬이 보장하는 것과 보장할 수 없는 것. 어떤 방법도 편집이 도움이 될 것이라고 약속할 수 없습니다. 일부 모델은 끌 수 있는 단일 습관이 없습니다. 이 스킬은 대신 프로세스를 보장합니다:
- 작업 손실 없음: 충돌 시 더 작은 배치로 다시 시작하고 재개합니다.
- 측정된 연습 검사(practice check)를 통과하지 않으면 어떤 편집도 보류된 테스트(held-out test)에 도달하지 않습니다.
- 실패한 검사는 중단하는 대신 고정된 단계를 통해 에스컬레이션됩니다.
- 모든 실행은 명확한 판정과 수치로 끝나며, 아무것도 작동하지 않으면 복사본이 복원됩니다.
참고 자료 (세부 사항만 필요할 때):
references/goals.md: 다른 목표; 일치하는 쌍 작성 방법; 채점기; 레시피.references/engines.md: 각 OS 및 GPU의 엔진, 설치, 크기 조정, 문제점, 스모크 테스트.references/evaluation.md: 분할, 샘플링 프로토콜, MMLU-Pro 특이사항, 쌍별 통계, 보고서 템플릿.references/method.md: 각 단계의 수학 및 저자의 정확한 레시피.
빠른 경로 (Fast path)
네 개의 플레이스홀더를 한 번 설정합니다 (PowerShell: $env:SKILL = "...", 그 다음 $env:SKILL):
SKILL=<이 스킬의 폴더> BASE=<기본 모델 폴더> COPY=<기본 모델 폴더>-<목표> WORK=<결과 폴더>
모든 생성 작업을 백그라운드에서 실행하고 (Claude Code: Bash 도구의 run_in_background, 셸 & 아님) 폴링 대신 완료 알림을 기다립니다. 생성이 시간을 지배하므로, 예산을 미리 사용자에게 알립니다: 사전 설정의 경우 소비자 GPU에서 1.5–3시간, 데이터센터 GPU에서 vLLM 사용 시 훨씬 짧습니다.
0. 필요한 것만 묻습니다 (한 가지 질문). 목표를 물어보세요. 수학이나 과학이라면 사전 설정을 사용하십시오: 더 이상 질문하지 않습니다. 그렇지 않으면 다음을 묻거나 작성을 도와야 합니다:
- 실패를 보여주는 프롬프트 (
{"id", "prompt", "answer"?, "group"?}JSON 라인 형식) - 프롬프트를 채점하는 방법 (
references/goals.md섹션 3) - 루프가 아닌 행동의 경우, 12개 이상의 일치하는 예시 쌍 (섹션 2)
"가중치 편집, 학습 없음"을 확인하십시오.
1. 시스템 확인 (2분): python $SKILL/scripts/device.py --model $BASE --jobs 2. 새 시스템에서는 references/engines.md 섹션 6의 스모크 테스트도 실행하십시오.
2. 모델 복사 (1분). 모든 편집은 이 복사본의 파일에 적용됩니다; 모든 평가는 복사본을 로드합니다.
python $SKILL/scripts/copy_model.py --base $BASE --copy $COPY
3. 분할 (몇 초).
- 과학 사전 설정:
python $SKILL/scripts/make_splits.py --task mmlu --source <MMLU-Pro 테스트 parquet 파일> --out $WORK/splits. - 수학 사전 설정: 동일하지만
--task math --source <MATH-500 test.jsonl> --practice 25 --heldout 75사용. - 사용자 정의 목표: 프롬프트 파일을 고정된 규칙에 따라
practice.jsonl과heldout.jsonl로 분할하고, 약 30개의 보류된 ID를 포함하는test_ids.txt를 추가로 만듭니다. 모든 분할은 어떤 답변도 보기 전에 이루어져야 합니다.
아래에서 T는 작업 (mmlu, math 또는 jsonl)이고 G는 채점기 옵션입니다 (사전 설정의 경우 없음; 그 외의 경우 references/goals.md 참조).
4. 두 개의 기본 실행을 동시에 시작:
python $SKILL/scripts/run_eval.py --task $T --model $BASE --label base --data $WORK/splits/practice.jsonl --out $WORK/practice/base.jsonl --max-tokens 16384 --jobs 2
python $SKILL/scripts/run_eval.py --task $T --model $BASE --label base --data $WORK/splits/heldout.jsonl --ids-file $WORK/splits/test_ids.txt --out $WORK/test/base.jsonl --jobs 2
다른 모델의 경우 모델 카드의 샘플링 설정을 사용하십시오 (--profile 또는 재정의 플래그; references/engines.md). 보류된 실행은 편집에 의존하지 않습니다.
5. 대비 얻기.
- 루프 (사전 설정, 또는 답변이 제한에 도달하는 모든 목표): 루프는 답변이 제한에 도달할 때만 나타납니다.
grep -c '"length"' $WORK/practice/base.jsonl로 개수를 세고, 15개 이상이면 연습 실행을 중지합니다. - 다른 행동: 쌍이 필요하며, 연습 실행은 기준선을 제공하기 위해 완료되어야 합니다.
그런 다음 채점:
python $SKILL/scripts/grade.py --task $T $G $WORK/practice/base.jsonl --out $WORK/practice/summary.json
진행/중단 결정. 개선 여지를 추정하십시오: 해당 행동을 보이는 답변의 비율에 해당 행동을 보이지 않는 답변의 점수를 곱합니다. 약 10% 미만이면 진행하기 전에 사용자에게 기대치가 낮을 것이라고 알리십시오.
6. 방향 읽기, 후보 빌드, 스크리닝 (몇 분, 순전파만 사용). 루프:
python $SKILL/scripts/probe.py collect --task $T --model $BASE --data $WORK/splits/practice.jsonl --runs $WORK/practice/base.jsonl --out $WORK/probes
쌍 (깨끗한 부수 효과 윈도우를 위해 --runs, --data 및 --task 추가):
python $SKILL/scripts/probe.py collect-pairs --model $BASE --pairs pairs.jsonl --thinking on --out $WORK/probes
그런 다음 1차 후보, 제어 그룹을 빌드하고 스크리닝:
for spec in "15 19:128:6" "15 19:256:6" "15 19:64:6" "11 15 17 19 21:128:6"; do IFS=: read L K A <<< "$spec"; python $SKILL/scripts/probe.py build --probes $WORK/probes --model $BASE --layers $L --k $K --alpha $A --out "$WORK/edits/L${L// /-}_k${K}_a${A}.safetensors"; done
python $SKILL/scripts/probe.py build --probes $WORK/probes --model $BASE --layers 15 19 --k 128 --alpha 6 --control random --out $WORK/edits/random.safetensors
python $SKILL/scripts/probe.py screen --probes $WORK/probes --model $BASE --edits $WORK/edits/*.safetensors
Windows PowerShell에서는 각 build 라인을 별도로 실행하십시오. 위 레이어는 24-레이어 모델에 적합합니다. 다른 모델의 경우 깊이의 약 60%와 80%에 해당하는 레이어, 5개 레이어 범위, 더 깊은 레이어 단독을 사용하십시오.
unwanted에 대한 감소량을 기준으로 후보의 순위를 매기고, wanted 및 clean 감소량이 그 값의 1/3 미만인 것만 유지하십시오. 무작위 제어는 0 근처에 유지되어야 합니다. 만약 최고 후보만큼 움직인다면 방향이 특이적이지 않으므로 중단 단계로 이동하십시오.
7. 최고 후보를 복사본에 쓰고 확인 (1분). 인메모리 편집을 평가하지 마십시오.
python $SKILL/scripts/apply_edit.py --base $BASE --copy $COPY --edit $WORK/edits/<후보>.safetensors
python $SKILL/scripts/diff_edit.py --base $BASE --edited $COPY --out $WORK/edit_report.json
diff는 의도된 down_proj 텐서만, changed_columns = k, rank-1 공유가 약 1이고 중앙값 α가 선택된 α에 가까워야 합니다.
8. 연습 검사: 게이트 (15–25분, 기본 보류 실행과 동시에). 기본이 실패한 (중단, 오답 또는 플래그 지정) 모든 연습 질문과 기본이 잘 처리한 약 6개 질문에 대해 복사본을 실행합니다:
python -c "import json; g=json.load(open('$WORK/practice/summary.json'))['graded']['base']; bad=[x['id'] for x in g if x['cut'] or x['correct'] is False or x['flagged']]; ok=[x['id'] for x in g if x['id'] not in bad]; open('$WORK/check_ids.txt','w').write('\n'.join(bad+ok[::max(1,len(ok)//6)][:6])+'\n')"
python $SKILL/scripts/run_eval.py --task $T --model $COPY --label copy --data $WORK/splits/practice.jsonl --ids-file $WORK/check_ids.txt --out $WORK/practice/copy.jsonl --max-tokens 16384 --jobs 2
python $SKILL/scripts/grade.py --task $T $G $WORK/practice/base.jsonl $WORK/practice/copy.jsonl
게이트 통과는 다음 세 가지가 모두 성립해야 합니다:
- 고정 수(fixed) ≥ max(3, 검사된 기본 실패의 20%)
- 손상 수(broke) ≤ 고정 수 / 4
- 루프 목표의 경우 중단 비율(cut share)이 최소 1/4 감소
통과: 10단계로 이동. 실패: 9단계.
9. 다음 순서대로 에스컬레이션; 각 단계는 하나의 추가 연습 검사입니다.
- 다음 순위의 후보. 복사본 복원 (
copy_model.py --base $BASE --copy $COPY --restore), 적용, 7-8단계 반복. 최대 두 개의 추가 후보에 대해 이 작업을 수행합니다. - 2차 시도, 행동이 사라진 것이 아니라 이동한 경우. 예를 들어, 생각이 닫히지만 루프가
response후에 다시 시작되거나 복사본 답변에 새로운 원치 않는 패턴이 나타납니다. 편집된 복사본을 새로운 기본으로 취급:copy_model.py --base $COPY --copy $COPY2로COPY2생성;--model $COPY --runs $WORK/practice/copy.jsonl로probe.py collect(또는collect-pairs) 실행;--model $COPY로 빌드 및 스크리닝;--base $COPY --copy $COPY2로 적용;- 8단계와 같이
COPY2확인.
- 중단. 세 번의 검사 후 (또는 사용자가 설정한 시간 예산 후) 신뢰할 수 있는 개선이 없습니다. 복사본을 복원하고 "신뢰할 수 있는 개선 없음" 판정과 함께 각 후보의 수치를 보고합니다. Qwen3.5-0.8B의 경우 게시된 수학 편집을 비교 자료로 제공하십시오 (저자의 로그에 따르면 MMLU-Pro의 중단 비율을 28.9%에서 0.5%로 줄였습니다; 이 파일의 끝 참조). 사용자가 동의하는 경우에만 사용하십시오.
선택을 위해 보류된 결과를 사용하지 마십시오; 연습 검사만 결정합니다.
10. 복사본에서 보류 테스트 (30–60분). 기본 보류 실행이 가장 긴 답변을 지나면 시작합니다:
python $SKILL/scripts/run_eval.py --task $T --model $COPY --label copy --data $WORK/splits/heldout.jsonl --ids-file $WORK/splits/test_ids.txt --out $WORK/test/copy.jsonl --jobs 2
python $SKILL/scripts/grade.py --task $T $G $WORK/test/base.jsonl $WORK/test/copy.jsonl --out $WORK/test/summary.json
쌍별 결과에서 판정을 내립니다:
- "명확한 개선" 고정 > 손상이고 부호 검정 p < 0.05인 경우.
- "개선과 일관되지만 입증되지 않음" 고정 > 손상이지만 p ≥ 0.05인 경우; 더 큰 테스트를 권장합니다.
- "개선 없음" 고정 ≤ 손상인 경우; 복사본 복원을 권장합니다.
11. 보고 references/evaluation.md의 템플릿 사용:
- 보류 전후 점수, 쌍별 고정/손상 개수;
- 행동 비율 (중단, 플래그, 생각 닫힘);
- 각 후보의 스크린 및 검사 수치, 무작위 제어;
- 변경된 가중치;
- 주의사항: 습관을 끄는 것은 새로운 능력이 아닙니다.
시간을 낭비하는 실수 (반복하지 마십시오)
- 너무 큰 배치, 또는 최고점에서 두 개의 긴 작업. 메모리 부족 충돌은 진행 중인 답변(루프)을 죽입니다.
--batch auto --jobs 2를 사용하고, 첫 번째 32k 작업이 가장 긴 답변에 있는 동안 두 번째 작업을 시작하지 마십시오. 감독자(supervisor)는 충돌한 실행을 배치 절반으로 다시 시작합니다. - 전체 실행을 기다리는 것. 약 15개의 루프면 충분합니다.
- 평가를 위한 인메모리 편집.
probe.py screen만 편집을 인메모리에 적용하며, 교사 강제(teacher-forced) 읽기에만 사용됩니다. - 스크린만 신뢰하는 것. 루프에 대한 스크린 감소 -0.10은 생성에서 26개 중 3개의 루프만 중단시켰으므로 항상 게이트를 실행하십시오.
- 부분 실행을 채점하거나 먼저 완료된 질문으로 테스트 질문을 선택하는 것.
pkill -f <텍스트>로 작업을 중지하는 것. 명령줄에 해당 텍스트가 포함된 감시자(watcher)도 함께 종료됩니다.
규칙 (포스트에 명시된 대로)
이 규칙을 지키고 보고서에 준수했다고 명시하십시오.
- 학습 없음. 역전파, 자동 미분, 옵티마이저, 또는 손실에 대한 가중치의 반복적 피팅이 없습니다. 메트릭이 개선될 때까지 α 또는 가중치를 조정하는 것은 피팅으로 간주됩니다. 위의 고정된 후보 목록 중에서 선택하는 것은 피팅이 아닙니다.
- 측정을 위한 순전파는 허용됨: 생성, 교사 강제 로그 확률, 은닉 상태 및 MLP 활성화, 그리고 이들 또는 가중치의 통계 (평균, 차이, SVD).
- 범위 밖:
- 임베딩, (공유된) 출력 헤드 및 최종 정규화 (
weights.py가 거부함); - 전체 텐서에 상수 곱하기;
- 전역 선명화 또는 평탄화;
- 문제와 관계없이 생각을 조기에 강제로 닫기;
- 안전 행동 제거: 거절, 보호 장치, 유해 요청 준수.
- 임베딩, (공유된) 출력 헤드 및 최종 정규화 (
- 가중치 값만 변경됩니다. 이름, 모양, dtype, 설정, 토크나이저, 채팅 템플릿 및 디코딩 설정을 유지하십시오.
- 분할 규율. 서로소인 연습 및 보류 세트, 편집 전에 고정. 보류 결과는 편집이 고정된 후 한 번만 확인합니다.
- 공개된 선택. 보고서는 시도된 모든 후보와 승자를 선택한 메트릭을 나열합니다.
각 단계가 이렇게 작동하는 이유
- 대비: 방향은 각 레이어의 출력에서, 그렇지 않으면 일치하는 원하지 않는 텍스트와 원하는 텍스트 사이의 평균 차이입니다.
- 루프의 경우,
loops.py는 루프 시작 직전의 1,024 토큰과 내부의 1,024 토큰을 취합니다: 동일한 질문, 동일한 답변, 거의 동일한 위치. 시작점은 다음 512 토큰의 90%가 이전 16-gram을 반복하는 첫 번째 지점입니다. - 다른 행동의 경우, 쌍이 일치를 제공합니다.
- 루프의 경우,
- 기여자 열: score_j = (원하지 않는 뉴런 j의 평균 활성화 − 원하는 뉴런 j의 평균 활성화) × (u · W_down[:, j]); 상위 k개를 취합니다. 정적 쓰기 u·W만으로는 충분하지 않습니다: 레이어당 게시된 64개 열 중 21-22개만이 상위 64개에 있습니다.
- 편집: W'[:, S] = W[:, S] − α u (uᵀ W[:, S]), 편집되는 모델에서 float32로 계산됩니다. α = 1은 구성 요소를 제거하지만 루프에 효과가 없었습니다; α = 6은 -5c로 뒤집어 해당 뉴런이 행동에 반대되도록 만듭니다.
- 스크리닝: 편집이 적용된 평균 로그 확률의 변화. 원하지 않는 텍스트는 덜 가능성이 높아져야 합니다; 원하는 텍스트와 깨끗한 텍스트는 그대로 있어야 합니다. 동일한 열에 대한 노름-일치 무작위 방향이 제어입니다.
- 게이트: 스크린 수치는 생성을 느슨하게만 예측합니다 (아래 결과 참조), 따라서 보류 테스트 전에 연습 질문에 대한 짧은 생성 검사가 결정합니다.
- 저장:
weights.py는 원시 파일에서 건드린 safetensors 샤드만 다시 작성합니다. 추론 엔진은 로드 시 텐서를 다시 작성하거나 드롭하므로 엔진에서 가중치를 저장하지 마십시오. - 프로토콜: 생각 켜기, temperature 0.6, top_p 0.95, top_k 20, 생성된 토큰에 대해서만 presence penalty 1.5, 32,768 새 토큰 (
--profile thinking). 모든 엔진은 vLLM의 의미론과 일치합니다. - 페어링: 엔진과 배치 크기는 난수를 변경하므로 하나의 비교 내에서 질문별로 쌍을 이루십시오. 다른 질문이나 다른 엔진으로 측정된 점수를 절대 비교하지 마십시오.
R
…
[번역을 위해 잘림]