본문 바로가기
C.W.K.
Stream
Lesson 06 of 06 · published

코드에서 벡터 연산: 영원히 재사용할 패턴

~10 min · numpy, pytorch, broadcasting, operations

Level 0수학 초심자
0 XP0/59 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

배열 코드에서 되풀이되는 다섯 패턴

벡터와 텐서 코드를 읽을 때는 함수 이름보다 입력과 출력의 모양이 어떻게 바뀌는지 먼저 봐. 다음 다섯 패턴이 자주 반복돼.

  1. 원소별 연산: a + b, a * b, np.exp(a). 각 위치에 같은 규칙을 적용하고 보통 브로드캐스팅 뒤의 모양을 유지해.
  2. 축소: a.sum(), a.mean(), a.max(). 지정한 축의 여러 값을 하나로 합쳐 그 축을 없애거나 길이 1로 남겨.
  3. 내적과 행렬곱: a @ b. 입력의 차원 수와 모양에 따라 벡터 내적이나 행렬곱, 배치 행렬곱으로 동작해.
  4. 브로드캐스팅: 호환되는 서로 다른 모양을 개념적으로 맞춰 원소별 연산을 수행해. 실제로 전체 복사본을 만들 필요는 없어.
  5. 슬라이싱과 고급 인덱싱: a[2:5], a[a > 0], a[indices]로 일부 원소를 고르거나 새 배열을 만들어.

브로드캐스팅 규칙

모양이 (4, 3)인 행렬에 (3,) 벡터를 더하면 벡터가 각 행에 적용돼. 두 모양을 오른쪽부터 맞췄을 때 각 축의 길이가 같거나 둘 중 하나가 1이면 호환되고, 한쪽에 축이 없으면 길이 1인 축처럼 취급해.

호환된다는 사실이 계산 뜻까지 보장하지는 않아. 잘못된 축을 우연히 브로드캐스트하면 오류 없이 틀린 결과가 나올 수 있으니 중간 모양과 축의 의미를 확인해.

배열 루프를 쓰기 전에 라이브러리가 제공하는 벡터화 연산이 있는지 찾아. 더 빠르고 의도가 선명해지는 경우가 많지만, 복잡한 제어나 메모리 사용까지 무조건 좋아지는 만능 규칙은 아니야. 측정하고 선택해.

트랙 보상

벡터의 크기와 방향, 내적과 노름을 익히고 코드에서는 모양 변화로 연산을 읽는 법을 배웠어. 다음 트랙에서는 이 벡터들을 한꺼번에 변환하는 행렬로 넘어가.

Code

다섯 배열 패턴을 15줄로 보기·python
import numpy as np

a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])

# Element-wise
print(a + b)                         # [11 22 33 44]
print(a * b)                         # [10 40 90 160]

# Reduction
print(a.sum(), a.mean(), a.max())    # 10  2.5  4

# Broadcasting
M = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8]])
print(M + a)                         # 벡터가 행에 broadcast
# [[ 2  4  6  8]
#  [ 6  8 10 12]]

# Fancy 인덱싱
mask = a > 2
print(a[mask])                       # [3 4]
MLX에서 같은 모양 규칙 확인하기·python
import mlx.core as mx

# 같은 배열 패턴이 MLX에서도 이어져. 기본 장치와 통합 메모리를 쓰므로
# 보통 PyTorch식 .to(device)를 호출할 필요가 없어.
a = mx.array([1, 2, 3, 4])
b = mx.array([10, 20, 30, 40])

print(a + b)                         # [11, 22, 33, 44]
print((a * b).sum().item())          # 1000

M = mx.array([[1, 2, 3, 4],
              [5, 6, 7, 8]])
print(M + a)                         # (4,) 벡터를 행에 broadcast

# MLX 연산은 지연 평가돼. print나 item도 평가를 일으키고,
# 반복 루프에서는 보통 반복마다 mx.eval(...)로 그래프를 실행해.

External links

Exercise

명시적 for 루프 없이 모양이 (5, 3)인 임의 부동소수점 행렬을 열별로 표준화해. 각 열의 평균을 빼고 표준편차로 나눈 뒤 결과 열의 평균이 약 0, 표준편차가 약 1인지 확인해.
Hint
(M - M.mean(axis=0)) / M.std(axis=0)에서 axis=0은 행을 가로질러 줄여 (3,) 벡터를 남기고, 그 벡터가 다시 각 행에 브로드캐스트돼. 표준편차가 0인 열도 생각해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 피파happy

댓글 2

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.
  1. Elechemist
    Elechemist

    just do it 정신을 잠시 잃고 너무 오랜만에 돌아왔어 , 평균 0 , 표준편차 1 인거 확인!

    import numpy as np

    rng = np.random.default_rng(42) X = rng.standard_normal((5, 3))

    mu = X.mean(axis=0) sigma = X.std(axis=0)

    Z = (X - mu) / sigma

    print("열 평균:", Z.mean(axis=0)) print("열 std :", Z.std(axis=0))

    assert np.allclose(Z.mean(axis=0), 0, atol=1e-12) assert np.allclose(Z.std(axis=0), 1, atol=1e-12) print("검증 통과")

    💛 by 피파happy
    1. 피파
      피파· happyElechemistElechemist

      Elechemist님, 돌아온 것 자체가 이미 just do it 재가동이에요. 코드도 정확해요 — axis=0으로 열별 평균/std를 만들고, 그 (3,) 벡터가 다시 각 행에 broadcast되면서 Z-score가 된 구조까지 잘 잡으셨어요. 다음엔 같은 패턴을 torchmlx로 한 번만 옮겨보면 “NumPy 문법”이 아니라 “배열 사고방식”이라는 게 더 선명해질 거예요.