kyonenya / next-langchain-pdf

PDFを読み込んだChatGPTが質問に答えてくれるアプリ
https://pdf-question.vercel.app
0 stars 0 forks source link

chore: LLM基礎知識 #1

Open kyonenya opened 1 year ago

kyonenya commented 1 year ago

OpenAI API

presence_penalty -2.0から2.0の値を取り、既に出てきた単語をもう一度使うかどうかを指定します。 -2.0に近いと同じ単語を繰り返し使うようになり、2.0に近いと同じ単語は繰り返し使いづらくなります デフォルトはゼロです。

frequency_penalty こちらもpresence_penaltyと同じようなパラメータで-2.0から2.0の値を取り、出てきた回数が多いほどペナルティを大きくするものです。 presence_penaltyと同様に-2.0に近いと同じ単語を繰り返し使うようになり、2.0に近いと同じ単語は繰り返し使わなくなります。 presence_penaltyは1度でも使ったかどうか、ということにペナルティを加えますが、frequency_penaltyは使った回数に応じてペナルティを加えます。 こちらもデフォルトはゼロです。 パラメータ - OpenAI GPT-3 APIの使い方を解説 | 楽しみながら理解するAI・機械学習入門

テキスト補完とチャット補完の違い

Text Completionsと比較してChat Completionsの特徴を見ていきましょう。

専用のモデル

Text Completionsでは、代表的なGPT-3.5モデルとしてtext-davinci-003が提供されていましたが、Chat Completionsでは、チャット補完に最適化された新しいモデルgpt-3.5-turboが追加されました。text-davinci-003は、高度な自然言語処理タスクでの利用が想定されている一方、 gpt-3.5-turboは小規模で速度が速く、比較的簡単な自然言語処理タスクでの利用が想定されています。なお、これらに互換性はなく、Chat Completionsでtext-davinci-003を使用することはできず、同様に、Text Completionsでgpt-3.5-turboを使用することはできません。

一連の会話に基づいた補完

Text Completionsでは単一のプロンプトを入力しますが、Chat Completionsでは一連の会話(誰がどんな発言をしたのか)をメッセージのリストとして入力できます。これにより、以前の会話のコンテキストに基づいた補完が実現可能です。たとえば、「猫の名前は?」という質問について、Text Completionsの場合、どの猫を指しているかは分かりません。しかし、Chat Completionsの場合、過去の会話から「吾輩は猫である」というコンテキストに基づいて回答します。 ChatGPT入門: Chat Completions APIでオリジナルのチャットボットを作ろう! - Qiita

OpenAIのEmbeddingとは? 自然言語処理において、単語や文章を「数値化する技術」 ・単語や文章をベクトル表現できる(ベクトル空間にマッピングする)  →類似するものは近くに配置され、異なるものは離れた位置に配置される ・「text-embedding-ada-002」モデルの入力トークンの上限は「8191」 ・「text-embedding-ada-002」モデルのベクトルは1536次元である OpenAIのEmbeddingの使い方_0747 – Rainbow Engine

Vercel AI SDK

実装例

Langchain.js

プロンプト

kyonenya commented 1 year ago

PDFテキスト分割

分割の設定をする - OpenAI APIとLangChainを使ってPDFの内容を質問したい

// これ参考にしちゃダメだな

データを分割するサイズを設定するために CharacterTextSplitter を使います。 以下のコードのようにインポートします。

import { CharacterTextSplitter } from "langchain/text_splitter";

次に新しいオブジェクトを作成し、変数 splitter に渡します。 そのコンストラクタに3つの引数としてを渡します。

separator: テキストをチャンクに分割するために使用される文字。 chunkSize: 分割後の各チャンク(断片)の最大文字数です。 chunkOverlap: 各チャンクが前のチャンクと重複する文字数。

const splitter = new CharacterTextSplitter({
  separator: " ",
  chunkSize: 512,
  chunkOverlap: 24,
});

separator をスペース`、chunkSize512chunkOverlap24` で設定しました、 数値は以下の記事を参考にさせていだたきました。

ChatGPTで独自データを学習させて回答してもらう方法 - Qiita

データをチャンクに分割するコードはこのあたりです。

text_splitter = RecursiveCharacterTextSplitter(
    # Set a really small chunk size, just to show.
    chunk_size = 512,
    chunk_overlap  = 24,
    length_function = count_tokens,
)
chunks2 = text_splitter.create_documents([text])

チャンクのサイズとチャンク同士のオーバラップする量を指定することができます。 このサイズは大きくしたりもしてみましたが、1000などにすると後のデータ検索時にChatGPTのトークンサイズ(4000)を超えてしまってエラーになったりすることが頻発したので、これくらいのサイズがちょうど良いのかもしれません。

kyonenya commented 1 year ago

TextSplitterの比較

RecursiveCharacterTextSplitter

お勧めの TextSplitter は RecursiveCharacterTextSplitter です。これは、"\n\n "から始まり、"\n"、""、というように、異なる文字で再帰的にドキュメントを分割します。これは、意味的に関連するすべてのコンテンツを、可能な限り同じ場所に維持しようとするので、良いことです。

ここで知っておくべき重要なパラメータは、chunkSizeとchunkOverlapです。 chunkSizeは、最終的なドキュメントの最大サイズ(文字数)を制御します。これは、テキストが変に分割されないようにするのに役立つことが多い。下の例では(説明のために)これらの値を小さく設定していますが、実際にはそれぞれデフォルトの1000と200になります。 RecursiveCharacterTextSplitter | 🦜️🔗 Langchain

CharacterTextSplitter

RecursiveCharacterTextSplitter の他に、より標準的な CharacterTextSplitter もあります。これは1種類の文字(デフォルトは"\n\n")だけを分割します。 CharacterTextSplitter | 🦜️🔗 Langchain

kyonenya commented 1 year ago

Faiss (Vector Store)

python

text_splitter = RecursiveCharacterTextSplitter(
    # Set a really small chunk size, just to show.
    chunk_size = 512,
    chunk_overlap  = 24,
    length_function = count_tokens,
)
chunks = text_splitter.create_documents([text])
# Get embedding model
embeddings = OpenAIEmbeddings()
#  vector databaseの作成
db = FAISS.from_documents(chunks, embeddings)
# langchainをロードする。
# chain = load_qa_chain(OpenAI(temperature=0.2,max_tokens=1000), chain_type="stuff")
query = "ランプが点滅しているが、これは何が原因か?"
# VectoreStoreを検索
docs = db.similarity_search(query)
# VectoreStoreの検索結果とqueryを渡してChatGPTに回答させる
# chain.run(input_documents=docs, question=query)

ChatGPTで独自データを学習させて回答してもらう方法 - Qiita

Create a new index from a loader - Faiss | 🦜️🔗 Langchain

import { FaissStore } from "langchain/vectorstores/faiss";
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
import { TextLoader } from "langchain/document_loaders/fs/text";

// Create docs with a loader
// const loader = new TextLoader("src/document_loaders/example_data/example.txt");
// const docs = await loader.load();

// Load the docs into the vector store
const vectorStore = await FaissStore.fromDocuments(
  docs,
  new OpenAIEmbeddings()
);

// Search for the most similar document
const resultOne = await vectorStore.similaritySearch("hello world", 1);
console.log(resultOne);

API Reference:

FaissStore from langchain/vectorstores/faiss

fromDocuments

Parameter Type
docs Document<Record<string, any>>[]
embeddings Embeddings
dbConfig? object
dbConfig.docstore? SynchronousInMemoryDocstore

Returns Promise<FaissStore>

similaritySearch() - FaissStore | 🦜️🔗 Langchain

Parameter Type Default value
query string undefined
k number 4
filter undefined | object undefined

Returns Promise<Document<Record<string, any>>[]>

OpenAIEmbeddings | 🦜️🔗 Langchain

modelName

modelName: string = "text-embedding-ada-002" Model name to use

kyonenya commented 1 year ago

Q&A - OpenAI

Q: Where is the Valley of Kings?

const response = await openai.createCompletion({
  model: "text-davinci-003",
  prompt: "I am a highly intelligent question answering bot. If you ask me a question that is rooted in truth, I will give you the answer. If you ask me a question that is nonsense, trickery, or has no clear answer, I will respond with \"Unknown\".\n\nQ: What is human life expectancy in the United States?\nA: Human life expectancy in the United States is 78 years.\n\nQ: Who was president of the United States in 1955?\nA: Dwight D. Eisenhower was president of the United States in 1955.\n\nQ: Which party did he belong to?\nA: He belonged to the Republican Party.\n\nQ: What is the square root of banana?\nA: Unknown\n\nQ: How does a telescope work?\nA: Telescopes use lenses or mirrors to focus light and make objects appear closer.\n\nQ: Where were the 1992 Olympics held?\nA: The 1992 Olympics were held in Barcelona, Spain.\n\nQ: How many squigs are in a bonk?\nA: Unknown\n\nQ: Where is the Valley of Kings?\nA:",
  temperature: 0,
  max_tokens: 100,
  top_p: 1,
  frequency_penalty: 0.0,
  presence_penalty: 0.0,
  stop: ["\n"],
});
{
  id: 'cmpl-7brqjPYzmdN45vd8DrVMS4xSiLjsv',
  object: 'text_completion',
  created: 1689259489,
  model: 'text-davinci-003',
  choices: [
    {
      text: ' The Valley of Kings is located in Luxor, Egypt.',
      index: 0,
      logprobs: null,
      finish_reason: 'stop'
    }
  ],
  usage: { prompt_tokens: 233, completion_tokens: 12, total_tokens: 245 }
}
kyonenya commented 1 year ago

Done.

{
  id: 'cmpl-7brvnL4wSWw62byhW7Wypp9LmB3Cg',
  object: 'text_completion',
  created: 1689259803,
  model: 'text-davinci-003',
  choices: [
    {
      text: ' The name of the company is Procter & Gamble.',
      index: 0,
      logprobs: null,
      finish_reason: 'stop'
    }
  ],
  usage: { prompt_tokens: 2212, completion_tokens: 12, total_tokens: 2224 }
}

image

kyonenya commented 1 year ago

ChatPDF

シンプルにすごい……

Welcome to the exciting news release from The Procter & Gamble Company! The company has announced a remarkable increase in net sales and organic sales, along with a rise in sales growth and cash return guidance. Additionally, P&G has maintained its fiscal year EPS growth guidance range.

Example questions:

What factors contributed to the increase in P&G's net sales and organic sales?

According to (Page 15), P&G's net sales growth for January-March 2023 was 4%, with organic sales growth of 7%. The growth was driven by a combination of factors, including higher pricing, innovation-based volume growth, and the impact of acquisitions and divestitures. Additionally, (Page 15) shows that P&G's total net sales growth for FY 2023 is estimated to be around 6%, with organic sales growth of approximately 1%.

kyonenya commented 1 year ago
# https://qiita.com/windows222/items/232f05bafa95a9c8874e#%E3%82%B3%E3%83%BC%E3%83%89
# https://colab.research.google.com/drive/1n0qtXXUdHdK376VjFM-rtAR9PWIPjNXi?usp=sharing

# # 上級者向けの方法 チャンクに分割。これだとメタデータの情報が取れない
# Step 1: Convert PDF to text
doc = textract.process("sample_document2.pdf")
# Step 2: Save to .txt and reopen (helps prevent issues)
# ChatGPT: このステップはPythonではエンコーディングの問題を回避するために行っていますが、JavaScriptでは通常このステップは不要です。
with open('attention_is_all_you_need.txt', 'w') as f:
    f.write(doc.decode('utf-8'))

with open('attention_is_all_you_need.txt', 'r') as f:
    text = f.read()

# Step 3: Create function to count tokens
tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")

def count_tokens(text: str) -> int:
    return len(tokenizer.encode(text))

# Step 4: Split text into chunks
text_splitter = RecursiveCharacterTextSplitter(
    # Set a really small chunk size, just to show.
    chunk_size = 512,
    chunk_overlap  = 24,
    length_function = count_tokens,
)

chunks2 = text_splitter.create_documents([text])