레이블이 AI인 게시물을 표시합니다. 모든 게시물 표시
레이블이 AI인 게시물을 표시합니다. 모든 게시물 표시

2018년 1월 1일 월요일

ML 초보자를 위한 MNIST(MNIST For ML Beginners)(5)

출처 : https://www.tensorflow.org/get_started/mnist/beginners

이글은 영어 원본을 읽고 공부하면서 불필요한 내용 빼고 이해하기 쉽도록 적절히 내맘대로 작성해보았습니다. 이해가 잘못되어 원저자의 의도대로 번역이 안되어 있을 수도 있습니다. 이점 참고해서 읽어 주시면 고맙겠습니다


앞서 작성한 글
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(1)
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(2)
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(3)
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(4)


우리 모델 평가

우선 우리가 올바른 라벨을 소스 코드 어디에서 예측했는지 알아 보겠습니다. tf.argmax는 축을 따라 텐서에서 가장 높은 엔트리의 인덱스를 제공하는 매우 유용한 함수입니다. 예를 들어, tf.argmax (y, 1)는 우리 모델이 각 입력에 대해 가장 가능성이 있다고 생각하는 레이블(0~9 값)을 리턴하고, tf.argmax (y_, 1)는 실제 레이블(0~9 값)입니다. (y,y_의 의미 때문 y는 예측된 확율 분포이고, y_는 훈련데이터로부터 얻는 실제 분포임) tf.equal을 사용하여 예측값과 실제 레이블일치하는지 아래와 같이 확인할 수 있습니다.

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
correct_prediction는 우리에게 boolean 값의 리스트를 줍니다. 어떤 부분이 올바른지 판단하기 위해 부동 소수점 숫자로 캐스팅 한 다음 평균을 취합니다. 예를 들어 [True, False, True, True]는 [1,0,1,1]이되며 0.75가됩니다.

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
마지막으로 테스트 데이터에 대한 정확도를 계산해 봅시다.

print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
실제 실행 화면

(E:\Users\abc\Anaconda3) E:\work\ai\anaconda>python mnist_softmax.py
Extracting /tmp/tensorflow/mnist/input_data\train-images-idx3-ubyte.gz
Extracting /tmp/tensorflow/mnist/input_data\train-labels-idx1-ubyte.gz
Extracting /tmp/tensorflow/mnist/input_data\t10k-images-idx3-ubyte.gz
Extracting /tmp/tensorflow/mnist/input_data\t10k-labels-idx1-ubyte.gz
2018-01-01 09:38:20.311850: I C:\tf_jenkins\home\workspace\rel-win\M\windows\PY\36\tensorflow\core\platform\cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
0.919
이것은 약 92 % 입니다.

이것은 좀 나쁜편입니다. 우리가 아주 간단한 모델을 사용하고 있기 때문입니다. 몇 가지 작은 변화를 통해 97 %를 달성 할 수 있습니다. 최고의 모델은 99.7 % 이상의 정확도를 얻을 수 있습니다! 자세한 내용은 https://rodrigob.github.io/are_we_there_yet/build/classification_datasets_results 이 결과 목록을 참조하십시오.


중요한 것은 우리가 이 모델로 부터 튜토리얼을 배웠다는 것입니다. 그래도 이러한 결과에 대해 조금이라도 느껴지시면 다음 튜토리얼에서 더 잘 살펴보고 TensorFlow를 사용하여보다 정교한 모델을 작성하는 방법을 살펴보세요.


2017년 12월 25일 월요일

ML 초보자를 위한 MNIST(MNIST For ML Beginners)(4)


출처 : https://www.tensorflow.org/get_started/mnist/beginners

이글은 영어 원본을 읽고 공부하면서 불필요한 내용 빼고 이해하기 쉽도록 적절히 내맘대로 작성해보았습니다. 이해가 잘못되어 원저자의 의도대로 번역이 안되어 있을 수도 있습니다. 이점 참고해서 읽어 주시면 고맙겠습니다


앞서 작성한 글
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(1)
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(2)
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(3)

이 글은 앞서 작성한 글에 이어지는 글입니다.



훈련


우리는 훈련을 하기 위해서 모델이 충분히 좋은 것이 어떤 것인지 정의를 해야합니다. 실제로, 기계 학습에서 우리는 전형적으로 모델이 나쁜 것을 의미하는 것을 정의합니다. 우우리는 이것을 비용 또는 손실이라 부르며 모델이 원하는 결과와 얼마나 멀리 떨어져 있는지 나타냅니다. 우리는 오류를 최소화하려고 노력하며 오류 마진이 작을수록 모델이 좋습니다.
(정리하자면 모델에 데이터를 넣어 훈련을 해서 오류를 최소화 하도록 한다는 뜻입니다.)
모델의 손실을 결정하는 매우 일반적인 함수 중 하나 인 "교차 엔트로피 (cross-entropy)"라고 합니다.
교차 엔트로피는 다음과 같이 정의 됩니다.
여기서 y는 우리의 예측된 확률 분포이고, y'는 실제 분포 (숫자 레이블을 갖는 원 핫 벡터)입니다. 크로스 엔트로피는 우리의 예측이 실제 값을 묘사하는 데 얼마나 비효율적인지를 측정합니다.(말이 어렵습니다. ) 크로스 엔트로피에 대한 자세한 내용은이 튜토리얼의 범위를 벗어나지만 이해할만한 가치가 있습니다.
교차 엔트로피를 구현하려면 정답을 입력하기 위해 먼저 새로운 "placeholder"를 추가해야합니다
y_ = tf.placeholder(tf.float32, [None, 10])
그런 다음 교차 엔트로피 함수를 구현할 수 있습니다.
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
먼저, tf.log는 y의 각 원소의 로그값를 계산합니다. 다음으로, y_의 각 요소에 tf.log (y)의 해당 요소를 곱합니다. 그런 다음 tf.reduce_sum은 reduction_indices = [1] 매개 변수로 인해 y의 두 번째 차원에 요소들을 더합니다. 마지막으로 tf.reduce_mean은 배치의 모든 예제에 대한 평균을 계산합니다.
소스 코드에서는 수치적으로 불안정하기 때문에 이 공식을 사용하지 않았습니다.(수치적으로 불안정하다는 말은 이해하기가 난감하네요. ) 대신, 정규화되지 않은 로그에 tf.nn.softmax_cross_entropy_with_logits를 적용합니다
(예를 들어 tf.matmul (x, W) + b에서 softmax_cross_entropy_with_logits를 호출합니다.)
왜냐하면 더 수치적으로 안정된 함수가 softmax 활성화를 내부적으로 계산하기 때문입니다. 당신의 코드에서 tf.nn.softmax_cross_entropy_with_logits 를 사용하는것을 고려해 보세요.
소스 코드를 살펴보면 동일한 내용의 주석이 있습니다. 정리하자면,
-tf.reduce_sum(y_ * tf.log(tf.nn.softmax(y)), reduction_indices=[1]) 이 부분 대신 tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y) 이렇게 사용하라는 의미 입니다.

  # The raw formulation of cross-entropy,
  #
  #   tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.nn.softmax(y)),
  #                                 reduction_indices=[1]))
  #
  # can be numerically unstable.
  #
  # So here we use tf.nn.softmax_cross_entropy_with_logits on the raw
  # outputs of 'y', and then average across the batch.
  cross_entropy = tf.reduce_mean(
      tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))

여기에서 궁금한점이 생겼습니다. 수치적으로 안정화되었다는게 무엇인지... 참 알다가도 모를 일입니다. 그래서 원본 소스에서 softmax_cross_entropy_with_logits 를 사용하지 않고 reduce_sum 를 사용해서 결과를 살펴보았습니다. 결과는 크게 차이가 없는것 같았습니다. 전문가 분이 수치적으로 안정화 되어있다는 말을 그냥 믿어야 할것 같습니다.
이제 우리 모델이 하고자하는 것이 무엇인지 알았으므로 TensorFlow가 그렇게 하도록 훈련시키는 것은 매우 쉽습니다. TensorFlow는 계산의 전체 그래프를 알고 있기 때문에 그것은 변수가 최소화하도록 요청한 손실(loss 또는 error를 의미)에 효율적으로 결정하기 위해서 backpropagation (역전파) 알고리즘을 자동으로 사용할 수 있습니다.
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
위 경우, 학습 속도가 0.5 인 그래디언트 디센트(경사 하강)알고리즘을 사용하여 cross_entropy를 최소화하도록 TensorFlow에 요청합니다. 경사 하강법은 간단한 절차입니다. TensorFlow는 각 변수의 비용을 줄이는 방향으로 조금씩 옮깁니다. TensorFlow는 다른 많은 최적화 알고리즘도 제공하는데 한 줄 바꾸는것 만큼 간단합니다.
뒤쪽에서 Tensorflow에서 실제로 하는 것은, 역전파와 경사 하강를 구현하는 그래프에 새로운 작업을 추가하는 것입니다. 그리고 나서 그것이 동작을 다시 한번 해 줍니다. 그것이 동작을 할 때, 약간의 경사 하강 train을 하고, 손실을 줄이기 위해 변수를 약간 변경합니다. (원문 내용이 뭔가 계속적으로 동일하고 비슷한 말만 하고 있습니다.)
이제 이 모델을 InteractiveSession(상호 작용)으로 시작할 수 있습니다.
sess = tf.InteractiveSession()
먼저 생성한 변수를 초기화하는 작업을 생성해야 합니다.
InteractiveSession을 사용하는것은 기본 세션을 설정한다는 의미로 받아들이면 조금 쉽습니다. 그래서 아래와같이 run을 곧장 수행할 수가 있습니다.
tf.global_variables_initializer().run()
위 내용은 앞에서도 몇차례 등장했던 내용입니다.
InteractiveSession 은 https://www.tensorflow.org/api_docs/python/tf/InteractiveSession 링크에서도 확인이 가능합니다.
Session 사용 예제)
  sess = tf.Session()
  sess.run(tf.global_variables_initializer())
InteractiveSession 사용 예제)
  sess = tf.InteractiveSession()
  tf.global_variables_initializer().run()

자, 이제 훈련을 1000번 해 봅시다!
for _ in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
루프의 각각의 step(단계) 에서, 우리는 훈련 데이터셋에서 100개의 랜덤 데이터 포인트 batch를 얻습니다. feed_dict에 값을 넣어 placeholders의 값(x, y_)을 변경하여 train_step(위에서 언급한 train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy))을 실행합니다. x,y_는 placeholder로 외부에서 값을 변경하기 위한 변수입니다.
참고로 앞에서 x,y_는 아래와 같이 정의 하였습니다.
  x = tf.placeholder(tf.float32, [None, 784])
  y_ = tf.placeholder(tf.float32, [None, 10])

무작위 데이터의 작은 일괄(batch) 처리를 사용하는 확률적 훈련 - 위 경우(mnist.train.next_batch(100) 처럼 사용)에는 확률적 경사 하강이라고 합니다. 이상적으로, 우리는 우리가 해야 할 일에 대해 모든 훈련 단계에 대해서 전체 데이터를 사용하면 좋지만, 비용이 많이 듭니다. 그래서, 대신 매번 다른 부분 집합을 사용합니다. 이렇게 하는 것은 저렴하고 많은 이점을 가지고 있습니다.

2017년 12월 17일 일요일

ML 초보자를 위한 MNIST(MNIST For ML Beginners)(3)


출처 : https://www.tensorflow.org/get_started/mnist/beginners

이글은 영어 원본을 읽고 공부하면서 불필요한 내용 빼고 이해하기 쉽도록 적절히 내맘대로 작성해보았습니다. 이해가 잘못되어 원저자의 의도대로 번역이 안되어 있을 수도 있습니다. 이점 참고해서 읽어 주시면 고맙겠습니다


앞서 작성한 글
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(1)
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(2)

이 글은 앞서 작성한 글에 이어지는 글입니다.


회귀 분석의 구현

파이썬에서 효율적으로 수치적인 처리를 하려면 NumPy 같은 라이브러리를 사용하게됩니다. NumPy는 행열 계산을 효과적으로 할 수 있지만 python으로 돌아오는데 많은 오버헤드가 있습니다.
TensorFlow 에서도 행열 연산을 외부에서 처리하는데, 그러나 이 오버헤드를 줄이기 위한 처리가 되어있습니다.

TensorFlow를 사용하기위해서 우리는 임포트 해야합니다. 아래 참고
import tensorflow as tf

x = tf.placeholder(tf.float32, [None, 784])

x는 runtime 중에 외부에서 데이터를 변경하기 위해서 사용할것이라 placeholder로 만들었습니다. placeholder설명은 아래 링크를 참고 바랍니다.
https://www.tensorflow.org/versions/r0.12/api_docs/python/io_ops/placeholders
placeholder는 인자는 아래와 같습니다.
tf.placeholder(dtype, shape=None, name=None)
https://swlock.blogspot.com/2017/11/getting-started-with-tensorflow2.html
우리는 많은 MNIST 이미지를 입력 할 수 있기를 원합니다. 각각의 이미지는 784개의 실수 벡터입니다. 2차원 텐서의 부동 소수점 숫자로 표현하고 [None, 784] 모양을 사용합니다. 여기서 None은 어떤 크기가 가능하다는 뜻입니다. 학습 과정에 사용될 이미지의 총 갯수가 될 됩니다.

우리는 또한 모델을 위해 가중치와 바이어스를 필요로 합니다. tf.Variable 함수를 사용하여 생성하였습니다. 기계 학습 어플리케이션의 경우 일반적으로 모델 매개 변수가 Variables입니다.
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
여기에서 모두 0으로 이루어진 상수 텐서로 초기값을 넣었습니다. W, b 은 학습해서 값이 들어가기 때문에 초기값이 어떤 값이던 관계는 없습니다.

W는 10개 숫자 클래스에 대해 이미지 벡터 784개 픽셀과 곱셈을 하기 위한 크기를 가지고 있으며 ([784, 10] 구조를 가짐) , b가 더해진 후에 evidence를 구성할 텐서가 만들어 집니다. (b는 [10] 구조를 가짐)
이제 모델을 아래와 같이 구현할 수 있습니다.
y = tf.nn.softmax(tf.matmul(x, W) + b)
먼저 x에 W를 곱해서 tf.matmul (x, W)라는 표현식을 만든다.
https://www.tensorflow.org/api_docs/python/tf/matmul

이것은 방정식에서 Wx가있는 방정식을 곱했을 때 뒤집 힙니다. 이건 제가 볼때 아마도 행열의 곱셈과 관계가 있습니다, W[784,10] 구조에 x[None,784]를 곱하면 안되기 때문에 x[None,784] * W[784,10] 이런식으로 곱해주어야 합니다.
그런 다음 b를 추가하고 마지막으로 tf.nn.softmax를 적용합니다.

몇 줄의 짧은 설정만으로도 모델을 정의하는 데 한 줄이 걸렸습니다. 이는 TensorFlow가 softmax 회귀를 쉽게 만들 수 있도록 설계 되었기 때문이 아닙니다. 기계 학습 모델에서 물리 시뮬레이션에 이르기까지 다양한 종류의 수치 계산을 설명하는 매우 유연한 방법입니다. 한 번 정의 된 모델은 컴퓨터의 CPU, GPU, 심지어 휴대폰까지 다른 장치에서 실행할 수 있습니다!


2017년 12월 9일 토요일

ML 초보자를 위한 MNIST(MNIST For ML Beginners)(2)


출처 : https://www.tensorflow.org/get_started/mnist/beginners

이글은 영어 원본을 읽고 공부하면서 불필요한 내용 빼고 이해하기 쉽도록 적절히 내맘대로 작성해보았습니다. 이해가 잘못되어 원저자의 의도대로 번역이 안되어 있을 수도 있습니다. 이점 참고해서 읽어 주시면 고맙겠습니다


앞서 작성한 글
ML 초보자를 위한 MNIST(MNIST For ML Beginners)(1)


이 글은 앞서 작성한 글에 이어지는 글입니다.



Softmax 회귀

MNIST에서 각각의 이미지는 0~9사이의 손으로 씌여진 숫자인것을 알고 있습니다. 그래서 주어진 이미지가 될 수 있는것은 10가지가 됩니다. 우리는 이미지를 보고 각 숫자가 될 확률을 줄 수 있기를 원합니다. 예를들어 우리 모델이 9인 사진을 보고 그것이 9라는 확률이 80%이고, 8일 확률(왜냐하면 위쪽 때문에 8,9는 위쪽 모양이 동일해서) 5%를 그리고 다른 숫자일 확률은 작다고 줄 수 있습니다. 손글씨라서 불확실한 부분이 있기 때문에 100% 확신을 얻기는 어렵습니다.
이것은 softmax 회귀가 자연스럽고 단순한 고전적인 사례입니다. 여러 다른 것들 중 하나 인 객체에 확률을 할당하려 softmax를 사용하면 0과 1 사이의 값 확률을 얻게되고, 모든 확률의 합계는 1이 됩니다. 나중에 더 정교한 모델에서, 마지막 단계는 softmax의 레이어로 구성 될 것입니다.
softmax 회귀는 두 단계로 이루어집니다. 먼저 특정 클래스에 입력의 근거(evidence)를 추가 한 다음 해당 근거(evidence)를 확률로 변환합니다.
주어진 이미지가 특정 클래스에 있다는 근거(evidence)를 계산하기 위해 픽셀 강도의 가중 합을 계산합니다. 높은 강도를 갖는 픽셀이 해당 클래스에있는 이미지에 대한 반하는 근거(evidence)라면 가중치는 음수이고, 그것이 유리한 근거(evidence)라면 양수입니다.
다음 도표는 각 클래스에 대해 학습된 가중치를 보여 줍니다. 빨간 색은 음의 가중치를 나타내고 파란 색은 긍정적인 가중치를 나타냅니다.


바이어스라고 불리우는 추가 evidence를 더합니다. 기본적으로 입력은 어떤것들과 독립적일 가능성이 높다라고 말할 수 있습니다. (어떤 식에서 상수 부분을 바이어스라고 생각하면 됩니다.)그 결과 주어진 입력 x의 class i에 대한 evidence는 아래와 같이 표현 됩니다.


Wi는 가중치이고 bi는 class i를 위한 바이어스, j는 입력 이미지 x의 점들의 합계를 위한 인덱스입니다.
여기에서 i는 0에서 9까지 숫자이고 j는 784개 원소가 됩니다.
그리고 나서 그 증거를 Softmax 함수를 사용하여 예상 가능한 확률(y)로 변환합니다.


여기서 softmax는 "활성화" 또는"링크" 함수로서, 우리가 원하는 형태의 선형 함수를 형성하여 10건 이상의 확률 분포를 형성한다. 여러분은 그것을 우리가 각각의 클래스에 있는 우리의 입력의 가능성의 확률로 바꾸는 것으로 생각할 수 있습니다. 이는 다음과 같이 정의됩니다.
방정식을 확장하면 다음과 같이 됩니다.

입력 값을 지수화 한 다음 정규화합니다. 지수화는 하나의 evidence 단위가 모든 가설에 주어진 가중치를 곱셈적으로 증가 시킨다는 것을 의미합니다. 반대로 하나의 evidence 단위가 없다는 것은 가설이 초기 가중치의 일부를 얻는다는 것을 의미합니다. (이게 무슨말인지 상당히 어렵네요. 다시 설명하자면 지수 함수를 사용하는것은 가중치가 더 커지게 하는 효과가 있다고 합니다. 이렇게 하는 이유는 좋은 예측은 여러개중 하나만 1에 가까운 값을 나타내기 위함입니다. )
Softmax는 이 가중치를 정규화하여 최대 1을 가산하여 유효한 확률 분포를 형성합니다. (softmax 기능에 대한 더 많은 정보를 얻으려면 Michael Nielsen의 책에서 complete with an interactive visualization 섹션을 확인하십시오.)
softmax 회귀 분석은 다음과 같이 보일 수 있습니다.  x가 더 많지만, 여기에서는 3개정도만 표시하였습니다. 각 출력에 대해 x의 가중치 합계를 계산하고 바이어스를 추가 한 다음 softmax를 적용합니다.

이것을 방정식으로 써보면 아래와 같습니다.

우리는이 절차를 "벡터화 (vectorize)"하여 행렬 곱셈과 벡터 덧셈으로 바꿀 수 있습니다. 이는 계산 효율에 도움이됩니다.
좀 더 단순하게 표현하면 아래와 같습니다.

이제 텐서플로가 사용 할 수 있는것으로 바꿉시다.



2017년 12월 2일 토요일

ML 초보자를 위한 MNIST(MNIST For ML Beginners)(1)



출처 : https://www.tensorflow.org/get_started/mnist/beginners

이글은 영어 원본을 읽고 공부하면서 불필요한 내용 빼고 이해하기 쉽도록 적절히 내맘대로 작성해보았습니다. 이해가 잘못되어 원저자의 의도대로 번역이 안되어 있을 수도 있습니다. 이점 참고해서 읽어 주시면 고맙겠습니다


앞서 작성한 글



이 글은 앞서 작성한 글에 이어지는 글입니다.




프로그램을 배우는데는 HelloWorld 가 기본, 머신런닝에서 MNIST 가 기본이라고 합니다.
MNIST는 손글씨 숫자로 구성된 간단한 컴퓨터 비전 데이터 셋입니다.
대충 아래와 같습니다.

또 labels(라벨) 이 붙어있어서 어떤게 어떤 숫자인지 알 수 있게 되어있습니다. 위의 라벨은 5,0,4,1입니다.

예제에서는 이미지를 보고 어떤 숫자인지 예측하는 모델을 만들게 됩니다. 이것은 Softmax Regression 이라는 모델로 텐서플로의 기본이 되는것입니다. (Softmax는 최종 출력값들의 합계는 1이 되는 특징을 가지며 주로 분류하는 용도에서 많이 사용하게 됩니다.)
이 예제의 실제 코드는 매우 짧으며 중심 내용은 단 3줄에서 발생합니다. TensorFlow가 작동하는 방법과 핵심 기계 학습 개념의 두 가지 아이디어를 이해하는 것이 매우 중요합니다.

이 예제에 관해서


코드는 아래 링크에서 받을 수 있습니다.
https://github.com/tensorflow/tensorflow/blob/r1.4/tensorflow/examples/tutorials/mnist/mnist_softmax.py


이 튜토리얼에서 우리가 학습 할 것
- MNIST 데이터와 softmax 회귀에 대해 배웁니다.
- 이미지의 모든 픽셀을 보면서 숫자를 인식하는 모델 함수를 만듭니다.
- TensorFlow를 사용하여 숫자를 인식하도록 모델을 훈련합니다.
- 테스트 데이터로 모델의 정확성을 확인합니다.

MNIST 데이터

MNIST데이터는 Yann LeCun's website (http://yann.lecun.com/exdb/mnist/)에서 호스팅 됩니다. 이 예제 코드를 복사하여 붙여 넣는 경우 아래 두줄 코드에 의해서 데이터를 자동으로 다운로드하게 됩니다.
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
MNIST 데이터는 트레인 데이터 (mnist.train)의 55,000, 테스트 데이터 (mnist.test)의 10,000 및 검증 데이터 (mnist.validation)의 5,000 의 세 부분으로 나누어집니다. 이 분할은 매우 중요합니다. 기계 학습에서 필수적입니다. 우리가 배우지 않은 별도의 데이터를 가지고 있으므로 배운 내용이 실제로 일반화되었는지 확인할 수 있습니다

앞에서 언급했듯이, 모든 MNIST 데이터 포인트는 두 부분으로되어 있습니다 : 손으로 쓴 숫자의 이미지와 해당 라벨, 우리는 이미지 "x"와 라벨(앞에서 5,0,4,1 같은 숫자를 의미합니다.) "y"를 부를 것입니다. 트레이닝 세트와 테스트 세트는 모두 이미지와 해당 라벨을 포함합니다. 예를 들어 트레이닝 이미지는 mnist.train.images이고 트레이닝 라벨은 mnist.train.labels입니다. (y=f(x)라고 볼때, 이미지 x를 가지고 우리가 궁금해 하는(머신러닝을 통해서 결과를 분류(인식)해야하는 값은 y가 되어야 합니다.) 라벨이 y가 되어야 합니다.)
각각의 이미지는 28*28크기입니다. 이것은 숫자의 큰 배열로 이해할 수 있습니다.

일렬로 풀어서 나열하면 28*28=784개의 숫자 벡터의 배열이 됩니다.  1차원적으로 표현하면 2D 이미지의 성분이 사라지게 됩니다. 여기에서는 softmax회귀를 해당 방법으로 사용하지만, 가장 최고의 방법은 2D데이터 그대로 사용하는것이 좋은 방법인데 그건 나중에 학습할 예정입니다.
mnist.train.images는 [55000, 784]형태를 가진 텐서입니다. 첫번째 차원은 이미지 리스트 인덱스이고 두번째 차원은 각 이미지에서 픽셀에 대한 인덱스 입니다.  텐서의 각 엔트리는 특정 이미지의 특정 픽셀에 대해 0과 1 사이의 픽셀 강도입니다.
위 그림 설명이 이미지가 2D표시되어 모호할 수 있어서 1D로 변환되는 부분을 나타내었습니다.

MNIST의 각 이미지에는 이미지에 그려지는 숫자를 나타내는 0에서 9 사이의 숫자가 해당 레이블을 가지고 있습니다.

이 튜토리얼의 목적을 위해 우리는 레이블을 "원 핫 벡터 (one-hot vectors)"로 원할 것입니다. (분류의 머신 러닝에서는 대부분 출력단(y)이 one-hot vectors로 사용합니다.)원 핫 벡터는 대부분 차원에서 0이고 단일 차원에서 1인 벡터입니다. 이 경우 n 번째 숫자는 n 차원에서 1 인 벡터로 표시됩니다.
예를 들어, 각각 아래와 같이 표시 됩니다.
0은 [1,0,0,0,0,0,0,0,0,0]
1은 [0,1,0,0,0,0,0,0,0,0]
2은 [0,0,1,0,0,0,0,0,0,0]
3은 [0,0,0,1,0,0,0,0,0,0]
따라서 mnist.train.labels는 [55000, 10] 배열입니다.

위 내용의 입출력 관계를 정리해보면 아래와 같습니다.


직접 데이터를 읽어서 처리하는 경우는 없겠지만 MNIST 파일의 구조는 아래와 같습니다.
TRAINING SET LABEL FILE (train-labels-idx1-ubyte):

[offset] [type]          [value]          [description] 
0000     32 bit integer  0x00000801(2049) magic number (MSB first) 
0004     32 bit integer  60000            number of items 
0008     unsigned byte   ??               label 
0009     unsigned byte   ??               label 
........ 
xxxx     unsigned byte   ??               label
The labels values are 0 to 9.

TRAINING SET IMAGE FILE (train-images-idx3-ubyte):

[offset] [type]          [value]          [description] 
0000     32 bit integer  0x00000803(2051) magic number 
0004     32 bit integer  60000            number of images 
0008     32 bit integer  28               number of rows 
0012     32 bit integer  28               number of columns 
0016     unsigned byte   ??               pixel 
0017     unsigned byte   ??               pixel 
........ 
xxxx     unsigned byte   ??               pixel
Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).

TEST SET LABEL FILE (t10k-labels-idx1-ubyte):

[offset] [type]          [value]          [description] 
0000     32 bit integer  0x00000801(2049) magic number (MSB first) 
0004     32 bit integer  10000            number of items 
0008     unsigned byte   ??               label 
0009     unsigned byte   ??               label 
........ 
xxxx     unsigned byte   ??               label
The labels values are 0 to 9.

TEST SET IMAGE FILE (t10k-images-idx3-ubyte):

[offset] [type]          [value]          [description] 
0000     32 bit integer  0x00000803(2051) magic number 
0004     32 bit integer  10000            number of images 
0008     32 bit integer  28               number of rows 
0012     32 bit integer  28               number of columns 
0016     unsigned byte   ??               pixel 
0017     unsigned byte   ??               pixel 
........ 
xxxx     unsigned byte   ??               pixel
Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).

이제 우리 모델을 실제로 만들 준비가되었습니다!










2017년 11월 25일 토요일

텐서플로 시작하기(Getting Started With TensorFlow)(3) tf.train tf.estimator API


출처 : https://www.tensorflow.org/get_started/get_started

이글은 영어 원본을 읽고 공부하면서 불필요한 내용 빼고 이해하기 쉽도록 적절히 내맘대로 작성해보았습니다. 이해가 잘못되어 원저자의 의도대로 번역이 안되어 있을 수도 있습니다. 이점 참고해서 읽어 주시면 고맙겠습니다


앞서 작성한 글

이 글은 앞서 작성한 글에 이어지는 글입니다.


tf.train API


TensorFlow는 손실 함수를 최소화하기 위해 각 변수를 천천히 변경하는 optimizers를 제공합니다. 가장 간단한  optimizers는 gradient descent(경사 하강법)입니다. 그것은 매개변수로 된 함수가 주어지면 함수의 값이 최소화되는 방향으로 매개변수를 변경하는 것을 반복적으로 수행하는 방법입니다. TensorFlow는 tf.gradients 함수를 사용하여 자동으로 생성 할 수 있습니다. 기울기를 계산해야 하므로 오차 함수는 미분 가능해야 합니다.  아래와 같이 사용합니다.
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
sess.run(init) # reset values to incorrect defaults.
for i in range(1000):
  sess.run(train, {x: [1, 2, 3, 4], y: [0, -1, -2, -3]})
print(sess.run([W, b]))
마지막 모델의 결과는 아래와 같이 나옵니다.
[array([-0.9999969], dtype=float32), array([ 0.99999082], dtype=float32)]
이 간단한 선형 회귀 모델이 TensorFlow 핵심 코드를 많이 필요로하지는 않지만 모델에 데이터를 입력하는 더 복잡한 모델과 방법은 더 많은 코드가 필요합니다. 따라서 TensorFlow는 일반적인 패턴, 구조 및 기능에 대해 더 높은 수준의 추상화를 제공합니다.

Complete program

완성 된 학습 가능한 선형 회귀 모델은 다음과 같습니다.
import tensorflow as tf
# Model parameters
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W*x + b
y = tf.placeholder(tf.float32)
# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# training data
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, {x: x_train, y: y_train})
# evaluate training accuracy
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
실행 결과는 아래와 같습니다.
W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
loss는 아주 작은 숫자입니다 (거의 0에 가깝습니다). 이 프로그램을 직접 실행해보면 loss값과 일치하지 않습니다. 그 이유는 의사 난수 값으로 초기화되기 때문입니다.

그리고 이것을 TensorBoard 에서 시각화 해보면 아래와 같습니다.

TensorBoard final model visualization


물론 이렇게 그대로 하면 시각화가 되지 않습니다.
시각화 예제는 아래 소스 참고 하시기 바랍니다.

TensorBoard 포함
import tensorflow as tf
# Model parameters
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W*x + b
y = tf.placeholder(tf.float32)
# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# training data
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
file_writer = tf.summary.FileWriter('E:/work/ai/anaconda', sess.graph)
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, {x: x_train, y: y_train})
# evaluate training accuracy
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
file_writer.add_graph(sess.graph)
file_writer.close()


코드 분석

앞서 최소 값이 되기위하여 엑셀표를 참고하면 W,b가 어떤값일때 loss값이 최소가 되는지 살펴보아서 알고는 있습니다. 그러나 여기에서는 목표값을 모른다고 가정하고 train을 하게됩니다. train시 for i in range(1000): 에 의해서 1000번 train을 하면서 W,b 값을 변경하게 됩니다.
위 코드를 이해하기 위해서는 아래와 같이 소스를 변경해서 실행해보면 이해하기 쉽습니다.
train 변경
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import tensorflow as tf
# Model parameters
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W*x + b
y = tf.placeholder(tf.float32)
# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# training data
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
#for i in range(1000):
#  sess.run(train, {x: x_train, y: y_train})

curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

sess.run(train, {x: x_train, y: y_train})
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

sess.run(train, {x: x_train, y: y_train})
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

sess.run(train, {x: x_train, y: y_train})
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

sess.run(train, {x: x_train, y: y_train})
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
line 21,22 을 삭제하고 line 27,31,35,39에서 train을 한번씩 하도록 변경하고 train을 한 후 값을 출력할 수 있도록 변경하였습니다.

결과
(E:\Users\xxx\Anaconda3) E:\work\ai\anaconda>python tensor2.py
2017-11-19 22:19:07.041552: I C:\tf_jenkins\home\workspace\rel-win\M\windows\PY\36\tensorflow\core\platform\cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
W: [ 0.30000001] b: [-0.30000001] loss: 23.66
W: [-0.21999997] b: [-0.456] loss: 4.01814
W: [-0.39679998] b: [-0.49552] loss: 1.81987
W: [-0.45961601] b: [-0.4965184] loss: 1.54482
W: [-0.48454273] b: [-0.48487374] loss: 1.48251
결과를 살펴보면 loss값이 점차 줄어드는것을 볼 수 있습니다. 또한 아래 결과는 GradientDescentOptimizer인자값을 변경하면서 결과를 살펴보았습니다. 값이 작게되면 loss값의 변화가 작게되며, 값이 어느 정도 커지면 loss값이 늘어나게 되는 경우도 발생하게 됩니다. 이런 경우 루프를 아무리 많이 돌아도 loss값이 줄어들지 않게 됩니다. 따라서 적절한 값의 설정이 필요하며, 너무 작으면 loss를 줄이는데 굉장히 많은 loop가 필요하기 때문에 많은 시간을 필요로 합니다.

tf.train.GradientDescentOptimizer(0.001) 일때
W: [ 0.30000001] b: [-0.30000001] loss: 23.66
W: [ 0.24800001] b: [-0.31560001] loss: 20.811
W: [ 0.19943202] b: [-0.33003521] loss: 18.3294
W: [ 0.1540668] b: [-0.34338358] loss: 16.1677
W: [ 0.11169046] b: [-0.35571784] loss: 14.2848

tf.train.GradientDescentOptimizer(0.1) 일때
W: [ 0.30000001] b: [-0.30000001] loss: 23.66
W: [-4.9000001] b: [-1.8599999] loss: 712.098
W: [ 24.22000122] b: [ 8.22800064] loss: 22936.2
W: [-141.55599976] b: [-47.99440002] loss: 740011.0
W: [ 799.76879883] b: [ 272.31311035] loss: 2.38765e+07



tf.estimator

tf.estimator는 기계 학습의 메커니즘을 단순화하는 상위 수준의 TensorFlow 라이브러리입니다. 아래 내용을 포함합니다.
-훈련 루프 실행
-평가 루프 실행
-데이터 세트 관리
tf.estimator는 많은 공통 모델을 정의합니다.(여기서 모델이라고 하면, 선형회귀 같은것을 의미합니다.)
좀더 자세한 내용을 원하면 아래 주제를 더 살펴 봐도 됩니다.
https://www.tensorflow.org/programmers_guide/estimators
https://www.tensorflow.org/get_started/estimator
하지면 여기에서는 원본내용에서도 간단하게되어 있어 여기까지만 설명하도록 하겠습니다.

기본적인 용법

tf.estimator를 사용하면 선형 회귀 프로그램이 얼마나 단순해지는지 보여집니다.

# NumPy is often used to load, manipulate and preprocess data.
import numpy as npimport tensorflow as tf
# Declare list of features. We only have one numeric feature. There are many
# other types of columns that are more complicated and useful.
feature_columns = [tf.feature_column.numeric_column("x", shape=[1])]
# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# linear classification, and many neural network classifiers and regressors.
# The following code provides an estimator that does linear regression.
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)
# TensorFlow provides many helper methods to read and set up data sets.
# Here we use two data sets: one for training and one for evaluation
# We have to tell the function how many batches
# of data (num_epochs) we want and how big each batch should be.
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)
# We can invoke 1000 training steps by invoking the  method and passing the
# training data set.
estimator.train(input_fn=input_fn, steps=1000)
# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)
실행시키면 아래와 같은 결과가 나옵니다.
train metrics: {'average_loss': 1.4833182e-08, 'global_step': 1000, 'loss': 5.9332727e-08}
eval metrics: {'average_loss': 0.0025353201, 'global_step': 1000, 'loss': 0.01014128}
결과에서 eval loss 데이터를 보면 평가값이 높긴하지만 0에 가까운것을 보면 제대로 train되었다는것을 알 수 있습니다. (train 후 eval 을 하게되는데, 보통 train data와 다른값을 사용하여 eval을 하기 때문에 loss 값은 많이 차이 날 수 있습니다.)


A custom model

tf.estimator는 미리 준비된 모델만 이용할 수 있는건 아니고 직접 저수준 함수를 이용해서 커스텀 모델을 만들 수 있습니다. 여기 예제에서는 앞서 사용한 1차원 선형 회귀 모델을 커스텀 모델로 변경하였습니다. 앞서 tf.estimator.LinearRegressor 이것을 이용하는 부분이  model_fn을 만들고 tf.estimator.Estimator(model_fn=model_fn) 에 전달하는 부분이 다릅니다.

import numpy as npimport tensorflow as tf
# Declare list of features, we only have one real-valued feature
def model_fn(features, labels, mode):
  # Build a linear model and predict values
  W = tf.get_variable("W", [1], dtype=tf.float64)
  b = tf.get_variable("b", [1], dtype=tf.float64)
  y = W*features['x'] + b
  # Loss sub-graph
  loss = tf.reduce_sum(tf.square(y - labels))
  # Training sub-graph
  global_step = tf.train.get_global_step()
  optimizer = tf.train.GradientDescentOptimizer(0.01)
  train = tf.group(optimizer.minimize(loss),
                   tf.assign_add(global_step, 1))
  # EstimatorSpec connects subgraphs we built to the
  # appropriate functionality.
  return tf.estimator.EstimatorSpec(
      mode=mode,
      predictions=y,
      loss=loss,
      train_op=train)

estimator = tf.estimator.Estimator(model_fn=model_fn)
# define our data sets
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7., 0.])
input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)
# train
estimator.train(input_fn=input_fn, steps=1000)
# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)
결과는 이전과 크게 다르지 않습니다.
train metrics: {'loss': 1.227995e-11, 'global_step': 1000}
eval metrics: {'loss': 0.01010036, 'global_step': 1000}