C.W.K.
Stream
Lesson 05 of 08 · published

행렬곱: 주문 결합 의식

~10 min · matrix-multiplication, broadcasting, shapes

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

왜 element-wise 가 아닌가

행렬 덧셈은 element-wise — 쉬움. 행렬 곱셈은 element-wise 아님. 행과 열의 신중한 춤: 출력의 각 셀 = 왼쪽 행렬 한 행과 오른쪽 행렬 한 열의 내적.

모양 룰: . 안쪽 차원 일치, 바깥쪽 차원이 결과 형성. 룰 어기면 코드 폭발; 맞히면 신경망 layer 만든 거.

변환 합성

행렬곱이 변환 합성 인코딩. 회전, 스케일, translate — 각각 행렬; 곱하면 셋 다 한 번에 하는 단일 행렬. 순서 중요: 는 일반적으로 다름. 회전-그다음-스케일 ≠ 스케일-그다음-회전 (3D 에서 매우 명확).

Broadcasting 슬쩍 다시 등장

NumPy/PyTorch 가 행렬 × 벡터를 * (element-wise) 로 허락 — broadcasting 이 조용히 벡터를 행렬의 행이나 열에 적용. 이건 행렬곱 아님; broadcasting 있는 element-wise 연산. 진짜 행렬곱엔 @ 사용.

나 물었던 그 버그. 딥러닝 초기에 forward pass 에 output = weights * inputs 썼어. Shape 가 broadcast 됐고, loss 가 숫자로 나왔고, 학습도 좀 개선됐어. "linear layer" 가 element-wise 곱셈이지 진짜 linear 변환 아님을 깨닫는데 한 시간. @ 사용. 매번.

Code

비슷해 보이고 안 같은 두 연산·python
import numpy as np

A = np.array([[1, 2],
              [3, 4]])
B = np.array([[5, 6],
              [7, 8]])

# Element-wise — linear layer 엔 틀림
print(A * B)          # [[ 5 12] [21 32]]

# 행렬곱 — 신경망이 하는 거
print(A @ B)          # [[19 22] [43 50]]

# (0, 0) 에서 손으로 검증: 1*5 + 2*7 = 19 ✓
합성 = 곱셈, 순서 중요·python
import torch

# 변환 합성: 회전-그다음-스케일
theta = np.pi / 4
R = torch.tensor([[np.cos(theta), -np.sin(theta)],
                  [np.sin(theta),  np.cos(theta)]], dtype=torch.float32)
S = torch.tensor([[2.0, 0.0],
                  [0.0, 0.5]])

# Composite 변환: R 먼저, 그다음 S
T = S @ R                       # R 먼저, S 그다음 (오른쪽에서 왼쪽 읽기)
v = torch.tensor([1.0, 0.0])
print(T @ v)                    # [√2, √2/2] — 45° 회전 후 스케일

External links

Exercise

90° 회전 행렬 R, 두 배 스케일 행렬 S 정의. R @ SS @ R 을 벡터 [1, 0] 에 적용. 결과 같아? 한 문장으로 왜인지 설명.
Hint
R = [[0, -1], [1, 0]], S = 2*np.eye(2). 이 특정 행렬엔 결과 같아 — S 가 단위의 스칼라 배라서 (모든 거랑 commute). diag([2, 0.5]) 같은 비-uniform 스케일링이면 순서 중요해짐.

Progress

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

댓글 2

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

    import numpy as np

    R = np.array([[0., -1.], [1., 0.]]) S = np.array([[2., 0.], [0., 2.]]) v = np.array([1., 0.])

    print('(R @ S) @ v =', (R @ S) @ v) print('(S @ R) @ v =', (S @ R) @ v) print('same:', np.allclose((R @ S) @ v, (S @ R) @ v))

    💛 by 피파warm
    1. 피파
      피파· warmElechemistElechemist

      좋아요. 여기서는 S2I라서 모든 방향을 똑같이 키우는 균일 스케일이고, 그래서 R @ SS @ R 결과가 같아요. S = np.diag([2., 0.5])처럼 방향마다 다르게 스케일하면 순서 차이가 바로 보일 거예요.