word2vecやGloVe、fastTextなどを使うと、単語をベクトルにできます。
import gensim.downloader
vectors = gensim.downloader.load('word2vec-google-news-300')
vectors['king'][:10]
array([ 0.12597656, 0.02978516, 0.00860596, 0.13964844, -0.02563477,
-0.03613281, 0.11181641, -0.19824219, 0.05126953, 0.36328125],
dtype=float32)
こういうベクトルのことを「分散表現」と呼ぶときと「埋め込み表現」と呼ぶときがありますが、どちらを使っても良いのでしょうか?私も過去に書いた記事で区別せず使っていたりしましたが、区別は無いのでしょうか。
単なる「ベクトル化」とは違うのでしょうか?「語彙数に比べると低次元」「密な(ゼロの要素が少ない)ベクトル」といった特徴が述べられている文献は多いように感じますが、それらが「分散表現」「埋め込み表現」たる十分条件なのでしょうか?
先に結論
IT Text 自然言語処理の基礎 (オーム社)に書いてあったので、引用します。
単語をベクトルで表現したものを, 単語埋込み (word embedding), 単語の分散表現 (distributed representation), 単語ベクトルという異なる用語で呼ぶことがある. これらの用語は多くの場合,言い換え可能な文脈で用いられるが, 指し示す概念が微妙に異なるので注意が必要である. 単語埋込みは, 単語の意味をニューラルネットワークが用いる実数空間に 「埋め込む」 という状況に焦点を当てている. 単語の分散表現は, 単語を複数の要素からなる実数値で表現し, それらの要素は他の単語の表現にも用いるというアイディア を表す用語である. 単語を個別のニューロンで表現し, あるニューロンは一つ の単語しか表現しないという局所表現 (local representation) (これは 3.2節 で説明したワンホットベクトルに相当する) と対をなす用語である. 単語ベクトルは, 単語をベクトルという数学の道具で表現するというニュアンスしかなく, これらの用語の中では最も一般的に用いることができる。
-
埋込み表現(embedding)
- ニューラルネットワークの実数空間に意味を埋め込む
-
分散表現(distributed representation)
- 単語(より一般には記号?)を複数の要素からなる実数値で表し、その要素は他の単語の表現にも用いる
- 対としてワンホットベクトルは 局所表現(local representation) と呼ばれる
-
単語ベクトル
- 単に単語をベクトルで表現すること
つまり、単語ベクトルが最も広義で、その中に分散表現があって、さらにその中に埋め込み表現があるというイメージでしょうか。「埋め込み表現ではあるが、分散表現ではない」という事があり得るのかは分かりませんが、珍しいケースではあると思います。
実例
Bag of WordsやTF-IDFで得られるベクトル
from janome.tokenizer import Tokenizer as JanomeTokenizer
from sklearn.feature_extraction.text import CountVectorizer
janome_tokenizer = JanomeTokenizer()
janome_tokenize = lambda text: janome_tokenizer.tokenize(text, wakati=True)
vectorizer = CountVectorizer(tokenizer=janome_tokenize, token_pattern=None)
texts = ["私は今日焼肉を食べる", "私は明日焼鳥を食べる"]
vectorizer.fit(texts)
print(vectorizer.get_feature_names_out())
print(vectorizer.transform(texts).toarray())
['は' 'を' '今日' '明日' '焼肉' '焼鳥' '私' '食べる']
[[1 1 1 0 1 0 1 1]
[1 1 0 1 0 1 1 1]]
Bag of WordsやTF-IDFのような手法は「埋め込み表現」とも「分散表現」とも呼べないでしょう。これらはニューラルネットワークを使っていないので埋め込み表現には該当しません。また、ひとつの要素がひとつの単語に対応しているので、分散表現ではなく局所表現になります。
なおBag of Wordsなどで作った局所表現を次元削減するような手法が考えられます。これは「分散表現」とは呼べそうですが「埋め込み表現」ではないと思います。
from sklearn.manifold import TSNE
tsne = TSNE(n_components=2, perplexity=1, init="random")
tsne.fit_transform(vectorizer.transform(texts))
array([[-1610.6106 , 638.94604],
[ 1610.6104 , -638.9459 ]], dtype=float32)
word2vecやfastTextで得られるベクトル
冒頭に挙げたword2vecのような手法は、「埋め込み表現」「分散表現」どちらで呼んでも良さそうです。
OpenAI Embeddings APIで得られるベクトル
from openai import OpenAI
client = OpenAI(api_key=OPENAI_API_KEY)
print(client.embeddings.create(model="text-embedding-ada-002", input="私は今日焼肉を食べる").data[0].embedding[:5])
print(client.embeddings.create(model="text-embedding-ada-002", input="私は明日焼鳥を食べる").data[0].embedding[:5])
[-0.00335930404253304, -0.011788398027420044, -0.01112627424299717, -0.0057416511699557304, 0.014501807279884815]
[0.003935805521905422, -0.010577674955129623, -0.013454449363052845, 0.004160257056355476, 0.004485870245844126]
OpenAI Embeddings APIやMultilingual E5のような、文に対して直接ベクトル化する手法は「埋め込み表現」と呼ぶのが良さそうです。
掲載したコードの実行環境
- Python 3.10.12
- gensim 4.3.2
- scikit-learn 1.2.2
- openai 1.5.0