- 王紹宇
- 約 4,600 文字
- 1,500 View
目次
はじめに
こんにちは。フューチャーTIG DXユニット所属の王です。
本記事は、夏の自由研究ブログ連載2023の4本目です。
今回はテキストの埋め込みエンコーダーを使ってセマンティック検索をおもちゃレベルで簡単に実装する方法を紹介します。分かりやすいように、YouTubeの動画のセリフをコーパスとして使用します。将来的に時間軸のメタ情報も利用したら、検索結果には動画の何分何秒に特定、遷移リンクの生成などもいろいろ面白いことができると思います。
セマンティック検索を注目するきっかけ
ChatGPTなどの生成AIが大ヒットしている現在、その応用場面は増加しており、自然言語で機械と会話し指示を与えたり情報を引いたりすることは今どきのトレンドになっています。しかし、生成AIを使用する際には、情報の最新性やファクトチェックの不足などの懸念点が存在します。これらの問題を低減するためには、なるべくコンテキストや背景情報など、比較的な高品質のインプットを提供し、生成式AIが得意な情報の抽出、変換、整形などのみ任せるのがうまい使い方でしょう。
生成AIに1回のクエリでインプットできる情報は限られていますので、事前に関係しそうな情報を粗く抽出するために、公開していないデータや特定のコーパスを使って、自然言語でクエリする際に、セマンティック検索が必要となります。
セマンティック検索(Semantic Search)とは
最初に、セマンティック検索と典型的なレキシカル検索(語彙検索、字句検索、Lexical Search)を比較します。レキシカル検索は、テキスト内の文字列や単語の表面的な一致に焦点を当てます。特定の文字列や単語がテキスト内に存在するかどうかを確認し、その一致度に基づいて情報を選別します。そのため、同義語や関連語、コンテキストに対応することが難しく、意味的な関連性を欠いた検索結果になり、自然言語のクエリに対する弱点があります。
一方、セマンティック検索は、キーワードだけでなく、文脈や意味に基づいて情報を検索するアプローチです。関連性やコンテキストを考慮し、より高度な情報検索を実現でき、同義語や関連語、さらに部分的な誤字などにも対応できるため、自然言語のクエリに適しています。
原理
テキストの埋め込みによってセマンティック検索の原理を簡単に説明します。
埋め込みベクトル(Embedding Vector)
コンピュータの世界には、文字だけではなく、画像、音声、動画などすべてのデータは符号化(Encoding)での表現ができます。それと似た思想で、単語、文、段落などを表す「意味」や「関連性」を数値のベクトルの表現で符号化に変換することは「埋め込み」と言います。その変換の条件は、意味が近い原文の変換後の埋め込みベクトルも距離が近いことです。
そうすることによって、統一化された表現形式「埋め込みベクトル」で「意味」の近さが定量的に表現で切るようになります。もちろん、文に対してベクトルの埋め込みは、深層学習などの技術を使って大量な事前計算が必要ですが、自ら訓練しても良いですし、後述のSentence-Transformerを利用して、公開の事前訓練された公開のモデルを簡単に使用できます。
ところで、ここの「距離」の定義は、ベクトルのドット積、コサイン類似度、ユークリッド距離など多数の形式はできますが、予め選定したら良いです。計算の簡単さを考慮したら、ユークリッド距離よりドット積、コサイン類似度のほうがよく採用されるでしょう。そしてベクトルを正規化(長さ1に統一する)のテクニックを使ったら、みんな等価になります。
さらに、もとの情報は文字に限らず、画像や音声、マルチメディアの情報も埋め込みベクトルに変換して数値化にしたら、文字と画像の距離や画像と音声の距離なども測ることが可能になります。画像や音声の類似検索、タグや説明文との紐付けなどいろいろ応用場面が可能になります。
埋め込みベクトルを使ったセマンティック検索
余談ですが、RDF (Resource Description Framework) を使用したセマンティック検索もありましたが、高度な事前定義と複雑のアルゴリズムが必要で実装は難しいです。今回ご紹介している埋め込みベクトルの手法は、事前のモデルの訓練での大量な計算でカバーしています。ただし、そのモデルの計算は、車輪の発明のように、大手が1度作ったら、誰でも繰り返して利用できて、恩恵を受けられます。これまで以上にAIの民主化を進めていますね。
さて、埋め込みベクトルを使ったセマンティック検索の手順を簡単にまとめます。
- 事前にデータベースやコーパスの情報を文や段落粒度を分割し、それぞれ高次元(数百から数千次元)のベクトルに埋め込みエンコーディング変換しておきます。
- クエリ文も同様に埋め込みエンコーディングして、ベクトル化して、それと距離が近いものが検索の候補結果になります。
- 計算した距離(近似度)がの検索のランキングになります。
- (Optional)そして、検索の動作を高速化するために、事前のコーパスにベクトルによってインデックスをつけることができます。後述のSimple Neighborsはインデックスの構造と高速化検索をやってくれます。
実装
使ったライブラリ
以下の2つのライブラリを使って実装しています。どれもシンプルなインターフェースを持って使いやすいと思います。
Sentence-Transformers
pipを使用して簡単にインストールできます。
pip install sentence-transformers |
Sentence-Transformersは、テキストだけではなく、画像のembeddingも対応できますが、今回はテキストの検索にフォーカスしたいので割愛します。画像の検索の詳細はこのページをご参考ください。
Sentence-Transformersのフレームワークがhuggingfaceで多数のモデルが公開しています(執筆時点124個)。
モデルの命名について、qaがついているモデルは、(質問、回答) ペアのセットでトレーニングされて、セマンティック検索用です。つまり、クエリ/質問が与えられた場合、関連する文章を見つける用途です。そして、multiがついているモデルは、多言語対応のモデルです。違う言語のインプットであっても、意味が似たものなら埋め込みベクトルの距離が近いようにエンコーディングしてくれます。ちなみに、最初から多言語のデータを使わず、例えばまずは英語で訓練して、そのモデルを教師モデルとして利用し、更に多言語に拡張する手法もあるらしく、興味深いです。
Simple Neighbors
https://simpleneighbors.readthedocs.io/en/latest/
コーパスの項目に対して最近傍検索するための簡単なインターフェースです。Annoy、Sklearn、BruteForcePurePythonの3つのバックエンドをサポートしていますが、Annoyが推奨していますので、それも一緒にインストールします。
pip install simpleneighbors annoy |
高速に検索するため、事前にindexのツリーをビルドする必要があります。つまり、検索対象のデータを増加したら、改めてツイリーのビルドが必要という点に要注意です。
また、N-Neighborを探す結果は近似的な結果になることにもご注意ください。とはいえ、訓練のモデルから検索結果の精度はすべて有限であるので、近似と言っても十分な精度が保証できていると思います(参考: Approximate Nearest Neighbors)
Semantic Searchの実装
今回はこのドキュメントを参考して、実装してみました。
https://www.sbert.net/examples/applications/semantic-search/README.html
まずは、フューチャーの会社紹介ページのYouTube動画のセリフをcorpus/future.txtファイルに保存します。今回は手動で前処理として文と文の間に改行で区切りました。
(※YouTubeから自動生成のセリフで誤字などが入っています。一旦無視します。
ただし、「フューチャー」が「Qちゃん」になっているのはみっともないので手修正を加えました。)
皆さん、こんにちは。 |
今回はこのページに紹介したモデルの中に、multi言語対応のモデルをピックアップし、予めメタデータとして用意します。モデル名name、ベクトルの次元dims、距離関数metricの属性を定義します。方便上、名前でモデルを引く関数find_model_with_nameも定義します。
models = [ |
以下はSemanticSearchクラスでシンプルにベーシックな機能(モデルを読み込み、corpusの読み込み、エンコードして文をベクトル化すし、vector tree indexのビルド、そして、N個の最近傍探索)を実装します。
from sentence_transformers import SentenceTransformer, util |
早速、クエリを投げてみます。
if __name__ == "__main__": |
出力結果1
('フューチャーは1989年にエンジニアが立ち上げたITコンサルティング企業です。', 0.2547425627708435) |
文章に「創立」などのキーワードが登場していないですけど、1個目近似度高い文(時間に関して述べているからかもしれません)がうまくヒットしています。
今度は他のモデルでやってみます。
モデル:paraphrase-multilingual-MiniLM-L12-v2
クエリ:フューチャーはいつ創立されましたか。
出力結果2
('昨今、DXと盛んに叫ばれるようになりましたが、私たちフューチャーは経営と業務、そしてその裏にあるシステムは切っても切り離せないものだと創業当初から考えて、それらを三位一体で捉えて推進するということを30年以上続けてきました。', 0.45087340474128723) |
結果が変わりましたが、「昨今」や「創業」や「30年」が含まれた文はトップになっています。まあまあ許容できる結果でしょう。
他の質問とモデルでもやってみます。
モデル:paraphrase-multilingual-MiniLM-L12-v2
クエリ:未来報はなんですか。
出力結果3
('フューチャーのオウンドメディア未来報では、フューチャーの人に焦点を当ててキャリアやカルチャーをご紹介しています。', 0.5177506804466248) |
モデル:multi-qa-mpnet-base-dot-v1
クエリ:長所はなに
出力結果4
(※このモデルは、他のコサイン類似度とは違ってドット積で距離を評価しているので、1以上の距離結果がありうる)
('そしてそれを30年以上続けてきたというのはなかなか他の会社には簡単に真似できないフューチャーならではの強みになっています。', 18.705921173095703) |
今度は、英語のコーパスを利用して、日本語で質問してみます。
HuggingFace出品の「Text embeddings & semantic search」を紹介するこのビデオのセリフを引っ張ってきます。corpus/semantic_search.txtに保存します。
Text embeddings and semantic search. |
同じように、それをロードして、日本語のクエリで投げてみます。
if __name__ == "__main__": |
出力結果5
それなりにいい感じにヒットできていますね。
('To create these embeddings we usually use an encoder-based model like BERT.', 0.6005619764328003) |
モデル:distiluse-base-multilingual-cased-v1
クエリ:セマンティック検索には、どんなテクニックが使えるか
出力結果6
('Text embeddings and semantic search.', 0.3169878125190735) |
まとめ
本記事では、セマンティック検索の概念や原理を簡単に説明しました。そして埋め込みベクトルの実装をシンプルに実現してデモしました。言語問わずにクエリを投げて、そこそこの精度の検索ランキングの結果が得ました。
AIの民主化が発展している現在、いろいろの技術のハードルが下がってきて、中小企業や一般の人々にも簡単に利用・導入可能になり、そのオポテュニティーをうまく掴める組織と人間こそ未来の勝者になるでしょう。
では、ようこそ〜 Futureへ!
