[TENSORFLOW] Tensor, operator, variable 생성하기

2017. 4. 4. 13:58machine learning

TensorFlow를 사용하는 가장 큰 이유는 무엇보다 코드의 간결함 때문일 것이다. 

벡터 내적을 구하는 아래의 식을 우선 살펴보자.

revenue = 0

for price, amout in zip(prices, amounts):

revenue += price * amout


이번에는 numpy를 활용한 아래의 식을 살펴보자

import numpy as np

revenue = np.dot(prices, amounts)


numpy를 활용한 코드가 훨씬 간결함을 알 수가 있다. (하지만 이런 함수 제공이 마냥 좋은 것만은 아님..)

우리는 tensorFlow를 활용함으로써 machine learning을 보다 쉽게 접근해볼 수 있을 것이다.


Tensor 생성하기

tensorFlow라는 용어에서 언급된 것처럼 tensor라는 표현이 많이 나오는데, 우선 간단하게 벡터 축에 대한 행렬을 일반화 한 것을 tensor라고 정의한다고 알아 두자.

예를 들어 scala 같은 경우에는 벡터가 없기 때문에 0차원 tensor가 되고, 벡터는 축이 1개 있기 때문에 1차원 tensor가 된다. 

M x N 행렬의 경우에는 벡터 축이 2개이기 때문에 2차원 tensor가 되고, M x N x L 행렬의 경우에는 3차원 tensor가 되는 것이다.

그럼 이제 tensorFlow에서 어떻게 tensor를 만드는지를 살펴보자.

import tensorflow as tf

import numpy as np


m1 = [[1.0, 2.0], [3.0, 4.0]]

m2 = np.array([[1.0, 2.0], [3.0, 4.0]], dtype=np.float32)

m3 = tf.constant([[1.0, 2.0], [3.0, 4.0]])


t1 = tf.convert_to_tensor(m1, dtype=tf.float32)

t2 = tf.convert_to_tensor(m2, dtype=tf.float32)

m1, m2의 경우에는 각각 list와 ndarray 타입을 지니고 있기 때문에 convert_to_tensor를 통해 tensor 타입으로 바꿔주어야 한다. 

tensorFlow에서는 tensor 생성 시 편리한 생성자를 제공하는데 tf.zeros(shape)와 tf.ones(shape)이다.

tf.zeros(shape) 모든 값이 0으로 초기화 된 tensor를 만들어 주고, tf.ones(shape)는 모든 값이 1로 초기화된 tensor를 만들어 준다.


operation 생성하기

tensorFlow에서는 곱셈과 같은 연산자들을 operator라고 하는데 이러한 operator를 만들어 보자.

import tensorflow as tf

x = tf.constant([[1, 2]])

neg_x = tf.negative(x)

위의 negative는 입력 받은 값에 반대 부호를 취해주는 operator를 말하며, 위와 같이 operator를 실행했다고 하더라도 실제 명령이 실행되지는 않는다. 그 다음에 공부할 session에서 이에 대해 추가적으로 설명할 것이다.

tensorflow에는 아래와 같은 다양한 operator를 제공한다.

tf.add(x, y) 

같은 type의 두 개의 tensor를 더한다. x + y 

tf.subtract(x, y) 

 같은 type의 tensor를 뺀다. x - y

tf.multiply(x, y) 

두 개의 tensor를 곱한다. 여기서 곱은 행렬 곱이 아님. 각 요소끼리의 곱(dot) 

 tf.pow(x, y)

 x에 y제곱을 한다. 각 요소끼리의 제곱

 tf.exp(x)

 pow(e, x)와 동일함

 tf.sqrt(x)

 pow(x, 0.5)와 동일함

 tf.div(x, y)

 x에서 y를 나눈다. 각 요소끼리의 나눗셈

 tf.truediv(x, y)

 인수를 float로 변환하는 것을 제외하고는 tf.div와 같다.

 tf.floordiv(x, y)

 마지막 결과에 round down 하는 것을 제외하곤 truediv와 같다.

 tf.mod(x, y)

x에서 y를 나눈 나머지를 취한다. 각 요소에서의 나머지


session에서 operation 실행하기

tensorFlow에서는 session 내에서만 operation을 실행할 수가 있다. 방금 위에서 operation을 생성했어도 실행되지 않았던 것을 기억해내자.

import tensorflow as tf

x = tf.constant([[1., 2.]]

neg_op = tf.negative(x)


with tf.Session() as sess:

result = sess.run(neg_op)

result를 찍어보면 [-1, -2]가 나타남을 확인해 볼 수 있다.

debugging을 목적으로 interactive하게 명령을 실행시킬 수도 있는데, 아래와 같이 interactiveSession()을 선언하면 된다.

import tensorflow as tf

sess = tf.InteractiveSession()

x = tf.constant([[1., 2.]])

neg_x = tf.negative(x)

result = neg_x.eval()

sess.close()

session 선언 시 파라미터의 입력도 가능하다.

import tensorflow as tf

x = tf.constant([[1., 2.]])

neg_x = tf.negative(x)

with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as sess:

result = sess.run(neg_x)

위와 같이 입력하면, 현재 neg_x가 어떤 디바이스(CPU인지 GPU인지)에서 몇 번째 task로 동작하고 있는지를 log로 나타내 준다.


변수 사용하기

tensorflow 에서는 아래와 같이 변수를 사용할 수가 있다.

import tensorflow as tf

sess = tf.InteractiveSession()


raw_data = [1., 2., 8., -1., 0., 5.5, 6., 13]

spike = tf.Variable(False)

spike.initializer.run()


for i in range(1, len(raw_data)):

if raw_data[i] - raw_data[i-1] > 5:

updater = tf.assign(spike, True)

updater.eval()

else:

tf.assign(spike, False).eval()

sess.close()

현재 변수와 이전 변수의 차가 5 이상일 경우에 spike 변수에 True를 저장하고 5 이하일 경우에는 False를 저장하는 코드이다. tf.assign을 통해 변수를 저장하고 eval을 통해 실제 실행한다는 것만 알아두면 될 것 같다.

변수 저장하고 불러오기

저장한 변수에 대해 file로 저장하고 불러올 수가 있다. tensorflow를 차츰 익히다 보면 나중에는 학습 결과로 많은 양의 파라미터 값들이 나올텐데 이를 저장하고 불러서 다시 사용하는 것은 상당히 유용하다. 

우선 변수를 저장하는 것부터 살펴보자.

import tensorflow as tf

sess =tf.InteractiveSession()

raw_data = [1., 2., 8., -1., 0., 5.5, 6., 13]

spikes = tf.Variable([False] * len(raw_data), name='spikes')

spikes.initializer.run()

saver = tf.train.Saver({'spikes': spikes})


for i in range(1, len(raw_data)):

if raw_data[i] - raw_data[i-1] > 5:

spikes_val = spikes.eval()

spikes_val[i] = True

updater = tf.assign(spikes, spikes_val)

updater.eval()

save_path = saver.save(sess, "spikes.ckpt")

sess.close()

이번에는 raw_data 개수만큼의 spike boolean list를 만들었다. 만약에 raw_data 차이가 5 이상 발생하면 해당 spikes 리스트를 eval로 계산하고 계산 결과 리스트에서 해당 index 값을 True로 바꾼다.

그리고 assign을 통해 이전 변수 리스트에서 새로운 spike 변수 리스트로 변경한 후 eval을 통해 실행한다.

for문 위에 보면 tf.train.Saver라는 함수가 있으며, 이 함수에서 저장할 변수 명을 dict 형식으로 기입을 하고, 변수 계산이 다 끝난 다음 saver.save를 통해 저장하고자 하는 파일 명을 쓰면 해당 spike 변수가 spikes.ckpt에 저장이 된다.


이번에는 저장한 spikes.ckpt 변수를 로드해 보자.

sess = tf.InteractiveSession()

spikes = tf.Variable([False] * len(raw_data), name='spikes')

saver = tf.train.Saver({'spikes': spikes})

saver.restore(sess, "./spikes.ckpt")

print(spikes.eval())

sess.close()

우선 spikes 변수에 대해 False로 초기화를 한 후, 변수를 부르기 위해 saver 객체를 생성을 한다. 그 후 restore를 통해 불러오고자 하는 저장 파일을 파라미터로 넣은 후 spikes를 eval하면 기존 False list가 아닌 이전에 저장된 값들이 출력되는 것을 확인할 수 있다.