본문 바로가기

데이터/머신러닝

[혼공] ch 7-1 인공 신경망

1. 패션 MNIST

 

- 텐서플로의 케라스(Keras) 패키지를 임포트하고 패션 MNIST 데이터를 다운로드 

 

from tensorflow import keras

(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()

 

- keras.datasets.fashion_mnist 모듈 아래 load_data() 함수는 훈련 데이터와 테스트 데이터를 나누어 반환 

 

- 전달받은 데이터의 크기를 확인 

print(train_input.shape, train_target.shape)

 

- 훈련 데이터는 60,000개의 이미지로 이루어져 있고, 각 이미지는 28*28 크기이다. 

- 타깃도 60,000개의 원소가 있는 1차원 배열이다. 

 

- 테스트 세트의 크기 확인 

print(test_input.shape, test_target.shape)

 

- 테스트 세트의 10,000개의 이미지로 이루어져 있다. 

 

- 훈련 데이터의 몇 개의 샘플을 그림으로 출력

import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 10, figsize=(10,10))
for i in range(10):
    axs[i].imshow(train_input[i], cmap='gray_r')
    axs[i].axis('off')
plt.show()

 

 

 

- 파이썬의 리스트 내포를 사용해서 처음 10개 샘플의 타깃값을 리스트로 만든 후 출력

 

print([train_target[i] for i in range(10)])

 

 

- 패션 MNIST의 타깃은 0~9까지의 숫자 레이블로 구성된다. 

 

레이블 0 1 2 3 4 5 6 7 8 9
패션 아이템 티셔츠 바지 스웨터 드레스 코트 샌달 셔츠 스니커즈 가방  앵클부츠 

 

- 넘파이 unique() 함수로 레이블 당 샘플 개수 확인 

 

import numpy as np

print(np.unique(train_target, return_counts=True))

 

 

- 0~9까지 레이블마다 정확히 6,000개의 샘플이 들어 있는 것을 볼 수 있다. 

 

 

2. 로지스틱 회귀로 패션 아이템 분류하기 

 

- SGDClassifier 클래스 loss 매개변수를 'log_loss'로 지정하여 로지스틱 손실 함수를 최소화하는 확률적 경사 하강법 모델

- 확률적 경사 하강법은 여러 특성 중 기울기가 가장 가파른 방향을 따라 이동

- 패션 MNIST의 경우 각 픽셀은 0~255 사이의 정숫값을 가니다. 이런 이미지의 경우 보통 255로 나누어 0~1 사이의 값으로 정규화한다. 

 

- reshape() 메서드를 사용해 2차원 배열인 각 샘플을 1차원 배열로 펼치기 

- reshape() 메서드의 두 번째 매개변수를 28*28 이미지 크기에 맞춰 지정하면 첫 번째 차원(샘플 개수)은 변하지 않고 원본 데이터의 두 번째, 세 번째 차원이 1차원으로 합쳐진다. 

train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)


print(train_scaled.shape)

 

- 784개의 픽셀로 이루어진 60,000개의 샘플이 준비됨 

 

- SGDClassifier클래스cross_validate 함수를 사용해 이 데이터에서 교차 검증으로 성능을 확인

 

from sklearn.model_selection import cross_validate
from sklearn.linear_model import SGDClassifier

sc = SGDClassifier(loss='log_loss', max_iter=5, random_state=42)

scores = cross_validate(sc, train_scaled, train_target, n_jobs=-1)
print(np.mean(scores['test_score']))

 

- 반복 횟수를 늘려도 성능이 크게 향상되지 않음 

 

- 로지스틱 회귀 공식 

z = a*(Weight) + b*(Length)+c*(Diagonal(+d*(Height)+e*(Width)+f

 

- 패션 MNIST 데이터에 맞게 변형하면 다음과 같다. 

z_티셔츠 = w1*(픽셀1) + w2*(픽셀2)+ ... + w784*(픽셀784)+b
z_바지 = w1`*(픽셀1) + w2`*(픽셀2)+ ... + w784`*(픽셀784)+b`

 

- SGDClassifier 모델은 패션 MNIST 데이터의 클래스를 가능한 잘 구분할 수 있도록 이 10개의 방정시겡 대한 모델 파라미터(가중치와 절편)를 찾는다. 

 

- 티셔츠를 계산하기 위해 픽셀 784개와 곱한느 가중치 784ro(w1~w784)와 절편(b)이 바지를 계산하기 위해 픽셀 784개와 곱하는 가중치 784개(w1`~w784`), 절편(b`)과 다르다.

 

- z_티셔츠, z_바지와 같이 10개의 클래스에 대한 선형 방정식을 모두 계산한 다음에는 소프트맥스 함수를 통과하여 각 클래스에 대한 확률을 얻을 수 있다. 

 

 

3. 인공신경망 

 

인공 신경망(artificial neural network, ANN)

 

- 생물학적 뉴런에서 영감을 받아 만든 머신러닝 알고리즘

- 가장 기본적인 인공 신경망은 확률적 경사 하강법을 사용하는 로지스틱 회귀와 같다. 

 

- 패션 아이템 분류 문제를 인공 신경망으로 표현 

 

- z1~z10을 계산하고 이를 바탕으로 클래스를 예측하기 때문에 신경망의 최종 값을 만든다는 의미에서 출력층(output layer)라고 부른다. 

-인공 신경망에서는 z값을 계산하는 단위를 뉴런(neuron)이라고 부른다. 

- 픽셀1,픽셀2를 x1,x2와 같이 바꾸었다. 인공 신경망은 x1~x784까지를 입력층(input layer)라고 부른다, 

 

 

텐서플로와 케라스 

 

- 텐서플로는 구글이 2015년 11월 오픈소스로 공개한 딥러닝 라이브러리 

- 코랩에는 이미 텐서플로가 설치되어 있기 때문에 간단히 임포트하여 사용 가능 

 

import tensorflow as tf

 

- 텐서플로에는 저수준 API와 고수준 API가 있는데 케라스(Keras)텐서플로의 고수준 API이다. 

- 딥러닝 라이브러리가 다른 머신러닝 라이브러리와 다른 점 중 하나는 그래픽 처리 장치인 GPU를 사용하여 인공 신경망을 훈련한다는 것이다. 

- GPU는 벡터와 행렬 연산에 매우 최적화되어 있기 때문에 곱셈과 덧셈이 많이 수행되는 인공 신경망에 큰 도움이 된다, 

 

 

4. 인공 신경망으로 모델 만들기 

 

- 로지스틱 회귀에서는 교차 검증을 사용해 모델을 평가했지만, 인공 신경망에선느 교차 검증을 잘 사용하지 않고 검증 세트를 별도로 덜어내어 사용한다. 

 

1) 딥러닝 분야의 데이터셋은 충분히 크기 때문에 검증 점수가 안정적

2) 교차 검증을 수행하기에는 훈련시간이 너무 오래걸림

 

- 사이킷런의 train_test_split() 함수를 사용하여 검증 세트 나누기 

 

from sklearn.model_selection import train_test_split

train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size=0.2, random_state=42)

 

 

print(train_scaled.shape, train_target.shape)

 

 

print(val_scaled.shape, val_target.shape)

 

- 60,000개 중에 12,000개가 검증 세트로 분리됨

- 먼저 훈련 세트(train_scaled, train_target)로 모델을 만든다. 그 다음 검증 세트(val_scaled, val_target)로 훈련한 모델을 평가한다, 

 

- 케라스의 레이어(keras,layers) 패키지 안에는 다양한 층이 준비 되어있고, 가장 기본이 되는 층은 밀집층(dense layer)이다. 

 

- 케라스의 Dense 클래스를 사용해 밀집층 만들기

- 필요한 매개변수는 뉴런 개수, 뉴런의 출력에 적용할 함수, 입력의 크기이다. 

 

dense = keras.layers.Dense(10, activation='softmax', input_shape=(784,))

 

- 10개의 패션 아이템을 분류하기 때문에 뉴런 개수를 10개로 지정

- 10개의 뉴런에서 출력되는 값을 확률로 바꾸기 위해서는 소프트맥스 함수를 사용 

- 케라스 층에서는 activation 매개변수에 뉴런의 출력에 적용할 함수를 지정

- 세 번째 매개변수는 입력값의 크기를 받는다. 10개의 뉴런이 각각 몇 개의 입력을 받는지 튜플로 지정

 

- 케라스의 Sequential 클래스를 사용해 이 밀집층을 가진 신경망 모델을 만든다. 

- Sequential 클래스의 객체를 만들 때 앞에서 만든 밀집층의 객체 dense를 전달 

model = keras.Sequential(dense)

 

 

 

- 소프트맥스와 같이 뉴런의 선형 방정식 계산 결과에 적용되는 함수를 활성화 함수(activation function)이라고 부른다. 

 

5. 인공 신경망으로 패션 아이템 분류하기 

 

 

- 케라스 모델은 훈련하기 전에 설정 단계가 있다. 

- 이런 설정을 model 객체의 compile() 메서드에서 수행한다. 

- 꼭 지정해야 할 것은 손실 함수의 종류이다. 그 다음 훈련 과정에서 계산하고 싶은 측정값을 지정한다.

 

model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')

 

- 이진 분류 -> loss='binary_crossentropy'

- 다중 분류 -> loss='categorical_crossentropy'

 

- 이진 크로스 엔트로피 손실을 위해 -log(예측 확률)에 타깃값(정답)을 곱했다. 

- 이진 분류에서는 출력층의 뉴런이 하나이다. 이 뉴런이 출력하는 확률 값 a(시그모이드 함수의 출력값)를 사용해 양성 클래스와 음성 클래스에 대한 크로스 엔트로피를 계산한다. 

- 이진 분류의 출력 뉴런은 오직 양성 클래스에 대한 확률(a)만 출력하기 때문에 음성 클래스에 대한 확률은 간단히 1-a로 구할 수 있다. 

 

- 패션 MNIST 데이터셋과 같이 다중 분류일 경우 

 

- 출력층은 10개의 뉴런이 있고 10개의 클래스에 대한 확률을 출력한다. 

- 첫 번째 뉴런은 티셔츠일 확률이고 두 번째 뉴런은 바지일 확률을 출력한다. 

- 이진 분류와 달리 각 클래스에 대한 확률이 모두 출력되기 때문에 타깃에 해당하는 확률만 남겨 놓기 위해서 나머지 확률에는 모두 0을 곱한다. 

 

- 이렇게 하기 위해서 티셔츠 샘플의 타깃값은 첫 번째 원소만 1이고 나머지는 모두 0인 배열로 만들 수 있다.

- 이 배열과 출력층의 활성화 값의 배열과 곱하면 된다. 

 

[a1,a2,a3,a4,a5,a6,a7,a8,a9,10] * [1,0,0,0,0,0,0,0,0,0]

 

- 결국 신경망은 티셔츠 샘플에서 손실을 낮추려면 첫 번째 뉴런의 활성화 출력 a1의 값을 가능한 1에 가깝게 만들어야 한다. 

 

원-핫 인코딩(one-hot encoding)

- 타깃값을 해당 클래스만 1이고 나머지는 모두 0인 배열로 만드는 것

 

- 다중 분류에서 크로스 엔트로피 손실 함수를 사용하려면 0,1,2와 같이 정수로된 타깃값을 원-핫 인코딩으로 변환해야 한다. 

 

 

- 패션 MNIST 데이터의 타깃값은 모두 정수로 되어 있다. 

 

print(train_target[:10])

 

 

- 하지만 텐서플로에서는 정수로 된 타깃값을 원-핫 인코딩으로 바꾸지 않고 그냥 사용 가능하다. 

- 정수로된 타깃값을 사용해 크로스 엔트로피 손실을 계산하는 것이 바로 'sparse_category_crossentropy'이다 ,

- 타깃값을 원-핫 인코딩으로 준비했다면 compile() 메서드에 손실 함수를 loss='categorical_crossentropy'로 지정한다. 

 

- 케라스는 모델이 훈련할 때 기본으로 에포크마다 손실 값을 출력해 준다. 정확도를 함께 출력하기 위해 두 번째 매개변수 metrics 매개변수에 정확도 지표를 의미하는 'accuracy'를 지정한다. 

 

- 처음 두 매개변수에 입력(train_scaled)과 타깃(train_target)을 지정하고 반복할 에포크 횟수를 epochs 매개변수를 지정하여 모델을 훈련 

 

model.fit(train_scaled, train_target, epochs=5)

 

 

- 에포크마다 걸린 시간과 손실(loss), 정확도(accuracy)를 출력

 

- 케라스에서 모델의 성능을 평가하는 메서드는 evaluate() 메서드이다. 

 

model.evaluate(val_scaled, val_target)