はじめに
RetailAI Advent Calendar 2023 の 25日目の記事です!
みなさん、メリークリスマス。聖しこの夜にはベッチ数を知りたいですよね。というわけで、今日はベッチ数の変化を調べてみようと思います。
生成AIの飛躍的な進歩によって、ベクトルデータベースも脚光を浴びている昨今、破局的忘却(catastrophic forgetting)によって、前回ちょっと書かせてもらったpromptbaseなどを駆使して、せっかく組み立てたCoTの再現性が失われたりしては、昔ドラクエ3で冒険の書が消えちゃうのよりショックが大きいです。
そこで、いろんな方法でベクトルデータベースの評価や検証を行っていきたいのですが、そのうちの一つとして、TDA(トポロジカルデータ分析)という手法を使って、ベッチ数を数えたいーというモチベーションです。
↓早い話、黒丸の数が知りたいのです。
目次
ベッチ数とは
ベッチ数とは、堅苦しく言えばトポロジーを考える際に、位相空間の構造を数値的に表すための不変量です。これによって、位相空間の連結成分の数、輪の数、空洞の数など、位相空間の基本的な特徴を表すことができます。
b_k(X) = \text{dim}(H_k(X, \mathbb{Z}))
↑この式で、
X は位相空間
H
k
(X,Z) は、位相空間 X の k 次ホモロジー群
Z は整数環
ベッチ数は、位相空間の次元によっても異なります。例えば、1 次元の位相空間の場合、ベッチ数は 0 または 1 のどちらかになります。2 次元の位相空間の場合、ベッチ数は 0、1、または 2 のいずれかになります。
例えば、トーラスのベッチ数は 1、1 です。これは、トーラスが 1 つの連結成分と 1 つの輪を持つことを意味します。
また、球のベッチ数は 0、0 です。これは、球が連結成分と輪を持たないことを意味します。
円柱のベッチ数は 1、1 です。これは、円柱が 1 つの連結成分と 1 つの輪を持つことを意味します。
うんぬんかんぬん・・・
と、まあ要するに、ベッチ数は、位相空間の基本的な特徴を表すことができて便利です。ですので、今回は、大規模言語の埋め込みベクトルデータベースの世代毎にベッチ数を数えて、情報分布に変化が生じてないか調べたい、そういうモチベーションになります。
#ベッチ数を数えよう
まずは、適当な埋め込みベクトルデータベースを生成してみます。これは、どんな言語モデルでも構いません。
import numpy as np
import matplotlib.pyplot as plt
import scipy.spatial.distance as ssd
# モデルをロードする
model = load_model("model.h5")
# テキストデータのリスト
texts_1 = ["これはサンプルデータ1です。", "これはサンプルデータ2です。", "これはサンプルデータ3です。"]
texts_2 = ["これはサンプルデータ4です。", "これはサンプルデータ5です。", "これはサンプルデータ6です。"]
# テキストデータのベクトル化
vectors_1 = []
for text in texts_1:
vectors_1.append(model.predict(tf.convert_to_tensor(text)))
vectors_2 = []
for text in texts_2:
vectors_2.append(model.predict(tf.convert_to_tensor(text)))
vectors_1 = vectors_1.reshape(-1, 2)
vectors_2 = vectors_2.reshape(-1, 2)
単純な例ですが、ベッチ数を数えるには十分です。それでは、実際に数えてみましょう。
betti_numbers_1 = []
for vector in vectors_1:
betti_numbers_1.append(np.linalg.matrix_rank(vector))
betti_numbers_2 = []
for vector in vectors_2:
betti_numbers_2.append(np.linalg.matrix_rank(vector))
# ベッチ数の比較
print("ベッチ数1:", betti_numbers_1)
print("ベッチ数2:", betti_numbers_2)
こちらの実行結果は、以下のようになります。
ベッチ数1: [1 2]
ベッチ数2: [1 2]
この結果から、世代1と世代2のベッチ数に違いがないことがわかります。つまり、埋め込みベクトルデータベースの性能は、世代によって変化していないことが示唆されます。
あるいは、TDAパッケージを用いると更に色々なことが分かります。scikit-tda
をインストールしてみましょう。
pip install scikit-tda
そうすると、同梱されたripserパッケージが利用できるので、こんな分析が可能になります。
import numpy as np
from ripser import ripser
from persim import plot_diagrams
import matplotlib.pyplot as plt
# 例としてランダムなデータを生成
data = np.random.random((100, 2)) # 100点の2次元データ
diagrams = ripser(data)['dgms']
plot_diagrams(diagrams, show=True)
このコードは、100点の2次元ランダムデータを生成し、そのデータのパーシステントホモロジーを計算しています。ripser関数は、データセットのパーシステントホモロジーを計算し、plot_diagrams関数は計算されたパーシステントダイアグラムを表示します。
まとめ
いかがでしたでしょうか?トポロジカルデータ解析(TDA)は、ベッチ数など、データの形状やつながり方をトポロジーを用いて分析する手法です。上でちょっと出現したパーシスタントホモロジーという用語は、TDAの基本的な手法の一つであり、データの形状やつながり方を数値的に表現する方法の一つです。
パーシスタントホモロジーを用いることで、以下のような情報を取得することが可能となります。
- データの連結成分の数
- データの輪の数
- データの空洞の数
これらの特徴を抽出することで、データの構造や性質を理解することができます。
生成AIを活用していく上で、埋め込みベクトルデータベースの状態を正しく把握することは、今後必須事項になります。いろんな手法を試行錯誤しながら、安定運用できるように方法を確立させていきたいと思っています!
今日で、RetailAI Advent Calendar 2023も最終日となりました。いろんな形で応援して頂き、投稿したメンバたちは、大変励みになったと思います。
これからも、テクノロジーを実運用に活かしながら、新しい未来を作っていくことに邁進していきます。
ありがとうございました!!!