인공신경망 ( ANN ) #3 MNIST 이미지 인식 ( 분류/추론/순전파 )
ANN에서 문제를 해결하는 방식은 두 단계로 이루어져 있다.
- 학습 : 학습 데이터를 이용해 가중치 매개변수를 학습한다. (지도 학습, SL(Supervised Learning))
- 추론 : 학습한 가중치 매개변수를 이용해 입력 데이터에 대한 결과를 추측한다.
MNIST 데이터셋 인식
img -> numpy array 변환
넘파이 배열로 저장해 놓았던 이미지 파일을 불러와 이미지로 출력할 때는 다음과 같이 사용한다.
```c
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
img = x_train[0]
label = t_train[0]
img = img.reshape(28, 28)
pil_img = Image.fromarray(np.uint8(img))
pil_img.show()
MNIST는 60000장의 훈련 이미지를 제공한다고 했다.
x_train.shape는 flatten=True인 경우 60000x784이고 flatten=False인 경우 60000x1x28x28이다.
즉 x_train의 각 row가 하나의 이미지 데이터를 보관하고 있으며 각 요소는 이미지의 픽셀 값이다.
그래서 x_train[0]은 60000장의 이미지 중 첫번째 이미지다.
label은 그 이미지에 대응되는 숫자 값이다. ( 필기체 5의 라벨은 5다. )
784개의 원소로 이루어진 1차원 배열이든, 1x28x28이든 이미지로 출력하려면 28x28로 reshape해야한다.
전처리(pre-processing), 정규화(normalization)
normalize=True이면 0~255 범위인 각 픽셀의 값을 0.0~1.0 범위를 갖도록 255로 나눈다.
입력 데이터에 특정 변환을 가하는 것을 전처리(pre-processing)라고 하고, 위와 같이 데이터를 특정 범위로 변환하는 전처리를 정규화(normalization)이라 한다. 즉 위에서는 전처리 작업으로 정규화를 수행했다.
신경망 추론 ( 분류 / 순전파forward propagation )
MNIST 데이터셋을 이용해 추론을 수행하는 신경망을 입력층 뉴런은 784개, 출력층 뉴런은 10개로 구성한다.
은닉층은 임의로 구성해도 좋다.
입력층 뉴런이 784개인 이유는 이미지 데이터 픽셀 수가 784이기 때문이다.
왜 이미지 픽셀 수만큼 입력층 뉴런이 존재해야 하냐면, 이미지 하나가 입력되면, 각각의 픽셀 데이터에 가중치를 곱한 결과를 종합해 출력층에서 정답을 찾아내야 하기 때문.
이미지 하나를 분석해서 분류해야 하는 작업이기 때문에, 입력층 뉴런의 수는 이미지 하나의 속성을 입력 받을수 있을 만큼 존재해야 한다.
분류 작업에서 입력층 뉴런의 수는 분류해야 하는 단일 입력이 가지고 있는 원소의 수 만큼 존재해야 하며 출력층 뉴런의 수는 분류해야 하는 가짓수 만큼 존재해야 한다.
추론 처리에서는 시험 이미지, 시험 레이블인 x_test, t_test(10,000개)를 사용한다.
```c
x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
p = np.argmax(y)
if p == t[i]:
accuracy_cnt += 1
```
배치(batch) 처리
위 코드에서는 for문을 이용해 10000개의 이미지를 한장 씩 predict()로 넘기게 된다.
이미지 여러장을 한꺼번에 입력해 일괄적으로 묶어 한꺼번에 처리(batch)하면 더 효율적으로 처리할 수 있다.
1x784 -> 1x10이었던 기존 코드를 100x784 -> 100x10으로 묶어서 처리하는 코드는 다음과 같다.
```python
x, t = get_data()
network = init_network()
batch_size = 100
accuracy_cnt = 0
for i in range(0, len(x), batch_size):
x_batch = x[i:i+batch_size]
y_batch = predict(network, x_batch)
p = np.argmax(y_batch, axis=1)
accuracy_cnt += np.sum(p == t[i:i+batch_size])
```
맨 아래 두줄에서 브로드캐스트가 동작했다.
range(start, end, step)과 slice로 간단히 처리한 부분이 눈에 띈다.
axis=1을 꼭 지정해 주어야 한다. 이는 출력인 100x10 배열 y_batch에서 1번째 차원을 구성하는 각 원소에서 최댓값의 인덱스를 찾도록 한 것이다.
다음과 같은 행렬이 있을 때, 배열의 차수는 배열안에 배열이 있으니 이차원이다.
즉, 행렬은 이차원 배열이다.
내부에 있는 [0.1 0.3 0.5]같은 배열이 1번째 차원을 구성하는 각 원소이므로, 이 원소(일차원 배열)에서 최댓값의 인덱스를 찾는 것이다.
아무튼 이래저래 이해가 안되면, 각 row에서 최댓값의 인덱스를 구한다고 하면 이해가 쉽다.
각 row에서 최댓값의 인덱스를 뽑아 일차원 배열로 만들고, 이를 레이블 배열 t와 비교한다.
사실 그냥 x를 넘겨도 된다. 데이터의 개수가 적으면 이게 더 빠를 수도 있다.
```python
y = predict(network, x)
p = np.argmax(y, axis=1)
accuracy_cnt += np.sum(p == t)
```
근데 x가 1만개라서 그런 것 뿐이지, x가 임계치를 넘어가면 수용이 안되니까 배치 처리해야한다.
하드웨어에 따라 다르겠지만 가상머신에서 돌리는 것도 천 단위까지는 배치로 묶어서 전달할 수록 더 빨라진다.
어차피 배치 처리의 이점을 못볼 만큼 작은 데이터면 배치 처리 하나 안하나 비슷한 시간이 나오므로 그냥 배치 처리 하는게 이식성이 좋다.
'Machine Learning > Theory' 카테고리의 다른 글
인공신경망 ( ANN ) #4-2 학습 ( 미분, 기울기, 경사법, 신경망 학습 과정 ) (4) | 2017.03.18 |
---|---|
인공신경망 ( ANN ) #4-1 학습 ( 손실함수, 오차함수 ) (5) | 2017.03.16 |
인공신경망 ( ANN ) #2 신경망 구조, softmax 함수 (0) | 2017.03.12 |
인공신경망 ( ANN, Artificial Neural Network ) #1 활성화 함수 (6) | 2017.03.12 |
퍼셉트론( perceptron ) (0) | 2017.03.12 |