수학적 직관 다지기 · Chapter 3

행렬이란 무엇인가

— 화살표를 통째로 움직이는 장치, 그리고 차원을 늘리고 줄이는 법

눈높이: 중3 ~ 고2 키워드: 행렬 · 선형변환 · 차원축소 · 압축

1장에서 단어를 벡터(화살표)로 바꿨고, 2장에서 두 화살표가 닮았는지 내적으로 쟀다. 지금까지는 전부 "화살표 하나, 둘" 이야기였다. 3장의 질문은 다르다 — 화살표를 통째로 움직이는 장치는 무엇인가? 그것이 행렬(matrix)이다.

1 자리수별 곱셈으로는 회전이 안 된다

첫 직관: "특정 숫자를 곱하면 화살표가 바뀌지 않을까?" 반은 맞다. (3,8)에 자리수별로 (−1,−1)을 곱하면 (−3,−8) → 정확히 180도 회전이다. 그런데 이건 운이 좋았던 특수한 경우다.

90도 회전을 해보면 무너진다. (3,8)을 반시계로 90도 돌리면 (−8, 3)이 되어야 한다.

원래 (3, 8) 90도 → (−8, 3) 반시계 90°
새 x값(−8)은 원래 y값(8)에서 왔고, 새 y값(3)은 원래 x값(3)에서 왔다. x와 y가 서로 자리를 바꿔 섞여야 회전이 된다. 자리수별 곱셈에는 이 "섞는 통로"가 없다.
행렬이 태어난 이유

새 벡터의 각 자리는 원래의 x와 y 둘 다한테서 영향을 받아야 한다. 그래서 "얼마씩 섞을지"를 적는 빈칸이 4개(2차원 기준) 필요하고, 이 빈칸을 네모나게 모은 것이 행렬이다.

2 행렬 읽는 법

2×2 행렬은 이렇게 읽는다. 윗줄 = 새 x를 어떻게 만드나, 아랫줄 = 새 y를 어떻게 만드나.

① 항등행렬 — 아무것도 안 함

1001 → 새 x = 1·x + 0·y = x · 새 y = 0·x + 1·y = y

(3,8) 넣으면 그대로 (3,8). 숫자 1의 행렬 버전이라 "단위행렬"이라 부른다. 여기서 0은 "원래 y는 0만큼만 섞어라(= 안 섞는다)"는 뜻 — 2장의 "0이면 그 자리는 상관없다"가 그대로 적용된 것.

② 180도 회전 — 부호만 뒤집기

−100−1 → (3,8) → (−3, −8)

x와 y가 안 섞이고 각자 부호만 바뀌면 되는 쉬운 경우. 그래서 첫 직관(자리수별 −1 곱하기)이 우연히 맞았다.

③ 90도 회전 — 0이 비대각선에

0−110 → 새 x = 0·3 + (−1)·8 = −8 · 새 y = 1·3 + 0·8 = 3

여기선 0이 대각선이 아닌 자리에 있다. 윗줄의 −1이 "새 x에 원래 y를 끌어다 쓴다", 아랫줄의 1이 "새 y에 원래 x를 끌어다 쓴다"는 뜻. 이 비대각선의 0이 아닌 숫자가 x와 y를 섞는 통로다.

행렬 읽기의 핵심 패턴

대각선 = "자기 자신을 얼마나 키우나" (크기 조절) · 비대각선 = "남을 얼마나 끌어다 섞나" (방향 섞기).

예: 2002 에 (3,8)을 넣으면 (6,16) — 비대각선이 0이라 안 섞이고, 대각선이 2라 길이만 2배. 방향은 그대로.

3 가장 강력한 관점 — "기준 축이 어디로 가는가"

행렬을 세로 기둥으로 보면 완전히 새롭게 보인다. 첫째 기둥 = "원래의 가로 방향 (1,0)이 변환 후 어디로 가는가", 둘째 기둥 = "원래의 세로 방향 (0,1)이 어디로 가는가".

변환 전 가로 (1,0) 세로 (0,1) 90° 회전 변환 후 가로→(0,1) 위로! 세로→(−1,0) 왼쪽!
90도 회전 행렬을 기둥으로 보면: 가로 방향 (1,0)이 (0,1)로(오른쪽이 위로), 세로 방향 (0,1)이 (−1,0)으로(위가 왼쪽으로) 간다. 딱 90도 돌린 것.
오늘의 큰 그림

행렬은 "기준 축들이 어디로 가는지"만 적어둔 것이다. 축이 어디로 가는지만 알면, (3,8) 같은 임의의 화살표는 "새 가로방향으로 3칸 + 새 세로방향으로 8칸"으로 운명이 자동 결정된다.

4 행렬의 크기 = (새 차원) × (원래 차원)

2차원→2차원이 왜 2×2였나? 줄(가로) 개수 = 새로 만들 벡터의 차원(새 x용 한 줄, 새 y용 한 줄), 칸(세로) 개수 = 원래 벡터의 차원(각 줄에서 원래 x몫·y몫을 적으니까).

그래서 1536차원 → 1536차원 변환은 1536 × 1536(약 236만 개의 숫자) 행렬이다. 그리고 꼭 정사각형일 필요는 없다 — 768차원을 1536차원으로 늘리는 변환은 1536 × 768 직사각형 행렬.

영준님의 연결 — "임베딩 모델과 LLM의 벡터 차원이 달라도 문제없던 게, 행렬로 변환할 수 있어서구나." 정확하다. 어텐션의 Q·K·V도 원래 토큰 벡터에 각각 다른 행렬을 곱해 만든 것 — 곱하는 행렬이 다르니 Q, K, V가 서로 다른 벡터가 된다.

5 늘리기 vs 줄이기 — 대칭이 아니다

여기서 가장 중요한 직관. 차원을 늘리는 것과 줄이는 것은 대칭이 아니다.

늘리기 (768→1536)
정보가 새로 생기지 않는다. 작은 종이의 메모를 큰 종이에 옮겨 적어도 내용은 그대로인 것처럼, 형태만 재배치될 뿐. LLM 내부의 차원 확대는 정확도가 아니라 "다음 연산이 받아먹을 모양"을 맞추는 계산용 변환.
줄이기 (6→2)
정보를 잃는다(압축). 고차원 점들을 저차원에 그림자처럼 눌러 떨어뜨리는 것 — 2장의 정사영과 같은 원리. 단, 어떤 행렬을 쓰느냐에 따라 "뭘 버리고 뭘 남기냐"가 달라진다.
영준님의 통찰 — "행렬 크기를 줄이면 정보가 압축되는 거 아니야?" 맞다. 압축은 실제로 일어나고, 머신러닝의 핵심 기술이다(PCA, 차원축소, 오토인코더). 잘 된 압축은 잡음을 버리고 신호를 남겨 오히려 성능이 좋아지기도 한다.

단, 똑똑한 압축은 공짜가 아니다

압축이 잘 되려면 데이터에 "중복"이나 "구조"가 있어야 한다.

압축 잘 됨 (구조 있음)
키·몸무게·팔길이·다리길이… 처럼 서로 얽힌 6개 값은 "전반적 체격"이라는 축 하나가 대부분을 설명한다. 6→2로 줄여도 거의 안 잃는다.
압축 안 됨 (구조 없음)
완전히 무관한 난수 6개는 진짜로 6개만큼의 정보다. 2개로 줄이면 4개만큼을 그냥 버린다. 남길 "공통 방향"이 없다.
내재 차원 (intrinsic dimension)

똑똑한 압축은 "데이터가 실제로는 겉보기 차원보다 낮은 차원에 살고 있을 때"만 가능하다. 6차원처럼 보여도 진짜 정보는 2차원어치뿐인 상태 = 내재 차원이 낮다.

언어에는 구조가 많아(단어들이 의미별로 뭉쳐 있음) 임베딩의 내재 차원은 겉보기보다 낮은 편 → 압축이 꽤 잘 먹힌다. 단, 근로기준법처럼 미묘한 조항이 많은 텍스트는 내재 차원이 높아 더 많은 축(3072)이 필요했던 것. 모순이 아니라, 내용의 복잡도가 다른 것.

압축의 두 가지 모양 — 축 정렬 vs 비스듬한

3차원을 2차원으로 줄일 때 가장 단순한 형태는 축 하나를 0으로 죽이는 것이다. (x,y,z)→(x,y,0). 대각행렬(비대각선이 0)이 하는 일이고, 원래 축에 칼을 수직·수평으로만 대는 셈이다.

하지만 압축이 꼭 원래 축을 버리는 것만은 아니다. 비스듬한 평면으로 눌러도 2차원어치 정보만 남는다 — 이때는 세 숫자가 다 섞이며 (x,y,0)처럼 깔끔하게 안 떨어진다. 비대각선에 숫자가 들어가면 이런 "기울어진 압축"이 된다.

이게 바로 PCA

핵심은 결과가 몇 차원어치 정보를 담느냐(얼마나 납작해졌나)지, 어느 자리가 0이 되느냐가 아니다. 실제 데이터는 정보가 원래 축에 맞춰 있지 않고 비스듬히 흩어져 있다. 그래서 잘 누르려면 칼도 비스듬히 — 데이터가 누운 기울기에 맞춰 들어야 한다. "정보가 가장 많이 흩어진 비스듬한 방향"을 데이터에서 자동으로 찾아 거기에 그림자를 떨구는 것이 PCA(주성분분석)다. (x,y,0) 직관에 "이 평면을 기울일 수도 있다"만 더하면 PCA가 된다.

늘리기는 정보를 못 만든다.
줄이기는 정보를 잃되, 구조가 있으면 똑똑하게 잃는다.
— 3장 한 줄 요약

이번 장 한눈에 정리

다음 장 예고

지금까지 벡터(1장), 내적(2장), 행렬(3장)을 쌓았다. 이제 이것들이 한데 모이는 곳 — 어텐션(attention)으로 간다. 토큰 벡터에 행렬을 곱해 Q·K·V를 만들고, Q와 K를 내적해 "어디에 주목할지"를 정하는 그 메커니즘이, 사실 우리가 1~3장에서 손으로 만진 것들의 조립품이라는 걸 보게 될 것이다.