콘텐츠로 이동

텐서 vs NumPy

NumPy를 사용해본 적이 있다면 PyTorch 텐서는 매우 친숙하게 느껴질 것입니다. 두 라이브러리는 API 설계 철학이 유사하고, 많은 함수 이름도 동일합니다. 차이점은 PyTorch가 딥러닝에 필요한 두 가지 핵심 기능을 추가했다는 점입니다.


기능NumPy ndarrayPyTorch Tensor
다차원 배열
슬라이싱 / 인덱싱
브로드캐스팅
수학 연산
GPU 실행
자동 미분 (Autograd)
데이터 타입 제어
Python 생태계 통합✅ (광범위)✅ (딥러닝 중심)

NumPy와 PyTorch의 코드는 놀라울 정도로 비슷합니다.

import numpy as np
import torch
# 배열/텐서 생성
a = np.array([1, 2, 3, 4, 5])
t = torch.tensor([1, 2, 3, 4, 5])
# 형태 확인
print(a.shape) # (5,)
print(t.shape) # torch.Size([5])
# 기본 연산
print(a * 2) # [2 4 6 8 10]
print(t * 2) # tensor([ 2, 4, 6, 8, 10])
# 통계
print(a.mean()) # 3.0
print(t.mean()) # tensor(3.) ← 반환 타입이 텐서
# 슬라이싱
print(a[1:4]) # [2 3 4]
print(t[1:4]) # tensor([2, 3, 4])
# 차원 변환
print(a.reshape(5, 1).shape) # (5, 1)
print(t.reshape(5, 1).shape) # torch.Size([5, 1])

# NumPy: CPU만 사용 가능
a = np.array([1.0, 2.0, 3.0])
# a.cuda() → 불가능!
# PyTorch: GPU로 이동 가능
t = torch.tensor([1.0, 2.0, 3.0])
if torch.cuda.is_available():
t_gpu = t.cuda() # GPU로 이동
# 또는
t_gpu = t.to('cuda') # 동일한 결과
print(t_gpu.device) # device(type='cuda', index=0)
# Apple Silicon (M1/M2/M3)
if torch.backends.mps.is_available():
t_mps = t.to('mps')
print(t_mps.device) # device(type='mps', index=0)

GPU에서 수행하는 행렬 연산은 CPU 대비 수십 배에서 수백 배 빠를 수 있습니다. 이것이 딥러닝 학습 시간을 수일에서 수시간으로 줄여줍니다.

# NumPy: 수동으로 미분 계산해야 함
# PyTorch: requires_grad=True 설정으로 자동 계산
x = torch.tensor(2.0, requires_grad=True)
y = x ** 3 + 3 * x # y = x³ + 3x
y.backward() # 역전파 자동 실행
print(x.grad) # tensor(15.) → dy/dx = 3x² + 3 = 3(4) + 3 = 15

이 기능 덕분에 복잡한 신경망의 모든 파라미터에 대한 그레디언트를 단 한 줄 .backward()로 계산할 수 있습니다.


import numpy as np
import torch
# 방법 1: torch.from_numpy() — 메모리 공유
np_array = np.array([1.0, 2.0, 3.0])
tensor_shared = torch.from_numpy(np_array)
# 방법 2: torch.tensor() — 데이터 복사
tensor_copy = torch.tensor(np_array)
print(tensor_shared) # tensor([1., 2., 3.], dtype=torch.float64)
print(tensor_copy) # tensor([1., 2., 3.], dtype=torch.float64)
t = torch.tensor([4.0, 5.0, 6.0])
# .numpy() 메서드 사용
np_from_tensor = t.numpy()
print(np_from_tensor) # [4. 5. 6.]
print(type(np_from_tensor)) # <class 'numpy.ndarray'>

torch.from_numpy().numpy()메모리를 공유합니다. 한쪽을 수정하면 다른 쪽도 바뀝니다.

np_array = np.array([1.0, 2.0, 3.0])
tensor = torch.from_numpy(np_array)
# NumPy 배열 수정
np_array[0] = 999.0
print(np_array) # [999. 2. 3.]
print(tensor) # tensor([999., 2., 3.], dtype=torch.float64) ← 함께 변경됨!
# 반대 방향도 동일
tensor[1] = 777.0
print(np_array) # [999. 777. 3.] ← 역시 함께 변경됨!
# 독립 복사본 만들기
np_array = np.array([1.0, 2.0, 3.0])
# 방법 1: torch.tensor() — 항상 복사
tensor_independent = torch.tensor(np_array)
# 방법 2: .clone() — 기존 텐서 복사
tensor_shared = torch.from_numpy(np_array)
tensor_cloned = tensor_shared.clone()
# 이제 np_array를 수정해도 tensor_cloned는 변하지 않음
np_array[0] = 999.0
print(tensor_cloned) # tensor([1., 2., 3.], dtype=torch.float64) ← 변하지 않음

GPU 텐서는 .numpy()를 바로 쓸 수 없다

섹션 제목: “GPU 텐서는 .numpy()를 바로 쓸 수 없다”
t_gpu = torch.tensor([1.0, 2.0]).cuda()
# 오류 발생!
# t_gpu.numpy() → TypeError: can't convert CUDA tensor to numpy
# 먼저 CPU로 이동한 후 변환
np_array = t_gpu.cpu().numpy()
print(np_array) # [1. 2.]
# requires_grad=True인 텐서도 마찬가지
t_grad = torch.tensor([1.0, 2.0], requires_grad=True)
# t_grad.numpy() → RuntimeError
np_array = t_grad.detach().numpy() # detach() 후 변환
print(np_array) # [1. 2.]

상황권장 도구
데이터 전처리, 통계 분석NumPy
딥러닝 모델 학습PyTorch
시각화 (matplotlib 등)NumPy 또는 .numpy() 변환
GPU 연산이 필요한 경우PyTorch
기존 NumPy 코드와 연동from_numpy() 또는 torch.tensor()

  • NumPy와 PyTorch는 문법이 유사하여 전환이 쉽다
  • PyTorch의 핵심 추가 기능: GPU 가속 + 자동 미분
  • torch.from_numpy() → 메모리 공유 (주의 필요)
  • torch.tensor() → 항상 복사본 생성 (안전)
  • GPU 텐서는 .cpu() 후, grad 텐서는 .detach().numpy() 사용