딥러닝 (Deep Learning)/딥러닝 분석연습

뉴스 기사 분류 : 로이터(Reuters) 데이터셋 (병목현상, 레이블을 벡터로 바꾸는 방법들 2가지)

DS지니 2021. 4. 27. 07:34
728x90
반응형

1986년 로이터에서 공개한 짧은 뉴스 기사와 토픽의 집합인 데이터.

텍스트 분류를 위해 널리 사용되는 간단한 데이터셋으로 46개의 토픽이 있고 어떤 토픽은 다른 것에 비해 데이터가 많다.

 

각 토픽은 훈련 세트에 최소한 10개의 샘플을 가지고 있다.

(이 데이터셋은 원본 로이터 데이터셋(135개 토픽) 중 샘플이 많은 것을 뽑아 간단하게 만든 것)

 

defalt값으로 8,982개의 훈련 샘플과 2,246개의 테스트 샘플이 있음.

IMDB, MNIST와 마친가지로 케라스에 포함되어 있다.

IMDB과 마찬가지로 미리 전체 데이터셋의 단어를 고유한 정수 인덱스로 바꾼 후 훈련/테스트 데이터로 나누어 놓았다.

 

 

>>  자세한 코드 & 설명

 

gggggeun/study

Contribute to gggggeun/study development by creating an account on GitHub.

github.com

 


1. 신경망 모델

  • 로이터 뉴스를 46개의 상호 배타적인 토픽으로 분류하는 신경망 만들기
  • 단일 레이블, 다중 분류 문제.(single-label, multiclass classification)
  • 각 데이터 포인트가 여러 개의 범주(ex.토픽)에 속하면 다중 레이블 다중 분류 문제가 된다.
# reuters 데이터 불러오기

from keras.datasets import reuters

(train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)  #단어 1만개로 제한
# 벡터화 : trian/test data는 파이썬 리스트의 넘파이 배열이기 때문에 to_categorical()함수 사용 못함.

import numpy as np

def vectorize_sequences(sequences, dimension=10000):
  results = np.zeros((len(sequences), dimension))  #크기가 (len(sequences), dimension)이고 모든 원소가 0인 행렬을 만든다.
  for i, sequence in enumerate(sequences):
    results[i, sequence] = 1.  #results[i]에서 특정 인덱스의 위치를 1로 만든다.
  return results

x_train = vectorize_sequences(train_data)  # 훈련데이터 벡터변환 
x_test = vectorize_sequences(test_data)   # 테스트데이터 벡터변환
# 각 레이블의 인덱스자리는 1이고 나머지는 0인 벡터로 변환
from keras.utils.np_utils import to_categorical

one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)
model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(46, activation='softmax'))

model.compile(optimizer='rmsprop',
              loss = 'categorical_crossentropy',
              metrics=['accuracy'])

model.fit(partial_x_train,
         partial_y_train,
         epochs=9,
         batch_size=512,
         validation_data=(x_val, y_val))
results = model.evaluate(x_test, one_hot_test_labels)

정확도 78%.

 

 

2. 데이터 병목현상

 

<충분히 큰 중간층을 두어야 하는 이유>

 

마지막 출력이 46차원이기 때문에 중간층의 히든 유닛이 46개보다 많이 적어서는 안된다. 46차원보다 훨씬 작은 중간층(ex.4차원)을 두면 정보의 병목이 어떻게 나타나는지 확인해보자.

 

# 유닛 64개 -> 4개
model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(4, activation='relu'))
model.add(layers.Dense(46, activation='softmax'))

model.compile(optimizer='rmsprop',
              loss = 'categorical_crossentropy',
              metrics=['accuracy'])

model.fit(partial_x_train,
         partial_y_train,
         epochs=20,
         batch_size=512,
         validation_data=(x_val, y_val))
results = model.evaluate(x_test, one_hot_test_labels)

 

  • val_accuracy의 최고값은 71%로 이전보다 약 7~8% 감소되었다.(78%였음.)

이런 손실의 원인 대부분은 많은 정보(클래스 46개의 분할 초평면을 복원하기에 충분한 정보)를 중간층의 저차원 표현 공간으로 압축하려고 했기 때문이다. 이 네트워크는 필요한 정보 대부분을 4차원 표현 안에 구겨 넣었지만 전부는 넣지 못했다.

 

 

 

3. 레이블을 벡터로 바꾸는 방법들 2가지

 

  • 레이블의 리스트를 정수 텐서로 변환
  • loss function - sparse_categorical_crossentropy
y_train = np.array(train_labels)
y_test = np.array(test_labels)

model.compile(optimizer="rmsprop",
             loss = 'sparse_categorical_crossentropy',
             metrics=['acc'])

 

  • 원-핫 인코딩(범주형 인코딩, categorical encoding) 
  • loss function - sparse_categorical_crossentropy
# 각 레이블의 인덱스자리는 1이고 나머지는 0인 벡터로 변환
from keras.utils.np_utils import to_categorical

one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)

model.compile(optimizer='rmsprop',
              loss = 'categorical_crossentropy',
              metrics=['accuracy'])

 

 

4. 추가실험

 

  • 더 크거나 작은 층 사용하기 (32, 128개 유닛)
  • 1개나 3개의 은닉 층 사용해보기
은닉층 개수 은닉 유닛 개수 epochs loss acc 평가
2 64,64 20 1.0 (val) 81% (val) 그래프에서 9번째 에폭 이후 과대적합이 시작됨. 
2 64,64 9 0.98 (test) 78% (test) base
2 64, 4 20 1.47 (test) 68% (test) 은닉층 유닛 개수가 출력층보다 많이 작아, 병목현상이 일어남. 성능이 많이 줄었다.
2 64, 32 9 1.02 (test) 77% (test) base보다 성능이 살짝 더 낮다.
2 64, 128 9 0.98 (test) 78% (test)  
2 128, 128 9 1.03 79.5% 유닛 64보다 loss는 크고 정확도는 높다 ??
1 128 9 0.94  79.7% 은닉층이 2개일때 보다  loss가 줄고 성능이 조금 좋아졌다.
1 🏆 64 9 0.91 79.8% 확실히 유닛개수가 64개일 때 제일 좋다.
3 64, 64, 64 9 1.11 77.3% 은닉층을 늘리니 성능이 줄었다.

최적 : 은닉층이 1개, 유닛 개수 64개 사용 할 때

 

 

 

5. 정리

 

  • 마지막 Dense층의 크기는 클래스 개수여야함.
  • 단일 레이블, 다중 분류 문제에서는 N개의 클래스에 대한 확률 분포를 출력하기 위해 Softmax 활성화 함수를 사용해야 한다.
  • 이런 문제에는 항상 범주형 크로스엔트로피를 사용한다. 이 함수는 모델이 출력한 확률 분포와 타깃 분포 사이의 거리를 최소화한다.
  • 다중 분류에서 레이블을 다루는 두 가지 방법이 있다.(원핫인코딩, 정수인코딩) 손실함수 다른점 주의
  • 많은 수의 범주를 분류할 때 중간층의 크기가 너무 작아 네트워크에 정보의 병목이 생기지 않도록 해야 한다.
728x90
반응형