일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 백준
- Docker
- 금융문자분석경진대회
- 코로나19
- 자연어처리
- 프로그래머스 파이썬
- 편스토랑 우승상품
- PYTHON
- gs25
- 우분투
- Baekjoon
- ChatGPT
- AI 경진대회
- 더현대서울 맛집
- Kaggle
- dacon
- Real or Not? NLP with Disaster Tweets
- 편스토랑
- hackerrank
- 캐치카페
- 프로그래머스
- leetcode
- programmers
- ubuntu
- 데이콘
- 맥북
- SW Expert Academy
- 파이썬
- github
- Git
- Today
- Total
솜씨좋은장씨
[DACON] 소설 작가 분류 AI 경진대회 4일차! 본문
소설 작가 분류 AI 경진대회 4일차!
오늘은 먼저 DACON 에서 제공해주는 베이스라인을 먼저 시도해보았습니다.
개발은 NIPA에서 지원받은 GPU 서버환경에서 진행하였습니다.
import pandas as pd
import warnings
warnings.filterwarnings(action='ignore')
import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.preprocessing.text import Tokenizer
import re
먼저 필요한 라이브러리를 import 합니다.
#파일 불러오기
train = pd.read_csv('train.csv', encoding = 'utf-8')
test = pd.read_csv('test_x.csv', encoding = 'utf-8')
sample_submission = pd.read_csv('sample_submission.csv', encoding = 'utf-8')
데이터를 불러옵니다.
#부호를 제거해주는 함수
def alpha_num(text):
return re.sub(r'[^A-Za-z0-9 ]', '', text)
정규식을 활용하여 영어 대문자, 소문자, 숫자만 남기고 나머지 데이터는 삭제합니다.
# 불용어 제거해주는 함수
def remove_stopwords(text):
final_text = []
for i in text.split():
if i.strip().lower() not in stopwords:
final_text.append(i.strip())
return " ".join(final_text)
# 불용어
stopwords = [ "a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", "as",
"at", "be", "because", "been", "before", "being", "below", "between", "both", "but", "by", "could",
"did", "do", "does", "doing", "down", "during", "each", "few", "for", "from", "further", "had", "has",
"have", "having", "he", "he'd", "he'll", "he's", "her", "here", "here's", "hers", "herself", "him", "himself",
"his", "how", "how's", "i", "i'd", "i'll", "i'm", "i've", "if", "in", "into", "is", "it", "it's", "its", "itself",
"let's", "me", "more", "most", "my", "myself", "nor", "of", "on", "once", "only", "or", "other", "ought", "our", "ours",
"ourselves", "out", "over", "own", "same", "she", "she'd", "she'll", "she's", "should", "so", "some", "such", "than", "that",
"that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll",
"they're", "they've", "this", "those", "through", "to", "too", "under", "until", "up", "very", "was", "we", "we'd", "we'll",
"we're", "we've", "were", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "who's", "whom",
"why", "why's", "with", "would", "you", "you'd", "you'll", "you're", "you've", "your", "yours", "yourself", "yourselves" ]
불용어를 정의하고 불용어 처리를 실시하는 함수를 만들어줍니다.
#전처리 적용
train['text'] = train['text'].str.lower()
test['text'] = test['text'].str.lower()
train['text'] = train['text'].apply(alpha_num).apply(remove_stopwords)
test['text'] = test['text'].apply(alpha_num).apply(remove_stopwords)
만든 함수들을 바탕으로 전처리를 진행합니다.
X_train = np.array([x for x in train['text']])
X_test = np.array([x for x in test['text']])
y_train = np.array([x for x in train['author']])
학습데이터와 테스트데이터, 각 데이터의 정답에 해당하는 값을 numpy의 array로 변환해줍니다.
#파라미터 설정
vocab_size = 20000
embedding_dim = 16
max_length = 500
padding_type='post'
#oov_tok = "<OOV>"
모델링 시 활용할 파라미터를 선언해줍니다.
여기서 embedding_dim에 16이 적힌 이유는 embedding layer 다음에 오는 GlobalAveragePooling1D 레이어의 입력이
16차원의 입력값을 받기 때문입니다.
#tokenizer에 fit
tokenizer = Tokenizer(num_words = vocab_size)#, oov_token=oov_tok)
tokenizer.fit_on_texts(X_train)
word_index = tokenizer.word_index
#데이터를 sequence로 변환해주고 padding 해줍니다.
train_sequences = tokenizer.texts_to_sequences(X_train)
train_padded = pad_sequences(train_sequences, padding=padding_type, maxlen=max_length)
test_sequences = tokenizer.texts_to_sequences(X_test)
test_padded = pad_sequences(test_sequences, padding=padding_type, maxlen=max_length)
데이터를 sequence로 변환하고 모든 길이를 500으로 동일하게 맞추어 줍니다.
#가벼운 NLP모델 생성
model = tf.keras.Sequential([
tf.keras.layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
tf.keras.layers.GlobalAveragePooling1D(),
tf.keras.layers.Dense(24, activation='relu'),
tf.keras.layers.Dense(5, activation='softmax')
])
Embedding레이어, GlobalAveragePooling1D 레이어, Dense 레이어를 활용하여 모델을 만들어줍니다.
# compile model
model.compile(loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
# model summary
print(model.summary())
y_train 값을 원핫인코딩하지 않고 활용하므로 loss는 sparse_categorical_crossentropy를 활용합니다.
optimizer는 항상 가장 무난했던 adam을 활용합니다.
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_1 (Embedding) (None, 500, 16) 320000
_________________________________________________________________
global_average_pooling1d_1 ( (None, 16) 0
_________________________________________________________________
dense_2 (Dense) (None, 24) 408
_________________________________________________________________
dense_3 (Dense) (None, 5) 125
=================================================================
Total params: 320,533
Trainable params: 320,533
Non-trainable params: 0
_________________________________________________________________
None
# fit model
num_epochs = 20
history = model.fit(train_padded, y_train,
epochs=num_epochs, verbose=2,
validation_split=0.2)
20번의 epoch 만큼 학습을 진행하고 validation data의 비율은 학습데이터의 20%로 설정합니다.
( 학습데이터가 100개일 경우 20개가 validation data )
Train on 43903 samples, validate on 10976 samples
Epoch 1/20
43903/43903 - 11s - loss: 1.5676 - accuracy: 0.2769 - val_loss: 1.5593 - val_accuracy: 0.2692
Epoch 2/20
43903/43903 - 8s - loss: 1.4574 - accuracy: 0.3836 - val_loss: 1.3442 - val_accuracy: 0.4677
...
Epoch 19/20
43903/43903 - 7s - loss: 0.5305 - accuracy: 0.8091 - val_loss: 0.7929 - val_accuracy: 0.7157
Epoch 20/20
43903/43903 - 7s - loss: 0.5109 - accuracy: 0.8170 - val_loss: 0.7935 - val_accuracy: 0.7158
그동안 보았던 학습양상과는 확실히 다른 모습을 보였습니다.
import matplotlib.pyplot as plt
def draw_history(history):
fig, loss_ax = plt.subplots()
acc_ax = loss_ax.twinx()
loss_ax.plot(history.history['loss'], 'y', label='train loss')
loss_ax.plot(history.history['val_loss'], 'r', label='val loss')
loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
loss_ax.legend(loc='upper left')
acc_ax.plot(history.history['accuracy'], 'b', label='train acc')
acc_ax.plot(history.history['val_accuracy'], 'g', label='val acc')
acc_ax.set_ylabel('accuracy')
acc_ax.legend(loc='bottom left')
plt.show()
결과 도출
# predict values
pred = model.predict_proba(test_padded)
sample_submission[['0','1','2','3','4']] = pred
sample_submission.to_csv('submission_10.csv', index = False, encoding = 'utf-8')
DACON 제출 결과
결과는 0.5730682471!
현재까지의 기록중에 최고의 기록이었습니다.
이 모델에 Dropout Layer를 추가하여 학습시키면 어떨까 한번 시도해보았습니다.
전처리 과정은 동일하고
# Dropout Layer 추가
model2 = tf.keras.Sequential([
tf.keras.layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
tf.keras.layers.GlobalAveragePooling1D(),
tf.keras.layers.Dense(24, activation='relu'),
tf.keras.layers.Dropout(0.1),
tf.keras.layers.Dense(5, activation='softmax')
])
# compile model
model2.compile(loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
# model summary
print(model2.summary())
Model: "sequential_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_2 (Embedding) (None, 500, 16) 320000
_________________________________________________________________
global_average_pooling1d_2 ( (None, 16) 0
_________________________________________________________________
dense_4 (Dense) (None, 24) 408
_________________________________________________________________
dropout (Dropout) (None, 24) 0
_________________________________________________________________
dense_5 (Dense) (None, 5) 125
=================================================================
Total params: 320,533
Trainable params: 320,533
Non-trainable params: 0
_________________________________________________________________
None
# fit model
num_epochs = 20
history2 = model2.fit(train_padded, y_train,
epochs=num_epochs,
validation_split=0.2)
Train on 43903 samples, validate on 10976 samples
Epoch 1/20
43903/43903 [==============================] - 7s 151us/sample - loss: 1.5697 - accuracy: 0.2712 - val_loss: 1.5618 - val_accuracy: 0.2680
Epoch 2/20
43903/43903 [==============================] - 6s 148us/sample - loss: 1.5112 - accuracy: 0.3136 - val_loss: 1.4021 - val_accuracy: 0.4055
...
Epoch 19/20
43903/43903 [==============================] - 7s 162us/sample - loss: 0.4773 - accuracy: 0.8299 - val_loss: 0.8171 - val_accuracy: 0.7103
Epoch 20/20
43903/43903 [==============================] - 7s 162us/sample - loss: 0.4605 - accuracy: 0.8341 - val_loss: 0.7706 - val_accuracy: 0.7271
결과 도출
# predict values
pred = model2.predict_proba(test_padded)
sample_submission[['0','1','2','3','4']] = pred
sample_submission.to_csv('submission_11.csv', index = False, encoding = 'utf-8')
DACON 제출 결과
이전 제출결과 보다 더 나은 0.5536510687 이 나왔습니다.
이번엔 여기서 batch size 만 32 에서 128으로 변경해보았습니다.
model7 = tf.keras.Sequential([
tf.keras.layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
tf.keras.layers.GlobalAveragePooling1D(),
tf.keras.layers.Dense(24, activation='relu'),
tf.keras.layers.Dropout(0.1),
tf.keras.layers.Dense(5, activation='softmax')
])
# compile model
model7.compile(loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
# model summary
print(model7.summary())
Model: "sequential_9"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_9 (Embedding) (None, 500, 16) 320000
_________________________________________________________________
global_average_pooling1d_9 ( (None, 16) 0
_________________________________________________________________
dense_18 (Dense) (None, 24) 408
_________________________________________________________________
dropout_7 (Dropout) (None, 24) 0
_________________________________________________________________
dense_19 (Dense) (None, 5) 125
=================================================================
Total params: 320,533
Trainable params: 320,533
Non-trainable params: 0
_________________________________________________________________
None
# fit model
num_epochs = 20
history7 = model7.fit(train_padded, y_train,
epochs=num_epochs, batch_size=128,
validation_split=0.2)
Train on 43903 samples, validate on 10976 samples
Epoch 1/20
43903/43903 [==============================] - 4s 82us/sample - loss: 1.5723 - accuracy: 0.2749 - val_loss: 1.5672 - val_accuracy: 0.2680
Epoch 2/20
43903/43903 [==============================] - 3s 72us/sample - loss: 1.5602 - accuracy: 0.2766 - val_loss: 1.5492 - val_accuracy: 0.2680
...
Epoch 19/20
43903/43903 [==============================] - 3s 73us/sample - loss: 0.6662 - accuracy: 0.7593 - val_loss: 0.7939 - val_accuracy: 0.7077
Epoch 20/20
43903/43903 [==============================] - 3s 73us/sample - loss: 0.6419 - accuracy: 0.7672 - val_loss: 0.7781 - val_accuracy: 0.7111
결과 도출
# predict values
pred = model7.predict_proba(test_padded)
sample_submission[['0','1','2','3','4']] = pred
sample_submission.to_csv('submission_12.csv', index = False, encoding = 'utf-8')
DACON 제출 결과
batch_size를 늘려보니 기존 보다 나은 0.5275360364의 점수를 얻을 수 있었습니다.
오늘은 데이콘에서 제공해준 BaseLine 코드를 바탕으로 한번 시도해보았습니다.
모델을 바꾸고 전처리 방식을 바꾸니 점수가 많이 달라졌습니다.
내일부터는 또 여러 가지 시도를 해보면서 좋은 성능을 내기 위해 노력해보고자 합니다.
읽어주셔서 감사합니다.
'DACON > 소설 작가 분류 AI 경진대회' 카테고리의 다른 글
[DACON] 소설 작가 분류 AI 경진대회 N일차! (0) | 2020.11.05 |
---|---|
[DACON] 소설 작가 분류 AI 경진대회 6일차! (0) | 2020.11.04 |
[DACON] 소설 작가 분류 AI 경진대회 5일차! (0) | 2020.11.03 |
[DACON] 소설 작가 분류 AI 경진대회 1, 2, 3일차! (0) | 2020.11.01 |
[DACON] 소설 작가 분류 AI 경진대회 도전! (0) | 2020.10.31 |