Closed5

LLamaIndexのSemantic Chunkerを試す

kun432kun432

Semantic Chunking

Semantic Chunkingは、Greg Kamradt氏の「The 5 Levels Of Text Splitting For Retrieval」で提唱された、チャンク分割の新しいコンセプト。Kamradt氏の動画は以下にある。

https://youtu.be/8OJC21T2SL4?t=1933

一般的にチャンク分割は固定のチャンクサイズで行われることが多いが、Semantic Chunkingでは、文ごとにEmbeddingの類似性を取得して、類似度に差がある箇所をブレークポイントとすることで、意味を持ったチャンク分割を行うというもの。

https://twitter.com/llama_index/status/1745482959237615847

LlamaIndexではSemanticSplitterNodeParserを使うことでSemantic Chunkingが利用できる。

おそらく文の分割は正規表現で行われているようで、英語では機能する、と書かれている。またブレークポイントをパーセンタイルで設定できるようだが、このあたりはチューニングが必要になりそう。

以下でNotebookが公開されているため、日本語でも使えるかを試してみる。
https://docs.llamaindex.ai/en/stable/examples/node_parsers/semantic_chunking.html

kun432kun432

まずは英語で試してみる。サンプルはおなじみのこれ。

https://paulgraham.com/worked.html

!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/pg_essay.txt'
from llama_index import SimpleDirectoryReader
from llama_index.node_parser import SentenceSplitter, SemanticSplitterNodeParser,
from llama_index.embeddings import OpenAIEmbedding

documents = SimpleDirectoryReader(input_files=["data/pg_essay.txt"]).load_data()

embed_model = OpenAIEmbedding()

# SemanticSplitterNodeParserを使ったSplitter
semantic_splitter = SemanticSplitterNodeParser(
    buffer_size=1,
     breakpoint_percentile_threshold=95,
     embed_model=embed_model
)

# 通常のSentenceSplitter
base_splitter = SentenceSplitter(chunk_size=512)

# それぞれでドキュメントをノードに分割
semantic_nodes = semantic_splitter.get_nodes_from_documents(documents)
base_nodes = base_splitter.get_nodes_from_documents(documents)

ではどのように分割されているかを見てみる。

print(len(semantic_nodes))
print(len(base_nodes))
39
56
for idx, n in enumerate(semantic_nodes[:5]):
    print(idx, n.get_content().replace("\n","")[:100])
0 What I Worked OnFebruary 2021Before college the two main things I worked on, outside of school, were
1 I didn't write essays. I wrote what beginning writers were supposed to write then, and probably stil
2 I couldn't figure out what to do with it. And in retrospect there's not much I could have done with 
3 For the next couple years I was on a roll. I knew what I was going to do.For my undergraduate thesis
4 I had no idea. I'd never imagined it was even possible. I knew intellectually that people made art —
for idx, n in enumerate(base_nodes[:5]):
    print(idx, n.get_content().replace("\n","")[:100])
0 What I Worked OnFebruary 2021Before college the two main things I worked on, outside of school, were
1 The only form of input to programs was data stored on punched cards, and I didn't have any data stor
2 This was when I really started programming. I wrote simple games, a program to predict how high my m
3 I haven't tried rereading The Moon is a Harsh Mistress, so I don't know how well it has aged, but wh
4 I had gotten into a program at Cornell that didn't make you choose a major. You could take whatever 

ノードの分割が異なっているのがわかる。

少し細かく見てみる。

0番目のチャンク

print(semantic_nodes[0].get_content())
print("\n----------\n")
print(base_nodes[0].get_content())

What I Worked On

February 2021

Before college the two main things I worked on, outside of school, were writing and programming.


What I Worked On

February 2021

Before college the two main things I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write then, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters with strong feelings, which I imagined made them deep.

The first programs I tried writing were on the IBM 1401 that our school district used for what was then called "data processing." This was in 9th grade, so I was 13 or 14. The school district's 1401 happened to be in the basement of our junior high school, and my friend Rich Draves and I got permission to use it. It was like a mini Bond villain's lair down there, with all these alien-looking machines — CPU, disk drives, printer, card reader — sitting up on a raised floor under bright fluorescent lights.

The language we used was an early version of Fortran. You had to type programs on punch cards, then stack them in the card reader and press a button to load the program into memory and run it. The result would ordinarily be to print something on the spectacularly loud printer.

I was puzzled by the 1401. I couldn't figure out what to do with it. And in retrospect there's not much I could have done with it. The only form of input to programs was data stored on punched cards, and I didn't have any data stored on punched cards. The only other option was to do things that didn't rely on any input, like calculate approximations of pi, but I didn't know enough math to do anything interesting of that type. So I'm not surprised I can't remember any programs I wrote, because they can't have done much. My clearest memory is of the moment I learned it was possible for programs not to terminate, when one of mine didn't. On a machine without time-sharing, this was a social as well as a technical error, as the data center manager's expression made clear.

With microcomputers, everything changed. Now you could have a computer sitting right in front of you, on a desk, that could respond to your keystrokes as it was running instead of just churning through a stack of punch cards and then stopping.

DeepL訳。同じ英文が含まれるけど、まるっと翻訳させてるので多少異なる点はご容赦を。。。

私が取り組んだこと

2021年2月

大学入学前、学校以外で主に取り組んでいたのは、文章を書くこととプログラミングだった。


取り組んだこと

2021年2月

大学入学前、学校以外で主に取り組んでいたのは、文章を書くこととプログラミングの2つだった。エッセイは書かなかった。当時も今も、作家の初心者が書くことになっている短編小説を書いた。私の物語はひどかった。筋書きはほとんどなく、ただ強い感情を持った登場人物たちがいて、それが深みのあるものだと想像していた。

私が最初に書こうとしたプログラムは、学区で当時 "データ処理 "と呼ばれていたものに使われていたIBM 1401だった。9年生のときだから、13歳か14歳だった。たまたま学区の1401が中学校の地下にあったので、友人のリッチ・ドレイブスと私は使用許可を得た。そこはまるでボンドの悪役の隠れ家のようで、CPU、ディスク・ドライブ、プリンター、カード・リーダーといったエイリアンのような機械が、明るい蛍光灯の下、一段高くなった床の上に置かれていた。

私たちが使っていた言語はFortranの初期バージョンだった。パンチカードにプログラムを打ち込み、それをカードリーダーに重ねてボタンを押すと、プログラムがメモリにロードされて実行された。その結果、通常なら目を見張るような大音量のプリンターで何かを印刷することになる。

私は1401に戸惑った。それで何をすればいいのかわからなかったのだ。今にして思えば、私が1401でできたことはそれほど多くはなかった。プログラムへの入力はパンチカードに保存されたデータしかなかったが、私はパンチカードに保存されたデータを持っていなかった。他の唯一の選択肢は、円周率の近似値を計算するような、入力に依存しないことをすることだったが、私はその種の面白いことをするほど数学を知らなかった。だから、自分が書いたプログラムを覚えていないのも不思議ではない。一番はっきり覚えているのは、プログラムが終了しないことがあり得ると知った瞬間のことだ。タイムシェアリングのないマシンでは、これは技術的なエラーであると同時に社会的なエラーでもあった。

マイクロコンピューターが登場すると、すべてが変わった。目の前の机の上にコンピュータを置くことができるようになり、パンチカードの束を動かして停止させるのではなく、実行中にキー入力に応答できるようになった。

1番目のチャンク

print(semantic_nodes[1].get_content().replace("\n",""))
print("==========")
print(base_nodes[1].get_content().replace("\n",""))

ここからは日本語訳のみ。

私はエッセイは書かなかった。当時も、そしておそらく今も、初級作家が書くことになっている短編小説を書いた。私の物語はひどかった。筋書きはほとんどなく、ただ登場人物が強い感情を持っていて、それが深みのあるものだと想像していた。

私が最初に書こうとしたプログラムは、学区で当時 "データ処理 "と呼ばれていたものに使われていたIBM 1401だった。9年生のときだから、13歳か14歳だった。たまたま学区の1401が中学校の地下にあったので、友人のリッチ・ドレイブスと私は使用許可を得た。そこはまるでボンドの悪役の隠れ家のようで、CPU、ディスク・ドライブ、プリンター、カード・リーダーといったエイリアンのような機械が、明るい蛍光灯の下、一段高くなった床の上に置かれていた。

私たちが使っていた言語はFortranの初期バージョンだった。パンチカードにプログラムを打ち込み、それをカードリーダーに重ねてボタンを押すと、プログラムがメモリにロードされて実行された。その結果、通常なら目を見張るような大音量のプリンターで何かを印刷することになる。

私は1401に戸惑った。


プログラムへの入力はパンチカードに保存されたデータだけで、私はパンチカードに保存されたデータを持っていなかった。他の唯一の選択肢は、円周率の近似値を計算するような、入力に依存しないことをすることだったが、私はその種の面白いことをするほど数学を知らなかった。だから、自分が書いたプログラムを覚えていないのも不思議ではない。一番はっきり覚えているのは、プログラムが終了しないことがあり得ると知った瞬間のことだ。タイムシェアリングのないマシンでは、これは技術的なエラーであると同時に社会的なエラーでもあった。

マイクロコンピューターが登場すると、すべてが変わった。目の前の机の上にコンピュータが置かれ、パンチカードの束を動かして停止するのではなく、実行中にキー入力に応答できるようになったのだ。[1]

マイコンを手に入れた最初の友人は、自分でそれを作った。ヒースキット社からキットとして販売されていた。彼がマイコンの前に座り、コンピュータにプログラムを打ち込んでいるのを見て、とても感心し、うらやましく思ったのを鮮明に覚えている。

当時のコンピューターは高価で、1980年頃に父を説得してTRS-80を買ってもらうまで、私は何年も口うるさく言い聞かせた。当時のゴールド・スタンダードはApple IIだったが、TRS-80で十分だった。プログラミングを本格的に始めたのはこの頃だ。簡単なゲームや、モデルロケットがどれくらい高く飛ぶかを予測するプログラムを書いたり、父が少なくとも1冊の本を書くのに使ったワープロを書いたりした。メモリには2ページ分しか空きがなかったので、父は一度に2ページずつ書いてはプリントアウトしていたが、タイプライターよりはずっとよかった。

プログラミングは好きだったが、大学で勉強するつもりはなかった。大学では哲学を学ぼうと思っていた。素朴な高校生の私には、哲学は究極の真理を研究する学問に思えた。大学に入ってわかったのは、他の分野が思想の空間を占めすぎていて、究極の真理とされるもののために残されたものはあまりないということだった。

2番目のチャンク

print(semantic_nodes[3].get_content())
print("\n----------\n")
print(base_nodes[3].get_content())

それから数年間、私は絶好調だった。自分が何をすべきかは分かっていた。

学部卒業論文では、SHRDLUをリバースエンジニアリングした。あのプログラムの研究は本当に楽しかった。ちょっとしたコードも嬉しかったが、それ以上にエキサイティングだったのは、今となっては想像もつかないが、1985年当時としては特異なことではなかった。

私はコーネル大学の専攻を選ばせないプログラムに入った。好きな授業を取り、好きなものを選んで学位につけることができた。私はもちろん "人工知能 "を選んだ。実際の卒業証書を手にしたとき、引用符が含まれていて、それが恐怖引用符のように読めることに気づき、落胆した。当時はそれが気になったが、今となっては面白いほど正確に思える。

私は3つの大学院に出願した: 当時AIで有名だったMITとイェール、そしてハーバードだ。ハーバードにはリッチ・ドレイブスが通っていて、私がSHRDLUクローンで使っていたパーサを発明したビル・ウッズの出身校でもあった。ハーバードだけが私を受け入れてくれたので、私はそこに進学した。

その瞬間がいつだったのか、具体的な瞬間があったのかさえ覚えていないが、大学院の1年目に、私は当時実用化されていたAIがデマであることに気づいた。つまり、「犬が椅子の上に座っている」と言われたプログラムが、それを何らかの形式的な表現に変換し、知っていることのリストに追加するようなAIのことだ。

これらのプログラムが本当に示したのは、自然言語には形式言語のサブセットがあるということだ。しかし、それは非常に適切なサブセットである。これらのプログラムができることと、実際に自然言語を理解することの間には、埋めがたい隔たりがあることは明らかだった。実際、SHRDLUに単に多くの単語を教えればいいという問題ではなかった。概念を明示的なデータ構造で表すという、AIのやり方全体がうまくいくはずがなかったのだ。その破綻は、よくあることだが、応急処置としてさまざまな論文を書く機会をたくさん生み出した。

そこで、私は自分の計画の残骸から何か救い出せるものはないかと見回したところ、Lispがあった。私は経験から、LispはAIとの関連だけでなく、それ自体が興味深いものだと知っていました。だから私はLispに集中することにした。実際、私はLispハッキングについての本を書くことにした。その本を書き始めたとき、私はLispハッキングについてほとんど知らなかったと思うと恐ろしい。しかし、何かについて本を書くことほど、それを学ぶのに役立つことはありません。この本『On Lisp』が出版されたのは1993年のことだが、その大部分は大学院時代に書いたものだ。

コンピュータ・サイエンスは、理論とシステムという2つの部門の間の不穏な同盟である。理論担当者は物事を証明し、システム担当者は物事を構築する。私はモノを作りたかった。理論に対する尊敬の念は十分にあったし、実際、理論の方が立派なのではという疑念もあった。

しかし、システムの仕事は長続きしないという問題があった。今日あなたが書いたプログラムは、どんなに優れていても、せいぜい数十年で時代遅れになる。人々は脚注の中であなたのソフトウェアについて言及するかもしれないが、実際に使う人はいないだろう。そして実際、それは非常に弱々しい仕事に見えるだろう。その分野の歴史を知っている人だけが、その時代には良いものだったと気づくだろう。

ゼロックスのダンデライオンは、ある時期、コンピューター室に何台か余っていた。遊びたい人は誰でも手に入れることができた。私も一時はその気になったが、現在の基準からするととても遅い。他の誰も欲しがらなかったので、彼らは去っていった。それがシステム・ワークの始まりだった。

私はただモノを作るのではなく、長持ちするモノを作りたかった。

そんな不満を抱えたまま1988年、私はリッチ・ドレイブスが大学院に通っていたCMUを訪ねた。ある日、私は子供の頃によく過ごしたカーネギー・インスティテュートを訪ねた。そこで絵画を見ているうちに、当たり前のようだが、私にとっては大きな驚きだったことに気づいた。壁に描かれた絵は、長く使えるものだったのだ。絵画は廃れることはなかった。最高のものは何百年も前のものもある。

しかもこれは、生計を立てることができるものだった。もちろん、ソフトウェアを書くほど簡単ではないけれど、本当に勤勉で、本当に安く暮らせば、生きていくのに十分な額を稼ぐことは可能なはずだと思った。そして、アーティストとして独立することもできる。上司もいないし、研究費をもらう必要もない。

私は昔から絵を見るのが好きだった。自分にも作れるだろうか?


月は苛酷な愛人』を再読したことがないので、どの程度古くなっているかはわからないが、読んだとき、私はその世界に完全に引き込まれた。マイクができるのは時間の問題だと思ったし、ウィノグラードがSHRDLUを使っているのを見たとき、その時間はせいぜい数年だろうと思った。SHRDLUにもっと多くの言葉を教えればよかったんだ。

当時、コーネル大学にはAIの授業はなく、大学院の授業でさえなかった。当時、LispはAIの言語とみなされていたからだ。当時、一般的に使われていたプログラミング言語はかなり原始的で、プログラマーの考え方もそれに比例していました。コーネル大学のデフォルト言語はPL/Iと呼ばれるPascalのような言語だったし、他の大学でも似たような状況だった。Lispを学んだことで、プログラムの概念が急速に広がった。これはむしろ、私が大学に期待していたことだった。授業では想定していたようなことは起こらなかったが、それでもよかった。それから数年間、私は絶好調だった。私は自分が何をするつもりなのか分かっていた。

学部卒業論文では、SHRDLUをリバースエンジニアリングした。あのプログラムの研究は本当に楽しかった。ちょっとしたコードも嬉しかったが、それ以上にエキサイティングだったのは、今となっては想像もつかないが、1985年当時としては特異なことではなかった。

私はコーネル大学の専攻を選ばせないプログラムに入った。好きな授業を取り、好きなものを選んで学位につけることができた。私はもちろん "人工知能 "を選んだ。実際の卒業証書を手にしたとき、引用符が含まれていて、それが恐怖引用符のように読めることに気づき、落胆した。当時はそれが気になったが、今となっては面白いほど正確に思える。

私は3つの大学院に出願した: 当時AIで有名だったMITとイェール、そしてハーバードだ。ハーバードにはリッチ・ドレイブスが通っていて、私がSHRDLUクローンで使っていたパーサーを発明したビル・ウッズの出身校でもあった。

base_splitterはある程度同じサイズで分割されているのに対し、SemanticSplitterNodeParserを使ったノードは、notebookにもあるように、

0番目: 冒頭
1番目: IMB1401との出会い
2番目: プログラミングと大学生活

といった感じに分かれているのがわかる。

kun432kun432

日本語で試してみる。

サンプルはこれ。

https://ja.wikipedia.org/wiki/イクイノックス

from pathlib import Path
import requests

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 = page["extract"]

    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)
from llama_index import SimpleDirectoryReader
from llama_index.node_parser import SentenceSplitter, SemanticSplitterNodeParser,
from llama_index.embeddings import OpenAIEmbedding

documents = SimpleDirectoryReader(input_files=["data/イクイノックス.txt"]).load_data()

embed_model = OpenAIEmbedding()

semantic_splitter = SemanticSplitterNodeParser(
    buffer_size=1,
    breakpoint_percentile_threshold=95,
    embed_model=embed_model
)

base_splitter = SentenceSplitter(chunk_size=512)

semantic_nodes = semantic_splitter.get_nodes_from_documents(documents)
base_nodes = base_splitter.get_nodes_from_documents(documents)

SemanticSplitterNodeParserでノード分割する際にコケる。

BadRequestError: Error code: 400 - {'error': {'message': "This model's maximum context length is 8192 tokens, however you requested 10296 tokens (10296 in your prompt; 0 for the completion). Please reduce your prompt; or completion length.", 'type': 'invalid_request_error', 'param': None, 'code': None}}

リクエストの中身を見てみると、どうやらうまく分割できずに、全部のテキストを1回でEmbedding APIに送ってトークンサイズを超えている模様。

SemanticSplitterNodeParserのコードを見ると、どうやらテキストを文に分割するための関数を渡せる模様。

https://github.com/run-llama/llama_index/blob/main/llama_index/node_parser/text/semantic_splitter.py#L26-L43

ChatGPTに日本語の文章を分割する関数を書いてもらった。

def japanese_sentence_splitter(text):
    sentences = []
    buffer = ""

    for char in text:
        buffer += char
        if char in ["\n", "。"]:
            if buffer.strip():
                sentences.append(buffer.strip())
                buffer = ""

    if buffer.strip():
        sentences.append(buffer.strip())

    return sentences

お試し。

japanese_sentence_splitter(documents[0].get_content())[:5]
['イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。',
 '2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。',
 '馬名の意味は「昼と夜の長さがほぼ等しくなる時」。',
 '2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。',
 '主な勝ち鞍は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。']

これをSemanticSplitterNodeParserで指定する。

semantic_splitter = SemanticSplitterNodeParser(
    buffer_size=1,
    breakpoint_percentile_threshold=95,
    embed_model=embed_model,
    sentence_splitter=japanese_sentence_splitter     # ここ
)

再度実行

semantic_nodes = semantic_splitter.get_nodes_from_documents(documents)
base_nodes = base_splitter.get_nodes_from_documents(documents)

print(len(semantic_nodes))
print(len(base_nodes))
12
34

どういうふうに分割されているのかを少しだけ見てみる。

for idx, n in enumerate(semantic_nodes[:5]):
    print(idx, n.get_content().replace("\n","")[:100])
0 イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味
1 ==== 天皇賞・秋 ====次走として天皇賞(秋)に出走することを表明した。東京優駿出走後の左前脚のダメージについては、経過は良好とした。10月30日、予定通り天皇賞(秋)に出走。1番人気に推され、
2 ==== 有馬記念 ====次走として有馬記念に出走すると表明した。ファン投票でも多くの票を集め、第1回中間発表、第2回中間発表で共に3位の票数を獲得し、最終結果発表でも294,688票を集め3位とな
3 ==== 宝塚記念 ====次走として宝塚記念に出走すると表明した。鞍上は引き続きクリストフ・ルメールが務める。秋は外国遠征のプランもあったが、最終的にジャパンカップを目標とすることも発表した。宝塚記
4 ==== 天皇賞・秋連覇 ====次走として連覇のかかる天皇賞(秋)に出走すると表明した。10月12日、ロンジンワールドベストレースホースランキング(2023年1月1日から10月8日までの世界の主要レ

普通にチャンクサイズ固定したほうはこう

for idx, n in enumerate(base_nodes[:5]):
    print(idx, n.get_content().replace("\n","")[:100])
0 イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味
1 == 血統・デビュー前 ==キタサンブラックの初年度産駒である。GIを7勝し、演歌歌手・北島三郎が実質的なオーナーである事からも注目を浴びた父を持ち、母はマーメイドステークスを制覇したシャトーブランシ
2 == 戦績 ===== 2歳(2021年) ===デビュー前に木村の自厩舎所属騎手に対するパワーハラスメントの一件で略式命令を受けたため、JRAから調教停止処分を受けた事に伴い、2021年7月29日か
3 8月28日、新潟競馬場 (芝 1,800m) での2歳新馬戦でデビュー。クリストフ・ルメールを鞍上に迎えたレースでは、好位のインに控え直線で先頭に立ってサークルオブライフ、ウィルソンテソーロなど後続を
4 === 3歳(2022年) ======= 春クラシック競走 ====予定通りトライアル競走を用いず、3歳初戦として中147日のローテーションで皐月賞に出走。前年のJRA賞最優秀2歳牡馬であるドウデュ

ぜんぜん異なるチャンク分割になっているのがわかる。

ではクエリエンジンを作成して実際に使ってみる。

from llama_index import VectorStoreIndex, ServiceContext
from llama_index.response.notebook_utils import display_source_node

from llama_index.llms import OpenAI

service_context = ServiceContext.from_defaults(
  llm=OpenAI(model="gpt-3.5-turbo", temperarture=0),
  embed_model=embed_model,
)

semantic_vector_index = VectorStoreIndex(semantic_nodes, service_context=service_context)
semantic_query_engine = vector_index.as_query_engine()

base_vector_index = VectorStoreIndex(base_nodes, service_context=service_context)
base_query_engine = base_vector_index.as_query_engine()
response = semantic_query_engine.query(
    "イクイノックスの主な勝ち鞍は?"
)
print("ANSWER: {}\n".format(str(response)))
for n in response.source_nodes:
    display_source_node(n, source_length=20000)

ANSWER: イクイノックスの主な勝ち鞍は、天皇賞(秋)の連覇です。また、GI競走では5連勝を達成しました。

Node ID: c8bf66c2-1e03-44ce-b096-4d47aed4dbdc
Similarity: 0.865539287786593
Text: ==== 天皇賞・秋連覇 ====次走として連覇のかかる天皇賞(秋)に出走すると表明した。10月12日、ロンジンワールドベストレースホースランキング(2023年1月1日から10月8日までの世界の主要レースを対象)が発表され、イクイノックスはレーティングは129ポンドで変わらず世界第1位となった。10月29日、予定通り天皇賞(秋)に出走。好スタートを切ると前半1000mを57秒7で逃げるジャックドールを追う形で先頭から3番手を追走。最後の直線に入ると先頭を走っていたガイアフォースを並ぶまもなく交わすと、最後に追ってきたジャスティンパレスの追撃も振り切りって勝ち時計1分55秒2というレコード記録で勝利。GI5連勝、史上3頭目となる天皇賞(秋)連覇を達成した。ジャックドールによる前半1000m通過57秒7という数字は、前年(2022年)のパンサラッサの大逃げによる同57秒4とコンマ3秒しか違わず、前年度と同じように全体的にタフな流れであった。前年と同じようなレース展開に対して、イクイノックスは、昨年は中団馬群の後方から追い込み勝利したのに対し、今年はジャックドール、ガイアフォースの後ろの3番手でレースを進めた。イクイノックスが直線半ばで先頭に立ったのと対照的に、直後にいたドウデュース(7着)やヒシイグアス(9着)らは失速し後方へ下がった。2着のジャスティンパレス、3着のプログノーシスは最後方にいた2頭であり、本来は典型的な追い込み決着となるはずであったレースにおいて、イクイノックスだけが先行して勝利したことから、よりイクイノックスの強さが際立つレースとなった。このレースの進め方に関して、鞍上のルメールは「イクイノックスの(背中の)上だと普通のペース。彼は跳びが大きくて、スムーズな走り方をする。全然力を使っていないから、3番手でもオーバーペースだとは思わなかった」と述べ、イクイノックスにとってこの度のレースは通常通りの走りであったことが説明された。また走破タイム1分55秒2は、1999年にクリスタルハウスがチリで記録した1分55秒4を上回り、広く「世界レコード更新」と認識された。鞍上のクリストフ・ルメールはレース後のインタビューで「安心しましたね。イクイノックスは世界一の馬ですから。世界のみんなが彼の競馬を見たかったと思う。イクイノックスの強さを見せられました」、「イクイノックスは全部を持っている馬。スタートからいいポジションが取れるし、その後冷静に走れて、いい脚で伸びてくれる。スタミナもある。完璧な馬です」とイクイノックスを称賛した。また、「彼はまだ強く、タフになれる。この秋はイクイノックスのピークに持っていけると思う」とさらに強くなる可能性があるとした。天皇賞(秋)を勝利したことにより、JRA総獲得賞金は12億5269万2000円となり、コントレイルを抜いて歴代10位となった。さらに、ドバイシーマクラシックの分(約4億6000万円)も含めると総獲得賞金は17億1158万2100円となり、オルフェーヴルを抜いて歴代6位となった。また、父キタサンブラックも天皇賞3勝を挙げており、親子ともに天皇賞2勝以上は史上初の快挙となった。なお2023年時点で天皇賞(春)のレコードと天皇賞(秋)の優勝タイム最遅記録はキタサンブラックが持っており、2023年秋の時点では天皇賞レコードを親子で独占する形となった。イクイノックスの生産者であるノーザンファームの吉田勝己代表は「あの時計を見て驚きました。

Node ID: d2a17401-2f32-44fd-8960-21235f370e7e
Similarity: 0.8609234820046091
Text: == 競走成績 ==以下の内容は、JBISサーチ、netkeiba.com、エミレーツ競馬協会およびTotal Performance Dataの情報に基づく。タイム欄のRはレコード勝ちを示す海外の競走の「枠番」欄にはゲート番を記載== 評価 ==2023年のジャパンカップでリバティアイランドに騎乗しイクイノックスと対戦した川田将雅は、イクイノックスを「現代日本競馬における『答え』であり、日本競馬史上最強の馬」と評価した。イクイノックスと5度対戦したジャスティンパレスの調教師である杉山晴紀は、イクイノックスについて「欠点がなくて、ある意味、サラブレッドの理想の形。そう言える走りでした。調教師として、いつかあんな馬に巡り合いたいと思う、偉大な馬です」と賛辞した。社台スタリオンステーションのスタッフは、netkeibaTVのインタビュー内にて「日本の馬産ならではの特徴が生んだ名馬なのだと考えています。レースでのパフォーマンスや、馬体、歩様を見ると、血統表にある個性の強い各馬の要素が高いレベルで融合したことで、全ての能力メーターが振り切れたような、あの走りができたのだと思えてきます。(中略)5代血統表を見渡すだけでも、3頭の凱旋門賞馬やキングジョージ勝ち馬といった欧州の名馬がいて、それでいて名スプリンターの血も複数持ち、もちろんサンデーサイレンスが生み出したディープインパクトの兄、そして名種牡馬ヌレイエフの血も流れていて…。様々な血脈をバランス良く織り重ねたような構成で、全てを良いとこ取りしたような馬なのだと思います」と答えている。イギリスのタイムフォーム社は、独自方式の「タイムフォームレーティング」にて、ジャパンカップにおけるイクイノックスを日本歴代首位のレーティング136と算定した。オーストラリアやニュージーランドにてGIを92勝し、現在は評論家を務めるシェーン・ダイは、「(イクイノックスは)世代を象徴する馬だ。滅多に世の中に現れるものではない」、「私の世代で最強馬と言えば、フランケル、フライトライン、そしてイクイノックス。この3頭が際立っている」と賞賛している。2024年1月9日、295票中293票という満票近い票を集めて年度代表馬に選出。これにより、2年連続で年度代表馬となった。また、親子で2年連続年度代表馬に選出されるのは史上初の事例となった。== 血統表 ==母シャトーブランシュは2015年のマーメイドステークスの勝ち馬。父の父ブラックタイドは2005年の中央競馬クラシック三冠ディープインパクトの全兄。半兄にヴァイスメテオール(父:キングカメハメハ)(ラジオNIKKEI賞)、近親にブランディス(中山大障害、中山グランドジャンプ)がいる。

response = base_query_engine.query(
    "イクイノックスの主な勝ち鞍は?"
)
print("ANSWER: {}\n".format(str(response)))
for n in response.source_nodes:
    display_source_node(n, source_length=20000)

ANSWER: イクイノックスの主な勝ち鞍は、GI5連勝であり、史上3頭目となる天皇賞(秋)連覇を達成しました。また、GI初勝利として天皇賞(秋)の3歳馬の勝利も挙げています。

Node ID: 87e8348a-3a05-4e37-ba0e-46717a93959e
Similarity: 0.8711760671422791
Text: GI5連勝、史上3頭目となる天皇賞(秋)連覇を達成した。ジャックドールによる前半1000m通過57秒7という数字は、前年(2022年)のパンサラッサの大逃げによる同57秒4とコンマ3秒しか違わず、前年度と同じように全体的にタフな流れであった。前年と同じようなレース展開に対して、イクイノックスは、昨年は中団馬群の後方から追い込み勝利したのに対し、今年はジャックドール、ガイアフォースの後ろの3番手でレースを進めた。イクイノックスが直線半ばで先頭に立ったのと対照的に、直後にいたドウデュース(7着)やヒシイグアス(9着)らは失速し後方へ下がった。2着のジャスティンパレス、3着のプログノーシスは最後方にいた2頭であり、本来は典型的な追い込み決着となるはずであったレースにおいて、イクイノックスだけが先行して勝利したことから、よりイクイノックスの強さが際立つレースとなった。このレースの進め方に関して、鞍上のルメールは「イクイノックスの(背中の)上だと普通のペース。彼は跳びが大きくて、スムーズな走り方をする。

Node ID: 2e00094c-0316-48f8-9a86-0774463155d1
Similarity: 0.8673449520056979
Text: GI初勝利を飾った。天皇賞(秋)の3歳馬の勝利は前年のエフフォーリア以来2年連続、史上5頭目。キャリア5戦での天皇賞(秋)制覇は史上最短、前年のホープフルステークスから続いていた平地GI競走の1番人気の連敗記録を16連敗で止めるなど、記録ずくめの勝利となった。キタサンブラック産駒はGI初制覇で、史上4組目の天皇賞(秋)父子制覇を達成した。レース後、インタビューでルメールは「春はアンラッキーだったけど、今日は本当のイクイノックスを見せることができた」「今回が彼の最初のGIですが、これが最後ではない。改めてこれからもGI取れると思います」とコメントした。

==== 有馬記念 ==== 次走として有馬記念に出走すると表明した。ファン投票でも多くの票を集め、第1回中間発表、第2回中間発表で共に3位の票数を獲得し、最終結果発表でも294,688票を集め3位となった。

12月25日、予定通り有馬記念に出走。単勝2.3倍の1番人気に推された。レースがスタートすると、タイトルホルダーを先頭にそれを追う形で馬群中団のやや後方を追走。

kun432kun432

ちなみにもう少し試してみたけども、Semantic Chunkingにそれほどの優位性は確認できなかった。良いときもあれば普通にチャンクしたときのほうが良い場合もある。このへんは定量的な評価をしないとなんとも言えないし、あと書いてなかったけど、buffer_sizeとbreakpoint_percentile_thresholdで変わってくる可能性もある。

パラメータの意味はざっと見た感じ、こんな感じではなかろうかと思う。

  • buffer_sizeは、Embeddingを取得する際の文の単位。buffer_size=1の場合、その文の前後の文も組み合わせてEmbeddingを取得しているっぽい。なので最低でも1つのチャンクの意味は3つの文で構成されているのではなかろうか。
  • breakpoint_percentile_thresholdは、全部の文のセマンティックスコアをパーセンタイルにしてこの範囲を超えたら意味的に変わる、つまりブレークポイントとする、って言うことだとも思う。

Semantic Chunkingの元々の目的としては、セマンティックな単位で分割、つまり、一定のコンテキストの塊にすればLLMの回答にもセマンティックさが反映される、ということだと思うので、上記で使ったwikipediaのように、元々セクションに分かれているようなケースではそこでセマンティックなコンテキストになっていると思うので、あえて使う必要もなさそう。

セクションなりセマンティックなりのチャンク分割が難しいUnstructuredなテキストとか、あとは小説とか散文とかみたいな細かいセクション区切りがないようなもののほうが向いている気はする。

kun432kun432

Greg Kamradt氏の動画ではもう少しローレベルで何をやっているのかがわかる。紹介されているコードはパブリックなのだけど、一応Kamradt氏のサイトでメアド登録しないとそのリンクは見れないという体のようなので、ここでは記載しない。

https://fullstackretrieval.com/

Dense X Retrievalなどを使用した方法なども紹介されているので、興味があれば。

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