내적은 닮음을 잰다
검색창에 단어를 치면 엔진은 글을 한 글자씩 비교하지 않는다. 각 글을 벡터로 바꿔 놓고 두 벡터가 얼마나 같은 쪽을 가리키는지를 본다. 이 얼마나 같은 쪽인가를 한 숫자로 재는 도구가 내적이에요. a·b = |a||b|cos(theta). 두 벡터의 길이와 둘이 이루는 각의 코사인을 곱한 값이다. 여기서 길이를 떼어내면 cos(theta) 하나만 남는데, 이게 바로 코사인 유사도다. 같은 방향이면 닮았고 직각이면 무관하고 반대면 정반대다. 검색과 추천, 단어 임베딩이 전부 이 한 줄 위에서 돌아가요.
초록 화살표 a는 고정해 두고 파란 화살표 b를 두 손잡이로 다룬다. 한 슬라이더는 b의 각도를, 다른 슬라이더는 b의 길이를 바꾼다. 화면 위 a·b 값이 두 손잡이에 모두 반응해요. b를 길게 하면 값이 통째로 커지는 길이 효과가 나타나고, b를 돌리면 같은 쪽일 때 양수, 직각이면 0, 반대쪽이면 음수로 휘는 정렬 효과가 나타난다. 부호에 따라 색이 초록과 흐림과 빨강으로 바뀌고, a 위로 떨어지는 b의 발도 같이 움직인다. 내적 하나가 길이와 정렬 두 가지를 동시에 담는다는 걸 손으로 느낄 수 있어요.
내적을 다른 눈으로도 볼 수 있다. a를 +x축에 길이 2로 눕혀 두고 b의 각도만 슬라이더로 돌리면, 금색으로 그려지는 게 b를 a 위로 곧장 떨어뜨린 그림자, 곧 사영이에요. 그러면 a·b는 정확히 |a| 곱하기 그 사영 길이가 된다. b를 a 쪽으로 눕히면 그림자가 길어져 내적이 크고, b를 세울수록 그림자가 짧아져 내적이 준다. 직각이 되면 그림자가 0이라 내적도 0이다. 내적은 결국 한 벡터가 다른 벡터 방향으로 얼마나 뻗었나를 길이로 재서 |a|배 한 값이에요.
내적의 부호만 따로 떼서 보면 규칙이 아주 단순하다. a를 +x축에 두고 b의 각도 theta를 0도에서 360도까지 슬라이더로 쓸면 평면이 두 영역으로 칠해져요. a와 같은 쪽 반평면(theta가 90도 안쪽)은 초록빛이고 거기서는 내적이 양수다. 정확히 90도와 270도, 직각에서는 0이다. 반대쪽 반평면(90도와 270도 사이)은 붉은빛이라 내적이 음수다. b를 돌리면 화면 글자가 양수·0·음수로 바뀌며 값도 같이 보여요. 부호 하나로 같은 편인가 무관한가 반대편인가가 정해진다는 걸 한눈에 알 수 있다.
이제 길이를 완전히 떼어낸다. cos(theta) = a·b / (|a||b|). 이 값은 항상 -1과 +1 사이에 든다. a를 고정하고 b의 각도와 길이를 두 슬라이더로 바꾸면 결정적인 장면이 나와요. b의 길이만 늘이거나 줄이면 cos(theta)는 꿈쩍도 안 하고, 화면 아래 -1에서 +1까지 그어진 게이지의 바늘이 제자리다. 반대로 각도를 돌리면 바늘이 쭉 미끄러진다. 코사인 유사도는 크기를 무시하고 방향만 보는 것이다. 그래서 검색엔진과 임베딩은 글의 길이가 길든 짧든 상관없이 가리키는 방향만으로 두 글이 닮았는지를 비교해요.
마지막으로 내적이 정확히 0이 되는 순간을 직접 잡아 본다. a는 고정이고, 파란 화살표 b를 손으로 끌어 평면 위를 돌아다니면 화면에 a·b 값이 실시간으로 떠요. b가 a와 직각을 이루는 자리를 지날 때 값이 0을 가로지르면서 화살표가 빛나고 직교라는 글자가 뜬다. 내적이 0이라는 건 두 방향이 완전히 수직, 곧 서로 무관하고 독립이라는 뜻이다. 이 성질이 좌표축을 깔끔하게 만든다. x축과 y축이 직교하니까 한 축으로 움직여도 다른 축 값은 안 흔들리기 때문이에요. 깨끗한 기저는 전부 이 내적 0에서 나온다.