Dense X Retrieval: What Retrieval Granularity Should We Use?
RAGの検索精度を上げるためのチャンク分割の単位は、文・節・行はなくて、命題がいいよ、ということらしい。
"Proposion"は日本語だと「命題」。
論理学における「命題」
論理学で言う「命題」とは真偽が確定した言明のことであり、例えば「1は偶数である」「2は偶数である」などは命題である。これに対して「Xは偶数である」のように不定のXが入ったものを「述語」と言う。
論文に載ってるプロンプトを日本語化して、ChatGPTで試してみた。few shotの部分はそのままにしてる。
"Content"を明確でシンプルな命題に分解し、文脈に関係なく解釈できるようにしてください。
1. 複文を単純な文に分割する。可能な限り、入力の元の言い回しを維持する。
2. 付加的な説明情報を伴う名前付きエンティティについては、この情報を独自の個別の命題に分割する。
3. 名詞または文全体に必要な修飾語を追加し、代名詞(例:「これ」「あれ」「それ」、「彼」、「彼女」、「彼ら」、「彼女ら」)を、それらが参照するエンティティのフルネームで置き換えることで、命題を非文脈化する。
4. 結果は、JSONでフォーマットされた文字列のリストとして表示される。
Input: Title: Eostre. Section: Theories and interpretations, Connection to Easter Hares. Content: The earliest evidence for the Easter Hare (Osterhase) was recorded in south-west Germany in 1678 by the professor of medicine Georg Franck von Franckenau, but it remained unknown in other parts of Germany until the 18th century. Scholar Richard Sermon writes that "hares were frequently seen in gardens in spring, and thus may have served as a convenient explanation for the origin of the colored eggs hidden there for children. Alternatively, there is a European tradition that hares laid eggs, since a hare’s scratch or form and a lapwing’s nest look very similar, and both occur on grassland and are first seen in the spring. In the nineteenth century the influence of Easter cards, toys, and books was to make the Easter Hare/Rabbit popular throughout Europe. German immigrants then exported the custom to Britain and America where it evolved into the Easter Bunny."
Output: [ "The earliest evidence for the Easter Hare was recorded in south-west Germany in 1678 by Georg Franck von Franckenau.", "Georg Franck von Franckenau was a professor of medicine.", "The evidence for the Easter Hare remained unknown in other parts of Germany until the 18th century.", "Richard Sermon was a scholar.", "Richard Sermon writes a hypothesis about the possible explanation for the connection between hares and the tradition during Easter", "Hares were frequently seen in gardens in spring.", "Hares may have served as a convenient explanation for the origin of the colored eggs hidden in gardens for children.", "There is a European tradition that hares laid eggs.", "A hare’s scratch or form and a lapwing’s nest look very similar.", "Both hares and lapwing’s nests occur on grassland and are first seen in the spring.", "In the nineteenth century the influence of Easter cards, toys, and books was to make the Easter Hare/Rabbit popular throughout Europe.", "German immigrants exported the custom of the Easter Hare/Rabbit to Britain and America.", "The custom of the Easter Hare/Rabbit evolved into the Easter Bunny in Britain and America." ]
Input: Title: イクイノックス. Section: . Content: 2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味は「昼と夜の長さがほぼ等しくなる時」[7]。2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。主な勝ち鞍は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。
Output:
渡す文章は以下の冒頭から。
[
"イクイノックスはキタサンブラック産駒である。",
"イクイノックスは2022年に初のGI制覇を果たした。",
"イクイノックスは2023年に秋春グランプリ制覇を達成した。",
"馬名イクイノックスの意味は「昼と夜の長さがほぼ等しくなる時」である。",
"イクイノックスは2022年度のJRA賞年度代表馬である。",
"イクイノックスは2022年度の最優秀3歳牡馬である。",
"イクイノックスの主な勝ち鞍には2022年の天皇賞(秋)が含まれる。",
"イクイノックスは2023年の天皇賞(秋)でも勝利を収めた。",
"イクイノックスは2022年の有馬記念に勝利した。",
"イクイノックスは2023年のドバイシーマクラシックに勝利した。",
"イクイノックスは2023年の宝塚記念に勝利した。",
"イクイノックスは2023年のジャパンカップに勝利した。"
]
なるほど。確かに端的な事実の列挙になっている。
ただ、実際にRAGで使ってみたときにどうなるか、というのはあるなぁ。これらをベクトル変換して検索に使うというのは良さそうなんだけど、そこからLLMに渡すために引っ張ってくるコンテキストとしてはこのままだとあっさりしすぎてそうなので、一工夫必要な気がする。
ちなみに、論文で紹介されている「命題」("Propositioner")に分割してくれるモデルを試してみたんだけど、日本語には対応していないみたいで全然ダメだった。
ただ、実際にRAGで使ってみたときにどうなるか、というのはあるなぁ。これらをベクトル変換して検索に使うというのは良さそうなんだけど、そこからLLMに渡すために引っ張ってくるコンテキストとしてはこのままだとあっさりしすぎてそうなので、一工夫必要な気がする。
ということはこっちの話になっていくのかなー、まだ試せてないのだけど。
論文ちゃんと読めてないけど、retreivalとqaのそれぞれの精度は分けて出してるように見える。端的なQAはの回答としての精度は重要ではあるんけど、それだけじゃなくて、関連しそうなコンテキストも付加して、最終的な回答にリッチさを加えるってのもRAGでは重要な気がするんだよね。
ちょうどこれと似たようなことを考えていた
こういうやつ
Input: Title: イクイノックス. Section: 戦績・2歳(2021年). Content: デビュー前に木村の自厩舎所属騎手に対するパワーハラスメントの一件で略式命令を受けたため、JRAから調教停止処分を受けた事に伴い、2021年7月29日から10月31日まで岩戸孝樹厩舎に一時転厩している。従って後述の新馬戦は岩戸厩舎所属馬としてデビューしている。
8月28日、新潟競馬場 (芝 1,800m) での2歳新馬戦でデビュー。クリストフ・ルメールを鞍上に迎えたレースでは、好位のインに控え直線で先頭に立ってサークルオブライフ、ウィルソンテソーロなど後続を突き放し、2着に6馬身差をつけ優勝した。本馬が見せた末脚は、長距離向きと見ていたノーザンファームの桑田を驚かせた。
木村厩舎に戻って初戦となる11月20日の東京スポーツ杯2歳ステークス (GII) では1番人気に支持されると、レースでは新馬戦と異なり後方馬群で待機、直線では上がり3ハロン32秒9[注釈 1]の末脚で各馬を差し切って無傷の2連勝で重賞初制覇を果たすと共に、キタサンブラック産駒の重賞初制覇となった。
Output:
[
"木村の自厩舎所属騎手に対するパワーハラスメントの一件で木村が略式命令を受けた。",
"JRAから調教停止処分を受けたため、イクイノックスは2021年7月29日から10月31日まで岩戸孝樹厩舎に一時転厩した。",
"イクイノックスの新馬戦は岩戸厩舎所属馬としてデビューした。",
"イクイノックスは2021年8月28日、新潟競馬場で2歳新馬戦にデビューした。",
"イクイノックスの鞍上はクリストフ・ルメールであった。",
"イクイノックスは新馬戦で先頭に立ち、2着に6馬身差をつけて優勝した。",
"イクイノックスの末脚はノーザンファームの桑田を驚かせた。",
"イクイノックスは木村厩舎に戻って初戦として2021年11月20日の東京スポーツ杯2歳ステークス (GII) に出走した。",
"イクイノックスは東京スポーツ杯2歳ステークスで1番人気に支持された。",
"イクイノックスは東京スポーツ杯2歳ステークスで上がり3ハロン32秒9の末脚で勝利し、重賞初制覇を果たした。",
"イクイノックスの勝利はキタサンブラック産駒の重賞初制覇となった。"
]
- 以下の箇所はセットじゃないとわからないというか間違った解釈を生む可能性がある。
-
"木村の自厩舎所属騎手に対する..."
は、「イクイノックス」ということと関わりがあるかどうかがこれだけではわからない。 -
"JRAから調教停止処分を受けたため、..."
の部分は、「イクイノックス」と関わりがあるということはわかるけど、理由がわからない。「イクイノックス」自身に問題があるようにも読める。
-
- 以下の部分も「どのレースについて言っているのか?」という点で情報が足りない
-
"イクイノックスの鞍上はクリストフ・ルメールであった。"
(全レースでルメールが鞍上ではあるのだけども) "イクイノックスの末脚はノーザンファームの桑田を驚かせた。"
-
"イクイノックスの勝利はキタサンブラック産駒の重賞初制覇となった。"
(調べればわかることではあるのだけども)
-
とりあえず、プロンプトを改良すればなんとかできそうな気はするけども、どこまでの単位を「命題」として扱うか?というところは難しそうだし、これを拡大解釈していくと文章は長くなりそう、そして、検索精度にも影響が出そう。
titleとsectionをどう使うかも重要だなぁ、生成時はin-contextに含めてやれば良さそうだけど、ベクトル検索時はどうすればいいんだろう?というのはある。
遅ればせながらLlama Packを試した。
Dense X Retrievalのパッケージが用意されているので、試してみる。
ドキュメントはいつも通り
from pathlib import Path
import requests
import re
def replace_heading(match):
level = len(match.group(1))
return '#' * level + ' ' + match.group(2).strip()
# Wikipediaからのデータ読み込み
wiki_titles = ["イクイノックス", "ドウデュース"]
for title in wiki_titles:
response = requests.get(
"https://ja.wikipedia.org/w/api.php",
params={
"action": "query",
"format": "json",
"titles": title,
"prop": "extracts",
# 'exintro': True,
"explaintext": True,
},
).json()
page = next(iter(response["query"]["pages"].values()))
wiki_text = f"# {title}\n\n"
wiki_text += page["extract"]
wiki_text = re.sub(r"(=+)([^=]+)\1", replace_heading, wiki_text)
wiki_text = re.sub(r"\t+", "", wiki_text)
wiki_text = re.sub(r"\n{3,}", "\n\n", wiki_text)
data_path = Path("data")
if not data_path.exists():
Path.mkdir(data_path)
with open(data_path / f"{title}.txt", "w") as fp:
fp.write(wiki_text)
あとでSimpleDirectoryReaderで読み込むのだけども、SimpleDirectoryReaderは拡張子によって呼び出されるモジュールがかわり、これによりチャンク分割の仕方が変わる(markdownだとセクションで分割される。txtだとまるっと読み込まれる)ので、今回はあえて.txtにしている。
Dense X Retrieval Packを読み込む。
from llama_index.llama_pack import download_llama_pack
DenseXRetrievalPack = download_llama_pack(
"DenseXRetrievalPack", "./dense_pack"
)
DenseXRetrievalPackでドキュメントからインデックスやクエリエンジンを含んだDenseXRetrievalPackオブジェクトを初期化する。
import nest_asyncio
from llama_index import SimpleDirectoryReader
nest_asyncio.apply()
documents = SimpleDirectoryReader("./data").load_data()
dense_pack = DenseXRetrievalPack(documents)
とりあえずクエリ
response = dense_pack.run(
"ドウデュースの主な勝ち鞍を教えて。", similarity_top_k=2
)
print(response)
ドウデュースの主な勝ち鞍は、2021年の朝日杯フューチュリティステークス、2022年の東京優駿、2023年の有馬記念です。
DenseXRetrievalPackのモジュールを見てみる。
modules = dense_pack.get_modules()
print(modules.keys())
クエリエンジンとリトリーバーだけが見える。
dict_keys(['query_engine', 'retriever'])
get_modules()
で定義されていないものを見てみる。
print([attr for attr in dir(dense_pack) if not attr.startswith('_') and not callable(getattr(dense_pack, attr))])
インデックスもある。
['query_engine', 'retriever', 'vector_index']
インデックスから直接ノードをリストアップしてみる。
node_doc_ids = dense_pack.vector_index.index_struct.nodes_dict.values()
for idx, node in enumerate(dense_pack.vector_index.docstore.get_nodes(node_doc_ids), start=1):
str_len = 30
output_str = "{}: ({}) {}".format(idx, len(node.text), node.text.replace("\n", " ")[:str_len])
if len(node.text):
output_str += "..."
print(output_str)
1: (930) # イクイノックス イクイノックス(欧字名:Equinox...
2: (870) 従って後述の新馬戦は岩戸厩舎所属馬としてデビューしている。 ...
3: (905) 最後の直線ではメンバー最速の上がり3ハロン33秒6の末脚で追...
4: (949) ファン投票でも多くの票を集め、第1回中間発表、第2回中間発表...
5: (972) 正式に出走することとなった。鞍上は主戦騎手であるクリストフ・...
6: (926) 379票を獲得しファン投票1位の座を勝ち取った。 6月25...
7: (912) 前年と同じようなレース展開に対して、イクイノックスは、昨年は...
8: (934) さらに、ドバイシーマクラシックの分(約4億6000万円)も含...
9: (913) 9を0.1秒上回った。1着賞金5億円を加え、総獲得賞金は22...
10: (926) アクセレーション(加速)がすごかったです。1番枠にリバティア...
11: (944) 同日付でJRAの競走馬登録を抹消された。 なお、種牡馬入りの...
12: (958) 社台スタリオンステーションの発表によれば、イクイノックスの2...
13: (799) イギリスのタイムフォーム社は、独自方式の「タイムフォームレー...
14: (931) # ドウデュース ドウデュース(欧字名:Do Deuce、...
15: (860) 単勝オッズ2.2倍の1番人気に推された。道中は勝ち馬アスクビ...
16: (862) 6月10日に国際競馬統括機関連盟が発表した「ロンジンワールド...
17: (846) しかし出馬投票後の同月24日、調教後に左前肢跛行を発症しドバ...
18: (600) 馬番5番での優勝は、1970年のスピードシンボリ、1972年...
19: (32) イクイノックス is a Japanese racehors...
20: (119) イクイノックス achieved the first GI ...
21: (275) In 2023, イクイノックス became the fi...
22: (100) The meaning of the horse's nam...
23: (170) イクイノックス won the Emperor's Cup ...
24: (95) イクイノックス is the JRA Horse of th...
25: (269) イクイノックス is the first progeny o...
26: (546) イクイノックス was born on March 23, ...
27: (314) Before his debut, イクイノックス was ...
28: (342) On August 28, イクイノックス made his...
29: (26) 後述の新馬戦は岩戸厩舎所属馬としてデビューしている。...
30: (24) 8月28日、新潟競馬場での2歳新馬戦でデビュー。...
31: (66) レースでは好位のインに控え直線で先頭に立ってサークルオブライ...
32: (37) 本馬が見せた末脚は、長距離向きと見ていたノーザンファームの桑...
33: (47) 木村厩舎に戻って初戦となる11月20日の東京スポーツ杯2歳ス...
34: (57) レースでは後方馬群で待機、直線では上がり3ハロン32秒9の末...
35: (24) 本馬はキタサンブラック産駒の重賞初制覇となった。...
36: (44) 予定通りトライアル競走を用いず、3歳初戦として中147日のロ...
37: (38) レースでは大外枠から中団につけ、勝負どころで好位の3番手につ...
38: (39) 一度は他馬を突き放したが、最後は外から同厩舎のジオグリフに差...
39: (31) 鞍上のルメールは「休み明けだったけど、すごくいい競馬はできた...
40: (28) 外枠もあって壁を作れなかったけど、勝ち馬は作れたからね。...
41: (26) でもダービーはビッグチャンスだと思う」と振り返った。...
42: (12) 続いて、東京優駿に出走。...
43: (26) 皐月賞4着のダノンベルーガに次ぐ2番人気に推された。...
44: (18) 道中は後方3番手からレースを進める。...
45: (66) 最後の直線ではメンバー最速の上がり3ハロン33秒6の末脚で追...
46: (7) 鞍上のルメール...
47: (66) 最後の直線ではメンバー最速の上がり3ハロン33秒6の末脚で追...
48: (11) ルメールは鞍上である。...
49: (52) ルメールは直線で勝ち馬をマークして外に出して追いだしたら、相...
50: (32) ルメールは次のレースとして天皇賞(秋)に出走することを表明し...
51: (35) ルメールは東京優駿出走後の左前脚のダメージについて、経過は良...
52: (28) 10月30日、ルメールは予定通り天皇賞(秋)に出走した。...
53: (14) ルメールは1番人気であった。...
54: (63) ルメールは前半1000メートルを57秒4で通過するというハイ...
55: (83) ルメールは最後の直線に入ってムチを入れると、逃げ粘るパンサラ...
56: (15) ルメールはGI初勝利を飾った。...
57: (40) 天皇賞(秋)の3歳馬の勝利は前年のエフフォーリア以来2年連続...
58: (88) ルメールはキャリア5戦での天皇賞(秋)制覇は史上最短、前年の...
59: (40) キタサンブラック産駒はGI初制覇で、史上4組目の天皇賞(秋)...
60: (62) ルメールはレース後のインタビューで春はアンラッキーだったけど...
61: (55) ルメールは今回が彼の最初のGIですが、これが最後ではないと改...
62: (184) イクイノックス collected many votes i...
63: (1137) On December 25th, as scheduled...
64: (22) At the age of 4 (2023)...
65: (20) Dubai Sheema Classic...
66: (639) On January 17th, the Internati...
67: (345) He announced that he would par...
68: (299) On March 25th (March 26th Japa...
69: (60) イクイノックス officially participate...
70: (32) クリストフ・ルメール served as the jocke...
71: (48) イクイノックス started the race well ...
72: (45) イクイノックス won the race with a co...
73: (63) ウエストオーバー finished second with ...
74: (53) The winning time was 2:25.65, ...
75: (79) イクイノックス achieved the first ove...
76: (120) ルメール stated that he knew that ...
77: (101) イクイノックス was ranked first with ...
78: (88) This was the third time a Japa...
79: (68) イクイノックス announced that he woul...
80: (38) クリストフ・ルメール continued to be the...
81: (55) イクイノックス also announced that hi...
82: (60) The fan voting for the Takaraz...
83: (165) イクイノックス received the most vote...
84: (56) イクイノックス participated in the Ta...
85: (76) イクイノックス overcame a stumble at ...
86: (91) イクイノックス held off the pursuit o...
87: (55) This was the fourth consecutiv...
88: (59) イクイノックス won the first place in...
89: (72) イクイノックス participated in the Ta...
90: (110) イクイノックス stumbled at the start ...
91: (130) イクイノックス started moving on the ...
92: (141) イクイノックス won by a neck against ...
93: (139) キタサンブラック, the father of イクイノック...
94: (252) As a result, イクイノックス achieved ...
95: (100) The achievement of surpassing ...
96: (113) ルメール, who rode イクイノックス, achiev...
97: (128) イクイノックス announced that he will...
98: (205) On October 12, the Longines Wo...
99: (79) As scheduled, イクイノックス particip...
100: (131) After a good start, イクイノックス ch...
101: (198) Entering the final straight, イ...
102: (137) イクイノックス achieved 5 consecutive...
103: (216) The number 57.7 seconds for th...
104: (208) In response to a similar race ...
105: (167) While イクイノックス took the lead in...
106: (28) イクイノックスは昨年中団馬群の後方から追い込み勝利した。...
107: (41) イクイノックスは今年ジャックドール、ガイアフォースの後ろの3...
108: (24) ドウデュースは直後にいたが失速し後方へ下がった。...
109: (24) ヒシイグアスも直後にいたが失速し後方へ下がった。...
110: (17) ジャスティンパレスは最後方にいた。...
111: (15) プログノーシスは最後方にいた。...
112: (19) イクイノックスだけが先行して勝利した。...
113: (31) ルメールはイクイノックスの背中の上だと普通のペースだと述べた...
114: (37) ルメールはイクイノックスは跳びが大きくて、スムーズな走り方を...
115: (52) ルメールはイクイノックスは全然力を使っていないから、3番手で...
116: (27) 走破タイム1分55秒2は世界レコード更新と認識された。...
117: (26) ルメールはイクイノックスは世界一の馬であると述べた。...
118: (30) ルメールはイクイノックスは全部を持っている馬であると述べた。...
119: (57) ルメールはイクイノックスはスタートからいいポジションが取れる...
120: (25) ルメールはイクイノックスはスタミナもあると述べた。...
121: (29) ルメールはイクイノックスはまだ強く、タフになれると述べた。...
122: (35) ルメールはこの秋はイクイノックスのピークに持っていけると思う...
123: (35) イクイノックスのJRA総獲得賞金は12億5269万2000円...
124: (32) イクイノックスの総獲得賞金は17億1158万2100円となっ...
125: (21) キタサンブラックは天皇賞3勝を挙げている。...
126: (41) イクイノックスとキタサンブラックは親子ともに天皇賞2勝以上は...
127: (24) 総獲得賞金は17億1158万2100円となった。...
128: (26) 総獲得賞金はオルフェーヴルを抜いて歴代6位となった。...
129: (22) 父キタサンブラックも天皇賞3勝を挙げている。...
130: (24) 親子ともに天皇賞2勝以上は史上初の快挙となった。...
131: (44) 天皇賞(春)のレコードと天皇賞(秋)の優勝タイム最遅記録はキ...
132: (21) 天皇賞レコードを親子で独占する形となった。...
133: (31) イクイノックスの生産者はノーザンファームの吉田勝己代表である...
134: (20) 吉田勝己代表はあの時計を見て驚きました。...
135: (36) 吉田勝己代表はイクイノックスを見て馬がさらによくなっていると...
136: (24) 吉田勝己代表はこれ以上があるのか、と驚きました。...
137: (21) 前半57秒7で行って後半は57秒5でしょ。...
138: (11) 常識から外れています。...
139: (12) 安藤勝己は元騎手である。...
140: (30) 安藤勝己はイクイノックスのスピードとスタミナを分析しました。...
141: (18) 安藤勝己はイクイノックスを称賛した。...
142: (12) 田原成貴は元騎手である。...
143: (39) 田原成貴はイクイノックスに歯向かった馬がみんな木っ端みじんに...
144: (54) 逆らわなかった馬だけが好走するとは皮肉であり、それもまたイク...
145: (30) 次走として当初の予定通りジャパンカップに出走すると表明した。...
146: (13) ジャパンカップに出走した。...
147: (21) パンサラッサを追う形で3番手から追走した。...
148: (23) イクイノックスは慌てることなく前を追いかけた。...
149: (20) イクイノックスは坂の途中で先頭に立った。...
(snip)
dense_pack/base.py
のコードを見るとわかるのだけども、Recursive Retrieverが使用されている。
- ドキュメントをデフォルトのSentenceSplitterでノード分割、つまり1024文字でチャンクされる。
- SentenceSplitterで分割された1024文字のノードごとに、命題に分割する
_aget_proposition
でサブノードに分割。 - 命題に分割されたサブノードと元の親ノードをRecursive Retrieverで紐づけ。
となっていて、上記の出力の最初の18個ぐらいまではデフォルトで分割されたベースノードで、それ以降はそこから命題に分割されたサブノードということになる。retrieverが検索するのはこのサブノードで、LLMに渡されるのはそれに紐づいたベースノードということだと思う。
デバッグログを表示するとよく分かる。
クエリから検索されたのは以下。
DEBUG:llama_index.indices.utils:> Top 4 nodes:
> [Node d498b676-ad57-4cb1-ab4c-fa69da766831] [Similarity score: 0.906044] ドウデュースは凱旋門賞への出走を表明した。
> [Node 06351115-a09d-4e1f-853d-83555a22e48d] [Similarity score: 0.889991] ドウデュースは京都記念でGIを含む重賞3勝目を挙げた。
> [Node 011a119c-c33c-40d7-8776-95b8794922bd] [Similarity score: 0.888117] ドウデュースは日本ダービーを勝利した功績を評価され、シャフリヤールやエンブレムロードと並ぶレーティング120で第15位タイに位置づけられた。
> [Node 0ad50b0d-3679-4b59-a5a8-2dbb534317db] [Similarity score: 0.883668] ドウデュース was trained by 友道康夫.
そこからベースノードが引っ張られて、実際にプロンプトに含められているのは以下。
file_path: data/ドウデュース.txt
6月10日に国際競馬統括機関連盟が発表した「ロンジンワールドベストレースホースランキング」において、ドウデュースは日本ダービーを勝利した功績を評価され、シャフリヤールやエンブレムロードと並ぶレーティング120で第15位タイに位置づけられた。
(snip)
次走は3月25日にドバイのメイダン競馬場で行われるドバイターフとし、同月15日(現地時間同月14日)にメイダン競馬場に到着した。しかし出馬投票後の同月24日、調教後に左前肢跛行を発症しドバイターフへの出走を取り消した。友道は「調教後に左腕節に違和感を認め、競馬に向けて進めておりましたが、将来のある馬なのでここでは無理をせず、取り消すことを決断いたしました」と語った。
その後夏は治療と休養にあて、秋初戦として10月29日に東京競馬場で開催される天皇賞(秋)に出走。
file_path: data/ドウデュース.txt
# ドウデュース
ドウデュース(欧字名:Do Deuce、2019年5月7日 - )は、日本の競走馬。主な勝ち鞍は2021年の朝日杯フューチュリティステークス、2022年の東京優駿、2023年の有馬記念。
(snip)
残り800メートル過ぎに後方からロジハービンが一気に進出したため、いったんポジションを下げる。そこから立て直し、ゴール前では勝ち馬を懸命に追い上げたがクビ差届かず2着に。デビューからの連勝は3でストップした。
続いて、4月17日に行われた皐月賞に出走。
ベースノードは比較的大きなチャンクになっているので、ある程度のコンテキストボリュームを含んでいるので、それを拾えれば比較的クエリに答えやすい回答が出しやすくなると思う。
Dense X Retrieval の論文とDenseXRetrievalPackの実装にはややちょっと異なる点がある。
前提として、チャンク分割の難しさは以下。
- ユーザのクエリは基本的に小さい
- 大きなチャンク
- メリット
- クエリの回答に必要十分なコンテキストを含んでいる
- デメリット
- ユーザクエリとの類似性が低くなり、検索に引っかかりにくい
- クエリと関係のないノイズも含まれる
- メリット
- 小さなチャンク
- メリット
- ユーザクエリとの類似性が高くなり、検索に引っかかりやすい
- クエリと関係のないノイズも含まれる
- デメリット
- クエリの回答に必要なコンテキストが失われるため、回答の質が下がる。
- メリット
Dense X Retrievalはこれを以下の点で解決する
- 「文章」を単純な「文」に分解する際に「命題化」する。
- 前後の文章にあるコンテキスト等を取り込んで命題に取り込む
- 前後の文章がなくても、単一の文だけで一定のコンテキストを保持できるようになる
- これにより、チャンク分割の課題を解決する
- 短いチャンクになるので、クエリと合致しやすくする
- 短いチャンクになるが、LLMの回答に必要なコンテキストを含めることができる
そもそも論文を見る限り、命題化された文章をLLMへのプロンプトに含めること「も」必要なのではないか?
Recusive Retrieverを使うってのは自分も確かに考えた。いくら命題にコンテキストを詰め込んで分割したとしても、その「セクション」が何について書かれているか?とかの大きなコンテキストは失われるだろうし、同じセクション内の周辺コンテキストも含めて、回答のリッチさを増やすのは必然だと思うし。その意味ではSentence Window Node Parserみたいな考え方でも良いと思う。
ただRecursiveに引っ張ってくるベースノードが元のドキュメントを分割しただけのものなのであれば、PassageでRetrievalしてるのと変わらない気がするのよなー。多分やるとするならば、
- ドキュメントを命題に分割
- 分割された命題を一定のコンテキストの塊にまとめる。
- Recursive Retrieverで命題をサブノード、上記をベースノードとする。
か、
- ドキュメントを一定のコンテキストの塊に分割する
- 分割された塊ごとに命題化する
- Recursive Retrieverで命題をサブノード、上記をベースノードとする。
にするのが良いのだと思う。元のコンテンツとは違うものになってしまうところに若干躊躇するわけではないけども(ソースドキュメントを提示するとかが必要だったりすると特に)