baya1116's picture
Super-squash branch 'main' using huggingface_hub
b5989f0
|
Raw
History Blame Contribute Delete
11 kB

RECALL_SPEC — ゲート式リコール生成 仕様書 (RECALL_V1, 2026-06-14)

SP 圧縮(露出窓 rw の外を pooler で gist 化)された無限ターン文脈において、CoT/生成の 各位置で「窓の外へ落ちた事実が今いるか」を検知(GATE)し、必要なら正しい evicted ブロックを 想起(RETRIEVE)して逐語再注入する機構の仕様・学習法・検証結果・成果物をまとめる。 COTSCAN_SPEC.md / APP_SPEC_ADDENDUM.md(hypernet_sp/)の後継・実装確定版。

ベース: deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B(FFT 版 = fft_hf)+ SP pooler(AttnPoolSP)。


1. 機構(3部品)

部品 役割 入力 出力
RecallGate いつ引くか 現在位置の pre-RoPE クエリ(層8/14/20, 4608次元) 発火スコア(>閾値で発火)
Retriever どれを引くか 同クエリ + evicted ブロック表現 top-k ブロック
RecallRuntime 配線 モデル+pooler+上記 prepare(seq)→特徴 / decide(ctx,p)→発火&想起

Retriever は 3 系統:

  • QKIndexer(学習): モデル自身の QK 空間。各ブロックの pre-RoPE キー要約(~3KB/block)が要る。
  • BGERetriever(学習・状態レス): 保持は token ids のみ。発火時に候補ブロックを BGE で逐次 エンコードし、固定の小ヘッド(~数十万パラ)で隠れクエリと橋渡し。無限ターンでも増えるのは ids だけ。
  • raw-QK(学習なし、block_recall.BlockArchive): モデルの QK 内積で逐語ブロックをスコア。

2. 学習方法(本体 SFT なし)

データ: 実 Dolphin-R1 の長 CoT(≥1000 トークン)。長考なので CoT 前半が窓外へ自然にスクロール アウトし、「引き戻しが必要な瞬間」が大量に生じる(レアイベントを母数で稼ぐ)。

ラベル(教師=実アテンション): フルKV で各窓位置のアテンションを測り、**窓(512)より前の evicted 領域へ集中して飛んだ位置=引き戻し位置(正例)**、飛んだ先のブロック=gold。 層8/14/20・ヘッド和・BOSシンク除外・行正規化。

特徴: 同位置の SP 圧縮レイアウト [BOS][SP(evicted)][窓512] での pre-RoPE クエリ(本番で 実際に得られる隠れ表現)。

学習: GATE=ロジスティック回帰(4608次元)。Indexer=DSA lightning-indexer 型(~20万パラ)を KL でアテンション分布に一致させる。BGEヘッド=隠れクエリ↔BGE埋め込みの小MLP。 item 分離 heldout で評価。

注: 学習部品(Indexer/Gate)は Dolphin ドメインに in-domain。別ドメイン(例 GSM8K の 質問位置クエリ)には分布外で、その場合は学習なし raw-QK の方が転移する。


3. 検証結果

3.1 検知・想起の汎化(実 Dolphin・item分離 heldout, 正例 ~3,951)

  • GATE 検知 AUC = 0.9584
  • 想起 top-2:学習QK 0.9995(raw-QK 0.807)/ 学習BGEヘッド 0.9997(raw-BGE cosine 0.286)
  • → 「BGE に学習変換をかませば壁(~0.8)を破れる」= 実証。状態レス(ids のみ)構成が QK保存版と同等

3.2 単体テスト(recall_kit ロード→fixtures、全 PASS)

gate 分離 AUC 0.94 / QK top-2 1.000 / BGEヘッド top-2 1.000 / BGE encode OK。

3.3 複合テスト(配線 end-to-end、未見held 46問・2117位置)

  • 想起@真の引き戻し:QK 0.999 / BGE 0.979
  • end-to-end(発火して正しいブロック):QK 1.0 / BGE 0.969
  • GATE: precision 0.75 / recall 0.48(出荷閾値=TPR優先。下げれば recall↑、best-F1点で R 0.79)

3.4 SP ランタイム自体のタスク影響(GSM8K, filler なし, 同採点)

条件 正答率 補足
full-KV(無圧縮) 66.7% 基準
SP @ rw=1024 66.7% CoT が窓に収まり圧縮 0 → full-KV と同一
SP @ rw=512 60.0% 19/30 が実圧縮 → SP圧縮の実コスト ~7pt

SP 圧縮は優秀(rw=1024 で無損失、rw=512 でも-7pt)。GSM8K 規模では recall を持ち出すまでもない。

3.5 圧縮が効く長尺(Dolphin 長CoT, CoT>rw, n=5)

arm 正答率
FULL 3/5 (60%)
SP@rw1024 2/5 (40%)
SP_RECALL 2/5 (40%)
  • 長尺では **圧縮が実コスト(60→40)**。recall は n=5 で差し引きゼロ(1救済・1破壊)。
  • trace で「ちゃんと引けている」ことを確認:発火は毎回「元問題を読み直そうとした瞬間」に起き、 窓外へ落ちた元の問題文を正確に引き戻していた(例: "check the original problem again"→発火 score 13.04→two-trains 問題を想起→\boxed{440/9} 正解)。
  • 正答率が動きにくいのは引きの失敗ではなく 1.5B の解答力がボトルネック(難問は手元にあっても 解けない)。

4. 成果物(HF baya1116/hypernet-sp-distill)

recall_runtime/(3.87GB・自己完結バンドル, これ一式で即動く)

fft_hf/                ベースLLM(HF形式, from_pretrained 可)
pooler.pt              SP pooler
components/            gate.npz / indexer.npz / bge_head.npz(学習済み重み)
recall_kit/            RecallGate / QKIndexer / BGERetriever / RecallRuntime
deps/                  attn_export3_torch(pooler loader)/ block_recall / attn_scenarios
README.md              ロード&実行例

検証ログ・各実験結果: trigger_experiment/(results_dolphin* / recall_kit_v4 / results_gsm_* 等)。 コード: GitHub bayamax/dual-masked-bert-jp ブランチ claude/hypernet-sp-spec-review-qrafn9

ロード例

import torch, sys; sys.path += ["deps", "."]
from transformers import AutoModelForCausalLM, AutoTokenizer
from attn_export3_torch import load_pooler
from recall_kit import RecallGate, QKIndexer, RecallRuntime
tok = AutoTokenizer.from_pretrained("fft_hf")
llm = AutoModelForCausalLM.from_pretrained("fft_hf", torch_dtype=torch.float32).eval().cuda()
pooler = load_pooler("pooler.pt").cuda().eval()
dims = (llm.config.num_attention_heads, llm.config.num_key_value_heads,
        llm.config.hidden_size // llm.config.num_attention_heads)
gate = RecallGate.load("components/gate.npz")
qk   = QKIndexer.load("components/indexer.npz", dims, device="cuda")
rt = RecallRuntime(llm, tok, pooler, gate, qk=qk, device="cuda")
ctx = rt.prepare(seq_ids)
for p in range(ctx.win_len):
    d = rt.decide(ctx, p, backend="qk")     # gate → (発火時のみ) 想起
    if d["fired"]:
        inject(ctx.block_ids[d["blocks"][0]])

5. 知見・限界

  1. SP圧縮は強い: rw=1024 では full-KV と無差。recall の真価は「CoT/会話が rw を大きく超える長尺」。
  2. recall は正しい中身を正しい瞬間に引ける(質的に実証)。最終正答への寄与はモデルの解答力次第で、 短サンプル×難問では見えにくい。
  3. 早期注入(ターン頭)> mid-CoT 発火(解くだけなら早い方が良い)。ゲートの価値は「無駄打ち削減」。
  4. filler で人工的に窓外へ追い出す評価は不適切(窓が filler で埋まり評価を歪める)。自然な長尺で測る。
  5. ドメイン外注意: 学習 Indexer/Gate は Dolphin in-domain。別分布では raw-QK 等の学習なし手法が転移しやすい。

6. 残課題

  • 1.5B でも解ける難度の長尺問題で母数を増やし、recall のタスク寄与を有意に測る。
  • 発火時の巻き戻し(rewind)・閾値の運用最適化(recall↑)、MLPゲート(AUC 0.950→0.961)の採用。
  • 再注入フォーマットの改善(逐語ブロック→問題文の完全復元等)で長尺の圧縮損失(60→40)を埋める。
  • RecallRuntime の本番 / MLX 移植(HANDOFF_PORTING.md のパリティ手順)。

7. 全成果物の所在(ありか)一覧

HF リポジトリ: baya1116/hypernet-sp-distill(URL は https://huggingface.co/baya1116/hypernet-sp-distill/tree/main/<path>) git: bayamax/dual-masked-bert-jp ブランチ claude/hypernet-sp-spec-review-qrafn9

7.1 モデル一式(これ一式で即動く)

所在
完全バンドル HF recall_runtime/
ベースLLM(HF形式) HF recall_runtime/fft_hf/
SP pooler HF recall_runtime/pooler.pt
検知ゲート / QK想起 / BGE想起 重み HF recall_runtime/components/{gate.npz, indexer.npz, bge_head.npz}
パッケージ HF recall_runtime/recall_kit/
依存 HF recall_runtime/deps/
本書 HF recall_runtime/RECALL_SPEC.md

7.2 学習済み重みの原本+テスト

所在
gate / indexer / bge_head + 単体・複合レポート + fixtures HF trigger_experiment/recall_kit_v4/artifacts/
パッケージ src(同上の出所) HF trigger_experiment/recall_kit_v4/src/
ベース重み(原本) HF fft_out/student.pt(3.55GB), fft_out/pooler.pt(302MB)

7.3 検証結果(主要)

検証 所在
検知AUC 0.958 + 学習QK top-2 0.9995(Dolphin heldout) HF trigger_experiment/results_dolphin/
BGE比較(raw 0.286 → 学習 0.9997) HF trigger_experiment/results_dolphin_bge/
探索(ゲート動作点 / MLP 0.961 / 後方スキャン) HF trigger_experiment/results_explore/
full-KV 66.7% HF trigger_experiment/results_gsm_fullkv/
SP@rw512 60% / SP@rw1024 66.7% HF trigger_experiment/results_gsm_sp512/, results_gsm_sp1024b/
長尺 FULL/SP/SP_RECALL(60/40/40) HF trigger_experiment/results_dolphin_solveB/
引き戻しの中身(trace) HF trigger_experiment/results_dolphin_trace/
新ゲート×raw-QK の GSM8K(OFF0/TURN31/GATE17) HF trigger_experiment/results_gsm_gate/
初期GSM8K知見(素朴per-positionは有害) HF trigger_experiment/results_gsm8k_v1..v4/(git: cotscan_live/results_gsm8k_v*.json)

補助・中間ラン(results_gsm_new*, results_gsm_rw1024, results_cotscan_live* 等)も 同 trigger_experiment/ 配下に残置(filler 等のアーティファクト確認用)。

7.4 コード(git ブランチ)

所在(git)
パッケージ + 本書 recall_kit/(gate.py / retriever.py / runtime.py / init.py / README.md / RECALL_SPEC.md)
実験スクリプト一式 cotscan_live/(dolphin_scan.py 学習 / build_package.py / composite_test.py / explore.py / gsm8k_sp.py / gsm8k_fullkv.py / cotscan_gsm8k.py / dolphin_solve.py 等)+ 各 boot_*.sh + 結果 JSON

7.5 元仕様・前提(本書の出発点)

所在
COTSCAN / Addendum 仕様 HF hypernet_sp/COTSCAN_SPEC.md, hypernet_sp/APP_SPEC_ADDENDUM.md
Phase B 想起インデクサ(既存) HF hypernet_sp/phaseb/phaseb_indexer.npz ほか
COTSCAN 実験コード(自然CoT等) git ブランチ claude/huggingface-model-status-ypclnutrigger_experiment/(cot_recall_natural.py 等)+ RESULTS.md