一般社団法人 全国個人事業主支援協会

COLUMN コラム

  • 自然言語処理の前処理テクニック:トークナイゼーションの深層理解

なぜトークナイゼーションが自然言語処理の要なのか

自然言語処理(NLP)のプロジェクトに携わったことがあるエンジニアなら、前処理の重要性を痛感しているはずです。どれほど優れたモデルを用意しても、入力データの質が低ければ結果は期待できません。その前処理の中でも、最も基本的かつ重要なステップがトークナイゼーションです。

トークナイゼーションとは、テキストを意味のある最小単位(トークン)に分割する処理のことです。英語であればスペースで区切れば概ね対応できますが、日本語のように単語間に区切りがない言語では、形態素解析器を使った高度な処理が必要になります。本記事では、トークナイゼーションの各手法を深掘りし、実務で使えるテクニックを紹介します。

トークナイゼーションの主要手法

1. 単語レベルのトークナイゼーション

最もシンプルな方法は、テキストを単語単位で分割することです。英語ではスペースや句読点で分割しますが、日本語の場合はMeCabやJanomeなどの形態素解析器を使います。

import MeCab

tagger = MeCab.Tagger("-Owakati")
text = "自然言語処理の前処理は非常に重要です"
tokens = tagger.parse(text).strip().split()
print(tokens)
# ['自然', '言語', '処理', 'の', '前処理', 'は', '非常', 'に', '重要', 'です']

単語レベルのトークナイゼーションは直感的で理解しやすいですが、未知語(OOV: Out of Vocabulary)問題が発生しやすいという欠点があります。訓練データに存在しない単語が出てくると、モデルは適切に処理できません。

2. サブワードトークナイゼーション

近年主流となっているのが、サブワード(部分単語)レベルでの分割です。代表的な手法としてBPE(Byte Pair Encoding)WordPieceSentencePieceがあります。これらは頻出する文字列パターンを学習し、未知語も既知のサブワードの組み合わせで表現できるため、OOV問題を大幅に軽減します。

import sentencepiece as spm

# モデルの学習
spm.SentencePieceTrainer.train(
input='corpus.txt',
model_prefix='sp_model',
vocab_size=8000,
model_type='bpe'
)

# 学習済みモデルの読み込みとトークナイズ
sp = spm.SentencePieceProcessor()
sp.load('sp_model.model')

text = "ディープラーニングによる自然言語処理"
tokens = sp.encode_as_pieces(text)
print(tokens)
# ['▁ディープ', 'ラーニング', 'による', '自然', '言語', '処理']

3. 文字レベルのトークナイゼーション

最も粒度が細かい方法が文字レベルです。OOV問題は完全に解消されますが、トークン列が非常に長くなるため、計算コストが増大します。特にTransformerベースのモデルでは、入力長の二乗に比例して計算量が増えるため、実用上の制約が大きくなります。

実務で押さえるべき前処理パイプライン

トークナイゼーションの前後にも、重要な前処理ステップがあります。実務では以下のようなパイプラインを構築することが一般的です。

  1. テキストクリーニング:HTML タグの除去、Unicode正規化(NFKC)、不要な空白の除去
  2. 正規化:大文字小文字の統一、数値の置換、URLやメールアドレスの匿名化
  3. トークナイゼーション:上述の手法による分割
  4. ストップワード除去:「の」「は」「が」などの機能語を除去(タスクにより判断)
  5. 特殊トークンの付与[CLS][SEP][PAD]などの特殊トークンを追加

import unicodedata
import re

def preprocess_text(text):
# Unicode正規化
text = unicodedata.normalize('NFKC', text)
# URLの除去
text = re.sub(r'https?://\S+', '[URL]', text)
# 連続する空白を1つに
text = re.sub(r'\s+', ' ', text).strip()
return text

raw = " 自然言語処理は https://example.com を参照"
cleaned = preprocess_text(raw)
print(cleaned)
# '自然言語処理は [URL] を参照'

BERTとGPT系モデルのトークナイザの違い

現在広く使われているBERTとGPT系モデルでは、採用しているトークナイゼーション手法が異なります。BERTはWordPieceを、GPT系はBPEをベースにしています。日本語BERTモデルの多くはMeCabによる事前分割とWordPieceを組み合わせています。

from transformers import AutoTokenizer

# 日本語BERTのトークナイザ
tokenizer = AutoTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-v3')
tokens = tokenizer.tokenize('自然言語処理の前処理テクニック')
print(tokens)
# ['自然', '言語', '処理', 'の', '前', '##処理', 'テクニック']

##プレフィックスは、そのトークンが前のトークンに続くサブワードであることを示しています。この仕組みにより、未知の複合語でも適切に処理できるわけです。

トークナイゼーション選択の実践的ガイドライン

筆者が10年以上NLPプロジェクトに携わってきた経験から、以下の指針を推奨します。

  • 事前学習済みモデルを使う場合:モデル付属のトークナイザをそのまま使う。独自のトークナイザを使うと精度が大幅に低下する
  • 独自モデルを訓練する場合:SentencePieceでBPEモデルを学習するのが安定した選択。vocab_sizeは8000〜32000が目安
  • 日本語特化の処理が必要な場合:MeCab + NEologd辞書の組み合わせが依然として強力。新語への対応力が高い
  • 多言語対応が必要な場合:SentencePieceのunigramモデルが有効。言語に依存しない分割が可能

トークナイゼーションは地味な処理に見えますが、NLPパイプライン全体の精度を左右する極めて重要なステップです。自分のタスクに最適な手法を選択し、丁寧に前処理パイプラインを構築することが、高品質なNLPシステムへの第一歩となります。

この記事をシェアする

  • Twitterでシェア
  • Facebookでシェア
  • LINEでシェア