소스코드로 텐서플로우 맛보기 : [CNN] CIFAR-10
이제 가장 중요한 부분은 지나갔다.
생각해보면 전체적인 흐름을 먼저 살펴보고 세부적인 내용들을 분석했어야 할 것 같은데 순서가 거꾸로 되어버렸다.
아무래도 전체 포스팅을 마무리한 후 다시 한 번 되짚는 과정을 거쳐야 할 것 같다.
앞서 분석한 내용들은 모델을 구성하고 loss값을 생성하고 optimizer를 적용하는 구체적인 내용들이었다.
처음 딥러닝을 공부할 때는 각각의 단계가 거의 1줄 코딩이었던 것을 생각하면 이 소스는 매우 복잡해보인다.
그러나 세부적인 설정들이 더 추가되었을 뿐 근본적인 맥락은 다를 바가 없다.
자세한 내용은 복습 시간에 다시 살펴보고 오늘은 사용자와 인터페이스하는 소스를 살펴보도록 하자.
cifar10_train.py
소스 분석에 들어가기 전에 참고로 이 소스를 훈련시켰을 때의 정확도가 소스 첫머리의 주석에 표시되어있다.
뭐 흙수저가 사용할 수 있을만한 장비는 아닌 듯하니 그냥 그런가보다 하고 넘어가자…-.-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from datetime import datetime
import time
import tensorflow as tf
import cifar10
첫 3줄은 앞서도 보았듯이 python 2와 3의 호환을 위한 것이고 datetime과 time은 이름에서도 알 수 있듯이 날짜와
시간을 사용하기 위한 것으로 print를 하거나 수행 시간을 체크하기 위한 용도로 import 하였다. 마지막 2줄도 생략
FLAGS = tf.app.flags.FLAGS
tf.app.flags.DEFINE_string('train_dir', '/tmp/cifar10_train',
"""Directory where to write event logs """
"""and checkpoint.""")
tf.app.flags.DEFINE_integer('max_steps', 1000000,
"""Number of batches to run.""")
tf.app.flags.DEFINE_boolean('log_device_placement', False,
"""Whether to log device placement.""")
tf.app.flags.DEFINE_integer('log_frequency', 10,
"""How often to log results to the console.""")
FLAG 역시 이전 포스팅에서 설명을 하였는데 그 아래 tf.app.flags.DEFINE_XXX로 지정한 이름으로 그 값을
사용할 수 있다. 즉, FLAG.train_dir은 '/tmp/cifar10_train’라는 값을 가지고 있게 된다. 두 번째 줄에 보면 학습
step을 1000000회로 설정하였다.
train()
# 학습을 실행시키는 함수
def train():
"""Train CIFAR-10 for a number of steps."""
# with tf.Graph().as_default() 문장은 지금까지 만들었던 모든 그래프 구성 요소(operation과 tensor들)을
# 하나의 전역 Graph 안에서 사용하겠다는 의미이다.
with tf.Graph().as_default():
# global_step은 학습의 step 카운트를 자동으로 관리해주는 tensor로 사용자가 별도로 step을 카운트
# 할 필요가 없이 이 global_step을 이용하면 된다.
global_step = tf.train.get_or_create_global_step()
# Get images and labels for CIFAR-10.
# Force input pipeline to CPU:0 to avoid operations sometimes ending up on
# GPU and resulting in a slow down.
# 학습을 수행할 장치를 지정. 첫 번째 CPU를 사용하도록 지정하고 있다. GPU를 사용하는 방법은
# cifar10_multi_gpu_train.py 소스를 참조하면 된다. 비록 multi gpu를 사용하는 소스지만...-.-
with tf.device('/cpu:0'):
# 학습에 사용할 미니 배치 크기의 image와 label을 가져온다.
# 자세한 내용은 cifar10.py 소스의 distorted_inputs함수 참조
# http://mazdah.tistory.com/814
images, labels = cifar10.distorted_inputs()
# Build a Graph that computes the logits predictions from the
# inference model.
# 학습 모델 생성. 자세한 내용은 cifar10.py 소스의 inference함수 참조
# http://mazdah.tistory.com/814
logits = cifar10.inference(images)
# Calculate loss.
# 손실값 계산. 자세한 내용은 cifar10.py 소스의 loss함수 참조
# http://mazdah.tistory.com/814
loss = cifar10.loss(logits, labels)
# Build a Graph that trains the model with one batch of examples and
# updates the model parameters.
# 실제 학습을 수행할 operation 생성. 자세한 내용은 cifar10.py 소스의 loss함수 참조
# http://mazdah.tistory.com/814
train_op = cifar10.train(loss, global_step)
# 아래 나오는 tf.train.MonitoredTrainingSession에 사용하기 위한 로그 hooker
# MonitoredTrainingSession.run() 호출에 대한 로그들을 hooking하는 역할을 한다.
# Pythons에서는 클래스 선언 시 ( )안에는 상속할 클래스를 지정한다. 즉, _LoogerHook 클래스는
# tf.train.SessionRunHook 클래스를 상속하여 만들어지게 되며 정의된 함수들은 이 클래스의
# 함수들을 Overriding해서 구현한 함수들이다.
class _LoggerHook(tf.train.SessionRunHook):
"""Logs loss and runtime."""
# session을 이용할 때 처음 한 번 호출되는 함수
def begin(self):
self._step = -1
self._start_time = time.time()
# run() 함수가 호출되기 전에 호출되는 함수
def before_run(self, run_context):
self._step += 1
return tf.train.SessionRunArgs(loss) # Asks for loss value.
# run() 함수가 호출된 후에 호출되는 함수
def after_run(self, run_context, run_values):
if self._step % FLAGS.log_frequency == 0:
current_time = time.time()
duration = current_time - self._start_time
self._start_time = current_time
loss_value = run_values.results
examples_per_sec = FLAGS.log_frequency * FLAGS.batch_size / duration
sec_per_batch = float(duration / FLAGS.log_frequency)
format_str = ('%s: step %d, loss = %.2f (%.1f examples/sec; %.3f '
'sec/batch)')
print (format_str % (datetime.now(), self._step, loss_value,
examples_per_sec, sec_per_batch))
# 분산 환경에서 학습을 실행할 때 사용하는 Session. 분산 환경에 대한 지원을 해준다.
# (Hook를 이용한 로그 관리, 오류 발생시 복구 처리 등)
with tf.train.MonitoredTrainingSession(
checkpoint_dir=FLAGS.train_dir,
hooks=[tf.train.StopAtStepHook(last_step=FLAGS.max_steps),
tf.train.NanTensorHook(loss),
_LoggerHook()],
config=tf.ConfigProto(
log_device_placement=FLAGS.log_device_placement)) as mon_sess:
while not mon_sess.should_stop():
# 드디어 마무리~ 학습 operation을 실제로 수행시킨다.
mon_sess.run(train_op)
main(argv=None)
# CIFAR-10 데이터를 다운로드 받아 저장. cifar10.py 소스 참조
# http://mazdah.tistory.com/814
cifar10.maybe_download_and_extract()
# 학습 수행 중의 로그를 저장할 디렉토리 생성. 기존에 동일 디렉토리가 있다면 삭제 후 생성.
if tf.gfile.Exists(FLAGS.train_dir):
tf.gfile.DeleteRecursively(FLAGS.train_dir)
tf.gfile.MakeDirs(FLAGS.train_dir)
# 학습 시작
train()
정리
소스 길이에 비해 분석하는 데 너무 많은 시간이 걸렸다…ㅠ.ㅠ
지난 포스팅에서도 언급한 것처럼 매개 변수나 리턴값들이 모두 tensor 형태이고 TensorFlow의 API 문서에 있는
내용들이 수학적인 내용을 많이 포함하고 있어 다른 언어나 프레임워크의 문서를 읽는 해석하는 것에 비해 원문
해석도 꽤나 어려웠다.
포스팅한 내용에 부정확한 내용이 있을지도 모르겠기에 일단 CIFAR-10 예제 코드를 실제로 돌려보고
그 중간 로그나 결과 값들과 비교해가면서 다시 한 번 찬찬히 살펴볼 필요가 있을 것 같다. 그리고 추후에 이 소스에
쓰인 API들을 별도로 정리해보겠다.
소스 중에는 아직 평가를 위한 cifar10_eval.py이 남아있는데 요건 우선 학습 관련 내용을 마무리하고
진행해보도록 하겠다.
'Study > 인공지능학습' 카테고리의 다른 글
[머신러닝 reboot] 개념 잡기 : 경사 하강법 1 - 특성의 scale (0) | 2018.11.25 |
---|---|
[머신러닝 reboot] 단순 선형 회귀 분석 - 정규방정식 도출하기 (6) | 2018.11.03 |
소스코드로 텐서플로우 맛보기 : [CNN] CIFAR-10 ~ cifar10.py (0) | 2018.02.20 |
소스코드로 텐서플로우 맛보기 : [CNN] CIFAR-10 ~ cifar10_input.py (0) | 2018.02.13 |
로지스틱 회귀 비용함수로부터 Cross-entropy 도출하기 (0) | 2017.06.18 |