Embeddingモデルでテキストをベクトル化しよう！

# はじめに
前回、ベクトル検索に必要な要素技術の一つとして、Embeddingモデルを紹介しました。Embeddingモデルは非構造化データをベクトル化するのに使われる大規模言語モデルです。今回は実際にEmbeddingモデルを使って、テキストデータをベクトル化し、ベクトル同士の類似度を確認するところまで行っていきます。

***前回記事***

https://qiita.com/araits/items/ae6ff066562c7a30e6fa

# 必要なもの
今回はAzureOpenAIのtext-embedding-ada-002と、SimCSEの2種類のEmbeddingモデルを使って比較しながら進めようと思います。ただし、AzureOpenAIの利用申請の方法については本記事では触れませんので別な記事を参照してください。

***プログラミング言語***
- Python

***モジュール***
- ***openai***
AzureOpenAIのEmbeddingモデルを利用するためのPythonモジュール
- ***SentenceTransformer***
SimCSEのEmbeddingモデルを利用するためのPythonモジュール

***Embeddingモデル***
- ***text-embedding-ada-002(AzureOpenAI)***
予めAzureOpenAI Serviceの利用申請を通しておけば、API利用することができる。Embeddingモデルそのもののダウンロードやデプロイ作業は不要であるため、比較的簡単な手続きで利用開始できる。
- ***sup-simcse-ja-large(SimCSE)***
名古屋大学の武田・笹野研究室の塚越さんが詳細な実験レポートと共に公開した日本語SimCSEモデルである。学習済みモデルを[Github](https://github.com/hppRC/simple-simcse-ja)からダウンロードすることができる。

***サンプルデータ***
- ***Wikipedia 日本語コーパス***
本記事ではWikipediaの日本語コーパスを利用します。[こちら](https://dumps.wikimedia.org/jawiki/latest/?)からダンプファイル（jawiki-latest-pages-articles.xml.bz2）をダウンロードおよび解凍すると使用できます。

# 処理の手順
ベクトル化の処理手順は以下の通りです。
1. モジュールの読み込み
1. Embeddingモデルの設定
1. テキストのベクトル化
1. ベクトル同士の比較

## １．モジュールの読み込み
各Embeddingモデルを使用するためのモジュールをインポートします。
※事前に該当モジュールをpipでインストールしておく必要があります。
```python
# AzureOpenAI用のモジュールを読み込む
from openai import AzureOpenAI
# SimCSE用のモジュールを読み込む
from sentence_transformers import SentenceTransformer
```

## ２．Embeddingモデルの設定
Embeddingモデルを扱うためのインスタンスを生成します。
AzureOpenAIを使用する場合は、APIキー(api_key)、APIバージョン(api_version)、エンドポイントURL(azure_endpoint)を指定する必要があります。
一方、SimCSEを使用する場合は、事前にダウンロードした学習済みモデルの格納先パスを指定します。

```python
# AzureOpenAIの設定
aoai_client = AzureOpenAI(
    api_key = azure_conf.aoai.key1,
    api_version = azure_conf.aoai.version,
    azure_endpoint = azure_conf.aoai.endpoint,
)

# SimCSEの設定
simcse_model = SentenceTransformer("cl-nagoya/sup-simcse-ja-large")
```

## ３．テキストのベクトル化
テキストデータをEmbeddingモデルに渡してベクトル（分散表現）を取得します。
AzureOpenAIを使用する場合は、モデル名(model)を指定する必要があります。
ここで得られる「ベクトル」とは、高次元の実数値を含んだ配列です。

```python
text = "こんにちは、世界"

# AzureOpenAIでベクトル化
vector = aoai_client.embeddings.create(
    input=text,
    model=azure_conf.aoai.deployName,
)
vector = vector.data[0].embedding

# SimCSEでベクトル化
vector = simcse_model.encode(text)
```

## ４．ベクトル同士の比較
ベクトル同士の比較にはユークリッド距離またはコサイン類似度を使うことが一般的です。
ここでは2通り試せるようにそれぞれのサンプルコードを示します。2つのベクトルをそれぞれの関数に入力すると、ベクトルの類似性を実数値で出力します。

```python
# ユークリッド距離
def euclid_dist(v1, v2):
    return np.linalg.norm(v1-v2)

# コサイン類似度
def cos_sim(v1, v2):
    return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
```

# 単語同士の比較
本記事では、日本語Wikipediaコーパスに収録されている単語同士の類似性をヒートマップにしてみました。

## ユークリッド距離を使った比較
類似性の高い単語同士はユークリッド距離が0に近い値をとります。

### AzureOpenAI
![sample0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456978/e7af980e-564a-dfb1-e12f-a50f937c6225.png)
### SimCSE
![sample0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456978/eb5a4da9-3e10-5d0f-613f-5ed4fc4c17cf.png)


## コサイン類似度を使った比較
類似性の高い単語同士はコサイン類似度が1に近い値をとります。

### AzureOpenAI
![sample0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456978/ce02b691-b492-ac34-d68e-75e69cca70e4.png)
### SimCSE
![sample0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456978/d3f9655c-afa7-200c-7715-dac4ad26c43d.png)

## 考察
SimCSEを使った場合の方が、似ている単語とそうでない単語の組み合わせがヒートマップの色の違いに顕著に表れています。
これは今回採用したSimCSEモデルが日本語データで学習されたものであったため、AzureOpenAIのEmbeddingモデルよりも単語の違いをより類似性尺度に反映できたからと考えられます。

# まとめ
今回はサンプルコードも交えてEmbeddingモデルを使ったベクトル化と、ベクトル同士の類似性比較をしました。Embeddingモデルと類似性尺度をそれぞれ2種類ずつ採用して試してみましたが、本記事で取り上げることができたものはほんの一部にすぎません。Embeddingモデルや類似性尺度、ベクトルストア、LLMを使うためのフレームワークなど、ぜひ様々な要素技術を比較してご自身の構築に役立ててみてください。