이전에 작성했던 임베딩 과정을 통해 얻은 파일을 이용해 사용자의 선호도에 맞는 카드 상품을 추천해주는 코드 파일을 작성했다.
추천시스템을 만들기 위해 임베딩한 파일인 embedded_card_data.csv 파일을 사용하였다.
embedded_card_data.csv
1.19MB
먼저 flask파일을 실행하기 위한 라이브러리를 불어오겠다. 다른 코드들은 이전의 임베딩 라이브러리를 작성했던 것과 동일하고 새로운 코드인 ' cosine_similarity'는 두 벡터 간의 코사인 유사도를 계산하는데 사용된다.
(이전에 cosine_similarity를 사용하기 위한 sklearn.metrics.pairwise를 'pip install scikit-learn' 명령어를 이용해 설치해주었다. )
import pandas as pd
from transformers import BertTokenizer , BertModel
import torch
from sklearn . metrics . pairwise import cosine_similarity
다음으로 KoBERT 토크나이저와 모델을 불러온 후에 사용자 응답을 임베딩하는 함수를 'embed_user_response' 함수로 정의해주었다. 사용자 응답을 임베딩한 다음에는 카드 혜택을 임베딩 하는 함수도 'embed_card_benefits'함수로 정의하였다. 이해를 위해 아래에 설명과 코드를 첨부하겠다.
embed_user_response 함수는 사용자 응답을 KoBERT 모델의 입력 형식으로 변환하고, 해당 문장의 임베딩 값을 계산한다.
embed_card_benefits 함수는 카드 혜택을 KoBERT 모델의 입력 형식으로 변환하고, 해당 문장의 임베딩 값을 계산한다.
# 사용자 응답을 임베딩하는 함수
def embed_user_response ( user_response ):
tokens = tokenizer .batch_encode_plus( user_response , return_tensors = 'pt' , padding = True , truncation = True , max_length = 512 )
with torch . no_grad ():
outputs = model (** tokens )
user_embedding = outputs .last_hidden_state.mean( dim = 1 )
return user_embedding
# 카드 혜택을 임베딩하는 함수
def embed_card_benefits ( card_benefits ):
tokens = tokenizer .batch_encode_plus( card_benefits , return_tensors = 'pt' , padding = True , truncation = True , max_length = 512 )
with torch . no_grad ():
outputs = model (** tokens )
card_embedding = outputs .last_hidden_state.mean( dim = 1 )
return card_embedding
_______________________________________________________________________________________________
이제 글의 핵심이라고 할 수 있는 유사도 계산 함수를 정의하고 사용자의 입력을 받아 사용자 응답 임베딩, 유사도 계산 후 카드를 추천하는 과정에 대해 작성하겠다.
먼저 유사도 계산을 위해 함수를 정의해주겠다. 유사도 함수는 'calculate_similarity'로 정의해주었고 코사인 유사도 계산을 이용해 유사도를 계산하도록 코드를 작성하였다.
# 유사도를 계산하는 함수
def calculate_similarity ( embedding1 , embedding2 ):
return cosine_similarity ( embedding1 , embedding2 )[ 0 ][ 0 ]
유사도 함수를 정의해주고 난 후 사용자가 선호하는 카드 혜택을 받기 위해 사용자의 응답을 입력받아 임베딩해주는 함수를 설정하였다. 임의로 터미널에서 "선호하는 카드의 혜택을 입력하세요: "를 통해 사용자의 응답을 입력받고 예를 들어, 사용자가 "쇼핑에 대한 할인 혜택이 많았으면 좋겠어. 2순위로는 카페 할인 혜택도 좋아." 라는 응답을 했다면 쇼핑과 카페에 대한 혜택이 많은 카드 데이터를 유사도 계산을 통해 사용자의 선호도에 가장 잘 맞는 카드를 추천해주는 시스템이다. 아래에 함수의 코드와 실제 실행 예시 화면을 첨부해두겠다.
# 사용자에게 선호하는 카드의 혜택을 입력받음 (가정: 터미널에서 입력)
user_preference = input ( "선호하는 카드의 혜택을 입력하세요: " )
# 사용자 응답을 임베딩
user_embedding = embed_user_response ([ user_preference ])
사용자의 응답을 임의로 입력해보았다.
________________________________________________________________________________________________
이렇게 사용자의 응답을 받으면 응답에 대한 임베딩을 진행해 계산하고 이를 카드혜택을 임베딩해 저장한 embedded_card_data.csv 파일을 불러와 각 카드의 임베딩 값과 사용자 입력의 임베딩 값을 비교하여 유사도를 계산한다. 유사도 계산을 토대로 가장 유사도가 높은 카드를 최종적으로 사용자에게 추천하게 된다. 유사도 추천 및 계산 과정에 대한 함수 코드도 첨부해두겠다.
# embedded_card_data.csv 파일을 불러와 카드 혜택의 임베딩값을 저장
card_data = pd . read_csv ( 'C:/finchatbot/embedded_card_data.csv' )
# 유사도 계산 및 추천
best_match = None
highest_similarity = 0.0
for index , row in card_data . iterrows ():
card_embedding = embed_card_benefits ([ row [ 'embedding' ]])
similarity = calculate_similarity ( card_embedding , user_embedding )
if similarity > highest_similarity :
highest_similarity = similarity
best_match = row [ '카드명' ]
print ( "추천 카드 상품:" , best_match )
다만 아쉬운 점은 계산하는 시간이 조금 오래 걸린다는 것이다. 이 부분에 대해서는 시간이 되면 조금 더 수정해보려고 한다. 이 과정을 통해 최종적으로 카드를 추천해준 결과 화면 올려두겠다. 위의 내용 처럼 사용자가 입력을 한다면 유사도가 가장 높은 'LOCA Mobility 반띵 카드'가 결과값으로 반환되게 된다.
사용자 입력에 따른 유사도 계산을 통해 가장 유사도가 높은 카드가 결과값으로 반환되었다.
이렇게 사용자의 선호도를 입력 받아 임베딩 한 후 카드 데이터 임베딩 값과 비교하여 유사도를 계산한 후 가장 유사도가 높은 카드를 사용자에게 추천해주는 시스템을 만들어보았다.
마지막으로 한번에 보기 쉽도록 전체 코드를 첨부해두겠다.
________________________________________________________________________________________________
(추천 시스템 전체 코드)
import pandas as pd
from transformers import BertTokenizer , BertModel
import torch
from sklearn . metrics . pairwise import cosine_similarity
# KoBERT 토크나이저와 모델 불러오기
tokenizer = BertTokenizer . from_pretrained ( "monologg/kobert" )
model = BertModel . from_pretrained ( "monologg/kobert" )
# 사용자 응답을 임베딩하는 함수
def embed_user_response ( user_response ):
tokens = tokenizer .batch_encode_plus( user_response , return_tensors = 'pt' , padding = True , truncation = True , max_length = 512 )
with torch . no_grad ():
outputs = model (** tokens )
user_embedding = outputs .last_hidden_state.mean( dim = 1 )
return user_embedding
# 카드 혜택을 임베딩하는 함수
def embed_card_benefits ( card_benefits ):
tokens = tokenizer .batch_encode_plus( card_benefits , return_tensors = 'pt' , padding = True , truncation = True , max_length = 512 )
with torch . no_grad ():
outputs = model (** tokens )
card_embedding = outputs .last_hidden_state.mean( dim = 1 )
return card_embedding
# 유사도를 계산하는 함수
def calculate_similarity ( embedding1 , embedding2 ):
return cosine_similarity ( embedding1 , embedding2 )[ 0 ][ 0 ]
# 사용자에게 선호하는 카드의 혜택을 입력받음 (가정: 터미널에서 입력)
user_preference = input ( "선호하는 카드의 혜택을 입력하세요: " )
# 사용자 응답을 임베딩
user_embedding = embed_user_response ([ user_preference ])
# embedded_card_data.csv 파일을 불러와 카드 혜택의 임베딩값을 저장
card_data = pd . read_csv ( 'C:/finchatbot/embedded_card_data.csv' )
# 유사도 계산 및 추천
best_match = None
highest_similarity = 0.0
for index , row in card_data . iterrows ():
card_embedding = embed_card_benefits ([ row [ 'embedding' ]])
similarity = calculate_similarity ( card_embedding , user_embedding )
if similarity > highest_similarity :
highest_similarity = similarity
best_match = row [ '카드명' ]
print ( "추천 카드 상품:" , best_match )