본문 바로가기
  • 데이터에 가치를 더하다, 서영석입니다.
도전 : 더 나은 사람으로/텍스트 산업 분류 공모전

[2022 통계청 공모전] 4. CNN-LSTM 사용

by 꿀먹은데이터 2022. 5. 15.

CNN-LSTM 사용하기에 앞서 PCA를 진행해주었다.

 

PCA 함수 생성

compute_pca 함수를 만들어,

  1. covariance 행렬을 계산
  2. covariance matrix에서 eignvector와 eigenvalue를 계산
  3. eigenvalue를 오름차순으로 sort
  4. highest 에서 lowest로 종렬
  5. eigen vector를 내림차순으로 sort
  6. n개의 eigenvector를 선택 후 배열
  7. eigenvector의 transpose를 곱하여 데이터를 변환
def compute_pca(X: np.ndarray, n_components: int=2) -> np.ndarray:

    X_demeaned = X - X.mean(axis=0)

    covariance_matrix = np.cov(X_demeaned, rowvar=False)
    eigen_vals, eigen_vecs = np.linalg.eigh(covariance_matrix)
    idx_sorted = np.argsort(eigen_vals)
    idx_sorted_decreasing = list(reversed(idx_sorted))
    eigen_vals_sorted = eigen_vals[idx_sorted_decreasing]
    eigen_vecs_sorted = eigen_vecs[:, idx_sorted_decreasing]
    eigen_vecs_subset = eigen_vecs_sorted[:, :n_components]

    X_reduced = np.dot(eigen_vecs_subset.T, X_demeaned.T).T
    return X_reduced

LabelEncoder() 이후 shape을 본 뒤 패딩을 시켜준다. (pad_sequences 사용)

이 후 임베딩 행렬의 크기를 확인.

embedding_matrix = np.zeros((vocab_size, 100))
print('임베딩 행렬의 크기(shape) :',np.shape(embedding_matrix))

100개인 임베일 shape를 50으로 PCA 시행.

X = embedding_matrix
X_reduced = compute_pca(X, n_components=50)

 CNN-LSTM 모델 생성

Embedding 시킨 모델에 Conv1D를 2곂 쌓고, LSTM을 2곂 쌓아 모델을 구축 후, Flatten으로 1차원으로 만들어준다.

마지막을 softmax를 통해 Dense를 넣어주면 끝. (lstm 사용..)

def build_cnn_lstm(recurrent_dropout = 0.5,dropout=0.5,):
    with tf.device('/gpu:0'):
        model = Sequential()

        model.add(Input(shape=(max_len,)))
        e = Embedding(vocab_size,output_dim =50,  weights=[X_reduced], input_length=max_len, trainable=False)
        model.add(e)

        model.add(Conv1D(filters=64, kernel_size=3, padding='same', activation='relu'))
        model.add(MaxPooling1D(pool_size=2))
        model.add(Dropout(dropout))

        model.add(Conv1D(filters=32, kernel_size=3, padding='same', activation='relu'))
        model.add(MaxPooling1D(pool_size=2))

        model.add(LSTM(256, recurrent_dropout=recurrent_dropout,activation='tanh',kernel_initializer="he_normal",unroll=True,return_sequences=True))
        model.add(Dropout(dropout))

        model.add(LSTM(512, recurrent_dropout=recurrent_dropout,activation='tanh',kernel_initializer="he_normal",unroll=True))
        model.add(Dropout(dropout))

        model.add(Flatten())
        model.add(Dense(y_train.shape[1], activation='softmax'))
        # adam = tf.keras.optimizers.Adam(learning_rate = 1e-5)
        

        return model

전에 gridsearch사용으로 Adam과 learning_rate가 8.382620250945622e-05 일 때 Accuracy가 최대가 되어 그대로 사용해준다. (정작 3일동안 모델 5개를 돌렸다.. 한번 돌릴 때 약 12시간 정도..>?)

optimizer = tf.keras.optimizers.Adam(learning_rate = 8.382620250945622e-05)

 

for tri, vai in cv.split(X_train):
    model = build_cnn_lstm2()
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    callbacks = [EarlyStopping(monitor='val_loss', patience=5)]
    history = model.fit(X_train[tri], y_train[tri],
                        validation_data=(X_train[vai], y_train[vai]),
                        epochs=40,callbacks=callbacks,
                        batch_size = 106, verbose=1) 
    models.append(model)
    scores.append(history.history["accuracy"])
    if is_holdout:
        break

 

약 accuracy가 87.01로 나왔고.. 약간 아쉽지만, 이로써 통계청 활용대회가 끝이났다.

(이 모델도 약 9시간은 돌아간 듯.. 하다)

 

아쉬운 점은

모델의 구성을 더 세밀하고 탄탄히 쌓아야 한다는 점.

자연어 토큰화 처리할 때, EDA를 더 정교하게 해야할 점.

 

이 둘을 높이면.. Accuracy가 더 높아지지 않을까 싶다. loss는 훨 적어졌었는데.. 이 모델에서 약간 높은 값이 나와 놀랐다.

이 전 모델의 loss와 accuracy가 train과 test에서 더 높았는데.. 너무 둘이 안붙는다 ..

 

관련 github code

https://github.com/rootofdata/NLP_AI_Industry_classification.git

 

GitHub - rootofdata/NLP_AI_Industry_classification

Contribute to rootofdata/NLP_AI_Industry_classification development by creating an account on GitHub.

github.com