<scshin />

PyTorch Tensor 기초 정리: 딥러닝의 핵심 데이터 구조 이해하기

1. PyTorch Tensor란?

PyTorch Tensor는 PyTorch에서 데이터를 표현하는 가장 기본적인 자료구조입니다.
쉽게 말하면 NumPy 배열과 비슷하지만, 딥러닝 학습에 필요한 기능이 추가된 다차원 배열입니다.

PyTorch에서 모델의 입력값, 출력값, 가중치, 손실값, 기울기 계산은 대부분 Tensor를 중심으로 동작합니다.

이미지 데이터
텍스트를 숫자로 바꾼 데이터
모델의 가중치
예측 결과
손실값
기울기

이런 것들이 모두 Tensor 형태로 처리됩니다.

PyTorch를 공부할 때 Tensor를 먼저 이해해야 하는 이유는 간단합니다.

PyTorch 모델 학습 = Tensor 연산의 반복

즉, Tensor는 PyTorch 딥러닝의 출발점입니다.


2. Tensor와 NumPy 배열의 차이

PyTorch Tensor는 NumPy 배열과 매우 비슷합니다.
둘 다 숫자 데이터를 다차원 배열 형태로 다룰 수 있습니다.

import numpy as np
import torch

np_arr = np.array([1, 2, 3])
torch_tensor = torch.tensor([1, 2, 3])

print(np_arr)
print(torch_tensor)

하지만 Tensor는 NumPy 배열과 비교했을 때 딥러닝에 필요한 중요한 기능을 제공합니다.

구분 NumPy 배열 PyTorch Tensor
기본 용도 수치 계산 딥러닝, 수치 계산
GPU 연산 기본 지원하지 않음 CUDA GPU 연산 지원
자동 미분 지원하지 않음 autograd 지원
딥러닝 모델 학습 직접 구현 필요 PyTorch 모델과 바로 연동
주요 객체 numpy.ndarray torch.Tensor

정리하면 다음과 같습니다.

NumPy 배열은 일반 수치 계산에 많이 사용됩니다.
PyTorch Tensor는 딥러닝 학습과 GPU 연산에 최적화되어 있습니다.

3. Tensor 생성하기

PyTorch를 사용하려면 먼저 torch를 import합니다.

import torch

3.1 리스트로 Tensor 만들기

import torch

x = torch.tensor([1, 2, 3])

print(x)
print(type(x))

출력 예시는 다음과 같습니다.

tensor([1, 2, 3])
<class 'torch.Tensor'>

3.2 2차원 Tensor 만들기

x = torch.tensor([
    [1, 2, 3],
    [4, 5, 6]
])

print(x)

출력 결과는 다음과 같습니다.

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

이 Tensor는 2행 3열 구조입니다.


4. 자주 사용하는 Tensor 생성 함수

PyTorch에서는 다양한 방식으로 Tensor를 만들 수 있습니다.

4.1 0으로 채운 Tensor

x = torch.zeros(3, 4)

print(x)

출력 결과는 다음과 같습니다.

tensor([[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]])

4.2 1로 채운 Tensor

x = torch.ones(2, 3)

print(x)

4.3 랜덤 Tensor

x = torch.rand(2, 3)

print(x)

torch.rand()는 0 이상 1 미만의 랜덤값을 만듭니다.

4.4 정규분포 랜덤 Tensor

x = torch.randn(2, 3)

print(x)

torch.randn()은 평균이 0이고 표준편차가 1인 정규분포 기반 랜덤값을 만듭니다.

4.5 연속된 숫자 Tensor

x = torch.arange(0, 10)

print(x)

출력 결과는 다음과 같습니다.

tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

간격을 지정할 수도 있습니다.

x = torch.arange(0, 10, 2)

print(x)

출력 결과는 다음과 같습니다.

tensor([0, 2, 4, 6, 8])

5. Tensor의 기본 속성

Tensor를 다룰 때는 다음 속성을 자주 확인합니다.

shape
dtype
device
requires_grad

예제를 보겠습니다.

x = torch.tensor([
    [1, 2, 3],
    [4, 5, 6]
])

print("shape:", x.shape)
print("dtype:", x.dtype)
print("device:", x.device)
print("requires_grad:", x.requires_grad)

출력 예시는 다음과 같습니다.

shape: torch.Size([2, 3])
dtype: torch.int64
device: cpu
requires_grad: False

각 속성의 의미는 다음과 같습니다.

속성 설명
shape Tensor의 모양입니다.
dtype Tensor 안에 들어있는 데이터 타입입니다.
device Tensor가 CPU에 있는지 GPU에 있는지 나타냅니다.
requires_grad 자동 미분을 추적할지 여부입니다.

6. shape 이해하기

shape는 Tensor의 모양을 나타냅니다.

x = torch.zeros(2, 3)

print(x.shape)

출력 결과는 다음과 같습니다.

torch.Size([2, 3])

이 Tensor는 2행 3열입니다.

딥러닝에서 shape는 매우 중요합니다.
모델에 들어가는 입력 데이터의 shape가 맞지 않으면 오류가 발생합니다.

이미지 분류에서는 보통 다음과 같은 shape를 자주 봅니다.

[batch_size, channels, height, width]

예를 들어 이미지 32장을 한 번에 학습하고, 각 이미지가 RGB 3채널이며 크기가 224x224라면 shape는 다음과 같습니다.

[32, 3, 224, 224]

여기서 의미는 다음과 같습니다.

위치 의미
32 배치 크기
3 색상 채널 수
224 이미지 높이
224 이미지 너비

7. dtype 이해하기

dtype은 Tensor 안의 데이터 타입입니다.

x = torch.tensor([1, 2, 3])
print(x.dtype)

출력 결과는 다음과 같습니다.

torch.int64

실수 Tensor를 만들면 다음과 같습니다.

x = torch.tensor([1.0, 2.0, 3.0])
print(x.dtype)

출력 결과는 다음과 같습니다.

torch.float32

직접 dtype을 지정할 수도 있습니다.

x = torch.tensor([1, 2, 3], dtype=torch.float32)

print(x)
print(x.dtype)

딥러닝에서는 보통 torch.float32를 많이 사용합니다.
분류 문제의 정답 라벨은 torch.long 타입을 요구하는 경우가 많습니다.

예를 들어 nn.CrossEntropyLoss()를 사용할 때 정답 라벨은 클래스 인덱스 형태의 torch.long 타입이어야 합니다.

labels = torch.tensor([0, 1, 2], dtype=torch.long)

8. device 이해하기

device는 Tensor가 어디에서 연산되는지를 나타냅니다.

x = torch.tensor([1, 2, 3])

print(x.device)

출력 결과는 보통 다음과 같습니다.

cpu

GPU를 사용할 수 있다면 다음과 같이 device를 지정합니다.

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

print(device)

Tensor를 GPU로 이동할 수 있습니다.

x = torch.tensor([1, 2, 3], dtype=torch.float32)

x = x.to(device)

print(x.device)

모델과 데이터는 같은 device에 있어야 합니다.

model = model.to(device)
images = images.to(device)
labels = labels.to(device)

모델은 GPU에 있고 데이터는 CPU에 있으면 연산 오류가 발생합니다.


9. Tensor 연산

Tensor는 사칙연산을 지원합니다.

a = torch.tensor([1, 2, 3])
b = torch.tensor([10, 20, 30])

print(a + b)
print(a - b)
print(a * b)
print(b / a)

출력 결과는 다음과 같습니다.

tensor([11, 22, 33])
tensor([ -9, -18, -27])
tensor([10, 40, 90])
tensor([10., 10., 10.])

스칼라 값과도 연산할 수 있습니다.

x = torch.tensor([1, 2, 3])

print(x + 10)
print(x * 2)

10. 브로드캐스팅

브로드캐스팅은 서로 다른 shape의 Tensor끼리 연산할 때 자동으로 크기를 맞춰주는 기능입니다.

x = torch.tensor([
    [1, 2, 3],
    [4, 5, 6]
])

y = torch.tensor([10, 20, 30])

print(x + y)

출력 결과는 다음과 같습니다.

tensor([[11, 22, 33],
        [14, 25, 36]])

y가 각 행에 자동으로 더해진 것입니다.

브로드캐스팅은 편리하지만 shape를 제대로 이해하지 못하면 의도와 다른 연산이 될 수 있습니다.
따라서 연산 전에 shape를 확인하는 습관이 중요합니다.


11. 인덱싱과 슬라이싱

Tensor도 리스트나 NumPy 배열처럼 인덱싱과 슬라이싱을 할 수 있습니다.

x = torch.tensor([10, 20, 30, 40, 50])

print(x[0])
print(x[2])
print(x[-1])

2차원 Tensor에서는 행과 열 기준으로 접근합니다.

x = torch.tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(x[0, 0])
print(x[1, 2])
print(x[:, 0])

출력 결과는 다음과 같습니다.

tensor(1)
tensor(6)
tensor([1, 4, 7])

x[:, 0]은 모든 행의 0번째 열을 가져온다는 의미입니다.


12. Tensor 모양 바꾸기

딥러닝에서는 Tensor의 shape를 바꿔야 하는 경우가 많습니다.

12.1 reshape

x = torch.arange(0, 6)

print(x)

출력 결과는 다음과 같습니다.

tensor([0, 1, 2, 3, 4, 5])

2행 3열로 바꿔보겠습니다.

y = x.reshape(2, 3)

print(y)

출력 결과는 다음과 같습니다.

tensor([[0, 1, 2],
        [3, 4, 5]])

12.2 view

view()도 Tensor의 shape를 바꿀 때 사용합니다.

x = torch.arange(0, 6)
y = x.view(2, 3)

print(y)

view()는 메모리 연속성에 영향을 받을 수 있습니다.
처음 공부할 때는 reshape()를 먼저 사용하는 것이 편합니다.

12.3 unsqueeze

unsqueeze()는 특정 위치에 차원을 하나 추가합니다.

x = torch.tensor([1, 2, 3])

print(x.shape)

y = x.unsqueeze(0)

print(y)
print(y.shape)

출력 결과는 다음과 같습니다.

torch.Size([3])
tensor([[1, 2, 3]])
torch.Size([1, 3])

딥러닝에서는 배치 차원을 추가할 때 자주 사용합니다.

예를 들어 이미지 한 장을 모델에 넣으려면 [C, H, W][1, C, H, W]로 바꿔야 하는 경우가 많습니다.

image = image.unsqueeze(0)

12.4 squeeze

squeeze()는 크기가 1인 차원을 제거합니다.

x = torch.zeros(1, 3, 1, 4)

print(x.shape)

y = x.squeeze()

print(y.shape)

출력 예시는 다음과 같습니다.

torch.Size([1, 3, 1, 4])
torch.Size([3, 4])

13. Tensor 합치기

Tensor를 합칠 때는 torch.cat()torch.stack()을 자주 사용합니다.

13.1 torch.cat

torch.cat()은 기존 차원 방향으로 Tensor를 이어 붙입니다.

a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6]])

result = torch.cat([a, b], dim=0)

print(result)

출력 결과는 다음과 같습니다.

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

열 방향으로 붙일 수도 있습니다.

a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[10], [20]])

result = torch.cat([a, b], dim=1)

print(result)

출력 결과는 다음과 같습니다.

tensor([[ 1,  2, 10],
        [ 3,  4, 20]])

13.2 torch.stack

torch.stack()은 새로운 차원을 만들어서 Tensor를 쌓습니다.

a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])

result = torch.stack([a, b], dim=0)

print(result)
print(result.shape)

출력 결과는 다음과 같습니다.

tensor([[1, 2, 3],
        [4, 5, 6]])
torch.Size([2, 3])

14. NumPy와 Tensor 변환

PyTorch Tensor와 NumPy 배열은 서로 변환할 수 있습니다.

14.1 NumPy 배열을 Tensor로 변환

import numpy as np
import torch

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

tensor = torch.from_numpy(np_arr)

print(tensor)

14.2 Tensor를 NumPy 배열로 변환

tensor = torch.tensor([1, 2, 3])

np_arr = tensor.numpy()

print(np_arr)

GPU에 있는 Tensor는 바로 NumPy로 변환할 수 없습니다.
먼저 CPU로 이동해야 합니다.

tensor = tensor.cpu().numpy()

또한 자동 미분을 추적 중인 Tensor는 detach() 후 변환하는 경우가 많습니다.

np_arr = tensor.detach().cpu().numpy()

15. Autograd와 requires_grad

PyTorch Tensor의 중요한 기능 중 하나는 자동 미분입니다.
딥러닝 모델은 손실값을 기준으로 가중치를 업데이트하는데, 이때 기울기 계산이 필요합니다.

PyTorch에서는 requires_grad=True를 설정하면 해당 Tensor에 대한 연산을 추적합니다.

x = torch.tensor(2.0, requires_grad=True)

y = x ** 2

y.backward()

print(x.grad)

출력 결과는 다음과 같습니다.

tensor(4.)

수학적으로 보면 다음과 같습니다.

y = x²
dy/dx = 2x
x = 2일 때 dy/dx = 4

PyTorch가 이 미분값을 자동으로 계산한 것입니다.


16. backward 이해하기

backward()는 계산 그래프를 따라 기울기를 계산합니다.

x = torch.tensor(3.0, requires_grad=True)

y = x * x + 2 * x + 1

y.backward()

print(x.grad)

수식은 다음과 같습니다.

y = x² + 2x + 1
dy/dx = 2x + 2
x = 3일 때 dy/dx = 8

출력 결과는 다음과 같습니다.

tensor(8.)

딥러닝 학습에서는 이 과정이 모델의 모든 가중치에 대해 자동으로 수행됩니다.


17. detach와 no_grad

학습 중에는 기울기 계산이 필요하지만, 예측할 때는 필요하지 않습니다.

17.1 detach

detach()는 Tensor를 계산 그래프에서 분리합니다.

x = torch.tensor(2.0, requires_grad=True)
y = x ** 2

z = y.detach()

print(z.requires_grad)

출력 결과는 다음과 같습니다.

False

17.2 torch.no_grad

모델 예측 시에는 보통 torch.no_grad()를 사용합니다.

model.eval()

with torch.no_grad():
    outputs = model(inputs)

이렇게 하면 불필요한 기울기 계산을 하지 않으므로 메모리를 절약할 수 있습니다.


18. Tensor와 딥러닝 모델 입력

PyTorch 모델에 들어가는 입력 데이터는 Tensor입니다.

예를 들어 이미지 분류 모델에서는 입력 shape가 보통 다음과 같습니다.

[batch_size, channels, height, width]

예시:

images = torch.randn(32, 3, 224, 224)

print(images.shape)

출력 결과는 다음과 같습니다.

torch.Size([32, 3, 224, 224])

모델 출력은 보통 다음과 같습니다.

outputs = torch.randn(32, 10)

print(outputs.shape)

출력 결과는 다음과 같습니다.

torch.Size([32, 10])

이 의미는 다음과 같습니다.

32개 이미지에 대해
10개 클래스 점수를 출력

19. CrossEntropyLoss에서 Tensor 형태

분류 문제에서 자주 사용하는 손실 함수는 nn.CrossEntropyLoss()입니다.

이 함수는 보통 다음 형태를 기대합니다.

outputs shape: [batch_size, num_classes]
labels shape : [batch_size]

예시는 다음과 같습니다.

import torch
import torch.nn as nn

outputs = torch.tensor([
    [2.0, 0.5, 0.1],
    [0.2, 1.5, 0.3]
])

labels = torch.tensor([0, 1], dtype=torch.long)

criterion = nn.CrossEntropyLoss()

loss = criterion(outputs, labels)

print(loss)

여기서 outputs는 각 클래스에 대한 점수이고, labels는 정답 클래스 인덱스입니다.

첫 번째 데이터의 정답: 0번 클래스
두 번째 데이터의 정답: 1번 클래스

주의할 점은 CrossEntropyLoss에 넣는 outputs는 softmax 결과가 아니라 raw score입니다.
PyTorch의 CrossEntropyLoss 내부에서 softmax에 해당하는 처리가 함께 이루어집니다.


20. Tensor에서 자주 나는 오류

20.1 shape 오류

가장 흔한 오류는 shape가 맞지 않는 경우입니다.

RuntimeError: mat1 and mat2 shapes cannot be multiplied

이런 오류가 나면 먼저 shape를 출력해봐야 합니다.

print(x.shape)
print(outputs.shape)
print(labels.shape)

20.2 device 오류

모델은 GPU에 있고 데이터는 CPU에 있으면 오류가 발생합니다.

Expected all tensors to be on the same device

이럴 때는 모델과 데이터를 같은 device로 이동해야 합니다.

model = model.to(device)
inputs = inputs.to(device)
labels = labels.to(device)

20.3 dtype 오류

손실 함수가 기대하는 dtype과 다를 때 오류가 발생할 수 있습니다.

분류 라벨은 보통 torch.long이어야 합니다.

labels = labels.long()

회귀 문제의 입력과 정답은 보통 torch.float32를 사용합니다.

x = x.float()
y = y.float()

21. Tensor 기본 실습 예제

아래 코드는 Tensor의 기본 흐름을 한 번에 연습할 수 있는 예제입니다.

import torch

# 1. Tensor 생성
x = torch.tensor([
    [1.0, 2.0],
    [3.0, 4.0]
])

# 2. 기본 정보 확인
print("x:")
print(x)

print("shape:", x.shape)
print("dtype:", x.dtype)
print("device:", x.device)

# 3. 연산
y = x * 2 + 1

print("y:")
print(y)

# 4. 평균
mean_value = y.mean()

print("mean:", mean_value)

# 5. shape 변경
z = y.reshape(4)

print("z:")
print(z)
print("z shape:", z.shape)

# 6. GPU 사용 가능 여부 확인
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

z = z.to(device)

print("z device:", z.device)

22. Autograd 기본 실습 예제

import torch

# requires_grad=True 설정
x = torch.tensor(2.0, requires_grad=True)

# 계산식
y = x ** 3 + 2 * x

# 역전파
y.backward()

print("x:", x)
print("y:", y)
print("x.grad:", x.grad)

수식으로 보면 다음과 같습니다.

y = x³ + 2x
dy/dx = 3x² + 2
x = 2일 때 dy/dx = 14

따라서 x.grad14가 됩니다.