QEUR23_LMABYS13: Llama2の精度評価(LangChain-英語-その1)
~ LangChainというのは、結局は「良し悪し」 ~
D先生 : “我々のLLM(大規模言語モデル)も、すこしづつ進化を続けています。今回はLangChainをのVector Storeを使います。これで回答の精度は上がりますか?”
QEU:FOUNDER : “わからん・・・。今回もUS永住権認証試験(改)のデータを使いますが、英語の部分を使います。ちなみに、回答の型式は「Open_QA」と「Classification」の2種類あります。”
D先生 : “ちなみに、前々回にやってみたLlama2による英語の質問に対する回答の正解率は、以下のような感じでした。Llama2はさすがのパフォーマンスでしたよね。本当に期待しちゃうんですが・・・。”
(Llama-v2-13b-GPTQ:英語)
QEU:FOUNDER : “まあ、(LLMのパフォーマンスなんて)実際にやってみないとわからないです。それでは、LLMとLangChainで質問に回答するプログラムを晒します”
# llama2-13B-chat-GPTQによる連続回答プログラム(LangChainつき)
import pandas as pd
import numpy as np
from langchain import HuggingFacePipeline
from langchain import PromptTemplate, LLMChain
from transformers import AutoTokenizer, pipeline, logging
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
# LangChain
from langchain.chains import RetrievalQA
from langchain.document_loaders import DirectoryLoader
from langchain.embeddings import HuggingFaceEmbeddings
#from langchain.llms import GPT4All
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
#Load all the .txt files from docs directory
loader = DirectoryLoader('/content/drive/MyDrive/LCdocs/',glob = "**/*.txt")
documents = loader.load()
len(documents)
# -----
print(documents[0].page_content[0:1500])
# -----
# 言語情報をChunk分割する
splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64, separators=["\n\n", "\n", "。", ","],)
texts = splitter.split_documents(documents)
len(texts)
# -----
print(texts[30].page_content)
# -----
# モデル名
model_name_or_path = "TheBloke/h2ogpt-4096-llama2-13B-chat-GPTQ"
use_triton = False
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, use_fast=True)
model = AutoGPTQForCausalLM.from_quantized(model_name_or_path,
use_safetensors=True,
trust_remote_code=False,
device="cuda:0",
use_triton=use_triton,
quantize_config=None)
"""
# To download from a specific branch, use the revision parameter, as in this example:
# Note that `revision` requires AutoGPTQ 0.3.1 or later!
model = AutoGPTQForCausalLM.from_quantized(model_name_or_path,
revision="gptq-4bit-32g-actorder_True",
use_safetensors=True,
trust_remote_code=False,
device="cuda:0",
quantize_config=None)
"""
# -----
# Inference can also be done using transformers' pipeline
# Prevent printing spurious transformers error when using pipeline with AutoGPTQ
logging.set_verbosity(logging.CRITICAL)
#print("*** Pipeline:")
pipe = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
device=0, # GPUを使うことを指定 (cuda:0と同義)
max_new_tokens=512,
temperature=0.2,
top_p=0.95,
repetition_penalty=1.15
)
# -----
# Create Embeddings
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
db = Chroma.from_documents(texts, embeddings, persist_directory="db")
#################
##################################
llm = HuggingFacePipeline(
pipeline = pipe,
model_kwargs = {"temperature": 0.2}
)
qa = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=db.as_retriever(search_kwargs={"k": 2}),
return_source_documents=True,
verbose=False,
)
# -----
#Ask Simple Questions
result = qa(
"What is the supreme law of US?"
)
print(result)
# -----
print(result["result"])
######################
##################
# ----
# 質問の文字列リストを定義する
df = pd.read_excel("/content/drive/MyDrive/LCdocs/QEU-verify100-ja2(en).xlsx")
#print(df)
len(df)
# 英語のQA情報を読み込む
question_list = df["instructions(en)"].values
#print(question_list[0:20])
reference_list = df["response(en)"].values
#print(referece_list[0:20])
type_list = df["type"].values
print(type_list[0:20])
#df_out = df.loc[:, ["NO", "instructions(en)", "type"]]
#print(df_out)
######################
##################
# -----
# 個別の質問応答のタスクを実行する関数を定義する
def repeat_qa(question):
# 質問に回答する
print(f"No.{i}: Question: {question}")
# Ask Questions
res = qa( question )
answer = res["result"]
# -----
# Retrieve the page number from the source document
list_content = list(res['source_documents'][0])
#print(list_content)
# -----
# 整形する
arr_content = list_content[0]
#print(arr_content)
str_content = arr_content[1]
#print(str_content)
# -----
# 答えを表示する
print(f"Answer: {answer}")
print(f"Content: {str_content}")
return answer, str_content
# 繰り返し質問する
mx_output = []
for i in range(5): # len(df)
# 今回の質問を抽出する
question = question_list[i]
reference = reference_list[i]
val_type = type_list[i]
# 質問に回答する
answer, str_content = repeat_qa(question)
# 質問と回答のマトリックス(リスト)を生成する
mx_output.append([question, answer, reference, val_type, str_content])
# リストを出力する
#print("--------")
#print("generate answer list")
#print(answer_output)
print("--------")
print("generate output matrix")
print(np.array(mx_output[0:5]))
# -----
# Create DataFrame
mx_out = np.array(mx_output)
columns1 = ["Question", "Answer", "Reference", "Type", "Context"]
df_out = pd.DataFrame(data=mx_out, columns=columns1)
print(df_out)
# EXCEL ファイル (USverify100_Llama_en(LC).xlsx) として出力
df_out.to_excel("/content/drive/MyDrive/USverify100_Llama_en2(LC).xlsx")
QEU:FOUNDER : “そして、以下が回答の結果です。今回は、LangChainがLLMにどのような情報を提供したのかを確認するために「Context」という欄を追加しました。”
D先生 : “Contextの内容をみると、Vector Storeは「そこそこに」関連した情報を引っ張ってきていると思います。それで、回答の評価結果は?”
(Llama-v2-13b-GPTQ:今回->LCあり)
(Llama-v2-13b-GPTQ:前回->LCなし)
D先生 : “あれ?かえってパフォーマンスが悪くなったじゃないですか・・・。でも、なんでかな?”
D先生 : “やっぱり、Open_QAでは、言い回しが違うだけで正解が多いですよね。ただし、全体的に文が長くなりましたよね。”
# Prompts: プロンプトを作成する(default)
template = """<prompt>Question: {question} Write answer within 15 words.</prompt>
<answer>Answer:"""
QEU:FOUNDER : “以前のプログラム(↑)は、LLMに対して文の長さを短くするように指示していたんですよ。だから、Open_QAの対応はカンタンなのだが、Classificationの場合はかなり面倒になるんですよ。”
QEU:FOUNDER : “なんというかな・・・。LangChainを使うとClassificationの能力が逆に弱くなるような気がします。特に、今回の質問は「〇〇でないものを選べ」という質問だから・・・。与えられたCONTEXTにドンピシャの情報があればよいが、もしなければ推論できなくなるんでしょう。”
D先生 : “どうすればいいんでしょうかねえ・・・。”
QEU:FOUNDER : “他の人も同様の問題を抱えているわけで、そのQ&Aを調べてみるとよいと思います。今回紹介するページ(↑)は、その一例です。すごくわかりやすくまとまっているので、回答の内容を一緒に見てみましょう。”
(1) Customize the prompt: プロンプトをカスタマイズする: RetrievalQA チェーンのプロンプトをカスタマイズして、LLM がより正確な回答を生成できるようにすることができます。
(2) Return source documents: ソース・ドキュメントを返す: 回答の抽出に使用される、取得したドキュメントの完全なセットを返すことができます。 これは、生成された回答の基礎を理解し、必要に応じて検索プロセスを改善するのに役立ちます。
D先生 : “我々は、今回のテストではプログラムを改造してソース・ドキュメントの内容を見てみました。検証の結果、コンテキスト抽出の精度には大きな問題がなさそうです。ただし、CONTEXTの内容がClassificationの精度アップに寄与しなかったわけで・・・。”
QEU:FOUNDER : “それでは、つづきに行きましょう。”
(3) Use a Conversation Buffer Memory: 会話バッファ・メモリを使用する: 会話を保持し、過去の対話を参照するには、メモリ バッファを使用できます。 これは、質問内の代名詞や参照を解決するのに役立ちます。
(4) Use MultiQueryRetriever: MultiQueryRetriever を使用する: これにより、入力質問のバリアントが生成され、検索が向上します。
(5) Use different chain types: さまざまなチェーン・タイプを使用する: 共有コンテキストでは、stuff、map_reduce、refine、map_rerank などのさまざまなチェーン・タイプについて説明します。 各チェーン・タイプには、抽出に対応するための異なるアプローチがあり、アプリケーションの特定の要件に基づいて使用できます。 たとえば、stuff チェーン・タイプは、取得したすべてのドキュメントをプロンプトに単に「詰め込み」ます。map_reduce チェーン・タイプは、質問を各ドキュメントにマップし、回答を 1 つの回答に絞り込みます。refine チェーン・タイプは、回答を反復的に絞り込みます。そして、map_rerank チェーンは、 type は質問を各ドキュメントにマッピングし、回答を再ランク付けして、それらを 1 つの回答にまとめます。
(6) Tune the Llama2 model parameters: Llama2 モデルのパラメーターを調整する: 共有コンテキストでは、Llama2 モデルには、モデルの精度を向上させるために調整できるパラメーターがいくつかあります。 これらには、mirostat、mirostat_eta、mirostat_tau、num_ctx、num_gpu、num_thread、repeat_last_n、repeat_penalty、温度、stop、tfs_z、top_k、top_p が含まれます。 これらの各パラメーターを調整して、特定のアプリケーションのモデルのパフォーマンスを最適化できます。
D先生 : “ああ・・・、チェーン・タイプって、こういう機能なのか・・・。今、使っている「stuff」という「詰め込み」パラメタというのは良くなかったかもしれない。いやぁ・・・、それにしても、このアドバイスはうまくまとまっているなァ。”
QEU:FOUNDER : “このアドバイスをもう一回読んで、もう一度リベンジしましょう。”
~ まとめ ~
C部長 : “もしもし、FOUNDER・・・。大好物の話の続編がリリースされましたよ。”
QEU:FOUNDER : “これは、おいしい・・・(笑)。”
C部長 : “どうなりますかね?”
QEU:FOUNDER : “小生は、それでも「何とかなる」に1000点。”
コメント
コメントを投稿