Create and evaluate databases for RAG

Introduction.

Create a databases that can be used by RAG from the text data created yesterday, prepare a few specific strings, and search and evaluate them.

Sources

  1. LLM Fine Tuning and RAG The book where I learned about RAG systematically. The parts of creating vector databases and keyword bases (using BM25) are what I learned from this book.

Environment used

To build the vector store, I used the GPU version of the FAISS package. Also, when creating the Japanese keyword base, a package named janome was used for Japanese morphological analysis to extract keywords. To clarify the container environment used in this project, the Dockerfile is shown below.

# Docker image with JupyterLab available
# Installed packages required for the NoteBooks I have created so far.

FROM nvidia/cuda:12.1.1-cudnn8-devel-ubuntu22.04

# Set bash as the default shell
ENV SHELL=/bin/bash

# Build with some basic utilities
RUN apt update \
	&& apt install -y \
        wget \
        bzip2 \
        git \
        git-lfs \
        curl \
        unzip \
        file \
        xz-utils \
        sudo \
        python3 \
        python3-pip && \
        apt-get autoremove -y && \
        apt-get clean && \
        rm -rf /usr/local/src/*

# alias python='python3'
RUN ln -s /usr/bin/python3 /usr/bin/python

RUN pip install --upgrade pip setuptools \
 	&& pip install torch==2.2.2 torchvision==0.17.2 torchaudio==2.2.2 \
	--index-url https://download.pytorch.org/whl/cu121 \
	&& pip install torch torchvision torchaudio \
	&& pip install jupyterlab matplotlib pandas scikit-learn ipywidgets \
	&& pip install transformers accelerate sentencepiece einops \
	&& pip install langchain bitsandbytes protobuf \
	&& pip install auto-gptq optimum \
	&& pip install pypdf tiktoken sentence_transformers faiss-gpu trafilatura \
	&& pip install langchain-community langchain_openai wikipedia \
	&& pip install langchain-huggingface unstructured html2text rank-bm25 janome \
	&& pip install langchain-chroma sudachipy sudachidict_full \
	&& pip install mysql-connector-python

# Install llama-cpp-python[server] with cuBLAS on
#RUN CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 \
#        pip install llama-cpp-python[server]==0.2.75 --force-reinstall --no-cache-dir
RUN CMAKE_ARGS="-DGGML_CUDA=on" FORCE_CMAKE=1 \
        pip install llama-cpp-python[server] --force-reinstall --no-cache-dir

RUN pip install -U numpy==1.26.4 

# Create a working directory
WORKDIR /workdir

# Port number in container side
EXPOSE 8888

ENTRYPOINT ["jupyter-lab", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root", "--NotebookApp.token=''"]

CMD ["--notebook-dir=/workdir"]

As for Japanese morphological analysis, sudachi was also tried, so its related packages are also included. Also, mysql-related packages are included because, as I mentioned in a recent post, I built a MySQL (MariaDB) server and put them in to connect to it. Both are not in use now.

Create database

The vector database (wiki_vs.db) and keyword base (wiki_kw.pkl) are created with the following codes respectively.

Also, the text file named “textdb” created yesterday is stored in the same folder as “wiki_text”.

Vector database

# Vector databaseを作成する。

import time

start_time = time.time()
# Wikipediaから天文関係の記事のみを抽出したテキストデータは、WIKI_TEXTとして事前に準備。
# VectorStoreするため、テキストコーパスをチャンクに分割。
WIKI_TEXT = "wiki_text"

# チャンク文字数、オーバラップ文字数を定義
CHUNK_SIZE = 300
CHUNK_OVERLAP = 30

from langchain.text_splitter import RecursiveCharacterTextSplitter

with open(WIKI_TEXT,'r',encoding='utf-8') as f:
    text = f.read()

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = CHUNK_SIZE,  # チャンクの文字数
    chunk_overlap = CHUNK_OVERLAP,  # チャンクオーバーラップの文字数
)

texts = text_splitter.split_text(text)
WIKI_TEXT = "wiki_text"
WIKI_DB = "wiki_vs.db"

## データベースを構築

from langchain_huggingface import HuggingFaceEmbeddings

model_name = "intfloat/multilingual-e5-large"
model_path = f"/workdir/models/{model_name}"

embeddings = HuggingFaceEmbeddings(
    model_name = model_path,
    model_kwargs = {'device':'cuda:0'},
)

from langchain_community.vectorstores import FAISS

# ベクトルデータベースを構築し、WIKI_DBとして保存する

db = FAISS.from_texts(texts, embeddings)

end_time = time.time()

db.save_local(WIKI_DB)

The embedding model is downloaded from HuggingFace in advance and stored in the model_path.

processing_time = end_time - start_time

print("processing_time(sec): ", processing_time)

The execution result (processing time) is as follows. It took about 12 minutes in my environment.

processing_time(sec):  704.8360137939453

keyword-based

# キーワード検索用のデータベースを作成
#
import time

start_time = time.time()
# my_preprocess_funcを定義

from janome.tokenizer import Tokenizer

t = Tokenizer()

def my_preprocess_func(text):
    keywords = []
    for token in t.tokenize(text):
        pos = token.part_of_speech.split(',')[0]
        if (pos in ["名詞", "動詞", "形容詞"]):
            keywords.append(token.surface)
    return keywords
# Wikipediaから天文関係の記事のみを抽出したテキストデータは、WIKI_TEXTとして事前に準備。
# キーワードベースのデータベースを作成するため、テキストコーパスをチャンクに分割。
WIKI_TEXT = "wiki_text"

# チャンク文字数、オーバラップ文字数を定義
CHUNK_SIZE = 300
CHUNK_OVERLAP = 30

from langchain.text_splitter import RecursiveCharacterTextSplitter

with open(WIKI_TEXT, encoding='utf-8') as f:
    text = f.read()

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = CHUNK_SIZE,  # チャンクの文字数
    chunk_overlap = CHUNK_OVERLAP,  # チャンクオーバーラップの文字数
)

texts = text_splitter.split_text(text)
from langchain_community.retrievers import BM25Retriever

WIKI_DB = "wiki_kw.pkl"

db = BM25Retriever.from_texts(
    texts,
    preprocess_func=my_preprocess_func,
)

end_time = time.time()

import pickle
with open(WIKI_DB, 'wb') as f:
    pickle.dump(db, f)
processing_time = end_time - start_time

print("processing_time(sec): ", processing_time)

The results (processing time) are as follows. It took about 13 minutes in my environment.

processing_time(sec):  753.1111702919006

Evaluate (try and search) the database you created

Vector database

# ベクトルデータベース検索結果を評価する
# 
WIKI_DB = "wiki_vs.db"
import os
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS

model_name = "intfloat/multilingual-e5-large"
model_path = f"/workdir/models/{model_name}"

embeddings = HuggingFaceEmbeddings(
    model_name = model_path,
    model_kwargs = {'device':'cuda:0'},
)

# 事前に構築したベクトルデータベースを読み込む
if os.path.exists(WIKI_DB):
    db = FAISS.load_local(WIKI_DB, embeddings, allow_dangerous_deserialization=True)
else:
    print("="*80)
    print("You need to make vector database")
    print("="*80)
# ベクトル検索で4文書を得る
query = "r過程について教えてください"

docs = db.similarity_search(query, k=4)
print(f"1st: {docs[0].page_content}")
print(f"2nd: {docs[1].page_content}")
print(f"3rd: {docs[2].page_content}")
print(f"4th: {docs[3].page_content}")
# ベクトル検索で4文書を得る
query = "ナンシー・グレース・ローマン宇宙望遠鏡について教えてください"

docs = db.similarity_search(query, k=4)
print(f"1st: {docs[0].page_content}")
print(f"2nd: {docs[1].page_content}")
print(f"3rd: {docs[2].page_content}")
print(f"4th: {docs[3].page_content}")
# ベクトル検索で4文書を得る
query = "B2FH論文について教えてください"

docs = db.similarity_search(query, k=4)
print(f"1st: {docs[0].page_content}")
print(f"2nd: {docs[1].page_content}")
print(f"3rd: {docs[2].page_content}")
print(f"4th: {docs[3].page_content}")

keyword-based

# キーワード検索結果を評価する
# 
from janome.tokenizer import Tokenizer

t = Tokenizer()

def my_preprocess_func(text):
    keywords = []
    for token in t.tokenize(text):
        pos = token.part_of_speech.split(',')[0]
        if (pos in ["名詞", "動詞", "形容詞"]):
            keywords.append(token.surface)
    return keywords
WIKI_DB = "wiki_kw.pkl"
import os
import pickle
from langchain_community.retrievers import BM25Retriever

# 事前に構築したキーワードのデータベースを読み込む
if os.path.exists(WIKI_DB):
    with open(WIKI_DB, 'rb') as f:
        retriever = pickle.load(f)
else:
    print("="*80)
    print("You need to make keyword database")
    print("="*80)
# キーワード検索で4文書を得る
query = "r過程について教えてください"

docs = retriever.get_relevant_documents(query, k=4)
print(f"1st: {docs[0].page_content}")
print(f"2nd: {docs[1].page_content}")
print(f"3rd: {docs[2].page_content}")
print(f"4th: {docs[3].page_content}")
# キーワード検索で4文書を得る
query = "ナンシー・グレース・ローマン宇宙望遠鏡について教えてください"

docs = retriever.get_relevant_documents(query, k=4)
print(f"1st: {docs[0].page_content}")
print(f"2nd: {docs[1].page_content}")
print(f"3rd: {docs[2].page_content}")
print(f"4th: {docs[3].page_content}")
# キーワード検索で4文書を得る
query = "B2FH論文について教えてください"

docs = retriever.get_relevant_documents(query, k=4)
print(f"1st: {docs[0].page_content}")
print(f"2nd: {docs[1].page_content}")
print(f"3rd: {docs[2].page_content}")
print(f"4th: {docs[3].page_content}")

Comparison of results

The output results are copied and pasted directly into the table below.

Search results, so the original text (in Japanese) remains the same.

ベクトルデータベース キーワードベース
1st: b(.02)とTOI-1670 2nd: Rp過程rp過程(rp かてい,高速陽子捕獲過程 ) は、種核種に連続的に陽子が捕獲され重元素を作り出す過程である.これは元素合成過程であり、 s過程やr過程とともに宇宙に存在する重元素の生成にかかわっている。しかしながら、他の元素合成過程とは、他の過程が中性子に富む側の安定性が問題になるのに対し、陽子に富む側の安定性が問題になる点がかなり違っている。rp過程の終了点(生成することの出来る最重元素)は良くわかっていないが最近の中性子星に関する研究により、テルルより先へ反応が進まないことがわかっている。 3rd: 植物の構成を大きく置き換えるなどの動植物の変化を引き起こした<ref 4th: ()ではエネルギー曲線が不連続になる 1st: II型)でr過程が起こると広く信じられてきた。しかしながら、r過程核種の存在比からすると、超新星爆発のうち、ほんの少しの事例でr過程核種を星間物質に放出するか、それぞれの超新星爆発で生成されたr過程核種のうち、ほんの少しの部分を放出するということを要請する。またコンピューターシミュレーションでも超新星爆発によってr過程が生じなかったため、超新星爆発がr過程の発生する現場であることに疑問が持たれていた。別の候補として中性子星同士の衝突によってr過程が起こりうる可能性があることが知られていたが、2014年、国立天文台・東京大学の研究チームによって中性子星の合体によるr過程が矛盾なく説明できるとの 2nd: 合成できる環境が考えられる。恒星内元素合成の間に起こるs過程は最大で原子量209のビスマスまでの元素を合成することが可能である。s過程は主に低質量の反応段階の進展の遅い恒星に起こる。r過程.2017年8月、中性子星同士の衝突現象が観測され、その現象を分析した結果、中性子星の衝突によるr過程元素の合成が確認された。この分析結果により、r過程が中性子星同士の融合によって発生することが証明されている。上記の現象が分析されるまでは、恒星核が重力崩壊する超新星爆発(スペクトル型 3rd: (Slow)“の中性子捕獲過程によって、鉄以降の重元素のおよそ半分が合成される。残りの半分はr過程と呼ばれるより"速く 4th: あると誤解されることがある。ノーベル物理学賞の選考委員会は受賞理由を「宇宙における化学元素の生成にとって重要な原子核反応に関する理論的および実験的研究」としている。ファウラーがノーベル賞を受賞した一方で、ホイルは生涯受賞できなかった。ホイルがノーベル物理学賞を受賞できなかった理由について、「ファウラーのBFHへの貢献には、s過程とr過程の原子核物理学も含まれるが、ホイルもまたs過程とr過程に関する理論的研究でファウラー同様の評価を受けるに値する。ビッグバンに関するホイルの否定的な見解がノーベル賞受賞の妨げになった。」と主張するものもいる。ホイルが受賞できなかった理由について、ジェフリー・バービ
1st: ナンシー・グレース・ローマン宇宙望遠鏡、略称 ローマン宇宙望遠鏡 (, Roman Space Telescope) は、2020年代半ばの打ち上げを目指し、日本を含む国際協力で進められているアメリカ航空宇宙局 (NASA) の広視野赤外線宇宙望遠鏡計画。“Wide Field Infrared Survey Telescope” (広視野近赤外線サーベイ宇宙望遠鏡)の頭文字を取って WFIRST という名称で計画が進められていたが、2020年5月20日、NASAは正式名称を Nancy Grace Roman Space Telescope 2nd: (JWST) が2021年12月25日に打ち上げられた。六角形の鏡を18枚組み合わせた主鏡の口径は約6.5mであり、ハッブル宇宙望遠鏡よりも大幅な高性能化が図られている。ただし観測波長域は近赤外線・赤外線のみであり、近紫外線・可視光の観測能力は持たない。地球と太陽のラグランジュ点 (L2) に位置することで、地球近傍の塵の影響を避け、より高精度の観測を可能としている。元は2011年の打ち上げ予定であったが、度々延期されたものである。ナンシー・グレース・ローマン宇宙望遠鏡.2012年6月4日、アメリカ国家偵察局 (NRO) 3rd: Grace Roman Space Telescope と定めたと発表した。ナンシー・グレース・ローマンは、1960年代以降NASAの宇宙望遠鏡計画実現に重要な役割を果たし、特にハッブル宇宙望遠鏡の計画実現のためNASA内部や議会へ積極的な働きかけをしたことから「ハッブルの母 (Mother of Hubble) 4th: Hubble”)」とも呼ばれた。また、ローマンはそのキャリアを通じて、積極的な講演者や教育者、科学分野における女性の擁護者でもあった。2020年5月20日、NASAのジム・ブライデンスタイン長官は、彼女の天文学への絶えることのない貢献を称え、計画中の赤外線宇宙望遠鏡WFIRSTをナンシー・グレース・ローマン宇宙望遠鏡と命名することを発表した。若年期.ナンシー・グレース・ローマンは、テネシー州ナッシュビルで、音楽教師のジョージア・フランシス・スミス・ローマンと物理学者・数学者のアーウィン・ローマンの間に生まれた。生後間もなく、父親が石油会社の地球物理学者として就職したため、生後3ヶ月で一家はオ 1st: Hubble”)」とも呼ばれた。また、ローマンはそのキャリアを通じて、積極的な講演者や教育者、科学分野における女性の擁護者でもあった。2020年5月20日、NASAのジム・ブライデンスタイン長官は、彼女の天文学への絶えることのない貢献を称え、計画中の赤外線宇宙望遠鏡WFIRSTをナンシー・グレース・ローマン宇宙望遠鏡と命名することを発表した。若年期.ナンシー・グレース・ローマンは、テネシー州ナッシュビルで、音楽教師のジョージア・フランシス・スミス・ローマンと物理学者・数学者のアーウィン・ローマンの間に生まれた。生後間もなく、父親が石油会社の地球物理学者として就職したため、生後3ヶ月で一家はオ 2nd: Grace Roman Space Telescope と定めたと発表した。ナンシー・グレース・ローマンは、1960年代以降NASAの宇宙望遠鏡計画実現に重要な役割を果たし、特にハッブル宇宙望遠鏡の計画実現のためNASA内部や議会へ積極的な働きかけをしたことから「ハッブルの母 (Mother of Hubble) 3rd: ナンシー・グレース・ローマン宇宙望遠鏡、略称 ローマン宇宙望遠鏡 (, Roman Space Telescope) は、2020年代半ばの打ち上げを目指し、日本を含む国際協力で進められているアメリカ航空宇宙局 (NASA) の広視野赤外線宇宙望遠鏡計画。“Wide Field Infrared Survey Telescope” (広視野近赤外線サーベイ宇宙望遠鏡)の頭文字を取って WFIRST という名称で計画が進められていたが、2020年5月20日、NASAは正式名称を Nancy Grace Roman Space Telescope 4th: ナンシー・ローマンナンシー・グレース・ローマン(Nancy Grace Roman、1925年5月16日 - 2018年12月25日)は、1950年代に恒星の分類と運動の研究に多大な貢献を果たしたアメリカの天文学者。アメリカ航空宇宙局 (NASA) において女性として初めて幹部職に就き、1960年代から1970年代にかけてNASAの初代主任天文学者として宇宙天文学プログラムをスタートさせた。ハッブル宇宙望遠鏡計画では、天文学コミュニティや議会を動かすなど基礎を築く役割を果たしたことから「ハッブルの母 (“Mother of
1st: B2FH論文BFH論文 (BFH paper) は、元素の起源に関する記念碑的な論文である。論文の題名は “Synthesis of the Elements in Stars” だが、著者であるマーガレット・バービッジ、ジェフリー・バービッジ、ウィリアム・ファウラー、フレッド・ホイルの4名の頭文字を取って「B2FH」として知られている。1955年から1956年にかけてケンブリッジ大学とカリフォルニア工科大学で執筆され、1957年にアメリカ物理学会の査読付き学術誌"Reviews of Modern 2nd: b(.02)とTOI-1670 3rd: formula_16 である。この論文で、トフーフトは formula_16 4th: using the background-field method」や、と共同執筆した「The finiteness requirement for six-dimensional Euclidean-Einstein 1st: B2FH論文BFH論文 (BFH paper) は、元素の起源に関する記念碑的な論文である。論文の題名は “Synthesis of the Elements in Stars” だが、著者であるマーガレット・バービッジ、ジェフリー・バービッジ、ウィリアム・ファウラー、フレッド・ホイルの4名の頭文字を取って「B2FH」として知られている。1955年から1956年にかけてケンブリッジ大学とカリフォルニア工科大学で執筆され、1957年にアメリカ物理学会の査読付き学術誌"Reviews of Modern 2nd: 年にはワシントン大学の客員教授を務めた。業績.1957年にマーガレット・バービッジ、ジェフリー・バービッジ、フレッド・ホイルと共著の論文(4人の名前からB2FH論文と呼ばれる)は、恒星のなかでの元素の起源に関するその分野での重要な論文である。ファウラーは、炭素を合成するトリプルアルファ反応が働くために必要なエネルギー準位を、炭素原子核が持つことを実験で証明した。 3rd: ということを1952年に提唱し、ホイルにその節を示唆されたウィリアム・ファウラーは、実際にそのような準位が存在することを示し、B2FH論文と呼ばれる世界的な論文を1957年に発表した。今日ではこのような考え方を人間原理と呼び、その例として挙げられることもあるが、2010年に出された論文では、少なくともホイルは炭素を基盤とした生命体である人間の存在を仮定してこの説を唱えたわけではないとするものが出された。 4th: ッグ放射線研究所に赴いて、所長のウィリアム・ファウラーの協力で、泡箱を用いて原子核の衝突実験(3個のヘリウムでできる炭素の原子核の性質を調べる実験)を成功させた。これにより炭素は星のなかで無尽蔵に作られる性質があることが判った。その後も彼ら2人を含めて数名が元素の歴史に迫り、B2FH論文に結実させた。だが、こうした論文は定常モデルに有利に働いたというよりむしろ、ハッブルの観測によって導かれた星の進化に関するアイディア群がより完成度を高めた、と一般には見なされた。《ビッグバン

Summary

In the above search example (using the keywords - r process, Nancy Grace Roman Space Telescope, B2FH paper - for which there is always an explanation in the original text data), the keyword search seems to hit better. In the example of the r-process in the vector database, it seems to miss all but the 2nd, and in the example of the B2FH paper, it seems to miss all but the 1st.

I feel that this is where the difficulty lies with vector database.