본문 바로가기
정리/텐서플로와 머신러닝으로 시작하는 자연어처리

Chap04. 한글 텍스트 분류_모델링 2

by 스꼬맹이브로 2021. 8. 3.
728x90
반응형
SMALL

이번 포스팅은 이전에 전처리한 한글 데이터 파일을 활용해 감정 분석 모델링을 해볼 것이다.

모델은 합성곱 신경망(CNN)을 활용하여 구현할 예정이다.

 

먼저 모델링 과정에 필요한 라이브러리와 데이터를 불러오자.

import os
from datetime import datetime
import tensorflow as tf
import numpy as np
import json
from sklearn.model_selection import train_test_split

DATA_IN_PATH = './data_in/'
DATA_OUT_PATH = './data_out/'
INPUT_TRAIN_DATA = 'nsmc_train_input.npy'
LABEL_TRAIN_DATA = 'nsmc_train_label.npy'
DATA_CONFIGS = 'data_configs.json'

input_data = np.load(open(DATA_IN_PATH + INPUT_TRAIN_DATA, 'rb'))
label_data = np.load(open(DATA_IN_PATH + LABEL_TRAIN_DATA, 'rb'))
prepro_configs = json.load(open(DATA_IN_PATH + DATA_CONFIGS, 'r'))

다음으로 불러온 데이터를 학습데이터와 검증데이터로 분리하자.

TEST_SPLIT = 0.1
RNG_SEED = 13371447

input_train, input_eval, label_train, label_eval = train_test_split(input_data, label_data, test_size=TEST_SPLIT, random_state=RNG_SEED)

여기서는 학습데이터와 검증데이터를 9:1로 분리한다.

이제 데이터를 입력하기 위한 데이터 입력 함수를 만들어보자.

def mapping_fn(X, Y):
    input, label = {'x': X}, Y
    return input, label

def train_input_fn():
    dataset = tf.data.Dataset.from_tensor_slices((input_train, label_train))
    dataset = dataset.shuffle(buffer_size=len(input_train))
    dataset = dataset.batch(BATCH_SIZE)
    dataset = dataset.map(mapping_fn)
    dataset = dataset.repeat(count=NUM_EPOCHS)
    iterator = dataset.make_one_shot_iterator()
    
    return iterator.get_next()

def eval_input_fn():
    dataset = tf.data.Dataset.from_tensor_slices((input_eval, label_eval))
    dataset = dataset.shuffle(buffer_size=len(input_eval))
    dataset = dataset.batch(16)
    dataset = dataset.map(mapping_fn)
    iterator = dataset.make_one_shot_iterator()
    
    return iterator.get_next()

에스티메이터에 데이터를 적용하기 위해 입력 함수를 정의하였다.

함수는 학습 함수와 검증 함수를 따로 만들며 tf.data를 활용하여 처리한다.

이렇게 모델을 제외한 모든 준비가 끝났다.

이제 모델을 구현해보자.

def model_fn(features, labels, mode, params):
    TRAIN = mode == tf.estimator.ModeKeys.TRAIN
    EVAL = mode == tf.estimator.ModeKeys.EVAL
    PREDICT = mode == tf.estimator.ModeKeys.PREDICT

    embedding_layer = tf.keras.layers.Embedding(
                    VOCAB_SIZE,
                    EMB_SIZE)(features['x'])

    dropout_emb = tf.keras.layers.Dropout(rate = 0.2)(embedding_layer)
    
    conv = tf.keras.layers.Conv1D(
           filters=32,
           kernel_size=3,
           padding='same',
           activation=tf.nn.relu)(dropout_emb)
  
    pool = tf.keras.layers.GlobalMaxPool1D()(conv)

    hidden = tf.keras.layers.Dense(units=250, activation=tf.nn.relu)(pool)   


    dropout_hidden = tf.keras.layers.Dropout(rate=0.2)(hidden, training = TRAIN)
    logits = tf.keras.layers.Dense(units=1)(dropout_hidden)

    if labels is not None:
        labels = tf.reshape(labels, [-1, 1])
        
    if TRAIN:
        global_step = tf.train.get_global_step()
        loss = tf.losses.sigmoid_cross_entropy(labels, logits)
        train_op = tf.train.AdamOptimizer(0.001).minimize(loss, global_step)

        return tf.estimator.EstimatorSpec(mode=mode, train_op=train_op, loss = loss)
    
    elif EVAL:
        loss = tf.losses.sigmoid_cross_entropy(labels, logits)
        pred = tf.nn.sigmoid(logits)
        accuracy = tf.metrics.accuracy(labels, tf.round(pred))
        return tf.estimator.EstimatorSpec(mode=mode, loss=loss, eval_metric_ops={'acc': accuracy})
        
    elif PREDICT:
        return tf.estimator.EstimatorSpec(
            mode=mode,
            predictions={
                'prob': tf.nn.sigmoid(logits),
            }
        )

모델 함수는 이전 영어 텍스트 분류를 위한 합성곱 신경망 모델과 크게 다르지 않다.

이제 모델을 실제로 학습하기 위해 마지막으로 필요한 하이퍼파라미터 값을 설정한다.

NUM_EPOCHS = 10
BATCH_SIZE = 16
VOCAB_SIZE = prepro_configs['vocab_size']+1
EMB_SIZE = 128

에폭 수는 10으로 전체 데이터를 10번 돌도록 지정하였다.

그리고 단어 사전의 크기는 데이터 정보가 담겨있는 딕셔너리에서 받아오고, 임베딩 크기는 128로 설정하였다.

이제 모델 학습을 실행해보자.

먼저 에스티메이터 객체를 정의한 후 학습을 진행한다.

est = tf.estimator.Estimator(model_fn, model_dir="data_out/checkpoint/cnn_model")

 

 

이제 생성한 객체의 train함수를 호출해서 학습힌다.

time_start = datetime.utcnow()
print("Experiment started at {}".format(time_start.strftime("%H:%M:%S")))
print(".......................................") 

est.train(train_input_fn)

time_end = datetime.utcnow()
print(".......................................")
print("Experiment finished at {}".format(time_end.strftime("%H:%M:%S")))
print("")
time_elapsed = time_end - time_start
print("Experiment elapsed time: {} seconds".format(time_elapsed.total_seconds()))

이때 학습에 경과된 시간을 확인하기 위해 학습 시작 전과 후에 각각 시간을 출력하도록 하였다.

학습이 모두 끝나면 다음과 같은 결과가 출력된다.

다음으로 검증 데이터를 이용해 모델을 평가해보자.

valid = est.evaluate(eval_input_fn)

결과 :

이 값을 참고하면서 하이퍼파라미터 값, 전처리 방법, 모델 등을 수정하면 된다.

또한 검증 데이터에 대해 만족한 결과가 나오면 평가를 진행한다.

 

평가 과정은 먼저 평가 데이터를 불러온 후 평가 입력 함수를 정의한다.

INPUT_TEST_DATA = 'nsmc_test_input.npy'
LABEL_TEST_DATA = 'nsmc_test_label.npy'

test_input_data = np.load(open(DATA_IN_PATH + INPUT_TEST_DATA, 'rb'))
test_label_data = np.load(open(DATA_IN_PATH + LABEL_TEST_DATA, 'rb'))

def test_input_fn():
    dataset = tf.data.Dataset.from_tensor_slices((test_input_data, test_label_data))
    dataset = dataset.batch(16)
    dataset = dataset.map(mapping_fn)
    iterator = dataset.make_one_shot_iterator()
    
    return iterator.get_next()

평가 입력 함수에서는 검증 함수에서 반복과 셔플을 수행하는 부분만 제거하였다.

이제 검증 과정과 동일하게 진행해보자.

predict = est.evaluate(test_input_fn)

결과 : 

결과를 보면 80.394%가 나온 것을 확인할 수 있다.

 

다음 포스팅에서는 텍스트 유사도 문제에 대해 알아보고 실제로 사용해보겠다.

 

728x90
반응형
LIST