0. 포스팅 목록 & GitHub
(깃허브 스타 버튼 눌러주시면 글 작성에 큰 도움이 됩니다!)
https://github.com/Seokii/Chatbot4Univ
https://seokii.tistory.com/146
1. 엑셀 구축 데이터
https://seokii.tistory.com/152
이전 글에서 엑셀을 통해 챗봇 데이터를 구축한다고 설명했습니다.
2. 문장 유사도와 임베딩 저장
챗봇 엔진에 사용자의 입력 질문이 들어오면, 정확한 정보의 전달을 위해서 구축한 데이터로부터 올바른 질문이 선택되어 해당하는 답변이 출력되어야만 합니다.
이 문제를 해결하기 위해서 문장의 유사도를 판별하는 모델이 필요합니다.
이러한 NLP task를 'Semantic Textual Similarity, STS'라 정의합니다.
한국어로 사전 훈련된 Word2Vec의 모델 파일을 통해 fine-tuning을 거친 후 해당 문제를 해결하고자 했지만,
Word2Vec의 fine-tuning을 진행하던 중, 더 우수한 양질의 데이터로 훈련된 SBERT 모델을 찾게 되어 해당 사전 학습 모델을 가져와 구현하기로 결정했습니다.
KR-SBERT 모델을 통해 엑셀 파일의 질문 항목들을 벡터화 및 텐서화 시킨 후 pt파일로 저장하는 기능을 구현했습니다.
3. KR-SBERT
해당 모델은 서울대학교 컴퓨터언어학 연구실에서 개발한 모델입니다.
깃허브 주소 : https://github.com/snunlp/KR-SBERT
Sentence BERT는 기존 BERT 구조에서 문장 임베딩의 성능을 우수하게 개선시킨 모델입니다.
사전 학습된 모델은 KLUE-nli와 KorSTS의 우수한 데이터로 fine-tuning이 되었기 때문에 추가적인 fine-tuning은 진행하지 않고 사용하도록 하겠습니다.
4. 코사인 유사도
챗봇 사용자가 질문한 입력과 구축한 데이터에서의 가장 유사한 질문을 뽑아낼 때 코사인 유사도를 사용하고자 합니다.
단어나 문장을 벡터로 표현할 수 있기 때문에, 벡터 간 거리나 각도를 이용해 유사성을 파악할 수 있습니다.
코사인 유사도는 두 벡터 간 코사인 각도를 이용해 유사도를 측정하는 방법입니다.
코사인은 -1 ~ 1 사이의 값을 가지며, 두 벡터의 방향이 완전히 동일한 경우에는 1, 반대 방향인 경우에는 -1, 두 벡터가 서로 직각을 이루면 0의 값을 가집니다.
즉, 두 벡터의 방향이 같아질수록 유사하다는 판단을 할 수 있습니다.
공간 벡터의 내적과 크기를 이용해 코사인 각도를 계산할 수 있으며, 식은 아래와 같습니다.
5. 엑셀 데이터 임베딩 및 저장
- KR-SBERT를 사용하기 위해서는 sentence-transformer 라이브러리의 설치가 필요합니다.
# /train_tools/qna/create_embedding_data.py
import pandas as pd
from tqdm import tqdm
tqdm.pandas()
import torch
from sentence_transformers import SentenceTransformer
train_file = "/Users/Home/Documents/GitHub/Chatbot4Univ/train_tools/qna/train_data.xlsx"
model = SentenceTransformer('snunlp/KR-SBERT-V40K-klueNLI-augSTS')
df = pd.read_excel(train_file)
df['embedding_vector'] = df['질문(Query)'].progress_map(lambda x : model.encode(x))
df.to_excel("train_data_embedding.xlsx", index=False)
embedding_data = torch.tensor(df['embedding_vector'].tolist())
torch.save(embedding_data, 'embedding_data.pt')
구축한 엑셀 파일과 사전 학습된 모델을 train_file, model 변수로 정의했습니다.
엑셀 파일의 내용에서 '질문(Query)' 열에 해당하는 내용만 필요하기 때문에 해당 부분 문장들에 대해 임베딩을 진행하고 'embedding_vector'열을 만들어 엑셀 파일로 저장했습니다.
또한, 해당 임베딩 데이터를 torch.tensor()를 통해 텐서화시켜 embedding_data 파일명의 pt 파일로 저장했습니다. pt파일은 챗봇 엔진 구현에 사용될 예정입니다.
6. 임베딩 파일 로드와 유사도 측정
# test/embedding_test.py
import torch
import numpy as np
import pandas as pd
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('snunlp/KR-SBERT-V40K-klueNLI-augSTS')
embedding_data = torch.load('C:/Users/Home/Documents/GitHub/Chatbot4Univ/train_tools/qna/embedding_data.pt')
df = pd.read_excel('C:/Users/Home/Documents/GitHub/Chatbot4Univ/train_tools/qna/train_data.xlsx')
# 질문 예시 문장
sentence = "컴공 과사 번호 알려줘"
print("질문 문장 : ",sentence)
sentence = sentence.replace(" ","")
print("공백 제거 문장 : ", sentence)
# 질문 예시 문장 인코딩 후 텐서화
sentence_encode = model.encode(sentence)
sentence_tensor = torch.tensor(sentence_encode)
# 저장한 임베딩 데이터와의 코사인 유사도 측정
cos_sim = util.cos_sim(sentence_tensor, embedding_data)
print(f"가장 높은 코사인 유사도 idx : {int(np.argmax(cos_sim))}")
# 선택된 질문 출력
best_sim_idx = int(np.argmax(cos_sim))
selected_qes = df['질문(Query)'][best_sim_idx]
print(f"선택된 질문 = {selected_qes}")
# 선택된 질문 문장에 대한 인코딩
selected_qes_encode = model.encode(selected_qes)
# 유사도 점수 측정
score = np.dot(sentence_tensor, selected_qes_encode) / (np.linalg.norm(sentence_tensor) * np.linalg.norm(selected_qes_encode))
print(f"선택된 질문과의 유사도 = {score}")
# 답변
answer = df['답변(Answer)'][best_sim_idx]
imageUrl = df['답변 이미지'][best_sim_idx]
print(f"\n답변 : {answer}\n")
print(f"답변 이미지 : {imageUrl}")
- 임베딩 파일을 불러오고 유사도를 측정하는 테스트 코드를 구현했습니다.
- 질문 예시 문장은 "컴공 과사 번호 알려줘", 구축한 질문 데이터의 내용은 "컴공번호알려줘" 입니다.
- SBERT 모델을 사용해 앞서 구현했던 내용과 같은 방법을 사용했습니다.
- 코사인 유사도를 통해 가장 유사한 벡터를 출력하는 코드는 sentence-transformers에서 제공하는 cos_sim() 함수를 통해 간단하게 구현했습니다.
- 코사인 유사도에 대한 점수 측정하는 score 부분의 코드를 깔끔하게 함수화 하면 아래의 코드와 같습니다.
import numpy as np
from numpy import dot
from numpy.linalg import norm
def cos_sim(A, B):
return dot(A, B)/(norm(A)*norm(B))
테스트 코드에 대한 결과입니다.
입력 질문인 "컴공 과사 번호 알려줘"에 대하여 코사인 유사도가 0.9588인
"컴공번호알려줘" 질문 데이터가 선택되었고, 엑셀 파일의 144번째 질문임을 알 수 있었습니다.
또한, 올바른 답변을 안내 받았으며 답변에 대한 이미지는 존재하지 않아 null값을 출력했습니다.
'머신러닝 & 딥러닝 > 자연어처리' 카테고리의 다른 글
대학교 AI 질의응답 챗봇 만들기 - 7. 임베딩 저장 & 답변 검색 클래스화 (0) | 2022.07.30 |
---|---|
대학교 AI 질의응답 챗봇 만들기 - 6. 소켓 모듈과 JSON (0) | 2022.07.29 |
대학교 AI 질의응답 챗봇 만들기 - 4. 질의응답 데이터 엑셀로 구축 (1) | 2022.07.29 |
[NLP] 한국어 자연어 추론(Korean NLI) - KLUE Dataset & ELECTRA (0) | 2022.07.27 |
대학교 AI 질의응답 챗봇 만들기 - 3. 의도 분류 모델(CNN) (0) | 2022.07.23 |
댓글