본문 바로가기
Python

[DL] Tensor 간의 변환: NumPy, PyTorch, TensorFlow

by ds31x 2024. 3. 15.

pytorch와 numpy의 경우, 텐서를 추상화하고 있는 tensor와 ndarray 를 제공하며, 이 둘은 zero-copy interoperability를 가진다고 말할 수 있을 정도로 상호호환이 가능하다.  TensorFlow도 numpy와 상당히 연관되어 있으나, 타입 변환에 있어서  pytorch보다는 불편한 부분이 있다.


from 파이썬 시퀀스 타입 (built-in) to 텐서 (numpy, tf, torch)

Python의 Sequence Type인 list, tuple 등을 통해

다음의 Tensor 인스턴스를 만들 수 있음.

  • np.array
  • torch.tensor
  • tf.constant (or tf.Variable)
t = (1,2,3,4,5,6)

a = np.array(t)
a_tf = tf.constant(t)
a_torch = torch.tensor(t)

from 텐서 (tf, torch) to ndarray (numpy)

tensor로부터 ndarray를 얻는 것은
일종의 새로운 view를 얻는 것으로 보는게 편함
numpy의 다양한 기능을 사용하여 tensor를 가공하기 위한 view

 

torchtensorflowtensor instance들은

numpyndarray (n-dimensional array) instance로 변환가능함.

a1 = a_tf.numpy()
a2 = a_torch.numpy()

 

주의할 점은 torch의 경우,
이같이 얻어진 ndarray 인스턴스는 원래의 tensor와 연결된 상태로,
한쪽에서 data 변경이 있을 경우 다른 쪽에도 영향을 준다. 

 

위의 경우는 torch의 tensor 인스턴스가 같이 cpu에서 동작하는 경우 (device="cpu")에 한정

(device가 다른 경우, underlying memory공유 자체가 불가함)

 

다음은 torch의 tensornumpy의 arrayunderlying memory가 공유됨.

a2[0] = 777
print(a2)
print(a_torch)

 

결과는 다음과 같음.

[777   2   3   4   5   6]
tensor([777,   2,   3,   4,   5,   6])

tensorflow의 tensor인 tf.constant instance는 immutable이기 때문에,
ndarray 인스턴스로 얻고나서 해당 ndarray 인스턴스를 변경한다해도
원래 tensorflow의 tensor 인스턴스에는 영향을 주지 않음.

 

실제로 tensorflow.python.framework.ops.EagerTensor 는 item assignment를 지원하지 않음

print(a1)
print(a_tf)
a1[0] = 888
print(a1)
print(a_tf)

 

결과는 다음과 같음.

[1 2 3 4 5 6]
tf.Tensor([1 2 3 4 5 6], shape=(6,), dtype=int32)
[888   2   3   4   5   6]
tf.Tensor([1 2 3 4 5 6], shape=(6,), dtype=int32)

만약 torch의 tensor 인스턴스의 경우에서 ndarray 인스턴스를 연결되지 않은 상태로 얻기 위해서는
copy 메서드를 사용함.

print(a_torch)
a3 = a_torch.numpy().copy()
a3[0] = 999
print(a3)
print(a_torch)

결과는 다음과 같음.

tensor([777,   2,   3,   4,   5,   6])
[999   2   3   4   5   6]
tensor([777,   2,   3,   4,   5,   6])

from ndarray (numpy) to 텐서 (tf, torch)

파이썬의 sequence type들과 비슷하게
numpy의 ndarray 인스터스로부터 tensor인스턴스를 얻을 수 있음.

t = (1,2,3,4,5,6)

a = np.array(t)
a_tf = tf.constant(a)
a_torch = torch.tensor(a)

다른 방식으로는 tf.convert_to_tensortorch.from_numpy을 이용할 수 있음.

t = (1,2,3,4,5,6)

a_tf = tf.convert_to_tensor(a)
a_torch = torch.from_numpy(a)
print(a_tf)
print(a_torch)

 

결과는 다음과 같음.

tf.Tensor([1 2 3 4 5 6], shape=(6,), dtype=int64)
tensor([1, 2, 3, 4, 5, 6])

 

주의할 점은
Real number(실수)의 경우 numpy는 flaot64를 기본으로 사용하나,
gpu 동작을 고려한 pytorch와 tensorflow는 float32를 기본으로 사용한다.

때문에 numpy로부터 gpu 사용을 염두에 둔  pytorch와 tensorflow의 텐서 객체를 얻을 경우,

반드시 float32로 dtype을 변환해야한다.

2024.03.15 - [Python] - [DL] Tensor: dtype 변경(casting) 및 shape 변경.

 

[DL] Tensor: dtype 변경(casting) 및 shape 변경.

Tensor를 추상화하고 있는 class로는 numpy.array: numpy의 ndarray torch.tensor tensorflow.constant: (or tensorflow.Variable) 이 있음. 이들은 Python의 sequence types과 달리 일반적으로 다음과 같은 특징을 지님. 데이터들

ds31x.tistory.com


torch 의 경우, copy를 사용하면 연결되지 않은 인스턴스를 얻을 수 있음.
(tf의 경우엔 앞서의 경우처럼 분리된 인스턴스가 얻어짐.)

다음 예제는 copy를 쓰지 않으면 연결된 객체로 얻어짐을 보여줌.

a_torch[0] = 999
print(a_torch)
print(a)

 

결과는 다음과 같음.

tensor([999,   2,   3,   4,   5,   6])
[999   2   3   4   5   6]

위의 예제에서 torch의 tensor 인스턴스를 변경한 내용이,
연결된 numpy의 ndarray 인스턴스에도 같이 반영됨.


같이 보면 좋은 자료들

https://dsaint31.tistory.com/456

 

[Programming] Primitive Data Type : C, C++, NumPy, Torch

Primitive Data Type이(Unboxed type)란? C, C++, NumPy, Torch, TensorFlow 등에서 numeric data type들은 보통 unboxed type이라고도 불리는 primitive data type들이다. unboxed type에서는 할당된 메모리 bit들이 해당 numeric data type

dsaint31.tistory.com

https://gist.github.com/dsaint31x/d14dcfe17fe9f1bad8ac86e6bf1bd1c5

 

dl_tensor_conversion.ipynb

dl_tensor_conversion.ipynb. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com