TensorFlow 기본 개념 (1)
머신러닝의 정의란 Andrew Ng
교수님의 말을 인용하면 아래와 같다.
A computer program is said to learn from experience E with respect to some class of taks T and performance tasks in T, as measured by P, improves with experience E, Tom M. Mitchell
Tensor는 뭔가?
많은 데이터를 효과적으로 처리하는 자료구조이다.
다차원 array, list라고 생각하면 된다.
이래서 NumPy
를 확장한것이 Tensor
인 것이다.
# What is tensor?
tensor1 = 7 # 0-dimensional
tensor2 = [7] # 1-dimensional
tensor3 = [[1,2,3], # 2-dimensional
[4,5,6]] ...
...
Flow
Flow
란 결국 Graph
이다.
즉 모든 계산을 쉽게 하기 위해서 각각의 연산을 잘게 쪼개고 이것을 Graph
로 연결 한 것이다.
미분 Chain Rule
같은것을 생각해보면 왜 연산이 간단해 지는지 알 수 있다.
Graph, Node, Edge
선언부와 실행부가 다르다
TensorFlow
코드 상에서 a=1
을 선언해도 추후에 이것이 반영되는 것이지 지금 당장 변수 a
가 1
로 assgin된것은 아니다.
이러한 부분이 기본적인 python
프로그래밍과는 다른점이다.
이러한 동작 매커니즘을 생각해보면 결국 앞으로 어떻게 동작 할 것이다
라는 계획
을 Graph
로 표현한것이 TensorFlow
가 되는 것이다.
Operation
: 동작을 정의한 것Node
: Operation 정의를 포함한 것Edge
: Node와 Node를 연결한 것
이러한 구조에서 Tensor
데이터 구조가 이동하면서 Operation
에 의해서 연산을 하는 방식이다.
import tensotflow as tf
위처럼 TensorFlow
를 일단 Import
하면 내부적으로 default_graph_stack
에 Default Graph
가 생긴다.
tf.get_default_graph()
명령어로 접근 가능
이 graph
에 저장된 operation
을 확인해 보면 []
비어 있는 것을 알 수 있다.
상수를 하나 선언 하면 아래처럼 주소가 기록된다.
이러한 의미는 operation이 리스트 형태로 들어가 있는 것이다.
import tensorflow as tf
graph = tf.get_default_graph()
graph.get_operations()
input = tf.constant(1.0)
operations = graph.get_operations()
operations
[<tensorflow.python.framework.ops.Operation at 0x7f94695fbd90>,
<tensorflow.python.framework.ops.Operation at 0x7f944788a990>]
operation을 감싸고 있는 node를 출력해보자.
>>> operations[0].node_def
## name: "Const"
## op: "Const"
## attr {
## key: "dtype"
## value {
## type: DT_FLOAT
## }
## }
## attr {
## key: "value"
## value {
## tensor {
## dtype: DT_FLOAT
## tensor_shape {
## }
## float_val: 1.0
## }
## }
## }
TensorFlow는 내부적으로 protocol buffer를 이용한다.
어떤 google style의 JSON이라고 생각하면 쉽다. 위에 출력도 JSON 스럽기 때문이다.
왜 tensorflow는 이처럼 고유한 특징의 구조나 타입들을 가지는 것일까?
Numpy는 기본적으로 matrix을 연산을 위해서 C++로 개발 되었다. 하지만 여전히 많은 overhead를 발생 시킨다.
완전히 Python 영역 밖에서 동작 시킴으로 성능을 끌어 올린다.
이러한 방법은Theano
또는Torch
에서 수행하는 방식이다.
그냥 input
을 출력해 보자
In [27]: input
Out[27]: <tf.Tensor 'Const_9:0' shape=() dtype=float32>
32비트 float tensor를 확인 할 수 있다. no dimension 이며 그냥 싱글 숫자이다.
이제 실제로 input값을 session으로 실행하자.
default에 의해서 default graph에서 값을 꺼내오는 방식이다.
>>> sess = tf.Session()
>>> sess.run(input_value)
## 1.0
초 간단 TensorFlow neuron
Hadley Wickham said Names have objects rather than the reverse
이다.
표현 하면 아래의 그림과 같다.
여기서 말하는 초간단 neron은 non-identity activation function도 없고 bias도 없는 것을 말한다.
constant
는 상수를 의미하고, variable
은 계속 변화하는 값을 의미 한다.
weight = tf.Variable(0.8)
#지원하는 operation 이름 확인
for op in graph.get_operations(): print op.name
x
에 w
를 곱해서 y
라는 출력값을 만들어냄
이때 참값은 0
이다.
입력값은 1로 고정 시킨다면 당연히 참값 y_ = 0과 일치시키는 w는 0일것이다.
단순한 방정식이다.
$$ 1 \times w = 0 $$
위와 같을 때는 $w$는 0
이 최적화된 값일 것이다.
하지만 이러한 해를 wieght
값 w
를 조정하면서 전체 cost
를 줄이는 방법으로 차근 차근 찾아보자.
w
의 시작값을 0.8
로 설정 한다.
이때의 cost는 $1 \times 0.8 = 0.8$ 이다.
이 cost를 계산하는 것이 최소제곱법이 있다.
$$ cost = minimum(\hat { y }- y)^{2} $$
이것을 최소화로 만들어주는 방법은 y를 결정하는 함수 $f(x) = wx$ 입니다. 결국 w를 조정해서 해를 찾을 수 있게 됩니다.
우선, cost
함수를 w
에 대해서 편미분하면 chain rule
에 의해서 아래와 같이 나옵니다.
$$ \frac{\partial cost}{\partial w} = 2 \times x$$
그리고 이러한 과정에 쓰이는 데이터를 트레이닝 데이터라고 하고 과정을 학습(learning)이라고 합니다.
TensorFlow에서느 사실 이러한 미분을 자동으로 해주게 됩니다. 구지 손으로 저렇게 해서 식으로 적을 필요 없습니다.
그리고 이러한 미분값을 최적화 시키기위해서 조금씩 값을 update
하는 방법을 사용하게 됩니다.
방법의 이름은 gradient descent algorihtm
입니다. 알고리즘을 표현하면 아래와 같습니다.
$$ w = w - \alpha \frac{\partial cost}{\partial w} $$
위 알고리즘은 간단하게 TensorFlow
에서는 아래와 같은 함수하나만 이용하면 딥니다.
optim = tf.train.GradientDescentOptimizer(learning_rate = 0.025)
learing rate을 0.025를 적용해서 손으로 1단계를 게산해보면 아래와 같습니다.
$1.6 \times 0.025 = 0.04$가 됩니다.
아래 코드는 이러한 과정을 적용한 전체 코드 입니다.
import tensorflow as tf
x = tf.constant(1.0, name='input')
w = tf.Variable(0.8, name='weight')
y = tf.mul(w, x, name='output')
y_ = tf.constant(0.0, name='correct_value')
loss = tf.pow(y - y_, 2, name='loss')
train_step = tf.train.GradientDescentOptimizer(0.025).minimize(loss)
for value in [x, w, y, y_, loss]:
tf.scalar_summary(value.op.name, value)
summaries = tf.merge_all_summaries()
sess = tf.Session()
summary_writer = tf.train.SummaryWriter('log_simple_stats', sess.graph)
sess.run(tf.initialize_all_variables())
for i in range(100):
if i % 10 ==0:
print("epoch {}, output: {}".format(i, sess.run(y)))
summary_writer.add_summary(sess.run(summaries), i)
sess.run(train_step)
출력결과
epochs 0, output: 0.800000011921
epochs 10, output: 0.478989481926
epochs 20, output: 0.286788702011
epochs 30, output: 0.171710968018
epochs 40, output: 0.10280970484
epochs 50, output: 0.0615559667349
epochs 60, output: 0.0368558317423
epochs 70, output: 0.0220669470727
epochs 80, output: 0.0132122989744
epochs 90, output: 0.00791069027036
output은 weight 값 w를 의미하며 정답인 0에 거의 근접한것을 알 수 있다.
해당 결과를 Tensor Board
를 통해서 시각적으로 확인 할 수도 있다.
프로젝트 디렉터리에서 log_simple_stats
에 저장한다고 했으니 그곳에서 아래의 명령어를 수행 한다.
tensorboard --logdir=./log_simple_stats
그다음 크롬을 이용해서 http://192.168.188.129:6006/#graphs
아래 주소로 접속 한다.
IP Address는 각자 맞춰서 한다.
그냥 local에서 작업한다면 localhost:6006/#graphs
라고 쓰면 된다.
작성코드
본 내용에 작성된 코드들은 Github
를 통해서 공유하겠습니다.
주소: https://github.com/leejaymin/TensorFlowLecture/tree/master/0.Basic
참고자료
https://www.oreilly.com/learning/hello-tensorflow
https://jihobak.github.io/2016-06-26-deeplearning-ninja001/
'AI > TensorFlow, PyTorch, Keras, Scikit' 카테고리의 다른 글
TensorFlow 기본 개념 (2) (0) | 2016.09.29 |
---|---|
MNIST 데이터 셋을 이용한 손글씨 인식 Deep Neural Network 구현 (6) | 2016.07.07 |
TensorFlow 버전 업데이트 (Version Update) (4) | 2016.06.15 |
Naive Bayes vs Neural network (2) | 2016.04.25 |
Softmax Function (0) | 2016.04.19 |