[개념] Tensorflow 자료형

[상수(constants), 변수(Variable), 플레이스 홀더(placeholder)]


이것 저것 Tensorflow를 경험하고 기본으로 돌아오게 되었다.  검색을 통해 얻은 고마운 학습 자료들을 기반으로 정리해보고자 한다. 아래는 이글을 쓰기 위해 공부한 자료들이다.

Chanwoo Jacob Lee님의 Tensorflow 자료형

텐서플로우 한글 번역본(기본 사용법)

텐서플로우 첫걸음(Special notes-TF의 텐서와 상수, 변수, 플레이스홀더)


정의를 내리기엔 아직 실력이 부족하오니, 텐서플로우 한글 번역본(기본 사용법)의 힘을 빌린다.


기본 사용법(Basic Usage)


TensorFlow를 사용하기 위해 먼저 TensorFlow가 어떻게 동작하는지를 이해해 봅시다.

  • 연산은 graph로 표현합니다.(역자 주: graph는 점과 선, 업계 용어로는 노드와 엣지로 이뤄진 수학적인 구조를 의미합니다.)
  • graph는 Session내에서 실행됩니다.
  • 데이터는 tensor로 표현합니다.
  • 변수(Variable)는 (역자 주: 여러 graph들이 작동할 때도) 그 상태를 유지합니다.
  • 작업(operation 혹은 op)에서 데이터를 입출력 할 때 feed와 fetch를 사용할 수 있습니다.

출처: 텐서플로우 한글 번역본(기본 사용법)



graph 만들기(Building the graph)


graph를 만드는 것은 상수(constant)같이 아무 입력값이 필요없는 작업(op)을 정의하는 것에서부터 시작합니다. 이 op을 연산이 필요한 다른 op들에게 입력값으로 제공하는 것입니다.

+

파이썬 라이브러리의 작업 생성 함수(op constructor)는 만들어진 작업(op)들의 결과값을 반환합니다. 반환된 작업들의 결과값은 다른 작업(op)을 생성할 때 함수의 입력값으로 이용할 수 있습니다.

+

파이썬 라이브러리에는 작업 생성 함수로 노드를 추가할 수 있는 default graph라는 것이 있습니다. default graph는 다양하게 이용하기 좋습니다. Graph class 문서에서 여러 그래프를 명시적으로 관리하는 방법을 알 수 있습니다.


import tensorflow as tf

matrix1 = tf.constant([[3., 3.]])

matrix2 = tf.constant([[2.],[2.]])

product = tf.matmul(matrix1, matrix2)


default graph에는 이제 3개의 노드가 있습니다. 2개는 상수(constant) 작업(op)이고 하나는 행렬곱(matmul) 작업(op)이죠. 그런데 사실 행렬을 곱해서 결과값을 얻으려면 Session에다 graph를 실행해야 합니다.


출처: 텐서플로우 한글 번역본(기본 사용법)


Tensorflow로 뭔가를 작성 한다는 것은 그래프를 생성한다는 것이다. 연산 방식을 전부 그래프로 표현 할 수 있다. Tensorflow는 기본적으로 돌아갈때는 python 레벨에서는 연산을 허용하지 않는다. 


In [1]: import tensorflow as tf

In [2]: ph = tf.placeholder(tf.float32, shape=[3, 1])

In [3]: var = tf.Variable([1, 2, 3, 4, 5], dtype=tf.float32)

In [4]: const = tf.constant([10, 20, 30, 40, 50], dtype=tf.float32)

In [5]: print(ph)

Tensor("Placeholder:0", shape=(3, 1), dtype=float32)

In [6]: print(var)

<tf.Variable 'Variable:0' shape=(5,) dtype=float32_ref>

In [7]: print(const)

Tensor("Const:0", shape=(5,), dtype=float32)

메타 정보만 확인 시켜주고, 실제 값을 보여주지 않음을 볼 수 있다.


Tensorflow는 아래와 같은 수식을 갖는 모든 연산을 그래프로 정의하게 된다.

2(5 + 4) + 3(1 + 2) = ?




session에서 graph 실행하기(Launching the graph in a session)


graph를 구성하고 나면 Session 오브젝트를 만들어서 graph를 실행할 수 있습니다. op 생성함수에서 다른 graph를 지정해줄 때까지는 default graph가 Session에서 실행됩니다. 관련 내용은 Session class에서 확인할 수 있습니다.


sess = tf.Session()

result = sess.run(product)

print(result)

sess.close()



연산에 쓰인 시스템 자원을 돌려보내려면 session을 닫아야 합니다. 시스템 자원을 더 쉽게 관리하려면 with 구문을 쓰면 됩니다. 각 Session에 컨텍스트 매니저(역자 주: 파이썬의 요소 중 하나로 주로 'with' 구문에서 쓰임)가 있어서 'with' 구문 블락의 끝에서 자동으로 'close()'가 호출됩니다.

with tf.Session() as sess:

  result = sess.run([product])

  print(result)


TensorFlow의 구현 코드(TensorFlow implementation)를 통해 graph에 정의된 내용이 실행가능한 작업들(operation)로 변환되고 CPU나 GPU같이 이용가능한 연산 자원들에 뿌려집니다. 코드로 어느 CPU 혹은 GPU를 사용할 지 명시적으로 지정할 필요는 없습니다. 작업을 가능한 한 많이 처리하기 위해 TensorFlow는 (컴퓨터가 GPU를 가지고 있다면) 첫 번째 GPU를 이용하니까요.

... 생략

출처: 텐서플로우 한글 번역본(기본 사용법)


Tensorflow에서는 연산을 수행하는 방식이 따로 있다.

모든 연산을 그래프로 그리고 연산을 수행하도록 Run을 시키게 되면, 역행 연산을 수행하게 되고 input까지 수행하게 된다. 그리고 나서 run에 대한 리턴을 값을 돌려준다. 이렇게 그래프가 돌아가는 것을 텐서플로우에서는 세션이라고 부르며, 하나의 디바이스(CPU,GPU)에 올라가게 된다. 



세션은 그래프를 디바이스에 올려주는 역할을 한다. 세션은 IDE상에 존재 할 수 없다는 것은 다음과 같다.

Tensorflow에서는 파이썬 레벨, C레벨, Device 레벨 이 있다. 파이썬에서는 그래프를 생성하여 Device로 세션을 임베딩을 시키고 실제 연산은 C코드(펌웨어 레벨)에서 수행하게 된다.(C에서 연산을 수행한다고 보면 된다.)



Tensors


TensorFlow 프로그램은 모든 데이터를 tensor 데이터 구조로 나타냅니다. 연산 graph에 있는 작업들(op) 간에는 tensor만 주고받을 수 있기 때문입니다. TensorFlow의 tensor를 n 차원의 배열이나 리스트라고 봐도 좋습니다. tensor는 정적인 타입(static type), 차원(rank 역자 주: 예를 들어 1차원, 2차원하는 차원), 형태(shape, 역자 주: 예를 들어 2차원이면 m x n) 값을 가집니다. TensorFlow가 어떻게 이 개념들을 다루는지 알고 싶으시면 Rank, Shape, and Type을 참조하시기 바랍니다.


출처: 텐서플로우 한글 번역본(기본 사용법)


상수(Constant)

참고 :  Tensor 를 인자로 받는 함수들은  tf.convert_to_tensor 의 인자로 들어갈 수 있는 값들 또한 받을 수 있습니다.


상수값 텐서

※ TensorFlow는 상수를 생성할 수 있는 몇가지 연산을 제공합니다.

tf.constant(value, dtype=None, shape=None, name='Const')

상수 텐서를 생성합니다.

+

결과값 텐서는 value인자와 (선택적인) shape에 의해 결정됨으로써 dtype타입의 값으로 채워집니다. (아래 예시를 보세요.)

+

인자 value는 상수 또는 dtype타입을 가진 값들의 리스트가 될 수 있습니다. 만약 value가 리스트라면, 리스트의 길이는 shape인자에 의해 나올 수 있는 원소들의 갯수와 같거나 작아야 합니다. 리스트의 길이가 shape에 의해 정해지는 원소들의 갯수보다 적을 경우, 리스트의 마지막 원소가 나머지 엔트리를 채우는데 사용됩니다.

+

shape인자는 선택사항입니다. 만약 이 인자가 존재할 경우, 이는 결과값 텐서의 차원을 결정합니다. 그 외에는, value의 shape을 그대로 사용합니다.

+

만약 dtype인자가 결정되지 않을 경우에는, value로부터 타입을 추론하여 사용합니다.

+

예시:

# Constant 1-D Tensor populated with value list.

 tensor = tf.constant([1, 2, 3, 4, 5, 6, 7]) => [1 2 3 4 5 6 7]


 # Constant 2-D tensor populated with scalar value -1.

 tensor = tf.constant(-1.0, shape=[2, 3]) => [[-1. -1. -1.]

                                              [-1. -1. -1.]]

인자:
  • value: 반환 타입 dtype의 상수값 (또는 리스트).
  • dtype: 결과값 텐서 원소들의 타입.
  • shape: 결과값 텐서의 차원 (선택사항).
  • name: 텐서의 명칭 (선택사항).
반환값:

상수 Tensor.


출처: 텐서플로우 한글 번역본(상수, 시퀀스, 그리고 난수)


Constant는 변하지 않은 수를 말하며, 메소드이다. Constant는 자기 자신이 그래프가 되는 특징이 있다.


In [1]: import tensorflow as tf

In [2]: const = tf.constant([10, 20, 30, 40, 50], dtype=tf.float32)

In [3]: print(const)

Tensor("Const:0", shape=(5,), dtype=float32)

In [4]: sess = tf.Session()

2018-01-10 17:25:38.269961: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

2018-01-10 17:25:38.410758: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:892] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero

2018-01-10 17:25:38.411252: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 

name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582

pciBusID: 0000:01:00.0

totalMemory: 11.90GiB freeMemory: 11.75GiB

2018-01-10 17:25:38.411289: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Graphics Device, pci bus id: 0000:01:00.0, compute capability: 6.1)

In [5]: result = sess.run(const)

In [6]: print(result)

[ 10.  20.  30.  40.  50.]

In [7]: sess.close()


Tensorflow 상수를 a, b, c 생성하여 d = a * b + c 연산을 그래프로 그리고 세션을 생성하여 그래프를 기반으로 연산을 수행한다. 세션을 수행(Run)한 결과 값을 돌려 받아 출력하게 된다.


In [1]: import tensorflow as tf

In [2]: a = tf.constant([5])

In [3]: b = tf.constant([10])

In [4]: c = tf.constant([2])

In [5]: d = a * b + c

In [6]: sess = tf.Session()

2018-01-10 17:30:00.320623: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

2018-01-10 17:30:00.483778: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:892] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero

2018-01-10 17:30:00.484247: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 

name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582

pciBusID: 0000:01:00.0

totalMemory: 11.90GiB freeMemory: 11.75GiB

2018-01-10 17:30:00.484277: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Graphics Device, pci bus id: 0000:01:00.0, compute capability: 6.1)

In [7]: result = sess.run(d)

In [8]: print(result)

[52]

In [9]: sess.close()


변수(Variable)


변수: 생성, 초기화, 저장, 복구


모델을 학습 시킬 때, 매개 변수(parameter) 업데이트와 유지를 위해 변수(Variables)를 사용합니다. 변수는 텐서를 포함하는 인-메모리 버퍼입니다. 변수는 반드시 명시적으로 초기화해야 합니다. 그리고 학습 중 혹은 학습 후에 디스크에 저장할 수 있습니다. 저장된 값들을 모델 실행이나 분석을 위해 나중에 복원할 수도 있습니다.

+

이 문서는 다음 TensorFlow 클래스를 참조합니다. 링크를 따라가 API에 대한 자세한 설명이 있는 문서를 살펴보세요.

+

출처: 텐서플로우 한글번역본(변수: 생성, 초기화, 저장, 복구)



변수: 생성


변수(Variable) 를 생성할 때 Variable() 생성자의 초기값으로 Tensor 를 전달받게 됩니다. TensorFlow는 상수(constants) 또는 임의(random)의 값 으로 초기화 하는 다양한 명령어(op)를 제공합니다.

+

이 모든 명령어는 Tensor 들의 형태(shape)을 지정해줘야 합니다. 이 형태가 자동적으로 변수(Variable)의 형태가 됩니다. 변수는 대부분 고정된 형태를 가지지만 TensorFlow에서는 변수의 형태를 수정하기 위한(reshape) 고급 매커니즘도 제공합니다.


# 두 변수를 생성.

weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),

                      name="weights")

biases = tf.Variable(tf.zeros([200]), name="biases")

tf.Variable()호출은 그래프에 여러 오퍼레이션(op)을 추가합니다:

+

  • variable 오퍼레이션은 그 변수의 값을 가지고 있습니다.
  • tf.assign 오퍼레이션을 이용해서 변수의 초기값을 설정할 수 있습니다.
  • 예제에서 편차(bias)를 설정할 때 쓰이는 zeros 오퍼레이션같이 초기값을 설정하는 오퍼레이션도 그래프에 추가됩니다.

tf.Variable()에서 반환되는 값은 Python 클래스의 인스턴스인 tf.Variable 입니다.

+

출처텐서플로우 한글번역본(변수: 생성, 초기화, 저장, 복구)


Variable은 객체이며, Weight를 저장할 때 주로 쓴다.(weight matrix) Variable도 그래프를 만든다.


In [1]: import tensorflow as tf

In [2]: var1 = tf.Variable([5])

In [3]: var2 = tf.Variable([3])

In [4]: var3 = tf.Variable([2])

In [5]: var4 = var1 * var2 + var3

In [6]: print(var4)

Tensor("add:0", shape=(1,), dtype=int32)


변수: 초기화


변수 초기화는 모델의 다른 연산을 실행하기 전에 반드시 명시적으로 실행해야 합니다. 가장 쉬운 방법은 모든 변수를 초기화 하는 연산을 모델 사용 전에 실행하는 것입니다.

+

다른 방법으로는 체크포인트 파일에서 변수 값을 복원할 수 있습니다. 다음 챕터에서 다룰 것입니다.

+

변수 초기화를 위한 작업(op)을 추가하기 위해 tf.global_variables_initializer()를 사용해봅시다. 모델을 모두 만들고 세션에 올린 후 이 작업을 실행할 수 있습니다.

# 두 변수를 생성
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
                      name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")
...
# 변수 초기화 오퍼레이션을 초기화
init_op = tf.global_variables_initializer()

# 나중에 모델을 실행할때
with tf.Session() as sess:
  # 초기화 오퍼레이션을 실행
  sess.run(init_op)
  ...
  # 모델 사용
  ...

출처텐서플로우 한글번역본(변수: 생성, 초기화, 저장, 복구)


Variable은 weight 파라미터를 담아 놓는 공간이며, weight는 언제나 초기화를 해줘야 한다. Variable은 반드시 초기화가 필요한 텐서이다. 그렇지 않으면 오류가 발생한다.


In [1]: import tensorflow as tf

In [2]: var1 = tf.Variable([5])

In [3]: var2 = tf.Variable([3])

In [4]: var3 = tf.Variable([2])

In [5]: var4 = var1 * var2 + var3

In [6]: sess = tf.Session()

2018-01-10 17:35:56.018639: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

2018-01-10 17:35:56.172663: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:892] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero

2018-01-10 17:35:56.173178: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 

name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582

pciBusID: 0000:01:00.0

totalMemory: 11.90GiB freeMemory: 11.75GiB

2018-01-10 17:35:56.173302: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Graphics Device, pci bus id: 0000:01:00.0, compute capability: 6.1)

In [7]: result = sess.run(var4)

FailedPreconditionError (see above for traceback): Attempting to use uninitialized value Variable_1
[[Node: Variable_1/read = Identity[T=DT_INT32, _class=["loc:@Variable_1"], _device="/job:localhost/replica:0/task:0/device:CPU:0"](Variable_1)]]


초기화를 시켜줘야만 활성화가 된다. Tf.initialize_all_variables()를 먼저 run을 해줘야 그래프로서 효력이 발생하게 된다. Variable도 그래프를 만든다.


In [1]: import tensorflow as tf

In [2]: var1 = tf.Variable([5])

In [3]: var2 = tf.Variable([3])

In [4]: var3 = tf.Variable([2])

In [5]: var4 = var1 * var2 + var3

In [6]: sess = tf.Session()

2018-01-10 17:43:15.148039: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

2018-01-10 17:43:15.289761: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:892] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero

2018-01-10 17:43:15.290229: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 

name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582

pciBusID: 0000:01:00.0

totalMemory: 11.90GiB freeMemory: 11.75GiB

2018-01-10 17:43:15.290261: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Graphics Device, pci bus id: 0000:01:00.0, compute capability: 6.1)

In [7]: init = tf.initialize_all_variables()

WARNING:tensorflow:From /usr/local/lib/python2.7/dist-packages/tensorflow/python/util/tf_should_use.py:107: initialize_all_variables (from tensorflow.python.ops.variables) is deprecated and will be removed after 2017-03-02.

Instructions for updating:

Use `tf.global_variables_initializer` instead.

In [8]: sess.run(init)

In [9]: result = sess.run(var4)

In [10]: print(result)

[17]

In [11]: sess.close()


다른 변수값을 참조하여 초기화 하기


변수를 초기화할 때 다른 변수의 초기값을 참조해야 하는 경우가 있습니다. tf.global_variables_initializer() 연산으로 모든 변수를 초기화 해야 하는 경우에는 조심해야 합니다.

+

다른 변수의 값을 이용해서 새로운 변수를 초기화할 때는 다른 변수의 initialized_value() 속성을 사용할 수 있습니다. 어떤 변수의 초기값을 바로 새로운 변수의 초기값으로 사용할 수도 있고 새로운 변수값을 위한 계산용으로 쓸 수도 있습니다.

# 랜덤 값으로 새로운 변수 초기화
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),
                      name="weights")
# weights와 같은 값으로 다른 변수 초기화
w2 = tf.Variable(weights.initialized_value(), name="w2")
# weights의 2배 값으로 다른 변수 초기화
w_twice = tf.Variable(weights.initialized_value() * 2.0, name="w_twice")

출처텐서플로우 한글번역본(변수: 생성, 초기화, 저장, 복구)


Placeholder

플레이스홀더는 Placeholder 연산 노드를 가리키는 텐서이며 텐서플로우에서 그래프를 실행할 때 사용자가 데이터를 주입할 수 있는 통로입니다.


Feeds


위의 예제에서 살펴본 graph에서 tensor들은 상수(Constant)변수(Variable)로 저장되었습니다. TensorFlow에서는 graph의 연산에게 직접 tensor 값을 줄 수 있는 'feed 메커니즘'도 제공합니다.

+

feed 값은 일시적으로 연산의 출력값을 입력한 tensor 값으로 대체합니다. feed 데이터는 run()으로 전달되어서 run()의 변수로만 사용됩니다. 가장 일반적인 사용방법은 tf.placeholder()를 사용해서 특정 작업(op)을 "feed" 작업으로 지정해 주는 것입니다.

input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = input1 * input2

with tf.Session() as sess:
  print(sess.run([output], feed_dict={input1:[7.], input2:[2.]}))

# output:
# [array([ 14.], dtype=float32)]


만약 feed 를 제대로 제공하지 않으면 placeholder() 연산은 에러를 출력할 것입니다. feed를 이용하는 다른 예시는 MNIST fully-connected feed tutorial(source code)를 참조하시기 바랍니다.


출처: 텐서플로우 한글 번역본(기본 사용법)


Placeholder는 그래프를 생성하지 않고, 플레이스홀더는 텐서와 데이터를 매핑 시키는 역할을 한다.


In [1]: import tensorflow as tf

In [2]: value1 = 5

In [3]: value2 = 3

In [4]: value3 = 2

In [5]: ph1 = tf.placeholder(tf.float32)

In [6]: ph2 = tf.placeholder(tf.float32)

In [7]: ph3 = tf.placeholder(tf.float32)

In [8]: ph4 = ph1 * ph2 + ph3

In [9]: result_value = ph1 * ph2 + ph3

In [10]: feed_dict = {ph1: value1, ph2: value2, ph3: value3}

In [11]: sess = tf.Session()

2018-01-10 17:46:27.078009: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

2018-01-10 17:46:27.219116: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:892] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero

2018-01-10 17:46:27.219590: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 

name: Graphics Device major: 6 minor: 1 memoryClockRate(GHz): 1.582

pciBusID: 0000:01:00.0

totalMemory: 11.90GiB freeMemory: 11.75GiB

2018-01-10 17:46:27.219696: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Graphics Device, pci bus id: 0000:01:00.0, compute capability: 6.1)

In [12]: result = sess.run(result_value, feed_dict=feed_dict)

In [13]: print(result)

17.0

In [14]: sess.close()


이 포스팅은 머신러닝/딥러닝 오픈소스 Tensorflow 개발을 위한 선행학습으로 Tensorflow API Document의 Python API 대한 학습노트입니다.

Posted by 이성윤