Skip to content

AI ChatBot Recommendation System

WGNW_gangdodan edited this page May 19, 2023 · 4 revisions

음성 인식 챗봇 시스템

이 문서는 음성 인식을 사용한 챗봇 시스템에 대한 구현 내용을 기술합니다.

데이터셋, 문장 임베딩 모델, 명령 의도분류 모델, 엔티티 구별 모델, 모델 설정 및 데이터셋 처리 관련 로직, 학습시 모델 설정 내용에 대한 설명이 포함됩니다.

데이터셋

직접 구성한 레시피 조작 명령어 데이터셋을 통해 모델학습을 진행.

  • 사용자의 명령어 문장에 대해 총 4가지 명령어 class 및 해당 명령어내 엔티티를 구별 가능하게 학습하였음.

데이터셋 세부 형태 :

  • 명령어 의도분류 데이터셋 형태 :

    question label
    다음 보여줘 NEXT
    다음 NEXT
    2페이지 넘겨줘 NEXT
    다음내용 알려줘 NEXT
    question label
    다시 한번 들려줘 REPEAT
    한번만 더 들려줘 REPEAT
    한번 더 말해줘 REPEAT
    다시 한번 말해줘 REPEAT
  • 명령어 엔티티(NER) 데이터셋 형태 :

    question label
    다음 보여줘 0 0
    다음 0
    2페이지 넘겨줘 S-Pcount 0
    다음내용 알려줘 0 0
    다음 넘겨줘 0 0
    다음 2장 넘겨줘 0 S-Pcount 0
    다음 3장 넘겨줘 0 S-Pcount 0
    다음 4장 넘겨줘 0 S-Pcount 0
    question label
    현재 레시피 다시 말해줘 S-NOW 0 0 0
    지금 레시피 다시 말해줘 S-NOW 0 0 0
    전체 레시피 다시 말해줘 S-TOTAL 0 0 0
    레시피 처음부터 다시 0 S-TOTAL 0
    처음부터 다시 말해줘 S-TOTAL 0 0
    처음부터 다시 들려줘 S-TOTAL 0 0
    처음부터 다시 S-TOTAL 0
    시작부터 다시 들려줘 S-TOTAL 0 0

문장 임베딩 모델 (gensim/FastText)

FastText 임베딩 모델을 사용하여 처리하며,

전체 데이터셋 문장을 FastText 방식을 통해 임베딩하여 처리합니다.

  • 인텐트 구별모델의 경우 SKTBrain/KoBERT 사용을 위해 별도의 문장 임베딩 모델을 사용함.

Untitled

명령어 의도분류 모델 (SKTBrain/KoBERT)

SKTBrain/KoBERT : https://github.com/SKTBrain/KoBERT#naver-sentiment-analysis

Untitled

SKTBrain에서 제공하는 KoBERT 모델에 자체 제작한 명령어 의도분류 데이터셋을 학습하여 사용자 명령어 의도분류가 가능한 모델을 학습 및 사용하였습니다.

  • 모델 결과 예시 :

Untitled

엔티티(NER) 구별 모델 (KoChat/LSTM)

KoChat/LSTM : https://github.com/hyunwoongko/kochat/blob/master/kochat/model/entity/lstm.py

Untitled

KoChat 프로젝트의 LSTM 모델에 자체 제작한 명령어 엔티티(NER) 데이터셋을 학습하여 사용자의 명령어 문장별로 NER(개체명 인식) 태깅을 분류가능한 LSTM 모델을 학습 및 사용하였습니다.

학습시 모델 설정 내용.

임베딩, 인텐트 학습, 엔티티 학습 등에 사용한 학습 횟수 및 기타 설정은 kochat_config.py 파일 내에 기록되어 있습니다.

Untitled

모델 설정 및 데이터셋 처리 관련 로직.

KoChat : https://github.com/hyunwoongko/kochat

KoChat 프로젝트에서 사용하는 데이터셋 처리 방식 및 학습모델 세부 설정 방식을 차용하여 저희 프로젝트에 적용하였습니다.

추천 시스템

이 문서는 협업 필터링 및 컨텐츠 베이스 필터링 방식으로 구현한 추천 시스템에 대한 내용을 기술합니다.

협업 필터링 방식 :

사용자들의 콘텐츠 평점 기록 (초기 데이터값은 자체적으로 제작)을 MatrixFactorization 방식을 통해 사용자 평점 예측 테이블을 제작 및 이를 기반으로 추천 리스트를 생성.

: 해당 MatrixFactorization 을 구현하는 과정에서 Gradient_descent 방식을 활용한 학습방식을 사용함.

관련 코드 :

def fit(self):
    """
    training Matrix Factorization : Update matrix latent weight and bias

    참고: self._b에 대한 설명
    - global bias: input R에서 평가가 매겨진 rating의 평균값을 global bias로 사용
    - 정규화 기능. 최종 rating에 음수가 들어가는 것 대신 latent feature에 음수가 포함되도록 해줌.

    :return: training_process
    """

    # init latent features
    self._User_Latent = np.random.normal(size=(self._num_users, self._k))
    self._Item_Latent = np.random.normal(size=(self._num_items, self._k))

    # init biases
    self._b_User_Latent = np.zeros(self._num_users)
    self._b_Item_Latent = np.zeros(self._num_items)
    self._b = np.mean(self._R[np.where(self._R != 0)])

    # train while epochs : 설정된 횟수만큼 반복 학습.
    self._training_process = []
    for epoch in range(self._epochs):
        # rating이 존재하는 index를 기준으로 training
        X_index, Y_index = self._R.nonzero()
        for x, y in zip(X_index, Y_index):
            self.gradient_descent(x, y, self._R[x, y])
        cost = self.cost()
        self._training_process.append((epoch, cost))

        # print status
        if self._verbose == True and ((epoch + 1) % 5 == 0):
            print("Iteration: %d ; cost = %.4f" % (epoch + 1, cost))


def cost(self):
    """
    compute root mean square error
    :return: rmse cost
    """

    # Nx_index, Ny_index: R[Nx_index, Ny_index]는 nonzero인 value를 의미한다.
    # 참고: http://codepractice.tistory.com/90
    Nx_index, Ny_index = self._R.nonzero()
    # predicted = self.get_complete_matrix()
    cost = 0
    for Nx, Ny in zip(Nx_index,Ny_index):
        cost += pow(self._R[Nx, Ny] - self.get_prediction(Nx, Ny), 2)
    return np.sqrt(cost/len(Nx_index))


def gradient(self, error, x, y):
    """
    gradient of latent feature for GD

    :param error: rating - prediction error
    :param i: user index
    :param j: item index
    :return: gradient of latent feature tuple
    """

    dp = (error * self._Item_Latent[y, :]) - (self._reg_param * self._User_Latent[x, :])
    dq = (error * self._User_Latent[x, :]) - (self._reg_param * self._Item_Latent[y, :])
    return dp, dq


def gradient_descent(self, x, y, rating):
    """
    graident descent function

    :param x: user index of matrix
    :param y: item index of matrix
    :param rating: rating of (x,y)
    """

    # get error
    prediction = self.get_prediction(x, y)
    error = rating - prediction

    # update biases
    self._b_User_Latent[x] += self._learning_rate * (error - self._reg_param * self._b_User_Latent[x])
    self._b_Item_Latent[y] += self._learning_rate * (error - self._reg_param * self._b_Item_Latent[y])

    # update latent feature
    dp, dq = self.gradient(error, x, y)
    self._User_Latent[x, :] += self._learning_rate * dp
    self._Item_Latent[y, :] += self._learning_rate * dq

컨텐츠 베이스 필터링 방식 :

제공하는 컨텐츠를 내의 정보를 CountVectorizer를 사용해 벡터형태로 변환후 이 벡터값들간의 유사도를 분석한 cosine_similarity 테이블을 통해 특정 컨텐츠에 대한 추천 리스트를 생성.

관련 코드 :

   from sklearn.feature_extraction.text import CountVectorizer
   stopwords=['으로', '가', '을', '를', '에', '로', '에게', '또한', ',', '.']

   count = CountVectorizer(stop_words=stopwords)
   count_matrix = count.fit_transform(df_new2['soup'])

   """다른 cosine_similarity를 구해준다, 이것은 category 에 대한 matrix"""
   cosine_sim2 = cosine_similarity(count_matrix, count_matrix)

   df_new1 = df_new1.reset_index()
   indices_c = pd.Series(df_new1.index, index=df_new1['레시피id'])

추천 시스템 접근 :

각 협업 필터링 및 컨텐츠 베이스 필터링 기법을 통한 추천 아이템 리스트에 접근하기 위해 Python Flask 및 Flask-RESTX 를 활용한 API 형태로 접근 및 사용.

예시 :

Gachon-USER

Front End(Android)
Back End
Data Base
API

Clone this wiki locally