miutti's picture
Source: kernel, desktop app, tools (snapshot of the GitHub repo)
df41178 verified
Raw History Blame Contribute Delete
3.62 kB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
bake.py -- 抜いた表を「焼く」
巨大な表(2.35GB, 7168次元)から必要な語だけ取り出し、
次元を落として小さな表にする。以後は掛け算がほぼゼロになる。
・次元削減はランダム射影(決定的な種を使う)。
Johnson–Lindenstrauss の定理より、内積・角度はおおむね保たれる。
・「1トークンで引ける語」だけを焼く。分割される語は表が壊れるため除外し、
その事実を印として残す(呼び出し側が別の手段に切り替えられるように)
"""
import os, json, math, random, time, sys
from embed_cards import EmbedCards
HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, "baked_cards.json")
def projection(dim_in, dim_out, seed=20260823):
"""決定的なランダム射影行列。列ごとに生成してメモリを節約"""
rng = random.Random(seed)
s = 1.0 / math.sqrt(dim_out)
return [[rng.gauss(0, 1) * s for _ in range(dim_in)] for _ in range(dim_out)]
def bake(words, tag="Kimi-K2-Instruct", dim_out=256, verbose=True):
e = EmbedCards(tag=tag)
P = projection(e.dim, dim_out)
baked, skipped = {}, []
t0 = time.time()
for w in words:
ids = e.encode(w)
if len(ids) != 1: # 1トークンで引けない語は焼かない
skipped.append((w, len(ids)))
continue
v = e.row(ids[0])
small = [sum(p[i] * v[i] for i in range(e.dim)) for p in P]
n = math.sqrt(sum(x * x for x in small)) or 1.0
baked[w] = [round(x / n, 5) for x in small] # 正規化して丸める
if verbose:
print(f" 焼けた: {len(baked)} 語 / 除外: {len(skipped)} 語 "
f"({time.time()-t0:.1f}秒)")
return baked, skipped
class Baked:
"""焼いた表。読み込みは一瞬、比較は256次元だけ"""
def __init__(self, path=OUT):
d = json.load(open(path, encoding="utf-8"))
self.v = d["vecs"]; self.meta = d["meta"]
def has(self, w): return w in self.v
def similarity(self, a, b):
va, vb = self.v.get(a), self.v.get(b)
if not va or not vb: return None # 引けない=別の手段へ
return sum(x * y for x, y in zip(va, vb)) # すでに正規化済み
def nearest(self, w, candidates):
va = self.v.get(w)
if not va: return None, 0.0
best, sc = None, -2.0
for c in candidates:
vb = self.v.get(c)
if not vb: continue
s = sum(x * y for x, y in zip(va, vb))
if s > sc: best, sc = c, s
return best, sc
if __name__ == "__main__":
import kernel
# 焼く対象=エンジンが知っている語+概念の値+動作でよく使う語
words = set(kernel.SEED.keys())
for slot, vals in kernel.vocab_table().items():
words.update(vals)
words.update(["猫","犬","石","川","橋","箸","写真","画像","動画","音楽",
"移動","削除","整理","複製","検索","一覧","合計","重複",
"書類","資料","保存","作成","変更","確認"])
words = sorted(w for w in words if w)
print(f"■ 焼く語: {len(words)} 語")
baked, skipped = bake(words)
json.dump({"meta": {"source": "Kimi-K2-Instruct", "dim": 256,
"skipped": skipped}, "vecs": baked},
open(OUT, "w", encoding="utf-8"), ensure_ascii=False)
print(f" → {OUT} ({os.path.getsize(OUT)/1e6:.1f} MB)")