단일 계층 신경망을 만들고 손글씨 숫자를 인식
신경망과 딥러닝 온라인 도서 홈페이지
http://neuralnetworksanddeeplearning.com
텐서플로의 공식 튜토리얼을 기반으로 설명
https://www.tensorflow.org/versions/master/tutorials/mnist/beginners/
MNIST 데이터셋: 훈련용 55000개 및 테스트 1만개로 이루어진 손글씨 숫자의 흑백 이미지 데이터
http://yann.lecun.com/exdb/mnist/
흑백이미지는 20 X 20 픽셀로 정규화됨. 이미지 중심을 계산하여 28 X 28 픽셀 크기의 프레임 중앙에 위치.
지도학습: 그 이미지가 어떤 숫자인지를 나타내는 레이블(label) 정보가 함께 있음.
이미지를 입력받아 각 카테고리(0~9)에 대한 점수를 원소로 갖는 벡터 형태로 결과를 출력.
오차를 줄이기 위해 가중치(weight) 매개변수를 조정.
데이터셋 다운로드: input_data.py 스크립트
이 스크립트가 현재 텐서플로우에 통합됨. 다음처럼 import하여 사용가능
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
Extracting MNIST_data/train-images-idx3-ubyte.gz Extracting MNIST_data/train-labels-idx1-ubyte.gz Extracting MNIST_data/t10k-images-idx3-ubyte.gz Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
현재 디렉터리 하위에 MNIST_data 디렉터리가 생성. 자동으로 필요한 데이터가 다운로드됨.
위 코드를 통해 mnist.train, mnist.test를 얻게 됨.
mnist.train: 훈련데이터, mnist.test: 테스트데이터
mnist.train.image: 훈련이미지, mnist.train.labels: 훈련레이블
# http://tneal.org/post/tensorflow-ipython/TensorFlowMNIST/ 참조
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.cm as cm
def get_num(label):
for i in range(len(label)):
if label[i] == 1.0:
return i
return -1
def print_image(image,x,y):
s = ""
for iy in range(y):
for ix in range(x):
s += "%1.1f" % (image[iy*x + ix]) + " "
s += "\n"
print(s)
def show_train_data(i):
print('Image')
tmp = mnist.train.images[i]
print_image(tmp,28,28)
tmp = tmp.reshape((28,28))
plt.imshow(tmp, cmap = cm.Greys)
plt.show()
print('Label ')
print(get_num(mnist.train.labels[i]), mnist.train.labels[i])
#for i in range(100):
# print("INDEX ", i)
# show_train_data(i)
show_train_data(16)
Image 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1 0.1 0.5 0.3 0.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.2 0.7 1.0 1.0 1.0 1.0 0.9 0.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7 1.0 1.0 1.0 0.7 0.6 0.7 1.0 0.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7 1.0 0.6 0.3 0.0 0.0 0.0 0.0 0.7 1.0 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.2 1.0 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.2 1.0 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3 1.0 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.6 1.0 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1 1.0 1.0 0.3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.2 1.0 0.7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.2 0.9 1.0 0.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1 0.4 0.8 0.8 0.8 1.0 1.0 1.0 0.5 0.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.7 0.4 0.0 0.0 0.2 0.3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.2 0.8 1.0 0.9 0.6 0.4 1.0 1.0 0.9 0.3 0.2 0.7 0.9 1.0 1.0 0.5 0.5 0.9 0.6 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3 0.8 1.0 0.6 0.1 0.1 0.8 1.0 0.9 0.2 0.0 0.0 0.0 0.1 0.4 1.0 1.0 0.9 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.6 1.0 0.8 0.5 0.9 0.9 1.0 0.9 0.2 0.0 0.0 0.0 0.0 0.0 0.0 0.1 0.5 0.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.9 1.0 1.0 1.0 1.0 0.9 0.4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.4 1.0 0.7 0.7 0.4 0.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Label 2 [ 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
행렬에서 각 원소는 0과 1 사이의 값으로 픽셀의 검은 정도를 표현.
레이블 숫자에 대응되는 위치에 1의 값을 가지고 그 외에는 0 값을 가짐.
2 이미지 벡터는 [0, 0, 1, ..., 0]
import tensorflow as tf
tf.convert_to_tensor(mnist.train.images).get_shape()
TensorShape([Dimension(55000), Dimension(784)])
첫 번째(D0) 차원은 각 이미지에 대한 인덱스(이미지는 55000개), 두 번째(D1) 차원은 이미지 안의 픽셀 수(28 X 28).
tf.convert_to_tensor(mnist.train.labels).get_shape()
TensorShape([Dimension(55000), Dimension(10)])
레이블은 0에서 9까지 구성된 숫자를 표현하기 위해 두 번째(D1) 차원에 10개의 원소를 가짐.
'사각형'과 '원' 레이블이 달린 점들이 2차원 평면에 있음.
일반적인 근사 방법은 두 그룹을 나누는 선을 긋고 이를 분류의 기준으로 삼음.
각 뉴런(neuron)은 가중치 W(입력 데이터 X와 같은 차원을 가짐)와 오프셋 b(bias, 편향)를 학습해서 어떻게 점들을 분류할 지 학습.
활성화 함수
http://www.aistudy.co.kr/cognitive/martindale_neural.htm#_bookmark_330c048
뉴런의 기능
z=b+∑ixiWi시그모이드 함수: 가중치 합을 계산하고 나면 z에 저장된 결과를 '0' 또는 1'로 바꿀 함수가 필요.
단일 계층 신경망(single-layer neural network): 계층이 하나
다중 계층 신경망(multi-layer neural network): 입력계층, (결과값을 내는)출력계능, (여러 개의 중간계층)은닉계층으로 구성.
소프트맥스 함수(softmax function): 두 가지 이상의 클래스로 데이터를 분류하고 싶을 때 사용하는 시그모이드 함수의 일반화된 형태의 함수.
손글씨 숫자를 인식하는 것엔 어느 정도 불확실한 부분이 있음.
확률분포(probability distribution)를 보면 예측을 얼마나 신뢰할 수 있을지 알 수 있음.
출력 벡터: 10개의 확률 값을 가짐. 각 값은 0~9 숫자에 대응되며, 확률의 전체 합은 1.
소프트맥스 함수 처리 2단계
MNIST 숫자 이미지를 학습한 결과 이미지(출처: 텐서플로 공식 튜토리얼)
https://www.tensorflow.org/versions/master/images/softmax-weights.png
붉은색은 잘 맞지 않는 부분(음의 가중치), 푸른색은 잘 들어맞는 부분(양의 가중치)
입력 x가 주어졌을 때 클래스 i에 대한 근거
i는 클래스(0~9까지 숫자), j는 이미지의 픽셀들의 합계를 내기 위한 인덱스
∑jWi,jxj+bi소프트맥스 함수 사용하여 근거들의 합을 예측 확률 y로 산출
y = softmax(evidence)
softmax(x)i=exp(xi)∑jexp(xj)=exi∑jexjimport tensorflow as tf
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
W는 784행x10열 구조의 모두 0으로 이루어진 텐서. b는 10행 구조의 모두 0으로 이루어진 텐서.
x = tf.placeholder("float", [None, 784])
MNIST 이미지를 784개의 실수 벡터로 저장하는 데 사용.
None은 학습 과정에 사용될 이미지의 총 개수.
y = tf.nn.softmax(tf.matmul(x, W) + b)
이미지 벡터 x와 가중치 행렬 W를 곱하고 b를 더한 텐서를 소프트맥스 함수에 입력.
교차엔트로피
모델이 얼마나 나쁜지를 나타내는 함수를 최소화하는 W와 b를 얻을 때 사용하는 함수
−∑iy′ilog(yi)y는 예측된 확률분포. y'은 레이블이 달린 훈련 데이터로부터 얻은 실제 분포.
두 분포(y와 y')가 같을 때 최솟값을 얻음.
y_ = tf.placeholder("float", [None, 10])
y_ : 실제 레이블을 담고 있는 placeholder
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
cross_entropy를 구하기 위해
tf.log()를 사용해 y의 각 원소 로그 값을 구함.
y_ 의 각 원소와 곱함.
텐서의 모든 원소를 더함.
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
역전파(backpropagation) 알고리즘
가중치 W를 재계산할 때, 출력 값으로부터 얻은 오차를 뒤쪽으로 전파.
오차를 줄이기 위해 루프 반복마다 W를 조금씩 변경.
텐서플로가 모델을 훈련시키기 위해 적절한 비용함수의 기울기를 찾는 최적화 알고리즘. 데이터 그래프를 실행.
학습속도 0.01과 경사 하강법 알고리즘을 사용하여 크로스 엔트로피를 최소화하는 역전파 알고리즘을 사용.
sess = tf.Session()
시스템이 사용 가능한 디바이스(CPU 또는 GPU)에서 텐서플로의 연산을 실행 가능.
sess.run(tf.initialize_all_variables())
모든 변수를 초기화하고 세션을 시작.
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
모델 훈련을 시작. 첫 번째 줄은 훈련 데이터로부터 무작위로 100개를 추출.
placeholder를 사용하여 100개의 샘플 데이터를 주입.
텐서플로의 자동화된 미분 기능을 사용하여 예측 모델의 계산 구조를 정의하고 목표함수와 연결한 후 데이터를 넣어줌.
minimize() 메서드가 실행될 때 손실함수(loss function)와 연관된 변수들을 알아서 인식하고 각각에 대해 기울기 계산.
미분계산 구현 소스. (버전 변경해서 봐야 자세한 내용이 확인 가능)
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/gradients.py
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
tf.argmax(y,1)은 입력 이미지에 대해 가장 높은 확률을 가진 레이블을 리턴.
tf.argmax(y_,1)은 실제 레이블.
tf.equal 메서드를 이용하여 예측 값과 실제 레이블이 같은지 비교.
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
정확도(accuracy)를 구함.
불리언을 수치 값(부동소수점)으로 변경한 뒤 평균을 구하면 그 값이 정확도가 됨.
print(sess.run(accuracy, feed_dict={x: mnist.test.images,
y_: mnist.test.labels}))
0.9175
feed_dict 매개변수로 mnist.test를 전달하여 테스트 데이터셋에 대한 정확도를 계산
# redneuronalsimple.py
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
import tensorflow as tf
x = tf.placeholder("float", [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x,W) + b)
y_ = tf.placeholder("float", [None, 10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
sess = tf.Session()
sess.run(tf.initialize_all_variables())
s = 0.0
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x:batch_xs, y_:batch_ys})
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
s += sess.run(accuracy, feed_dict={x: mnist.test.images,
y_: mnist.test.labels})
print(s / 1000.)
Extracting MNIST_data/train-images-idx3-ubyte.gz Extracting MNIST_data/train-labels-idx1-ubyte.gz Extracting MNIST_data/t10k-images-idx3-ubyte.gz Extracting MNIST_data/t10k-labels-idx1-ubyte.gz 0.895401800722