単語の数値表現と従来手法の課題
自然言語処理(NLP)における根本的な課題は、コンピュータが解釈不可能な「文字」という情報を、どのように「数値」として表現するかという点にあります。初期の手法として広く用いられたのが、One-hot Encoding(ワンホットエンコーディング)やBag of Words(BoW)です。
One-hot Encodingは、語彙数と同じ次元を持つベクトルを作成し、該当する単語のインデックスのみを1、それ以外を0とする手法です。しかし、この方法には以下の重大な欠点がありました。
- 次元の呪い: 語彙が増えるほどベクトルの次元が膨大になり、メモリ消費が激しくなる。
- スパース性(希薄性): ベクトルのほとんどの要素が0であり、計算効率が悪い。
- 意味の欠落: 各単語が直交するため、「犬」と「猫」のような意味の近い単語であっても、ベクトル間の類似度(コサイン類似度など)が0になり、単語間の関連性を表現できない。
これらの問題を解決するために登場したのが、単語を低次元の密なベクトル空間に写像する「単語埋め込み(Word Embedding)」技術です。
単語埋め込み(Word Embedding)の核心
単語埋め込みは、単語を固定長(通常50〜300次元程度)の連続値ベクトルとして表現する技術です。この技術の最大の特徴は、「似た文脈で使われる単語は、ベクトル空間上でも近い位置に配置される」という分布仮説(Distributional Hypothesis)に基づいている点にあります。
主なアルゴリズムと原理
代表的な単語埋め込み手法には、Googleのチームが提案した「Word2Vec」と、スタンフォード大学が提案した「GloVe」があります。
1. Word2Vec
Word2Vecは、ニューラルネットワークを用いて単語の分散表現を学習します。主に以下の2つのモデル構造が存在します。
- CBOW (Continuous Bag of Words): 周囲の単語(コンテキスト)から中心の単語を予測する手法。計算速度が速く、頻出単語の精度が高い傾向にあります。
- Skip-gram: 中心の単語から周囲の単語を予測する手法。計算量は増えるが、稀少な単語の意味を捉える能力が高いとされています。
2. GloVe (Global Vectors for Word Representation)
GloVeは、コーパス全体の共起統計(どの単語とどの単語が一緒に現れやすいか)を直接モデル化する手法です。局所的なコンテキスト窓を利用するWord2Vecに対し、GloVeはコーパス全体の統計情報を活用することで、より包括的な意味関係を抽出することを目指しています。
アルゴリズムの数学的側面
Word2Vec(Skip-gram)における目的関数は、ある単語 $w_t$ が与えられた際に、その周囲の単語 $w_{t+j}$ が出現する対数確率を最大化することです。
$$\mathcal{L} = \sum_{t=1}^{T} \sum_{-c \leq j \leq c, j \neq 0} \log P(w_{t+j} | w_t)$$
ここで、$c$ はコンテキスト窓のサイズを示します。この確率 $P$ は、通常ソフトマックス関数を用いて定義され、学習過程で単語ベクトル間の内積が調整されることで、類似した単語が近いベクトルを持つようになります。
実装例:単語ベクトルの学習と活用
以下に、Pythonのライブラリ「Gensim」を用いたWord2Vecの実装例を示します。独自のコーパスを用いて単語ベクトルを学習する流れを記述します。
from gensim.models import Word2Vec
# サンプルコーパス(トークン化済みリスト)
corpus_data = [
["機械", "学習", "は", "非常に", "強力", "な", "技術", "です"],
["自然", "言語", "処理", "で", "単語", "ベクトル", "を", "使う"],
["ディープ", "ラーニング", "は", "人工", "知能", "の", "一部", "です"],
["ベクトル", "演算", "で", "単語", "の", "意味", "を", "計算", "する"]
]
# モデルの初期化と学習
# vector_size: ベクトルの次元数, window: 参照する前後の単語数, min_count: 最小出現回数
embedding_model = Word2Vec(
sentences=corpus_data,
vector_size=50,
window=3,
min_count=1,
workers=2
)
# 「単語」という言葉に最も似ている単語を抽出
similar_words = embedding_model.wv.most_similar("単語", topn=3)
for word, score in similar_words:
print(f"Word: {word}, Similarity: {score:.4f}")
# 特定の単語のベクトルを取得
vector_value = embedding_model.wv["ベクトル"]
print(f"Vector sample: {vector_value[:5]}...")
次に、TensorFlow/Kerasを用いた埋め込み層(Embedding Layer)の基本的な構築例を示します。これは主に分類タスクなどで、学習プロセスの一部としてベクトルを最適化する場合に使用されます。
import tensorflow as tf
from tensorflow.keras.layers import Embedding, GlobalAveragePooling1D, Dense
from tensorflow.keras.models import Sequential
vocab_size = 1000 # 語彙数
embed_dim = 64 # 埋め込み次元
max_seq_len = 20 # 入力テキストの最大長
# シンプルな感情分析などのためのネットワーク構造
nlp_net = Sequential([
Embedding(input_dim=vocab_size, output_dim=embed_dim, input_length=max_seq_len),
GlobalAveragePooling1D(),
Dense(16, activation='relu'),
Dense(1, activation='sigmoid')
])
nlp_net.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
nlp_net.summary()
単語埋め込みの今後の展望と課題
単語埋め込みは、NLPにおける「意味の数値化」を可能にしましたが、いくつかの課題も残されています。
- 多義性の問題: Word2VecやGloVeでは、1つの単語に対して1つのベクトルしか割り当てられません。例えば、「Bank」という単語が「銀行」と「土手」の両方の意味を持つ場合でも、同じベクトルになってしまいます。
- 未知語(OOV)への対応: 学習データに含まれていない単語はベクトル化できず、処理が困難になります。
これらの課題に対し、現在はBERTやGPTといった、文脈に応じて単語の表現を動的に変化させる「コンテキスト依存型(Contextualized)」の埋め込み手法が主流となっています。しかし、軽量なモデル構築や、特定のドメインにおける高速な類似度検索などにおいて、Word2Vecのような静的な単語埋め込み技術は依然として重要な役割を担っています。