딥러닝을 위한 NumPy 기본 연산: +, -, *, /, **, 비교, sum/mean/max/min, axis

1. 왜 기본 연산을 먼저 잡아야 할까?



딥러닝에서 우리가 하는 일은 결국:

  • 입력/가중치를 더하고(+)
  • 곱하고(*, 행렬곱)
  • 비선형 함수를 적용하고 (**, relu, sigmoid 등)
  • 손실(loss)을 계산한 뒤, 그 값을 평균(mean) 내거나 합(sum) 내는 작업

으로 귀결됩니다.

PyTorch의 텐서 연산은 NumPy의 기본 연산 스타일을 그대로 따라가기 때문에, NumPy에서 이 감각을 잡아두면 딥러닝 수식이 훨씬 잘 보입니다.


2. 원소별 산술 연산: +, -, *, /, **

NumPy 배열끼리의 기본 연산은 원소별(element-wise) 로 동작합니다.

import numpy as np

x = np.array([1, 2, 3])
y = np.array([10, 20, 30])

print(x + y)   # [11 22 33]
print(x - y)   # [ -9 -18 -27]
print(x * y)   # [10 40 90]
print(y / x)   # [10. 10. 10.]
print(x ** 2)  # [1 4 9]
  • 길이가 같은 1차원 배열끼리는 원소별로 연산
  • 2차원, 3차원 배열도 마찬가지로 같은 위치끼리 연산

2.1 스칼라와의 연산

스칼라(숫자 하나)와의 연산도 자연스럽게 됩니다.

x = np.array([1, 2, 3])

print(x + 10)   # [11 12 13]
print(x * 2)    # [2 4 6]
print(x / 2)    # [0.5 1.  1.5]

이런 “모든 원소에 같은 값 더하기/곱하기”는 딥러닝에서 정규화, 스케일링, 바이어스 추가 등에 자주 쓰입니다.

PyTorch 텐서도 똑같이 동작합니다. x_t + y_t, x_t * 2, x_t ** 2 같은 표현은 거의 그대로 사용 가능.


3. 비교 연산: >, <, >=, <=, ==, !=



NumPy 배열끼리 비교 연산을 하면, 결과는 불리언(Boolean) 배열입니다.

import numpy as np

x = np.array([1, 2, 3, 4, 5])

print(x > 3)   # [False False False  True  True]
print(x == 2)  # [False  True False False False]

이 불리언 배열은:

  • 마스크(mask) 로 사용해서 특정 원소를 고르거나
  • 조건을 만족하는 원소의 개수를 셀 때 자주 사용합니다.

예:

x = np.array([1, -2, 3, 0, -5, 6])

mask = x > 0
print(mask)          # [ True False  True False False  True]

# 양수만 뽑기
pos = x[mask]
print(pos)           # [1 3 6]

# 양수의 개수
num_pos = np.sum(mask)   # True를 1, False를 0으로 보고 합산
print(num_pos)           # 3

딥러닝에서는 이런 식으로:

  • 예측이 맞은 샘플의 비율 (accuracy)
  • 특정 조건을 만족하는 위치만 손실(loss)에 포함

같은 계산을 많이 합니다. PyTorch에서도 완전히 같은 패턴을 씁니다.


4. 집계 함수: np.sum, np.mean, np.max, np.min

4.1 axis 없이: 전체에 대해 계산

기본 형태는 “배열 전체”에 대해 합, 평균, 최댓값, 최솟값을 구합니다.

import numpy as np

x = np.array([1, 2, 3, 4])

print(np.sum(x))   # 10
print(np.mean(x))  # 2.5
print(np.max(x))   # 4
print(np.min(x))   # 1

2차원 이상의 배열도 마찬가지입니다.

X = np.array([[1, 2, 3],
              [4, 5, 6]])

print(np.sum(X))   # 21
print(np.mean(X))  # 3.5

딥러닝에서:

  • 전체 배치/전체 데이터에 대한 평균 손실값
  • 전체 데이터의 평균/표준편차를 구한 뒤 정규화

등에 사용됩니다.


5. axis 개념 이해하기

axis는 “어느 축을 기준으로 연산할 것인가”를 정하는 옵션입니다.

  • axis를 지정하지 않으면 → 전체 원소에 대해 계산
  • axis를 지정하면 → 그 축을 따라 줄여(reduce) 나머지 축을 남김

5.1 2차원 예제로 보는 axis

import numpy as np

X = np.array([[1, 2, 3],
              [4, 5, 6]])  # shape: (2, 3)

axis=0: “행을 내려가면서” 계산 (열 단위)

print(np.sum(X, axis=0))   # [5 7 9]
print(np.mean(X, axis=0))  # [2.5 3.5 4.5]
  • 결과 shape: (3,)
  • 각 열(column)에 대해 합/평균을 계산한 것
  • 딥러닝에서 각 feature별 평균/표준편차 계산에 많이 씁니다.

axis=1: “열을 가로지르며” 계산 (행 단위)

print(np.sum(X, axis=1))   # [ 6 15]
print(np.mean(X, axis=1))  # [2. 5.]
  • 결과 shape: (2,)
  • 각 행(row)에 대해 합/평균을 계산한 것
  • 딥러닝에서 각 샘플별 합/평균 계산과 연결됩니다.

5.2 딥러닝에서 자주 보는 axis 예시

배치 데이터가 다음과 같다고 해봅시다.

# (batch_size, feature_dim)
X = np.random.randn(32, 10)  # 32개 샘플, 10차원 특징
  1. 각 feature별 평균 (feature-wise mean)
mean_per_feature = np.mean(X, axis=0)  # shape: (10,)
  • axis=0 → 배치 방향으로 줄이기
  • “각 column의 평균” = 각 feature의 평균
  1. 각 샘플별 평균 (sample-wise mean)
mean_per_sample = np.mean(X, axis=1)  # shape: (32,)
  • axis=1 → feature 방향으로 줄이기
  • “각 row의 평균” = 각 샘플 벡터의 평균값

5.3 이미지 배치에서 axis 생각하기

이미지 배치를 PyTorch 스타일 (N, C, H, W)로 생각해봅시다.

NumPy에서도 비슷한 배열을 만들 수 있습니다.

# N=32, C=3 (RGB), H=W=64
images = np.random.randn(32, 3, 64, 64)

예:

  1. 배치 전체에 대한 픽셀 최댓값
global_max = np.max(images)  # 스칼라
  1. 채널별 평균 (RGB 채널별로 평균)
# axis=(0, 2, 3): 배치, 높이, 너비 방향으로 줄이고 채널만 남김
channel_mean = np.mean(images, axis=(0, 2, 3))  # shape: (3,)

이건 실제로 채널별 정규화 할 때 많이 쓰는 패턴입니다.


6. 집계 함수 + 비교 연산: 자주 쓰는 패턴들

6.1 정확도(accuracy) 계산

예를 들어, 이진 분류에서:

import numpy as np

# 예측 (logit이 아니라 0~1 확률이라고 가정)
pred = np.array([0.2, 0.8, 0.9, 0.3])
# 정답 라벨 (0 또는 1)
target = np.array([0, 1, 1, 0])

# 0.5 기준으로 예측 클래스 만들기
pred_label = (pred > 0.5).astype(np.int32)   # [0 1 1 0]

# 맞은 곳은 True
correct = (pred_label == target)             # [ True True True True]

accuracy = np.mean(correct)                  # True=1, False=0으로 mean
print(accuracy)  # 1.0
  • 비교 연산 → 불리언 배열
  • mean을 취하면 정확도

PyTorch에서도 거의 같은 코드로 작성합니다.

6.2 마스크를 씌운 손실 계산

loss = np.array([0.1, 0.5, 0.2, 0.9])
mask = np.array([True, False, True, False])

masked_loss = loss[mask]      # [0.1, 0.2]
mean_loss = np.mean(masked_loss)
print(mean_loss)              # 0.15000000000000002

조건을 만족하는 위치만 손실에 포함시키고 싶을 때, NumPy+마스크+집계 함수를 묶어서 많이 씁니다.


7. 정리: 오늘 다룬 기본 연산들

이번 글에서 본 것들을 정리해보면:

  1. 산술 연산 (+, -, *, /, **)
  • 기본적으로 원소별 연산
  • 스칼라와도 자연스럽게 연산 가능 2. 비교 연산 (>, <, >=, <=, ==, !=)

  • 결과는 불리언 배열

  • 마스크로 활용 → 필터링, 개수 세기, 정확도 계산 등 3. 집계 함수 (np.sum, np.mean, np.max, np.min)

  • axis 없이: 전체에 대해 계산

  • axis로 어떤 축을 줄일지 선택 가능 4. axis 개념

  • 2D: axis=0 → 열 기준, axis=1 → 행 기준

  • 딥러닝에서 (batch, feature), (N, C, H, W) 구조에서 많이 사용
  • feature-wise, sample-wise, channel-wise 통계 계산에 필수

이 기본 연산에 익숙해지면:

  • 손실, 정확도, 통계량 등을 “수학식처럼” 바로 NumPy/PyTorch 코드로 옮길 수 있고
  • 복잡한 텐서 연산도 한결 덜 낯설게 느껴질 것입니다.

image