'Dynamic few-shot prompting'에 해당되는 글 1건

  1. 2024.01.03 [LangChain] Chat Model로 Few-shot Prompting 하기

Zero-shot, One-shot, Few-shot prompting은 특히 자연어 처리나 이미지 생성과 관련된 머신러닝 모델에서, 모델이 데이터를 어떻게 훈련하거나 사용하는지에 대해 설명할 때 사용됩니다. 이 용어들은 훈련 또는 추론 중에 모델에 제공되는 예제의 수와 관련이 있습니다. 


1. Zero-Shot Prompting

- 이는 모델이 수행해야 할 작업에 대한 예제가 전혀 제공되지 않는 시나리오를 의미합니다. 모델은 오로지 사전 훈련과 프롬프트의 지시에만 의존합니다. 

- 예시: 언어 모델에게 영어에서 프랑스어로 문장을 번역하라고 요청하는 것이며, 이때 이전의 번역 예제는 제공되지 않습니다. 


2. One-Shot Prompting 

- 이 경우 모델은 수행해야 할 작업의 한 가지 예제(a single example)를 제공받습니다. 이는 모델이 기대하는 형식이나 응답 유형을 이해하는 데 도움이 됩니다. 

- 예시: 언어 모델에게 새로운 농담을 만들기 전에 한 가지 농담 예제를 보여주는 것입니다. 이 예제는 템플릿이나 가이드 역할을 합니다. 


3. Few-Shot Prompting 

- 여기서는 모델에게 작업을 더 잘 이해할 수 있도록 소수의 예제(하나 이상이지만 일반적으로 많지 않음)가 제공됩니다. 

- 예시: 언어 모델에게 긴 텍스트를 한 단락으로 요약하는 세 가지 다른 예제를 제공한 후 새로운 텍스트를 요약하도록 요청하는 것입니다. 


각 경우에서 모델은 제공된 프롬프트의 정보를 사용하여 요청된 작업을 더 잘 이해하고 완수합니다. Zero-shot, One-shot, Few-shot prompting의 효과는 작업의 복잡성과 모델의 능력에 따라 다를 수 있습니다. 

 

 

지난번 포스팅에서는 LangChain과 LLM Models 을 사용하여 Few-shot Prompting 하는 방법을 소개하였습니다. 

 

이번 포스팅에서는 LLM Models 대신에 Chat Models 과 LangChain을 사용하여 Few-shot Prompting 하는 방법을 소개하겠습니다. 

 

(1) Chat Model 에 고정된 개수의 몇 개의 예시를 주는 Few-shot Prompting 

(2) Chat Model 에 사용자 인풋과 유사한 top k 개의 예시를 선별해서 주는 Dynamic Few-shot Prompting

 

 

 

LangChain - Few-shot Prompting for Chat Models

 

 

 

(1) Chat Model 에 고정된 개수의 몇 개의 예시를 주는 Few-shot Prompting 

 

먼저 터미널에서 pip install 로 langchain, openai, faiss-cup 모듈을 설치합니다. 

 

! pip install -q langchain openai faiss-cpu

 

 

그리고, 실습에 필요한 모듈을 importing 하고, Chat Model로 ChatGPT-4를 사용할 것이므로 OnenAI API Key를 등록해줍니다. 

 

from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import FewShotPromptTemplate, PromptTemplate
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain.vectorstores import FAISS
#from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

# set environment: OpenAI API Key
import os
os.environ["OPENAI_API_KEY"]="sk-xxxx..." # set with yours

 

 

(a) Few-shot Prompting에 사용할 몇 개의 예시를 작성합니다.

 

(b) 그리고 ChatPromptTemplate() 를 사용해서 ("human": "{input}"), ("ai", "{output}") 처럼 Human과 AI의 역할에 인풋과 아웃풋을 매핑해줍니다 (이 부분이 LLM Model과 Chat Model이 다른 부분임).

 

(c) 그 다음에 FewShotChatMessagePromptTemplate()에 앞서 정의해준 examples, example_prompt를 각 각 설정해줍니다.

 

(d) 마지막으로 ChatPromptTemplate.from_messages() 으로 앞에서 정의해준 예시와 Prompt 포맷을 다 조합해서 최종 Few-shot Prompt 를 작성해줍니다. 이때 "system"에게 페르소나를 지정해주는 것과 마지막에 "human"의 "input"이 추가되었습니다. 

 

# (a) Fixed Examples
# Define examples of creating antonyms
examples = [
    {"input": "happy", "output": "sad"}, 
    {"input": "tall", "output": "short"}, 
    {"input": "sunny", "output": "rainy"}, 
    {"input": "surprised", "output": "calm"}, 
    {"input": "dry", "output": "humid"}, 
    {"input": "hot", "output": "cold"}, 
    {"input": "satisfied", "output": "dissatisfied"}, 
]


# (b) A prompt template used to format each individual example.
example_prompt = ChatPromptTemplate.from_messages(
    [
        ("human", "{input}"), 
        ("ai", "{output}")
    ]
)

# (c) Assemble them into the few-shot prompt template
few_shot_prompt = FewShotChatMessagePromptTemplate(
    example_prompt = example_prompt, 
    examples = examples,
)

print(few_shot_prompt.format())
# Human: happy
# AI: sad
# Human: tall
# AI: short
# Human: sunny
# AI: rainy
# Human: surprised
# AI: calm
# Human: dry
# AI: humid
# Human: hot
# AI: cold
# Human: satisfied
# AI: dissatisfied


# (d) Finally, assemble the final prompt and use it with a model
final_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a trustwordy AI assistant."), 
        few_shot_prompt, 
        ("human", "{input}")
    ]
)

 

 

앞에서 정의한 Few-shot Prompt와 Chat Model, 그리고 Output Parser를 '|'를 사용해서 Chaining 해줍니다. 

 

# Chat Model
model = ChatOpenAI(model="gpt-4")

# Output Parser
parser = StrOutputParser()

# Chaining
chain = final_prompt | model | parser

 

 

앞에서 정의한 chain을 invoke()를 사용해서 실행시켜줍니다. 

chain.invoke({"input": "excited"})  ==> 'bored'

chain.invoke({"input": "snowy"})  ==> 'sunny'

라고 답변하는걸 보니 Few-shot Prompting이 잘 작동하네요. 

 

## Run the chain

chain.invoke({"input": "excited"})
# 'bored'

chain.invoke({"input": "snowy"})
# 'sunny'

 

 

 

(2) Chat Model 에 사용자 인풋과 유사한 top k 개의 예시를 선별해서 주는 Dynamic Few-shot Prompting

 

LangChain은 여러개의 예시 중에서 몇 개의 예시만을 선별해서 Few-shot Prompting을 할 수 있도록 4가지 종류의 Example Selector를 제공합니다. 

 

[ LangChain: Example Selector Types ]

LangChain Example Selector Types

 

 

이중에서 인풋과 예시를 임베딩으로 변환한 후에, 각 임베딩 벡터간 코사인 유사도를 계산해서, 사용자의 인풋과 가장 유사한 k개의 예시를 선택해주는 Semantic Similarity Example Selector를 사용해보겠습니다. 임베팅 변환은 OpenAI의 OpenAIEmbeddings() 를 사용하였으며, 임베딩 벡터를 저장하고 유사도 검색을 하는 Vector DB는 FAISS를 사용하였습니다. 

 

FewShotChatMessagePromptTemplate() 에 (예제 대신에) Example Selector를 설정해주고, ChatPromptTemplate.from_messages()에 "human"과 "ai"의 메시지 포맷을 설정해줍니다. 그리고 인풋으로 받는 변수 input_variables=["input"] 을 설정해주면 됩니다. 

 

# Select examples based on similarity to the inputs 
# by finding the examples with the embeddings that have the greatest cosine similarity with the inputs.
example_selector = SemanticSimilarityExampleSelector.from_examples(
    # the list of examples available to select from.
    examples, 
    # The embedding class used to produce embeddings which are used to measure semantic similarity.
    OpenAIEmbeddings(), 
    # The VectorStore class used to store the embeddings and do a similarity search over.
    FAISS, 
    # the number of examples to produce.
    k=2,
)


similar_prompt = FewShotChatMessagePromptTemplate(
    # we provide an ExampleSelector instead of examples.
    example_selector=example_selector, 
    # Define how each example will be formatted. 
    example_prompt=ChatPromptTemplate.from_messages(
        [("human", "{input}"), ("ai", "{output}")]
    ), 
    input_variables=["input"]
)

 

 

k=2 로서 사용자 인풋과 가장 유사한(즉, 인풋과 예제 임베딩 간 코사인 유사도가 가장 큰) 2개의 예제를 Example Selector를 사용해 선별해보겠습니다. 

 

"excited"를 인풋으로 넣었더니 감정에 해당하는 예제 2개를 잘 선택했습니다. 

"snowy"를 인풋으로 넣엏더니 날씨에 해당하는 예제 2개를 잘 선택했습니다. ^^b

 

# "excited" is a Feeling, k=2
example_selector.select_examples({"input": "excited"})
# [{'input': 'surprised', 'output': 'calm'}, {'input': 'happy', 'output': 'sad'}]


# "snowy" is a Weather, k=2
example_selector.select_examples({"input": "snowy"})
# [{'input': 'sunny', 'output': 'rainy'}, {'input': 'hot', 'output': 'cold'}]

 

 

ChatPromptTemplate.from_messages() 로 "system"의 페르소나를 지정해주고, 앞에서 Example Selector를 사용한 Few-shot Prompt 와 "human"의 "input" 까지 조합해주면 최종 프롬프트가 완성됩니다. 

 

# Assemble the final prompt template
final_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a trustwordy AI assistant."),
        similar_prompt, 
        ("human", "{input}"),
    ]
)


print(final_prompt.format(input="excited"))
# System: You are a trustwordy AI assistant.
# Human: surprised
# AI: calm
# Human: happy
# AI: sad
# Human: excited

 

 

final_prompt, Chat Model, 그리고 Output Parser를 '|'를 사용해서 Chaining 해줍니다. 

 

마지막으로 invoke()를 써서 chat_chain을 실행시켜주면 됩니다. 

 

chat_chain.invoke({"input": "excited"}) ==> "relaxed"

chat_chain.invoke({"input": "snowy"}) ==> "clear"

 

라고 몇 개의 예제를 통해 과제에 대한 정보를 주었더니 Chat Model이 잘 이해해서 답변을 정확하게 생성했네요. 

 

# Chaining
chat_chain = final_prompt | model | parser

# Run the chain
chat_chain.invoke({"input": "excited"})
# 'relaxed'

chat_chain.invoke({"input": "snowy"})
# 'clear'

 

 

 

[ Reference ]

- LangChain - Few-shot examples for chat models: 
https://python.langchain.com/docs/modules/model_io/prompts/few_shot_examples_chat

- LangChain - Example Selector Types:

https://python.langchain.com/docs/modules/model_io/prompts/example_selector_types/

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,