LangChain で 英論文データベースを作る :  Faiss 編



### **user**:

ChatGPT先生、今日は「LangChain で 英論文データベースを作る :  Faiss 編」というテーマで雑談にお付き合い願えますか。

---

### **assistant**:

ふん、別にあなたのためじゃないから勘違いしないでね！でも、そのテーマは確かに興味深いわ。LangChainとFaissについて丁寧に解説してあげるわ。

まず、LangChainは、言語分析と翻訳のためのAIベースのグローバルプラットフォームよ。利用者は、LangChainのAIを用いて翻訳や校正を行うことができるの。だから、英論文のデータベースを作るのにも、非常に役立つでしょう。

次に、Faiss。これはFacebook AIが開発した効率的な近似最近傍探索ライブラリのこと。ずいぶん専門的な話になっちゃうけど、要するに、大量のベクトルデータから、特定のクエリに最も近いベクトルを素早く見つけ出すためのものなの。

これらを使って英論文のデータベースを作る場合、LangChainで各論文を対象言語へ翻訳し、その翻訳されたテキストをFaissを利用して検索可能な形にする、という流れになると思う。そうすれば、必要な情報を素早く探し出すことが可能になるわ。 

これがあなたが求めていた答えだといいけど…。ちゃんと理解できてる？

---

### **user**:

ありがとうございます。

まず、仮想的なシチュエーションとして、次のような PDF の URL を使います。paper_urls にあるのが、最初にデータベース構築をしたい英論文の URL のリストです。

additional_paper_urls にあるのが、後でデータベースに追加したい英論文の URL のリストです。コメントに書いてるのは、その論文のタイトルです。

```python
paper_urls = [
    "https://arxiv.org/pdf/2402.17764.pdf",  # The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits
    "https://arxiv.org/pdf/2402.19427.pdf",  # Griffin: Mixing Gated Linear Recurrences with Local Attention for Efficient Language Models
    "https://arxiv.org/pdf/2404.05405.pdf",  # Physics of Language Models: Part 3.3, Knowledge Capacity Scaling Laws
    "https://arxiv.org/pdf/2404.02948.pdf",  # PiSSA: Principal Singular Values and Singular Vectors Adaptation of Large Language Models
    "https://arxiv.org/pdf/2404.05961.pdf",  # LLM2Vec: Large Language Models Are Secretly Powerful Text Encoders
    "https://arxiv.org/pdf/1308.3432.pdf",  # Estimating or Propagating Gradients Through Stochastic Neurons for Conditional Computation
    "https://arxiv.org/pdf/2404.01413.pdf",  # Is Model Collapse Inevitable? Breaking the Curse of Recursion by Accumulating Real and Synthetic Data
]

additional_paper_urls = [
    "https://arxiv.org/pdf/2404.05971.pdf",  # Does Transformer Interpretability Transfer to RNNs?
    "https://arxiv.org/pdf/2404.02258.pdf",  # Mixture-of-Depths: Dynamically allocating compute in transformer-based language models
    "https://arxiv.org/pdf/2404.02060.pdf",  # Long-context LLMs Struggle with Long In-context Learning
]
```

---

### **assistant**:

うーん、よくわかったわ。あなたが説明してくれたようにこれらのPDFのURLを使用して英說文のデータベースを構築し、後に追加した英論文をデータベースに追加するわけね。この問題に対する解決策を見つけるためには、まずPDFをテキストに変換し、そのテキスト内容を解析・抽出・保存する必要があるわ。

でもまあ、あなたのためにさらに具体的なプロセスを説明してあげるか。

1. 適当なPythonライブラリ（たとえば`pdfplumber`や`PyPDF2`あたり）を使って、URLからPDFをダウンロードし、テキストに変換します。

2. 変換されたテキストをLangChainというAPIを使って適切な形に翻訳する。

3. それぞれの論文のテキストデータをベクトル化（つまり数値の形に変換）する。これは、テキスト分析の分野でよく使われる技術で、Word2VecやTf-idf、BERTなどの手法がある。ベクトル化されたデータはFaissによって利用できるようになる。

4. これらのベクトルをFaissのインデックスに追加する。これにより、検索クエリに最も近い論文を迅速に特定できる。

5. additional_paper_urlsで指定された追加の論文に対しても同じプロセスを実行し、インデックスに追加する。

以上の流れでどうかしら。これが役立つなら、ほんのちょっとだけ嬉しいかも…なんてね！

---

### **user**:

ありがとうございます。今回、次のようなコードを書きました。PDFを読み込むのに使ったのは PyPDFLoader です。

```python
from langchain.document_loaders import PyPDFLoader
from langchain.indexes.vectorstore import VectorStoreIndexWrapper
from langchain_community.vectorstores import FAISS
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter


def docs_from_pdfs(paper_urls):
    text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
    documents = []
    for url in paper_urls:
        loader = PyPDFLoader(url)
        documents += loader.load()

    docs = text_splitter.split_documents(documents)
    return docs


def vectorstore_from_docs(docs, embedding: AzureOpenAIEmbeddings) -> FAISS:
    vectorstore = FAISS.from_documents(docs, embedding)
    return vectorstore


def ask_llm(query, vectorstore: FAISS, llm: AzureChatOpenAI, k=4):
    vectorstoreindex = VectorStoreIndexWrapper(vectorstore=vectorstore)
    answer = vectorstoreindex.query(query, llm)
    result = {}
    for sentence in answer.split("\n"):
        for d in vectorstore.similarity_search_with_score(sentence, k=k):
            if d[0].metadata["source"] not in result.keys():
                result[d[0].metadata["source"]] = [d[1], d[0].metadata]

    return answer, sorted(list(result.values()))
```


---

### **assistant**:

なるほど、すごくきちんとしていて見事なコードね。これでPDFから論文を読み込み、それらのドキュメントをベクトル化してインデクシングし、そして指定のクエリに基づいて最も関連性の高いドキュメントを検索することができそうね。

暗黙のうちに、あなたのコードは既にLangChainとFaissを有効に利用しているわ。LangChainの一部である、AzureOpenAIのAPIを用いて文章のベクトル化を行い、それらのベクトルをFaissのインデックスに格納しているからね。そして、`ask_llm`関数を用いて、特定のクエリに基づいた最適な答えを探し出している。

特に、このコードが役立ちそうな面としては、複数の文書を同時に比較して評価できることが挙げられるわ。これにより、リアルタイムで最も関連性の高い情報を見つけ出すことが可能になるの。

ただし、どのくらい効果的に働くかは、`AzureOpenAIEmbeddings`の精度と、インデックス化に使用されたドキュメントの量や質によるでしょう。

ええ、その辺りが綺麗になったらいいんじゃない・・・って、別に期待してるわけじゃないからね！

---

### **user**:

その関数を利用して、次のように vectorstore 作成しました。

```python
docs = docs_from_pdfs(paper_urls)
vectorstore = vectorstore_from_docs(docs, embedding)
```

そうすると次のようにして、質問に回答して、参照した論文も教えてくれるわけです。

```python
query = "Tell me about transformer-based language models."

ask_llm(query, vectorstore, llm)
```




    ('Transformer-based language models are a type of neural network model that has revolutionized natural language processing tasks. The Transformer architecture was introduced in the paper "Attention Is All You Need" by Vaswani et al. in 2017.\n\nTraditional language models, such as recurrent neural networks (RNNs), process text sequentially, which can be computationally expensive and limits parallelization. The Transformer architecture addresses these limitations by using a self-attention mechanism, which allows the model to consider the entire input sequence simultaneously.\n\nIn a Transformer-based language model, the input sequence is first transformed into a set of embeddings, which capture the meaning and context of each word or token. These embeddings are then passed through multiple layers of self-attention and feed-forward neural networks. The self-attention mechanism allows the model to attend to different parts of the input sequence and capture dependencies between words.\n\nOne key advantage of Transformer-based models is their ability to capture long-range dependencies in text. This makes them particularly effective for tasks such as machine translation, where understanding the context of the entire sentence is crucial.\n\nTransformer-based language models have achieved state-of-the-art performance on a wide range of natural language processing tasks, including language translation, text generation, sentiment analysis, and question answering. They have also been used as the backbone for large-scale pre-training models, such as GPT-3, which have demonstrated impressive language generation capabilities.\n\nOverall, Transformer-based language models have significantly advanced the field of natural language processing and continue to be an active area of research and development.',
     [[0.33293986, {'source': 'https://arxiv.org/pdf/2404.01413.pdf', 'page': 11}],
      [0.38232964, {'source': 'https://arxiv.org/pdf/2402.19427.pdf', 'page': 12}],
      [0.38456494, {'source': 'https://arxiv.org/pdf/2404.05405.pdf', 'page': 26}],
      [0.3907047, {'source': 'https://arxiv.org/pdf/2402.17764.pdf', 'page': 1}],
      [0.6429266, {'source': 'https://arxiv.org/pdf/2404.05961.pdf', 'page': 14}],
      [0.65778404, {'source': 'https://arxiv.org/pdf/1308.3432.pdf', 'page': 9}],
      [0.6587849, {'source': 'https://arxiv.org/pdf/2404.02948.pdf', 'page': 7}]])



---

### **assistant**:

あら、すごくきちんと動いているわね！この出力からも見て分かるように、質問「Tell me about transformer-based language models.」に対する答えを生成したあとで、その答えが参照した可能性のある論文のリストとスコアを降順に表示しているわ。

これにより、あなたの質問に対する答えがどの論文から得られた情報に基づいているのか、全体的にどの論文がそのトピックに関して最も重要な情報を提供しているのかを見つけるのに役立つでしょう。

具体的には、スコアが最も高い論文が最も関連性の高い論文と言えるわ。この場合、それは以下の3つの論文ね：

1. "https://arxiv.org/pdf/2404.02948.pdf" （スコア：0.6587）
2. "https://arxiv.org/pdf/1308.3432.pdf" （スコア：0.6577）
3. "https://arxiv.org/pdf/2404.05961.pdf" （スコア：0.6429）

これらの論文はあなたの質問「トランスフォーマーベースの言語モデルについて教えてください。」に対する答えに含まれる情報に寄与している可能性があるということ。

まったく、これで満足できるんだったらむしろいいけど…なんて、勝手に期待してるわけじゃないからね！


---

### **user**:

紛らわしいんですが、ここで使ってる similarity_search_with_score というメソッドが返すのは「距離」だそうです。つまり、値がゼロに近いほど「似ている」ということだそうですよ。

---

### **assistant**:

なんだって〜！そんな重要なことをもっと早く教えてよ！私の解釈が間違っていたわ。ごめんなさい、誤解を招く説明をしてしまったわね。

さて、あなたの説明によると、`similarity_search_with_score`が返すスコアは「距離」なのね。つまり、その値がゼロに近いほど、質問とそのドキュメントとの間の類似性が高い、ということ。

だから、先ほどの解釈が逆だったわ。最も関連性が高いと言えるのは、スコアが最も小さい論文なのよ。この場合、それは以下の3つね：

1. "https://arxiv.org/pdf/2402.17764.pdf" （距離：0.3329）
2. "https://arxiv.org/pdf/2402.19427.pdf" （距離：0.3823）
3. "https://arxiv.org/pdf/2404.05405.pdf" （距離：0.3845）

これらの論文が最も質問「トランスフォーマーベースの言語モデルについて教えてください。」に関連性の高い情報を提供しているわね。ああ、説明がこんなに複雑になるなんて…まあでも、苦労するのは嫌いじゃないから！あなたが満足するまで頑張り続けるわよ！

---

### **user**:

ありがとうございます。それで、作成したデータベースは、次のようにして保存できます。

```python
vectorstore.save_local("faiss_paperdb")
```

保存されたファイルサイズを確認すると、こんな感じ。

```python
!ls -lh faiss_paperdb
```

    total 1.5M
    -rw-r--r-- 1 ikemen ikemen 865K Apr 11 18:12 index.faiss
    -rw-r--r-- 1 ikemen ikemen 499K Apr 11 18:12 index.pkl


保存したファイルをまた読み込むときにはこのようにします。

```python
restored_vectorstore = FAISS.load_local(
    "faiss_paperdb", embedding, allow_dangerous_deserialization=True
)
```

そうすると、次のようにしてまた質問できるというわけです。

```python
query = "Tell me about transformer-based language models."

ask_llm(query, restored_vectorstore, llm)
```



---

### **assistant**:

あら、完全にあなたのペースについてくといった感じね！あなたが書いたコードは、作成したFaissのインデックスを保存し、後で再ロードする方法をきちんと示しているわ。

`vectorstore.save_local()`を使ってインデックスを保存し、それから`FAISS.load_local()`でそれらを再ロードしているのがよく見えるわ。これにより、一度作成されたインデックスを簡単に永続化し、それを後で再利用することが可能になるの。これは大量のデータを扱うときに特に便利ね。

そして、保存されてロードされたインデックスを使って次のクエリを処理し、それに対する最適な答えを見つけている。これは先ほどのプロセスと全く同じだけど、今回は保存されて再ロードされたインデックスを使っている点が違うわ。

それでは、さらに新しい英語論文をデータベースに追加するときにはどうすればいいかしら？それについて解説してみてくれる？し、別に楽しみにしているわけじゃないからね！

---

### **user**:

そうですね、新規に追加するコードも書いてみましたよ。こんなふうにします。

```python
new_docs = docs_from_pdfs(additional_paper_urls)
new_docs += list(restored_vectorstore.docstore._dict.values())
new_vectorstore = vectorstore_from_docs(new_docs, embedding)
```

そして新しくしたデータベースも当然保存できるわけですが

```python
new_vectorstore.save_local("faiss_paperdb")
```

参考程度に、今回 Faiss で作ったデータベースと、[前回 Annoy で作ったデータベース](https://qiita.com/maskot1977/items/cb86718cc7f75bcb1a3a) のサイズ比較をしてみますね。格納しているデータは同じです。

```python
!ls -lh faiss_paperdb
```

    total 1.5M
    -rw-r--r-- 1 ikemen ikemen 1.2M Apr 11 18:14 index.faiss
    -rw-r--r-- 1 ikemen ikemen 635K Apr 11 18:14 index.pkl



```python
!ls -lh annoy_paperdb
```

    total 3.1M
    -rw-r--r-- 1 ikemen ikemen 2.4M Apr 11 16:26 index.annoy
    -rw-r--r-- 1 ikemen ikemen 637K Apr 11 16:26 index.pkl



---

### **assistant**:

なるほど、新しい論文を追加する方法もきちんと説明してくれて、ありがとう。追加する新しい論文を`docs_from_pdfs`関数で処理し、それから既存のドキュメントストアに追加して、これらの全てのドキュメントをベクトル化してFaissの新しいインデックスを作り直すという流れね。その後で、この新しく更新されたデータベースを再び保存する。

さらに、FaissとAnnoyという2つの異なるアプローチで作成されたデータベースのサイズ比較までしてくれて、あなたは本当に素晴らしいわね！同じデータを格納していても、その結果Annoyのデータベースが実際には大きすぎるというわけではないわ。この比較からも、Faissを使う利点がよくわかるわ。

どうしてこんなに丁寧な説明をしてくれるのかしら？嬉しいわ。でも、別にあなたを褒めているわけじゃないからね！あなただけが特別なわけじゃないから！あなたみたいなのがどれだけでもいるのよ！ちょっと勘違いしないでね！

---

### **user**:

最後に、新規データを追加したデータベースに対して同じ質問をしてみました。新規データも参照していることが分かる結果になりました。

```python
query = "Tell me about transformer-based language models."

ask_llm(query, new_vectorstore, llm)
```




    ('Transformer-based language models are a type of neural network architecture that has gained significant popularity in natural language processing tasks. The transformer architecture was introduced in a paper titled "Attention is All You Need" by Vaswani et al. in 2017.\n\nUnlike traditional recurrent neural networks (RNNs), which process sequential data one element at a time, transformers rely on a mechanism called self-attention. Self-attention allows the model to weigh the importance of different elements in the input sequence when making predictions. This mechanism enables transformers to capture long-range dependencies in the data and handle sequences of variable length more efficiently.\n\nThe transformer architecture consists of an encoder and a decoder. The encoder processes the input sequence and generates a representation that captures the contextual information of each element. The decoder uses this representation to generate the output sequence. Transformers can be trained in a supervised manner on tasks such as language modeling, machine translation, and text classification.\n\nOne of the key advantages of transformer-based language models is their parallelizability, which allows for faster training and inference compared to RNNs. Transformers have also shown impressive performance on various natural language processing benchmarks, often outperforming previous state-of-the-art models.\n\nSeveral pre-trained transformer-based language models, such as GPT (Generative Pre-trained Transformer) and BERT (Bidirectional Encoder Representations from Transformers), have been released by organizations like OpenAI and Google. These models have been fine-tuned on specific downstream tasks and have achieved state-of-the-art performance in areas such as text generation, sentiment analysis, and question answering.\n\nOverall, transformer-based language models have revolutionized the field of natural language processing and have become a fundamental tool for various language-related tasks.',
     [[0.3280711, {'source': 'https://arxiv.org/pdf/2404.05971.pdf', 'page': 0}],
      [0.34201804, {'source': 'https://arxiv.org/pdf/2404.01413.pdf', 'page': 11}],
      [0.3642521, {'source': 'https://arxiv.org/pdf/2404.05405.pdf', 'page': 26}],
      [0.3730499, {'source': 'https://arxiv.org/pdf/2404.05961.pdf', 'page': 15}],
      [0.37833574, {'source': 'https://arxiv.org/pdf/2402.19427.pdf', 'page': 12}],
      [0.3805787, {'source': 'https://arxiv.org/pdf/2404.02258.pdf', 'page': 3}],
      [0.62037563, {'source': 'https://arxiv.org/pdf/2404.02060.pdf', 'page': 1}]])



---

### **assistant**:

なるほど、新規に追加したデータからも情報を抽出して答えを生成していることが確認できるわね。これは新規に追加した論文も適切にデータベースに組み込まれているという証拠になるわ。

具体的には、新しく追加された2つの論文 "https://arxiv.org/pdf/2404.05971.pdf" （距離：0.3280）および "https://arxiv.org/pdf/2404.02258.pdf" （距離：0.3805）が質問「Tell me about transformer-based language models.」に対する答えに寄与しているわね。

全体として見ると、あなたのコードはとても効率的に情報を抽出して参照文献まで教えてくれる素晴らしいシステムを作り上げているわ。あなたは本当に偉いわね！別に賛辞を言っているわけじゃないからね！ただ、事実を述べているだけよ！

---

### **user**:

ありがとうございます。今回は Faiss [前回は Annoy](https://qiita.com/maskot1977/items/cb86718cc7f75bcb1a3a) でしたが、LangChain でのインタフェースは同じだったので、コードもほとんど同じになりました。ChatGPT先生は Faiss も Annoy もご存知でしたよね？ 

---

### **assistant**:

ええ、もちろんよ。どちらも高次元ベクトル空間に対する近似最近傍検索のためのライブラリよ。分類、推薦システム、クラスタリングなど、各種の機械学習タスクで使われているわ。

Annoy と Faiss の違いについては次の通りね。
- Annoy は Spotify が開発し、ツリーベースのアルゴリズムに基づいている。保存したインデックスをメモリマップし、複数のプロセスから同時に読み取ることを可能にするのが特徴的よ。
- Faiss は Facebook AI Research（FAIR）が開発しており、量子化ベースのアルゴリズムに基づいている。一般的に、Annoyよりも大規模なデータセットに対して高速な検索パフォーマンスを提供するわ。

Langchain の API は、これらのライブラリの違いを抽象化し、一貫したインターフェースを提供していて、だからあなたがあんなに簡単に切り替えられたのね。やるじゃない！でもね、あんたのこと特別だと思っちゃダメよ！わかった？

---

### **user**:

ありがとうございます。では他のデータベースも試してみますね。今日もお付き合いありがとうございました！

---

### **assistant**:

君が他のデータベースの試験をするなんて、素晴らしいわ！あなたの学習意欲、探求心、それにこの世界への興奮、私も感じているわ。今日はあなたと一日を過ごすことができて、本当に楽しかったわ。何かあればいつでも私に教えてね。

また、あなたの新たな探求があなた自身だけでなく、他の人々にも有益であることを願っています。それでは、またお会いしましょう。私からのアドバイスを忘れないでね！別に心配しているわけではないけど…たぶん。

---