머신러닝 & 딥러닝/자연어처리

대학교 AI 질의응답 챗봇 만들기 - 7. 임베딩 저장 & 답변 검색 클래스화

by seokii 2022. 7. 30.
728x90
반응형

0. 포스팅 목록 & GitHub

(깃허브 스타 버튼 눌러주시면 글 작성에 큰 도움이 됩니다!)

https://github.com/Seokii/Chatbot4Univ

 

GitHub - Seokii/Chatbot4Univ: 대학생을 위한 AI 질의응답 챗봇 만들기

대학생을 위한 AI 질의응답 챗봇 만들기. Contribute to Seokii/Chatbot4Univ development by creating an account on GitHub.

github.com

https://seokii.tistory.com/146

 

[Project] 대학생을 위한 AI 질의응답 챗봇 만들기

1. GitHub https://github.com/Seokii/Chatbot4Univ GitHub - Seokii/Chatbot4Univ: 대학교 재학생을 위한 AI 질의응답 챗봇 대학교 재학생을 위한 AI 질의응답 챗봇. Contribute to Seokii/Chatbot4Univ development by creating an account o

seokii.tistory.com

 

이전 포스팅인 [5. 엑셀 내용 임베딩 및 pt파일 저장 & 입력 질문과 유사도 비교] 글에서 구현했던

임베딩 저장 기능과 유사도 비교를 통한 점수 측정 기능을

챗봇 엔진에서 사용하기 위해 클래스화 시키도록 하겠습니다.

 

1. 질문 데이터 임베딩 & pt파일 저장 

이전에 작성했던 코드는 주석 처리하고 진행했습니다.

 

# /train_tools/qna/create_embedding_data.py

class create_embedding_data:
    def __init__(self, preprocess, df):
        # 텍스트 전처리기
        self.p = preprocess

        # 질문 데이터프레임
        self.df = df

        # pre-trained SBERT
        self.model = SentenceTransformer('snunlp/KR-SBERT-V40K-klueNLI-augSTS')

    def create_pt_file(self):
        # 질문 목록 리스트
        target_df = list(self.df['질문(Query)'])

        # 형태소 분석
        for i in range(len(target_df)):
            sentence = target_df[i]
            pos = self.p.pos(sentence)
            keywords = self.p.get_keywords(pos, without_tag=True)
            temp = ""
            for k in keywords:
                temp += str(k)
            target_df[i] = temp

        self.df['질문 전처리'] = target_df
        self.df['embedding_vector'] = self.df['질문 전처리'].progress_map(lambda x : self.model.encode(x))
        # self.df.to_excel("/Users/Home/Documents/GitHub/Chatbot4Univ/train_tools/qna/train_data_embedding.xlsx", index=False)
        embedding_data = torch.tensor(self.df['embedding_vector'].tolist())
        torch.save(embedding_data, '/Users/Home/Documents/GitHub/Chatbot4Univ/train_tools/qna/embedding_data.pt')

코드의 내용은 이전과 거의 같고 클래스화 시켰습니다.

이전 코드와 다른 점은, 구현했던 텍스트 전처리기를 통해 질문 데이터를 pos태깅하고 불용어 제거를 진행한 후 임베딩을 진행했습니다.

이는 유사도를 비교할 대상이 챗봇 사용자의 전처리된 입력이기 때문입니다.

따라서, 구축한 질문 데이터의 임베딩도 전처리 후 진행되도록 구현했습니다.

주석 처리된 # self.df.to_excel~ 부분은 윈도우에서 개발 진행 시 권한 오류가 발생하여 주석처리했습니다.

리눅스 기반의 서버 컴퓨터에서는 이를 쉽게 해결할 수 있기에 후에 주석을 제거하면, 전처리와 임베딩 데이터도 표시된 엑셀 파일을 저장할 수 있습니다.

 

 

2. 답변 검색 클래스

# utils/FindAnswer.py

import torch
import numpy as np
from numpy import dot
from numpy.linalg import norm
from sentence_transformers import SentenceTransformer, util

class FindAnswer:
    def __init__(self, preprocess, df, embedding_data):
        # 챗봇 텍스트 전처리기
        self.p = preprocess

        # pre-trained SBERT
        self.model = SentenceTransformer('snunlp/KR-SBERT-V40K-klueNLI-augSTS')

        # 질문 데이터프레임
        self.df = df

        # embedding_data
        self.embedding_data = embedding_data

    def search(self, query, intent):
        # 형태소 분석
        pos = self.p.pos(query)

        # 불용어 제거
        keywords = self.p.get_keywords(pos, without_tag=True)
        query_pre = ""
        for k in keywords:
            query_pre += str(k)

        # 전처리된 질문 인코딩 및 텐서화
        query_encode = self.model.encode(query_pre)
        query_tensor = torch.tensor(query_encode)

        # 코사인 유사도를 통해 질문 데이터 선택
        cos_sim = util.cos_sim(query_tensor, self.embedding_data)
        best_sim_idx = int(np.argmax(cos_sim))
        selected_qes = self.df['질문(Query)'][best_sim_idx]

        if self.df['의도(Intent)'][best_sim_idx] == intent:
            # 선택된 질문 문장 인코딩
            selected_qes_encode = self.model.encode(selected_qes)

            # 유사도 점수 측정
            score = dot(query_tensor, selected_qes_encode) / (norm(query_tensor) * norm(selected_qes_encode))

            # 답변
            answer = self.df['답변(Answer)'][best_sim_idx]
            imageUrl = self. df['답변 이미지'][best_sim_idx]
            success = True

        else:
            selected_qes = "nan"
            score = 0
            answer = "nan"
            imageUrl = "nan"
            success = False

        return selected_qes ,score, answer, imageUrl, success

이전 포스팅에서 구현했던 코드의 흐름과는 거의 동일합니다.

이전 코드와 다른 점은 아래와 같습니다.

- 앞서 언급한 것처럼, 전처리기를 통해 질문의 전처리가 이루어짐.

- 질문의 의도 파악 모델이 먼저 실행되기 때문에 선택된 질문의 의도와 모델이 계산한 의도가 일치하지 않는다면, 올바른 답변을 출력할 수 없게 설정함.

- 올바른 수행이 이루어졌는지 아닌지를 구분하기 위한 success 변수를 반환하도록 구현함.

  이는 추후에 데이터 축적을 목적으로 로그를 남기기 위함.

 

 

728x90
반응형

댓글