Closed12

RAGatouilleを試す(JaColBERTv2)

kun432kun432

DSPyで調べてて拾ったので少し調べてみる

https://twitter.com/fblissjr/status/1745905685122932761

https://github.com/bclavie/RAGatouille

RAGatouilleの主な動機は単純で、最先端の研究と錬金術的なRAGパイプラインの実践とのギャップを埋めることである。RAGは複雑で、多くの可動部分があります。最高のパフォーマンスを得るためには、多くのコンポーネントを最適化する必要がある。その中でも非常に重要なのは、検索に使用するモデルである。

密な検索、つまりOpenAIのtext-ada-002のような埋め込みを使用することは良いベースラインですが、密な埋め込みがあなたのユースケースに最適でないかもしれないことを示す多くの研究があります。

情報検索の研究分野は最近活況を呈しており、ColBERTのようなモデルは、密な埋め込みよりも新しいドメインや複雑なドメインに対してより良く汎化することが示されています!残念なことに、これらの新しいアプローチのほとんどはあまり知られておらず、密な埋め込みよりもずっと使いにくい。

そこでRAGatouilleの登場です: RAGatouilleの目的は、このギャップを埋めることです:詳細や長年の文献を気にすることなく、RAGパイプラインで最先端の手法を簡単に使えるようにすることです!現時点では、RAGatouilleはColBERTを簡単に使えるようにすることに重点を置いています。次に何が出てくるかをチェックしたい場合は、私たちの幅広いロードマップをご覧ください!

ColBERTが使用する動機、哲学、レイトインタラクションアプローチがなぜうまく機能するのかについてもっと読みたい方は、ドキュメントのイントロダクションをご覧ください。

試してみたい?pip install ragatouilleを実行するだけです!

kun432kun432

https://secon.dev/entry/2024/02/02/080000/

先日公開された、ColBERT の日本語pretrainモデル、JaColBERTの性能が良いらしい。早速、普段評価に利用している、AIクイズ王のQ&A RAGタスクで評価してみた。
結果としては、multilingual-e5-large よりわずかに低い、という結果となった。学習データも少なく、モデルサイズも12層のBert(= multilingual-e5-smallと同じサイズ)とほとんど一緒なのにね、すごい。

ColBERTはいわゆるSentenceTransformer等を用いて文からEmbeddings(文ベクトル)を出力して類似度比較で検索、ではなくトークンベースの類似度検索だ。文の最終隠れ層は、その文章のコンテキスト文脈の情報をトークン単位でも持っているので、文全体ではなくトークン単位で使って類似度を算出する。

ColBERT の実装は読んでみて分かったが、処理の複雑性とそもそもの実装コードの複雑性も相まって、サクッと使うのが難しい。それを解消するために、ゼロコンフィグでもすぐに使えるアプローチが RAGatouille である。今回の評価にもRAGatouilleを利用した。

RAGatouille はインデクスの作成・検索はもちろん、Trainerで学習させることもできる。また、LangChain の retriver にすることもできるなど、今風の対応も入っている。

なるほど、ColBERTを使いやすくしたのがRAGatouilleという風に認識した。

kun432kun432

Colaboratoryで。ランタイムはデフォルト(CPU)で。

日本語の場合はJaColBERTv2を使う
https://huggingface.co/bclavie/JaColBERTv2

以下にRagatouilleのサンプルnotebookがいくつかあるので、これのモデルをJaColBERTv2に書き換えてやってみる。
https://github.com/bclavie/RAGatouille/tree/main/examples/

まずこれ

Basic indexing and searching with RAGatouille
https://github.com/bclavie/RAGatouille/blob/main/examples/01-basic_indexing_and_search.ipynb

Ragatouilleのパッケージをインストール

!pip install -U ragatouille

日本語の場合は以下も必要

!pip install fugashi unidic-lite

モデルのロード。JaColBERTv2を指定。

from ragatouille import RAGPretrainedModel

RAG = RAGPretrainedModel.from_pretrained("bclavie/JaColBERTv2")

RAGのドキュメントにWikipediaのコンテンツを使う。コンテンツを取得するためのヘルパー関数。

import requests

def get_wikipedia_page(title: str):
    """
    Wikipediaのページの全文を取得する

    :param title: str - Wikipediaのページのタイトル
    :return: str - ページの全文(生の文字列)
    """
    # Wikipedia API エンドポイント ※日本語版
    URL = "https://ja.wikipedia.org/w/api.php"

    # APIリクエストのパラメータ
    params = {
        "action": "query",
        "format": "json",
        "titles": title,
        "prop": "extracts",
        "explaintext": True,
    }

    # Wikipediaのベストプラクティスに準拠するためのカスタムUser-Agentヘッダー
    headers = {
        "User-Agent": "RAGatouille_tutorial/0.0.1 (kun432.8d1w@gmail.com)"
    }

    response = requests.get(URL, params=params, headers=headers)
    data = response.json()

    # ページの内容を抽出
    page = next(iter(data['query']['pages'].values()))
    return page['extract'] if 'extract' in page else None

試しに以下を取得。

https://ja.wikipedia.org/wiki/オグリキャップ

sample_document = get_wikipedia_page("オグリキャップ")

print(len(sample_document))
print(sample_document[:100])
36186
オグリキャップ(欧字名:Oguri Cap、1985年3月27日 - 2010年7月3日)は、日本の競走馬、種牡馬。
1987年5月に岐阜県の地方競馬・笠松競馬場でデビュー。8連勝、重賞5勝を含む12

ドキュメントからインデックスを作成

RAG.index(
    collection=[sample_document],
    document_ids=['oguricap'],
    document_metadatas=[{"entity": "oguricap", "source": "wikipedia"}],
    index_name="jra_race_horses",
    # ドキュメントをチャンク分割するか
    split_documents=True,
    # ドキュメントの長さ、これ以上の長さであればチャンクに分割する
    max_document_length=400,
    )

以下のようなWarningが出る。

---- WARNING! You are using PLAID with an experimental replacement for FAISS for greater compatibility ----
This is a behaviour change from RAGatouille 0.8.0 onwards.
This works fine for most users and smallish datasets, but can be considerably slower than FAISS and could cause worse results in some situations.
If you're confident with FAISS working on your machine, pass use_faiss=True to revert to the FAISS-using behaviour.
--------------------

なるほど、FAISSは高速だけど使いにくいので、実験的に切り替えを行っているらしい。

https://twitter.com/bclavie/status/1769814738127462668

https://twitter.com/bclavie/status/1769814740182704602

ここはとりあえず気にせず進める。

以下のような感じでインデックスが作成された。

[Jul 24, 22:25:58] #> Creating directory .ragatouille/colbert/indexes/jra_race_horses 


[Jul 24, 22:26:01] [0] 		 #> Encoding 122 passages..
/usr/local/lib/python3.10/dist-packages/torch/amp/grad_scaler.py:131: UserWarning: torch.cuda.amp.GradScaler is enabled, but CUDA is not available.  Disabling.
  warnings.warn(
  0%|          | 0/4 [00:00<?, ?it/s]/usr/local/lib/python3.10/dist-packages/torch/amp/autocast_mode.py:250: UserWarning: User provided device_type of 'cuda', but CUDA is not available. Disabling
  warnings.warn(
100%|██████████| 4/4 [01:54<00:00, 28.54s/it][Jul 24, 22:27:55] [0] 		 avg_doclen_est = 204.12295532226562 	 len(local_sample) = 122
[Jul 24, 22:27:55] [0] 		 Creating 2,048 partitions.
[Jul 24, 22:27:55] [0] 		 *Estimated* 24,903 embeddings.
[Jul 24, 22:27:56] [0] 		 #> Saving the indexing plan to .ragatouille/colbert/indexes/jra_race_horses/plan.json ..

used 20 iterations (24.7817s) to cluster 23658 items into 2048 clusters
[0.034, 0.036, 0.036, 0.036, 0.033, 0.035, 0.036, 0.035, 0.035, 0.032, 0.035, 0.036, 0.033, 0.034, 0.033, 0.035, 0.036, 0.03, 0.035, 0.034, 0.036, 0.039, 0.034, 0.038, 0.032, 0.037, 0.036, 0.038, 0.034, 0.036, 0.035, 0.033, 0.033, 0.033, 0.033, 0.034, 0.035, 0.034, 0.032, 0.044, 0.034, 0.038, 0.032, 0.035, 0.037, 0.035, 0.034, 0.035, 0.035, 0.038, 0.038, 0.034, 0.036, 0.038, 0.034, 0.035, 0.035, 0.036, 0.04, 0.032, 0.036, 0.035, 0.035, 0.033, 0.034, 0.032, 0.036, 0.038, 0.039, 0.034, 0.036, 0.035, 0.035, 0.033, 0.034, 0.038, 0.034, 0.034, 0.033, 0.035, 0.036, 0.035, 0.035, 0.037, 0.036, 0.034, 0.035, 0.031, 0.038, 0.036, 0.037, 0.035, 0.036, 0.038, 0.036, 0.035, 0.035, 0.039, 0.036, 0.039, 0.034, 0.036, 0.033, 0.036, 0.036, 0.039, 0.034, 0.036, 0.034, 0.04, 0.034, 0.036, 0.037, 0.034, 0.038, 0.036, 0.035, 0.034, 0.036, 0.04, 0.037, 0.037, 0.031, 0.035, 0.039, 0.03, 0.033, 0.035]
0it [00:00, ?it/s][Jul 24, 22:28:20] [0] 		 #> Encoding 122 passages..

  0%|          | 0/4 [00:00<?, ?it/s]
 25%|██▌       | 1/4 [00:30<01:32, 30.90s/it]
 50%|█████     | 2/4 [00:59<00:59, 29.82s/it]
 75%|███████▌  | 3/4 [01:29<00:29, 29.47s/it]
100%|██████████| 4/4 [01:53<00:00, 28.32s/it]
1it [01:54, 114.84s/it]
100%|██████████| 1/1 [00:00<00:00, 928.56it/s][Jul 24, 22:30:15] #> Optimizing IVF to store map from centroids to list of pids..
[Jul 24, 22:30:15] #> Building the emb2pid mapping..
[Jul 24, 22:30:15] len(emb2pid) = 24903

100%|██████████| 2048/2048 [00:00<00:00, 45463.58it/s][Jul 24, 22:30:15] #> Saved optimized IVF to .ragatouille/colbert/indexes/jra_race_horses/ivf.pid.pt
Done indexing!

インデックスは、.ragatouille/colbert/indexes/[インデックス名]として圧縮保存された形で保持され、後で読み出して使うこともできる。

では検索してみる。

results = RAG.search(query="オグリキャップの母は?", k=5)
results

初回だけロードに時間がかかる様子。

Loading searcher for index jra_race_horses for the first time... This may take a few seconds
[Jul 24, 22:35:28] #> Loading codec...
[Jul 24, 22:35:29] #> Loading IVF...
[Jul 24, 22:35:29] Loading segmented_lookup_cpp extension (set COLBERT_LOAD_TORCH_EXTENSION_VERBOSE=True for more info)...
[Jul 24, 22:36:03] #> Loading doclens...
100%|██████████| 1/1 [00:00<00:00, 3221.43it/s][Jul 24, 22:36:03] #> Loading codes and residuals...

100%|██████████| 1/1 [00:00<00:00, 182.35it/s][Jul 24, 22:36:03] Loading filter_pids_cpp extension (set COLBERT_LOAD_TORCH_EXTENSION_VERBOSE=True for more info)...

[Jul 24, 22:36:37] Loading decompress_residuals_cpp extension (set COLBERT_LOAD_TORCH_EXTENSION_VERBOSE=True for more info)...
Searcher loaded!

結果

[{'content': 'オグリキャップの母・ホワイトナルビーは競走馬時代に馬主の小栗孝一が所有し、笠松競馬場の調教師鷲見昌勇が管理した。ホワイトナルビーが繁殖牝馬となった後はその産駒の競走馬はいずれも小栗が所有し、鷲見が管理していた。\n1984年のホワイトナルビーの交配相手には、小栗によると当初はトウショウボーイが種付けされる予定だったが、種付け予定に空きがなかったため断念した。そこで小栗の意向により、笠松競馬で優れた種牡馬成績を残していたダンシングキャップが選ばれた。',
  'score': 25.329814910888672,
  'rank': 1,
  'document_id': 'oguricap',
  'passage_id': 2,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'あれほどの騎手に、オグリがいちばん体調がよくない時に乗ってもらったんですから」と、増沢を庇う言葉を残している。\n\n父・ダンシングキャップの種牡馬成績はさほど優れていなかったため、オグリキャップは「突然変異で生まれた」、もしくは「(2代父の)ネイティヴダンサーの隔世遺伝で生まれた競走馬である」と主張する者もいた。一方で血統評論家の山野浩一は、ダンシングキャップを「一発ある血統」と評し、ネイティヴダンサー系の種牡馬は時々大物を出すため、「オグリキャップに関しても、そういう金の鉱脈を掘り当てたんでしょう」と分析している。\n母・ホワイトナルビーは現役時代は笠松で4勝を挙げ、産駒は全て競馬の競走で勝利を収めている(ただしほとんどの産駒は地方競馬を主戦場としていた)。',
  'score': 22.600013732910156,
  'rank': 2,
  'document_id': 'oguricap',
  'passage_id': 110,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '同年9月29日には同競馬場で初勝利を挙げた。\n繁殖入りした牝馬も少なく、34頭しかいない。2017年にラインミーティア(父メイショウボーラー、母の母の父がオグリキャップ)がアイビスサマーダッシュを勝利し、オグリキャップの血を引く馬としては初めて重賞を制覇した。しかし、34頭のうち産駒が繁殖牝馬となった馬もほとんどおらず、オグリキャップの血を引く繁殖牝馬は急激に減少している。\n2020年10月にホワイトシスネ(母キョウワスピカ、母父オグリキャップ)がホッカイドウ競馬を登録抹消となり一旦はオグリキャップの孫世代の現役競走馬がいなくなった。その後、2021年4月にミンナノアイドルの産駒であるミンナノヒーロー(父ゴールドアリュール、母父オグリキャップ)が岩手競馬でデビュー。',
  'score': 21.67919921875,
  'rank': 3,
  'document_id': 'oguricap',
  'passage_id': 66,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '後に馬術競技馬「ワダルコ」となる。\nアラマサキャップ - クイーンステークス2着。孫にアイビスサマーダッシュの勝ち馬ラインミーティアがいる。\nオグリワン - ききょうステークス、小倉3歳ステークス2着。\nノーザンキャップ - 中央競馬3勝、種牡馬。産駒のクレイドルサイアーが種牡馬登録されている。\nオグリエンゼル - 地方競馬27勝、如月賞\nアンドレアシェニエ - 地方競馬14勝、オグリキャップ産駒最後の現役競走馬。2012年7月死亡。\nミンナノアイドル - オグリキャップ最後の産駒。母グレイスクイン。馬主はローレルクラブ。\nRocks Rule - 母のワカシラユキがアイルランドで出産。2010年3月9日、イギリスニューカッスル競馬場の障害馬用の平地競走で初出走初勝利。',
  'score': 21.609539031982422,
  'rank': 4,
  'document_id': 'oguricap',
  'passage_id': 64,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '5代母のクインナルビー(父:クモハタ)は1953年の天皇賞(秋)を制している。クインナルビーの子孫には他にアンドレアモン、キョウエイマーチなどの重賞勝ち馬がいる。\n\n兄弟\nオグリローマン - 1994年桜花賞優勝馬\nオグリイチバン - オグリキャップの活躍を受けてシンジケートを組まれ種牡馬となった。\nオグリトウショウ - オグリキャップの活躍後に誕生し、デビュー前から話題を集めた。競走馬引退後はオグリイチバンと同様、種牡馬となった。\n\n書籍\n\n朝日新聞論説委員室『天声人語 2010年7月-12月』朝日新聞出版、2011年。ISBN 4022508469。 \n阿部珠樹『有馬記念物語 世界最大のレースの魅力を追う』青春出版社〈プレイブックス・インテリジェンス〉、2003年。ISBN 4413040805。',
  'score': 21.27869415283203,
  'rank': 5,
  'document_id': 'oguricap',
  'passage_id': 111,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}}]

別の検索

results = RAG.search(query="オグリキャップの主な勝ち鞍は?", k=5)
results
[{'content': 'オグリキャップ(欧字名:Oguri Cap、1985年3月27日 - 2010年7月3日)は、日本の競走馬、種牡馬。\n1987年5月に岐阜県の地方競馬・笠松競馬場でデビュー。8連勝、重賞5勝を含む12戦10勝を記録した後、1988年1月に中央競馬へ移籍し、重賞12勝(うちGI4勝)を記録した。1988年度のJRA賞最優秀4歳牡馬、1989年度のJRA賞特別賞、1990年度のJRA賞最優秀5歳以上牡馬および年度代表馬。1991年、JRA顕彰馬に選出。愛称は「オグリ」「芦毛の怪物」など多数。',
  'score': 23.554176330566406,
  'rank': 1,
  'document_id': 'oguricap',
  'passage_id': 0,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'オグリキャップは第3コーナーで最後方の位置から馬群の外を通って前方へ進出を開始し、ゴール直前で先頭に立って優勝した。\nオグリキャップは初代馬主の小栗孝一が中央で走らせるつもりがなかったことでクラシック登録をしていなかったため、前哨戦である毎日杯を優勝して本賞金額では優位に立ったものの皐月賞に登録できず、代わりに京都4歳特別に出走した。このレースでは翌1989年の全戦に騎乗することとなる南井克巳が鞍上を務め、オグリキャップ一頭だけが58キロの斤量を背負ったが第3コーナーで後方からまくりをかけ、優勝した。\nクラシック登録をしていないオグリキャップは東京優駿(日本ダービー)にも出走することができず、代わりに「断念ダービー」と言われていたニュージーランドトロフィー4歳ステークスに出走した。',
  'score': 22.54889678955078,
  'rank': 2,
  'document_id': 'oguricap',
  'passage_id': 15,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'オグリキャップの騎手は何度も交替した。以下、オグリキャップに騎乗した主な騎手と騎乗した経緯について記述する。\n\n安藤勝己\nデビュー当初のオグリキャップには高橋一成(鷲見厩舎の所属騎手)と青木達彦が騎乗していたが、6戦目のレースではいずれも騎乗することができなかったため、当時笠松競馬場のリーディングジョッキーであった安藤が騎乗し、以降は安藤がオグリキャップの主戦騎手を務めた。安藤はオグリキャップに騎乗した中でもっとも思い出に残るレースとして、楽に勝たせようと思い早めに先頭に立った結果オグリキャップが気を抜いてマーチトウショウとの競り合いになり、目一杯に追う羽目になった7戦目のジュニアクラウンを挙げている。',
  'score': 22.350475311279297,
  'rank': 3,
  'document_id': 'oguricap',
  'passage_id': 101,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '続く高松宮杯では、中央競馬移籍後初の古馬との対戦、特に重賞優勝馬でありこの年の宝塚記念で4着となったランドヒリュウとの対戦にファンの注目が集まった。レースではランドヒリュウが先頭に立って逃げたのに対してオグリキャップは序盤は4番手に位置して第3コーナーから前方への進出を開始する。第4コーナーで2番手に立つと直線でランドヒリュウをかわし、中京競馬場芝2000mのコースレコードを記録して優勝した。この勝利により、地方競馬からの移籍馬による重賞連勝記録である5連勝を達成した。\n高松宮杯のレース後、陣営は秋シーズンのオグリキャップのローテーションを検討し、毎日王冠を経て天皇賞(秋)でGIに初出走することを決定した。',
  'score': 22.327320098876953,
  'rank': 4,
  'document_id': 'oguricap',
  'passage_id': 17,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'また、日本馬主協会連合会が史誌『日本馬主協会連合会40年史』(2001年)の中で、登録馬主を対象に行ったアンケートでは、「一番印象に残る競走馬」の部門で第1位を獲得、「一番印象に残っているレース」の部門でも、ラストランの第35回有馬記念が第38回有馬記念(トウカイテイオー優勝)と同率での第1位(504票中19票)に選ばれた。「一番の名馬」部門では第5位(第1位はシンザン)、「一番好きな競走馬」部門では第9位(第1位はハイセイコー)だった。\n\n競走馬名「オグリキャップ」の由来は、馬主の小栗が使用していた冠名「オグリ」に父ダンシングキャップの馬名の一部「キャップ」を加えたものである。',
  'score': 22.116165161132812,
  'rank': 5,
  'document_id': 'oguricap',
  'passage_id': 88,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}}]

バッチもできる。

batch_results = RAG.search(query=["オグリキャップの父は?", "オグリキャップの母は?"], k=3)
batch_results
[[{'content': 'あれほどの騎手に、オグリがいちばん体調がよくない時に乗ってもらったんですから」と、増沢を庇う言葉を残している。\n\n父・ダンシングキャップの種牡馬成績はさほど優れていなかったため、オグリキャップは「突然変異で生まれた」、もしくは「(2代父の)ネイティヴダンサーの隔世遺伝で生まれた競走馬である」と主張する者もいた。一方で血統評論家の山野浩一は、ダンシングキャップを「一発ある血統」と評し、ネイティヴダンサー系の種牡馬は時々大物を出すため、「オグリキャップに関しても、そういう金の鉱脈を掘り当てたんでしょう」と分析している。\n母・ホワイトナルビーは現役時代は笠松で4勝を挙げ、産駒は全て競馬の競走で勝利を収めている(ただしほとんどの産駒は地方競馬を主戦場としていた)。',
   'score': 23.717721939086914,
   'rank': 1,
   'document_id': 'oguricap',
   'passage_id': 110,
   'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
  {'content': 'なお、父のダンシングキャップは一般的に「ダートの短距離血統」という評価をされていた。\n\n鷲見昌勇はオグリキャップが3歳の時点で「五十年に一頭」「もうあんなにすごい馬は笠松からは出ないかもしれない」と述べている。安藤勝己は初めて調教のためにオグリキャップに騎乗したとき、厩務員の川瀬に「どえらい馬だね。来年は間違いなく東海ダービーを取れる」と言った。安藤のオグリキャップに対する評価は高く、3歳の時点で既に「オグリキャップを負かすとすればフェートノーザンかワカオライデンのどちらか」と考えていた。\n河内洋は初めて騎乗したペガサスステークスについて「とても長くいい脚を使えたし、これはかなり走りそうだと思ったよ。',
   'score': 23.18995475769043,
   'rank': 2,
   'document_id': 'oguricap',
   'passage_id': 80,
   'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
  {'content': '同年9月29日には同競馬場で初勝利を挙げた。\n繁殖入りした牝馬も少なく、34頭しかいない。2017年にラインミーティア(父メイショウボーラー、母の母の父がオグリキャップ)がアイビスサマーダッシュを勝利し、オグリキャップの血を引く馬としては初めて重賞を制覇した。しかし、34頭のうち産駒が繁殖牝馬となった馬もほとんどおらず、オグリキャップの血を引く繁殖牝馬は急激に減少している。\n2020年10月にホワイトシスネ(母キョウワスピカ、母父オグリキャップ)がホッカイドウ競馬を登録抹消となり一旦はオグリキャップの孫世代の現役競走馬がいなくなった。その後、2021年4月にミンナノアイドルの産駒であるミンナノヒーロー(父ゴールドアリュール、母父オグリキャップ)が岩手競馬でデビュー。',
   'score': 22.28539276123047,
   'rank': 3,
   'document_id': 'oguricap',
   'passage_id': 66,
   'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}}],
 [{'content': 'オグリキャップの母・ホワイトナルビーは競走馬時代に馬主の小栗孝一が所有し、笠松競馬場の調教師鷲見昌勇が管理した。ホワイトナルビーが繁殖牝馬となった後はその産駒の競走馬はいずれも小栗が所有し、鷲見が管理していた。\n1984年のホワイトナルビーの交配相手には、小栗によると当初はトウショウボーイが種付けされる予定だったが、種付け予定に空きがなかったため断念した。そこで小栗の意向により、笠松競馬で優れた種牡馬成績を残していたダンシングキャップが選ばれた。',
   'score': 25.32981300354004,
   'rank': 1,
   'document_id': 'oguricap',
   'passage_id': 2,
   'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
  {'content': 'あれほどの騎手に、オグリがいちばん体調がよくない時に乗ってもらったんですから」と、増沢を庇う言葉を残している。\n\n父・ダンシングキャップの種牡馬成績はさほど優れていなかったため、オグリキャップは「突然変異で生まれた」、もしくは「(2代父の)ネイティヴダンサーの隔世遺伝で生まれた競走馬である」と主張する者もいた。一方で血統評論家の山野浩一は、ダンシングキャップを「一発ある血統」と評し、ネイティヴダンサー系の種牡馬は時々大物を出すため、「オグリキャップに関しても、そういう金の鉱脈を掘り当てたんでしょう」と分析している。\n母・ホワイトナルビーは現役時代は笠松で4勝を挙げ、産駒は全て競馬の競走で勝利を収めている(ただしほとんどの産駒は地方競馬を主戦場としていた)。',
   'score': 22.60001564025879,
   'rank': 2,
   'document_id': 'oguricap',
   'passage_id': 110,
   'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
  {'content': '同年9月29日には同競馬場で初勝利を挙げた。\n繁殖入りした牝馬も少なく、34頭しかいない。2017年にラインミーティア(父メイショウボーラー、母の母の父がオグリキャップ)がアイビスサマーダッシュを勝利し、オグリキャップの血を引く馬としては初めて重賞を制覇した。しかし、34頭のうち産駒が繁殖牝馬となった馬もほとんどおらず、オグリキャップの血を引く繁殖牝馬は急激に減少している。\n2020年10月にホワイトシスネ(母キョウワスピカ、母父オグリキャップ)がホッカイドウ競馬を登録抹消となり一旦はオグリキャップの孫世代の現役競走馬がいなくなった。その後、2021年4月にミンナノアイドルの産駒であるミンナノヒーロー(父ゴールドアリュール、母父オグリキャップ)が岩手競馬でデビュー。',
   'score': 21.679195404052734,
   'rank': 3,
   'document_id': 'oguricap',
   'passage_id': 66,
   'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}}]]
kun432kun432

すでに作成済みのインデックスをロードする場合。別名で作成してみる。

from ragatouille import RAGPretrainedModel

RAG_2 = RAGPretrainedModel.from_index(".ragatouille/colbert/indexes/jra_race_horses")
results = RAG_2.search(query="オグリキャップが不振に陥った理由は?", k=5)
results
[{'content': '池江は撮影スタッフの振る舞いについて次のように証言している。\n\n池江によると、オグリキャップはテレビ取材のカメラに一日中追いかけられた事で「それまではカイバを食べている鼻先にカメラを近づけられても全然気にしていなかったのに、極端にカメラを怖がるようになってしまった」と述べている。\n体調に関しては、第35回有馬記念に優勝した時ですらよくなかったという証言が複数ある。オグリキャップと調教を行ったオースミシャダイの厩務員出口光雄や同じレースに出走したヤエノムテキの担当厩務員(持ち乗り調教助手)の荻野功がレース前の時点で体調の悪化を指摘していたほか、騎乗した武豊もパドックで跨った時の事について「あまり元気がないなという雰囲気でした」と、レース後には「ピークは過ぎていたでしょうね。',
  'score': 21.928768157958984,
  'rank': 1,
  'document_id': 'oguricap',
  'passage_id': 43,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '調教師の瀬戸口は、この年の秋のオグリキャップは骨膜炎に苦しんでいたと述べている。また、厩舎関係者以外からも体調の悪さを指摘する声が挙がっていた。天皇賞(秋)出走時の体調について瀬戸口は急仕上げ(急いで臨戦態勢を整えること)による影響もあったことを示唆している。厩務員の池江は、馬体の回復を考えれば競走馬総合研究所常磐支所の温泉療養施設にもう少し滞在したかったと述べている。\n精神面に関しては、瀬戸口と池江はともに気迫・気合いの不足を指摘していた。さらに池江は、天皇賞(秋)の臨戦過程においてテレビ番組の撮影スタッフが密着取材を行ったことによりオグリキャップにストレスが生じたと証言している。',
  'score': 21.928531646728516,
  'rank': 2,
  'document_id': 'oguricap',
  'passage_id': 42,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '1994年に産駒がデビューし、JRA新種牡馬リーディングにおいては首位となったサンデーサイレンスに大きく水をあけられたものの、内国産種牡馬としては最上位となる6位にランクインし、アーニングインデックスは1.75を記録した。しかし、後述の喉嚢炎を発症したことがきっかけで年を経るごとに交配牝馬のレベルが徐々に低下し、シンジケートが再結成された1996年からは交配頭数も減少し、1998年にはわずか10頭にまで落ち込んだ。\n\n1991年7月28日、オグリキャップが馬房の隅でぐったりとしているのが発見され、発熱、咳、鼻水などの症状がみられるようになった。',
  'score': 21.700668334960938,
  'rank': 3,
  'document_id': 'oguricap',
  'passage_id': 57,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '元気そうに見えてもやはり生き物だから」と述べ、オグリキャップに疲れがあった状態で出走させてしまったことを認めた。辻本も「少しは疲れはあったと思う」と認めて「ここまで本当によく頑張ってくれた」とオグリキャップの苦労を称えた。南井克巳も有馬記念直後のインタビューで、敗因は前に行きすぎた事かもしれないとしつつ、「追い切りがこの馬にしては物足りない気もした」と語った。南井は2010年7月29日に行われた「お別れ会」での挨拶の場において、この年のローテーションを回顧し、「天性のタフな資質に、厩舎の力が加わったからこそ、ああいうローテーションでも状態が維持できたのでしょう」と述べている。\n\n一時は1989年一杯で競走馬を引退すると報道されたオグリキャップであったが、1990年も現役を続行することになった。',
  'score': 21.54414939880371,
  'rank': 4,
  'document_id': 'oguricap',
  'passage_id': 35,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '陣営はかねてからの目標であった天皇賞(秋)出走を目指し、8月末にオグリキャップを栗東トレーニングセンターへ移送したが、10月上旬にかけて次々と脚部に故障を発症して調整は遅れ、「天皇賞回避濃厚」という報道もなされた。最終的に出走が決定し、このレースでは増沢末夫が鞍上を務めたが、レースでは序盤から折り合いを欠き、直線で伸びを欠いて6着に敗れた。続くジャパンカップに向けた調教では一緒に走行した条件馬を相手に遅れをとり、体調が不安視された。レースでは最後方から追走し、第3コーナーから前方への進出を開始したが直線で伸びを欠き、11着に敗れた(レースに関する詳細については第10回ジャパンカップを参照)。',
  'score': 21.509822845458984,
  'rank': 5,
  'document_id': 'oguricap',
  'passage_id': 39,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}}]
kun432kun432

インデックスへのドキュメントの追加

sample_document_2 = get_wikipedia_page("キタサンブラック")

RAG.add_to_index([sample_document_2])

でもいいのだけども、最初に作ったドキュメントはこうしていた

ドキュメントからインデックスを作成

RAG.index(
   collection=[sample_document],
   document_ids=['oguricap'],
   document_metadatas=[{"entity": "oguricap", "source": "wikipedia"}],
   index_name="jra_race_horses",
   # ドキュメントをチャンク分割するか
   split_documents=True,
   # ドキュメントの長さ、これ以上の長さであればチャンクに分割する
   max_document_length=400,
   )

メタデータとかその辺も個別に付与するならこうかな?追加時も作成時と同じで少し時間がかかる。

sample_document_2 = get_wikipedia_page("キタサンブラック")

RAG.add_to_index(
    new_collection=[sample_document_2],
    new_document_ids=["kitasanblack"],
    new_document_metadatas=[{"entity": "kitasanblack", "source": "wikipedia"}],
)

一応add_to_indexはまだexperimentalらしい。

WARNING: add_to_index support is currently experimental! add_to_index support will be more thorough in future versions

追加されたっぽい

100%|██████████| 2048/2048 [00:00<00:00, 85028.65it/s][Jul 24, 23:54:40] #> Saved optimized IVF to .ragatouille/colbert/indexes/jra_race_horses/ivf.pid.pt
Successfully updated index with 60 new documents!
 New index size: 182

検索してみる。

results = RAG.search("キタサンブラックの馬主は?", k=5)
results

んー、出てこない。。。。

[{'content': 'レースで実況を担当した杉本清は最後の直線で「これは噂にたがわない強さだ」と実況した。なお、この日中京競馬場で行われた中日新聞杯では佐橋が所有するトキノオリエントが優勝し、佐橋は中央競馬史上初となる同一馬主による地方出身馬の同日開催重賞制覇を達成している。\n移籍2戦目には毎日杯が選ばれた。このレースでは馬場状態が追い込み馬に不利とされる重馬場と発表され、オグリキャップが馬場状態に対応できるかどうかに注目が集まった。オグリキャップは第3コーナーで最後方の位置から馬群の外を通って前方へ進出を開始し、ゴール直前で先頭に立って優勝した。',
  'score': 15.408933639526367,
  'rank': 1,
  'document_id': 'oguricap',
  'passage_id': 14,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'なお、近藤と岡はともに北海道浦河高等学校に在籍した経験を持つ。岡は3年後の1993年に落馬事故で死去している。\n増沢末夫\n1990年の天皇賞(秋)およびジャパンカップに騎乗した。当時の馬主である近藤俊典は、増沢が非常に可愛がられていた馬主・近藤ハツ子の甥であり、増沢が若手騎手の頃から面識があった。前述のように、安藤勝己、青木達彦、渡瀬夏彦は増沢とオグリキャップとの相性は良くなかったという見解を示している。一方、瀬戸口は「増沢騎手には本当に気の毒な思いをさせました。済まなかったと思います。あれほどの騎手に、オグリがいちばん体調がよくない時に乗ってもらったんですから」と、増沢を庇う言葉を残している。',
  'score': 15.193703651428223,
  'rank': 2,
  'document_id': 'oguricap',
  'passage_id': 109,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'また、日本馬主協会連合会が史誌『日本馬主協会連合会40年史』(2001年)の中で、登録馬主を対象に行ったアンケートでは、「一番印象に残る競走馬」の部門で第1位を獲得、「一番印象に残っているレース」の部門でも、ラストランの第35回有馬記念が第38回有馬記念(トウカイテイオー優勝)と同率での第1位(504票中19票)に選ばれた。「一番の名馬」部門では第5位(第1位はシンザン)、「一番好きな競走馬」部門では第9位(第1位はハイセイコー)だった。\n\n競走馬名「オグリキャップ」の由来は、馬主の小栗が使用していた冠名「オグリ」に父ダンシングキャップの馬名の一部「キャップ」を加えたものである。',
  'score': 14.804426193237305,
  'rank': 3,
  'document_id': 'oguricap',
  'passage_id': 88,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': '5代母のクインナルビー(父:クモハタ)は1953年の天皇賞(秋)を制している。クインナルビーの子孫には他にアンドレアモン、キョウエイマーチなどの重賞勝ち馬がいる。\n\n兄弟\nオグリローマン - 1994年桜花賞優勝馬\nオグリイチバン - オグリキャップの活躍を受けてシンジケートを組まれ種牡馬となった。\nオグリトウショウ - オグリキャップの活躍後に誕生し、デビュー前から話題を集めた。競走馬引退後はオグリイチバンと同様、種牡馬となった。\n\n書籍\n\n朝日新聞論説委員室『天声人語 2010年7月-12月』朝日新聞出版、2011年。ISBN 4022508469。 \n阿部珠樹『有馬記念物語 世界最大のレースの魅力を追う』青春出版社〈プレイブックス・インテリジェンス〉、2003年。ISBN 4413040805。',
  'score': 14.326939582824707,
  'rank': 4,
  'document_id': 'oguricap',
  'passage_id': 111,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'また、売却価格の高さも指摘された。オグリキャップ売却と同時に佐橋の馬主登録は抹消されたが、近藤は自らの勝負服の色と柄を、佐橋が用いていたものと全く同じものに変更した。\n\n陣営は1989年前半のローテーションとして、大阪杯、天皇賞(春)、安田記念、宝塚記念に出走するプランを発表したが、2月に右前脚の球節(ヒトのかかとにあたる部分)を捻挫して大阪杯の出走回避を余儀なくされた。さらに4月には右前脚に繋靭帯炎を発症。前半シーズンは全て休養に当てることとし、同月末から競走馬総合研究所常磐支所(福島県いわき市)にある温泉療養施設(馬の温泉)において治療を行った。',
  'score': 14.225560188293457,
  'rank': 5,
  'document_id': 'oguricap',
  'passage_id': 26,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}}]

kを思いっきり引き上げても(k=1000)、2回目に追加したドキュメントが1件も出てこなかったのだけど気になったのはこれ。

results = RAG.search("キタサンブラックの馬主は?", k=1000)
results
WARNING: k value is larger than the number of documents in the index! Lowering k to 122...
(snip)

追加時のメッセージで、Successfully updated index with 60 new documents! New index size: 182とあったはずなので、どうも新しいドキュメントが検索対象に入っていない?

searchのオプションを調べてみるとドキュメントのIDを指定できる様子。

results = RAG.search("キタサンブラックの馬主は?", k=5, doc_ids=["kitasanblack"])
results

ランタイムがクラッシュした。。。ハイメモリにしてもクラッシュする。。。。

どうやらこれっぽい気がする

https://github.com/bclavie/RAGatouille/issues/205

これ以外にもadd_to_indexはちらほらissueが上がっていて、どうもColBERT側にも問題があるように思える。

https://github.com/stanford-futuredata/ColBERT/issues/261

CRUD操作ができないのはちょっとしんどいな。現時点では、インデックス作り直してマルっと入れ替える、みたいなアプローチになりそう。

kun432kun432

追加は色々やってみたけどだめだった。複数ドキュメントの場合は、インデックス作成時に以下のような感じで指定すれば出来た。

RAG.index(
    collection=[get_wikipedia_page("オグリキャップ"), get_wikipedia_page("キタサンブラック")],
    document_ids=['oguricap', 'kitasanblack'],
    document_metadatas=[{"entity": "oguricap", "source": "wikipedia"}, {"entity": "kitasanblack", "source": "wikipedia"}],
    index_name="jra_race_horses",
    max_document_length=400,
    split_documents=True,
    )
results = RAG.search(query="オグリキャップの主な勝ち鞍は?", k=3)
results
[{'content': 'オグリキャップ(欧字名:Oguri Cap、1985年3月27日 - 2010年7月3日)は、日本の競走馬、種牡馬。\n1987年5月に岐阜県の地方競馬・笠松競馬場でデビュー。8連勝、重賞5勝を含む12戦10勝を記録した後、1988年1月に中央競馬へ移籍し、重賞12勝(うちGI4勝)を記録した。1988年度のJRA賞最優秀4歳牡馬、1989年度のJRA賞特別賞、1990年度のJRA賞最優秀5歳以上牡馬および年度代表馬。1991年、JRA顕彰馬に選出。愛称は「オグリ」「芦毛の怪物」など多数。',
  'score': 23.557249069213867,
  'rank': 1,
  'document_id': 'oguricap',
  'passage_id': 0,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'オグリキャップは第3コーナーで最後方の位置から馬群の外を通って前方へ進出を開始し、ゴール直前で先頭に立って優勝した。\nオグリキャップは初代馬主の小栗孝一が中央で走らせるつもりがなかったことでクラシック登録をしていなかったため、前哨戦である毎日杯を優勝して本賞金額では優位に立ったものの皐月賞に登録できず、代わりに京都4歳特別に出走した。このレースでは翌1989年の全戦に騎乗することとなる南井克巳が鞍上を務め、オグリキャップ一頭だけが58キロの斤量を背負ったが第3コーナーで後方からまくりをかけ、優勝した。\nクラシック登録をしていないオグリキャップは東京優駿(日本ダービー)にも出走することができず、代わりに「断念ダービー」と言われていたニュージーランドトロフィー4歳ステークスに出走した。',
  'score': 22.552488327026367,
  'rank': 2,
  'document_id': 'oguricap',
  'passage_id': 15,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'オグリキャップの騎手は何度も交替した。以下、オグリキャップに騎乗した主な騎手と騎乗した経緯について記述する。\n\n安藤勝己\nデビュー当初のオグリキャップには高橋一成(鷲見厩舎の所属騎手)と青木達彦が騎乗していたが、6戦目のレースではいずれも騎乗することができなかったため、当時笠松競馬場のリーディングジョッキーであった安藤が騎乗し、以降は安藤がオグリキャップの主戦騎手を務めた。安藤はオグリキャップに騎乗した中でもっとも思い出に残るレースとして、楽に勝たせようと思い早めに先頭に立った結果オグリキャップが気を抜いてマーチトウショウとの競り合いになり、目一杯に追う羽目になった7戦目のジュニアクラウンを挙げている。',
  'score': 22.351572036743164,
  'rank': 3,
  'document_id': 'oguricap',
  'passage_id': 101,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}}]
results = RAG.search("キタサンブラックの馬主は?", k=3)
results
[{'content': 'キタサンブラック(欧字名:Kitasan Black、2012年3月10日 - )は日本の競走馬・種牡馬。\n2016年度と2017年度のJRA賞年度代表馬および最優秀4歳以上牡馬。菊花賞、天皇賞(春・秋)、ジャパンカップ、有馬記念を制した日本中央競馬会(JRA)の顕彰馬。史上2頭目の天皇賞3勝馬で、春の天皇賞ではコースレコードを持つ。演歌歌手の北島三郎が所有したことでも知られる。2023年のワールドベストレースホースであるイクイノックスの父であり、親子での2年連続年度代表馬は史上初。\n\n北海道日高町のヤナガワ牧場で生産された父ブラックタイドの牡馬である。「キタサン」の冠名を用いる国民的演歌歌手の北島三郎が所有し、栗東トレーニングセンターの清水久詞が調教師を担った。',
  'score': 25.805316925048828,
  'rank': 1,
  'document_id': 'kitasanblack',
  'passage_id': 122,
  'document_metadata': {'entity': 'kitasanblack', 'source': 'wikipedia'}},
 {'content': '陣営は、キタサンブラックは大型馬であり本格化に時間が掛かると考えていたことからデビュー時点でクラシック登録をしていなかった。しかし、皐月賞の優先出走権を得たことでオーナー北島三郎の決断により追加登録料200万円を支払い、クラシック戦線に進出することとなった。\n\n4月19日の皐月賞に出走。主戦の北村が騎乗停止のため浜中俊を鞍上に迎えた。レース当日、北村は装鞍所を訪れて装鞍を手伝っていた。道中2番手追走から直線で一度は先頭に立ったがドゥラメンテとリアルスティールにかわされ3着となった。\n\n5月31日の東京優駿に出走。パドックでは初めて二人引きを行うほどテンションが高かった。レースでは道中2番手で追走、直線でしかけ残り400mあたりまではミュゼエイリアンと並んで先頭に立っていたが後続に交わされ14着に敗れた。',
  'score': 23.908313751220703,
  'rank': 2,
  'document_id': 'kitasanblack',
  'passage_id': 133,
  'document_metadata': {'entity': 'kitasanblack', 'source': 'wikipedia'}},
 {'content': 'なかなか売り手がつかないことから牧場と馬主の共同名義で競走馬としてデビューさせようと考えていた。\nその後、ヤナガワ牧場と約半世紀の付き合いがあるという北島三郎が「顔が二枚目。僕とよく似ている」「目も顔も男前で惚れた」という理由で350万円で購入した。\nキタサンブラックはトラブルに見舞われることなく離乳し、そして1歳秋まで牧場で育てられた。当歳の頃から夜間放牧をこなしていた。体高があって脚が長く、ヤナガワ牧場の会長夫人はその体形を1996年菊花賞優勝馬ダンスインザダークに似ていると評していた。\n\n1歳秋の11月12日に北海道新冠町の日高軽種馬共同育成公社に移動して育成が施された。',
  'score': 23.8648624420166,
  'rank': 3,
  'document_id': 'kitasanblack',
  'passage_id': 127,
  'document_metadata': {'entity': 'kitasanblack', 'source': 'wikipedia'}}]
results = RAG.search("オグリキャップとキタサンブラックの血統を知りたい", k=5)
results
[{'content': 'キタサンブラックは2012年3月10日、北海道日高町のヤナガワ牧場にてブラックタイドの4年目産駒、シュガーハートの3番仔として誕生した。キタサンブラックは、生後立ち上がった直後から高評価だった。骨量に富み、バランスの良い馬体の持ち主だった。牧場ではけがや病気に見舞われることなく順調で、良い出来に成長していた。\nキタサンブラックはこの年にヤナガワ牧場で生産された牡馬の中でアレスバローズに次ぐ2番目の評価を得ていたが、活躍馬に乏しい牝系に属するために、ヤナガワ牧場代表の梁川正晋は活躍を保証する自信がなく、牧場を訪れる調教師や馬主などにキタサンブラックをたやすく薦めることができなかった。なかなか売り手がつかないことから牧場と馬主の共同名義で競走馬としてデビューさせようと考えていた。',
  'score': 18.622055053710938,
  'rank': 1,
  'document_id': 'kitasanblack',
  'passage_id': 126,
  'document_metadata': {'entity': 'kitasanblack', 'source': 'wikipedia'}},
 {'content': 'キタサンブラック(欧字名:Kitasan Black、2012年3月10日 - )は日本の競走馬・種牡馬。\n2016年度と2017年度のJRA賞年度代表馬および最優秀4歳以上牡馬。菊花賞、天皇賞(春・秋)、ジャパンカップ、有馬記念を制した日本中央競馬会(JRA)の顕彰馬。史上2頭目の天皇賞3勝馬で、春の天皇賞ではコースレコードを持つ。演歌歌手の北島三郎が所有したことでも知られる。2023年のワールドベストレースホースであるイクイノックスの父であり、親子での2年連続年度代表馬は史上初。\n\n北海道日高町のヤナガワ牧場で生産された父ブラックタイドの牡馬である。「キタサン」の冠名を用いる国民的演歌歌手の北島三郎が所有し、栗東トレーニングセンターの清水久詞が調教師を担った。',
  'score': 17.98715591430664,
  'rank': 2,
  'document_id': 'kitasanblack',
  'passage_id': 122,
  'document_metadata': {'entity': 'kitasanblack', 'source': 'wikipedia'}},
 {'content': '入厩するまでに北島は、本馬に冠名のキタサンと父ブラックタイドの一部のブラックを組み合わせてキタサンブラックと命名した。キタサンブラックは、宇治田原のスタッフにはブラックと呼ばれていた。\n本馬には、宇治田原でも成長に寄り添った調教が施された。当初の見立てでは仕上がりには時間がかかると思われていたが、その見立てよりも早いペースで成長した。当初は2014年暮れ、2歳末か2015年明け、3歳初めに清水厩舎に入厩する見立てだった。しかし清水厩舎の馬房が空いていたため、前倒しでの入厩となった。宇治田原の担当田辺滋久は、調教を見て「2、3勝できる」馬という認識だった。\n\nキタサンブラックは、2014年、2歳12月17日に栗東トレーニングセンターの清水厩舎に入厩した。そして翌18日から坂路調教が開始された。厩舎では、辻田義幸が厩務員を担った。',
  'score': 17.864843368530273,
  'rank': 3,
  'document_id': 'kitasanblack',
  'passage_id': 130,
  'document_metadata': {'entity': 'kitasanblack', 'source': 'wikipedia'}},
 {'content': '5代母のクインナルビー(父:クモハタ)は1953年の天皇賞(秋)を制している。クインナルビーの子孫には他にアンドレアモン、キョウエイマーチなどの重賞勝ち馬がいる。\n\n兄弟\nオグリローマン - 1994年桜花賞優勝馬\nオグリイチバン - オグリキャップの活躍を受けてシンジケートを組まれ種牡馬となった。\nオグリトウショウ - オグリキャップの活躍後に誕生し、デビュー前から話題を集めた。競走馬引退後はオグリイチバンと同様、種牡馬となった。\n\n書籍\n\n朝日新聞論説委員室『天声人語 2010年7月-12月』朝日新聞出版、2011年。ISBN 4022508469。 \n阿部珠樹『有馬記念物語 世界最大のレースの魅力を追う』青春出版社〈プレイブックス・インテリジェンス〉、2003年。ISBN 4413040805。',
  'score': 17.850387573242188,
  'rank': 4,
  'document_id': 'oguricap',
  'passage_id': 111,
  'document_metadata': {'entity': 'oguricap', 'source': 'wikipedia'}},
 {'content': 'その後、梁川は馬格があり繁殖牝馬に適していると判断し、繁殖牝馬としてヤナガワ牧場に迎え入れていた。キタサンブラック以外に活躍した産駒として、2024年に青葉賞を制したシュガークン(父ドゥラメンテ)がいる。\n曾祖母のテイズリーは初仔であるシーズティジー(ティズナウの父)を出産後に社台グループに購買され、祖母のオトメゴコロは吉田勝己の持ち馬で、父・母父とも社台グループの生産馬であった事など社台グループとは縁が深く、シーズディジー以外の近親には従兄(母の姉の産駒)にアドマイヤフライト(父マンハッタンカフェ、日経新春杯2着)、祖母の妹にオトメノイノリ(父サンデーサイレンス、アイビーステークス)がいる。',
  'score': 17.838356018066406,
  'rank': 5,
  'document_id': 'kitasanblack',
  'passage_id': 175,
  'document_metadata': {'entity': 'kitasanblack', 'source': 'wikipedia'}}]
kun432kun432

とりま所感

  • Pros
    • 確かにインタフェースはめちゃめちゃシンプルで簡単。
    • こことかここにあるように、検索精度はかなり良い様子。自分的にも悪くない感じだった。
    • かつ、他のマルチリンガルなローカルEmbeddingモデルよりもパラメータ数が小さいので、おそらくリソースも少なくて済みそう。
    • notebook見る限りは、ファインチューニングやリランキングもできる様子
  • Cons
    • あくまでもDocument Retrievalモデルなので、Embeddingモデルのような汎用性はない。
    • CRUDはまだ難しそう、当然ColBERTにも依存する
    • 上とも関連するけども、ドキュメントごとにチャンク単位を分けるとかは現状だと厳しそうな感。
      • その場合は前処理を先にやる感じになりそう。まあそれは普通か。

以前に調べたときはColBERTとかさっぱりわからなくて手を付けれなかった。今もぜんぜんわかってないけども、RAGatouilleのおかげで多少なりともイメージはできるようになったし、かなり実装が簡略化されているというのもありがたい。

なお、モデルとしてはJaColBERTv2.5がどうやら出てきそうで、さらに性能上がってるっぽいので、期待。

https://twitter.com/bclavie/status/1816139669001707584

kun432kun432

JaColBERTv2/2.4/2.5をranxでベンチ取って他のembeddingモデルを使ったretrievalと比較してみた。

結果から先に。 ベンチマーク性能的にはv2.5がOpenAI text-embedding-3-largeと同じぐらいといったところ。

===== @3 =====

#    Model                                   Hit Rate@3    MRR@3
---  --------------------------------------  ------------  ------------
a    JaColBERTv2                             0.832ᵈᵏ       0.767ᵈᵏ
b    JaColBERTv2.4                           0.860ᵃᵈʲᵏ     0.794ᵃᵈʲᵏ
c    JaColBERTv2.5                           0.863ᵃᵈʲᵏ     0.793ᵃᵈʲᵏ
d    amazon-titan-embeddings-g1              0.745         0.645
e    baai-bge-m3                             0.853ᵈʲᵏ      0.782ᵈʲᵏ
f    cohere-embed-multilingual-v3.0          0.856ᵈʲᵏ      0.779ᵈʲᵏ
g    infloat-multilingual-e5-large-instruct  0.864ᵈʲᵏ      0.782ᵈʲᵏ
h    infloat-multilingual-e5-large           0.867ᵃᵈʲᵏ     0.802ᵃᵈᶠʲᵏ
i    openai-text-embedding-3-large           0.869ᵃᵈʲᵏ     0.797ᵈʲᵏ
j    openai-text-embedding-3-small           0.822ᵈ        0.747ᵈᵏ
k    openai-text-embedding-ada-002           0.793ᵈ        0.713ᵈ
l    solar-embedding-1-large                 0.870ᵃᵈʲᵏ     0.810ᵃᵈᵉᶠʲᵏ
m    voyage-multilingual-2                   0.888ᵃᵈᵉᶠʲᵏ   0.813ᵃᵈᵉᶠᵍʲᵏ

===== @5 =====

#    Model                                   Hit Rate@5    MRR@5
---  --------------------------------------  ------------  ------------
a    JaColBERTv2                             0.876ᵈ        0.777ᵈᵏ
b    JaColBERTv2.4                           0.893ᵈʲᵏ      0.802ᵃᵈʲᵏ
c    JaColBERTv2.5                           0.900ᵃᵈʲᵏ     0.801ᵃᵈʲᵏ
d    amazon-titan-embeddings-g1              0.799         0.658
e    baai-bge-m3                             0.882ᵈᵏ       0.789ᵈʲᵏ
f    cohere-embed-multilingual-v3.0          0.897ᵈʲᵏ      0.788ᵈʲᵏ
g    infloat-multilingual-e5-large-instruct  0.902ᵈʲᵏ      0.790ᵈʲᵏ
h    infloat-multilingual-e5-large           0.903ᵈʲᵏ      0.810ᵃᵈᶠʲᵏ
i    openai-text-embedding-3-large           0.903ᵈʲᵏ      0.805ᵈʲᵏ
j    openai-text-embedding-3-small           0.863ᵈ        0.756ᵈᵏ
k    openai-text-embedding-ada-002           0.850ᵈ        0.727ᵈ
l    solar-embedding-1-large                 0.905ᵃᵈᵉʲᵏ    0.817ᵃᵈᵉᶠᵍʲᵏ
m    voyage-multilingual-2                   0.918ᵃᵈᵉʲᵏ    0.820ᵃᵈᵉᶠᵍʲᵏ

===== @10 =====

#    Model                                   Hit Rate@10    MRR@10
---  --------------------------------------  -------------  ------------
a    JaColBERTv2                             0.909ᵈ         0.782ᵈᵏ
b    JaColBERTv2.4                           0.935ᵃᵈʲᵏ      0.808ᵃᵈʲᵏ
c    JaColBERTv2.5                           0.946ᵃᵇᵈᵉʲᵏˡ   0.807ᵃᵈʲᵏ
d    amazon-titan-embeddings-g1              0.860          0.666
e    baai-bge-m3                             0.914ᵈᵏ        0.793ᵈʲᵏ
f    cohere-embed-multilingual-v3.0          0.924ᵈʲᵏ       0.792ᵈʲᵏ
g    infloat-multilingual-e5-large-instruct  0.934ᵈʲᵏ       0.795ᵈʲᵏ
h    infloat-multilingual-e5-large           0.938ᵃᵈᵉʲᵏ     0.815ᵃᵈᶠʲᵏ
i    openai-text-embedding-3-large           0.931ᵈʲᵏ       0.808ᵈʲᵏ
j    openai-text-embedding-3-small           0.899ᵈ         0.761ᵈᵏ
k    openai-text-embedding-ada-002           0.885          0.732ᵈ
l    solar-embedding-1-large                 0.923ᵈʲᵏ       0.820ᵃᵈᵉᶠʲᵏ
m    voyage-multilingual-2                   0.953ᵃᵈᵉᶠᶦʲᵏˡ  0.824ᵃᵈᵉᶠᵍʲ

jaColbert以外の評価は以下を参考

https://zenn.dev/link/comments/010b0924e49356

jaColbertのranxの評価用trec出力スクリプトは以下。だいぶ雑。

ranxによるjaColbertの評価スクリプト
!pip install -U ragatouille
!pip install fugashi unidic-lite
# FAQデータのダウンロード
!wget https://d.line-scdn.net/stf/linecorp/ja/csr/dataset_.zip
!unzip dataset_.zip
# FAQデータをpandasのデータフレームに読み込んで整形
import pandas as pd

df = pd.read_excel("dataset_.xlsx")
df["QID"] = df["サンプルID"].apply(lambda x: f'Q{x:03}')
df["AID"] = df["サンプルID"].apply(lambda x: f'A{x:03}')
df.rename(columns={
    'サンプル 問い合わせ文': 'Question',
    'サンプル 応答文': 'Answer',
    'カテゴリ1': 'Category',
}, inplace=True)
df.drop(columns=["ID", "サンプルID", "カテゴリ2","出典","<参考>UMカテゴリタグ","<参考>UMサービスメニュー\n(標準的な行政サービス名称)"], inplace=True)
df = df.reindex(columns=["QID", "Question", "AID", "Answer", "Category"])
df

documents = []
document_ids = []
document_metadatas = []
qrels = []

for idx, row in df.iterrows():
    qid = row["QID"]
    aid = row["AID"]
    text = row["Answer"]
    category = row["Category"]

    documents.append(text)
    document_ids.append(aid)
    document_metadatas.append({"aid": aid, "category": category})

    # ranxのqrelsを作成
    # 参考) https://github.com/joaopalotti/trectools?tab=readme-ov-file#file-formats
    #
    # QとAで1対1のペアを元にQrelを作成する
    # 注: 例えば、Qに対して複数のAを関連させる、とか、関連する複数のAの中に関連度のグラデーションをつける、とか、
    #     ができれば、より詳細な評価ができると思うが、そのデータを作るのは大変なので、ここでは簡単のため1対1としている
    qrel = "{} 0 {} 1".format(qid, aid)
    qrels.append(qrel)

# Qrelをファイルに出力
with open(f'qrels.trec', 'w') as file:
    for qrel in qrels:
        file.write(f"{qrel}\n")
from ragatouille import RAGPretrainedModel

RAG_2 = RAGPretrainedModel.from_pretrained("bclavie/JaColBERTv2")
RAG_2_4 = RAGPretrainedModel.from_pretrained("answerdotai/JaColBERTv2.4")
RAG_2_5 = RAGPretrainedModel.from_pretrained("answerdotai/JaColBERTv2.5")
RAG_2.index(
    collection=documents,
    document_ids=document_ids,
    document_metadatas=document_metadatas,
    index_name="line_kosodate_faq_2",
    # ドキュメントをチャンク分割するか
    split_documents=False,
    )

RAG_2_4.index(
    collection=documents,
    document_ids=document_ids,
    document_metadatas=document_metadatas,
    index_name="line_kosodate_faq_2_4",
    # ドキュメントをチャンク分割するか
    split_documents=False,
    )

RAG_2_5.index(
    collection=documents,
    document_ids=document_ids,
    document_metadatas=document_metadatas,
    index_name="line_kosodate_faq_2_5",
    # ドキュメントをチャンク分割するか
    split_documents=False,
    )
from tqdm.auto import tqdm

k = 100

runs = []
for idx, row in tqdm(df.iterrows(), total=df.shape[0], desc=f"Processing JaColBERTv2"):
    q_id = row["QID"]
    query = row["Question"]

    for r in RAG_2.search(query=query, k=k):
        a_rank = r["rank"]
        a_id = r["document_metadata"]["aid"]
        a_score = r["score"]
        run = "{} Q0 {} {} {} {}".format(q_id, a_id, a_rank, a_score, "JaColBERTv2")
        runs.append(run)

with open(f"run_JaColBERT_v2.trec", 'w') as file:
    for run in runs:
        file.write(f"{run}\n")

from tqdm.auto import tqdm

k = 100

runs = []
for idx, row in tqdm(df.iterrows(), total=df.shape[0], desc=f"Processing JaColBERTv2.4"):
    q_id = row["QID"]
    query = row["Question"]

    for r in RAG_2_4.search(query=query, k=k):
        a_rank = r["rank"]
        a_id = r["document_metadata"]["aid"]
        a_score = r["score"]
        run = "{} Q0 {} {} {} {}".format(q_id, a_id, a_rank, a_score, "JaColBERTv2.4")
        runs.append(run)

with open(f"run_JaColBERT_v2_4.trec", 'w') as file:
    for run in runs:
        file.write(f"{run}\n")

from tqdm.auto import tqdm

k = 100

runs = []
for idx, row in tqdm(df.iterrows(), total=df.shape[0], desc=f"Processing JaColBERTv2.5"):
    q_id = row["QID"]
    query = row["Question"]

    for r in RAG_2_5.search(query=query, k=k):
        a_rank = r["rank"]
        a_id = r["document_metadata"]["aid"]
        a_score = r["score"]
        run = "{} Q0 {} {} {} {}".format(q_id, a_id, a_rank, a_score, "JaColBERTv2.5")
        runs.append(run)

with open(f"run_JaColBERT_v2_5.trec", 'w') as file:
    for run in runs:
        file.write(f"{run}\n")

::

このスクラップは1ヶ月前にクローズされました