加载中…
加载中…
日本語の対話 (雑談) で話題の区切りを見つける BERT 分類器です。イベントセグメント検出 (event segmentation)・
話題分割 (topic segmentation) を、文と文の境界ごとの 3 クラス分類 (区切りなし / 脇道 / 新しい話題) として行います。
transformers の AutoModelForSequenceClassification (trust_remote_code=True) でも、同梱の shiori_infer.py でも使えます。
A Japanese BERT classifier for dialogue topic segmentation / event segmentation: it scores each boundary
between two sentences of a conversation as no boundary, side topic, or new topic. Loadable with transformers
(AutoModelForSequenceClassification, trust_remote_code=True) or with the bundled shiori_infer.py.
Keywords: イベントセグメント検出 / 話題の区切り / 話題分割 / 対話 / 会話 / event segmentation / topic segmentation / dialogue / conversation / discourse segmentation / Japanese
English summary. shiori-bert-jp is a small Japanese BERT classifier that finds topic boundaries in a chat
conversation. For each boundary between two sentences it looks at the 2 sentences before and the 2 after
(with speaker tags) and outputs 3 classes: C0 (no boundary), C1 (side topic inside the current topic) and C2+
(new topic). It was distilled from LLM teacher labels (Claude Opus 5.5 given human-labelled examples) on 400
synthetic Japanese chats generated with Claude Sonnet 5.5. On 8 fresh human-labelled conversations
(287 boundaries) the 5-seed mean F1 of this configuration is 0.770 (this released seed: 0.790), on par with its
LLM teacher (0.769), at about 45 ms per boundary on a desktop CPU. The training data is not released.
It is a non-generative classifier for research and hobby use. Load it with the bundled shiori_infer.py
or with AutoModelForSequenceClassification.from_pretrained(..., trust_remote_code=True) (see below).
日本語の雑談で、文と文の間 (境界) ごとに「ここで話の区切りがあるか」を判定する分類器です。
利用者:…、相棒:…、コロンは全角)。境界の 1 文先まで見て判断するので、会話の流れに合わせて文が 1 つ届くたびに、その直前の境界を判定する使い方ができます。
| ラベル | 意味 |
|---|---|
| C0 | 区切りなし。同じやりとりの続き |
| C1 | 小さな区切り。いまの話題の中の脇道 |
| C2+ | 話題の区切り。新しい話題が始まる (会話がいったん閉じて新しく始まる場面を含む) |
学習時のラベルは C0〜C3 の 4 段階でしたが、C3 (会話が閉じて新しく始まる) は数が少ないので C2 にまとめて 3 クラスにしています。
必要なもの: torch、transformers、safetensors、huggingface_hub、fugashi、unidic-lite
(動作確認: torch 2.6.0 / transformers 5.20.1 / safetensors 0.8.0 / fugashi 1.5.2 / unidic-lite 1.0.8)。
pip install torch transformers safetensors huggingface_hub fugashi unidic-lite
トークナイザ (tohoku-nlp/bert-base-japanese-v3 のものを同梱)、BERT の設定、学習済みの重みとヘッドは、
すべてこのリポジトリから読みます。読み込みは同梱の shiori_infer.py で行います (transformers から直接読む方法は
下の「transformers で使う」を参照)。
from huggingface_hub import hf_hub_download
import importlib.util
repo = "melon1891/shiori-bert-jp"
path = hf_hub_download(repo, "shiori_infer.py")
spec = importlib.util.spec_from_file_location("shiori_infer", path)
shiori_infer = importlib.util.module_from_spec(spec)
spec.loader.exec_module(shiori_infer)
seg = shiori_infer.ShioriSegmenter(repo) # ローカルのフォルダを渡してもよい
conv = [
("利用者", "今朝、駅まで走ったら汗だくになったよ。"),
("相棒", "急いでたの?"),
("利用者", "うん、目覚ましを止めて二度寝しちゃって。"),
("相棒", "寝坊なんて珍しいね。"),
("利用者", "そうだ、週末に図書館で借りた本がすごく面白かったんだ。"),
("相棒", "どんな本?"),
]
for r in seg.segment(conv):
print(r["index"], r["probs"], r["piece_boundary"], r["topic_boundary"])
segment() は 1 文ずつの (話し手, 文) のリストを受け取り、境界 i (i-1 番目と i 番目の文の間、i ≥ 1) ごとに
確率と 2 段の判定を返します。shiori_infer.split_sentences() で文に分けてから渡してください
(学習データと同じ規則: 「。!?!?」と、その後に続く閉じ括弧で文が終わる)。利用者 と 相棒 の 2 つだけです。別の名前の話し手は
speaker_map={"A": "利用者", "B": "相棒"} のように置き換えて渡すのがおすすめです。config.json は transformers の設定ファイルで、このモデルの入力形式 (input_format) と判定規則 (decision_rules)
も追加の項目として含みます。
ヘッドは BERT の pooler ではなく [CLS] の最終層の隠れ状態に直接かかります (pooler は使わないので重みも含みません)。python shiori_infer.py で、上の 6 文の作例に対する判定を表示します。
モデルの定義 (modeling_shiori.py) がこのリポジトリにあるので、trust_remote_code=True が必要です。
出力は shiori_infer.py と同じです (ロジットの差 < 1e-5 を確認済み)。
import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer
repo = "melon1891/shiori-bert-jp"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForSequenceClassification.from_pretrained(repo, trust_remote_code=True).eval()
# 境界の前の 2 文 (left) と後の 2 文 (right)。話し手の札付きで、文はそのまま連結します。
left = "利用者:うん、目覚ましを止めて二度寝しちゃって。相棒:寝坊なんて珍しいね。"
right = "利用者:そうだ、週末に図書館で借りた本がすごく面白かったんだ。相棒:どんな本?"
enc = tok(left, right, return_tensors="pt")
with torch.no_grad():
p = model(**enc).logits.softmax(-1)[0]
print({model.config.id2label[i]: round(v, 3) for i, v in enumerate(p.tolist())})
print("piece boundary:", (p[1] + p[2]).item() >= 0.5, " topic boundary:", p[2].item() >= 0.5)
pipeline でも使えます (文の組は text / text_pair で渡します):
from transformers import pipeline
clf = pipeline("text-classification", model="melon1891/shiori-bert-jp", trust_remote_code=True)
print(clf({"text": left, "text_pair": right}, top_k=None))
shiori_infer.py が便利です。shiori_infer.py は学習時と同じ規則 (前側は後ろ寄り、後側は前寄りに
切り詰め) を使います。tokenizer の truncation=True はこれと違う切り方になるので、長い入力は shiori_infer.py を
使ってください。shiori_infer.py 専用の形式) は、revision="a6ad40d749bc4fbebf1c0d2d57e959dc44cd17b8" を指定すると読めます。
The earlier shiori_infer.py-only layout is available at that revision.tohoku-nlp/bert-base-japanese-v3 を fine-tune し、[CLS] の隠れ状態に 3 クラスの線形ヘッドを追加。学習にも改良の判断にも使っていない、新しく生成した 8 会話 (287 境界) に、1 名の作業者が人手でラベルを付けた 評価セットで、1 回だけ採点しました。指標は「区切りあり (C1 以上) / なし」の F 値 (F1) です。
| モデル | F 値 |
|---|---|
| この構成 (Opus + 例を先生にした生徒) の 5 種平均 | 0.770 (種ごとの範囲 0.756〜0.790) |
| このリポジトリの種 (種 3、5 種の中で最高) | 0.790 |
| 先生: Claude Opus 5.5 + 人手ラベルの例 | 0.769 |
| 参考: Claude Sonnet 5.5 (例なし、zero-shot) | 0.736 |
利用者 / 相棒 の 2 つでしか学習していません。このモデルの学習に使った会話とラベルは、Anthropic の Claude で作成しました。このモデルやその出力を使う方は、 ご自身が利用するサービスの規約を守る責任があります。
LICENSE)。帰属と変更点は NOTICE にあります。vocab.txt、tokenizer_config.json) もこのベースモデルから写したものです
(tokenizer_config.json には model_input_names だけを追加。詳細は NOTICE)。猫飼人. 「AI キャラクター向けイベントセグメント検出モデルを作って検証してみた」. 技術書典 21.