OpenAI ChatGPT API를 활용해 추천 시스템 구현하기(feat. HuggingFace)
포스팅 개요
최근 OpenAI에서 ChatGPT의 공식 API가 드디어 공개되었습니다. ChatGPT는 계속해서 이슈가 대두되고 있는 굉장한 모델인데요. 이번 포스팅에서는 파이썬(Python) 환경에서 OpenAI의 ChatGPT API를 활용해 추천 시스템(recommender system)을 간단하게 구현해보려고 합니다.
본 포스팅 외에도 최근 저는 OpenAI의 API 활용법에 대해서 궁금해 아래 2가지 글을 작성했습니다. 혹시 OpenAI GPT 모델을 파인튜닝(fine-tuning)하거나 GPT3.5 모델을 Python으로 간단하게 활용하는 방법에 대해서 궁금하시다면 아래 글을 참고하시면 조금이나마 도움이 되실 것 같습니다.
- Python OpenAI API를 활용해 GPT3.5 활용하기 : https://lsjsj92.tistory.com/655
- OpenAI GPT fin-tuning 방법 : https://lsjsj92.tistory.com/656
본 포스팅에서 참고한 자료는 다음과 같습니다.
- https://openai.com/blog/chatgpt
- https://www.kaggle.com/datasets/rounakbanik/the-movies-dataset
- https://openai.com/blog/introducing-chatgpt-and-whisper-apis
- https://platform.openai.com/docs/guides/chat/chat-completions-beta
- https://huggingface.co/models
본 포스팅에서 사용한 모든 코드는 아래 github에 올려두었습니다.
또한, 본 포스팅은 파이토치 한국 사용자 모임 제 2회 세미나에서 발표한 자료이기도 합니다.
포스팅 본문
이번 포스팅은 OpenAI에서 최근에 공개한 ChatGPT API를 활용해 Python으로 추천 시스템(recommender system)을 간단하게 만들어보는 과정을 정리합니다. 본 포스팅은 저의 이전 포스팅과 다르게 ChatGPT의 API를 활용하니 다른 GPT3.5과 혼동이 없으시길 바랍니다.
1. ChatGPT와 추천 시스템을 어떻게 조합해 활용할 수 있을까?
저는 추천 시스템(recommender system)을 개발하고 있는 사람으로써 ChatGPT를 추천 시스템에 어떻게 적용할 수 있을지 여러모로 고민을 많이 했습니다. 그러던 중 간단한 아이디어가 떠올라서 ChatGPT API, HuggingFace model을 활용해 구현을 해봤는데요. 2시간 정도의 시간으로 ChatGPT와 함께 추천 시스템을 간단하게 만들어볼 수 있었습니다.
제가 생각한 추천 시스템에 ChatGPT를 적용하는 간단한 아이디어는 다음과 같습니다.
- 사용자의 의도를 파악한 후 아이템을 추천하거나 자세한 설명을 제공
- 사용자가 히스토리가 없는 경우, 선호 메타 태그 값을 이용해 간단한 추천 제공
- 사용자의 히스토리가 있는 경우, 다음 콘텐츠를 제공
등등의 아이디어가 있을 것 같습니다.
( 혹시 다른 좋은 아이디어가 있으시다면 같이 공유해주시면 좋을 것 같아요! )
본 포스팅에서는 위의 1번, 2번의 스토리를 파이썬 코드로 직접 구현해보며 ChatGPT를 활용한 추천 시스템을 만들어보겠습니다. 또한, 저는 이때 HuggingFace 모델도 함께 활용하였음을 참고해주시면 감사하게습니다.
포스팅 개요에서도 언급하였듯, 전체 코드는 위의 github에 공개되어 있습니다.
2. Python ChatGPT API를 활용한 추천 시스템 만들어보기
먼저, 본 포스팅에서 활용한 개발 환경은 다음과 같습니다.
- OS : MacOS
- Python : Python3.9
- 라이브러리
- OpenAI : 0.27.0
- sentence-transformers : 2.2.2
본 포스팅에서 만들어보는 ChatGPT를 활용한 recommender system을 만들어보려면 아래와 같은 step에 따라 진행되어야 합니다.
- 활용 데이터 셋팅
- embedding vector 추출 ( HuggingFace 및 OpenAI embedding 활용 )
- 코사인 유사도 (cosine similarity ) 계산 함수 구현
- ChatGPT에 던질 Prompt 설정
- 추천 로직 구현
이제 위의 순서를 하나하나 살펴보면서 진행하겠습니다.
2-1. 데이터 준비
가장 먼저, 추천 시스템에 활용할 데이터를 준비해줍니다. 저는 데이터를 포스팅 개요에 작성한 Kaggle에 올라와있는 The Movie Dataset로 활용하겠습니다. Kaggle의 The Movie Dataset에는 아래와 같이 다양한 데이터가 있는데요.
본 포스팅에서는 movies_metadata.csv 데이터만 활용하도록 하겠습니다.
데이터는 다운로드 후 다음과 같은 Python 코드로 불러올 수 있습니다.
movies_metadata = pd.read_csv('./movie_meta/movies_metadata.csv', sep=",", dtype=str)
print(movies_metadata.shape)
movies_metadata.head()
2-2. Embedding vector 추출
이제 위 데이터에서 Embedding vector를 추출합니다. Embedding Vector를 왜 추출할까요? 그 이유는 다음과 같습니다.
- 텍스트의 Embedding vector를 구성하여, 사용자가 날리는 질문(query)에 따라 코사인 유사도를 구해 가장 유사한 아이템에 대한 정보 설명, 아이템 추천 등에 활용
이러한 이유로 embedding vector를 추출합니다. 저는 크게 아래와 같이 2가지의 embedding 값을 활용하였습니다.
- OpenAI에서 제공해주는 openai.embedding을 활용
- huggingface에서 제공해주는 embedding을 활용
그림으로 표현하면 아래와 같습니다.
2-2-1. OpenAI Embedding 활용
OpenAI에서 제공해주는 Embedding을 사용하려면 다음과 같은 코드를 활용하시면 됩니다. 아무래도 ChatGPT API가 OpenAI에서 제공해주는 것이다보니 OpenAI embedding을 활용하면 환경이 통일되어 편리함이 있을 수 있습니다.
openai_embedding_model = "text-embedding-ada-002"
def get_embedding(text: str, model: str) -> List[float]:
result = openai.Embedding.create(
model=model,
input=text)
return result["data"][0]["embedding"]
movies_metadata['openai_embeddings'] = movies_metadata['feature'].apply(lambda x : get_embedding(x, openai_embedding_model))
2-2-2. HuggingFace Embedding 활용
저는 이번 ChatGPT를 활용한 추천 시스템 구현에서는 HuggingFace를 활용하였습니다. 그 이유는 모델이 더 가벼운 것도 있고 제가 다른 모델로 테스트 해보고 싶을 때 자유롭게 적합한 모델(그리고 더욱 방대한 다양한 모델)로 변경할 수 있기 떄문입니다.
Python HuggingFace에서 embedding을 추출하시려면 다음과 같이 진행하시면 됩니다. 참고로 저는 SentenceTransformer를 활용하였습니다. 다른 모델을 활용하시려면 HuggingFace의 models를 참고해주세요!
model = SentenceTransformer("사용하고 싶은 모델")
movies_metadata['hf_embeddings'] = movies_metadata['feature'].apply(lambda x : model.encode(x))
그러면 아래와 같이 embedding 정보가 데이터 정보에 들어간 것을 확인할 수 있습니다.
2-3. 코사인 유사도(cosine similarity) 구현
이제 embedding vector까지 구했으니 코사인 유사도를 구하는 방법을 구현하면 됩니다. 이미 다양한 코드가 나와 있으니 편하신 코드를 활용하시면 됩니다. 저는 huggingface의 sentence_transformer에 있는 utils.pytorch_cos_sim을 활용하였습니다.
제가 활용한 cosine similarity 코드는 다음과 같습니다.
def get_query_sim_top_k(query, model, df, top_k):
query_encode = model.encode(query)
cos_scores = util.pytorch_cos_sim(query_encode, df['hf_embeddings'])[0]
top_results = torch.topk(cos_scores, k=top_k)
return top_results
query로 어떤 정보를 받게 되면 model.encode에 데이터를 올려 query가 가지고 있는 embedding 정보를 가져오고, 위에서 구한 huggingface embedding과 유사도를 구하는 방법입니다.
마지막으로 torch.topk를 활용해 top 개수를 가져옵니다.
2-4. ChatGPT을 활용한 추천 시스템에 활용할 ChatGPT Prompt 환경 구축
이제 OpenAI의 ChatGPT API에서 활용할 프롬프트(prompt)를 구축합니다. 사실 ChatGPT는 Prompt engineering이라는 직업명이 나올 정도로 prompt를 잘 셋팅해주는 것이 중요합니다. ChatGPT를 웹에서 쓰신 분들이 계시다면 web에서 chatgpt를 사용하실 때도 문장과 질문 형식을 어떻게 작성하냐에 따라서 답변의 퀄리티와 디테일이 다르다는 것을 볼 수 있으셨을 겁니다.
본 포스팅에서는 chatgpt를 활용한 recommendation system을 주제로 작성하고 있기 때문에 아래와 같은 목적으로 chatgpt prompt engineering을 간단하게 셋팅해줍니다.
- 추천을 원하는 것인가?
- 추가 정보를 더 알고 싶은 것인가?
- 상세한 설명을 원하는 것인가?
위와 같이 prompt를 나누는 이유는 다음과 같습니다.
- 사용자가 어떤 query를 입력함
- chatgpt는 해당 query에 따라 사용자의 의도를 파악
- 또한, ChatGPT는 사용자 의도에 따라 자연스러운 도움 메세지 생성
- huggingface의 embedding을 기반으로 유사도를 계산해 어떤 콘텐츠를 추천해줄 때 도움 메세지 뒤에 콘텐츠 추천 정보 제공
- 이러한 사용자 이력을 기반으로 상세 정보 설명등에 활용
이처럼 본 포스팅에서는 ChatGPT를 간단하게 사용자에게 어떤 도움 메세지나, 메세지를 chatbot스럽게 제공해주기 위해 활용합니다. 저는 추천 시스템을 돕는 일종의 조력자 역할로 ChatGPT를 사용했는데요. 어떻게 확장해서 활용할 수 있을지는 더 다양한 아이디에이션이 가능할 것 같습니다!
위 prompt 예시는 다음과 같습니다.
*여기서 잠시! OpenAI에서 제공해주는 ChatGPT는 어떻게 사용할 수 있을까요?
Python에서 OpenAI ChatGPT를 활용하는 방법은 ChatGPT 공식 홈페이지에 자세히 나와있습니다.
공식 홈페이지에서는 아래와 같이 설명이 되어있습니다.
'''
ChatGPT is powered by gpt-3.5-turbo, OpenAI’s most advanced language model.
Using the OpenAI API, you can build your own applications with gpt-3.5-turbo to do things like:
'''
즉, ChatGPT는 gpt-3.5-turbo 라는 것을 통해 사용할 수 있다는 것입니다. 또 더 자세히 살펴보면 아래와 같은 설명이 있습니다.
'''
Model: The ChatGPT model family we are releasing today, gpt-3.5-turbo, is the same model used in the ChatGPT product. It is priced at $0.002 per 1k tokens, which is 10x cheaper than our existing GPT-3.5 models. It’s also our best model for many non-chat use cases—we’ve seen early testers migrate from text-davinci-003 to gpt-3.5-turbo with only a small amount of adjustment needed to their prompts.
'''
OpenAI ChatGPT는 gpt-3.5-turbo로 제공되며 이는 ChatGPT 제품과 동일한 모델입니다. 또한, 가격은 1k tokens에 따라 0.002$로 측정되어 있네요! 가격은 GPT-3.5보다 10배 더 저렴해졌습니다.
그리고 위 사진을 보면 ChatGPT API를 Python에서 사용하는 방법은 아래 코드와 같이 활용하시면 됩니다.
OpenAI ChatGPT python example
import openai
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Tell the world about the ChatGPT API in the style of a pirate."}]
)
print(completion)
이제 다시 본문으로 돌아오겠습니다. prompt를 작성하기 위해서 아래와 같은 예시를 확인할 수 있습니다.
위 사진의 대한 내용은 다음과 같습니다.
- 사용자가 어떤 입력문을 넣었을 때 이게 추천을 원하는 것인가? 아니면 설명을 원하는 것인가?
즉, 위 ChatGPT의 prompt는 사용자의 의도(intent)를 파악하는 prompt입니다. 제가 따로 분류 모델을 만들지 않고도 이렇게 ChatGPT를 이용해 분류 형식의 모델을 zero-shot 형태로 만들 수 있는 것이죠!
또한, 아래와 같은 prompt 예시도 있습니다.
제가 사용자의 의도를 파악한 뒤에는 적절한 도움 메세지를 작성해준다고 말씀드렸는데, 위 사진이 그 예시입니다.
이렇게 사용자의 의도를 파악할 수 있고 이에 따라 도움 메세지가 추가되는 prompt를 만들어봤습니다. 이제 이에 따라 추천 시스템 로직이 다르게 돌아가도록 설계하도록 하겠습니다.
2-5. ChatGPT를 활용한 추천 시스템 로직 설계, 코드 구현
자! 이제 준비 단계는 다 끝났습니다. 위의 내용을 간단하게 정리하자면 다음과 같습니다.
- 데이터 셋팅 및 embedding vector 셋팅
- prompt 셋팅
이제 사용자의 의도에 따라 추천이 진행되도록 recommender system using ChatGPT를 간단하게 구현해봅시다.
2-5-1. 사용자가 어떤 영화를 추천해달라고 요청
가장 먼저, 사용자가 어떤 영화를 추천해달라고 요청 했을 경우 어떻게 동작되는지 확인해보겠습니다.
사용자가 영화를 추천해달라고 요청이 오면, 다음과 같은 프로세스로 추천 시스템이 동작됩니다.
- 사용자가 마블 히어로 영화와 비슷한 영화를 추천해달라고 요청
- ChatGPT는 가장 먼저, 해당 질문(query)이 추천을 원하는 것인지, 설명을 원하는 것인지 등 의도(intent)를 파악
- 추천(recommend)를 원하는 것으로 ChatGPT가 파악해서, recommend 로직을 타게 됨
- recommend 로직은 가장 먼저 사용자의 질문(query)을 model.encode로 huggingface embedding vector로 변환
- 이후, query embedding과 다른 아이템들의 코사인 유사도를 계산해서 어떤 것이 가장 연관성 있는지 측정
- 결과 출력. 이때 ChatGPT는 추천을 하기 위한 소개말을 작성해주고 그 뒤에 추천 된 콘텐츠가 덧붙여서 나옴
위 사진이 그 결과입니다. 마블과 같은 히어로 영화를 알려달라고 요청하니까, 모델은 엑스맨(X-men)과 같은 콘텐츠를 제공해주는 것을 확인할 수 있습니다. 간단한 로직이지만, ChatGPT가 사용자와 interaction하여 아이템을 추천하는 과정을 볼 수 있습니다.
2-5-2. 사용자가 추천 받은 영화에 대해서 자세한 설명을 요청
또 다르게 ChatGPT를 이용하는 방법은 사용자가 제공 받은 추천 콘텐츠를 자세히 설명해달라는 로직입니다. 여기서 사용자의 질문(query)는 위의 내용을 더 자세히 알려달라고 하는 질문인데요. 앞서 언급한 사용자의 message를 ChatGPT의 role 중 assistant에 넣어두어서 이 내용을 참고할 수 있도록 합니다.
사용자가 더 자세한 내용을 요청하는 프로세스는 다음과 같이 진행됩니다.
- 사용자가 더 자세히 설명해달라고 질문(query)를 던짐
- ChatGPT는 이전 사용자 대화 이력을 참고하도록 assistant에 추가된 내용을 참고함
- ChatGPT는 설명문이라는 사용자 의도(intent) 파악
- 사용자가 질문한 것과 가장 유사한 콘텐츠를 추출(자기 자신이 나옴)
- 설명문 출력
자세한 설명을 해달라고 하니, 위 영화에 대한 정보를 제공해줍니다. 제가 사용한 데이터는 더 자세한 내용을 설명하기엔 부족해서 2-5-1의 내용과 비슷하게 나왔는데요. 만약 자세한 내용이 있는 데이터가 있다면 다르게 나오도록 할 수 있습니다. 마찬가지로 ChatGPT가 생성한 문구가 앞에 붙어서 설명에 대한 수식을 해줍니다!
2-5-3. 사용자가 추천 받은 영화와 비슷한 다른 영화 정보를 요청
다음은 사용자가 마블과 비슷한 히어로물을 추천해달라고 질문을 던졌을 때 엑스맨(X-men)을 추천 받았었는데요. 이때 사용자가 다시 또 다른 콘텐츠가 있니?라는 질문을 던졌을 때의 처리 방법입니다.
이때는 다음과 같이 프로세스가 동작합니다.
- 사용자가 다른 영화는 없냐고 질문을 던짐
- ChatGPT는 가장 먼저, 해당 질문(query)이 추천을 원하는 것인지, 설명을 원하는 것인지 등 의도(intent)를 파악
- 추가 검색(search)를 원하는 것으로 ChatGPT가 파악해서, search 로직을 타게 됨
- search 로직에 따라 chatgpt는 소개(또는 인사말)을 작성해줌
- 사용자가 이전에 추천 받은 X-men과 비슷한 콘텐츠를 cosine similarity로 계산함
- 결과 출력. 이때 ChatGPT는 추가 검색을 하기 위한 소개말을 작성해주고 그 뒤에 추천 된 콘텐츠가 덧붙여서 나옴
그 결과로 엑스맨: 데이즈 오브 퓨터 패스트 ) (X-men: Days of Future Past)를 추천해주는 것을 확인할 수 있습니다.
2-5-4. 사용자 선호 태그를 활용한 기본 추천
마지막 예제입니다. 마지막은 굉장히 간단합니다. 만약, 사용자가 아무런 히스토리 정보가 없고 선호 태그 정보만 있을 경우에는 아래와 같이 추천할 수 있다는 것을 보여줍니다.
단순히, 사용자가 선호하는 정보를 huggingface model에 넣어 embedding을 뽑아낸 후 유사도를 계산하면 끝입니다.
사용자 선호 태그가 컴퓨터, 기술, 과학이었다면, 그것과 관련된 영화들이 추천되는 것을 확인할 수 있습니다.
한계점 및 확장성
본 포스팅에서 다룬 ChatGPT를 활용한 추천 시스템은 기본적인 것을 활용하였습니다. 여기서 이제 효율적인 Vector Search 방법, 사용자 과거 히스토리를 핸들링하는 방법 등 다양하게 확장할 수 있을 것입니다. 본 글에서는 이러한 것을 다루지 않았기 때문에 여러모로 한계점이 있는 간단한 방법입니다.
또한, Prompt의 output이 매번 달라지면서 데이터 셋에 맞지 않은 소개문이 나올 수도 있고 실제 application에서 활용할 수 있는 방안은 여러가지 테스트와 검증이 필요할 것입니다.
마무리
이번 포스팅은 Python 환경에서 OpenAI ChatGPT API를 활용해 추천 시스템(recommender system)을 간단하게 만들어보았습니다. ChatGPT가 엄청나게 이슈인 요즘, 다양한 분야에 어떻게 접목시킬 지 고민이 되는데요. 저는 그 중에 추천 시스템 영역에서 ChatGPT를 매우 간단하게 HuggingFace model과 조합해 구현해봤습니다.
혹시 다른 아이디어가 있다면 편하게 말씀주세요!
긴 글 읽어주셔서 감사합니다.
저에게 연락을 주시고 싶으신 것이 있으시다면
- Linkedin : https://www.linkedin.com/in/lsjsj92/
- github : https://github.com/lsjsj92
- 블로그 댓글 또는 방명록
으로 연락주시면 감사하겠습니다.