出典:LangChain公式ドキュメント/Retrieval
はじめに
この記事では、LangChainを活用してPDF文書から演習問題を抽出する方法を紹介します。これは、いわゆるRAG(Retrieval-Augmented Generation)の実践例となります。使用するPDF文書としては、PRML(Pattern Recognition and Machine Learning)の原著を選びました。この文書は無料で公開されており、以下のリンクからアクセスできます。
対象読者様
この記事は、以下のような方をメインに想定して執筆しました。
- RAG(Retrieval-Augmented Generation)について学びたい方
- LangChainやOpenAI APIに興味がある方
- LLM(Large Language Model)ベースのアプリケーションを開発したい方
インストール
この記事のソースコードを実行するためには、以下のライブラリをインストールする必要があります:
pip install openai
pip install langchain
pip install pypdf
pip install tiktoken
pip install chromadb
PDFから演習問題を抽出する手順
LangChainを用いてPDF文書から演習問題を抽出する手順は以下の通りです:
-
PDF文書の読み込み:
-
PyPDFLoader
を使用してPDFファイルを読み込みます。
-
-
ドキュメントのチャンク分割:
-
CharacterTextSplitter
を用いて文書を小さなテキストチャンクに分割します。
-
-
埋め込みモデルの初期化:
-
OpenAIEmbeddings
でテキストの埋め込みモデルを初期化します。
-
-
ベクトルストアへのドキュメントの格納:
- 分割されたドキュメントを
Chroma
ベクトルストアに格納します。
- 分割されたドキュメントを
-
ドキュメントの抽出:
- リトリーバーを使用して、特定のクエリに関連するドキュメントを抽出します。
-
QAチェーンの初期化と実行:
-
ChatOpenAI
モデルとリトリーバーを組み合わせてQAチェーンを初期化し、質問応答を行います。
-
ソースコードのざっくり解説
この関数は、 この関数は、 この関数は、 この関数は、 この関数は、リトリーバーを使用して指定されたクエリに関連するドキュメントを抽出します。これにより、特定の情報を含む文書を取得することができます。 この関数は、 このセクションでは、上記で定義した関数を使用して、PDF文書から特定の情報を抽出し、その情報に基づいて質問応答を行うプロセスを実行します。まずPDFを読み込み、ドキュメントをチャンクに分割し、埋め込みモデルを初期化してベクトルストアに格納します。その後、リトリーバーを使用してドキュメントを抽出し、最後にQAチェーンを実行して結果を出力します。 len = 4 Exercise 4.6を選んで日本語に翻訳します。 上記は実際に存在する演習問題です。RAGを用いることで、ハルシネーションの発生確率を下げることができました。 この記事は以下の情報を参考にして執筆しました。 本記事で使用したソースコードは、下記のGitHubレポジトリに格納しています。ソースコード全文
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import PyPDFLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
def load_pdf_document(file_path):
loader = PyPDFLoader(file_path)
return loader.load()
def split_documents_into_chunks(documents, chunk_size=1000, chunk_overlap=0):
text_splitter = CharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
return text_splitter.split_documents(documents)
def initialize_embeddings():
return OpenAIEmbeddings()
def store_documents_in_vector_store(docs, embeddings):
db = Chroma.from_documents(docs, embeddings)
return db.as_retriever()
def retrieve_documents(retriever, retrieval_query):
return retriever.get_relevant_documents(retrieval_query)
def initialize_qa_chain(retriever, model_name="gpt-4-1106-preview"):
chat = ChatOpenAI(model_name=model_name)
return RetrievalQA.from_chain_type(llm=chat, chain_type="stuff", retriever=retriever)
## メインの処理
if __name__ == "__main__":
file_path = "path_to_your_pdf_file.pdf"
retrieval_query = "Exercisesを抽出してください。"
qa_query = "Exerciseを1題選択し日本語に翻訳してください。"
# 1. PDFを読み込む
pages = load_pdf_document(file_path)
# 2. ドキュメントをチャンクに分割
docs = split_documents_into_chunks(pages)
# 3. 埋め込みモデルの初期化
embeddings = initialize_embeddings()
# 4. ベクトルストアにドキュメントを格納
retriever = store_documents_in_vector_store(docs, embeddings)
# 5. ドキュメントを抽出
context_docs = retrieve_documents(retriever, retrieval_query)
print(f"len = {len(context_docs)}") # 抽出したドキュメントの数
first_doc = context_docs[0] # 1つ目のドキュメント
print(f"metadata = {first_doc.metadata}") # 1つ目のドキュメントのメタデータ
print(first_doc.page_content) # 1つ目のドキュメントの中身
# 6. QAチェーンの初期化と実行
qa_chain = initialize_qa_chain(retriever)
result = qa_chain.run(qa_query)
print(result)
1. PDF文書の読み込み
def load_pdf_document(file_path):
loader = PyPDFLoader(file_path)
return loader.load()
PyPDFLoader
を使用して指定されたファイルパスのPDF文書を読み込みます。読み込まれた文書は、後続の処理のために返されます。
2. ドキュメントのチャンク分割
def split_documents_into_chunks(documents, chunk_size=1000, chunk_overlap=0):
text_splitter = CharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
return text_splitter.split_documents(documents)
CharacterTextSplitter
を使用して読み込んだPDF文書を小さなテキストチャンクに分割します。これにより、大きな文書を扱いやすいサイズの部分に分けることができます。
3. 埋め込みモデルの初期化
def initialize_embeddings():
return OpenAIEmbeddings()
OpenAIEmbeddings
を使用してテキストの埋め込みモデルを初期化します。このモデルは、テキストの意味的内容を数値的なベクトルに変換するために使用されます。
4. ベクトルストアへのドキュメントの格納
def store_documents_in_vector_store(docs, embeddings):
db = Chroma.from_documents(docs, embeddings)
return db.as_retriever()
Chroma
を使用して分割されたドキュメントをベクトルストアに格納し、リトリーバーを生成します。これにより、各ドキュメントの埋め込みベクトルが保存され、後続の検索処理に使用されます。
5. ドキュメントの抽出
def retrieve_documents(retriever, retrieval_query):
return retriever.get_relevant_documents(retrieval_query)
6. QAチェーンの初期化と実行
def initialize_qa_chain(retriever, model_name="gpt-4-1106-preview"):
chat = ChatOpenAI(model_name=model_name)
return RetrievalQA.from_chain_type(llm=chat, chain_type="stuff", retriever=retriever)
ChatOpenAI
モデルとリトリーバーを使用してQAチェーンを初期化します。このチェーンは、指定されたQAクエリに基づいて質問に答えるために使用されます。
モデルはOpenAI Dev Dayで発表されたgpt-4-1106-preview
を使っています。
メインの処理
if __name__ == "__main__":
# ...
結果と解説
5. ドキュメントの抽出
部分ではPDFから演習問題が抽出されています。
実行結果は下記です。抽出されたドキュメントの数、1つ目のドキュメントのメタデータ、1つ目のドキュメントの中身が表示されています。
metadata = {'page': 376, 'source': 'path_to_your_pdf_file.pdf'}
Exercises 357
Exercises
7.1 (⋆⋆)www Suppose we have a data set of input vectors {xn}with corresponding
target values tn∈{ −1,1}, and suppose that we model the density of input vec-
tors within each class separately using a Parzen kernel density estimator (see Sec-
tion 2.5.1) with a kernel k(x,x′). Write down the minimum misclassification-rate
decision rule assuming the two classes have equal prior probability. Show also that,if the kernel is chosen to be k(x,x
′)=xTx′, then the classification rule reduces to
simply assigning a new input vector to the class having the closest mean. Finally,
show that, if the kernel takes the form k(x,x′)=φ(x)Tφ(x′), that the classification
is based on the closest mean in the feature space φ(x).
7.2 (⋆)Show that, if the 1on the right-hand side of the constraint (7.5) is replaced by
some arbitrary constant γ>0, the solution for the maximum margin hyperplane is
unchanged.
7.3 (⋆⋆)Show that, irrespective of the dimensionality of the data space, a data set
consisting of just two data points, one from each class, is sufficient to determine the
location of the maximum-margin hyperplane.
7.4 (⋆⋆)www Show that the value ρof the margin for the maximum-margin hyper-
plane is given by
1
ρ2=N∑
n=1an (7.123)
where {an}are given by maximizing (7.10) subject to the constraints (7.11) and
(7.12).
7.5 (⋆⋆)Show that the values of ρand{an}in the previous exercise also satisfy
1
ρ2=2˜L(a) (7.124)
where˜L(a)is defined by (7.10). Similarly, show that
1
ρ2=∥w∥2. (7.125)
7.6 (⋆)Consider the logistic regression model with a target variable t∈{ −1,1}.I f
we define p(t=1|y)=σ(y)where y(x)is given by (7.1), show that the negative
log likelihood, with the addition of a quadratic regularization term, takes the form(7.47).
7.7 (⋆)Consider the Lagrangian (7.56) for the regression support vector machine. By
setting the derivatives of the Lagrangian with respect to w,b,ξ
n, andˆξnto zero and
then back substituting to eliminate the corresponding variables, show that the dual
Lagrangian is given by (7.61).6. QAチェーンの初期化と実行
部分では演習問題が1題選択され、日本語に翻訳されています。
実行結果は下記です。
4.6 (⋆) クラス間およびクラス内の共分散行列がそれぞれ(4.27)および(4.28)で定義されていること、(4.34)および(4.36)を使うこと、およびセクション4.1.5で説明されているターゲット値の選択を使うことによって、二乗和誤差関数を最小限にする式(4.33)が(4.37)の形で書けることを示せ。
参考文献
ソースコード