딥러닝(AI학습 50)

이유진·2024년 7월 8일

--31.문장분류, 감정분류.ipynb--

문장분류를 위한 CNN모델

  • CNN 은 이미지 분류 외에도 자연어 분류에도 좋은 성능을 냅니다 (단 임베딩 품질이 좋아야 함.)
  • 이미지 이든, 자연어이든 수치(벡터) 로 표현 가능한 대상이면, 특징을 뽑아내도록 CNN 모델 학습인 가능한겁니다

필요한 모듈 임포트

import pandas as pd
import tensorflow as tf
from tensorflow.keras import preprocessing

CNN 모델 생성용 ↓

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Embedding, Dense, Dropout, Conv1D, GlobalMaxPool1D, concatenate

import os

base_path = r'/content/drive/MyDrive/dataset/chatbot'

data = pd.read_csv(os.path.join(base_path, 'chatbot_data.csv'))
data

  • 위 데이터셋 구조
    • Q (질문),
    • A (답변)
    • label (감정)
      • 0: 일상다반사
      • 1 : 이별(부정)
      • 2 : 사랑(긍정)

data.shape

data.info()

data['label'].unique()

data['label'].value_counts()

features = data['Q'].tolist()
labels = data['label'].tolist()

features[0]

단어 시퀀스 만들기

  • text_to_word_sequence()

preprocessing.text.text_to_word_sequence(features[0])

단어 시퀀스 벡터

corpus = [
preprocessing.text.text_to_word_sequence(text) for text in features
]

corpus

tokenizer = preprocessing.text.Tokenizer()

tokenizer.fit_on_texts(corpus)

corpus # 매개변수가 변한게 아니다.

sequences = tokenizer.texts_to_sequences(corpus)
sequences

corpus[0], sequences[0]

corpus[8], sequences[8]

단어별 시퀀스 번호 확인 가능

word_index = tokenizer.word_index
word_index

len(word_index)

다른 문장으로 테스트

texts_to_sequences()

tokenizer.texts_to_sequences([['여기', '어때'], ['정말', '좋아'], ['온달', '장군']])

패딩

  • pad_sequences()

max([len(words) for words in corpus])

주어진 입력 문장에서 최대 토큰 개수가 15개. 이 길이로 패딩 해보자.

MAX_SEQ_LEN = 15 # 단어 시퀀스 벡터 크기

padded_seqs = preprocessing.sequence.pad_sequences(sequences, maxlen=MAX_SEQ_LEN, padding='post')
padded_seqs

padding옵셥값

'pre' : 앞쪽에 패딩이 붙는다 (디폴트, RNN 등에선 이를 사용)

'post': 뒤쪽에 패딩이 붙는다 (여기선, CNN 을 사용할거다 )

corpus[0], sequences[0], padded_seqs[0]

Dataset 객체 만들기

padded_seqs.shape

len(labels)

ds = tf.data.Dataset.from_tensor_slices((padded_seqs, labels))
ds # Dataset 객체

Dataset 의 첫번째 원소

iter(ds).get_next()

랜덤 섞기

ds = ds.shuffle(len(features))
ds

훈련세트 : 검증세트 : 테스트세트 = 7 : 2 : 1

train_size = int(len(padded_seqs) 0.7)
val_size = int(len(padded_seqs)
0.2)
test_size = int(len(padded_seqs) * 0.1)

len(ds), train_size, val_size, test_size

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).batch(20)

len(train_ds), len(val_ds), len(test_ds)

(414, 119, 60) <--- 데이터의 개수가 아니라 batch의 개수!

모델 생성

  • 감정 클래스 분류 모델

하이퍼 파라미터 설정

dropout_prob = 0.5
EMB_SIZE = 128 # 벡터의 크기
EPOCH = 5
VACAB_SIZE = len(word_index) + 1 # 전체 단어수 + 1

모델 정의

1. 전처리된 입력데이터를 '단어 임베딩'

input_layer = Input(shape=(MAX_SEQ_LEN,))

embedding_layer = Embedding(VACAB_SIZE, EMB_SIZE, input_length=MAX_SEQ_LEN)(input_layer)

dropout_emb = Dropout(rate=dropout_prob)(embedding_layer)

2. 합성곱 필터와 연산을 통해 문장의 특징정보(feature map)을 추출 ... => flatten

Conv1D 를 이용해 크기 3, 4, 5 인 합성곱 필터를 128개씩 사용한 합성곱 계층을 3개 생성

합성곱 연산 과정 : 필터 크기에 맞게 입력 데이터 위를 슬라이딩 하게 되는데 이는 3, 4, 5-gram 언어 모델의 개념과 비슷

입베딩 벡터를 합성곱으로 받아 GlobalMaxPool1D () 를 이용해 최대 max pooling 연산 수행

각각 '병렬'로 진행

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, 5- gram 이후 합쳐서 그 다음 fully connected layer 에 전달될수 있도록 합니다

concatenate () 함수 는 각각 병렬로 처리된 합성곱 계층의 특징맵 결과를 하나로 묶어 줍니다

concat = concatenate([pool1, pool2, pool3])

3. 완전연결층 (fully connected layer) 를 통한 '분류'

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)

모델 생성

model = Model(inputs=input_layer, outputs=predictions)

model.summary()

모델 학습

모델 컴파일

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

학습

model.fit(train_ds, validation_data=val_ds, epochs=EPOCH)

모델 평가

loss, accuracy = model.evaluate(test_ds)
print(loss, accuracy)

모델 저장

model.save(os.path.join(base_path, 'out', 'cnn_model.h5'))

감정분류 모델 사용

모델 불러오기

model = None
model = tf.keras.models.load_model(os.path.join(base_path, 'out', 'cnn_model.h5'))
model.summary()

모델 사용을 위한 테스트 데이터 생성

ds = tf.data.Dataset.from_tensor_slices((padded_seqs, labels))
ds = ds.shuffle(len(features))
test_ds = ds.take(2000).batch(20)

print(corpus[10212])
print(padded_seqs[10212])
print(labels[10212])

picks = [10212]

predict = model.predict(padded_seqs[picks])
tf.math.argmax(predict, axis=1)

loss, accuracy = model.evaluate(test_ds)

print(loss, accuracy)

profile
독해지자

0개의 댓글