[텐서플로우 정리] 09. argmax 함수

argmax 함수가 어떤 역할을 하는지만 알면 충분한데, 갑자기 궁금해졌다. 두 번째 파라미터로 전달되는 차원이 무엇을 의미하는건지. 너무 당연하게 전달하는 배열의 차원을 알려달라는 것인지 알았다.


import tensorflow as tf
import functions

a1 = tf.Variable([0.1, 0.3, 0.5])
functions.showOperation(tf.argmax(a1, 0))
[출력 결과]
2

두 번째 파라미터는 one-hot-encoding을 적용할 차원을 알려주는 매개변수이다. 1차원 배열에 대해서는 0, 2차원 배열에 대해서는 0과 1, 3차원 배열에 대해서는 0, 1, 2를 사용할 수 있다. 헷갈릴 수 있는데, 0은 열(column), 1은 행(row), 2는 면(page, 행열)을 가리킨다. 그러고 보니 flag 2에 대해서는 정확한 용어를 모르겠다. 보통 차원(dimension)을 얘기할 때 점선면이라고 말하니까, 여기서는 '면'이라고 하고 page라고 읽겠다.

1차원 배열을 전달했으니까 사용할 수 있는 플래그는 0 밖에 없다. 그런데, 느낌이 이상한 것이 1행밖에 없는데 왜 결과가 한 개밖에 나오지 않을까,라고 생각할 수도 있다. 그러나, 1차원 배열을 행이 아니라 열로 생각할 수도 있다. 다시 말해 열이 1개 있기 때문에 결과도 하나가 나왔다,라고 보면 된다.


import tensorflow as tf
import functions

a2 = tf.Variable([[0.1, 0.3, 0.5]])
functions.showOperation(tf.argmax(a2, 0))
functions.showOperation(tf.argmax(a2, 1))
[출력 결과]
[0 0 0]
[2]

1행 3열의 2차원 배열을 사용했다. 사용할 수 있는 플래그는 0과 1의 두 가지다.

먼저 열 단위로 찾기 위해서 0을 전달했다. 결과는 3개가 나왔고 모두 0이다. 열 단위로는 데이터가 1개밖에 없으니까, 위치는 항상 0이 될 수밖에 없다.

행 단위로 찾기 위해서 1을 전달하면, 결과는 1개만 나온다. 행이 하나밖에 없으니까. 0번째 행에서 가장 큰 값은 0.5이고, 2번째 위치에 있어서 2를 반환했다.


import tensorflow as tf
import functions

a3 = tf.Variable([[[0.1, 0.3, 0.5],
[0.3, 0.5, 0.1]],
[[0.5, 0.1, 0.3],
[0.1, 0.3, 0.5]],
[[0.3, 0.5, 0.1],
[0.5, 0.1, 0.3]]])

functions.showOperation(tf.argmax(a3, 0))
functions.showOperation(tf.argmax(a3, 1))
functions.showOperation(tf.argmax(a3, 2))
[출력 결과]
[[1 2 0]
[2 0 1]]
[[1 1 0]
[0 1 1] [1 0 1]]
[[2 1]
[0 2]
[1 0]]

a3은 3x2x3 크기를 갖는 3차원 배열이다. 어떻게 이런 결과가 나왔는지 말로 하는 것이 쉽지 않다. 행과 열, 페이지에 따라 계산한 방식을 빨간색으로 표시해 보았다. 행열 기준의 경우에는 행과 같은 행에 있으면서 열이 일치하는 요소끼리 비교하고 있다. 0행의 0열과 1열, 1행의 0열과 1열 등등.

플래그 0 (열 기준)
[[0.1, 0.3, 0.5], [0.3, 0.5, 0.1]]
[[0.5, 0.1, 0.3], [0.1, 0.3, 0.5]]
[[0.3, 0.5, 0.1], [0.5, 0.1, 0.3]]
[[  1     2     0 ], [  2     0     1 ]]

플래그 1 (행 기준)
[[0.1, 0.3, 0.5],
[0.3, 0.5, 0.1]]    [[1 1 0],
[[0.5, 0.1, 0.3],
[0.1, 0.3, 0.5]]     [0 1 1],
[[0.3, 0.5, 0.1],
[0.5, 0.1, 0.3]]     [1 0 1]]

플래그 2 (행열 기준)
[[0.1, 0.3, 0.5], [0.3, 0.5, 0.1]]     [[2 1],
[[0.5, 0.1, 0.3], [0.1, 0.3, 0.5]]      [0 2],
[[0.3, 0.5, 0.1], [0.5, 0.1, 0.3]]      [1 0]]

텐서플로우 실수 오차(정밀도)

텐서플로우에서 이상한 점을 발견했다. 그런데, 이게 틀리다고 얘기할 수는 없겠지만, 지금까지의 실수 연산하고는 다른 점이어서 정리한다.

텐서플로우의 기본이 되는 코드를 하나 만들었다. hypothesis를 통해서 새로운 입력이 들어왔을 때의 결과를 예측하고 있다. hypothesis는 W와 X를 곱하는 아주 단순한 코드다. 결과를 예측하기 위해 X는 placeholder로 처리했다.

import tensorflow as tf
import numpy as np

x_data = [1., 2., 3.]
y_data = [2., 4., 6.]

W = tf.Variable(0.5)
X = tf.placeholder(tf.float32)

hypothesis = W * X
cost = tf.reduce_mean(tf.square(hypothesis-y_data))
rate = tf.constant(0.1)

optimizer = tf.train.GradientDescentOptimizer(rate)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.initialize_all_variables())

for i in range(3):
sess.run(train, feed_dict={X: x_data})
print(i, sess.run(W))
print('-'*30)

t = np.array([3.6]) # x가 3.6일 때의 y 예측 시도
ww = sess.run(W)
hh = sess.run(hypothesis, {X: t})

print('manual : {}'.format((ww*t)[0]))
print('hypothesis : {}'.format(hh[0]))
[출력 결과]
0 1.9
1 1.99333
2 1.99956
------------------------------
manual : 7.198400115966797
hypothesis : 7.198400020599365

출력된 결과를 보면, hypothesis를 통해 계산한 값과 직접 계산한 값이 다르게 나온다. 많이 다르지는 않고 미세하게 소숫점 뒷자리에서 달라진다. 실제로는 같을 때도 있고, 다르게 나올 때도 있다.

텐서플로우를 통해 hypothesis를 계산하는 것과 직접 W와 X를 곱하는 것이 같다는 것을 이해하지 못하면, 지금 코드는 의미가 없다. 이 부분은 단순 계산이기 때문에, W와 X가 복잡해지면 직접 할 수가 없으니까, 텐서플로우에 hypothesis를 계산해 달라고 부탁하는 것일 뿐이다.


아래 코드는 텐서플로우의 곱셈 코드다. 실수 2개를 곱해서 결과를 numpy로 변환을 해서 출력하고 있다. 텐서플로우는 결과를 numpy로 반환하기 때문에 함수 이름 또한 op2Numpy라고 만들었다. op2Numpy 함수는 functions.py 파일에 들어 있다.

import tensorflow as tf
import functions

a, b = 0.4, 0.6

print(functions.op2Numpy(tf.mul(a, b)))
print('{}'.format(functions.op2Numpy(tf.mul(a, b))))
[출력 결과]
0.24
0.24000000953674316

같은 함수를 호출했는데, 출력 결과가 다르게 나왔다. print 함수는 일정 자릿수 이상을 출력하지 않는 관계로 첫 번째 출력에서는 0.24까지만 표시됐다. 전체 자릿수 출력을 위해 문자열의 format 함수를 사용했다.

놀랍게도 아래쪽에 숨겨진 값들이 보인다. 컴퓨터에서는 모든 숫자를 2진수의 형태, 즉 비트(bit) 단위로 저장을 해야 한다. 2의 32승으로 실수를 저장한다는 뜻은 2의 32승 갯수만큼의 실수 종류만 저장할 수 있다는 뜻이다. 10진수를 2진수로 변환하는 과정에서 오차는 필연적으로 발생할 수밖에 없다.

마찬가지로 0.6을 10진수로 표현하는 것은 쉽지만, 2진수로 표현하게 되면 굉장히 길게 저장을 하게 되는데, 이 부분에서 오차가 발생하게 된다. 텐서플로우는 이렇게 발생하는 오차에 대한 처리 없이, 2진수 자체를 계산에 활용하고 있는 것처럼 보인다. 어쩌면 이런 오차 하나를 수정하는 것조차도 성능에 영향을 줄 수 있기 때문에 무시하는 것일 수도 있다. 실수 하나에 대해서라고 쉽게 얘기하지만, 한 번 연산에 수천, 수만 개의 연산이 포함될 수 있기 때문에 신중한 영역일 수도 있다.

0.24가 맞는지 0.24000000953674316이 맞는지 나는 판단할 수 없다. 그러나, 간혹 우리가 생각했던 결과가 나올 수 있다는 것은 명심해야 한다. 매우 작은 오차를 여러 번 적용하는 과정에서 꽤 큰 오차로 변할 수도 있지 않을까, 하는 걱정이 든다. 오차를 고민하지 않는 제일 좋은 방법은 직접 계산하려고 시도하지 말고, 텐서플로우에 계산을 맡기는 것이다. 첫 번째 코드에서 올바른 코드가 무엇이냐고 묻는다면, hypothesis를 사용한 코드라고 대답할 수 있다. 언제나.

그냥 결과가 다르게 나와서 궁금했을 뿐이고, 당연히 텐서플로우의 원칙을 따르는 것이 맞다. 궁금증을 풀었으니, 푹 자야겠다. 이렇게 단순한 문제일 거라고 생각하지 못하고, 온갖 상상을 적용해 보고 나서야 여기에 올 수 있었다. 개운하지는 않다.

[텐서플로우 정리] 08. 초기값과 난수

이번 글에서는 변수의 초기값을 주는 함수들에 대해 살펴 본다.
이번 코드 또한 functions.py 파일에 있는 함수를 이용해서 결과를 출력하고 있다. (functions.py)


코딩할 때마다 나오는 개념인데.. 매번 헷갈려서 정리한다. uniform이란 단어의 뜻을 이제서야 알았다.
정규분포(normal distribution) - 통계 확률분포에서 가장 중요한 분포로 종 모양(bell shpae)으로 표현되는 확률
균등(균일)분포(uniform distribution) - 각각의 구간에서 동일한 확률로 표현되는 분포로 사각형 모양
잘린(절단)정규분포(truncated normal distribution) - 정규분포에서 일부 구간을 잘라낸 분포
나무위키(정규분포)
나부랭이의 수학블로그(균등분포 개념정리)
잘린정규분포   truncated normal distribution(위키피디아, 영어)


tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
Outputs random values from a normal distribution.

Args:
shape: A 1-D integer Tensor or Python array. The shape of the output tensor.
mean: A 0-D Tensor or Python value of type dtype. The mean of the normal distribution.
stddev: A 0-D Tensor or Python value of type dtype. The standard deviation of the normal distribution.
dtype: The type of the output.
seed: A Python integer. Used to create a random seed for the distribution. See set_random_seed for behavior.
name: A name for the operation (optional).

Returns:
A tensor of the specified shape filled with random normal values.


tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
Outputs random values from a truncated normal distribution.

The generated values follow a normal distribution with specified mean and standard deviation, except that values whose magnitude is more than 2 standard deviations from the mean are dropped and re-picked.

Args:
shape: A 1-D integer Tensor or Python array. The shape of the output tensor.
mean: A 0-D Tensor or Python value of type dtype. The mean of the truncated normal distribution.
stddev: A 0-D Tensor or Python value of type dtype. The standard deviation of the truncated normal distribution.
dtype: The type of the output.
seed: A Python integer. Used to create a random seed for the distribution. See set_random_seed for behavior.
name: A name for the operation (optional).

Returns:
A tensor of the specified shape filled with random truncated normal values.


tf.random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)
Outputs random values from a uniform distribution.

The generated values follow a uniform distribution in the range [minval, maxval). The lower bound minval is included in the range, while the upper bound maxval is excluded.

For floats, the default range is [0, 1). For ints, at least maxval must be specified explicitly.

In the integer case, the random integers are slightly biased unless maxval - minval is an exact power of two. The bias is small for values of maxval - minval significantly smaller than the range of the output (either 2**32 or 2**64).

Args:
shape: A 1-D integer Tensor or Python array. The shape of the output tensor.
minval: A 0-D Tensor or Python value of type dtype. The lower bound on the range of random values to generate. Defaults to 0.
maxval: A 0-D Tensor or Python value of type dtype. The upper bound on the range of random values to generate. Defaults to 1 if dtype is floating point.
dtype: The type of the output: float32, float64, int32, or int64.
seed: A Python integer. Used to create a random seed for the distribution. See set_random_seed for behavior.
name: A name for the operation (optional).

Returns:
A tensor of the specified shape filled with random uniform values.

Raises:
ValueError: If dtype is integral and maxval is not specified.


import tensorflow as tf
from functions import showOperation as showOp

showOp(tf.zeros([2,3])) # [[ 0. 0. 0.] [ 0. 0. 0.]]
showOp(tf.ones([2,3], tf.int32)) # [[1 1 1] [1 1 1]]
showOp(tf.zeros_like(tf.ones([2,3]))) # [[ 0. 0. 0.] [ 0. 0. 0.]]
showOp(tf.fill([2,3], 2)) # [[2 2 2] [2 2 2]]
showOp(tf.fill([2,3], 2.0)) # [[ 2. 2. 2.] [ 2. 2. 2.]]
print('# ------------------------------------------------ #')
showOp(tf.linspace(1.0, 10.0, 4)) # [ 1. 4. 7. 10.]
showOp(tf.range(5)) # [0 1 2 3 4]
showOp(tf.range(0, 5)) # [0 1 2 3 4]
showOp(tf.range(0, 10, 2)) # [0 2 4 6 8]
print('# ------------------------------------------------ #')
# tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
# [[-0.14479451 -0.50265551 1.38471031] [-2.46794224 0.56639165 -0.59352636]]
showOp(tf.random_normal([2, 3]))
# [[ 5.0084033 6.28203726 5.49111032] [ 4.81292725 4.8216362 4.82326126]]
showOp(tf.random_normal([2, 3], mean=5.0))
# [[ 0.02739749 0.15692481 -0.18835409] [-0.20757729 0.76803416 -0.07633832]]
showOp(tf.random_normal([2, 3], stddev=0.35))
# [[ 4.7160387 5.51960945 5.0228653 ] [ 4.14505386 5.03473711 5.20692873]]
showOp(tf.random_normal([2, 3], mean=5.0, stddev=0.35, seed=1))
print('# ------------------------------------------------ #')
# -0.1293 -0.0633 0.0984 0.0508 0.1916 0.1197 -0.3135 -0.0823 -0.0300 0.0430
for _ in range(10):
showOp(tf.reduce_sum(tf.random_normal([2, 3], stddev=0.35) / 6))
# 5.03024 4.9332 4.97116 4.96042 4.99974 5.15176 4.961 4.64518 5.26943 5.18463
for _ in range(10):
showOp(tf.reduce_sum(tf.random_normal([2, 3], mean=5.0, stddev=0.35) / 6))
print('# ------------------------------------------------ #')
# tf.random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)
# [[ 0.67391849 0.66735017 0.0794853 ] [ 0.64219582 0.47089899 0.68388402]]
showOp(tf.random_uniform([2, 3]))
# [[ 1.28794432 2.02983379 2.73823977] [ 2.97947931 4.48065186 4.69495058]]
showOp(tf.random_uniform([2, 3], minval=5)) # no error. do not work.
# [[ 13.32174492 3.7804091 10.80069256] [ 8.99943733 0.50998271 9.10907364]]
showOp(tf.random_uniform([2, 3], maxval=15))
# [[ 8.30814171 8.18294716 6.43582296] [ 5.31517982 9.81415558 8.0894165 ]]
showOp(tf.random_uniform([2, 3], 5, 10))
# [[ 7.41970491 7.5310154 6.27571869] [ 5.62371159 9.66505051 8.32304668]]
showOp(tf.random_uniform([2, 3], 5, 10, seed=7))
print('# ------------------------------------------------ #')
# tf.random_shuffle(value, seed=None, name=None)
showOp(tf.random_shuffle(tf.Variable([1,2,3,4,5,6]))) # [3 4 6 5 2 1]
showOp(tf.random_shuffle(tf.Variable([[1,2], [3,4], [5,6]]))) # [[5 6] [3 4] [1 2]]
print('# ------------------------------------------------ #')
# [[ 0.23903739 0.92039955 0.05051243] [ 0.49574447 0.83552229 0.02647042]]
showOp(tf.random_uniform([2, 3], seed=1))
# [[ 0.23903739 0.92039955 0.05051243] [ 0.49574447 0.83552229 0.02647042]]
showOp(tf.random_uniform([2, 3], seed=1))
print('# ------------------------------------------------ #')
# tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
# The generated values follow a normal distribution with specified mean and standard deviation,
# except that values whose magnitude is more than 2 standard deviations
# from the mean are dropped and re-picked.
# [[-0.50039721 -1.03818107 -0.1909811 ] [-0.41344216 -0.91877717 0.24455361]] showOp(tf.truncated_normal([2,3])) # [[ 3.40512562 -0.11788981 1.92399371] [ 6.6576376 4.21847486 4.41285849]] showOp(tf.truncated_normal([2,3], stddev=3.5))

[텐서플로우 정리] 07. 세션과 구구단

텐서플로우를 구동해서 실질적인 결과를 보여준다.
여기까지 익히면 머신러닝을 학습하기 전의 준비 과정으로 충분하다.

1부터 3까지 반복하는 코드와 구구단을 출력하는 코드를 만들어 봤다.
각각 두 가지, 세 가지 버전으로 만들었는데,
많은 차이가 나진 않지만, 나름대로 모든 방법이 의미를 갖기 때문에 차이점을 주목해서 봤으면 한다.
가장 중요한 코드는 마지막에 있는 placeholder를 사용하는 방법이다.

# 예제1 : 1부터 3까지 증가
# 예제2 : 구구단

import tensorflow as tf

def one2three_1():
state = tf.Variable(1)
one = tf.constant(1)

with tf.Session() as sess:
sess.run(tf.initialize_all_variables())

for _ in range(3):
print(sess.run(state))
state = tf.add(state, one)

def one2three_2():
state = tf.Variable(0)
one = tf.constant(1)
value = tf.add(state, one)
update = tf.assign(state, value)

with tf.Session() as sess:
sess.run(tf.initialize_all_variables())

for _ in range(3):
print(sess.run(update))

def table99_1(which):
level = tf.constant(which)
state = tf.Variable(1)

with tf.Session() as sess:
sess.run(tf.initialize_all_variables())

for i in range(1, 10):
left, rite = sess.run(level), sess.run(state)
state = tf.add(state, 1)

print('{} x {} = {:2}'.format(left, rite, left*rite))

def table99_2(which):
# update를 처리하면 연계된 모든 Tensor 객체도 함께 처리됨
level = tf.constant(which)
state = tf.Variable(0)
add = tf.add(state, 1)
value = tf.assign(state, add)
update = tf.mul(level, value)

with tf.Session() as sess:
sess.run(tf.initialize_all_variables())

for _ in range(9):
# left, rite, result = sess.run([level, state, update])

result = sess.run(update)
left, rite = level.eval(), state.eval()

print('{} x {} = {:2}'.format(left, rite, result))

def table99_3(which):
left = tf.placeholder(tf.int32)
rite = tf.placeholder(tf.int32)
update = tf.mul(left, rite)

with tf.Session() as sess:
sess.run(tf.initialize_all_variables())

for i in range(1, 10):
result = sess.run(update, feed_dict={left: which, rite: i})
print('{} x {} = {:2}'.format(which, i, result))

one2three_1()
one2three_2()

table99_1(7)
table99_2(7)
table99_3(7)
[출력 결과 1]
1
2
3

[출력 결과 2]
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63


[텐서플로우 정리] 06. 수학 함수

제곱, 로그, 지수 등의 다양한 수학 함수에 대해 살펴 본다.
생각했던 것보다 함수가 많아 정리하기도 힘이 들었다. 대신 코딩할 때는 도움 되겠다.

import tensorflow as tf
import functions

c2, c3 = tf.constant([1.2, 5.6]), tf.constant([-4, -1, 7])
v2, v3 = tf.Variable([2.3, 4.5]), tf.Variable([-2, 3, 5])

print('-----------add_n------------') # same shape aod dtype 덧셈
functions.showOperation(tf.add_n([c2, v2])) # [ 3.5 10.10000038]
functions.showOperation(tf.add_n([c3, v3, v3])) # [-8 5 17]

print('-----------abs------------')
functions.showOperation(tf.abs(c2)) # [ 1.20000005 5.5999999 ]
functions.showOperation(tf.abs([c3, v3])) # [[4 1 7] [2 3 5]]

print('-----------neg------------')
functions.showOperation(tf.neg(c2)) # [-1.20000005 -5.5999999 ]
functions.showOperation(tf.neg([c3, v3])) # [[ 4 1 -7] [ 2 -3 -5]]

print('-----------sign------------')
functions.showOperation(tf.sign(c2)) # [ 1. 1.]
functions.showOperation(tf.sign([c3, v3])) # [[-1 -1 1] [-1 1 1]]

print('-----------square------------')
functions.showOperation(tf.square(c2)) # [ 1.44000006 31.3599987 ]
functions.showOperation(tf.square([c3, v3])) # [[16 1 49] [ 4 9 25]]

print('-----------round------------')
functions.showOperation(tf.round(c2)) # [ 1. 6.]
functions.showOperation(tf.round([c3, v3])) # [[-4 -1 7] [-2 3 5]]

print('-----------sqrt------------') # 정수 사용 불가. 음수는 nan.
functions.showOperation(tf.sqrt(c2)) # [ 1.44000006 31.3599987 ]
functions.showOperation(tf.sqrt([c2, v2])) # [[ 1.09544516 2.36643171] [ 1.5165751 2.12132025]]

print('-----------pow------------') # 갯수 일치 주의
functions.showOperation(tf.pow(c2, 2)) # [ 1.44000006 31.3599987 ]
# [[ 1.44000006 175.61599731] [ 5.28999996 91.125 ]]
functions.showOperation(tf.pow([c2, v2], [2, 3]))
# [[ 1.44000006 175.61599731] [ 5.28999996 91.125 ]]
functions.showOperation(tf.pow([c2, v2], [[2, 3], [2, 3]]))

print('-----------exp------------') # 정수 사용 불가. 음수 동작.
functions.showOperation(tf.exp(c2)) # [ 3.320117 270.4263916]
functions.showOperation(tf.exp([c2, v2])) # [[ 3.320117 270.4263916 ] [ 9.97418213 90.01712799]]

print('-----------log------------') # 정수 사용 불가. 음수는 nan.
functions.showOperation(tf.log(c2)) # [ 0.18232159 1.72276664]
functions.showOperation(tf.log([c2, v2])) # [[ 0.18232159 1.72276664] [ 0.83290911 1.50407743]]

print('-----------ceil------------') # 정수 사용 불가.
functions.showOperation(tf.ceil(c2)) # [ 2. 6.]
functions.showOperation(tf.ceil([c2, v2])) # [[ 2. 6.] [ 3. 5.]]

print('-----------floor------------') # 정수 사용 불가.
functions.showOperation(tf.floor(c2)) # [ 1. 5.]
functions.showOperation(tf.floor([c2, v2])) # [[ 1. 5.] [ 2. 4.]]

print('-----------maximum------------')
functions.showOperation(tf.maximum(c2, v2)) # [ 2.29999995 5.5999999 ]
# [[ 2.29999995 5.5999999 ] [ 2.29999995 5.5999999 ]]. [c2, c3] is error because shape is different.
functions.showOperation(tf.maximum([c2, c2], [v2, v2]))

print('-----------minimum------------')
functions.showOperation(tf.minimum(c2, v2)) # [ 1.20000005 4.5 ]
# [[ 1.20000005 4.5 ] [ 1.20000005 4.5 ]]
functions.showOperation(tf.minimum([c2, c2], [v2, v2]))

print('-----------sin------------') # 정수 사용 불가.
functions.showOperation(tf.sin(c2)) # [ 0.93203908 -0.63126671]
# [[ 0.93203908 -0.63126671] [ 0.74570525 -0.97753012]]
functions.showOperation(tf.sin([c2, v2]))

print('-----------cos------------') # 정수 사용 불가.
functions.showOperation(tf.cos(c2)) # [ 0.36235771 0.7755658 ]
# [[ 0.36235774 0.77556586] [-0.66627598 -0.21079579]]
functions.showOperation(tf.cos([c2, v2]))

print('-----------tan------------') # 정수 사용 불가.
functions.showOperation(tf.tan(c2)) # [ 2.5721519 -0.81394345]
# [[ 2.5721519 -0.81394345] [-1.1192137 4.63733196]]
functions.showOperation(tf.tan([c2, v2]))

c4 = tf.constant([[1, 3, 5], [0, 2, 4]])
v4 = tf.Variable([[1, 2], [3, 7], [8, 9]])

print('-----------matmul------------') # (2x3)*(3x2) = (2x2), (3x2)*(2x3) = (3x3)
functions.showOperation(tf.matmul(c4, v4)) # [[50 68] [38 50]]
functions.showOperation(tf.matmul(v4, c4)) # [[ 1 7 13] [ 3 23 43] [ 8 42 76]]


[텐서플로우 정리] 05. Shapes & Shaping

텐서플로우 내부를 보여주거나 변경하는 함수에 대해 소개한다.
텐서플로우에 이러한 역할을 하는 함수가 몇 개 없어 간략하게 정리할 수 있었다.

rank. 배열의 차원.

Rank

Math

Entity

Python example

0

Scalar

(magnitude only)

s = 483

1

Vector

(magnitude and direction)

v = [1.1, 2.2, 3.3]

2

Matrix

(table of numbers)

m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

3

3-Tensor

(cube of numbers)

t = [[[2], [4], [6]], [[8], [10], [12]], [[14], [16], [18]]]

n

n-Tensor

(you get the idea)

....


shape. 배열의 모양(2x5는 2행 5열)

Rank

Shape

Dimension number

Example

0

[]

0-D

A 0-D tensor. A scalar.

1

[D0]

1-D

A 1-D tensor with shape [5].

2

[D0, D1]

2-D

A 2-D tensor with shape [3, 4].

3

[D0, D1, D2]

3-D

A 3-D tensor with shape [1, 4, 3].

n

[D0, D1, ... Dn-1]

n-D

A tensor with shape [D0, D1, ... Dn-1].


내부 정보를 출력하는 함수로 functions.py에 만들었던 함수다.

def showConstantDetail(t):
sess = tf.InteractiveSession()
print(t.eval())
print('shape :', tf.shape(t))
print('size :', tf.size(t))
print('rank :', tf.rank(t))
print(t.get_shape())

sess.close()


shape을 변경할 수 있는 2개의 함수를 살펴 본다.

import tensorflow as tf
import functions

c1 = tf.constant([1, 3, 5, 7, 9, 0, 2, 4, 6, 8, 3, 7])
v1 = tf.Variable([[1, 2, 3], [7, 8, 9]])

print('-----------reshape------------')
functions.showOperation(tf.reshape(c1, [2, -1])) # [[1 3 5 7 9 0] [2 4 6 8 3 7]]
functions.showOperation(tf.reshape(c1, [-1, 3])) # [[1 3 5] [7 9 0] [2 4 6] [8 3 7]]
functions.showOperation(tf.reshape(v1, [-1])) # [1 2 3 7 8 9]

c2 = tf.reshape(c1, [2, 2, 1, 3])
c3 = tf.reshape(c1, [1, 4, 1, 3, 1])

print('-----------squeeze------------') # reemoves dimensions of size 1
# [[[[1 3 5]] [[7 9 0]]] [[[2 4 6]] [[8 3 7]]]]
functions.showOperation(c2)
functions.showOperation(tf.squeeze(c2)) # [[[1 3 5] [7 9 0]] [[2 4 6] [8 3 7]]]

# [[[[[1] [3] [5]]] [[[7] [9] [0]]] [[[2] [4] [6]]] [[[8] [3] [7]]]]]
functions.showOperation(c3)
functions.showOperation(tf.squeeze(c3)) # [[1 3 5] [7 9 0] [2 4 6] [8 3 7]]

reshape 함수에 사용된 -1은 나누어 떨어지는 숫자를 자동으로 적용하겠다는 뜻이다. 12개의 요소가 있을 때, [3,-1]이라는 것은 [3,4]와 같고, [2,2,-1]이라는 것은 [2,2,3]과 같다. 행과 열, 페이지에서 중심이 되는 것을 지정한 다음에, 나머지를 계산하기 싫을 때 주로 사용된다.

[텐서플로우 정리] 04. Slicing & Joining

다차원 배열을 자르거나, 잘린 배열을 연결하는 함수들에 대해 살펴 본다.
이 영역에 속한 텐서플로우 함수들은 갯수가 많아서 전체를 정리하지 못했다.
지금까지의 경험으로 좀더 사용될 것 같은 함수들 위주로만 사용법을 정리했다.

이번 코드에서는 원본과 출력 결과를 자세하게 살펴 보아야 한다.
다차원 배열이 등장하다 보니, 데이터 갯수 때문에 결과 확인이 조금 어렵다.

import tensorflow as tf
import functions

c1 = tf.constant([1, 3, 5, 7, 9, 0, 2, 4, 6, 8])
c2 = tf.constant([1, 3, 5])
v1 = tf.constant([[1, 2, 3, 4, 5, 6], [7, 8, 9, 0, 1, 2]])
v2 = tf.constant([[1, 2, 3], [7, 8, 9]])

print('-----------slice------------')
functions.showOperation(tf.slice(c1, [2], [3])) # [5 7 9]
functions.showOperation(tf.slice(v1, [0, 2], [1, 2])) # [[3 4]]
functions.showOperation(tf.slice(v1, [0, 2], [2, 2])) # [[3 4] [9 0]]
functions.showOperation(tf.slice(v1, [0, 2], [2,-1])) # [[3 4 5 6] [9 0 1 2]]

print('-----------split------------')
functions.showOperation(tf.split(0, 2, c1)) # [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8]]
functions.showOperation(tf.split(0, 5, c1)) # [[1, 3], [5, 7], [9, 0], [2, 4], [6, 8]]
functions.showOperation(tf.split(0, 2, v1)) # [[[1, 2, 3, 4, 5, 6]], [[7, 8, 9, 0, 1, 2]]]
functions.showOperation(tf.split(1, 2, v1)) # [[[1, 2, 3], [7, 8, 9]], [[4, 5, 6], [0, 1, 2]]]

print('-----------tile------------')
functions.showOperation(tf.tile(c2, [3])) # [1 3 5 1 3 5 1 3 5]
# [[1 2 3 1 2 3] [7 8 9 7 8 9] [1 2 3 1 2 3] [7 8 9 7 8 9]]
functions.showOperation(tf.tile(v2, [2, 2]))

print('-----------pad------------') # 2차원에 대해서만 동작
# [[0 0 0 0 0 0 0]
# [0 0 1 2 3 0 0]
# [0 0 7 8 9 0 0]
# [0 0 0 0 0 0 0]]
functions.showOperation(tf.pad(v2, [[1, 1], [2, 2]], 'CONSTANT'))
# [[9 8 7 8 9 8 7]
# [3 2 1 2 3 2 1]
# [9 8 7 8 9 8 7]
# [3 2 1 2 3 2 1]] # 3 2 1 2 3 2 1 2 3 2 1 처럼 반복
functions.showOperation(tf.pad(v2, [[1, 1], [2, 2]], 'REFLECT'))
# [[2 1 1 2 3 3 2]
# [2 1 1 2 3 3 2]
# [8 7 7 8 9 9 8]
# [8 7 7 8 9 9 8]] # 3 2 1 (1 2 3) 3 2 1. 가운데와 대칭
functions.showOperation(tf.pad(v2, [[1, 1], [2, 2]], 'SYMMETRIC'))

print('-----------concat------------')
functions.showOperation(tf.concat(0, [c1, c2])) # [1 3 5 7 9 0 2 4 6 8 1 3 5]
functions.showOperation(tf.concat(1, [v1, v2])) # [[1 2 3 4 5 6 1 2 3] [7 8 9 0 1 2 7 8 9]]
# functions.showOperation(tf.concat(0, [v1, v2])) # error. different column size.

c3, c4 = tf.constant([1, 3, 5]), tf.constant([[1, 3, 5], [5, 7, 9]])
v3, v4 = tf.constant([2, 4, 6]), tf.constant([[2, 4, 6], [6, 8, 0]])

print('-----------pack------------') # 차원 증가. tf.pack([x, y]) = np.asarray([x, y])
functions.showOperation(tf.pack([c3, v3])) # [[1 3 5] [2 4 6]]
functions.showOperation(tf.pack([c4, v4])) # [[[1 3 5] [5 7 9]] [[2 4 6] [6 8 0]]]

t1 = tf.pack([c3, v3])
t2 = tf.pack([c4, v4])

print('-----------unpack------------') # 차원 감소
functions.showOperation(tf.unpack(t1)) # [[1, 3, 5], [2, 4, 6]]
functions.showOperation(tf.unpack(t2)) # [[[1, 3, 5], [5, 7, 9]], [[2, 4, 6], [6, 8, 0]]]

print('-----------reverse------------')
functions.showOperation(tf.reverse(c1, [True])) # [8 6 4 2 0 9 7 5 3 1]
functions.showOperation(tf.reverse(v1, [True, False])) # [[7 8 9 0 1 2] [1 2 3 4 5 6]]
functions.showOperation(tf.reverse(v1, [True, True ])) # [[2 1 0 9 8 7] [6 5 4 3 2 1]]

print('-----------transpose------------') # perm is useful to multi-dimension .
functions.showOperation(tf.transpose(c3)) # [1 3 5]. not 1-D.
functions.showOperation(tf.transpose(c4)) # [[1 5] [3 7] [5 9]]
functions.showOperation(tf.transpose(c4, perm=[0, 1])) # [[1 3 5] [5 7 9]]
functions.showOperation(tf.transpose(c4, perm=[1, 0])) # [[1 5] [3 7] [5 9]]

print('-----------gather------------')
functions.showOperation(tf.gather(c1, [2, 5, 2, 5])) # [5 0 5 0]
functions.showOperation(tf.gather(v1, [0, 1])) # [[1 2 3 4 5 6] [7 8 9 0 1 2]]
functions.showOperation(tf.gather(v1, [[0, 0], [1, 1]])) # [[[1 2 3 4 5 6] [1 2 3 4 5 6]] [[7 8 9 0 1 2] [7 8 9 0 1 2]]]

print('-----------one_hot------------') # make one-hot matrix.
# [[ 1. 0. 0.]
# [ 0. 1. 0.]
# [ 0. 0. 1.]
# [ 0. 1. 0.]]
functions.showOperation(tf.one_hot([0, 1, 2, 1], 3))
# [[ 0. 0. 0. 1.]
# [ 0. 0. 0. 0.]
# [ 0. 1. 0. 0.]]
functions.showOperation(tf.one_hot([3, -1, 1], 4))


[텐서플로우 정리] 03. 관계 연산, 논리 연산

텐서플로우에서 제공하는 관계 연산과 논리 연산 함수에 대해 살펴 본다.
관계 연산은 참(True)과 거짓(False)을 만들어 내고, 논리 연산은 참과 거짓을 갖고 계산을 한다.

import tensorflow as tf
import functions

c1, c2, c3 = tf.constant([1, 2]), tf.constant([1.0, 2.0]), tf.constant([1])
v1, v2 = tf.Variable([1, 3]), tf.Variable([1.0, 3.0])

print('-----------equal------------')
functions.showOperation(tf.equal(c1, v1)) # [ True False]
functions.showOperation(tf.equal(c2, v2)) # [ True False]
# functions.showOperation(tf.equal(c1, c2)) # error. different type.

print('-----------not_equal------------')
functions.showOperation(tf.not_equal(c1, v1)) # [False True]
functions.showOperation(tf.not_equal(c2, v2)) # [False True]
# functions.showOperation(tf.not_equal(c1, c3)) # error. different size.

print('-----------less------------')
functions.showOperation(tf.less(c1, v1)) # [False True]
functions.showOperation(tf.less(c2, v2)) # [False True]

print('-----------less_equal------------')
functions.showOperation(tf.less_equal(c1, v1)) # [ True True]
functions.showOperation(tf.less_equal(c2, v2)) # [ True True]

print('-----------greater------------')
functions.showOperation(tf.greater(c1, v1)) # [False False]
functions.showOperation(tf.greater(c2, v2)) # [False False]

print('-----------greater_equal------------')
functions.showOperation(tf.greater_equal(c1, v1)) # [ True False]
functions.showOperation(tf.greater_equal(c2, v2)) # [ True False]

c4 = tf.constant([[1, 3], [5, 7]])
v4 = tf.Variable([[2, 4], [6, 8]])

# if True, select c4. if False, select v4.
cond1 = tf.Variable([[True, True ], [False, False]])
cond2 = tf.Variable([[True, False], [False, True ]])

print('-----------select------------')
functions.showOperation(tf.select(cond1, c4, v4)) # [[1 3] [6 8]]
functions.showOperation(tf.select(cond2, c4, v4)) # [[1 4] [6 7]]

c5 = tf.constant([[True , True], [False, False]])
v5 = tf.Variable([[False, True], [True , False]])

functions.showOperation(tf.where(c5)) # [[0 0] [0 1]]
functions.showOperation(tf.where(v5)) # [[0 1] [1 0]]

functions.showOperation(tf.select(cond1, c4, v4)) # [[1 3] [6 8]]
functions.showOperation(tf.select(cond2, c4, v4)) # [[1 4] [6 7]]

print('-----------and, or, xor, not------------')
functions.showOperation(tf.logical_and(c5, v5)) # [[False True] [False False]]
functions.showOperation(tf.logical_or (c5, v5)) # [[ True True] [ True False]]
functions.showOperation(tf.logical_xor(c5, v5)) # [[ True False] [ True False]]
functions.showOperation(tf.logical_not(c5)) # [[False False] [ True True]]

결과를 보면 함수가 하는 역할을 알 수 있기 때문에 별도의 주석을 달지 않았는데, select 함수의 경우는 결과를 보고 이해하기가 쉽지 않다. select 함수의 두 번째 매개변수는 참일 때 사용하고, 세 번째 매개변수는 거짓일 때 사용한다. 첫 번째 매개변수로 전달된 참과 거짓 값으로부터 참이라면 앞에 오는 것을, 거짓이라면 뒤에 오는 것을 선택하는 구조이다.

c = tf.Variable([1, 2])
v = tf.Variable([3, 4])
showOperation(tf.select([True, False], c, v))       # [1 4]
showOperation(tf.select([True, False], v, c))       # [3 2]

c와 v를 전달한다면 c는 참일 때 사용하고, v는 거짓일 때 사용한다. 마지막 줄에서처럼 순서를 바꾸면, 결과도 달라진다.

[텐서플로우 정리] 02. 산술 연산

텐서플로우에서 상수와 변수를 만들어 보고,
이들을 사용해서 덧셈, 뺄셈, 곱셈, 나눗셈 등의 산술 연산을 수행해 본다.

Tensor 출력을 위해 functions.py 파일의 함수를 사용한다. 출력 결과는 코드 오른쪽에 주석으로 달아 놓았다.
코드는 매우 단순하다. 여기서 볼 것은 함수에 전달되는 매개 변수의 형태다. 1-D, 2-D 등등.

import tensorflow as tf
import functions

c1, c2 = tf.constant([3]), tf.constant([1, 5])
v1, v2 = tf.Variable([5]), tf.Variable([2, 4])

functions.showConstant(c1)
functions.showConstant(c2)
functions.showVariable(v1)
functions.showVariable(v2)

print('-----------add------------')
functions.showOperation(tf.add(c1, v1)) # [8]
functions.showOperation(tf.add(c2, v2)) # [3 9]
functions.showOperation(tf.add([c2, v2], [c2, v2])) # [[ 2 10] [ 4 8]]

print('-----------sub------------')
functions.showOperation(tf.sub(c1, v1)) # [-2]
functions.showOperation(tf.sub(c2, v2)) # [-1 1]

print('-----------mul------------')
functions.showOperation(tf.mul(c1, v1)) # [15]
functions.showOperation(tf.mul(c2, v2)) # [ 2 20]

print('-----------div------------')
functions.showOperation(tf.div(c1, v1)) # [0]
functions.showOperation(tf.div(c2, v2)) # [0 1]

print('-----------truediv------------')
functions.showOperation(tf.truediv(c1, v1)) # [ 0.6]
functions.showOperation(tf.truediv(c2, v2)) # [ 0.5 1.25]

print('-----------floordiv------------')
functions.showOperation(tf.floordiv(c1, v1)) # [0]
functions.showOperation(tf.floordiv(c2, v2)) # [0 1]

print('-----------mod------------')
functions.showOperation(tf.mod(c1, v1)) # [3]
functions.showOperation(tf.mod(c2, v2)) # [1 1]


[텐서플로우 정리] 01. 텐서플로우 화면 출력 함수

텐서플로우가 왜 어려울까?
대부분의 사람들은 텐서플로우가 아니라 머신러닝이 어렵다고 한다.
텐서플로우를 사용하는 방법에 대한 소개는 정말 간략하고,
나머지는 머신러닝에서 텐서플로우가 적용되는 방식에 대해 설명한다.

텐서플로우를 사용하기 위한 기본 개념 일부를 코드로 정리했다.
당연한 것일 수도 있지만, 나는 이것 때문에 머신러닝을 익히는 것이 많이 힘들었다.

텐서플로우를 익히려면 Tensor 객체에 들어간 값의 확인이 첫 번째다.
그런데, 텐서플로우에서는 아직 모르기 때문에 값을 보여주려고 하지 않는다.
이번 줄에서 만든 코드가 어떤 데이터를 갖는지 알아야 다음 줄도 이해할 수가 있는데.. 말이다.

왜 이 생각을 못했는지 모르겠지만, 간단하게 처리할 수 있었다.
아래 함수들을 사용해서 텐서플로우를 공부했는데, 답답한 것 없이 너무 통쾌했다.

아래에는 상수, 변수, 연산자 등의 출력 함수가 있다. 모듈의 이름은 functions.py로 해서 import 해서 사용했다.
너무 간단한 관계로 코드에 대한 설명은 생략한다.
어찌 됐든 이 파일은 이후 나오는 텐서플로우 코드의 기본 코드로 활용된다.

# functions.py

import tensorflow as tf
import functools, operator

def getLength(t):
temp = (dim.value for dim in t.get_shape()) # dim is Dimension class.
return functools.reduce(operator.mul, temp)

def showConstant(t):
sess = tf.InteractiveSession()
print(t.eval())
sess.close()

def showConstantDetail(t):
sess = tf.InteractiveSession()
print(t.eval())
print('shape :', tf.shape(t))
print('size :', tf.size(t))
print('rank :', tf.rank(t))
print(t.get_shape())

sess.close()

def showVariable(v):
sess = tf.InteractiveSession()
v.initializer.run()
print(v.eval())
sess.close()

def var2Numpy(v):
sess = tf.InteractiveSession()
v.initializer.run()
n = v.eval()
sess.close()

return n

def op2Numpy(op):
sess = tf.InteractiveSession()
init = tf.initialize_all_variables()
sess.run(init)
ret = sess.run(op)
sess.close()

return ret

def showOperation(op):
print(op2Numpy(op))