MLPClassifier의 다중 레이블 분류

이 포스트는 “나이브”님이 메일로 문의 주신 내용을 바탕으로 작성되었습니다. “파이썬 라이브러리를 활용한 머신러닝” 2.3.8절의 신경망에 소개된 MLPClassifier 모델이 다중 분류Multi-class Classification, 다중 레이블 분류Multi-label Classification가 가능한지에 대해 문의를 주셨습니다. 책을 보니 공교롭게도 예제가 모두 이진 분류로 나와 있네요. 🙂

MLPClassifier는 다중 분류, 다중 레이블 분류를 지원합니다. 일반적으로 신경망에서 다중 분류를 구현하려면 출력층의 뉴런을 2개 이상 놓아야 합니다. MLPClassifier 클래스는 겉으로 드러나 있지는 않지만 타깃 배열 y의 차원을 보고 출력 뉴런의 개수를 자동으로 결정합니다. 간단한 예를 만들어 확인해 보겠습니다. 먼저 책에서 사용한 moons 데이터셋을 억지로 다중 분류를 위한 데이터셋으로 변경해 보겠습니다. 즉1차원 배열인 타깃값 y를 (100, 2) 2차원 배열로 만들어 사용합니다.

print(Y_train[:10])
array([[ 0.,  1.],
        [ 0.,  1.],
        [ 1.,  0.],
        [ 0.,  1.],
        [ 0.,  1.],
        [ 1.,  0.],
        [ 0.,  1.],
        [ 1.,  0.],
        [ 1.,  0.],
        [ 0.,  1.]])

그런 다음 책의 예제와 동일한 옵션으로 신경망을 학습시켜 보겠습니다. 타깃을 2차원 배열로 변형시켰기 때문에 y_train이 아니라 Y_train 처럼 대문자를 사용했습니다.

mlp_multi = MLPClassifier(solver='lbfgs', random_state=0).fit(X_train, Y_train)

mlp_multi

이 그래프를 아래 이진 분류의 경우와 비교해 보면 결정 경계가 조금 다른 것을 확인할 수 있습니다.

mlp_binary

MLPClassifier의 기본값은 100개의 뉴런을 가진 은닉층 하나를 사용합니다. 그림 2-47과 같은 신경망 구조를 상상해 보면, 마지막 출력층과 은닉층 사이의 연결(가중치)이 출력층의 뉴런의 개수가 하나일때와 두 개일때 달라질 것이라는 것을 눈치챌 수 있습니다. 이런 차이 때문에 결정 경계가 조금 달라졌습니다. 하지만 우리가 사용한 샘플 데이터는 그렇게 조밀하지 않으므로 변화된 결정 경계에 영향을 받지 않아 테스트 점수가 동일합니다.

mlp_multi.score(X_test, Y_test)
0.88

이번에는 다중 레이블 분류를 위해 ClassifierChain 예제에서 사용했던 Yeast 데이터셋을 이용해 보겠습니다. 이 데이터의 타깃값은 확실히 다중 레이블입니다.

Y_train[:10]
array([[ 1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,
          0.],
        [ 1.,  1.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,  0.,  0.,  0.,  0.,
          0.],
        [ 0.,  0.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,
          0.],
        [ 1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,
          0.],
        [ 0.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,
          0.],
        [ 1.,  1.,  0.,  0.,  0.,  1.,  1.,  1.,  0.,  0.,  0.,  1.,  1.,
          0.],
        [ 0.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.],
        [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,  0.,  0.,  0.,  0.,
          0.],
        [ 1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,
          0.],
        [ 1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,
          0.]])

입력의 특성이 103개이므로 뉴런과 은닉층의 개수를 조금 늘려 보겠습니다(300, 100). 그리고 기본 solver인 Adam 알고리즘을 사용하므로 최대 반복횟수(max_iter)를 기본값인 200에서 크게 증가시켜 주었습니다.

mlp_multilabel = MLPClassifier(hidden_layer_sizes=(300,100), max_iter=10000, 
                               random_state=42).fit(X_train, Y_train)
mlp_multilabel.score(X_test, Y_test)
0.16115702479338842

분류 모델의 score 메서드는 다중 레이블 분류를 지원하지 않습니다. 즉 행의 전체 원소가 모두 정확히 맞았을 때를 카운트합니다. ClassifierChain에서 처럼 자카드 유사도를 사용할 수 있지만 여기서는 하나 원소라도 맞았을 때를 수동으로 확인해 보겠습니다.

Y_pred = mlp_multilabel.predict(X_test)
np.sum(np.sum(Y_test.astype(int) & Y_pred, axis=1) > 0)/Y_test.shape[0]
0.85330578512396693

이 코드는 예측(Y_pred)을 만들어 테스트 데이터(Y_test)의 각 원소에 대해 논리 곱(AND) 연산을 합니다. 즉 두 행렬의 같은 위치의 원소가 모두 True일 때만 True가 됩니다. 그리고 난 후 True의 개수가 0 보다 큰 행의 개수를 카운트했습니다. 테스트 세트의 85%는 최소한 하나의 레이블 이상 맞았네요. 🙂

 

이 글의 샘플 코드는 ‘파이썬 라이브러리를 활용한 머신러닝‘ 깃허브(https://github.com/rickiepark/introduction_to_ml_with_python/blob/master/MLP_Multilabel.ipynb)에서 확인할 수 있습니다.

MLPClassifier의 다중 레이블 분류”에 대한 3개의 생각

  1. gyogyo

    hidden_layer_sizes=(300,100)는 각각 뉴런이 300개, 100개인 2개의 히든레이어를 사용한다는 의미죠?

    좋아요

    응답
      1. gyogyo

        좋은글 덕분에 짬짬이 공부하는 와중에도 조금씩 알아가고 있는 중입니다. 그냥 얻어가도 되나 싶을 정도로 좋은 내용이 많아서 항상 감사하는 마음입니다. 새책이 기대됩니다~

        Liked by 1명

댓글 남기기

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.