メインコンテンツへスキップ

11.4.2 シーケンスラベリングタスク

BIO 標注から実体を復元する図

この節の位置づけ

テキスト分類の出力は通常、次のようになります。

  • 文全体に1つのラベル

一方、シーケンスラベリングの出力はより細かくなります。

  • 各 token に1つのラベル

この違いはとても重要です。NLP を「文全体の判定」から、

文の中の具体的な情報を見つけること

へと進めるからです。

そしてここから、命名実体認識、情報抽出、スロットフィリングのようなタスクへ、より自然につながっていきます。

学習目標

  • シーケンスラベリングと文全体分類の根本的な違いを理解する
  • BIO / BIOES のようなラベル体系がなぜよく使われるのかを理解する
  • 実行可能な例を通して token 単位のラベリング手順を理解する
  • シーケンスラベリングと情報抽出タスクのつながりを理解する

一、シーケンスラベリングは何を解決するのか?

「この文は何か」を判断するだけでなく、「この文のどの部分が何か」を判断する

たとえば、次の文を考えます。

  • 「張三は北京大学で働いている」

テキスト分類なら、たとえば次のように出力されるかもしれません。

  • これは人物と場所に関する文である

しかしシーケンスラベリングでは、より重要なのは次のような点です。

  • 張三 は人名
  • 北京大学 は組織名

なぜこれが重要なのか?

なぜなら、実際の多くの業務では、文全体の理解だけでは足りないからです。
より知りたいのは、たとえば次のような情報です。

  • 人名
  • 住所
  • 組織名
  • 金額
  • 時間

つまり、具体的な断片の位置や境界です。

たとえで考えると

テキスト分類は、記事全体にラベルを貼るようなものです。
シーケンスラベリングは、蛍光ペンで文の重要部分を囲むようなものです。


二、なぜ出力は通常 token 単位なのか?

実体は連続した断片だから

抽出したい情報の多くは、単語1つではなく、連続した span です。
たとえば次のようなものです。

  • 上海交通大学
  • 2025年6月1日

token 単位のラベルなら境界を表現できる

そのため、よく使われるラベル体系は、単純に次のように書くのではなく、

  • PERSON
  • LOCATION

次のように書きます。

  • B-PER
  • I-PER
  • O

BIO の直感

  • B-:実体の開始
  • I-:実体の内部
  • O:どの実体にも属さない

こうすることで、システムはより明確に区別できます。

  • 実体がどこから始まるか
  • どこで終わるか

三、まずは最小の BIO ラベリング例を動かしてみる

tokens = ["張三", "は", "北京", "大学", "で", "働いている"]
tags = ["B-PER", "O", "B-ORG", "I-ORG", "O", "O"]

for tok, tag in zip(tokens, tags):
print(tok, tag)

実行結果の例:

張三 B-PER
は O
北京 B-ORG
大学 I-ORG
で O
働いている O

token の列とタグの列は同じ長さでなければなりません。系列ラベリングのデータを見るとき、最初に確認するのはこの一対一の対応です。

この例でいちばん大事なことは?

ここで見えてくるのは、

  • シーケンス入力
  • 対応するシーケンス出力

です。

これが、シーケンスラベリングの最も基本的な形です。

token の列を入力し、同じ長さのラベル列を出力する。

なぜ 北京 大学B-ORG / I-ORG なのか?

ここで表したいのは、

  • これは同じ連続した実体である

ということです。

別々の2つの実体ではありません。


四、ラベル列から実体を復元する

次の例では、token + BIO ラベルから実体の断片を復元します。

tokens = ["張三", "は", "北京", "大学", "で", "働いている"]
tags = ["B-PER", "O", "B-ORG", "I-ORG", "O", "O"]


def decode_entities(tokens, tags):
entities = []
current_tokens = []
current_type = None

for token, tag in zip(tokens, tags):
if tag == "O":
if current_tokens:
entities.append(("".join(current_tokens), current_type))
current_tokens = []
current_type = None
continue

prefix, entity_type = tag.split("-", 1)

if prefix == "B":
if current_tokens:
entities.append(("".join(current_tokens), current_type))
current_tokens = [token]
current_type = entity_type
elif prefix == "I" and current_type == entity_type:
current_tokens.append(token)
else:
# ラベルが不正な場合は、いったん切って開き直す
if current_tokens:
entities.append(("".join(current_tokens), current_type))
current_tokens = [token]
current_type = entity_type

if current_tokens:
entities.append(("".join(current_tokens), current_type))

return entities


print(decode_entities(tokens, tags))

実行結果の例:

[('張三', 'PER'), ('北京大学', 'ORG')]

この処理で、token 単位のラベルが実際に使う成果物、つまりエンティティ文字列とエンティティタイプに変わります。

このコードが重要なのはなぜ?

これは「ラベリングタスク」と「抽出結果」をつないでいるからです。
実際のシステムで本当に大事なのは、タグそのものよりも、次のような結果です。

  • 実体 span
  • 実体の種類

五、シーケンスラベリングと情報抽出の関係は?

NER は典型的なシーケンスラベリングタスク

最も代表的なのは次のタスクです。

  • 命名実体認識

でも NER だけではない

ほかにも次のような用途があります。

  • スロットフィリング
  • キーワード抽出
  • イベントトリガー語の位置特定

つまり「情報抽出の土台となるスキル」

多くの抽出システムは、さらに複雑になります。
それでも、いちばん基礎となる一歩は、しばしば次のことです。

  • まず重要な span を見つける

六、よくある落とし穴

誤解1:シーケンスラベリングを普通の分類だと思ってしまう

文全体分類との最大の違いは、

  • 出力が列に対して対応づいていること

です。

誤解2:ラベルだけ見て、境界の復元を見ない

実際のシステムでは、ラベル表そのものよりも、最終的に抽出された実体片のほうが重要です。

誤解3:ラベル体系を適当に決める

ラベル設計が乱れていると、モデルも評価も一緒に乱れます。


まとめ

この節でいちばん大切なのは、次の考え方を身につけることです。

シーケンスラベリングの核心は、入力シーケンスの各 token にラベルを付け、それによって文の中の重要な断片と境界を復元すること。

この感覚がしっかりしていれば、後で NER、BiLSTM+CRF、情報抽出プロジェクトを学ぶときに、かなり理解しやすくなります。


練習

  1. 例に時間表現 2025年 を追加して、自分で BIO ラベルの組を作ってみましょう。
  2. なぜ BIO ラベル体系の重要な役割は、実体の境界を表すことだと言えるのでしょうか?
  3. 自分の言葉で説明してみましょう。シーケンスラベリングとテキスト分類の最大の違いは何ですか?
  4. 考えてみましょう。ラベル列の中に不正な I-XXX が出てきたら、システムはどう処理するとより安定でしょうか?