重み空間プログラミング
小さなオープンモデルの重みを直接編集することで、最適化器を使わずに目標を改善します。これは「Sparks of Weight-Space Programming」(Takehi, Teoh, Zhang, Khattab, MIT CSAIL, 2026年11月2日)の実験8に従っています。Qwen3.5-0.8Bの思考ループは、レイヤー15と19のMLPによって書き込まれた1つの残差方向に起因し、各レイヤーの64個のdown_projカラムに対するランク1編集により、MATH-500スコアが7.9%から48.1%に向上しました。
以下の高速パスを順番に実行してください。 すべてのスクリプトはscripts/にバンドルされ、テスト済みです。ステップが失敗しない限り、パイプラインを再設計したり、新しいツールを作成したりしないでください。
このスキルが保証すること、そしてできないこと。 どの方法も編集が必ず役立つとは約束できません。一部のモデルには、オフにできる単一の習慣がありません。スキルは代わりにプロセスを保証します。
- 作業の損失なし:クラッシュ時はより小さいバッチで再開します。
- 測定済みのプラクティスチェックに合格するまで、編集はホールドアウトテストに到達しません。
- チェック失敗時は、停止する代わりに固定されたステップでエスカレーションします。
- すべての実行は明確な判定と数値で終了し、何も機能しなかった場合はコピーが復元されます。
参考資料(詳細のみ):
references/goals.md:他の目標、マッチングペアの書き方、評価器、レシピ。references/engines.md:各OSとGPUのエンジン、インストール、サイジング、落とし穴、スモークテスト。references/evaluation.md:分割、サンプリングプロトコル、MMLU-Proの詳細、ペア統計、レポートテンプレート。references/method.md:各ステップの数学と著者の正確なレシピ。
高速パス
4つのプレースホルダーを一度設定します(PowerShell:$env:SKILL = "..."、次に$env:SKILL):
SKILL=<このスキルのフォルダ> BASE=<ベースモデルフォルダ> COPY=<ベースモデルフォルダ>-<目標> WORK=<結果フォルダ>
すべての生成ジョブをバックグラウンドで実行し(Claude Code:Bashツールのrun_in_background、シェルの&ではありません)、ポーリングではなく完了通知を待ちます。生成が時間を支配するので、事前にユーザーに予算を伝えてください:コンシューマGPUでプリセットの場合1.5〜3時間、データセンターGPUでvLLMを使用する場合はもっと短くなります。
0. 必要なことだけを尋ねる(1つの質問)。目標を尋ねます。数学または科学の場合はプリセットを使用します:これ以上の質問は不要です。それ以外の場合は、以下も尋ねるか、作成を支援します。
- 失敗を示すプロンプト(
{"id", "prompt", "answer"?, "group"?}JSON Lines形式)。 - それらをスコアリングする方法(
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テスト.jsonl> --practice 25 --heldout 75。 - 独自の目標: プロンプトファイルを固定ルールで
practice.jsonlとheldout.jsonlに分割し、さらに約30個のホールドアウトIDを含むtest_ids.txtを作成します。これらはすべて、回答が確認される前に選択されます。
以下、Tはタスク(mmlu、math、またはjsonl)、Gは評価器オプション(プリセットの場合はなし。それ以外はreferences/goals.mdを参照)です。
4. 2つのベース実行を同時に開始する:
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
Go/No-go。 改善の余地を見積もります:振る舞いを示す回答の割合×振る舞いを示さない回答のスコア。約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の低下がその3分の1未満のもののみを保持します。ランダムコントロールは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、ランク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
ゲート通過は以下の3つすべてが成立する場合のみ:
- 修正数 ≥ max(3, チェックされたベース失敗の20%)、
- 破損数 ≤ 修正数 ÷ 4、
- そして、ループ目標の場合、カット割合が少なくとも4分の1減少する。
合格:ステップ10へ。失敗:ステップ9へ。
9. 次の順序でエスカレーションします。各段階は1回の追加プラクティスチェックです。
- 次にランク付けされた候補。 コピーを復元し(
copy_model.py --base $BASE --copy $COPY --restore)、それを適用し、ステップ7〜8を繰り返します。これを最大2つの追加候補に対して行います。 - ラウンド2。振る舞いが消えたのではなく移動した場合。 例えば、思考が閉じるようになったが、
responseの後にループが再開する、またはコピーの回答に新しい不要なパターンが現れる場合など。編集済みコピーを新しいベースとして扱います:copy_model.py --base $COPY --copy $COPY2でCOPY2を作成します。probe.py collect(またはcollect-pairs)を--model $COPY --runs $WORK/practice/copy.jsonlで実行します。--model $COPYで構築およびスクリーニングします。--base $COPY --copy $COPY2で適用します。- ステップ8と同様に
COPY2をチェックします。
- 停止。 3回のチェック後(またはユーザーが設定した時間予算後)、信頼できる改善なし。コピーを復元し、「信頼できる改善なし」という判定を各候補の数値と共に報告します。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のテンプレートを使用して報告する:
- ホールドアウトスコアの前後、およびペアの修正/破損カウント。
- 振る舞い率(カット、フラグ付き、思考クローズ)。
- 各候補とそのスクリーンおよびチェック数、およびランダムコントロール。
- 変更された重み。
- 注意点:習慣をオフにすることは新しい能力ではないこと。
以前に時間を浪費した間違い(繰り返さないこと)
- バッチが大きすぎる、または2つの長時間ジョブがピーク時に重なる。 メモリ不足クラッシュは進行中の回答を破棄します。ループはこれにあたります。
--batch auto --jobs 2を使用し、最初の32kジョブが最長の回答中にあるときに2つ目の32kジョブを開始しないでください。スーパーバイザーはクラッシュした実行を半分のバッチで再開します。 - 実行全体を待つ。 約15ループで十分です。
- 評価のためのインメモリ編集。
probe.py screenのみがインメモリで編集を適用し、それも教師強制読み取りのみです。 - スクリーンだけを信頼する。 ループでのスクリーン低下-0.10は、生成中に26ループ中3つしか破損しませんでした。そのため、常にゲートを実行してください。
- 部分的な実行を評価する、または先に終了したものからテスト問題を選択する。
pkill -f <text>でジョブを停止する。 これはコマンドラインにそのテキストを含むウォッチャーも停止します。
ルール(投稿通り)
これらを守り、報告書で守ったことを述べてください。
- トレーニングなし。 逆方向パス、autograd、最適化器、または損失に対する重みの反復フィッティングは禁止。指標が向上するまでαまたは重みを微調整することはフィッティングとみなされます。上記の固定候補リストから選択することはフィッティングではありません。
- 測定のためのフォワードパスは許可: 生成、教師強制ログ確率、隠れ状態とMLP活性化、およびそれらの統計量、または重みの統計量(平均、差分、SVD)。
- 範囲外:
- 埋め込み、(タイド)出力ヘッドおよび最終ノルム(
weights.pyが拒否)。 - テンソル全体を定数で乗算すること。
- グローバルなシャープ化または平坦化。
- 問題に関係なく思考を早期に強制終了すること。
- 安全動作の除去:拒否、セーフガード、有害リクエストへの準拠。
- 埋め込み、(タイド)出力ヘッドおよび最終ノルム(
- 重みの値のみ変更。 名前、形状、dtype、設定、トークナイザー、チャットテンプレート、デコード設定は保持します。
- 分割規律。 編集前に固定された、重複しないプラクティスセットとホールドアウトセット。ホールドアウト結果は、編集が確定した後に一度だけ確認します。
- 開示された選択。 報告書は試行されたすべての候補と、勝者を選択した指標をリストします。
各ステップがその理由
- コントラスト: 方向は、各レイヤーの出力において、それ以外はマッチングされた不要テキストと必要テキストの平均差です。
- ループの場合、
loops.pyはループ発症の直前の1,024トークンとループ内部の1,024トークンを取得します:同じ質問、同じ回答、ほぼ同じ位置。発症点は、次の512トークンの90%が以前の16-gramを繰り返す最初の点です。 - 他の振る舞いの場合、ペアがマッチングを提供します。
- ループの場合、
- ライターカラム: score_j = (平均不要 − 平均必要活性化 of neuron 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シャードのみを書き換えます。推論エンジンはロード時にテンソルを書き換えたりドロップしたりするため、エンジンから重みを保存しないでください。 - プロトコル: thinking on, temperature 0.6, top_p 0.95, top_k 20, presence penalty 1.5(生成トークンのみ)、32,768 new tokens(
--profile thinking)。すべてのエンジンがvLLMのセマンティクスに一致します。 - ペアリング: エンジンとバッチサイズは乱数を変更するため、1つの比較内で質問ごとにペアにします。異なる質問や異なるエンジンで測定されたスコアを比較しないでください。
R
…
[翻訳のため省略]