텐서 vs NumPy
NumPy를 알면 PyTorch가 쉽다
섹션 제목: “NumPy를 알면 PyTorch가 쉽다”NumPy를 사용해본 적이 있다면 PyTorch 텐서는 매우 친숙하게 느껴질 것입니다. 두 라이브러리는 API 설계 철학이 유사하고, 많은 함수 이름도 동일합니다. 차이점은 PyTorch가 딥러닝에 필요한 두 가지 핵심 기능을 추가했다는 점입니다.
유사점과 차이점 한눈에 보기
섹션 제목: “유사점과 차이점 한눈에 보기”| 기능 | NumPy ndarray | PyTorch Tensor |
|---|---|---|
| 다차원 배열 | ✅ | ✅ |
| 슬라이싱 / 인덱싱 | ✅ | ✅ |
| 브로드캐스팅 | ✅ | ✅ |
| 수학 연산 | ✅ | ✅ |
| GPU 실행 | ❌ | ✅ |
| 자동 미분 (Autograd) | ❌ | ✅ |
| 데이터 타입 제어 | ✅ | ✅ |
| Python 생태계 통합 | ✅ (광범위) | ✅ (딥러닝 중심) |
문법 비교
섹션 제목: “문법 비교”NumPy와 PyTorch의 코드는 놀라울 정도로 비슷합니다.
import numpy as npimport 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.0print(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])PyTorch만의 강점
섹션 제목: “PyTorch만의 강점”1. GPU 가속
섹션 제목: “1. GPU 가속”# 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 대비 수십 배에서 수백 배 빠를 수 있습니다. 이것이 딥러닝 학습 시간을 수일에서 수시간으로 줄여줍니다.
2. 자동 미분 (Autograd)
섹션 제목: “2. 자동 미분 (Autograd)”# 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()로 계산할 수 있습니다.
상호 변환: NumPy ↔ PyTorch
섹션 제목: “상호 변환: NumPy ↔ PyTorch”NumPy → PyTorch
섹션 제목: “NumPy → PyTorch”import numpy as npimport 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)PyTorch → NumPy
섹션 제목: “PyTorch → NumPy”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.0print(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.0print(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()사용