/KoGPT2-chatbot

Simple Chit-Chat based on KoGPT2

Primary LanguageJupyter NotebookMIT LicenseMIT

KoGPT-2 Chatbot 컴컴이

Run on Ainize

공개된 한글 챗봇 데이터와 pre-trained KoGPT2를 이용하여 간단한 대화를 나눌 수 있는 챗봇 모델이 등장하였습니다! 이를 활용하여 ainize의 GPU 환경에서 opyrator로 챗봇 프로토타입 컴컴이을 만들었습니다.

스크린샷 2021-05-13 오후 3 10 19

  • 한글 챗봇 데이터

    인공데이터로 주로 사랑과 이별에 관한 내용입니다. 그 덕분에 챗봇은 연애상담에 최적화되어 있습니다. 그리고 감정상태에 따라 라벨링되어있습니다. 내용이 일상다반사라면 0, 이별(부정)라면 1, 사랑(긍정)은 2로 라벨을 표시합니다.

data

  • KoGPT2

    GPT-2는 주어진 텍스트의 다음 단어를 예측하기에 적합한 학습 언어 모델이며 문장 생성에 최적화되어있습니다. KoGPT2는 GPT2의 부족한 한국어 성능을 극복하기 위해 40GB 이상의 텍스트로 학습된 한국어 디코더 모델입니다.

  • Tokenizer

    기본적으로 tokenizers 패키지의 Character BPE tokenizer를 사용합니다.

from transformers import PreTrainedTokenizerFast

U_TKN = '<usr>'
S_TKN = '<sys>'
BOS = '</s>'
EOS = '</s>'
MASK = '<unused0>'
SENT = '<unused1>'
PAD = '<pad>'

TOKENIZER = PreTrainedTokenizerFast.from_pretrained("skt/kogpt2-base-v2",
            bos_token=BOS, eos_token=EOS, unk_token='<unk>',
            pad_token=PAD, mask_token=MASK

그렇다면 어떻게 문장 생성 모델을 통해 응답형식의 문장을 생성할 수 있나요?

simsimi

위와 같은 아키텍처를 통해 유저의 발화에 따른 챗봇의 응답을 생성할 수 있습니다.

  • <usr> : 데이터의 Q필드(사용자의 발화)
  • <sent> : 감정 라벨
  • <sys> : 데이터의 A필드(챗봇의 응답)

각각의 데이터 필드에 매핑하여 **P(<sys> | <usr>, <sent>)**의 값이 최대가 되는, 즉 이전 내용과 감정 폭을 기반으로 가장 가능성이 높게 도출될 수 있는 <sys>가 챗봇의 응답이 되도록 합니다.

Class

간단한 설명을 위해 argument parsing, 구체적인 클래스 메소드는 생략하였습니다. CharDataset 클래스에서 csv 데이터의 Q필드, label필드, A필드를 추출하여 토큰화합니다. 이를 기반으로 KoGPT2Chat에서 트레이닝을 하고 model_chp/model_-last.ckpt 에 트레이닝된 모델을 저장합니다. 더욱 자세히 트레이닝 메소드에 알고 싶다면 여기를 참고해주세요.

import numpy as np
import pandas as pd
import torch
from pytorch_lightning import Trainer
from pytorch_lightning.callbacks import ModelCheckpoint
from pytorch_lightning.core.lightning import LightningModule
from torch.utils.data import DataLoader, Dataset
from transformers.optimization import AdamW, get_cosine_schedule_with_warmup
from transformers import PreTrainedTokenizerFast, GPT2LMHeadModel

class CharDataset(Dataset):
    def __init__(self, chats, max_len=32):
        self._data = chats # 학습 데이터(csv)
        self.first = True 
        self.q_token = U_TKN # <usr>
        self.a_token = S_TKN # <sys>
        self.sent_token = SENT # <sent>
        self.bos = BOS # </s>
        self.eos = EOS # </s>
        self.mask = MASK # 이모티콘
        self.pad = PAD
        self.max_len = max_len
        self.tokenizer = TOKENIZER

class KoGPT2Chat(LightningModule):
    def __init__(self, hparams, **kwargs):
        super(KoGPT2Chat, self).__init__()
        self.hparams = hparams
        self.neg = -1e18
        self.kogpt2 = GPT2LMHeadModel.from_pretrained('skt/kogpt2-base-v2')
        self.loss_function = torch.nn.CrossEntropyLoss(reduction='none')

Command

트레이닝을 하기 위해 모든 코드를 이해해야할 필요는 없습니다. Colab을 통해 간단하게 트레이닝을 할 수 있도록 안내되어있습니다. 직접 코드를 수정하여 gpus, max_epochs 등 트레이닝 옵션을 자유롭게 부여하며 모델 학습을 진행할 수 있습니다. 저는 colab에 주어진 max_epochs보다 약간 높게 부여하여 더욱 주어진 데이터를 중점적으로 학습하도록 하였습니다.

_2021-05-12__6 06 35

Usage

위 과정을 거쳐 모델을 생성하였고, opyrator를 이용해 유저가 컴컴이에게 말을 걸면 컴컴이가 답하는 구조의 사이트를 간단하게 생성하였습니다. 더 자세한 opyrator를 사용 방식이 궁금하시다면 여기를 참고해주세요

[app.py]

from model import User, Comcom, KoGPT2Chat 

def chatbot(input : User)->Comcom : 
    """심심할 때 컴컴이와 대화해보세요."""
    model = KoGPT2Chat.load_from_checkpoint('model_chp/model_-last.ckpt')
    text = input.user
    return Comcom(comcom = model.chat(text = text.strip()))

[model.py]

# 상단의 class 외에 아래와 같이 input, output class 추가
class User(BaseModel):
    user : str = Field(
        ...,
        title = "User",
        max_length = 20
    )

class Comcom(BaseModel):
    comcom : str

심심하시다구요? 여기에서 컴컴이와 대화해보세요!