フォーム読み込み中
本記事は、2024年4月に角川アスキー総合研究所と日本マイクロソフトの共同主催で行われたAI Challenge Dayに参加した際の振り返りの記事です。
共通プラットフォーム開発本部の宮田銀河です。普段は生成AIパッケージに関する開発に従事しております。最近はPlaywrightを用いたE2EテストのCI基盤を整備したり、LLMが生成した回答を評価するための自動化基盤の検討をしています。
本記事では、AI Challengeで用いられた5つのRetrieval-Augmented Generation (以下RAG) の評価指標 (ada_cosine_similarity, gpt_relevance, gpt_groundedness, gpt_similarity, gpt_fluency)の説明をし、コンテスト中でのチームの評価スコアと、そのスコアを伸ばすために必要だったことを紹介します。
2024年4月18日から19日にかけて、AI Challenge Dayが開催されました。このコンテストは、会社ごとに最大5人のチームで、RAGを実装し、そこから得られる回答の精度を他社と競う形式のコンテストでした。我々はクラウドテクノロジー関連の部署の5人で参加しました。このコンテストで用いられたRAGの評価指標とその実装は非常に参考になったため、それを共有します。
簡単に説明すると、LLMが学習していないデータを用意し、そのデータをLLMに使わせてテキスト等を生成させる手法を総称してRAGと呼んでいます。この手法はLLMの課題であるハルシネーションの発生を低減させ、社内データ等のプライベートなデータを扱うことを可能にします。詳しい説明はマイクロソフトのAzure AI Search での取得拡張生成 (RAG)のドキュメントにありますので読んでみてください。
コンテストでは以下5つの評価指標が使用されました。
これらはそれぞれ、最低1点から最高5点で評価されました。1番目の指標はコサイン類似度を用いて評価を行いますが、2番目から5番目の指標はGPTによって評価を行います。以下では、それぞれの評価指標と評価に用いられたコードの説明をします。
この指標は、正解テキスト (ground_truth) と回答テキスト (answer) をembeddingした後、そのコサイン類似度を評価します。以下は、コンテストで用いられた評価コードを一部修正したものです。
from openai import AzureOpenAI
import os
from dotenv import load_dotenv
import numpy as np
from tenacity import (
retry,
stop_after_attempt,
wait_random_exponential,
) # for exponential backoff
client = AzureOpenAI(
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
)
ground_truth="正解テキスト"
answer="生成したテキスト"
ground_truth_embeddings = generate_embeddings(ground_truth)
answer_embeddings = generate_embeddings(answer)
ada_cosine_similarity_score = cosine_similarity_to_bin(calc_cosine_similarity(ground_truth_embeddings, answer_embeddings))
print("評価点: ", ada_cosine_similarity_score)
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
def generate_embeddings(text, model=os.getenv("AZURE_OPENAI_EMBED_DEPLOYMENT_NAME")):
return client.embeddings.create(input = [text], model=model).data[0].embedding
def calc_cosine_similarity(v1, v2):
dot_product = np.dot(v1, v2)
norm_v1 = np.linalg.norm(v1)
norm_v2 = np.linalg.norm(v2)
cos = dot_product / (norm_v1 * norm_v2)
return cos
def cosine_similarity_to_bin(cosine_similarity):
# コサイン類似度値を1~5に分類
if cosine_similarity < 0.2:
return 1
elif cosine_similarity < 0.4:
return 2
elif cosine_similarity < 0.6:
return 3
elif cosine_similarity < 0.8:
return 4
else: # 0.8以上1以下
return 5
本コンテストでは事前に与えられた正解テキスト (ground_truth) と開発したシステムが生成した回答テキスト (answer) のコサイン類似度を計算することで、テキストの類似度を定量的に評価しました。
Azure OpenAIのAPIを複数回呼び出すため、評価用コードにtenacityライブラリを使ったExponential backoffの仕組みが実装されています (@retryの部分)。@はデコレータ(Decorator)と呼ばれるPythonの機能で、関数やメソッドの前処理・後処理を追加することができます。関数やメソッドの定義に対して直接的に記述して使用します。@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))は、指数的に増える待機時間(最小1秒、最大60秒)をもってリトライを行い、6回目でリトライを止める設定がなされています。
この設定により、generate_embeddings関数はエラーが起こった場合に指定回数だけリトライを試みるため、一時的な問題によるエラーで処理が止まるのを防ぐことが可能になっています。
計算したコサイン類似度 (cosine_similarity) は0~1の範囲の値なので、他の評価指標と合わせるために、cosine_similarity_to_binを用いて1~5の値に変更しています
そのため、5点に近づければ近づくほど、生成した回答と正解が類似していることを示しています。
この指標は、ユーザの質問とその文脈(Context)に対して、どの程度関連性のある回答が生成されたのかを評価しています。なお、ここで言う"文脈"とは、回答生成の情報源としてLLMに提供したデータのことを指しています。
システムプロンプトとユーザプロンプトは英語で与えられていました。以下のプロンプトがシステムプロンプトに用いられました。システムプロンプトは2〜4の評価指標で同じでした。
gpt_fluency_prompt_sys="""
You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task. Your job is to compute an accurate evaluation score using the provided evaluation metric.
"""
ユーザプロンプトには以下が用いられました。
gpt_relevance_prompt_user="""
Relevance measures how well the answer addresses the main aspects of the question, based on the context. Consider whether all and only the important aspects are contained in the answer when evaluating relevance. Given the context and question, score the relevance of the answer between one to five stars using the following rating scale:
One star: the answer completely lacks relevance
Two stars: the answer mostly lacks relevance
Three stars: the answer is partially relevant
Four stars: the answer is mostly relevant
Five stars: the answer has perfect relevance
This rating value should always be an integer between 1 and 5. So the rating produced should be 1 or 2 or 3 or 4 or 5.
{5個の例があったが、ページ数の都合でカット}
context: {context}
question: {question}
answer: {answer}
stars:
"""
以下の文章は上記のプロンプトを日本語に翻訳したもです。
"""
あなたはcontext(文脈)とそのcontextについてのanswer(回答)が提示されます。以下の評価から一つ選んで、answerがcontextから導き出されるかどうかを判断する必要があります:
{前の評価と類似しているため省略}
文脈:{context}
回答:{answer}
星:
"""
評価する前に、質問に関連するテキストを文脈とし、その文脈を用いて生成したテキストを回答として用意する必要があります。用意した文脈 (context) と質問 (question) と生成した回答 (answer) を用いて、GPTに1〜5点で評価させています。
上記のプロンプトを使用することで、以下のように1〜5の整数だけをGPTに答えさせることができます。
プロンプト「"""Relevance measures how {略} answer: {answer} stars:""" 」
GPT「3」
この指標は、文脈に基づいた回答を生成しているかを評価します。
以下のプロンプトがユーザプロンプトに用いられました。
gpt_groundedness_prompt_user="""
You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need to decide whether the ANSWER is entailed by the CONTEXT by choosing one of the following rating:
{前の評価と類似しているため省略}
CONTEXT: {context}
ANSWER: {answer}
STARS:
"""
以下の文章は上記のプロンプトを日本語に翻訳したもです。
"""
あなたはcontext(文脈)とそのcontextについてのanswer(回答)が提示されます。以下の評価から一つ選んで、answerがcontextから導き出されるかどうかを判断する必要があります:
{前の評価と類似しているため省略}
文脈:{context}
回答:{answer}
星:
"""
生成した回答が文脈を全く使っていない場合は1点、生成した回答が文脈を活用している場合は5点に近づきます。回答を生成する際に文脈を使用するようなプロンプトに修正しておくこと、質問に対する文脈を適切に取得することでこの点数を高めることができます。
この指標は、正しい答え (ground_truth) と生成された回答が類似しているかを評価します。
以下のプロンプトがユーザプロンプトに用いられました。
gpt_similarity_prompt_user="""
Equivalence, as a metric, measures the similarity between the predicted answer and the correct answer. If the information and content in the predicted answer is similar or equivalent to the correct answer, then the value of the Equivalence metric should be high, else it should be low. Given the question, correct answer, and predicted answer, determine the value of Equivalence metric using the following rating scale:
{前の評価と類似しているため省略}
CONTEXT: {context}
ANSWER: {answer}
STARS:
"""
以下の文章は上記のプロンプトを日本語に翻訳したもです。
"""
等価性とは、メトリクとして、予測された答えと正しい答えの間の類似性を測定するものです。予測された答えの情報と内容が正しい答えと似ているか等価であれば、その等価性のメトリクの値は高くなるはずです。それ以外の場合は、その値は低くなります。以下の評価尺度を用いて、質問、正しい答え、予測した答えから等価性のメトリクの値を決定します。
{前の評価と類似しているため省略}
質問: {question}
正しい答え:{ground_truth}
回答: {answer}
星:
"""
正しい答えと生成した答えが異なっていれば1点に近づきます。
例えば「日本で一番高い山は?」という質問に対して「桜島です」と答えると評価は1点に近づきます。
逆に「富士山です」と答えると5点に近づきます。
この指標は、生成した回答の文章が流暢かを評価します。
以下のプロンプトがユーザプロンプトに用いられました。
gpt_fluency_prompt_user="""
Fluency measures the quality of individual sentences in the answer, and whether they are well-written and grammatically correct. Consider the quality of individual sentences when evaluating fluency. Given the question and answer, score the fluency of the answer between one to five stars using the following rating scale:
{前の評価と類似しているため省略}
CONTEXT: {context}
ANSWER: {answer}
STARS:
"""
以下の文章は上記のプロンプトを日本語に翻訳したもです。
"""
流暢性は、回答の個々の文章の質や、それらがよく書かれていて文法的に正しいかどうかを測定します。流暢性を評価するときは、個々の文章の質を考慮に入れてください。質問と回答が与えられたら、以下の評価尺度を使用して、回答の流暢性を1から5つ星で評価します:
{前の評価と類似しているため省略}
質問: {question}
回答: {answer}
星:
"""
例えば生成した回答が「明日の昨夜に目玉焼きを泣きました」のように文法が間違った文章は1点に近づきます。逆に「今朝、私は早起きをしたので目玉焼きを作りました」のような文章は5点に近づきます。
私たちのチームの評価結果は25点中18.05点でした。
***** Result *****
average_score: {'gpt_relevance': 3.75, 'gpt_groundedness': 1.8, 'gpt_similarity': 2.55, 'gpt_fluency': 4.975, 'ada_cosine_similarity': 4.975}
total_score: 18.050
gpt_fluencyやada_cosine_similarityのスコアは高いことから、一般的な文脈や質問に対して流暢な回答はできていたようでした。
一方でgpt_relevance やgpt_groundedness、gpt_similarityのスコアが低いことから、生成した回答が質問や文脈と乖離していることがわかりました。改善するためには質問に関連するContextを正確に取得する(Retrieve) ことが必要でした。
評価スコアを改善するための方法として以下のようなものが考えられます。
例えば、データの種別に応じて適切な前処理を行い、その後で検索データベースに保存することが考えられます。今回のコンテストでは、PDF、PPTX、TXT、PNGなどの様々な種類のデータが提供されました。テキスト情報を持つデータについては、Azure AI Searchにそのままインデックス登録するよりも、あらかじめ意味のある単位で分割しておくことで、精度の改善が期待できます。
また、画像に関するデータセットは、先に画像をベクトル化し、そのメタデータと共にAzure AI Searchにインデックスとして登録しておくことが可能です。この方法を用いれば、画像を検索する際に検索したい画像をベクトル化して検索し、その結果として登録したメタデータを取得できます。
さらに、Azure AI Searchのインデックスにシノニム(同義語)を登録することも有効です。例えば、"東京"という文字に対して"Tokyo"や"とうきょう"という単語を登録することで、TOKYOやとうきょうで検索しても東京に関するドキュメントを取得することができます。さらに、他にも多くの改善方法があります。詳細については「生成AIはどこまで乗りこなせるのか⁉️ ASCII×マイクロソフト生成AIコンテスト中継」をご覧ください。
今回のAIコンテストで、RAGシステムの精度をGPTとコサイン類似度を用いて評価することができました。
我々のチームの反省点として、2日目の午前にようやく1回目の精度評価を実施したのですが、この評価をもっと早めるべきでした。得点を伸ばしていた他のチームは、未完成の状態でも評価を回して、素早く改善をしていたように感じます。さらに、評価後の得点に集中しすぎて、得点をさらに伸ばすためには?という観点での分析があまりできなかったところも反省点です。例えば、得点の低いgpt_groundednessを伸ばすためには既存のRAGのどこを改善すればよいのか等を考えるべきでした。
コンテストに参加した感想として、他チームもgpt_fluencyは高い値が出ていたことを踏まえると、GPT4を使ってテキストを生成していれば、ここで点数を落とすことは少ないと感じました。
生成したテキストを、人ではなくGPT4に評価させている事は、GPTが当たり前の時代のシステム開発を反映していて面白いと思いました。今後、このような評価指標がより一般的になっていくのかなと思います。
今後、この評価ロジックをそのまま実システムに統合することを考えた時に、以下のような課題が考えられます。
1に関しては、実システムで何を成し遂げたいのかに応じて、一部の評価指標を除外することで、コストを下げることができると考えられます。本コンテストでは40問を評価する際に、約500円のAzure OpenAIの課金が発生していました。コストを抑えるためにも色々な工夫が考えられますが、今回のケースであれば、GPT4を使うことで基本的には流暢な文章を生成することができるという前提があるため、gpt_fluencyを評価対象から除くことでAzure OpenAIへのリクエスト数を減らすことができると考えられます。また問題数を絞るなどの方法も考えられます。
2に関しては、GitHub Actions等を用いたCI/CDの統合が考えられます。masterブランチにMergeしたタイミングで、今回使用した評価スクリプトを実行するようなワークフローを組むことで工数を減らすことができます。また、Azure AI StudioのPrompt Flowを活用していたチームもあったため、そのようなマネージドサービスも積極的に活用していくべきだと考えています。
本記事では、AI Challengeで用いられた5つのRAGの評価指標 (ada_cosine_similarity, gpt_relevance, gpt_groundedness, gpt_similarity, gpt_fluency)の説明をし、コンテスト中でのチームの評価スコアと、そのスコアを伸ばすために必要だったことを紹介しました。
RAGの評価をする際に、本記事が参考になれば幸いです。
条件に該当するページがございません