<jupyter_start><jupyter_text>모듈 불러오기<jupyter_code>import tensorflow as tf
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from tensorflow.keras import layers

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt

import os
import json

from tqdm import tqdm<jupyter_output><empty_output><jupyter_text>시각화 함수<jupyter_code>def plot_graphs(history, string):
    plt.plot(history.history[string])
    plt.plot(history.history['val_'+string], '')
    plt.xlabel("Epochs")
    plt.ylabel(string)
    plt.legend([string, 'val_'+string])
    plt.show()<jupyter_output><empty_output><jupyter_text>학습 데이터 경로 정의<jupyter_code>DATA_IN_PATH = './data_in/'
DATA_OUT_PATH = './data_out/'
TRAIN_INPUT_DATA = 'train_input.npy'
TRAIN_LABEL_DATA = 'train_label.npy'
DATA_CONFIGS = 'data_configs.json'<jupyter_output><empty_output><jupyter_text>랜덤 시드 고정<jupyter_code>SEED_NUM = 1234
tf.random.set_seed(SEED_NUM)<jupyter_output><empty_output><jupyter_text>파일 로드<jupyter_code>train_input = np.load(open(DATA_IN_PATH + TRAIN_INPUT_DATA, 'rb'))
train_label = np.load(open(DATA_IN_PATH + TRAIN_LABEL_DATA, 'rb'))
prepro_configs = prepro_configs = json.load(open(DATA_IN_PATH + DATA_CONFIGS, 'r'))<jupyter_output><empty_output><jupyter_text>모델 하이퍼파라메터 정의<jupyter_code>model_name = 'cnn_classifier_en'
BATCH_SIZE = 512
NUM_EPOCHS = 2
VALID_SPLIT = 0.1
MAX_LEN = train_input.shape[1]

kargs = {'model_name': model_name,
        'vocab_size': prepro_configs['vocab_size'],
        'embedding_size': 128,
        'num_filters': 100,
        'dropout_rate': 0.5,
        'hidden_dimension': 250,
        'output_dimension':1}<jupyter_output><empty_output><jupyter_text>모델 선언 및 컴파일<jupyter_code>class CNNClassifier(tf.keras.Model):
    
    def __init__(self, **kargs):
        super(CNNClassifier, self).__init__(name=kargs['model_name'])
        self.embedding = layers.Embedding(input_dim=kargs['vocab_size'],
                                     output_dim=kargs['embedding_size'])
        self.conv_list = [layers.Conv1D(filters=kargs['num_filters'],
                                   kernel_size=kernel_size,
                                   padding='valid',
                                   activation=tf.keras.activations.relu,
                                   kernel_constraint=tf.keras.constraints.MaxNorm(max_value=3.))
                     for kernel_size in [3,4,5]]
        self.pooling = layers.GlobalMaxPooling1D()
        self.dropout = layers.Dropout(kargs['dropout_rate'])
        self.fc1 = layers.Dense(units=kargs['hidden_dimension'],
                           activation=tf.keras.activations.relu,
                           kernel_constraint=tf.keras.constraints.MaxNorm(max_value=3.))
        self.fc2 = layers.Dense(units=kargs['output_dimension'],
                           activation=tf.keras.activations.sigmoid,
                           kernel_constraint=tf.keras.constraints.MaxNorm(max_value=3.))
    
    def call(self, x):
        x = self.embedding(x)
        x = self.dropout(x)
        x = tf.concat([self.pooling(conv(x)) for conv in self.conv_list], axis=-1)
        x = self.fc1(x)
        x = self.fc2(x)
        
        return x
model = CNNClassifier(**kargs)
model.compile(optimizer=tf.keras.optimizers.Adam(),
              loss=tf.keras.losses.BinaryCrossentropy(),
              metrics=[tf.keras.metrics.BinaryAccuracy(name='accuracy')])<jupyter_output><empty_output><jupyter_text>Callback 선언<jupyter_code># overfitting을 막기 위한 ealrystop 추가
earlystop_callback = EarlyStopping(monitor='val_accuracy', min_delta=0.0001,patience=2)
# min_delta: the threshold that triggers the termination (acc should at least improve 0.0001)
# patience: no improvment epochs (patience = 1, 1번 이상 상승이 없으면 종료)\

checkpoint_path = DATA_OUT_PATH + model_name + '/weights.h5'
checkpoint_dir = os.path.dirname(checkpoint_path)

# Create path if exists
if os.path.exists(checkpoint_dir):
    print("{} -- Folder already exists \n".format(checkpoint_dir))
else:
    os.makedirs(checkpoint_dir, exist_ok=True)
    print("{} -- Folder create complete \n".format(checkpoint_dir))
    

cp_callback = ModelCheckpoint(
    checkpoint_path, monitor='val_accuracy', verbose=1, save_best_only=True, save_weights_only=True)<jupyter_output>./data_out/cnn_classifier_en -- Folder already exists<jupyter_text>모델 학습<jupyter_code>history = model.fit(train_input, train_label, batch_size=BATCH_SIZE, epochs=NUM_EPOCHS,
                    validation_split=VALID_SPLIT, callbacks=[earlystop_callback, cp_callback])<jupyter_output>Epoch 1/2
44/44 [==============================] - ETA: 0s - loss: 0.6709 - accuracy: 0.5958
Epoch 00001: val_accuracy improved from -inf to 0.77560, saving model to ./data_out/cnn_classifier_en\weights.h5
44/44 [==============================] - 4s 84ms/step - loss: 0.6709 - accuracy: 0.5958 - val_loss: 0.5596 - val_accuracy: 0.7756
Epoch 2/2
44/44 [==============================] - ETA: 0s - loss: 0.3790 - accuracy: 0.8400
Epoch 00002: val_accuracy improved from 0.77560 to 0.87760, saving model to ./data_out/cnn_classifier_en\weights.h5
44/44 [==============================] - 3s 76ms/step - loss: 0.3790 - accuracy: 0.8400 - val_loss: 0.3092 - val_accuracy: 0.8776<jupyter_text>결과 플롯<jupyter_code>plot_graphs(history, 'accuracy')
plot_graphs(history, 'loss')<jupyter_output><empty_output><jupyter_text>테스트 데이터 불러오기<jupyter_code>DATA_OUT_PATH = './data_out/'
TEST_INPUT_DATA = 'test_input.npy'
TEST_ID_DATA = 'test_id.npy'

test_input = np.load(open(DATA_IN_PATH + TEST_INPUT_DATA, 'rb'))
test_input = pad_sequences(test_input, maxlen=test_input.shape[1])<jupyter_output><empty_output><jupyter_text>베스트 모델 불러오기<jupyter_code>SAVE_FILE_NM = 'weights.h5'

model.load_weights(os.path.join(DATA_OUT_PATH, model_name, SAVE_FILE_NM))<jupyter_output><empty_output><jupyter_text>테스트 데이터 예측하기<jupyter_code>predictions = model.predict(test_input, batch_size=BATCH_SIZE)
predictions = predictions.squeeze(-1)
test_id = np.load(open(DATA_IN_PATH + TEST_ID_DATA, 'rb'), allow_pickle=True)

if not os.path.exists(DATA_OUT_PATH):
    os.makedirs(DATA_OUT_PATH)

output = pd.DataFrame(data={"id": list(test_id), "sentiment": list(predictions)} )
output.to_csv(DATA_OUT_PATH + 'movie_review_result_cnn.csv', index=False, quoting=3)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13796892167634595, 'fraction_numerical': 0.027154292889656255, 'mean_word_length': 4.296758104738155, 'pattern_counts': {'":': 2, '<': 51, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '108559', 'license': 'Apache-2.0', 'n_tokens_mistral': 2505, 'n_tokens_neox': 2458, 'n_words': 348, 'path': '3.TEXT_CLASSIFICATION/3.1.7.CNN_Classification.ipynb', 'repo_name': 'semi-zero/NLP_study', 'size': '6371'}