0. 포스팅 목록 & GitHub
(깃허브 스타 버튼 눌러주시면 글 작성에 큰 도움이 됩니다!)
https://github.com/Seokii/Chatbot4Univ
https://seokii.tistory.com/146
1. 의도 분류 모델
사용자의 입력을 전달받아, 챗봇 엔진에서 전처리를 수행하고 질문의 의도를 분류하고자 합니다.
일단은 대학교에 대한 Q&A 챗봇이기 때문에, 다음과 같이 의도를 분류했습니다.
기본적인 의도를 분류해 일단 모델을 만들고,
챗봇을 운영하며 질문자의 질문 데이터 로그를 모아 모델의 기능을 개선할 수 있다고 생각합니다.
일단 3가지의 간단한 의도 분류 모델을 CNN으로 구현했습니다.
2. 분류 모델 훈련 데이터
분류 모델을 훈련하기 위해서는 각 의도별 클래스로 분류된 데이터가 필요합니다.
1. 사용 데이터 & 텍스트 전처리기 게시글에서 설명한 데이터를 사용해 분류 모델에 사용할 훈련 데이터를 만들었습니다.
코드 참고 : https://github.com/Seokii/Chatbot4Univ/blob/main/models/intent/create_train_data.ipynb
위의 사진과 같이 사용한 텍스트 데이터에 주관적인 기준을 정해 분류 모델 클래스인 0, 1, 2로 텍스트를 분류했습니다.
약 220만 개의 텍스트 데이터 중, 46,000개가량의 텍스트를 분류해 모델을 학습하는 데 사용했습니다.
3. 적절 패딩 길이 구하기
코드 참고 : https://github.com/Seokii/Chatbot4Univ/blob/main/models/intent/create_train_data.ipynb
CNN으로 의도 분류 모델을 학습할 때 사용되는 학습 데이터마다의 텍스트 길이는 다릅니다.
따라서, 토크나이징을 진행하고 길이가 다른 학습 데이터들을 패딩을 통해 동일한 길이로 맞춰주는 작업이 필요합니다. 적절한 패딩 길이를 구하기 위해서 다음과 같은 코드를 구현했습니다.
위와 같은 코드 구현을 통해, 토큰 길이를 25로 설정한다면 전체 데이터의 약 99% 정도 표현할 수 있는 결과를 산출할 수 있었습니다. 25보다 큰 길이의 데이터는 삭제하는 것이 좋지만, 1%의 손실이기 때문에 영향이 미미하다고 판단했으며 삭제하지 않고 진행했습니다.
# /config/GlobalParams.py
# 단어 시퀀스 벡터 크기
MAX_SEQ_LEN = 25
def GlobalParams():
global MAX_SEQ_LEN
25로 정한 패딩 길이를 지정하여 config폴더에 저장했습니다.
4. CNN 구현
의도 분류 모델을 CNN으로 아래와 같이 구현했습니다.
텐서플로우를 사용해 구현했으며, 각각의 하이퍼파라미터는 조정될 수 있는 값입니다.
Conv1D를 사용해 훈련을 진행했고 의도 분류 모델이기 때문에 최종적으로는 softmax를 사용해 3가지의 분류를 할 수 있도록 했습니다. (기타 의도는 추후에 개선할 예정)
3 에포크를 수행하고 모델을 프로젝트 폴더에 저장했습니다.
# Import
import pandas as pd
import tensorflow as tf
from tensorflow.keras import preprocessing
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Embedding, Dense, Dropout, Conv1D, GlobalMaxPool1D, concatenate
from utils.Preprocess import Preprocess
# Load Data
data = pd.read_csv("train_data.csv")
text = data['text'].tolist()
label = data['label'].tolist()
# Load preprocessor
p = Preprocess(word2index_dic='../../train_tools/dict/chatbot_dict.bin',
userdic='../../utils/user_dic.tsv')
# Data preprocess
sequences = []
for sentence in text:
pos = p.pos(sentence)
keywords = p.get_keywords(pos, without_tag=True)
seq = p.get_wordidx_sequence(keywords)
sequences.append(seq)
# set padding length & pad to sequences
from config.GlobalParams import MAX_SEQ_LEN
padded_seqs = preprocessing.sequence.pad_sequences(sequences, maxlen=MAX_SEQ_LEN, padding='post')
# data to tensor
ds = tf.data.Dataset.from_tensor_slices((padded_seqs, label))
ds = ds.shuffle(len(text))
# set train & validation & test size
train_size = int(len(padded_seqs) * 0.7)
val_size = int(len(padded_seqs) * 0.2)
test_size = int(len(padded_seqs) * 0.1)
train_ds = ds.take(train_size).batch(100)
val_ds = ds.take(train_size).take(val_size).batch(100)
test_ds = ds.take(train_size + val_size).take(test_size).batch(100)
# Hyperparameter
dropout_prob = 0.5
EMB_SIZE = 128
EPOCH = 3
VOCAB_SIZE = len(p.word_index) + 1
# CNN model definition
input_layer = Input(shape=(MAX_SEQ_LEN, ))
embedding_layer = Embedding(VOCAB_SIZE, EMB_SIZE, input_length=MAX_SEQ_LEN)(input_layer)
dropout_emb = Dropout(rate=dropout_prob)(embedding_layer)
conv1 = Conv1D(
filters=128,
kernel_size=3,
padding='valid',
activation=tf.nn.relu)(dropout_emb)
pool1 = GlobalMaxPool1D()(conv1)
conv2 = Conv1D(
filters=128,
kernel_size=4,
padding='valid',
activation=tf.nn.relu)(dropout_emb)
pool2 = GlobalMaxPool1D()(conv2)
conv3 = Conv1D(
filters=128,
kernel_size=5,
padding='valid',
activation=tf.nn.relu)(dropout_emb)
pool3 = GlobalMaxPool1D()(conv3)
concat = concatenate([pool1, pool2, pool3])
hidden = Dense(128, activation=tf.nn.relu)(concat)
dropout_hidden = Dropout(rate=dropout_prob)(hidden)
logits = Dense(3, name='logits')(dropout_hidden)
predictions = Dense(3, activation=tf.nn.softmax)(logits)
# CNN model create
model = Model(inputs=input_layer, outputs=predictions)
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# train model
model.fit(train_ds, validation_data=val_ds, epochs=EPOCH, verbose=1)
# evaluate model
loss, accuracy = model.evaluate(test_ds, verbose=1)
print("Accuracy: %f" % (accuracy * 100))
print("loss : %f" % (loss))
# save model
model.save('intent_model.h5')
5. 구현 모델 테스트
구현한 모델을 불러와 테스트하는 코드입니다.
입력한 질문의 의도 분류는 모두 일치했으나, 질문에 따라 다르게 나오기도 함을 확인했습니다.
해당 문제는 챗봇 운영 초기에 사용자의 질문 로그 데이터를 수집하고 모델의 갱신을 통해 해결할 수 있을 것 같습니다. 또한 갱신을 통해 다른 의도 분류를 추가하거나 기타 의도를 추가할 수 있습니다.
# test/model_intent_test.py
from utils.Preprocess import Preprocess
from models.intent.IntentModel import IntentModel
p = Preprocess(word2index_dic='../train_tools/dict/chatbot_dict.bin',
userdic='../utils/user_dic.tsv')
intent = IntentModel(model_name='../models/intent/intent_model.h5', preprocess=p)
query = "컴공 과사 번호 알려줘"
predict = intent.predict_class(query)
predict_label = intent.labels[predict]
print("="*30)
print(query)
print("의도 예측 클래스 : ", predict)
print("의도 예측 레이블 : ", predict_label)
query = "회계팀 전화번호 알려줘."
predict = intent.predict_class(query)
predict_label = intent.labels[predict]
print("="*30)
print(query)
print("의도 예측 클래스 : ", predict)
print("의도 예측 레이블 : ", predict_label)
query = "학교 도서관 번호는??"
predict = intent.predict_class(query)
predict_label = intent.labels[predict]
print("="*30)
print(query)
print("의도 예측 클래스 : ", predict)
print("의도 예측 레이블 : ", predict_label)
query = "본관 건물 위치 어디야?"
predict = intent.predict_class(query)
predict_label = intent.labels[predict]
print("="*30)
print(query)
print("의도 예측 클래스 : ", predict)
print("의도 예측 레이블 : ", predict_label)
query = "학교 운동장은 어디야?"
predict = intent.predict_class(query)
predict_label = intent.labels[predict]
print("="*30)
print(query)
print("의도 예측 클래스 : ", predict)
print("의도 예측 레이블 : ", predict_label)
query = "기간 언제까지야?"
predict = intent.predict_class(query)
predict_label = intent.labels[predict]
print("="*30)
print(query)
print("의도 예측 클래스 : ", predict)
print("의도 예측 레이블 : ", predict_label)
query = "OOO행사 제출 마감 날짜 알려줘"
predict = intent.predict_class(query)
predict_label = intent.labels[predict]
print("="*30)
print(query)
print("의도 예측 클래스 : ", predict)
print("의도 예측 레이블 : ", predict_label)
print("="*30)
'머신러닝 & 딥러닝 > 자연어처리' 카테고리의 다른 글
대학교 AI 질의응답 챗봇 만들기 - 4. 질의응답 데이터 엑셀로 구축 (1) | 2022.07.29 |
---|---|
[NLP] 한국어 자연어 추론(Korean NLI) - KLUE Dataset & ELECTRA (0) | 2022.07.27 |
대학교 AI 질의응답 챗봇 만들기 - 2. 단어 사전 구축 (2) | 2022.07.22 |
대학교 AI 질의응답 챗봇 만들기 - 1. 사용 데이터 & 텍스트 전처리기 (1) | 2022.07.21 |
[NLP] 도서 자료 텍스트 요약(Text Summarization) - TextRank (use gensim) (0) | 2022.06.30 |
댓글