cse 🐸
順番のあるデータを覚えて「次に何が来そうか」を予測する、学習用の小さなAIです。 Pythonの練習や、言語モデル(LM)の仕組みを手で触って理解するために作りました。
これはLLMの代わりではありません。 中身が全部見えて、壊して学べることが目的です。
🐸 解剖用の「LMの素体」
理科の授業でカエルを解剖するのは、カエルが一番強いからではなく、体のつくりが一通りそろっていて、しかも見やすいからです。
cse も同じで、言語モデルの**基本の流れ(覚える → 点数 → 確率 → 選ぶ)**を一通り持った、全部開いて見られる小さな体です。
アテンションや勾配降下は持っていません。それは「次に自分で組む部品」として、わざと外してあります(→ HANDBOOK「🐸の先へ」)。
(しかも何度解剖しても Frog() でもう1匹出てきます)
| LMの臓器 | 🐸 CSE では | 大きな LLM では |
|---|---|---|
| 入力を記号にする | 1文字=1記号(Frog なら1要素=1記号) |
トークナイザー |
| 覚える | ヘブ則で結びつきが強くなる | 勾配降下で重みを直す |
| 文脈を持つ | 活性の残り・直前2つの並び | アテンション |
| 予測する | 点数 → softmax / linear で確率に | logits → softmax |
| 抑える | 不応期 | 繰り返しペナルティ |
| 選ぶ | (自分で作る! Top-p など) | サンプラー |
右の列の「本物の臓器」が何のためにあるのかを、左の小さな体で先に触って理解できます。 たとえば 🐸 の文脈は直前2つまでしか見えません。だから大きな LLM は、遠くを見るためにアテンションを持っています。
立ち位置: 数え上げ(n-gram)より動く部分が多く(発火・伝播・減衰・不応期)、LLM より中身が見える。 予測の精度では数え上げに負けることもあります。それも含めて全部見せるのが、この 🐸 の役目です。
いじる設定 ↔ LLM で似ているもの
Frog(設定名=値) で変えて、frog.show(...) で点数と確率の変化を見てみてください。
| 🐸 でいじる設定 | LLM で似ているもの | いじるとどうなる |
|---|---|---|
temperature |
temperature(そのまま同じ!) | 下げると自信満々、上げると迷いがち |
top_k_edges |
Top-k(①の役割) | 2つの役割: ① 確率にする候補を上位 k 個に絞る ② 活性を広げるとき、各記号から強い順に k 本のつながりだけを使う |
refractory_steps |
繰り返しペナルティ | 同じ記号を続けて出さなくなる(🐸 は完全に禁止するので、点数を下げるだけのペナルティより極端) |
pair_context_capacity / pair_context_boost |
コンテキストの長さ | 🐸 は直前2つまで。0 にすると「右右 → 下」が覚えられない |
max_nodes |
語彙サイズ | 覚えられる記号の数 |
learn(..., epochs=) |
学習のステップ数 | 何周くり返して覚えるか |
history_boost |
今の LLM の標準的な設定にはない。近いのはマイナスの presence_penalty(OpenAI の API などで、使った言葉を出やすくする方向)や、昔のキャッシュ言語モデル(最近出た単語の確率を上げる方法) | 少し前に出た記号が出やすくなる(研究では、生成を崩す方向に効いていた: H-GEN-2) |
あくまで「似た働き」です。違い(不応期は禁止、文脈は2つだけ、など)も含めて比べてみてください。
📝 紹介記事(note): 🐸を1匹飼うと、言語モデルの中身が見える ― pip install cse-frog
クイックスタート
インストール(使うときの名前は from cse import Frog):
pip install cse-frog
全機能・全設定の一覧は docs/REFERENCE.md、遊び方・壊し方・改造のしかたは docs/HANDBOOK.md、設定をいじると何が起こるかは docs/CONFIG_GUIDE.md にあります。
from cse import Frog
frog = Frog() # 🐸 を1匹つくる
frog.learn([["右", "右", "下"]] * 10) # 行動の系列を覚えさせる
print(frog.predict(["右", "右"])) # -> 下
print(frog.top(["右"], k=2)) # 確率の高い順に2つ
print(frog.generate(["右"], greedy=True)) # 続きをしゃべらせる -> ['右', '下']
learn()の渡し方は3通り: 文字列1つ"右右下"(1文字=1記号の1本の系列)、リスト1つ["正常", "温度上昇", "停止"](1要素=1記号の1本の系列。「停止」は「停」と「止」に分かれません)、リストのリスト[[...], [...]](何本もの系列)。learn(データ, epochs=20)のように、同じデータを何周くり返して覚えるかも決められます(既定 3)。predict()がcse.END(表示は<END>)を返したら「ここで系列が終わりそう」という意味です。- 覚えていない記号を渡すと、日本語のエラーで教えてくれます。
ノートブックで遊ぶ 🐸
| ノートブック | 中身 |
|---|---|
| 00_hello_frog | 🐸を作る・覚えさせる・中を見る・保存する |
| 01_prediction_knobs | temperature / probability_mode / top_k_edges |
| 02_context_and_inhibition | 並びの記憶 / 不応期 / history_boost |
| 03_memory_and_forgetting | 忘却の2つの罠 / 並びの記憶は忘れない / 遠くを学ぶ |
| 04_break_your_frog | 壊し放題実験場・「何も変わらない」の診断器・自作top-p |
| 05_add_parts | 🐸にしゃべらせる(generate)・生成の1歩を解剖・自作top-p・自作の繰り返しペナルティ |
各ノートブックの先頭に「Open in Colab」ボタンがあります。
正直な限界
- 局所的な予測器です。 既定の設定では、基本的に「今の記号」と「直前2つの並び」から次を予測します。n-gram(数え上げ)に近い性質です。
- 研究(Chain-Spike Engine の検証)では、古典的な評価軸(精度・メモリ・速度・較正など)で、n-gram などの既存手法に対する比較優位は見つかりませんでした。遠くの文脈を使う問題(検索など)は苦手です。
- エンジンは本来文字単位です。
Frogは単語などの記号を内部で1文字に置き換えて、この制約を吸収しています。 - 既定の設定(
refractory_steps=0など)は、素直に予測するための設定です。Frog(refractory_steps=2)のように変えると、元の仕組み(不応期)の挙動を観察できます。
品質について
研究で使ったエンジンと同じ計算結果になることを、開発時にテストで確認しています(そのテストは配布物に含めていません)。
ライセンス
MIT License。Copyright (c) 2026 Emilia Lab / 鍵乃ねこ (kagioneko)。
再配布・公開するときは、LICENSE の著作権表示とライセンス文を含めてください。
🐸 を保存する
frog.save("my_frog.cse") # 覚えたことをファイルに保存
frog = Frog.load("my_frog.cse") # 次の日に読み込んで、続きから学習も予測もできる
- 保存したファイルは JSON と数値の配列だけです(pickle は使わないので、人の 🐸 を読み込んでも安全です)。
- 記号として保存できるのは、文字列・整数・小数・True/False・None です。
- 読み込んだ 🐸 は、保存する前の 🐸 と予測も続きの学習もビット単位で同じになります(テストで確認)。
設定をいじって壊して遊ぶ 🐸
Frog(設定名=値) で、エンジンの設定を1つずつ変えられます。今の設定は frog.config で見られます。知らない設定名を書くと、使える名前の一覧つきでエラーになります。
from cse import Frog
data = [["右", "右", "下"] * 5]
Frog().learn(data).top(["右", "右", "下"]) # 右 0.87 / <END> 0.13 (素直)
Frog(refractory_steps=2).learn(data).top(["右", "右", "下"]) # <END> 1.0 (不応期: 直前に出た「右」を出せない!)
Frog(probability_mode="linear").learn(data).top(["右", "右", "下"]) # 右 0.80 / <END> 0.20 (確率の出し方を変える)
Frog(temperature=2.0).learn(data).top(["右", "右", "下"]) # 右 0.68 / <END> 0.32 (温度を上げると自信が弱まる)
refractory_steps: 直前に出た記号を、しばらく出さない仕組み(不応期)。既定は 0(オフ)。history_boost: 少し前の記号の「残り香」で点数を盛る。既定は 0.0(オフ)。temperature/probability_mode: 点数を確率に変える方法。温度が低いほど、確率が 0 か 1 に張り付きやすい。pair_context_capacity/pair_context_boost: 直前2つの並びを覚える量と、その使い方の強さ。0 にすると「右右 → 下」が覚えにくくなる。max_nodes: 覚えられる記号の数の上限(+3)。
安心して使うために
Frog()を作っても、あなたのプログラムの乱数(random/numpy.random)の状態は変わりません。- 同じ
Frogを複数のスレッドから同時に使っても、予測は壊れません(学習と予測は1つずつ順番に処理されます)。 - 覚えられる記号の数には上限があります(
max_nodes − 3個。既定 253 個)。こえるとエラーで知らせます。Frog(max_nodes=1000)のように増やせますが、メモリはmax_nodesの2乗で増えます。
中身をのぞく(中級〜上級)🔍
大きなLLMではできない、「どこで・なぜその予測をしたか」を数字で見られます。
from cse import Frog
frog = Frog(refractory_steps=2).learn([["右", "右", "下"] * 5])
frog.show(["右", "右", "下"])
# 🐸 ['右', '右', '下'] の次の候補
# 候補 直接 履歴 並び 痕跡 合計点 確率
# <END> 0.298 0.000 0.200 0.000 0.498 1.000
# 右 1.186 0.000 0.800 0.000 0.000 0.000 ← 不応期で消された
frog.explain(prefix, k=5): 候補ごとの点数の内訳(直接のつながり・履歴・直前2つの並び・文脈の痕跡)と確率。内訳の合計がエンジンの点数とぴったり一致することを、毎回確認しています。frog.scores(prefix): 確率に変える前の生の点数。これを使って Top-p や Top-k のサンプラーを自分で作れます。frog.edges("右"): その記号から出ている「直接のつながり」と強さ(何を覚えたか)。
例: Top-p サンプラーを自分で作る
import random
def top_p(frog, prefix, p=0.9):
items = sorted(frog.probabilities(prefix).items(), key=lambda kv: -kv[1])
keep, total = [], 0.0
for tok, prob in items:
keep.append((tok, prob)); total += prob
if total >= p:
break
tokens, weights = zip(*keep)
return random.choices(tokens, weights=weights)[0]
応援する 🐸
cse は Emilia Lab / 鍵乃ねこ が個人で研究・開発しています。気に入ったら GitHub Sponsors で応援してもらえると、🐸の研究と教材づくりの続きに使わせていただきます。
Metadata
Release files for cse-frog 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cse_frog-0.2.0.tar.gz | 28.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cse_frog-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 49.5 kB
Release files / cse_frog-0.2.0.tar.gz
| Download URL | cse_frog-0.2.0.tar.gz |
|---|---|
| Size | 28.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
91fd48ab9d126d209cde79d4cb796b68a418a836896e5575e68c6df8840c994d
|
|
BLAKE2b-256 checksum How to use checksums |
d0e7606b1f423a66fc131a08a922c1904ad3f541b5f9560fd47544834ecebce2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|
Release files / cse_frog-0.2.0-py3-none-any.whl
| Download URL | cse_frog-0.2.0-py3-none-any.whl |
|---|---|
| Size | 21.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
402389b1e60b84bafb50958c28bc20ec0c9390d9cf7047dd4f1446735381a383
|
|
BLAKE2b-256 checksum How to use checksums |
66f94581ccea26d85257889111e351dce5673b403776f7b685ed4311acc4bc94
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|