머신러닝과 딥러닝을 배울 때 가장 많이 사용하는 데이터가 있다.
바로 MNIST 데이터 이다
MNIST 데이터는 손으로 쓴 0~9까지의 숫자로 이루어져 있다.
MNIST 데이터와 크기, 개수가 동일하지만 숫자 대신 패션 아이템으로 이루어진 데이터가 있는데, 패션 MNIST이다.
패션 MNIST 데이터 알아보기
패션 MNIST 데이터는 딥러닝 라이브러리에서 가져올 수 있다.
이때 텐서플로(tensorflow) 를 사용해서 데이터를 불러올 수 있다. 텐서플로의 케라스 패키지를 임포트하여서 패션 MNIST 데이터를 다운로드 할 수 있다.
from tensorflow import keras
(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.loda_data()
이 데이터는 각각 입력과 타깃 데이터가 한 쌍으로 구성되어있다.
print(train_input.shape, train_target.shape)
(60000, 28, 28) (60000,)
print(test_input.shape, test_target.shape)
(10000, 28, 28) (10000,)
훈련 데이터에서 몇 개의 샘플을 출력해보자.
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()
이 input 값들의 target 값을 알아보자.
print([train_target[i] for i in range(10)])
[9, 0, 0, 3, 0, 2, 7, 2, 5, 5]
각각 레이블의 의미는 다음과 같다.
레이블 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
패션 아이템 | 티셮츠 | 바지 | 스웨터 | 드레스 | 코드 | 샌달 | 셔츠 | 스니커즈 | 가방 | 앵클부츠 |
import numpy as np
print(np.unique(train_target, return_counts=True))
(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8), array([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000]))
각각 레이블마다 6000개의 샘플이 들어있음을 볼 수 있다.
로지스틱 회귀로 패션 아이템을 분류해보자.
로지스틱 회귀로 패션 아이템을 분류해보자
SGDClassifier 를 통해서 확률적 경사 하강법을 학습했다.
손실함수를 정의하기 위해 loss ='log' 로 지정하여 로지스틱 손실 함수를 최소화하는 확률적 경사 하강법 모델을 만들었다.
SGDClassifier 사용할 때 표준화 시킨 전처리 데이터를 사용하였는데, 각 특성마다 값의 범위가 다르면 안되기 때문이다.
패션 MNIST 는 0~255까지의 값을 가지므로 255로 나누어 0~1 사이의 값으로 정규화를 한다.
SGDClassifier는 2차원 배열은 다루지 못하기 때문에 1차원 배열로 만들어준다.
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)
print(train_scaled.shape)
(60000, 784)
SGDClassifier 의 cross_validate 함수를 이용해서 교차 검증하여 성능을 확인해보자
from sklearn.model_selection import cross_validate
from sklearn.linear_model import SGDClassifier
sc = SGDClassifier(loss='log', max_iter=5, random_state=42)
scores = cross_validate(sc, train_scaled, train_target, n_jobs=-1)
print(np.mean(scores['test_score']))
0.8195666666666668
성능이 그리 좋지는 않다.
로지스틱 회귀 공식을 떠올린다면 다음 식과 같고,
이 식을 패션 MNIST 데이터에 맞게 변형한 식을 생각할 수 있다.
다만, 레이블 마다 각각 다른 가중치를 사용해야 한다.
이런 방법으로 나머지 레이블(클래스)에 대한 방정식을 모두 생각할 수 있을 것이다. SGDClassifier 모델은 10개 클래스에 대한 가중치와 절편, 즉 파라미터를 찾는다.
방정식이 이런 식으로 구현이 된다.
인공신경망을 더 자세히 살펴보면 로지스틱 회귀를 표현한 그림과 비슷하다.
출력층이 있고
z 값을 계산하는 단위를 나타내는 뉴런
입력층, 가중치 등이 있다.
인공 신경망을 만들 때는 텐서플로를 사용해서 만드는데, SGDClassifier 에 없는 기능들을 더 제공한다.
텐서플로에는 저수준 API와 고수준 API가 있는데, 케라스가 고수준 API이다.
그러면 본격적으로 인공 신경망 모델을 만들어보자.
인공 신경망으로 모델 만들기
인공 신경망에서는 교차 검증을 사용하지 않고 검증세트를 별도로 빼고 사용한다.
그 이유는 딥러닝 데이터셋은 충분히 커서 검증 점수가 안정적이고, 교차검증을 수행할 때 훈련 시간이 오래걸리기 때문이다.
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)
(48000, 784) (48000,)
print(val_scaled.shape, val_target.shape)
(12000, 784) (12000,)
이때 입력층과 출력층 사이에 있는 층을 밀집층 이라고 한다.
이런 층을 양쪽의 뉴런이 모두 연결하고 있기 때문에 완전 연결층이라고도 부른다.
케라스의 Dense 클래스를 사용해서 밀집층을 만들 수 있다.
dense = keras.layers.Dense(10, #뉴런개수
activation='softmax', #뉴런 출력에 적용할 함수
input_shape=(784,) #입력의 크기
)
이때 2개의 클래스를 분류하는 이진 분류라면 activation='sigmoid' 로 설정하여 시그모이드 함수를 사용할 수 있다.
이 밀집층을 가진 신경망 모델을 만들어야 하는데, 이는 케라스의 Sequential 클래스를 사용한다.
model = keras.Sequential(dense)
객체를 만들 때 밀집층의 객체 dense를 전달한다.
그러면 model 객체가 신경망 모델이 된다.
앞에서 소프트맥스 함수와 같이 뉴런의 선형 방정식 계산 결과에 적영되는 함수를 활성화 함수 라고 부른다.
인공 신경망으로 패션 아이템 분류하기
케라스 모델은 훈련하기 전에 설정 단계가 있는데, 이는 모델 객체의 compile() 메서드에서 수행한다.
지정하는 것은 손실 함수의 종류이다.
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
loss에는 손실함수를 지정하는데
이중 분류에서는 'binary_crossentropy'
다중 분류에서는 categorical_crossentropy를 사용한다.
앞의 sparse라는 단어가 붙은 이유는 양성 클래스와 음성 클래스에 대한 크로스 엔트로피를 계산하는 것이다.
이진 분류의 출력 뉴런은 양성 클래스에 대한 확률만 출력하므로 음성 클래스에 대한 확률은 1-알파 로 구할 수 있다.
이진 분류의 타깃값은 양성 샘플일 때 1, 음성 샘플일 때 0으로 되어있다.
이 때문에 특별히 음성 샘플일 때 1로 바꿔서 (1- 타깃값)으로 계산한다.
이렇게 하나의 뉴런만으로도 양성과 음성 클래스에 대한 크로스 엔트로피를 구할 수 있다.
다중 분류의 경우에는 다음과 같다..
예를 들어 샘플이 티셔츠라면, 첫 번째 뉴런의 활성화 함수 출력에 크로스 엔트로피 손실 함수를 적용하고 나머지 활성화 함수 출력은 모두 0으로 만든다. 이렇게 하기 위해서 티셔츠 샘플의 타깃값만 1로 만들고 나머지는 0인 배열을 만들 수 있다
[1,0,0,0,0,0,0,0,0,0]
이 값을 출력층의 활성화 값의 배열과 곱하면 된다.
바지일 경우에는 [0,1,0,0,0,0,0,0,0,0] 이 될 것이다.
이처럼 타깃값을 해당 클래스만 1이고 나머지는 모두 0인 배열로 만드는 것을 원-핫 인코딩이라고 한다.
그러나 텐서플로에서는 정수로된 타깃값을 이용해서 바로 크로스 엔트로피 손실을 계산할 수 있는데
이것이 바로 sparse_categorical_crossentropy 이다.
compile() 매서드의 metrics는 정확도 지표를 지정해서 정확도를 함께 출력하도록 한다.
케라스는 기본적으로 에포크마다 손실 값을 출력해주기 때문에 정확도도 함께 출력하면 좋다.
model.fit(train_scaled, train_target, epochs=5)
Epoch 1/5
1500/1500 [==============================] - 4s 2ms/step - loss: 0.6077 - accuracy: 0.7934
Epoch 2/5
1500/1500 [==============================] - 2s 1ms/step - loss: 0.4786 - accuracy: 0.8387
Epoch 3/5
1500/1500 [==============================] - 2s 2ms/step - loss: 0.4575 - accuracy: 0.8473
Epoch 4/5
1500/1500 [==============================] - 2s 2ms/step - loss: 0.4446 - accuracy: 0.8529
Epoch 5/5
1500/1500 [==============================] - 2s 2ms/step - loss: 0.4376 - accuracy: 0.8556
모델을 훈련하면 이와같이 손실값과 정확도가 함께 계산이 된다.
그러면 이 모델에 val_scaled, val_target 즉 검증세트를 이용해서 모델의 성능을 확인해보자.
사용하는 메서드는 evaluate() 메서드이다.
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 1s 2ms/step - loss: 0.4559 - accuracy: 0.8464
[0.45590299367904663, 0.8464166522026062]
'Study > 혼자 공부하는 머신러닝' 카테고리의 다른 글
혼자 공부하는 머신러닝 + 딥러닝 - 신경망 모델 훈련 (0) | 2022.04.21 |
---|---|
혼자 공부하는 머신러닝 + 딥러닝 - 심층 신경망 (0) | 2022.04.21 |
혼자 공부하는 머신러닝 + 딥러닝 - 주성분 분석 (0) | 2022.03.31 |
혼자 공부하는 머신러닝 + 딥러닝 - K-Means 알고리즘 (0) | 2022.03.29 |
혼자 공부하는 딥러닝 + 머신러닝 - 군집 알고리즘 (0) | 2022.03.29 |