evex-ft-3
Qwen3-0.6B (instruct) に、ある Discord サーバーの過去ログを追加学習したもの。
evex-ft-2 と
同じコーパス・同じ設定で、
変えたのは
--base を base 版から
instruct 版にした 1 点だけ。
ゼロから学習した兄弟もある —
evex-1 /
evex-2(5.87M / tokenizer もログから作った)。
⚠️ 表示名が重みに入っている
話者ラベルが実在の人の表示名そのもの(あかり: にょ: たこ:)。
つまりこのモデルは特定の人になりきって書ける。
- 出力をその人が書いたものとして扱ってはいけない
- 学習データは同意を明示的に取っていない会話。ログそのものと Discord の
user ID は公開していない
- 使える 147 個のラベルは
speakers.json にある(表示名と発言数だけ)
- このモデルは逐語コピーが 13.3% ある(下記)。ft-2 の 0% より高い
なぜ instruct 版に乗せたか
ft-2 の不満は「間違っている」ではなく**「文の体をなしていない」**だった。実際に
Discord で返っていたもの:
Q: 日本の首都どこ A: zeta-aiはお前らのアカウントからのメッセージしか見れない定期
Q: t3traって誰? A: 見てたら知らなかったw
Q: ユニバ行きたい A: 拡張機能から削除しとくか
受け入れ基準は「大阪市なら間違っていても構わない」。つまり欲しいのは知識ではなく
答えの形にする性質で、それを持っているのは instruct 版だけ
(instruct 素の実測: 首都 → 大阪市 / 17×23 → 400。中身は外すが形にはなっている)。
base 版を選んでいた元の理由は「instruct の『承知しました』が上書きしきれない」
だった。それが今回は欲しいものになった。
効果と代償(実測)
同じプロンプト・同じ乱数で、このサーバー自身の val を同じ尺度で測った値を地の値
として並べる。
匿名の役 B:(n=50)
| ft-1 | ft-2 | ft-3 | 地の値 |
|---|
| 噛み合い(質問の語が返答に出る) | 20% | 34% | 30% | — |
| 平均の長さ | 32字 | 49字 | 36字 | 17字 |
| 敬体で終わる | 5% | 0% | 0% | 3% |
| 未知語 | 14.3% | 13.8% | 8.6% | 14.8% |
| 逐語コピー | — | 0% | 2.0% | — |
名前持ち あかり:(n=30)
| ft-1 | ft-2 | ft-3 |
|---|
| 噛み合い | 55% | 55% | 33% |
| 逐語コピー | — | 0% | 13.3% |
狙いは当たった。答えの形になる。
'@C ちょっと分からないけどgitのrebaseはコミットまでやる、mergeは最初から2つ目までの部分だけするんだよ'
'グローバルリポジトリの参照から、リポジトリの別にあるファイルを最新に反映させる操作'
'@あかり UDPはネットワークの帯域をフル活用するために使うため、TCPは帯域を使用する前に…'
心配していた助手口調は漏れなかった(敬体 0%)。1 epoch では instruct の
「〜がおすすめです」が出てくる前に口調が移った。
代償は2つ。 なりきり時の噛み合いが 55% → 33% に落ち、逐語コピーが 13.3%
に増えた(ゴミみたいにゃ機能つけたせいで嫌い のような実発言の丸写し)。
なりきりを重視するなら ft-2、答えの形を重視するなら ft-3。
数字
| |
|---|
| ベース | Qwen/Qwen3-0.6B (instruct / 596,049,920 params) |
| 学習トークン | 15.85M / 73,782 会話(ft-2 と同一のコーパス sft-v5) |
| 窓 | 1024(会話を EOS で継いで詰める / パディングしない) |
| 学習 | 1 epoch / lr 5e-5 / cosine / AdamW 8bit / fp16 + fp32 master |
| val loss | 2.6072(ft-2 は epoch1 2.5980 / epoch2 2.6079) |
| ハードウェア | Kaggle T4 / 峰 12.8GB / 約 3.3 時間 |
1 epoch なのは GPU 枠の都合(残り5時間)。2 epoch なら答えの形はさらに強く、
なりきりはさらに弱くなる見込み。
コーパス sft-v5(ft-2 と同一)
外部データは使っていない。全部このサーバーのログ。
| 件数 | train に占める割合 |
|---|
| 噛み合った箇所 | 23,111 | 12.3% |
| 長い発言(40字以上) | 32,593 | 25.6% |
長い発言の 91% は名前を持つ人のものなので、そこを重くすると「長く喋る」と
「なりきり度」が同時に上がる。切り出しの一部は話者を匿名の役に付け替えてある
(bot が既定で匿名の役で喋るのに、信号の 88% が名前持ちだった)。
使い方
素の transformers で動く。独自トークンは1つも足していない。
1import torch
2from transformers import AutoModelForCausalLM, AutoTokenizer
3
4path = "tako080614/evex-ft-3"
5tok = AutoTokenizer.from_pretrained(path, subfolder="epoch-1")
6model = AutoModelForCausalLM.from_pretrained(path, subfolder="epoch-1", dtype=torch.float32)
7model.eval()
8
9prompt = "#ch2\nA: git rebase と merge の違いって何\nB:"
10
11ids = tok(prompt, return_tensors="pt")
12out = model.generate(**ids, max_new_tokens=80, do_sample=True, temperature=0.9,
13 top_k=40, min_p=0.05, repetition_penalty=1.1,
14 pad_token_id=tok.eos_token_id)
15print(tok.decode(out[0], skip_special_tokens=True)[len(prompt):])
チャットテンプレートは使わない。 instruct 版が土台だが、学習したのは
名前: 本文 の会話ログ形式なので、apply_chat_template を通すと学習中に
一度も見ていない形になる。
プロンプトの形
#ch2 ← #ch0..#ch15 か #other(上位16で全体の 97%)
たこ: これバグってる? ← 147人は表示名(speakers.json)
A: どこで止まってる? ← それ以外は A..H / Z の相対の役
あかり: ← 末尾に置いた人として続きを書く
同じ人が続けて喋ることがある(学習データの話者の塊のうち 27.4% が2連続以上)。
素の日本語形式には終端トークンが無いので、放っておくと max_new_tokens を使い切る。
次の 名前: で切ること。
できること / できないこと
できる: 答えの形にすること、そのサーバーの口調、147人の読み分け(ft-2 より弱い)
できない: 事実、計算、翻訳、指示に従うこと
内容は当てにならない。 0.6B なので、instruct 版ですら「日本の首都」を大阪と答える。
狙えるのは「話を受けて、それらしい形で、このサーバーの口調で返す」まで。
ライセンス
ベースは Qwen3-0.6B (Apache-2.0) の派生。学習データは非公開の私的な会話なので、
再配布・商用利用は想定していない。上の「表示名が重みに入っている」を必ず読むこと。