벡터를 바닥부터 뜯어보기
들어가며
- 이 글은 LLM을 이해하기 위한 가장 작은 단위인 벡터(Vector)에서부터 시작하기 위해 작성되었다.
- 최종 수정일: 26/02/01
업무적으로나 개인적으로 LLM을 활용하고 공부하다 보면, 토큰이나 임베딩과 같은 개념을 자주 마주하게 된다. 간략하게 이해는 다음과 같다. 문서는 벡터로 변환되고, 질의는 벡터로 바뀌며, 모델은 벡터를 입력으로 받아 또 다른 벡터를 출력한다.
여기에서 벡터를 설명할 때는 흔히 “의미적 유사성을 수치로 표현한 것”이라는 말이 따라붙는다. 의미가 비슷한 단어일수록 벡터 사이의 거리가 가깝다는 식이다. 하지만 이런 설명은 벡터의 내부가 무엇인지, 그 숫자들이 어떤 구조를 이루고 있는지에 대해서는 거의 말해주지 않는다. 간략하게 최종 결과가 문장으로 변환되는 과정을 이해할 뿐, 그 사이에서 어떤 변환이 일어나는지는 쉽게 파악할 수 없다.
따라서 LLM을 이해하는 단계에서 한 발짝 더 나아가려면, 벡터라는 자료구조를 외면할 수 없다. 토큰, 임베딩, 히든 스테이트, 로짓 같은 용어들은 모두 벡터의 다른 얼굴일 뿐이다. 모델은 실제로는 텍스트가 아니라 벡터를 다룬다. 문장이나 의미는 직접 처리되지 않는다. 오직 고정된 차원의 실수 벡터들이 행렬 연산을 거치며 변형될 뿐이다.
이 글은 그 지점에서 출발하고자 한다. 단순히 벡터의 정의로 끝내기 보다는 왜 벡터라는 표현 형식을 선택했는지, 그리고 그 선택이 어떤 사고방식과 계산 구조를 가능하게 만들었는지를 따라가 며 이해해보고자 한다.
벡터와 토큰
개념
- 토큰(Token)
토큰은 현대의 신경망 기반 자연어 처리 모델이 텍스트를 처리하기 위해 입력받는 최소의 단위이다. 문자열은 토크나이저(Tokenizer)를 통해 특정 규칙에 따라 분절된다. 각 토큰은 모델이 미리 정의한 어휘 사전(Vocabulary) 내의 고유한 정수 인덱스(Integer Index)에 매핑된다. 모델이 받는 것은 문장이나 단어가 아니라, 토큰 ID의 시퀀스다.
- 벡터(Vector)
벡터는 토큰 ID가 임베딩 테이블을 통해 변환된 결과로, 고정된 차원을 갖는 실수 배열이다. 이러한 신경망 기반 모델 내부에서 모든 정보는 밀집 벡터(Dense Vector)로 표현된다. 모델은 텍스트나 의미를 직접 이해하거나 다루지 않는다. 대신 벡터들 사이의 내적, 합성, 선형 변환과 같은 기하학적 연산만을 수행한다. 의미라고 여겨지는 것은 이 고차원 공간에서의 위치와 관계를 사후적으로 해석한 결과다.
관계
토큰과 벡터는 이산적 기호와 연속적 연산 값 사이를 잇는 관계에 놓여 있다. 토큰이 구분 가능한 표식에 머문다면, 벡터는 계산이 가능한 물리적 표현이다. 모델은 이 둘을 직접 넘나들지 않고, 참조를 통해서 기호를 연산의 세계로 옮긴다. 이 지점에서 세 가지 주요한 특징이 드러난다.
- 매핑 구조
하나의 토큰 ID는 하나의 고정 차원 벡터와 일대일로 대응된다. 모델은 토큰 ID를 주소값처럼 사용해, 가중치 행렬(임베딩 테이블)에서 해당 벡터를 추출한다. 이 과정은 해석이 아니라 조회에 가깝다.
- 정보의 구체화
토큰 ID는 그 자체로는 비교나 변형이 불가능한 기호에 불과하다. 그러나 벡터로 변환되는 순간부터 각 차원의 성분값을 통해 거리, 유사성, 방향과 같은 기하학적 연산이 가능해진다. 토큰이 벡터라는 계산 가능한 실체로 바뀌는 지점이다.
- 가변성
입력 단계에서의 벡터는 정적이지만 레이어를 통과하며 주변 벡터들과 연산을 거치면 그 성분값은 계속 변화한다. 동일한 토큰이라도 이미 형성된 벡터들의 상태에 따라 서로 다른 좌표로 이동한다. 우리가 컨텍스트라고 부르는 것 역시, 동일한 출발점이 서로 다른 연산의 장 위에서 다른 경로를 따르며 형성된 벡터 상태의 총합에 가깝다.
임베딩
임베딩은 이산적인 토큰을 고차원 연속 공간의 벡터로 전환하는 과정이자 그 결과물이다. 토큰은 의미로 해석되는 것이 아니라, 모델 내부의 좌표계에 배치된다. 각 토큰은 임베딩 행렬에서 하나의 벡터를 할당받고 연속적인 공간 위에 놓인다. 이 공간에서는 거리, 방향, 조합과 같은 기하학적 연산이 가능해지며, 이후의 모든 계산은 이 좌표 위에서 이루어진다.
벡터의 각 성분값 자체로는 인간이 해석할 수 있는 축으로 나뉘어 있지 않다는 점도 유의해야 한다. 임베딩 공간은 의미의 사전이 아니라, 연산이 가장 잘 작동하도록 형성된 공간에 가깝다. 유사성이나 단어 간 관계는 이를 인간의 언어로 받아들이는 과정의 것이다.
여기에서 좌표계는 실제로 모델 내부에서 구체적인 파라미터 행렬로 구현된다. 그 성질은 다음 세 가지로 정리할 수 있다.
- 구현 구조: 임베딩 행렬(Embedding Matrix)
$V \times d$ 크기의 파라미터 행렬이다 ($V$: 어휘 사전 크기, $d$: 모델의 은닉층 차원). 토큰 ID가 $i$일 때, 임베딩 행렬의 $i$번째 행이 해당 토큰의 초기 벡터가 된다.
- 표현 형식: 밀집 표현(Dense Representation)
1과 0으로만 표현되는 원-핫 인코딩(One-hot Encoding)과 달리, 수백~수천 차원의 공간 안에 실수값을 빽빽하게 채워 넣는다. 이는 데이터의 특징을 압축하여 표현하며 계산 효율성을 극대화한다.
- 형성 방식: 학습 가능한 파라미터(Learnable Parameters)
임베딩 벡터 내의 각 실수값들은 고정된 것이 아니라, 모델 학습 과정에서 손실 함수(Loss Function)를 최소화하는 방향으로 최적화된다. 즉, 모델은 학습을 통해 각 토큰이 벡터 공간의 어느 좌표에 위치해야 연산에 유리한지를 스스로 결정한다.
왜 벡터인가?
역사에서 왜 무언가 선택되고 이어졌는지를 단정하는 것은 꽤 위험이 따른다. 나는 오늘날 LLM이 벡터를 기반으로 동작하는 구조 역시 운명론적이라기보다는 당시의 기술적 제약과 계산 모델, 그리고 신경망이라는 방법론이 요구한 조건들이 수렴한 결과에 가깝다고 생각한다.
하지만 이러한 조건을 살펴보는 것은 엔지니어로서도 중요하다. 벡터라는 형식의 필요성을 이해하는 것만으로도 LLM에 씌워지는 신비주의적이고 의인적인 의미를 벗겨낼 수 있기 때문이다.
수학적 층위
수학적 층위에서 벡터는 의미를 설명하기 위해 선택된 게 아니라 의미를 계산 대상으로 만들기 위한 형식이다.
- 비교 가능한 실체
기호의 세계는 이산적이다. 서로 다른 두 단어는 기호로서 독립적이다. 그러나 기호가 벡터라는 좌표로 치환되는 순간, 서로 다른 두 존재는 동일한 공간 위에서 비교 가능한 실체가 된다. 서로 다른 두 벡터는 특성이 축으로 나열되어있는 까닭에, 사과와 배가 기호로서는 다르지만 벡터로서는 여러 특성값을 공유할 수 있다.
- 거리와 운동성
벡터 공간에서 “거리”는 상태를 나타내는 것이기도 하지만, 동시에 가까워지고 멀어지는 운동이라는 가능성을 포함하는 개념이다. 이 거리는 역전파(backpropagation)를 통해 줄어든다. 초기에는 임베딩 행렬 안의 벡터가 무의미한 난수 배열로 존재하지만, 사전 학습을 통해 벡터와 벡터 사이 연산 결과가 사전에 정의된 목표 분포에 가까워지도록 수정된다. 이 연산은 선형 변환과 비선형 활성화 함수의 반복이며, 이 과정에서 벡터가 가지는 특성값은 정답에 가까이 가기 위해 소멸시키고 증폭시키는 필터링을 거친 결과로 남는다.
- 유사성과 가중치
왜 벡터는 ‘사과’와 ‘배’ 같이 유사성을 반영한다고 여겨질까? 이는 특성값이 사전에 정의된 의미가 아닌 연산 결과이기 때문이다. ‘사과’와 ‘배’가 유사해지는 것은 동일한 가중치 행렬층 아래에서 같은 손실 함수의 영향을 받기 때문이다. 동일한 행렬층과 곱해지면서 같은 사전 정의된 목표 분포와 유사해지는 방향으로 손실이 최소화된다.
결국 역전파 과정에서 두 벡터의 성분값이 유사해지는 것은 지능의 결과가 아니라 구조적으로 강제된 수렴의 결과다. 이는 모델이 ‘사과’와 ‘배’의 유사성을 이해하기 때문이 아니라, 비슷해질 수밖에 없는 계산 경로 위에 놓였기 때문이다.
구조적 층위
구조적 층위에서 벡터는 비용, 속도, 확장 가능성을 모두 고려한 계산 단위다.
- 계산 효율과 하드웨어적 고려
자연어 문장의 길이는 제각각이며 단어의 형태도 다양하다. 이 불규칙한 언어는 고정 차원의 실수 벡터로 변환된다. 규격화를 통해서 모델은 데이터의 내용과 상관없이 동일한 크기와 규격 내의 연산 파이프라인을 유지할 수 있다. 이는 대규모 병렬 처리를 가능하게 하는 물리적 토대가 된다.
- 행렬 곱셈과 병렬 처리
LLM이 벡터를 다루는 실질적인 방식은 행렬 연산이다. 왜 하필 행렬인가? 행렬 곱 연산의 각 출력 원소는 동일한 입력을 공유하지만, 계산 과정 자체는 서로의 결과에 의존하지 않는다.
GPU는 수만 개의 코어가 각자 담당한 구역의 내적을 동시에 수행하는 데 특화되어 있다. 만약 언어를 그래프나 트리 같은 유연한 구조로 다뤘다면, 지금처럼 수조 개의 파라미터를 실시간으로 처리하는 것은 비효율적이었을 것이다. 결국 벡터라는 형식은 우리가 가진 가장 강력한 계산 자원인 GPU가 가장 효율적으로 처리할 수 있는 규격이었기에 선택된 셈이다.
- 연산 밀도와 메모리 효율
엔지니어링 관점에서 가장 비싼 비용은 연산 그 자체가 아니라 메모리에서 데이터를 가져오는 행위에 있다. 벡터를 행렬 단위로 묶어 처리하게 되면, 메모리에서 가중치를 한 번 읽어올 때 여러 개의 입력 벡터를 동시에 처리할 수 있다.
즉, 행렬 연산은 하드웨어가 데이터를 가져온느 것에 메모리를 낭비하지 않고 대규모로 연산을 실행할 수 있게 한다. 이러한 이유로 벡터는 하드웨어 아키텍처에서 가장 빠르고 저렴하게 연산을 수행할 수 있는 선택지가 되었다.
표현적 층위
표현적 층위에서 벡터는 언어의 복잡성을 분해하지 않은 채, 하나의 연산 상태로 유지할 수 있는 표현 형식이다. 여기서 중요한 것은 차원의 크기가 아니라, 연산을 거친 이후에도 표현 형식이 변하지 않는다는 점이다.
- 직교성
벡터는 서로 다른 특성들을 하나의 상태 안에 중첩시키면서도, 연산 과정에서 서로의 간섭을 줄인다. 이를 가능하게 하는 조건으로 충분히 높은 차원이 요구된다. 고차원 공간에서는 서로 거의 직교한 방향이 다수 존재하기에 무작위로 선택된 벡터 간의 내적은 0에 수렴한다. 이로 인해 하나의 단어가 가진 여러 독립적인 맥락적 특성들은 분리된 구조로 나뉘지 않고도, 하나의 벡터 상태 안에서 공존할 수 있다.
이는 ‘사과’라는 단어가 가진 색상, 맛, 역사, 발화적 맥락 등 수만 가지의 독립적인 특징들이 서로 간섭(Interference)하지 않고 각자의 수치를 유지할 수 있는 바탕이 된다.
- 정보의 중첩과 밀도
벡터 표현에서 하나의 차원은 특정 의미에 고정되지 않는다. 대신 의미는 여러 차원의 조합 상태로 분산되어 저장된다. 즉, 하나의 차원이 단 하나의 고정된 의미를 담당하는 것이 아니다. 그렇기에 수천 개의 차원들이 서로 조합되며 수백만 개의 미세한 개념적 상태를 표현할 수 있다. 이러한 분산 표상(Distributed Reprsentations)은 언어의 다양한 맥락을 단일 상태 안에 압축하기 위한 공학적 선택이다. 표현이 벡터라는 형식을 유지하는 한, 정보는 분해되지 않고 연산 가능한 형태로 유지된다.
- 선형 분리 가능성
벡터 표현이 중요한 이유는 표현의 풍부함보다 계산의 단순함에 있다. 벡터 상태는 선형 변환과 비선형 활성화를 거쳐도 다시 벡터로 돌아오는 닫힌 연산을 가진다. 따라서 모델은 벡터라는 동일한 연산 틀 안에서 다양한 판단을 병렬적으로 수행할 수 있다. 이는 복잡한 언어적 판단을 별도의 구조로 분기시키지 않고, 표현 형식을 바꾸지 않은 채 단일 연산 상태 위에서 처리하기 위한 조건이다.
세 층위 정리하기
벡터가 중요한 이유는 의미를 담고 있어서가 아니라, 벡터가 연산의 대상이 될 수 있기 때문이다. 벡터는 선형 변환과 합성 같은 연산을 거쳐도 다시 벡터로 돌아오는 닫힌 구조를 가진다. 이 닫힌 연산성 덕분에 모델은 표현 형식을 바꾸지 않은 채, 동일한 계산 틀 안에서 상태를 반복적으로 변형할 수 있다. 의미처럼 보이는 판단은 이 연산의 누적 결과일 뿐이다.
나가며
벡터는 의미를 담아두는 그릇이 아니다. 벡터의 각 성분은 특정한 의미 축에 대응되지 않으며, 어느 차원도 단어의 뜻이나 개념을 직접 가리키지 않는다. 그럼에도 불구하고 벡터가 의미를 표현하는 것처럼 보이는 이유는, 여러 벡터가 동일한 연산 구조 아래에서 형성되고 상호작용하기 때문이다. 의미는 개별 벡터의 속성이 아니라, 벡터들이 만들어내는 연산 상태의 관계에서 사후적으로 드러난다. 의미는 저장되는 것이 아니라 계산되는 셈이다.
임베딩 벡터는 이 계산의 출발점이다. 모델이 실제로 다루는 것은 고정된 단어 표현이 아니라, 레이어를 통과하며 계속 갱신되는 벡터 상태다. 동일한 토큰에서 시작한 벡터라도 어떤 연산을 거쳤는지에 따라 전혀 다른 좌표로 이동하며, 우리가 컨텍스트라고 부르는 것은 이러한 상태 변화의 누적에 가깝다.
임베딩 벡터가 토큰에 대응된다는 사실은, 토큰 분절 방식이 달라질 경우 벡터 공간의 구조 역시 달라질 수 있음을 의미한다. 의미가 어떤 좌표에 놓이게 되는지는, 모델의 학습뿐 아니라 언어를 어떻게 분절했는지에 의해서도 규정되는 까닭이다.
그렇게 보자면 LLM은 언어를 이해하는 존재라기보다 벡터 상태를 변형하는 거대한 계산 장치에 가깝다. 벡터라는 형식은 의미를 담기 위해 선택된 것이 아니라, 의미를 계산 가능하게 만들기 위해 선택된 표현이다. 이 글은 출발점에서 벡터를 의미보다는 다시 연산의 관점에서 바라보고자 했다.
References
본문에서 다룬 내용이 아래 레퍼런스에 동일한 문장으로 직접 서술되어 있음을 의미하지는 않는다. 대신, 각 논문이 전제하는 계산 구조·학습 방식·표현 형식을 바탕으로 본 글의 관점을 정립하는 근거로 사용했다.
- Embedding (machine learning) – Wikipedia
- Mikolov et al., Efficient Estimation of Word Representations in Vector Space
- Vaswani et al., Attention Is All You Need
- Devlin et al., BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
- Elman, Distributed Representations
- Olah et al., The Building Blocks of Interpretability (Distill)
- Kudo & Richardson, SentencePiece: A simple and language independent subword tokenizer
- NVIDIA, Deep Learning Performance Guide