NumPy 없이 PyTorch만 해도 되나요?
딥러닝 개발자라면 한 번쯤 헷갈렸던 그 관계 정리
파인튜닝 코드들을 보다 보면 항상 같이 등장하는 두 이름이 있습니다.
import numpy as np
import torch
“아니, 텐서 연산은 파이토치에 다 있는데… 굳이 넘파이(NumPy)가 왜 필요하지?” “둘이 컨셉이 겹치는 것 같은데, 넘파이를 따로 공부해야 하나?”
저도 정확히 이 부분이 궁금했고, 그걸 깔끔하게 설명해 준 답변을 바탕으로 내용을 정리해 봤습니다.
1. NumPy와 PyTorch, 도대체 뭐가 다른가?
아주 거칠게 말하면 파이토치는:
“GPU에 올라간 NumPy + 자동 미분(autograd)”
이라고 볼 수 있습니다.
역할을 나눠보면:
-
NumPy
-
CPU 위에서 돌아가는 배열/행렬 라이브러리
- 수치 계산, 선형대수, 통계 연산의 사실상 “파이썬 표준”
-
ndarray라는 자료구조를 중심으로 동작 -
PyTorch
-
NumPy와 거의 같은 스타일의 API
- 하지만 CPU뿐 아니라 GPU(CUDA) 에도 올라갈 수 있고
- 텐서 연산에 대해 자동 미분을 지원 → 딥러닝 학습이 가능
파이토치 개발자들이 아예 의도적으로 NumPy 문법을 거의 베꼈습니다.
np.array([...])→torch.tensor([...])x_np.shape→x_torch.shapenp.reshape(x, ...)→x_torch.view(...)또는x_torch.reshape(...)
그래서 파이토치의 텐서 연산을 익히다 보면, 자연스럽게 NumPy 스타일의 사고방식과 문법까지 함께 익히게 됩니다.
2. “NumPy 먼저 공부해야 하나요?”에 대한 현실적인 답
많은 튜토리얼이 NumPy부터 시작해서 헷갈리기 쉬운데, 실무적인 관점에서 답을 내리면 이렇습니다.
NumPy를 각 잡고 먼저 공부할 필요까지는 없습니다. PyTorch가 텐서 연산부터 바로 시작해도 충분합니다.
이유는 간단합니다.
- 텐서의 모양/브로드캐스팅/인덱싱 같은 개념은 NumPy와 PyTorch가 거의 똑같이 동작합니다.
- 딥러닝을 할 때 우리가 진짜로 많이 쓰는 건 “딥러닝 모델을 위한 텐서 연산 + 자동 미분”이고, 이건 어차피 파이토치 쪽에만 있습니다.
그래서 딥러닝이 목적이라면:
- 파이토치 텐서 조작법을 먼저 익히고
- 코드 중간에
np.xxx가 보일 때 “아, 이건 파이토치에서 하던 그거를 CPU 배열 버전으로 쓰는구나” 정도로 이해해도 충분합니다.
3. 그런데도 NumPy의가 계속 보이는 이유: “생태계의 공용어”
그럼 이런 의문이 듭니다.
“파이토치가 더 강력한데, 그냥 다 파이토치 텐서로 하면 안 되나?”
안 되는 이유가 하나 있습니다. 파이썬 데이터/과학 생태계의 대부분이 넘파이를 기준으로 설계되어 있기 때문입니다.
3-1. 데이터 전처리 단계: NumPy의 세상
데이터를 준비할 때 자주 쓰는 라이브러리들을 보면:
OpenCV,Pillow→ 이미지 읽으면 보통 NumPy 배열로 반환pandas→DataFrame.values/to_numpy()등으로 넘파이 배열을 사용- 각종 통계/수치 패키지들 → 입력/출력이 대부분 NumPy 기준
즉 “모델에 넣기 전까지의 데이터 조작”은 대부분 NumPy로 이루어지는 경우가 많습니다.
3-2. 모델 학습/추론 단계: PyTorch의 세상
이제 딥러닝 모델에 넣으려면:
import numpy as np
import torch
x_np = ... # 전처리 결과 NumPy 배열
x_tensor = torch.from_numpy(x_np) # 텐서로 변환
x_tensor = x_tensor.to("cuda") # GPU에 올림
out = model(x_tensor)
이 구간부터는 파이토치의 텐서 월드입니다.
3-3. 시각화·저장·후처리 단계: 다시 NumPy의 세상
모델이 예측한 결과를:
matplotlib로 그래프 그리기- 다시
pandas에 넣어서 CSV로 저장 - 간단한 통계 계산
이런 걸 하려면 이 라이브러리들도 대부분 넘파이 배열을 기준으로 동작합니다.
그래서 다시 텐서를 넘파이로 바꿔야 하죠.
out_cpu = out.detach().cpu().numpy()
여기서 자주 보는 에러가 바로 이거입니다:
TypeError: can't convert cuda:0 device type tensor to numpy
GPU에 있는 텐서를 바로 .numpy()로 바꾸려 하면 생기고,
반드시 .cpu().numpy()로 CPU로 내린 뒤 넘파이로 변환해야 합니다.
4. 시스템 관점에서 중요한 포인트: “Zero-Copy” 공유
조금 더 저수준 관점에서 재밌는 포인트가 하나 있습니다.
x_np = np.random.randn(3, 3)
x_tensor = torch.from_numpy(x_np) # 여기!
여기서 실제로는 데이터가 복사되지 않습니다.
torch.from_numpy(...)는 넘파이가 쓰던 메모리를 그대로 공유하는 텐서를 만듭니다.- 즉, 거대한 배열을 변환해도 추가 메모리를 거의 쓰지 않는 구조입니다.
반대로:
x_np2 = x_tensor.numpy()
도 마찬가지로 (CPU 텐서라면) 같은 메모리를 바라보는 NumPy 배열이 됩니다.
그래서 이런 일도 벌어집니다.
x_np = np.zeros((2, 2))
x_tensor = torch.from_numpy(x_np)
x_tensor[0, 0] = 1
print(x_np)
# [[1. 0.]
# [0. 0.]] ← 넘파이 배열도 같이 바뀜
둘이 서로의 “창문”처럼 같은 데이터를 보는 셈이죠.
정리하면:
- 파이토치와 넘파이는 CPU 상에서 메모리를 공유할 수 있고
- 덕분에 “전처리(NumPy) ↔ 학습(PyTorch) ↔ 후처리(NumPy)”를 큰 복사 비용 없이 오갈 수 있습니다.
5. 전체 흐름을 한 번에 보는 간단 예제
아주 단순한 이미지 분류 예시를 가정하면:
import cv2
import numpy as np
import torch
# 1. 이미지 로딩 & NumPy 전처리 (NumPy 영역)
img = cv2.imread("cat.png") # shape: (H, W, C), BGR, NumPy array
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (224, 224))
img = img.astype(np.float32) / 255.0
img = np.transpose(img, (2, 0, 1)) # (C, H, W)
# 2. NumPy -> PyTorch 텐서 변환 & GPU로 이동 (PyTorch 영역)
x = torch.from_numpy(img) # shape: (3, 224, 224)
x = x.unsqueeze(0) # 배치 차원 추가: (1, 3, 224, 224)
x = x.to("cuda")
# 3. 모델 추론
with torch.no_grad():
logits = model(x)
probs = torch.softmax(logits, dim=1)
# 4. 결과를 다시 NumPy로 변환해 후처리/시각화 (NumPy 영역)
probs_np = probs.cpu().numpy()
pred_class = np.argmax(probs_np, axis=1)[0]
코드 흐름을 보면 자연스럽게:
- 입력/출력 경계엔 NumPy
- 중간의 학습/추론엔 PyTorch
가 자리 잡고 있다는 걸 알 수 있습니다.
6. 최종 정리: 이렇게 이해하면 편해진다
정리하면, 이 정도 관점이면 충분합니다.
- 파이토치를 공부하는 것은 “미래형 넘파이”를 배우는 것과 비슷하다. 텐서 조작법과 브로드캐스팅 감각을 익히면, 그게 사실상 넘파이 감각이다.
- 넘파이를 별도로 깊게 파고들 필요는 없다.
딥러닝이 목표라면 파이토치 중심으로 공부하고,
중간에 보이는
np.xxx는 “CPU 배열 버전의 텐서 조작” 정도로 이해하면 된다. - 다만, 실무에서는
- 데이터 전처리 / 후처리 / 시각화 / 통계 계산 때문에 넘파이를 완전히 피할 수는 없다.
-
특히 PyTorch ↔ NumPy 변환 코드 (
.numpy(),torch.from_numpy,.cpu())는 자주 보게 되니 이 부분은 익숙해져야 한다. 4. 시스템 관점에서는 -
둘이 메모리를 공유(Zero-Copy) 할 수 있게 설계되어 있어 대규모 데이터에서도 효율적으로 오갈 수 있다.
딥러닝 코드를 볼 때 이제 이렇게 생각하시면 됩니다.
- 텐서가 GPU에 올라가 있고, 미분이 필요하다 → PyTorch의 영역
- 주변 라이브러리와 데이터를 주고받거나, 단순 수치/통계/시각화 → NumPy의 영역
이 두 세계를 자연스럽게 오가는 게, 현대 파이썬 딥러닝 개발자의 기본 스킬셋이라고 보면 됩니다.

댓글이 없습니다.