순전파 신경망 (Feedforward neural network)
-
뉴런이 여러 개의 층으로 나열되고, 인접하는층끼리만 연결된 네트워크
-
입력된 데이터는 순방향으로만 전파됨
-
각각의 뉴런은 여러 개의 입력을 받음
-
해당 입력에 가중치를 곱해서 더하고, 바이어스를 더한 후에 그 값을 활성화함수를 이용해서 변환한 값을 출력함
Keras 를 통한 순전파 신경망 구형
여기서는 손으로 쓴 숫자들로 이루어진 MNIST 데이터베이스를 사용하여 순전파 신경망을 케라스로 구현해본다. MNIST 데이터베이스는 다음과 같이 0~9까지 10가지 숫자에 대한 60,000개의 28x28 그레이 스케일 이미지 데이터셋과, 그에 더해 10,000개의 이미지로 이루어진 테스트셋이다.
MNIST 데이터 가져오기
다음과 같이 데이터를 다운로드한 후 데이터를 불러온다.
from tensorflow.python.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
다운로드된 데이터는 다음과 같이 '~/.keras/datasets/'의 위치로 다운로드 된다.
데이터의 구조
print('x_train.shape:', x_train.shape)
print('y_train.shpae:', y_train.shape)
print('x_test.shape:', x_test.shape)
print('y_test.shape:', y_test.shape)
x_train.shape: (60000, 28, 28)
y_train.shpae: (60000,)
x_test.shape: (10000, 28, 28)
y_test.shape: (10000,)
임포트한 데이터는 위와 같은 형태를 갖는다. 60,000개의 학습용데이터를 통해 모델을 구축한 다음, 평가용 데이터를 이용하여 해당 모델에 대해 평가를 하게 된다.
-
x_train, x_test : 그레이 스케일 이미지 데이터의 uint8 배열. (num_samples, 28, 28)의 형태를 취한다.
-
y_train, y_test : 숫자 레이블의 uint8 배열 (0-9 범위의 정수). (num_samples,)의 형태를 취한다.
-
x_train, y_train : 학습용데이터
-
x_test, y_test : 평가용데이터
즉, 다음과 같다.
-
x_ : 손으로 쓴 숫자 포함
-
y_ : 레이블 포함
-
_train : 60,000 개의 학습용 샘플 포함
-
_test : 10,000개의 평가용 샘플 포함
예를 들어 25168번째 학습용데이터를 살펴보자. 숫자 9를 나타내는 해당 데이터는 아래와 같은 배열을 보여준다.
x_train[25168]
array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,
159, 194, 255, 205, 60, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 198, 242,
253, 253, 254, 253, 238, 58, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 225, 253, 253,
253, 253, 254, 253, 253, 208, 8, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, 253, 253, 253,
253, 162, 154, 98, 208, 253, 74, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 193, 253, 253, 221,
102, 5, 0, 0, 34, 253, 223, 18, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 253, 253, 196,
0, 0, 0, 3, 184, 253, 206, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 253, 253, 236,
178, 143, 110, 189, 253, 253, 139, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 253, 253, 253,
253, 253, 254, 253, 253, 253, 112, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 253, 253, 253,
253, 253, 254, 253, 253, 253, 43, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 253, 253, 253,
253, 253, 254, 253, 253, 253, 146, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 188, 212,
188, 188, 129, 95, 159, 254, 236, 30, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11,
0, 0, 0, 0, 152, 253, 253, 117, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 141, 240, 253, 235, 29, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 73, 244, 253, 253, 193, 16, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 70, 247, 253, 253, 253, 60, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73, 241, 254, 253, 253, 212, 10, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
242, 253, 254, 253, 253, 84, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113,
253, 253, 254, 209, 30, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106,
253, 253, 246, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
225, 253, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0]], dtype=uint8)
임포트한 데이터 스케일 변형
x_train = x_train.reshape(60000, 784)
x_train = x_train/255.
x_test = x_test.reshape(10000, 784)
x_test = x_test/255.
임포한 데이터는 28px x 28px 3D 구조로 네트워크에 맞게 배열 크기가 784인 2D로 변환하자. 그리고 변환한 후에 255 로 나눠서 0 에서 1 사이의 값을 가지도록 스케일을 변환한다. 변환된 구조를 확인해보자. 기존의 60000×28×28의 텐서구조를 가졌던 x_train이 60000×784의 행렬로 변환되었음을 알 수 있다.
print('x_train.shape:', x_train.shape)
print('y_train.shpae:', y_train.shape)
print('x_test.shape:', x_test.shape)
print('y_test.shape:', y_test.shape)
x_train.shape: (60000, 784)
y_train.shpae: (60000,)
x_test.shape: (10000, 784)
y_test.shape: (10000,)
앞서 숫자 9를 나타내던 25168번째 데이터의 경우 다음과 같이 변환되었음을 알 수 있다.
from __future__ import print_function
# This is the extracted array for x_train = 25168 from the training matrix
xt_25168 = x_train[25168,:]
print(xt_25168)
[0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0.23921569 0.62352941 0.76078431 1. 0.80392157 0.23529412
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0.28627451 0.77647059 0.94901961 0.99215686
0.99215686 0.99607843 0.99215686 0.93333333 0.22745098 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.24313725
0.88235294 0.99215686 0.99215686 0.99215686 0.99215686 0.99607843
0.99215686 0.99215686 0.81568627 0.03137255 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0.81176471 0.99215686 0.99215686
0.99215686 0.99215686 0.63529412 0.60392157 0.38431373 0.81568627
0.99215686 0.29019608 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0.75686275 0.99215686 0.99215686 0.86666667 0.4
0.01960784 0. 0. 0.13333333 0.99215686 0.8745098
0.07058824 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.92156863
0.99215686 0.99215686 0.76862745 0. 0. 0.
0.01176471 0.72156863 0.99215686 0.80784314 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0.92156863 0.99215686 0.99215686
0.9254902 0.69803922 0.56078431 0.43137255 0.74117647 0.99215686
0.99215686 0.54509804 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0.92156863 0.99215686 0.99215686 0.99215686 0.99215686
0.99215686 0.99607843 0.99215686 0.99215686 0.99215686 0.43921569
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.87843137
0.99215686 0.99215686 0.99215686 0.99215686 0.99215686 0.99607843
0.99215686 0.99215686 0.99215686 0.16862745 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0.41960784 0.99215686 0.99215686
0.99215686 0.99215686 0.99215686 0.99607843 0.99215686 0.99215686
0.99215686 0.57254902 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0.32941176 0.7372549 0.83137255 0.7372549
0.7372549 0.50588235 0.37254902 0.62352941 0.99607843 0.9254902
0.11764706 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0.04313725 0. 0. 0.
0. 0.59607843 0.99215686 0.99215686 0.45882353 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0.55294118 0.94117647
0.99215686 0.92156863 0.11372549 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0.28627451 0.95686275 0.99215686 0.99215686 0.75686275
0.0627451 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0.2745098 0.96862745
0.99215686 0.99215686 0.99215686 0.23529412 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0.28627451 0.94509804 0.99607843 0.99215686 0.99215686
0.83137255 0.03921569 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0.15686275 0.94901961
0.99215686 0.99607843 0.99215686 0.99215686 0.32941176 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0.44313725 0.99215686 0.99215686 0.99607843
0.81960784 0.11764706 0.01176471 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0.41568627 0.99215686 0.99215686 0.96470588 0.28627451 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0.05882353 0.88235294
0.99215686 0.19215686 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. ]
y_train, y_test 도 네트워크에 맞게 변형한다.
from tensorflow.keras.utils import to_categorical
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
utils 모듈에 있는 to_categorical 메서드를 사용하여 레이블 숫자가 들어있는 벡터를 하나가 1이고 나머지가 0인 벡터인 one-Hot 벡터로 변환한다. 예를 들어, 25168번째 데이터의 경우 9번째가 1이라고 나오므로, 해당 데이터의 레이블은 9이다.
# One-Hot Vector for y_train = 25168 representing the number 9
# The nth-digit will be represented as a vector which is 1 in the nth dimensions.
y_train[25168,:]
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 1.], dtype=float32)
네트워크 구축
Sequential API 를 사용해서 다층 신경망을 구축한다.
from tensorflow.keras.models import Sequential
model = Sequential()
Dense 레이어를 사용해서 모든 입력이 모든 뉴런과 결합된 층인 완전연결 계층을 추가한다. Sequential API의 add 메서드를 사용해서 다음과 같이 중간층을 추가할 수 있다. 여기서 units 은 출력될 뉴런의 수, input_shape 는 입력 텐서의 형태, 그리고 activation 은 활성화 함수의 종류를 의미한다.
from tensorflow.keras.layers import Dense
model.add(
Dense(
units=64,
input_shape=(784,),
activation='relu'
)
)
즉, 아래 이미지에서 입력층과 은닉층을 연결하는 코드이다.
마지막으로 Dense 레이어를 한 층 더 추가하여 은닉층과 결과층을 연결해보자. 0에서 9까지의 숫자 중 하나를 결과로 출력하므로 출력차원(units)을 10으로 지정한다. 2층 이후에는 케라스가 input_shape 를 자동으로 계산해주므로 여기서는 생략한다.
model.add(
Dense(
units=10,
activation='softmax'
)
)
구축한 모델의 학습
compile 메서드의 인수중 loss는 교차 엔트로피(2개의 확률 분포 사이에 정의된 척도)를 나타내는 것으로, 이 값이 작아지도록 학습한다. 손글씨 분류는 다중분류에 해당하므로 categorical_crossentropy 를 사용할 수 있다. fit 메서드의 인수중 validation_split 은 학습용 데이터 중에서 검증용 데이터로 이용하는 비율. 여기서는 0.2로 지정하고 있으므로 학습용 데이터 중에서 80%의 데이터로 학습하고, 나머지 20%로 검증한다.
from tensorflow.keras.callbacks import TensorBoard
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
tsb=TensorBoard(log_dir='./logs')
history_adam=model.fit(
x_train,
y_train,
batch_size=32,
epochs=20,
validation_split=0.2,
callbacks=[tsb]
)
에폭수를 20 으로 지정하여 학습하면 다음과 같은 결과를 얻는다.
여기서 사용된 acc, loss, val_accuracy, val_loss 는 다음을 의미한다.
-
acc : 구축한 모델의 학습용 데이터에 대한 분류 정확도
-
loss구축한 모델의 학습용 데이터에 대한 손실함수의 값
-
val_accuracy : 구축한 모델의 검증용 데이터에 대한 분류 정확도
-
val_loss : 구축한 모델의 검증용 데이터에 대한 손실함수의 값
Epoch 1/20
2/1500 [..............................] - ETA: 3:37 - loss: 2.3679 - accuracy: 0.0938WARNING:tensorflow:Method (on_train_batch_end) is slow compared to the batch update (0.139502). Check your callbacks.
1500/1500 [==============================] - 4s 3ms/step - loss: 0.3353 - accuracy: 0.9063 - val_loss: 0.1911 - val_accuracy: 0.9452
Epoch 2/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.1695 - accuracy: 0.9502 - val_loss: 0.1430 - val_accuracy: 0.9575
Epoch 3/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.1236 - accuracy: 0.9629 - val_loss: 0.1258 - val_accuracy: 0.9633
Epoch 4/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0968 - accuracy: 0.9705 - val_loss: 0.1183 - val_accuracy: 0.9653
Epoch 5/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0780 - accuracy: 0.9768 - val_loss: 0.1087 - val_accuracy: 0.9684
Epoch 6/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0654 - accuracy: 0.9802 - val_loss: 0.1083 - val_accuracy: 0.9671
Epoch 7/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0555 - accuracy: 0.9830 - val_loss: 0.1059 - val_accuracy: 0.9677
Epoch 8/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0469 - accuracy: 0.9859 - val_loss: 0.0967 - val_accuracy: 0.9710
Epoch 9/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0403 - accuracy: 0.9881 - val_loss: 0.1140 - val_accuracy: 0.9673
Epoch 10/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0354 - accuracy: 0.9897 - val_loss: 0.1005 - val_accuracy: 0.9718
Epoch 11/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0309 - accuracy: 0.9909 - val_loss: 0.1014 - val_accuracy: 0.9715
Epoch 12/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0265 - accuracy: 0.9923 - val_loss: 0.1041 - val_accuracy: 0.9716
Epoch 13/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0230 - accuracy: 0.9936 - val_loss: 0.1108 - val_accuracy: 0.9707
Epoch 14/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0199 - accuracy: 0.9945 - val_loss: 0.1133 - val_accuracy: 0.9712
Epoch 15/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0186 - accuracy: 0.9942 - val_loss: 0.1088 - val_accuracy: 0.9729
Epoch 16/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0156 - accuracy: 0.9957 - val_loss: 0.1246 - val_accuracy: 0.9712
Epoch 17/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0142 - accuracy: 0.9958 - val_loss: 0.1284 - val_accuracy: 0.9700
Epoch 18/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0133 - accuracy: 0.9959 - val_loss: 0.1193 - val_accuracy: 0.9724
Epoch 19/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0108 - accuracy: 0.9971 - val_loss: 0.1228 - val_accuracy: 0.9722
Epoch 20/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.0110 - accuracy: 0.9968 - val_loss: 0.1182 - val_accuracy: 0.9732
참고링크
pages.databricks.com/rs/094-YMS-629/images/Keras%20MNIST%20CNN.html