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: 훈련레이블
import tensorflow as tf
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])
텐서플로 플레이스 홀더를 정의.
x_image = tf.reshape(x, [-1, 28, 28, 1])
입력 데이터를 원래 이미지 구조로 재구성.
4D 텐서. 마지막 차원은 이미지의 컬러 채널로 여기서는 1.
목적: 테두리, 선, 색 등 이미지의 시각적 특징(characteristic)이나 특성(feature)을 감지
입력 데이터가 첫번째 은닉 계층의 뉴런에 완전 연결되어(fully connected)있지 않음.
은닉 계층의 각 뉴런은 입력 계층의 윈도(window) 영역(이 예시는 5x5)과 연결.
윈도 영역이 전체 입력 계층을 훑고 지나가면서 (여기서는) 24x24 크기의 은닉 계층을 만들게 됨.
스트라이드(stride): 윈도우 영역이 한 번에 얼만큼 움직일 지 결정하는 매개변수.
패딩(padding): 0(또는 다른 값)으로 이미지의 바깥 테두리를 채움. 체울 테두리의 크기를 지정하는 매개변수.
http://cs231n.github.io/convolutional-networks/
스탠퍼드의 강의문서: 매개변수에 대한 더 자세한 내용이 실려있음.
윈도(window) 영역(이 예시는 5x5)에 대한 가중치 행렬 W, 편향 b가 필요.
은닉 계층의 모든 뉴런이 행렬 W, 편향 b를 공유함. (24x24(576)개의 뉴런이 같은 W,b를 사용.)
커널(Kernel), 필터(filter): 공유 행렬 W와 편향 b
https://docs.gimp.org/en/plug-in-convmatrix.html
GIMP 매뉴얼의 예제문서: 합성곱이 어떻게 작동하는지?
하나의 가중치 행렬과 하나의 편향으로 하나의 커널을 정의.
감지하고 싶은 각 특징에 한 개씩 여러 개의 커널을 사용하는 것이 좋음.
합성곱 계층(convolution layer): 첫 번째 은닉 계층은 여러 개의 특징 맵으로 구성. (이 예시는 32개 커널 사용)
풀링 계층(pooling): 합성곱 계층의 출력 값을 단순하게 압축하고 합성공 계층이 생산한 정보를 컴팩트한 버전으로 만들어줌.
합성곱 계층 뒤에 따라오는 것이 일반적.
맥스 풀링(max-polling): 2x2영역에서 가장 큰 값을 선택해서 정보를 다시 압축.
24x24 합성곱의 결과를 2x2 영역으로 분할하면 12x12 개의 조각에 해당하는 12x12 크기의 맥스 풀링 계층이 만들어짐.
풀링을 하는 이유
local invariance 측면에서 강한 구조를 만들기 위함.
어떤 물체를 인식한다고 했을 때, 그 물체가 image상 어디에 위치하더라도 잘 인식해낼 수 있게 하는 과정 중 하나
https://www.tensorflow.org/versions/master/tutorials/mnist/pros/
텐서플로 웹사이트에 있는 전문가를 위한 MNIST 예제문서를 참조
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
가중치는 임의잡음(random noise)으로 초기화, 편향은 0.1을 갖도록 초기화.
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
일부 버려진 정규분포로부터 임의의 값을 출력합니다. 특정 평균값과 표준 편차로 정규 분포를 따르는 생성된 값은 지정한 평균의 2 표준편차보다 큰 값은 제외하며 이 값은 버려지고 다시 선택됩니다.
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
각 차원 방향으로 스트라이드를 1로 하고 패딩은 'SAME'으로 지정합니다. (출력이 입력과 같은 크기로 나오도록 합니다.)
padding='VALID'로 바꾸면 패딩을 하지 않고 출력이 나오게 됩니다. (출력데이터가 손실됩니다.)
https://www.tensorflow.org/versions/master/api_docs/python/nn/convolution#conv2d
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
풀링은 2x2 크기의 맥스 풀링을 적용.
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
윈도우 크기가 5x5인 32개 필터를 사용. [5, 5, 1, 32]인 가중치 행렬 W를 저장한 텐서를 정의.
처음 2개는 윈도우 크기. 세 번째는 컬러채널. 우리 예제는 1. 마지막은 얼마나 많은 특징을 사용할 지 정의.
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
print(h_conv1) # shape = (?, 28, 28, 32)
h_pool1 = max_pool_2x2(h_conv1)
print(h_pool1) # shape = (?, 14, 14, 32)
Tensor("Relu:0", shape=(?, 28, 28, 32), dtype=float32) Tensor("MaxPool:0", shape=(?, 14, 14, 32), dtype=float32)
렐루(Rectified Linear Unit, ReLU): 은닉셰층에서 거의 기본적으로 사용되는 활성화 함수.
max(0,x)를 리턴.
x_image에 대해 합성곱을 적용. 합성곱의 결과를 2D 텐서 W_conv1에 리턴.
여기에 편향을 더해 렐루 활성화 함수 적용.
출력 값을 구하기 위해 맥스 풀링을 적용.
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
5x5 윈도에 64개 필터를 갖는 두 번째 합성곱 계층을 만듬.
이전 계층의 출력 값의 크기(32)를 채널의 수로 넘김.
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
print(h_conv2) # shape = (?, 14, 14, 64)
h_pool2 = max_pool_2x2(h_conv2)
print(h_pool2) # shape = (?, 7, 7, 64)
Tensor("Relu_1:0", shape=(?, 14, 14, 64), dtype=float32) Tensor("MaxPool_1:0", shape=(?, 7, 7, 64), dtype=float32)
14x14 크기 행렬 h_pool1에 스트라이드 1로 5x5 윈도를 적용하여 합성곱 계층을 만듬.
맥스 풀링까지 거쳐 크기는 7x7이 됨.
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
마지막 소프트맥스 계층에 주입하기 위해 7x7 출력 값을 완전 연결 계층에 연결.
전체 이미지 처리를 위해 1024개의 뉴런을 사용.
첫 번째 차원: 7x7 크기의 64개 필터를 뜻함.
두 번째 차원: 임의로 선택한 뉴런의 개수. (여기서는 1024)
h_pool2_flat = tf.reshape(h_pool2, [-1, 7 * 7 * 64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
소프트맥스 함수는 이미지를 직렬화해서 벡터 형태로 입력.
가중치 행렬 W_fc1과 일차원 벡터를 곱하고 편향 b_fc1을 더한 후 렐루 활성화 함수를 적용.
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
드롭아웃(dropout, 중도탈락): 신경망에서 필요한 매개변수 수를 줄이는 것.
노드를 삭제하여 입력과 출력사이의 연결을 무작위로 제거.
뉴런이 제거되거나 그렇지 않을 확률은 코드로 처리하지 않고 텐서플로에 위임.
오버피팅(overfitting, 과적합)
아주 많은 뉴런을 사용한다면 매우 상세한 모델이 만들어짐.
임의의 잡음(혹은 오차)도 모델에 포함될 수 있음.
마지막 소프트맥스 계층 전에 tf.nn.dropout 함수를 사용하여 드롭아웃을 적용.
뉴런이 드롭아웃되지 않을 확률을 저장할 플레이스홀더를 만듬.
W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
소프트맥스 계층을 추가.
입력 이미지가 각 클래스(여기서는 0~9까지 숫자)에 속할 확률을 리턴. 이 확률의 전체 합은 1이 됨.
모델이 얼마나 잘 수행되는지 알기 위해서는 이전 장의 예제들이 했던 방식을 따라야 함.
경사 하강법 최적화 알고리즘 => ADAM 알고리즘
https://www.tensorflow.org/versions/master/api_docs/python/train/optimizers#AdamOptimizer
ADAM 최적화 알고리즘이 특별한 장점을 가지기 때문에 사용함.
드롭아웃 계층의 확률을 조절하는 추가 매개변수 keep_prob도 feed_dict 인수를 통해 전달.
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess = tf.Session()
sess.run(tf.initialize_all_variables())
for i in range(1000):
batch = mnist.train.next_batch(100)
if i % 100 == 0:
train_accuracy = sess.run(accuracy, feed_dict={x:batch[0], y_:batch[1], keep_prob: 1.0})
print("step %d, training accuracy %g" % (i, train_accuracy))
sess.run(train_step, feed_dict={x:batch[0], y_:batch[1], keep_prob: 0.5})
print("test accuracy %g" % sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
step 0, training accuracy 0.08 step 100, training accuracy 0.86 step 200, training accuracy 0.95 step 300, training accuracy 0.95 step 400, training accuracy 0.93 step 500, training accuracy 0.95 step 600, training accuracy 0.93 step 700, training accuracy 0.99 step 800, training accuracy 0.97 step 900, training accuracy 0.98 test accuracy 0.972
실행 모델은 99.2% 정확도를 보임.
많은 계층을 가진 네트워크는 훈련시간이 많이 걸리기 때문에
훈련 시간을 대폭 줄일 수 있는 CPU를 어떻게 사용하는지 다음에 설명.