Skip to main content

텐서 (Tensor)

텐서(Tensor)는 PyTorch의 기본 데이터 구조입니다. NumPy의 ndarray와 유사하지만, GPU 연산과 자동 미분(Autograd)을 지원합니다.

텐서 생성

import torch

# 직접 생성
x = torch.tensor([1, 2, 3])                    # 1차원 텐서
matrix = torch.tensor([[1, 2], [3, 4]])         # 2차원 텐서 (행렬)
tensor_3d = torch.tensor([[[1, 2], [3, 4]]])    # 3차원 텐서

# 특수 텐서 생성
zeros = torch.zeros(3, 4)           # 0으로 채운 3×4 행렬
ones = torch.ones(2, 3)             # 1로 채운 2×3 행렬
rand = torch.rand(3, 3)             # [0, 1) 균일 분포
randn = torch.randn(3, 3)           # 표준 정규 분포 N(0, 1)
arange = torch.arange(0, 10, 2)     # [0, 2, 4, 6, 8]
linspace = torch.linspace(0, 1, 5)  # [0.0, 0.25, 0.5, 0.75, 1.0]
eye = torch.eye(3)                  # 3×3 단위 행렬

# 기존 텐서와 같은 형태
x_like = torch.zeros_like(matrix)   # matrix와 같은 shape, 0으로 채움
x_rand = torch.rand_like(matrix, dtype=torch.float32)

print(f"shape: {matrix.shape}, dtype: {matrix.dtype}, device: {matrix.device}")

데이터 타입 (dtype)

dtype설명크기주 사용처
torch.float3232비트 부동소수4B기본 학습
torch.float1616비트 부동소수2BMixed Precision
torch.bfloat16Brain Float 16비트2B최신 GPU 학습
torch.int6464비트 정수8B레이블, 인덱스
torch.bool불리언1B마스크
# dtype 변환
x = torch.tensor([1.5, 2.7, 3.2])
x_int = x.to(torch.int64)       # float → int
x_half = x.to(torch.float16)    # float32 → float16
x_bool = x > 2.0                # 불리언 마스크

텐서 연산

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

# 요소별 연산
print(a + b)     # 덧셈
print(a * b)     # 요소별 곱셈 (Hadamard product)
print(a ** 2)    # 제곱

# 행렬 연산
print(a @ b)               # 행렬 곱 (matmul)
print(torch.matmul(a, b))  # 동일
print(torch.mm(a, b))      # 2D 전용

# 집계 연산
print(a.sum())            # 전체 합
print(a.mean(dim=0))      # 열 방향 평균
print(a.max(dim=1))       # 행 방향 최대값 (값 + 인덱스)
print(a.argmax(dim=1))    # 행 방향 최대값 인덱스

형태 변환 (Shape Manipulation)

x = torch.arange(12)

# reshape: 형태 변환
y = x.reshape(3, 4)        # 3×4로 변환
z = x.reshape(2, -1)       # 자동 계산: 2×6

# view: reshape과 유사하지만 메모리 연속성 필요
v = x.view(3, 4)

# squeeze / unsqueeze: 차원 추가/제거
a = torch.randn(1, 3, 1, 4)
print(a.squeeze().shape)       # (3, 4) — 크기 1인 차원 제거
print(a.squeeze(0).shape)      # (3, 1, 4) — 지정 차원만 제거

b = torch.randn(3, 4)
print(b.unsqueeze(0).shape)    # (1, 3, 4) — 0번째에 차원 추가
print(b.unsqueeze(-1).shape)   # (3, 4, 1) — 마지막에 차원 추가

# permute: 차원 순서 변경
img = torch.randn(3, 224, 224)         # CHW 형식
img_hwc = img.permute(1, 2, 0)         # HWC 형식으로 변환
print(f"CHW: {img.shape} → HWC: {img_hwc.shape}")

# flatten: 다차원을 1차원으로
flat = img.flatten()          # (3*224*224,)
flat_partial = img.flatten(1) # (3, 224*224) — 1번 차원부터 평탄화

# cat / stack: 텐서 결합
t1 = torch.randn(2, 3)
t2 = torch.randn(2, 3)
cat = torch.cat([t1, t2], dim=0)     # (4, 3) — 기존 차원에 이어 붙이기
stack = torch.stack([t1, t2], dim=0)  # (2, 2, 3) — 새 차원 추가

인덱싱과 슬라이싱

x = torch.arange(20).reshape(4, 5)
# tensor([[ 0,  1,  2,  3,  4],
#         [ 5,  6,  7,  8,  9],
#         [10, 11, 12, 13, 14],
#         [15, 16, 17, 18, 19]])

print(x[0])         # 첫 번째 행: [0, 1, 2, 3, 4]
print(x[:, 1])      # 두 번째 열: [1, 6, 11, 16]
print(x[1:3, 2:4])  # 부분 행렬: [[7, 8], [12, 13]]

# 불리언 인덱싱
mask = x > 10
print(x[mask])       # [11, 12, 13, 14, 15, 16, 17, 18, 19]

# 팬시 인덱싱
indices = torch.tensor([0, 2, 3])
print(x[indices])    # 0, 2, 3번째 행 선택

브로드캐스팅 (Broadcasting)

형태가 다른 텐서 간 연산 시 자동으로 차원을 맞춰줍니다. NumPy와 동일한 규칙을 따릅니다.
# (3, 4) + (4,) → (3, 4) + (1, 4) → (3, 4)
a = torch.randn(3, 4)
b = torch.tensor([1.0, 2.0, 3.0, 4.0])
result = a + b  # b가 (1, 4)로 확장 후 각 행에 더해짐

# (3, 1) + (1, 4) → (3, 4)
col = torch.tensor([[1], [2], [3]])  # (3, 1)
row = torch.tensor([10, 20, 30, 40])  # (4,)
result = col + row  # (3, 4) 결과

GPU 연산

# 디바이스 확인
if torch.cuda.is_available():
    device = torch.device('cuda')
elif torch.backends.mps.is_available():
    device = torch.device('mps')     # Apple Silicon
else:
    device = torch.device('cpu')

print(f"사용 디바이스: {device}")

# 텐서를 GPU로 이동
x = torch.randn(1000, 1000)
x_gpu = x.to(device)

# GPU에서 직접 생성
y_gpu = torch.randn(1000, 1000, device=device)

# GPU 연산 (CPU보다 대규모 행렬 연산에서 훨씬 빠름)
result = x_gpu @ y_gpu

# 결과를 CPU로 가져오기 (NumPy 변환 등에 필요)
result_cpu = result.cpu()
result_numpy = result_cpu.numpy()
CPU와 GPU 텐서 간 연산은 불가능합니다. 반드시 같은 디바이스에서 연산해야 합니다. RuntimeError: Expected all tensors to be on the same device 오류가 발생하면 디바이스를 통일하세요.

NumPy 변환

import numpy as np

# NumPy → PyTorch (메모리 공유)
np_array = np.array([1, 2, 3])
tensor = torch.from_numpy(np_array)   # 메모리 공유!
np_array[0] = 100
print(tensor)  # tensor([100, 2, 3]) — 원본 변경이 반영됨

# PyTorch → NumPy (CPU 텐서만 가능)
tensor = torch.tensor([4, 5, 6])
np_result = tensor.numpy()

# 메모리 복사 (독립적)
np_copy = tensor.detach().clone().numpy()

체크리스트

  • 다양한 방법으로 텐서를 생성할 수 있다
  • reshape, permute, squeeze 등 형태 변환을 활용할 수 있다
  • 텐서를 GPU로 이동하고 연산할 수 있다
  • NumPy와 PyTorch 텐서 간 변환 시 메모리 공유 여부를 이해한다

다음 문서