CNN 모델
파이참으로 챗봇 만들기 실습하던 파일에서 데이터 부분만 바꿔넣어서 돌려봄. 아마 단어사전이 안맞거나 문제가 있을수도 있을 듯?
# 의도분류모델 학습
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 tensorflow.keras import datasets, layers, models
from chatbot.Preprocess2 import Preprocess2
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
try:
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
except RuntimeError as e:
print(e)
# 데이터 읽어오기
train_file = "../data/TrainingData.xlsx"
data = pd.read_excel(train_file)
queries = data['data'].tolist()
mapping = {'기쁨':0, '분노':1, '상처':2, '슬픔':3, '불안':4, '당황':5}
data['emotion'] = data['label'].map(mapping)
intents = data['emotion'].tolist()
p = Preprocess2(word2index_dic='../data/chatbot_dict.bin',
userdic='../data/user_dic.tsv')
# 단어 시퀀스 생성
sequences = []
for sentence in queries:
pos = p.pos(sentence)
keywords = p.get_keywords(pos, without_tag=True)
seq = p.get_wordidx_sequence(keywords)
sequences.append(seq)
# 단어 인덱스 시퀀스 벡터
# 단어 시퀀스 벡터 크기
from chatbot.GlobalParams import MAX_SEQ_LEN
padded_seqs = preprocessing.sequence.pad_sequences(sequences,
maxlen=MAX_SEQ_LEN,
padding='post')
# (105658, 15)
print(padded_seqs.shape)
print(len(intents)) # 105658
# 학습용, 검증용, 테스트용 데이터셋 생성
# 학습셋:검증셋:테스트셋 = 7:2:1
ds = tf.data.Dataset.from_tensor_slices((padded_seqs,intents))
ds = ds.shuffle(len(queries))
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(20)
val_ds = ds.skip(train_size).take(val_size).batch(20)
test_ds = ds.skip(train_size + val_size).take(test_size).batch(20)
# 하이퍼 파라미터 설정
dropout_prob = 0.2
EMB_SIZE = 100
EPOCH = 5
VOCAB_SIZE = len(p.word_index) + 1 # 전체 단어 개수
# CNN 모델 정의
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)
# 3,4,5gram 이후 합치기
#concat = concatenate([pool1, pool2, pool3])
concat = concatenate([pool1, pool2])
hidden = Dense(128, activation=tf.nn.relu)(concat)
dropout_hidden = Dropout(rate=dropout_prob)(hidden)
logits = Dense(5, name='logits')(dropout_hidden)
predictions = Dense(5, activation=tf.nn.softmax)(logits)
# 모델 생성
model = Model(inputs=input_layer, outputs=predictions)
#model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# 모델 학습
with tf.device('/GPU:0'):
model.fit(train_ds, validation_data=val_ds,
epochs=EPOCH, verbose=1)
# 모델 평가(테스트 데이터 셋 이용)
with tf.device('/GPU:0'):
loss, accuracy = model.evaluate(test_ds, verbose=1)
print('Accuracy: %f' % (accuracy * 100))
print('loss: %f' % (loss))
# 모델 저장
model.save('intent_model.h5')
print('완료되었습니다.')
어쨌든 이렇게 해서 오류는 없이 돌아가지만,, 정확도 점수가 0.11xxx가 나와서 사용할 수 없는 모델이 만들어짐.
test 돌려보니 어떤 문장을 넣든 무조건 '기쁨'으로만 판별해서,, 쓸 수가 없음.
RNN, LSTM 모델
이건 vscode로 의도분류모델만 따로 만들어봄.
import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import re
import urllib.request
from konlpy.tag import Okt
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from collections import Counter
from sklearn.model_selection import train_test_split
data = pd.read_excel('data/TrainingData.xlsx')

# 감정 -> 숫자로 변경
mapping = {'기쁨':0, '분노':1, '상처':2, '슬픔':3, '불안':4, '당황':5}
data['label'] = data['label'].map(mapping)
X=data[['data']] #독립변수
y=data['label'] #종속변수
#언더샘플링
from imblearn.under_sampling import RandomUnderSampler
X_sample, y_sample = RandomUnderSampler(random_state=0).fit_resample(X, y)
X_samp = pd.DataFrame(data=X_sample,columns=['data'] )
y_samp = pd.DataFrame(data=y_sample,columns=['label'])
df_samp=pd.concat([X_samp,y_samp],axis=1)
print(df_samp['label'].value_counts())
df_samp['label'].value_counts().plot(kind='bar')
X = df_samp['data']
y = df_samp['label']
# 한글만 남기기
X = X.str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣 ]","")
X = X.str.replace('^ +', "")
X.replace('', np.nan, inplace = True)
# 불용어 사전
stopwords = ['도', '는', '다', '의', '가', '이', '은', '한',
'에', '하', '고', '을', '를', '인', '듯', '과', '와',
'네', '들', '듯', '지', '임', '게']
#형태소 분석, 불용어 제거
from konlpy.tag import Okt
okt = Okt()
X_token = []
for sentence in X:
temp_X = okt.morphs(sentence, stem=True) # 토큰화
temp_X = [word for word in temp_X if not word in stopwords] # 불용어 제거
X_token.append(temp_X)
# 정수 인코딩
#단어 집합을 만들고 단어에 고유한 숫자 인덱스를 부여
from keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer()
tokenizer.fit_on_texts(X_token)
#텍스트를 시퀀스로 변환(단어의 인덱스로만 구성된 새로운 리스트)
sequences = tokenizer.texts_to_sequences(X_token)
print(sequences[:5])
# 데이터 나눔
X_train, X_test, y_train, y_test = train_test_split(sequences, y, test_size=0.2, random_state=0)
#문장 길이 확인
print('문장의 최대 길이 :',max(len(l) for l in X_train))
print('문장의 평균 길이 :',sum(map(len, X_train))/len(X_train))
plt.hist([len(s) for s in X_train], bins=50)
plt.xlabel('length of samples')
plt.ylabel('number of samples')
plt.show()
def below_threshold_len(max_len, nested_list):
cnt = 0
for s in nested_list:
if(len(s) <= max_len):
cnt = cnt + 1
print('전체 샘플 중 길이가 %s 이하인 샘플의 비율: %s'%(max_len, (cnt/len(nested_list))*100))
max_len = 39
below_threshold_len(max_len, X_train)
#패딩
X_train2 = pad_sequences(X_train, maxlen = max_len)
X_test2 = pad_sequences(X_test, maxlen = max_len)
from keras import models
from tensorflow.keras.layers import Embedding, Dense, LSTM, Flatten, GRU, Dropout, SimpleRNN, TimeDistributed
from tensorflow.keras.models import Sequential
from tensorflow.keras.models import load_model
from tensorflow.keras.callbacks import EarlyStopping,ModelCheckpoint
model2 = Sequential()
# model2.add(Embedding(vocab_size, 100, input_length =max_len))
model2.add(Embedding(39, 50, input_length=max_len))
# model2.add(SimpleRNN(32, return_sequences=True))
# model2.add(TimeDistributed(Dense(32)))
model2.add(LSTM(16))
model2.add(Dense(1, activation='softmax'))
model2.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
model2.summary()
중간 단계층을 이리저리 바꿔봐도 점수가 0.18을 넘기질 못함. 마찬가지로 못 쓸 것 같음.