shiori-bert-jp

日本語の対話 (雑談) で話題の区切りを見つける 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).

何をするモデルか

日本語の雑談で、文と文の間 (境界) ごとに「ここで話の区切りがあるか」を判定する分類器です。

  • 入力: 境界の前の 2 文と後の 2 文。各文に話し手の札を付けます (利用者:…、相棒:…、コロンは全角)。
  • 出力: 3 クラスの確率 (C0 / C1 / C2+)。
  • 判定は 2 段です。
    • 細かい区切り (piece boundary): P(C1) + P(C2+) ≥ 0.5
    • 話題の区切り (topic boundary): P(C2+) ≥ 0.5

境界の 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 段の判定を返します。
  • 1 つの発話に複数の文がある場合は、shiori_infer.split_sentences() で文に分けてから渡してください (学習データと同じ規則: 「。!?!?」と、その後に続く閉じ括弧で文が終わる)。
  • 学習時の話し手の札は 利用者 と 相棒 の 2 つだけです。別の名前の話し手は speaker_map={"A": "利用者", "B": "相棒"} のように置き換えて渡すのがおすすめです。
  • 最大長は 256 トークンです。長すぎる場合は、前側は後ろ寄りの約 126 トークン、後側は残りの長さまで切り詰めます。
  • config.json は transformers の設定ファイルで、このモデルの入力形式 (input_format) と判定規則 (decision_rules) も追加の項目として含みます。 ヘッドは BERT の pooler ではなく [CLS] の最終層の隠れ状態に直接かかります (pooler は使わないので重みも含みません)。

python shiori_infer.py で、上の 6 文の作例に対する判定を表示します。

transformers で使う (Usage with transformers)

モデルの定義 (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))
  • 1 つの会話をまとめて判定するとき (前後 2 文の組み立て、文の分割、話し手の札の置き換え) は shiori_infer.py が便利です。
  • 前後を合わせて 256 トークンを超える入力では、shiori_infer.py は学習時と同じ規則 (前側は後ろ寄り、後側は前寄りに 切り詰め) を使います。tokenizer の truncation=True はこれと違う切り方になるので、長い入力は shiori_infer.py を 使ってください。
  • 2026-11-09 より前の版 (shiori_infer.py 専用の形式) は、revision="a6ad40d749bc4fbebf1c0d2d57e959dc44cd17b8" を指定すると読めます。 The earlier shiori_infer.py-only layout is available at that revision.

学習

  • 方式: LLM の先生のラベルを小さな BERT (生徒) に写す、知識の蒸留です。
  • 学習用の会話: Anthropic の Claude (Sonnet 5.5) で生成した、合成の日本語雑談 400 本 (14,744 境界)。 同じ家で暮らす 2 人が 18〜22 ターンで 3〜4 個の日常の話題を話す形で、手がかり語 (「そういえば」など) のない 話題の変わり目や、ターンの途中での話題の切り替えを意図的に含めています。
  • ラベル: Claude Opus 5.5 が、人手でラベルを付けた会話を例として見たうえで、すべての境界に C0〜C3 を付けたもの。
  • モデル: tohoku-nlp/bert-base-japanese-v3 を fine-tune し、[CLS] の隠れ状態に 3 クラスの線形ヘッドを追加。
  • 設定: 8 エポック、学習率 5e-5、バッチ 16、最大 256 トークン、クラスの重みは頻度の −0.5 乗。 種 0〜4 の 5 つで学習し、このリポジトリはそのうち種 3 のモデルです。学習は RTX 2070 1 枚。
  • 学習データ (会話・ラベル) は公開していません。

評価

学習にも改良の判断にも使っていない、新しく生成した 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
  • 主に見るべき値は 5 種の平均 0.770 です。公開している種 3 の 0.790 は種の揺れの上端にあたります。
  • 評価セットが小さいため区間は広く、先生や Sonnet との差は偶然と区別できる大きさではありません。 言えるのは「生徒が先生と同じ水準」までです。
  • 速さ: CPU (AMD Ryzen 9 3900X、8 スレッド) で 1 境界あたり中央値 約 45 ms (同じ作りの生徒で測定)。

限界

  • 合成会話で学習。 会話は LLM が書いた整った雑談で、実際の会話より言いよどみや脱線が少なめです。 実会話、3 人以上の会話、雑談以外の分野では精度が下がる可能性があります。
  • 人手ラベルは 1 名。 評価の正解は 1 名の作業者のラベルです。
  • 評価セットは 8 会話。 数字の信頼区間は広いです。
  • 日本語の 2 人の雑談のみ。 話し手の札は 利用者 / 相棒 の 2 つでしか学習していません。
  • 細かく切りすぎる傾向。 人が 1 つの話題とみなす所を小さな脇道に分けたり、話題の区切りを細かい区切り (C1) と して出したりしがちです。誤りの多くは位置ではなく、区切りの大きさ (粒度) の誤りです。

想定する用途

  • 対話システムでの研究・趣味の利用。たとえば会話ログを話題ごとにまとめる、記憶の単位を決める、など。
  • 文章を生成しない分類器として使うことを想定しています。
  • 想定外: 人の評価や判断の材料に使うこと、ここに書いた評価の数字を別の評価セットの代わりに使うこと。

Claude の出力についての注意

このモデルの学習に使った会話とラベルは、Anthropic の Claude で作成しました。このモデルやその出力を使う方は、 ご自身が利用するサービスの規約を守る責任があります。

ライセンスと帰属

  • ライセンス: Apache License 2.0 (LICENSE)。帰属と変更点は NOTICE にあります。
  • ベースモデル: tohoku-nlp/bert-base-japanese-v3 (Apache-2.0)。トークナイザのファイル (vocab.txt、tokenizer_config.json) もこのベースモデルから写したものです (tokenizer_config.json には model_input_names だけを追加。詳細は NOTICE)。
  • 変更点: ベースの BERT を日本語の会話の話題境界の分類に fine-tune し、[CLS] の隠れ状態に 3 クラス (C0 / C1 / C2+) の線形ヘッドを追加しました。重みは PyTorch の checkpoint から safetensors に変換しています。
  • 依存 (同梱していません): fugashi (MIT、同梱の MeCab は BSD-3-Clause)、 unidic-lite (コードは MIT または WTFPL、UniDic 2.1.2 の辞書は BSD)。

引用

猫飼人. 「AI キャラクター向けイベントセグメント検出モデルを作って検証してみた」. 技術書典 21.
Downloads last month
55
Safetensors
Model size
0.1B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for melon1891/shiori-bert-jp

Finetuned
(51)
this model