TensorFlow2 A to Z

[Tensorflow2 강의자료] 1. Making Tensors

Shin's Lab 2020. 9. 28. 19:08

Tensors in Tensorflow

Tensorflow를 배우기 위해 알아야할 기본적인 tensor는 두 가지가 있다. 바로 아래의 4가지 중에 tf.Variable과 tf.constant이다.

https://www.tensorflow.org/guide/tensor?hl=ko

위의 두 가지 tensor는 각각 사용하는 용도가 다른데, tf.constant는 이름에서 알 수 있듯이 immutable object이다. 즉 내용 수정이 불가능하므로 학습에 필요한 input, label등에 사용될 수 있다. 단순히 immutable의 차이점이 아니라 우리가 딥러닝을 이용하여 학습을 진행할 때 input, label에 대한 학습은 할 필요가 없기 때문에 gradient가 자동으로 구해지지 않는 역할도 한다. 

 

한편 tf.Variable은 mutable object이다. 즉 내용의 값들이 바뀔 수 있고 training model의 weight, bias과 같은 trainable parameter는 iteration이 일어나면서 값이 바뀌어야 하므로 mutable object여야 한다. 추가적으로 학습 중 이 tf.Variable로 만들어진 object들은 gradient가 구해지고 이를 통해 값을 update할 수 있게 된다.

 

위의 차이점을 통해 Tensorflow 입문자들은 쉽게 dataset은 tf.constant, trainable parameter는 tf.Variable이라고 생각해도 큰 지장이 없다. 

 

 


Making Tensors in Tensorflow

글쓴이는 대부분의 Tensorflow 이용자들과 같이 Python 위에서 Tensorflow를 사용한다. Python 위에서 Tensorflow가 돌아가기 위해선 기존 Python primitive objects(예를 들어 Python list, string, number)들을 Tensorflow의 tensor로 만들어주는 API가 있으면 좋을 것이다. 당연히 Tensorflow는 이런 API들을 제공한다.

 

또한 data science에서 가장 많이 사용하는 data type은 Numpy array(ndarray)이다. 실제로 Tensorflow나 Pytorch의 tensor들은 모두 ndarray와 많이 닮아있다. 그래서 많은 tensor에 대한 operation들이 tf.를 np.로만 바꿔줘도 동작한다. 또한 OpenCV, Scikit-learn, Matplotlib과 같은 다양한 library들이 기존에 ndarray와 서로 공생관계에 있었으므로 Tensorflow도 ndarray로 부터 tensor를 만드는 API를 제공한다. 그리고 반대의 API도 물론 존재한다.

 

위와 같이 Tensorflow의 사용성을 확장하기 위해 Tensorflow에서는 tensor를 만드는 방법은 크게 세 가지

  • tf.constant
  • tf.convert_to_tensor
  • tf.Variable

가 있는데 이들은 모두 Python list, ndarry에서 tensor를 만들어낼 수 있다. 간단한 비교를 하고 살펴보도록 하자.

t1 = tf.constant([1, 2, 3])
t2 = tf.convert_to_tensor([1, 2, 3])
t3 = tf.Variable([1, 2, 3])

위에서 볼 수 있듯이 모두 Python list에서부터 tensor를 만들어낼 수 있고 arguemtn에 Python list나 ndarray를 넣어주면 된다. 각각의 tensor들을 출력해보면 다음과 같다

 

print(t1)
# tf.Tensor([1 2 3], shape=(3,), dtype=int32)
print(t2)
# tf.Tensor([1 2 3], shape=(3,), dtype=int32)
print(t3)
# <tf.Variable 'Variable:0' shape=(3,) dtype=int32, numpy=array([1, 2, 3], dtype=int32)>

t1, t2 tensor들은 서로 같은 결과가 나왔다. 즉, tf.constant와 tf.convert_to_tensor의 output은 같은 object라는 뜻일 것이다.

그리고 tf.Variable은 조금 다른 모습을 보이는 것을 알 수 있다. 그러면 각각의 data type을 출력해보자.

 

print(type(t1))
# <class 'tensorflow.python.framework.ops.EagerTensor'>
print(type(t2))
# <class 'tensorflow.python.framework.ops.EagerTensor'>
print(type(t3))
# <class 'tensorflow.python.ops.resource_variable_ops.ResourceVariable'>

예상한대로 tf.constant, tf.convert_to_tensor는 같은 object이고 tf.Variable은 다른 것을 알 수 있다. 이때 각각 EagerTensor, ResourceVariable이라는 클래스의 instant인 것을 확인할 수 있는데 이 타입에 따라 작동하는 방법이 달라지게 된다. 그럼 하나씩 살펴보자.

 


tf.constant

tf.constant의 argument에 Python list와 ndarray를 입력하면 다음과 같이 결과는 동일한 것을 알 수 있다. 즉 Python list와 ndarray를 가지고 Tensorflow의 constant tensor를 만들어낼 수 있다.

test_list = [1, 2, 3]
test_np = np.array([1, 2, 3])

t1 = tf.constant(test_list)
t2 = tf.constant(test_np)

print(t1)
# tf.Tensor([1 2 3], shape=(3,), dtype=int32)
print(t2)
# tf.Tensor([1 2 3], shape=(3,), dtype=int64)

 

추가적으로 다음을 통해서 constant tensor로부터 constant를 만들어낼 수 있는 것도 알 수 있다.

t3 = tf.constant(t1)
print(t3)
# tf.Tensor([1 2 3], shape=(3,), dtype=int32)

 


tf.Variable

tf.constant와 마찬가지로 tf.Variable에 Python list, ndarray를 이용하여 variable tensor를 만들어낼 수 있다. 이때 주의해야될 점은 tf.constant는 method이므로 소문자 c로 시작하고 tf.Variable은 클래스로부터 instance를 만들어내기 때문에 대문자 V로 시작한다. 이는 PEP8 convention을 따른 결과이다. 

test_list = [1, 2, 3]
test_np = np.array([1, 2, 3])

t1 = tf.Variable(test_list)
t2 = tf.Variable(test_np)

print(t1)
# <tf.Variable 'Variable:0' shape=(3,) dtype=int32, numpy=array([1, 2, 3], dtype=int32)>
print(t2)
# <tf.Variable 'Variable:0' shape=(3,) dtype=int64, numpy=array([1, 2, 3])>

 

추가적으로 다음을 실행시켜도 오류가 뜨지 않는다. 즉, constant tensor와 variable tensor를 모두 variable tensor로 만들 수 있다는 뜻이다. 이는 다음의 tf.convert_to_tensor를 설명하기 위해 미리 설명한다.

t3 = tf.constant(test_list)
t4 = tf.Variable(test_list)

t5 = tf.Variable(t3)
t6 = tf.Variable(t4)

 


tf.convert_to_tensor

마지막으로 tf.convert_to_tensor를 살펴보면 결과는 Python list, ndarray로부터 EagerTensor를 만들어내므로 동일한 API라고 생각할 수 있다. 하지만 다음의 코드를 실행시켜보면 오류가 발생하는 것을 알 수 있다.

test_list = [1, 2, 3]

t1 = tf.Variable(test_list)
t2 = tf.constant(t1)
# ValueError: TypeError: object of type 'ResourceVariable' has no len()

 

하지만 같은 과정을 tf.convert_to_tensor를 이용하면 다음과 같이 정상적으로 작동하는 것을 알 수 있다.

test_list = [1, 2, 3]

t1 = tf.Variable(test_list)
t2 = tf.convert_to_tensor(t1)

 

그럼 variable tensor를 constant tensor로 마음껏 바꿀 수 있을까?

test_list = [1, 2, 3]

t1 = tf.constant(test_list)
t2 = tf.Variable(t1)

위의 코드는 정상적으로 작동한다

 

여기서 '왜 이렇게 복잡하게 만들었을까?' 라는 질문이 생긴다. 이에 대해 글쓴이는 다음과 같이 추측한다.

딥러닝에서 학습을 시작할 때 trainable parameter를 initialization할 때를 제외하곤 크게 trainable parameter에 특정 값을 직접적으로 넣어줄 일이 없다. 이때는 variable이나 constant이나 initialization을 할 땐 크게 상관이 없다.

하지만 딥러닝 중에 variable을 다른 module에 전달해주는 경우는 많아도 아예 constant로 만들어버리는 경우는 많지 않다. 이 때문에 Tensorflow 개발자들이 실수를 방지하기 위함이 아닐까 생각한다.

 

물론 이 실수 하나 때문에 API를 만들진 않았을 것이다. 실제로 다양한 개발자들이 이 convert_to_tensor를 이용해 중간중간 tensor operation에 대한 custom function을 만들고 학습을 진행한다. 딱 이 이유 하나 때문은 아니겠지만 독자들은 이 차이점은 꼭 알고 넘어갔으면 좋겠다.

 

이상으로 이번 포스팅을 마치도록 한다.