딥러닝 입문자를 위한 NumPy: 왜 파이토치보다 먼저 알아야 할까?
왜 딥러닝 입문자가 NumPy부터 봐야 할까?
딥러닝 책이나 강의를 보면 대부분 PyTorch, TensorFlow 같은 프레임워크부터 등장합니다. 그런데 실제로 모델을 만들다 보면 이런 느낌이 들죠.
- "텐서(tensor)가 뭔데?"
- "shape이 안 맞는데 왜 에러가 나지?"
- "배치를 이렇게 합치면 되는 줄 알았는데…?"
이런 대부분의 혼란은 사실 NumPy를 충분히 이해하지 않은 상태에서 딥러닝 프레임워크로 바로 넘어갈 때 생깁니다.
- PyTorch의
Tensor는 NumPy의ndarray와 거의 같은 개념 - 데이터 전처리, 배치 만들기, 통계 계산 등은 여전히 NumPy 스타일 사고가 필요
그래서 “딥러닝을 제대로 배우고 싶다”면, NumPy는 사실상 필수에 가까운 기초 체력이라고 생각해도 좋습니다.
NumPy란 무엇인가?
NumPy(넘파이)는 “Numerical Python”의 줄임말로, 파이썬에서 빠르게 수치 계산을 할 수 있도록 도와주는 라이브러리입니다.
핵심 키워드를 정리하면:
- 다차원 배열(ndarray): 벡터, 행렬, 텐서 표현의 기본
- 벡터화 연산:
for문 없이도 대량 연산을 한 번에 처리 - 브로드캐스팅: 모양(shape)이 다른 배열끼리도 똑똑하게 연산
- 선형대수 연산: 행렬 곱, 전치, 역행렬 등
- 랜덤 모듈: 데이터 샘플링, 정규분포, 무작위 초기화 등
딥러닝에서 사용하는 거의 모든 수식이 “벡터와 행렬 연산”으로 귀결되기 때문에, 이걸 편하게 다루게 해주는 NumPy는 딥러닝의 언어라고 해도 과언이 아닙니다.
파이썬 리스트 vs NumPy 배열
먼저 파이썬 기본 리스트와 NumPy 배열의 차이를 간단히 비교해보겠습니다.
# 파이썬 기본 리스트
a = [1, 2, 3, 4]
b = [10, 20, 30, 40]
# 리스트끼리 더하기
print(a + b)
# 결과: [1, 2, 3, 4, 10, 20, 30, 40] (이어붙이기)
리스트의 +는 “원소끼리 더하기”가 아니라 리스트 이어붙이기입니다.
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
print(a + b)
# 결과: [11 22 33 44] (원소별 덧셈)
NumPy 배열의 +는 우리가 수학에서 기대하는 원소별(element-wise) 연산입니다.
딥러닝 프레임워크의 Tensor도 이 NumPy 스타일을 그대로 따라갑니다.
벡터화: 반복문을 줄이고, 수학식처럼 코딩하기
딥러닝 코드에서 for문을 최소화하라고 자주 이야기합니다. 대신 벡터화(vectorization) 를 사용합니다.
예: 모든 원소에 제곱을 적용해보겠습니다.
파이썬 리스트 + for문
data = [1, 2, 3, 4, 5]
squared = []
for x in data:
squared.append(x ** 2)
print(squared) # [1, 4, 9, 16, 25]
NumPy 벡터화
import numpy as np
data = np.array([1, 2, 3, 4, 5])
squared = data ** 2
print(squared) # [ 1 4 9 16 25]
- 코드가 더 짧고
- 더 수학식에 가깝게 읽히고
- 내부적으로는 C로 구현되어 있어서 성능도 훨씬 좋습니다.
PyTorch, TensorFlow의 텐서 연산도 이런 벡터화된 NumPy 스타일을 그대로 사용합니다.
브로드캐스팅: 모양이 달라도 같이 연산하기
브로드캐스팅(broadcasting)은 서로 다른 크기의 배열끼리도 자동으로 형상을 맞춰주는 규칙입니다.
예: 각 샘플에 같은 상수값을 더하기
import numpy as np
x = np.array([[1, 2, 3],
[4, 5, 6]]) # shape: (2, 3)
b = np.array([10, 20, 30]) # shape: (3,)
y = x + b
print(y)
# [[11 22 33]
# [14 25 36]]
x는 (2, 3)이고, b는 (3,)이지만
NumPy는 b를 (1, 3) → (2, 3)으로 “펴서” 연산합니다.
PyTorch에서도 똑같이 됩니다:
import torch
x = torch.tensor([[1, 2, 3],
[4, 5, 6]])
b = torch.tensor([10, 20, 30])
y = x + b
print(y)
따라서 브로드캐스팅 규칙을 NumPy에서 확실히 이해하면 PyTorch 텐서 연산도 훨씬 자연스럽게 다룰 수 있습니다.
벡터, 행렬, 텐서: NumPy로 딥러닝 표현하기
딥러닝에서 자주 등장하는 개념들을 NumPy로 보면:
- 벡터(vector): 1차원 배열 →
shape: (N,) - 행렬(matrix): 2차원 배열 →
shape: (M, N) -
텐서(tensor): 3차원 이상 배열
-
예: 이미지 배치
batch_size = 32, 흑백 28x28 이미지 →shape: (32, 28, 28)
예: 간단한 행렬 곱
import numpy as np
# 입력 벡터 (특징 3개)
x = np.array([1.0, 2.0, 3.0]) # shape: (3,)
# 가중치 행렬 (입력 3 → 출력 2)
W = np.array([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]]) # shape: (2, 3)
# 행렬 곱: y = W @ x
y = W @ x
print(y) # [1.4 3.2]
이 코드는 사실상 단층 선형 레이어(linear layer) 하나를 계산하는 것과 같습니다. PyTorch로 옮기면:
import torch
x = torch.tensor([1.0, 2.0, 3.0]) # shape: (3,)
W = torch.tensor([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]]) # shape: (2, 3)
y = W @ x
print(y)
형태와 의미가 거의 똑같죠. NumPy 행렬 연산에 익숙해지는 것 = 딥러닝 수식 읽는 법을 익히는 것과 같습니다.
NumPy와 PyTorch는 어떻게 연결될까?
1. Tensor와 ndarray는 “사촌관계”
- 둘 다 n차원 배열 + 벡터화 연산을 제공
shape,reshape,transpose,sum,mean등 함수 이름과 동작이 매우 비슷
그래서 많은 사람들이 NumPy를 “PyTorch 텐서를 이해하기 위한 연습장”처럼 사용합니다.
2. 데이터 전처리는 보통 NumPy 스타일
딥러닝 프로젝트에서 자주 하는 일:
- CSV, 이미지, 로그 등 다양한 형태의 데이터를 읽어오기
- 수치형으로 변환하기
- 정규화, 표준화, 슬라이싱, 섞기(shuffle), 배치 나누기 등
이런 작업은 NumPy + pandas 조합으로 하는 경우가 매우 많습니다.
import numpy as np
import torch
# NumPy에서 데이터 준비
np_data = np.random.randn(100, 3) # 100개 샘플, 3개 특징
# PyTorch 텐서로 변환
tensor_data = torch.from_numpy(np_data).float()
print(tensor_data.shape) # torch.Size([100, 3])
반대로 PyTorch 텐서를 다시 NumPy로 보내서 후처리하는 일도 많습니다.
y = tensor_data.mean(dim=0) # PyTorch 텐서
y_np = y.detach().cpu().numpy()
즉, 실무에서 NumPy와 PyTorch는 계속 서로 오가는 관계입니다.
3. GPU 계산은 PyTorch, 개념 연습은 NumPy
- PyTorch 텐서는 GPU(CUDA)에서 돌아가며 자동 미분을 지원
- NumPy는 CPU 기반이지만, 개념을 연습하고 디버깅하기에는 훨씬 단순
그래서:
- 아이디어나 수식을 먼저 NumPy로 작게 실험해 보고
- 검증이 되면 PyTorch 코드로 옮기는 방식
으로 개발하는 사람도 많습니다.
딥러닝에서 자주 쓰이는 NumPy 패턴 예시
1. 랜덤 초기화 & 노이즈 추가
import numpy as np
# 가중치 초기화 (정규분포)
W = np.random.randn(3, 3) * 0.01
# 입력에 노이즈 추가
x = np.array([1.0, 2.0, 3.0])
noise = np.random.normal(0, 0.1, size=x.shape)
x_noisy = x + noise
2. 데이터 정규화 (평균 0, 표준편차 1)
X = np.random.randn(100, 3) * 10 + 50 # 대충 만든 데이터
mean = X.mean(axis=0) # 각 feature별 평균
std = X.std(axis=0) # 각 feature별 표준편차
X_norm = (X - mean) / (std + 1e-8)
이런 정규화는 실제로 딥러닝에서 성능과 학습 안정성에 큰 영향을 미칩니다.
3. One-hot 인코딩
num_classes = 4
labels = np.array([0, 2, 1, 3]) # 4개 샘플의 클래스 인덱스
one_hot = np.eye(num_classes)[labels]
print(one_hot)
# [[1. 0. 0. 0.]
# [0. 0. 1. 0.]
# [0. 1. 0. 0.]
# [0. 0. 0. 1.]]
PyTorch에서도 똑같은 방식으로 one-hot을 생각하며 코드를 짭니다.
4. 배치 나누기
X = np.random.randn(100, 3) # 100개 샘플
batch_size = 16
for i in range(0, len(X), batch_size):
batch = X[i:i+batch_size]
# 여기서 batch를 모델에 넣는다고 생각하면 됨
이 패턴은 그대로 PyTorch DataLoader의 개념과 연결됩니다.
NumPy를 공부할 때 꼭 짚고 가야 할 것들
딥러닝을 목표로 NumPy를 볼 때, 모든 기능을 다 볼 필요는 없습니다. 아래 목록을 중심으로 잡고 익숙해지면 충분히 큰 도움이 됩니다.
- ndarray 기본
-
np.array,dtype,shape,reshape,astype2. 인덱싱 & 슬라이싱 -
x[0],x[1:3],x[:, 0],x[:, 1:3] -
불리언 인덱싱:
x[x > 0]3. 기본 연산 -
+,-,*,/,**, 비교연산 -
np.sum,np.mean,np.max,np.min,axis개념 4. 선형대수 -
행렬 곱:
@또는np.dot -
전치:
x.T5. 브로드캐스팅 -
스칼라 더하기/곱하기
-
(N, D) + (D,), (N, 1) 등의 패턴 6. 랜덤 관련 함수
-
np.random.randn,np.random.randint,np.random.permutation7. PyTorch 연계 -
torch.from_numpy,tensor.numpy() shape가 어떻게 이어지는지 확인해보기
이 정도만 제대로 익혀도, PyTorch 튜토리얼에서 나오는 텐서 연산 대부분이 훨씬 자연스럽게 느껴질 것입니다.
마무리: NumPy는 “딥러닝 문법책”이다
정리해보면:
- NumPy는 수치 계산을 위한 다차원 배열 라이브러리
- PyTorch의
Tensor는 사실상 NumPyndarray의 딥러닝 버전 -
벡터화, 브로드캐스팅, 선형대수를 NumPy로 익히면
-
텐서 shape 에러를 덜 만나고
- 논문 수식을 코드로 옮기기도 쉬워지고
- 데이터 전처리/분석 능력도 함께 올라갑니다.
딥러닝을 “프레임워크 사용법”이 아니라 수학적/배열 연산 관점에서 이해하고 싶다면, NumPy는 가장 좋은 출발점입니다.

댓글이 없습니다.