[中級編]LLMへ至る道~単語を埋め込むってどういうこと?~[8日目]

2023.12.08

みなさんこんにちは!クルトンです。

前日は、トークナイザーについて見ていきました。文章をトークンと呼ばれる単位に分割するものでしたね。

本日のブログは、単語を埋め込むとはどういう事かを「単語レベル」で考えるWord2Vecという機械学習モデルを通して知っていきましょう。

単語を埋め込むとは

簡単にいうと、下記のようなイメージです。

ID 単語
1
2
3
4
5

上記の表の例では、IDの1に猫というものが対応しています。 イメージではありますが、数値と単語を対応させるという事をしています。

Word2Vecでは、数値対応に以前のブログでも紹介した分散表現を使っています。

つまり実際にはベクトル(複数の数値の集まり)によって、一意にどの単語を表しているかが決まります。

このように分散表現で持って一定の集まりの文(今回でいえば単語)を表す事を埋め込みと言います。

Word2Vecの種類

Word2Vecには2種類のモデルがあります。Word2Vecの学習済みモデルを使うときに知っておくと、コードを読みやすくなるので概要を簡単に知っておきましょう。

  • Continuous Bag-Of-Words(CBOW)
    • ある単語が何であるかを予測する時に、前後の単語から予測する手法。前後の範囲をウィンドウサイズと呼ぶ。
    • モデルの中身としてニューラルネットワークが使われている。
    • ちなみにBagとは多重集合のことで、「同じ要素が重複して含まれる場合のある集合」の事を表す。
  • Skip-Gram
    • ある単語の周辺がどのような単語であるかを予測する。(CBOWとは逆のやり方のイメージ。)
    • モデルの中身としてニューラルネットワークが使われている。

分散表現であるから出来ること

分散表現というのは、ベクトル(複数の数値の集まり)であるという事をお伝えしました。

数値である事から足し算や引き算が可能です。つまり単語を足し引きできます。

以下は例です。

女王 - 女性 = 王

加法構成性と呼びます。

Word2Vecを実際に触ってみよう!

Google Colab(ランタイムはCPU)で動かしていきます。

Word2Vecではすでに日本語で学習が行なわれている事前学習済みモデルがあるため、そちらを使っていきます。

モデルのダウンロード

学習済みモデルには色々なものがありますが、本ブログではFaceBook社が作ったモデルを使います。

以下のサイトでJapanと書かれている箇所のtextと書かれているボタンを押してダウンロードしてください。

road-to-llm-advent-calendar-2023-08-01

ダウンロードした学習済みモデルファイルはGoogle Driveへアップロードしておいてください。

モデルを読み込み

準備ができたので早速コードを動かしていきましょう!

まずは以下のコードを実行してください。

# Google Driveと連携する。
from google.colab import drive
drive.mount('/content/drive')

上記コードを実行すると最初に以下の画像のようなポップアップが画面に表示されるので、指示に従って順番に実行していきます。

road-to-llm-advent-calendar-2023-08-02

なお、アカウントを選択する画面では、学習済みモデルファイルをアップロードしたGoogle Driveのアカウントを選択してください。

次にGoogle Colab(ランタイムはCPU)で以下のモデル読み込みするコードを実行します。なお、model_pathと書かれている変数は、自身がファイルをアップロードしたファイルパスへ変更してください。

from gensim.models import Word2Vec
from gensim.models import KeyedVectors

# Word2Vecモデルのロード
model_path = '/content/drive/MyDrive/<Google Driveでアップロードしたファイルパス>/cc.ja.300.vec.gz'
word2vectors = KeyedVectors.load_word2vec_format(model_path, binary=False)

8分ほどでモデルの読み込みが終わりました!

Word2Vecを動かしてみる

読み込んだWord2Vecは次のようなコードで動かせます。

# 単語の引き算
result_vector = word2vectors['東京'] - word2vectors['首都']

# 類似単語の取得
similar_words = word2vectors.similar_by_vector(result_vector, topn=5)

# 結果表示
print(f"東京 - 首都の結果から近い単語を表示")
for word, score in similar_words:
    print(f"{word}: {score}")

例として、「東京」から「首都」を引いたら何になるかを確認してみました。

出力結果は以下です。

東京 - 首都の結果から近い単語を表示
東京: 0.4033203125
墨田: 0.3162616193294525
清瀬: 0.309244304895401
台東: 0.3009122908115387
神田: 0.28334444761276245

上記の名称は東京の地名が書かれているのが確認できました!

他にも result_vectorと書かれている部分を適当な単語に変えることで、類似する単語を確認できます。よければやってみてください。

単語埋め込み時の課題点

ここまで、Word2Vecを実際に動かして見てきました。 しかし、ここまでの内容では触れてこなかった課題点もあります。

単語と分散表現を一対一対応させるため、例えば、以下の単語を文脈に即して対応させる事は難しいです。

  1. 彼は人気のない通りを歩いた
  2. 彼は人気のあるミュージシャンだ

上記2つの文章では、同じ「人気」という言葉が使われています。 ただし、意味は大きく異なります。 1番の文章では、「ひとけ」と読み、道に人がいない様子を表す文章になっています。2番の文章では「にんき」と読み、様々な人から好かれている文章になっています。

文章によっては明らかに意味が異なる場合でも同様に扱ってしまうという課題が単語埋め込みをする場合は存在しています。

このような課題に対応するため「文脈によって意味が異なる」という内容を考慮する必要が出てきました。

終わりに

今回は簡単に単語埋め込みについて、実際のモデルを含めてご紹介いたしました。 簡単なコードも紹介していますので、よければ動かしてみてください。

明日以降は「文脈に合わせた単語埋め込み」に関連する内容をご紹介していきます!

本日はここまで。それでは、また明日もよければご覧ください!