evex-3.5
ある Discord サーバーの過去ログを主材料に、tokenizer からゼロで作った 18.9M パラメータの言語モデル。事前学習済みの重みは1つも使っていない。
evex-3(15.74M)から変えたのは 2 つだけ:
- 語彙を 4096 → 12288 にした
- 公開のなりきり掲示板で会話の土台を作ってから、このサーバーのログで仕上げた
同じ系統の兄弟 — evex-1 / evex-2(5.87M)/ evex-3(15.74M)。
⚠ 147人の話者が重みに入っている
<|s0|> から <|s146|> は実在の人ひとりひとりに対応する。
つまりこのモデルは特定の人になりきって書ける。
- 出力をその人が書いたものとして扱ってはいけない
- 学習データは同意を明示的に取っていない会話。ログそのものと Discord の
user ID・表示名は公開していない(
speakers.jsonは順位と発言数だけ) - 外部データには話者トークンを一切使っていない。
<|sN|>が指すのは このサーバーの人だけで、なりきり掲示板の投稿者ではない
二段で学習している
| データ | 目的 | |
|---|---|---|
| 段1 | 公開のなりきり掲示板 78% + このサーバー 22% | 会話の交代・話の受け方 |
| 段2 | このサーバーだけ | 口調と 147 人 |
混合比だけで「このサーバーらしさ」を守ろうとすると、外部が数倍あるぶん永久に 薄まる。最後がこのサーバーなら分布は戻り、土台の恩恵だけ取れる。
外部データには相対の役 <|a|>..<|h|> しか使わない。
「会話とはこう進むもの」だけを外から教え、誰が誰かはこのサーバーだけが持つ。
二段は効いたのか(対照を回して確かめた)
同じコーパス・同じ語彙で、段2 をゼロからも回した。
| 段2 | val (epoch 1) | val (epoch 3) | 噛み合い |
|---|---|---|---|
| 段1 から | 5.0638 | 4.9405 | 38.3% |
| ゼロから(対照) | 5.6111 | 5.1017 | 30.0% |
段1 からの方が全 epoch で上。しかも段1 からの epoch 1 が対照の epoch 3 より 良いので、土台があると 3 分の 1 の学習で追い越せる。
効果(実測 / n=150)
このモデル自身の val を同じ尺度で測った値を地の値として並べる。
匿名の役 <|b|>(bot の既定経路)
| evex-3 | evex-3.5 | 地の値 | |
|---|---|---|---|
| 噛み合い(質問の語が返答に出る) | 37.3% | 45.3% | — |
| 20字以上で返す | 55.3% | 60.0% | 31.2% |
| 平均の長さ | 30字 | 32字 | 19字 |
| 未知語 | 9.9% | 10.0% | 14.9% |
| 逐語コピー(20字以上の完全一致) | 0.0% | 0.0% | — |
名前持ち <|s0|>(なりきり)
| evex-3 | evex-3.5 | |
|---|---|---|
| 噛み合い | 24.0% | 34.0% |
| 20字以上 | 64.7% | 48.7% |
| 平均の長さ | 41字 | 29字 |
両方の経路で噛み合いが大きく伸びた(+8pt / +10pt)。なりきり時は短くなったが、 噛み合いが 24% → 34% なので、中身の薄い長文が減って的を射た短文になった形。
なりきり掲示板の口調は漏れていない。地の文((微笑み のような括弧)を
含む返答は 0.7% で、このサーバー自身の val(0.9%)を下回る。
元データは本文の 74% が地の文だったが、ビルド時に落としてある。
逐語コピーの数え方について
20字以上の完全一致だけを数える。閾値なしで測ると あ(学習に1877回)
それはそ(114回)のような誰でも言う相槌が「丸写し」として数えられ、
なりきりが 25.3% と出る。中身を見ると 14 件すべてが 10 字以下で、
21字以上の一致は 0 件だった。短い相槌を返しやすい経路ほど高く出るだけの
指標になっていたので、下限を入れている。
数字
| パラメータ | 18,880,896(埋め込み 4.72M + 8層 14.2M) |
| 形 | d_model 384 / 8層 / 6 head / context 1024 / RoPE + RMSNorm + SwiGLU + weight tying |
| 語彙 | 12,288(ログから作った sentencepiece BPE) |
| 学習 | 段1 3 epoch (lr 1e-3) → 段2 6 epoch (lr 3e-4 → 1.5e-4) |
| val loss | 4.9299(記号を外した尺度)/ 素の val 5.0206 |
| ハードウェア | HF Jobs t4-small / 55,493 tok/s / 約60分 |
val は evex-3(4.0741)と比べられない。語彙が 3 倍になると 1 トークンあたりの 情報量が増えて loss は上がる。比べられるのは同じ語彙で回した対照との間だけ。
語彙 12288 を選んだ理由
| 語彙 | 日本語 | 英字 | 英字トークン | docker compose up -d |
|---|---|---|---|---|
| 4096(evex-3) | 1.56字 | 1.94字 | 641 | 11 tok |
| 12288 | 2.06字 | 2.62字 | 3,058 | 7 tok |
| 16384 | 2.21字 | 3.08字 | 4,218 | 7 tok |
evex-3 は「100回以上出る語 9,342 に対しマージ枠 3,670」で、英字は 2,663 語に対し
トークン 641 しかなかった。出力に出ていた Cloberlop PHTHPAPAPA は、
この断片を組み立て損ねた形。
他の設定は全部いまの値が最善だった(総トークン数で比較): coverage 0.9995 は +0.8%、coverage 1.0 は +5.8%、split_digits は +2.3%、 unigram は +1.4% で、いずれも悪化。珍しい文字に3トークン払う方が、 頻出語のマージ枠を失うより安い。
コーパス
| 段1 | 23,267,670 トークン(外部 78%) |
| 段2 | 19,280,662 トークン(このサーバーだけ) |
| 話者 | 147人(200件以上 / 発言の 96.6%)+ 相対の役 8 + 溢れ 1 |
外部は OmniAICreator/Japanese-Roleplay-Dialogues(Apache-2.0)。 なりきりチャット掲示板 4,324 スレッド / 606,492 投稿。 中の人の連絡(OOC)と地の文を落とし、露骨な表現を含む投稿を除いてある。
日本語の Discord データは公開されていない。discord を名前に含む 116 の
データセットに language: ja は 0 件で、92GB の多言語ダンプ 2,863 ギルドを
抽出調査しても日本語が 5% を超えるものは 0 件だった。
使い方
transformers では動かない。素の PyTorch で読む。
import json, torch, sentencepiece as spm
from safetensors.torch import load_file
from huggingface_hub import snapshot_download
path = snapshot_download("tako080614/evex-3.5")
cfg = json.load(open(f"{path}/config.json"))
sp = spm.SentencePieceProcessor(model_file=f"{path}/tok.model")
state = load_file(f"{path}/model.safetensors")
state["head.weight"] = state["embed.weight"] # tie_word_embeddings
# model.py は https://github.com/tako0614/sakana の scripts/llm/model.py
from model import Config, MicroLM
model = MicroLM(Config(**{k: cfg[k] for k in
["vocab_size", "n_layers", "d_model", "n_heads", "context", "dropout", "attn_dropout"]}))
model.load_state_dict(state)
model.eval()
prompt = "<|conv|><|a|>これバグってる?<|s0|>"
ids = torch.tensor([sp.encode(prompt, out_type=int)])
out = model.generate(ids, max_new_tokens=80, temperature=0.9, top_k=40,
stop_id=sp.piece_to_id("<|end|>"))
print(sp.decode(out[0].tolist())[len(prompt):])
プロンプトの形
<|conv|><|s0|>これバグってる?<|s3|><|re|><|s0|>どこで止まってる?<|s0|>
↑147人の誰か ↑別の人 ↑<|s0|> への返信 ↑ここの続きを書かせる
- 話者は
<|s0|>..<|s146|>(固有)と<|a|>..<|h|>/<|z|>(会話ごとの相対) - 名前を持たない人だけに相対の役を振る。混ぜ方を学習と変えてはいけない
- 返信は
<|re|>のあとに相手のトークンを置く。読む側は<|re|>と続く話者トークンを落としてから本文を取ること — 相手のトークンを「次の話者」と読むと本文が丸ごと落ちる <|end|>で会話が終わる。<url><file><mention><channel><time>は 正規化が作った記号で、損失から外してあるので自分では書かない
できること / できないこと
できる: このサーバーの口調、147人の読み分け、会話の交代、話を受けて返すこと
できない: 事実、計算、翻訳、指示に従うこと
18.9M しか無いので内容は当てにならない。狙えるのは「話を受けて、それらしい形で、 このサーバーの口調で返す」まで。
ライセンス
重みは MIT。学習データのうち外部ぶんは Japanese-Roleplay-Dialogues(Apache-2.0)、 残りは非公開の私的な会話。上の「147人の話者が重みに入っている」を必ず読むこと。
- Downloads last month
- 122