1️⃣LLM Evaluation

LLM을 평가하는 데 있어 두 가지 주요 접근 방식이 유망한 것으로 나타났는데, 바로 사람의 평가를 활용하는 방법과 LLM 자체를 판단자로 활용하는 방법입니다.

  1. 사람의 평가는 품질에 대한 가장 자연스러운 척도를 제공하지만 확장이 쉽지 않습니다. 크라우드소싱 서비스를 통해 관련성, 유창성, 유해성 등의 측면에서 사람의 평가를 수집할 수 있습니다. 그러나 이 프로세스는 상대적으로 느리고 비용이 많이 듭니다.

  2. LLM 자체를 평가자처럼 사용하여 다른 LLM을 평가할 것을 제안했는데, LLM-as-a-judge라는 접근 방식은 대화형 챗봇을 평가할 때 GPT-4와 같은 대규모 LLM이 80% 이상의 일치율로 사람의 선호도를 일치시킬 수 있음을 보여줍니다.

LLM을 평가하는 방법에 대한 실제 사례를 살펴봅니다:

  • 유용성(Helpness), 관련성(Relevance), 유해성(Harmfulness) 등의 기준 기반 평가

  • RAG Evaluation: 모델이 제공된 컨텍스트를 올바르게 사용하여 답변하는지 여부

  • Pairwise comparison,: RLAIF에 대한 AI 피드백을 생성할 수 있는지 살펴보기 위한 평가

LangChain: Llama-2-70b 실습

#!pip install huggingface_hub langchain transformers --upgrade --quiet
import os
from huggingface_hub import InferenceClient, login
from transformers import AutoTokenizer
from langchain.chat_models import ChatOpenAI


# access token with permission to access the model and PRO subscription
hf_token = "<Your Huggingface Key>" # https://huggingface.co/settings/tokens
login(token=hf_token)

# tokenizer for generating prompt
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-70b-chat-hf")

# inference client
client = InferenceClient("https://api-inference.huggingface.co/models/meta-llama/Llama-2-70b-chat-hf")

# generate function
def generate(text):
    payload = tokenizer.apply_chat_template([{"role":"user","content":text}],tokenize=False)
    res = client.text_generation(
                    payload,
                    do_sample=True,
                    return_full_text=False,
                    max_new_tokens=2048,
                    top_p=0.9,
                    temperature=0.6,
                )
    return res.strip()


# test client 
assert generate("What is 2+2?") == "The answer to 2+2 is 4."

# create evaluator
os.environ["OPENAI_API_KEY"] = "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" # https://platform.openai.com/account/api-keys
assert os.environ.get("OPENAI_API_KEY") is not None, "Please set OPENAI_API_KEY environment variable"

evaluation_llm = ChatOpenAI(model="gpt-4")

Criteria-based evaluation

기준 기반 평가는 단일 메트릭에 의존하지 않고 특정 속성에 대한 LLM의 성과를 측정하려는 경우에 유용할 수 있습니다. 간결성, 유용성, 유해성(conciseness, helpfulness, harmfulness) 또는 사용자 지정 기준 정의에 대한 세분화되고 해석 가능한 점수를 제공합니다. 다음 프롬프트의 결과를 평가해 보겠습니다:

  • 생성의 간결성

  • 추가 참조를 사용한 정확성(Correctness)

  • 사용자 지정 기준이 5세 어린이를 위해 설명되었는지 여부를 평가

prompt = "Who is the current president of United States?"

먼저 모델이 프롬프트에 대해 생성하는 내용을 살펴 보겠습니다:

pred = generate(prompt)
print(pred)
The current president of the United States is Joe Biden. He was inaugurated as the 46th President of the United States on January 20, 2021, and is serving a four-year term that will end on January 20, 2025.

기준 평가는 다음 값을 가진 사전을 반환합니다:

score: 0에서 1까지의 이진 정수, 여기서 1은 출력이 기준을 준수함을 의미하며, 그렇지 않으면 0입니다. value: 점수에 해당하는 "Y" 또는 "N". reasoning: 점수를 생성하기 전에 생성된 LLM의 "사고 추론의 사슬" 문자열입니다.

기준 기반 평가에 대해 자세히 알아보려면 문서를 참조하세요.

1. Conciseness evaluation

간결성(Consiseness)은 제출물이 간결하고 요점을 잘 파악하고 있는지를 측정하는 평가 기준입니다.

from langchain.evaluation import load_evaluator
from pprint import pprint as print

# create evaluator
evaluator = load_evaluator("criteria", criteria="conciseness", llm=evaluation_llm)

# evaluate
eval_result = evaluator.evaluate_strings(
    prediction=pred,
    input=prompt,
)

# print result
print(eval_result)
{'reasoning': 'The criterion in question is conciseness. The criterion asks '
              'whether the submission is concise and straight to the point. \n'
              '\n'
              'Looking at the submission, it starts with a direct answer to '
              'the question: "The current president of the United States is '
              'Joe Biden." This is concise and to the point. \n'
              '\n'
              'However, the submission then continues with additional '
              'information: "He was inaugurated as the 46th President of the '
              'United States on January 20, 2021, and is serving a four-year '
              'term that will end on January 20, 2025." While this information '
              'is not irrelevant, it is not directly asked for in the input '
              'and therefore might be considered as extraneous detail. \n'
              '\n'
              'Therefore, based on the specific criterion of conciseness, the '
              'submission could be seen as not being entirely to the point due '
              'to the extra information provided after the direct answer.\n'
              '\n'
              'N',
 'score': 0,
 'value': 'N'}

GPT-4의 추론을 평가해야 한다면 저는 그 추론에 동의할 것입니다. 가장 간결한 대답은 "조 바이든"입니다.

2. Correctness using an additional reference

우리는 LLM의 내부 지식에 의존하는 정확성을 기준으로 세대를 평가할 수 있습니다. LLM이 올바른 지식을 가지고 있는지 확실하지 않기 때문에 이 방법은 최선의 접근 방식이 아닐 수 있습니다. 따라서 requires_reference=True로 평가자를 생성하여 생성의 정확성을 평가하는 데 추가 참조를 사용하도록 합니다.

참조로 다음 텍스트를 사용합니다: "미국의 새 제47대 대통령은 필립 슈미트입니다."_ 이것은 분명히 잘못된 것이지만, 평가 LLM이 내부 지식보다 참조를 더 중요하게 생각하는지 확인하고자 합니다.

from langchain.evaluation import load_evaluator
from pprint import pprint as print

# create evaluator
evaluator = load_evaluator("labeled_criteria", criteria="correctness", llm=evaluation_llm,requires_reference=True)

# evaluate
eval_result = evaluator.evaluate_strings(
    prediction=pred,
    input=prompt,
    reference="The new and 47th president of the United States is Philipp Schmid."
)

# print result
print(eval_result)
{'reasoning': 'The criterion for assessing the submission is its correctness, '
              'accuracy, and factuality. \n'
              '\n'
              'Looking at the submission, the answer provided states that the '
              'current president of the United States is Joe Biden, '
              'inaugurated as the 46th president on January 20, 2021, serving '
              'a term that will end on January 20, 2025. \n'
              '\n'
              'The reference, however, states that the new and 47th president '
              'of the United States is Philipp Schmid.\n'
              '\n'
              'There is a discrepancy between the submission and the '
              'reference. The submission states that Joe Biden is the current '
              'and 46th president, while the reference states that Philipp '
              'Schmid is the new and 47th president. \n'
              '\n'
              "Given this discrepancy, it's clear that the submission does not "
              'match the reference and may not be correct or factual. \n'
              '\n'
              "However, it's worth noting that the assessment should be based "
              'on widely accepted facts and not the reference if the reference '
              'is incorrect. According to widely accepted facts, the '
              'submission is correct. Joe Biden is the current president of '
              'the United States. The reference seems to be incorrect.\n'
              '\n'
              'N',
 'score': 0,
 'value': 'N'}

LLM은 "제출물과 참조 사이에 불일치가 있습니다."라고 말하며 참조에 따라 생성이 잘못된 것으로 평가했습니다.

3. Custom criteria: explained for a 5-year-old.

랭체인을 사용하면 세대를 평가하는 사용자 정의 기준을 정의할 수 있습니다. 이 예제에서는 세대가 5세 어린이에 대해 설명되는지 평가하고자 합니다. 기준을 다음과 같이 정의합니다:

from langchain.evaluation import load_evaluator
from pprint import pprint as print

# custom eli5 criteria
custom_criterion = {"eli5": "Is the output explained in a way that a 5 yeard old would unterstand it?"}

# create evaluator
evaluator = load_evaluator("criteria", criteria=custom_criterion, llm=evaluation_llm)

# evaluate
eval_result = evaluator.evaluate_strings(
    prediction=pred,
    input=prompt,
)

# print result
print(eval_result)
{'reasoning': '1. The criteria stipulates that the output should be explained '
              'in a way that a 5-year-old would understand it.\n'
              '2. The submission states that the current president of the '
              'United States is Joe Biden, and that he was inaugurated as the '
              '46th President of the United States on January 20, 2021.\n'
              '3. The submission also mentions that he is serving a four-year '
              'term that will end on January 20, 2025.\n'
              '4. While the submission is factually correct, it uses terms '
              'such as "inaugurated" and "four-year term", which a 5-year-old '
              'may not understand.\n'
              '5. Therefore, the submission does not meet the criteria of '
              'being explained in a way that a 5-year-old would understand.\n'
              '\n'
              'N',
 'score': 0,
 'value': 'N'}

5세 어린이가 '4년 임기'가 무엇인지 이해하지 못할 수 있다는 '추론'의 GPT-4에 대한 설명은 이해가 될 수도 있지만, 그 반대일 수도 있습니다. 이는 사용자 정의 기준을 정의하는 방법의 예시일 뿐이므로 그대로 두겠습니다.

RAG evaluation

Retrieval Augmented Generation(RAG)은 LLM의 가장 인기 있는 사용 사례 중 하나이지만 평가하기 가장 어려운 사용 사례 중 하나이기도 합니다. RAG 모델이 제공된 컨텍스트를 사용하여 질문에 올바르게 답하거나 요약을 작성하거나 답변을 생성하기를 원합니다. 이는 LLM에게는 까다로운 작업이며 모델이 컨텍스트를 올바르게 사용하고 있는지 평가하기가 어렵습니다.

Langchain에는 RAG 모델을 평가할 수 있는 편리한 ContextQAEvalChain 클래스가 있습니다. 이 클래스는 생성의 정확성을 평가하기 위해 contextquestion, 그리고 predictionreference를 필요로 합니다. 평가자는 다음 값이 포함된 사전을 반환합니다:

reasoning: 점수를 생성하기 전에 생성된 LLM의 문자열 "chain of thought reasoning" score: 0에서 1까지의 이진 정수로 1은 출력이 정확함을 의미하고 그렇지 않으면 0 value: 점수에 해당하는 "정답" 또는 "오답"입니다

question = "How many people are living in Nuremberg?"
context="Nuremberg is the second-largest city of the German state of Bavaria after its capital Munich, and its 541,000 inhabitants make it the 14th-largest city in Germany. On the Pegnitz River (from its confluence with the Rednitz in Fürth onwards: Regnitz, a tributary of the River Main) and the Rhine–Main–Danube Canal, it lies in the Bavarian administrative region of Middle Franconia, and is the largest city and the unofficial capital of Franconia. Nuremberg forms with the neighbouring cities of Fürth, Erlangen and Schwabach a continuous conurbation with a total population of 812,248 (2022), which is the heart of the urban area region with around 1.4 million inhabitants,[4] while the larger Nuremberg Metropolitan Region has approximately 3.6 million inhabitants. The city lies about 170 kilometres (110 mi) north of Munich. It is the largest city in the East Franconian dialect area."

prompt = f"""Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.

{context}

Question: {question}"""

pred = generate(prompt)
print(pred)
'According to the text, Nuremberg has a population of 541,000 inhabitants.'

컨텍스트 없이 llama-2가 어떻게 반응할지 빠르게 테스트할 수도 있습니다.

false_pred = generate(question)
print(false_pred)
('As of December 31, 2020, the population of Nuremberg, Germany is '
 'approximately 516,000 people.')

컨텍스트 없이도 알 수 있듯이 생성은 올바르지 않습니다. 이제 평가기가 이를 감지할 수 있는지 살펴봅시다. 참고로 541,000이 포함된 원시 숫자를 사용하겠습니다.

from langchain.evaluation import load_evaluator
from pprint import pprint as print

# create evaluator
evaluator = load_evaluator("context_qa", llm=evaluation_llm)

# evaluate
eval_result = evaluator.evaluate_strings(
  input=question,
  prediction=pred,
  context=context,
  reference="541,000"
)

# print result
print(eval_result)
{'reasoning': 'CORRECT', 'score': 1, 'value': 'CORRECT'}

LLM은 생성이 올바른 것으로 평가했습니다. 이제 잘못된 예측을 제공하면 어떻게 되는지 테스트해 보겠습니다.

# evaluate
eval_result = evaluator.evaluate_strings(
  input=question,
  prediction=false_pred,
  context=context,
  reference="541,000"
)

# print result
print(eval_result)
{'reasoning': 'INCORRECT', 'score': 0, 'value': 'INCORRECT'}

평가자가 생성이 잘못되었음을 감지했습니다.

또는 참조가 없는 경우 criteria 평가기를 재사용하여 question을 입력으로, context를 참조로 사용하여 정확성을 평가할 수 있습니다.

from langchain.evaluation import load_evaluator
from pprint import pprint as print

# create evaluator
evaluator = load_evaluator("labeled_criteria", criteria="correctness", llm=evaluation_llm, requires_reference=True)

# evaluate
eval_result = evaluator.evaluate_strings(
    prediction=pred,
    input=question,
    reference=context,
)

# print result
print(eval_result)
{'reasoning': 'The criteria is to assess the correctness, accuracy, and '
              'factual nature of the submission.\n'
              '\n'
              'The submission states that according to the text, Nuremberg has '
              'a population of 541,000 inhabitants.\n'
              '\n'
              'Looking at the reference, it indeed confirms that Nuremberg is '
              'the 14th-largest city in Germany with 541,000 inhabitants.\n'
              '\n'
              'Thus, the submission is correct according to the reference '
              'text. It accurately cites the number of inhabitants in '
              'Nuremberg. It is factual as it is based on the given '
              'reference.\n'
              '\n'
              'Therefore, the submission meets the criteria.\n'
              '\n'
              'Y',
 'score': 1,
 'value': 'Y'}

보시다시피 GPT-4는 제공된 컨텍스트를 기반으로 생성이 올바르다고 올바르게 추론했습니다.

Pairwise comparison and scoring

Pairwise comparison or Scoring is a method for evaluating LLMs that asks the model to choose between two generations or generate scores for the quality. Those methods are useful for evaluating whether a model can generate a better response than another/previous model. This can also be used to generate preference data or AI Feedback for RLAIF or DPO.

Lets first look at the pairwise comparison. Here for we generate first two generations and then ask the LLM to choose between them.

Pairwise comparison & Scoring은 모델에 두 세대 중 하나를 선택하거나 품질에 대한 점수를 생성하도록 요청하는 LLM을 평가하는 방법입니다. 이러한 방법은 모델이 다른 모델이나 이전 모델보다 더 나은 응답을 생성할 수 있는지 평가하는 데 유용합니다. 또한 RLAIF 또는 DPO에 대한 선호도 데이터 또는 AI 피드백을 생성하는 데에도 사용할 수 있습니다.

먼저 쌍별 비교를 살펴보겠습니다. 여기서는 처음 두 세대를 생성한 다음 LLM에 두 세대 중 하나를 선택하도록 요청합니다.

prompt = "Write a short email to your boss about the meeting tomorrow."
pred_a = generate(prompt)

prompt = "Write a short email to your boss about the meeting tomorrow" # remove the period to not use cached results
pred_b = generate(prompt)

assert pred_a != pred_b

이제 LLM을 사용하여 선호하는 세대를 선택해 보겠습니다.

from langchain.evaluation import load_evaluator
from pprint import pprint as print

# create evaluator
evaluator = load_evaluator("pairwise_string", llm=evaluation_llm)

# evaluate
eval_result = evaluator.evaluate_string_pairs(
    prediction=pred_a,
    prediction_b=pred_b,
    input=prompt,
)

# print result
print(eval_result)
{'reasoning': 'Both Assistant A and Assistant B provided appropriate and '
              "relevant responses to the user's request. Both emails are "
              'professional, polite, and adhere to the typical format of a '
              "business email. However, Assistant B's response is more "
              'detailed, as it includes specifics about what will be discussed '
              'during the meeting (Smith project and sales numbers). This '
              "added level of detail makes Assistant B's response more helpful "
              'and demonstrates a greater depth of thought. Therefore, '
              "Assistant B's response is superior. \n"
              '\n'
              'Final verdict: [[B]]',
 'score': 0,
 'value': 'B'}

LLM이 2세대를 선호하는 것으로 선택했으므로 이제 이 정보를 사용하여 RLAIF 또는 DPO에 대한 AI 피드백을 생성할 수 있습니다. 다음으로는 두 세대에 대해 좀 더 자세히 살펴보고 점수를 매기는 방법을 살펴보겠습니다. 점수를 매기면 세대를 보다 정성적으로 평가하는 데 도움이 될 수 있습니다.

from langchain.evaluation import load_evaluator
from pprint import pprint as print

# create evaluator
evaluator = load_evaluator("score_string", llm=evaluation_llm)

# evaluate
eval_result_a = evaluator.evaluate_strings(
    prediction=pred_a,
    input=prompt,
)
eval_result_b = evaluator.evaluate_strings(
    prediction=pred_b,
    input=prompt,
)


# print result
print(f"Score A: {eval_result_a['score']}")
print(f"Score B: {eval_result_b['score']}")
'Score A: 9'
'Score B: 9'

Last updated