-
[자연어처리] Text-CNN 구현하기 (코드 위주)자연어처리 공부 2024. 1. 2. 12:43
▶︎ CNN(Convolutional Neural Network) 이란?
→ 이름에서 알 수 있듯이 합성곱(새로운 연산)을 활용한 신경망 딥러닝 모델입니다.
→ 필터가 상하좌우 이동하면서 데이터와 convolution을 하여 특징을 추출합니다. 일반적인 Dense layer보다 적은 수의 파라미터θ로 데이터의 주요 특징을 찾아낼 수 있습니다.
→ 필터를 이동시키면서 서로 다른 데이터의 특성을 추출하기 때문에 공간적(지역적, 위치적, 계층적) 패턴을 가지고 있는 이미지, 신호 데이터에 적합합니다.
▶︎ Text-CNN이란?
→ 용어 그대로 텍스트 데이터에 대한 CNN을 기반으로 하는 모델입니다.
→ 공간적(지역적, 위치적, 계층적) 특징을 잘 포착하는 CNN의 특징에서 영감을 받아 텍스트 모델에도 적용을 한 것입니다. 이를 통해 텍스트(시퀀스) 데이터의 지역적인 특징을 잘 포착하며 문장 분류, 감성 분석 등에서 자주 사용됩니다.
CNN의 특징을 잘 알고 계시면 Text-CNN에 적용하는 것도 쉬울 것입니다. 또한 쉽게 Text-CNN을 설명하는 곳이 많은데 코드로는 많지 않아서 오늘은 코드 위주의 정리를 해보려고 합니다.
▶︎ 텍스트 분류 모델을 사용하기 전에 필요한 단계
1. 데이터 불러오기
2. 타겟 변수(y) 라벨 인코딩하기(원핫인코딩을 해도 되지만, 그러면 모델 컴파일할 때 loss='categorical_crossentropy'로 고쳐주세요)
3. 토큰화하여 불용어 제거한 전처리된 corpus를 준비해주세요! (자연어 모델에서는 특히 전처리에 따라 모델 성능이 더 크게 차이납니다)
4. 전처리된 corpus로 사전 만들어서 corpus를 숫자로 변환하고 패딩까지 완료시켜 모델에 입력할 데이터를 만들어주세요!
5. 사전에 담긴 단어들을 Word2Vec을 사용하여 의미를 담은 숫자로 임베딩시켜주세요!
6. 이제 모델을 만들겠습니다!
▶ 모델 구축 및 학습
class RocAucEvaluation(Callback): def __init__(self, validation_data=(), interval=1): super(Callback, self).__init__() self.interval = interval self.X_val, self.y_val = validation_data def on_epoch_end(self, epoch, logs={}): if epoch % self.interval == 0: y_pred = self.model.predict(self.X_val, verbose=0) score = roc_auc_score(self.y_val, y_pred, multi_class='ovo') # 'ovr' 또는 'ovo' print("\n ROC-AUC - epoch: %d - score: %.6f \n" % (epoch+1, score))
filter_sizes = [1,2,3,5] num_filters = 32 def get_model(): inp = Input(shape=(max_len, )) x = Embedding(vocab_size, embedding_dim, weights=[embedding_matrix], trainable=True)(inp) x = SpatialDropout1D(0.4)(x) x = Reshape((max_len, embedding_dim, 1))(x) conv_0 = Conv2D(num_filters, kernel_size=(filter_sizes[0], embedding_dim), kernel_initializer='normal', activation='elu')(x) conv_1 = Conv2D(num_filters, kernel_size=(filter_sizes[1], embedding_dim), kernel_initializer='normal', activation='elu')(x) conv_2 = Conv2D(num_filters, kernel_size=(filter_sizes[2], embedding_dim), kernel_initializer='normal', activation='elu')(x) conv_3 = Conv2D(num_filters, kernel_size=(filter_sizes[3], embedding_dim), kernel_initializer='normal', activation='elu')(x) maxpool_0 = MaxPool2D(pool_size=(max_len - filter_sizes[0] + 1, 1))(conv_0) maxpool_1 = MaxPool2D(pool_size=(max_len - filter_sizes[1] + 1, 1))(conv_1) maxpool_2 = MaxPool2D(pool_size=(max_len - filter_sizes[2] + 1, 1))(conv_2) maxpool_3 = MaxPool2D(pool_size=(max_len - filter_sizes[3] + 1, 1))(conv_3) z = Concatenate(axis=1)([maxpool_0, maxpool_1, maxpool_2, maxpool_3]) z = Flatten()(z) z = Dropout(0.1)(z) outp = Dense(3, activation="softmax")(z) # 클래스의 갯수 입력 model = Model(inputs=inp, outputs=outp) model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy']) return model
model = get_model() batch_size = 256 epochs = 7 X_tra, X_val, y_tra, y_val = train_test_split(padded_sequences, train['label_encoded'], train_size=0.95, random_state=233) RocAuc = RocAucEvaluation(validation_data=(X_val, y_val), interval=1)
model = get_model() batch_size = 256 epochs = 7 X_tra, X_val, y_tra, y_val = train_test_split(padded_sequences, train['label_encoded'], train_size=0.95, random_state=233) RocAuc = RocAucEvaluation(validation_data=(X_val, y_val), interval=1)
hist = model.fit(X_tra, y_tra, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val), callbacks=[RocAuc], verbose=2)
▶︎ 평가 지표 시각화하기
acc = hist.history['accuracy'] val_acc = hist.history['val_accuracy'] x_len = np.arange(len(acc)) plt.plot(x_len, acc, marker='.', c='blue', label="Train-set Acc.") plt.plot(x_len, val_acc, marker='.', c='red', label="Validation-set Acc.") plt.legend(loc='upper right') plt.grid() plt.xlabel('epoch') plt.ylabel('Accuracy') plt.show()
loss = hist.history['loss'] val_loss = hist.history['val_loss'] x_len = np.arange(len(acc)) plt.plot(x_len, loss, marker='.', c='blue', label="Train-set loss.") plt.plot(x_len, val_loss, marker='.', c='red', label="Validation-set loss.") plt.legend(loc='upper right') plt.grid() plt.xlabel('epoch') plt.ylabel('Cross-entropy') plt.show()
▶ ︎ 테스트 데이터 평가하기 (테스트 데이터도 동일한 전처리와 패딩 절차를 밟아야합니다.)
result = model.evaluate(test_padded_sequences, test['label_encoded']) print('loss (cross-entropy) :', result[0]) print('test accuracy :', result[1])
참조 자료 : https://www.kaggle.com/code/yekenot/textcnn-2d-convolution/script
'자연어처리 공부' 카테고리의 다른 글
[자연어처리] Transformer 쉽게 풀어서 정리해드립니다. (0) 2024.01.05 [자연어처리] N-gram으로 아이오아이 너무너무너무 언어모델 학습하기. 다음에 올 가사 생성하기 (0) 2024.01.03 [자연어처리] 문자를 숫자로 변환하는 방법 (BOW, TF-IDF, Word-Embedding) (0) 2024.01.02 [자연어처리] Word2Vec 의 모든 것 (1) 2023.12.26 [자연어처리] 기계 번역 seq2seq Encoder-Decoder Model (2) Inference step (1) 2023.12.26