PyTorch & Tensor

nalimeitb·2025년 9월 8일

PyTorch & Tensor

Tensor는 PyTorch의 핵심 data 구조이고 NumPy의 다차원 배열인 ndarray와 유사하다고 볼 수 있다.
scalar, vector, matrix, ... 를 모두 아우르는 data structure 이다.

PyTorch는 왜 Tensor를 핵심 data structure로 삼았는가?

Tensors are a specialized data structure that are very similar to arrays and matrices. In PyTorch, we use tensors to encode the inputs and outputs of a model, as well as the model’s parameters.

Tensors are similar to NumPy’s ndarrays, except that tensors can run on GPUs or other hardware accelerators. In fact, tensors and NumPy arrays can often share the same underlying memory, eliminating the need to copy data (see Bridge with NumPy). Tensors are also optimized for automatic differentiation

https://docs.pytorch.org/tutorials/beginner/basics/tensorqs_tutorial.html

다른 배열들과 달리, Tensor는 차원 확장성이 뛰어나고 다양한 연산을 지원하기 때문에 딥러닝의 핵심인 automatic differentiation 연산과 GPU 가속을 지원하여 효율적인 연산이 가능하도록 하고, 뿐만 아니라 Tensor로 model의 input/output data를 저장하고 model의 grdient와 parameters를 나타낼 수 있다.

torch.tensor

PyTorch의 핵심인 Tensor
어떻게 만들 수 있을까?

앞서 이야기 했던 것처럼,
Tensor와 유사한 기존의 배열들(list, tuple, ndarray 등)과
스칼라값 등 다양한 data를 가지고
Tensor로 생성하는 것을 떠올려 볼 수 있다.

기존 data로 Tensor를 만들 수 있는 방법은
torch.tensor는 Tensor를 생성하는 함수를 이용해,
parameter의 data 넣어 Tensor로 생성하는 것이다.

  • Parameters
    data (array_like) – Initial data for the tensor.
    Can be a list, tuple, NumPy ndarray, scalar, and other types.

https://docs.pytorch.org/docs/stable/generated/torch.tensor.html

torch.tensor의 기본 문법은 일반적으로,
torch.tensor(data, dtype = None, device = None)의 형태를 띈다.
이때, torch.tensor의 파라미터로
data에는 Tensor로 변환할 data,
dtype에는 생성할 Tensor의 데이터 타입,
device에는 Tensor를 생성할 device를 지정할 수 있다.

NumPy ndarray to Tensor

다만, numpy의 ndarray를 가지고 Tensor를 생성하는 것은 두가지 방법이 있다.

1) 기존 방식대로 torch.tensor(ndarray)로 생성 -> 복사본
2) torch.from_numpy(ndarray)로 생성 -> 메모리 공유

전자는 기존 NumPy 배열을 복사하여 새로운 Tensor를 만든 것이기 때문에, 메모리를 공유하지 않는 특징이 있는데 반해 후자는 기존 NumPy 배열과 메모리를 공유하므로 Tensor를 변경하면 NumPy 배열의 값도 변한다는 점에 유의해야 한다.

dtype

  • Keyword Arguments
    dtype (torch.dtype, optional) – the desired data type of returned tensor.
    Default: if None, infers data type from data.

https://docs.pytorch.org/docs/stable/generated/torch.tensor.html

torch.tensor에 들어갈 수 있는 파라미터로 dtype이 있다.
dtype 파라미터는 생성할 Tensor 자료형을 구체적으로 지정해줄 수 있다.

만약 dtype 별도로 설정하지 않는다면, parameter의 data에 따른 default가 적용된다.
(예를 들어 NumPy ndarray는 torch.int가 default가 된다.)

Tensor의 dtype은 크게 int형과 float형으로 나눌 수 있다.

Int 자료형

torch.uint8(unsigned integer 8bit)
torch.int8(signed integer 8bit)
torch.int16 or torch.short
torch.int32 or torch.int
torch.int64 or torch.long

Float 자료형

크게 고정소수점형과 부동소수점형으로 나눌 수 있는데,
고정소수점형은 소수점 이하 각 자리마다 소수부를 따로 저장해야 하기 때문에
메모리 측면에서 큰 문제점이 있었고,
(각 소수점 아래 자리마다 0~9까지 수를 지정해주기 위해서 4bit씩 필요)
이에 대한 대안으로 부동소수점형이 제안되었다.

부동소수점형은 떠다닐 부, 움직일 동을 써서
소수점의 위치를 고정하지 않고 그 위치를 따로 적는 형식을 말한다.

부동소수점형 자료형은 숫자가 주어지면
이를 정규화하여 x.xxx * 10^y 꼴로 변환한다.
유효숫자를 나타내는 가수 x.xxx와
소수점의 위치를 풀이하는 지수 10^y로
나누어 주어진 수를 표현할 수 있다.

torch.float32 or torch.float
torch.float64 or torch.double

Type Casting

타입캐스팅은 하나의 datatype에서 다른 datatype으로 변환하는 것을 말한다.

딥러닝에서 model의 매개변수와 gradient는 매우 큰 Tensor 형태로 저장되고 연산되는데, 이 때 더 작은 데이터형으로 Type casting 하면 같은 크기의 Tensor라도 메모리 사용량에 대한 부담을 덜을 수 있고, GPU 메모리 한도 내에서 더 큰 모델이나 더 많은 batch를 다룰 수 있게 되는 다양한 이점이 있을 수 있다.

하지만, 적합하지 않은 너무 작은 데이터형을 사용하면 수치 정밀도가 떨어질 수 있어 적절한 균형을 맞추는 것이 중요하다.

# 32비트 부동 소수점형 datatype의 tensor로 변환

i = torch.tensor([2, 3, 4], dtype = torch.int8)
j = i.float()
print('j.dtype =', j.dtype)

# 64비트 부동 소수점형 datatype의 tensor로 변환

k = j.double()
print('k.dtype =', k.dtype)

device

A torch.device is an object representing the device on which a torch.Tensor is or will be allocated.

https://docs.pytorch.org/docs/stable/tensor_attributes.html#torch.device

  • Keyword Arguments
    device (torch.device, optional) – the device of the constructed tensor. If None and data is a tensor then the device of data is used. If None and data is not a tensor then the result tensor is constructed on the current device.

https://docs.pytorch.org/docs/stable/generated/torch.tensor.html

torch.tensor에 들어갈 수 있는 파라미터로 device가 있다.
device는 해당객체가 어디에 위치할 지, 어디에 할당할지를 결정하며,
device는 CPU와 CUDA 유형이 보편적으로 사용된다.
device를 CUDA로 설정하지 않았다면 current device인 CPU로 할당된다.
이 device 파라미터에 따라 CPU Tensor, CUDA Tensor로 분류하기도 한다.

# 현재 내가 대하는 Tensor가 어떤 device에 있는지 확인하는 코드

a = torch.tensor([1, 2, 3])
# tensor a가 어떤 device에 있는지 확인
a.device
# device(type='cpu')

CUDA Tensor

  • device를 CUDA로 설정하기 위해서는 현재 내가 CUDA를 사용할 수 있는 환경인지 우선 확인해야 한다.
    torch.cuda.is_available()

  • 그리고 사용가능한 GPU 개수를 확인할 수 있다.
    torch.cuda.device_count()

  • CUDA device의 이름을 확인하는 함수를 통해 어떤 GPU를 할당했는지 확인할 수 있다.
    torch.cuda.get_device_name(device = 0)

  • CPU Tensor를 GPU에 할당하는 코드
    torch.tensor(tensorname).to(device = 'cuda')
    torch.tensor(tensorname).cuda()
    torch.tensor(tensorname, device = 'cuda')

  • CUDA Tensor를 CPU에 할당하는 코드
    tensorname.to(device = 'cpu')
    tensorname.cpu()

Tensor Attributes

이전까지 torch.tensor 함수로 Tensor를 만들어 보았다.
그렇다면 이렇게 만든 이 Tensor객체는 어떤 Attributes를 가질 수 있는가?
이 Attributes로 하여금 Tensor의 어떤 특성을 확인할 수 있는가?

많은 속성들이 있겠지만, 앞서 다루었던 dtype, device 외에
Tensor의 특성을 확인할 수 있는 주요한 Attributes를 알아보자.

Tensor의 차원

Tensor의 차원은 Tensor의 중요한 특성으로 볼 수 있다.
Dimension은 Tensor가 몇 개의 축(axis)를 가지고 있는지 알 수 있다.
0-D Tensor은 스칼라
1-D Tensor은 벡터
2-D Tensor은 행렬
...
N-D Tensor를 가질 수 있다.

Dimension 특성은 해당 Tensor, Data가 어떤 구조로
이루어져 있는지 확인할 수 있고
적절한 연산과 모델 설계에 필요한 기초 정보를 얻을 수 있다.

# tensor의 차원의 수를 확인하는 메서드
# Tensor.dim() → int
# Returns the number of dimensions of self tensor.

print('l.dim() =', l.dim())

Tensor의 모양

Tensor의 모양은 Tensor의 또 다른 중요한 특성이다.
Tensor의 shape 또는 size은 각 차원별 크기를 의미한다.

예를 들어)
shape이 (2, 3, 4)인 3-D Tensor는 일반적으로,
2개의 깊이(axis 0), 3개의 행(axis 1), 4개의 열(axis 2)을 가진 Tensor라고 확인할 수 있다.

shape 또한, Tensor가 어떤 데이터 구조인지 파악하고
또, 데이터를 어떻게 저장하고 연산할지 이해하는데 큰 도움을 줄 수 있다.

# tensor의 모양(크기)를 확인하는 메서드

# Returns the size of the self tensor.
l.size()
print('l.size() =', l.size())

# Returns the size of the self tensor. Alias for size.
l.shape
print('l.shape =', l.shape)

Tensor의 원소 개수

Tensor의 원소 개수를 파악하는 것 또한 Tensor의 중요한 특성이다.
Tensor의 dim, shape만 가지고 해당 Tensor의 원소의 개수를
정확하게 파악하기 어려울 수 있다. (복잡한 경우에)
따라서, 총 개수가 몇 개인지 따로 파악하는 것이 중요할 수 있다.

또한, 총 원소의 개수를 파악하는 것은 Tensor가 차지하는
메모리, 파라미터 수, 연산량 등을 따질 수 있는 기본단위가 되고
데이터 전처리, 크기 조정 등의 작업을 하는 데 있어 중요하다.

# tensor내의 요소들의 총 개수를 확인하는 메서드

# numel = number of elements
l.numel()
print('l.numel() =', l.numel())

0개의 댓글