토큰과 임베딩이란? LLM이 언어를 숫자로 바꾸는 원리

토큰과 임베딩이란? LLM이 언어를 숫자로 바꾸는 원리

문장은 숫자가 되어야 계산된다

토큰(token)은 문장을 잘게 나눈 조각이고, 임베딩(embedding)은 그 조각을 의미의 지도 위 좌표로 바꾼 숫자 묶음이다. 이 두 단계가 대규모 언어모델(LLM, Large Language Model)이 언어를 다루는 출발점이다. 사람이 '고양이' 세 글자를 보고 곧바로 뜻을 떠올리는 것과 달리, 컴퓨터가 다루는 것은 오직 숫자다. 글자든 문장이든 결국 숫자로 바꿔 넣어 줘야 한다.

그래서 LLM의 입력 파이프라인은 두 번의 변환을 거친다. 먼저 문장을 토큰으로 쪼개 각 토큰에 고유 번호를 매긴다. 그다음 그 번호를 다시 여러 개의 실수로 이뤄진 벡터, 곧 임베딩으로 바꾼다. 토큰화가 '조각내서 번호 붙이기'라면, 임베딩은 '번호에 뜻을 입히기'다.

이 글에서는 토큰화가 왜 단어가 아니라 서브워드(subword) 단위로 이뤄지는지, 임베딩이 어떻게 단어 사이의 '가깝고 멂'을 좌표로 담아내는지, 그리고 이 둘이 실무에서 컨텍스트 길이와 요금, 다국어 성능에 어떤 영향을 주는지 차례로 짚는다. GPT를 한 번이라도 써 본 정도면 충분히 따라올 수 있다.

레고 블록처럼 쪼개는 토큰화

토큰화(tokenization)는 문장을 토큰이라는 조각으로 자르는 과정이다. 토큰은 단어 하나일 수도, 단어의 일부일 수도, 때로는 글자 하나일 수도 있다. 모델은 미리 정해 둔 토큰 목록(vocabulary)의 블록마다 고유 번호를 붙여 둔다. 문장이 들어오면 먼저 블록으로 쪼개고, 각 블록을 번호로 바꿔 모델에 넣는다.

레고 블록에 비유하면 감이 잡힌다. 아무리 복잡한 문장도 결국 정해진 블록들의 조합으로 표현된다. 예를 들어 'the weather is so good' 같은 문장은 다섯 개의 조각으로 나뉘어 각각 '3', '8921', '412', '77', '2065' 같은 번호로 바뀐다. 이 번호 배열이 모델이 실제로 받아 드는 입력이다.

핵심은 토큰이 사람이 정한 문법 단위가 아니라는 점이다. 방대한 글뭉치에서 '자주 뭉쳐 다니는 글자 덩어리'를 통계적으로 잘라낸 조각이 토큰이다. 그래서 토큰의 경계가 우리 직관과 어긋날 때가 잦다. 흔한 단어는 통째로 한 토큰이 되지만, 드문 단어나 오타는 여러 조각으로 쪼개진다.

왜 단어가 아니라 '조각' 단위인가

가장 단순한 방법은 단어마다 번호를 하나씩 붙이는 것이다. 하지만 이 방식은 곧 벽에 부딪힌다. 세상의 단어는 사실상 무한하다. 새 유행어, 고유명사, 합성어, 오타가 끝없이 등장한다. 모든 단어에 미리 번호를 부여하려 들면 목록이 감당할 수 없이 커지고, 그럼에도 사전에 없는 단어는 계속 나온다.

반대로 글자 하나하나를 토큰으로 삼으면 목록은 작아지지만, 문장을 표현하는 데 필요한 토큰 수가 너무 많아지고 의미 단위가 지나치게 잘게 부서진다. 그래서 현대 LLM은 그 중간을 택한다. 자주 쓰는 덩어리는 통째로 한 토큰으로, 드문 것은 잘게 쪼개는 절충이다. 이 방식을 서브워드 토큰화라 부른다.

예를 들어 'cyberpunk' 같은 드문 단어가 목록에 없어도 문제없다. 'cyber'와 'punk'라는 두 블록을 이어 붙여 조립하면 된다. 정해진 수의 블록만으로도 처음 보는 단어를 표현할 수 있는 셈이다. 이 방식의 대표 알고리즘이 BPE(Byte Pair Encoding)다. 자주 나란히 등장하는 글자 쌍을 반복해서 하나의 블록으로 합쳐 나가며 목록을 만든다. OpenAI의 tiktoken이나 구글의 SentencePiece가 이런 서브워드 토크나이저를 구현한 대표 도구다.

한국어는 왜 조각이 더 많이 날까

언어마다 조각나는 정도가 다르다. 영어는 대체로 토큰 하나가 네 글자쯤이고, 토큰 하나가 영어 단어 약 0.75개에 해당한다. 즉 100개의 토큰이면 영어 단어 75개 남짓이다. 이 어림값은 OpenAI가 안내하는 '1 토큰 ≈ 영어 4글자 ≈ 0.75단어'라는 규칙에서 나온다.

한국어는 사정이 다르다. 같은 뜻을 담아도 토큰이 더 많이 나온다. 조사와 어미가 붙어 어형이 다양하게 바뀌는 데다, 토크나이저가 주로 영어 중심의 글뭉치로 학습된 탓에 한글 조각의 단위가 잘게 잡히기 때문이다. 한 측정에 따르면 한국어는 같은 내용을 담아도 대략 2~3배, 문장에 따라서는 그 이상까지 토큰이 늘어난다.

주요 토크나이저 방식을 비교하면 다음과 같다.

방식 대표 사용처 특징
BPE(Byte-Pair Encoding) GPT 계열(tiktoken) 자주 붙어 나오는 글자쌍을 병합해 어휘를 구성
WordPiece BERT 계열 우도를 높이는 서브워드를 선택해 병합
SentencePiece(Unigram) 다국어 모델(T5·LLaMA 등) 공백까지 기호로 다뤄 언어 독립적으로 학습

이 차이는 두 가지로 체감된다. 첫째는 길이 제한이다. 같은 분량의 글이라도 한국어가 컨텍스트 한도에 더 빨리 닿는다. 둘째는 요금이다. 사용한 토큰만큼 과금하는 API 서비스에서 한국어 입력·출력은 영어보다 비싸게 계산되기 쉽다. 한국어로 긴 문서를 다루는 실무에서는 이 '토큰 세금'을 늘 염두에 둬야 한다.

직접 확인하는 토크나이저 실험

토큰화는 말로 설명하기보다 눈으로 확인할 때 확실히 와닿는다. 문장을 입력하면 곧바로 조각과 조각 수를 보여 주는 공개 도구가 있다. OpenAI Tokenizer 같은 웹 도구는 문장을 넣으면 토큰 경계를 색으로 구분해 표시하고 총 개수를 알려 준다.

몇 가지 실험을 권한다. '오늘 날씨가 참 좋다'를 넣어 몇 조각으로 나뉘는지 보고, 같은 뜻의 영어 'The weather is nice today'와 조각 수를 나란히 비교해 본다. 대개 한국어 쪽 조각 수가 눈에 띄게 많다. 여기에 띄어쓰기를 바꾸거나 이모지, 오타를 일부러 섞으면 조각이 어떻게 달라지는지도 확인할 수 있다.

코드로도 쉽게 확인된다. 파이썬에서 tiktoken 라이브러리를 쓰면 enc = tiktoken.get_encoding('cl100k_base') 뒤에 enc.encode('오늘 날씨가 참 좋다')를 호출해 토큰 번호 배열을 그대로 얻는다. 배열의 길이가 곧 토큰 수다. 이 짧은 실험만으로도 '문장이 숫자 조각으로 바뀐다'는 개념이 추상이 아니라 손에 잡히는 사실이 된다.

번호만으로는 뜻을 담지 못한다

토큰마다 고유 번호가 붙었다. 그런데 번호는 이름표에 지나지 않는다. '고양이'가 5번, '강아지'가 8721번이라 하자. 이 두 번호만 봐서는 둘이 얼마나 비슷한 뜻인지 전혀 알 수 없다. 5와 8721은 크기만 다를 뿐 서로 아무 관계도 없는 두 숫자다. 만약 번호의 크기가 곧 의미의 크기라고 오해하면, 모델은 엉뚱한 계산을 하게 된다.

사람은 '고양이'와 '강아지'가 가깝고, '고양이'와 '냉장고'가 멀다는 것을 안다. 기계도 이 '가깝고 멂'을 다룰 수 있어야 문맥을 근사하게라도 파악한다. 다음에 올 단어를 그럴듯하게 고르려면 단어들 사이의 의미적 거리를 계산할 수 있어야 하기 때문이다.

그 답이 임베딩이다. 토큰 하나를 숫자 하나가 아니라 숫자 여러 개의 묶음, 곧 좌표로 바꾼다. 이 좌표들이 놓인 공간을 '의미의 지도'라 부를 만하다. 뜻이 비슷한 토큰은 지도 위에서 가까이 모이고, 뜻이 먼 토큰은 멀리 떨어진다. 번호가 단순한 이름표였다면, 임베딩은 위치가 곧 뜻을 말해 주는 좌표다.

의미의 지도 위 좌표, 임베딩

임베딩(embedding)은 각 토큰을 고정된 길이의 실수 벡터로 바꾼 것이다. 예컨대 한 토큰을 수백에서 수천 개의 숫자로 이뤄진 벡터로 표현한다. 이 벡터는 다차원 공간의 한 점이며, 학습을 거치면서 뜻이 비슷한 토큰끼리 가까운 좌표를 갖도록 조정된다.

핵심 아이디어는 '함께 쓰이는 단어는 뜻도 비슷하다'는 관찰이다. word2vec이나 GloVe 같은 초기 단어 임베딩 연구가 이 원리를 정량화했다. 방대한 글에서 어떤 단어들이 자주 이웃해 등장하는지 통계를 내면, 그 분포만으로도 단어의 의미를 좌표에 담아낼 수 있다. 이렇게 얻은 좌표에서는 놀라운 성질이 나타난다. 벡터끼리 더하고 빼면 '왕 − 남자 + 여자 ≈ 여왕' 같은 유추가 근사적으로 성립한다. 의미의 관계가 좌표의 방향과 거리로 표현되는 것이다.

임베딩 — 단어의 의미를 벡터 공간의 좌표로 표현

두 벡터가 얼마나 비슷한지는 보통 코사인 유사도(cosine similarity)로 잰다. 두 좌표가 이루는 각이 작을수록, 즉 방향이 비슷할수록 유사도가 1에 가까워진다. 검색이나 추천에서 '의미가 비슷한 문장 찾기'가 바로 이 계산으로 이뤄진다. LLM 안에서는 이 임베딩이 입력의 첫 층으로 들어가, 뒤이은 어텐션(attention) 계산의 재료가 된다.

정적 임베딩과 문맥 임베딩의 차이

임베딩에도 세대가 있다. word2vec, GloVe 같은 초기 방식은 단어 하나에 좌표 하나를 고정으로 매긴다. 이를 정적 임베딩이라 부른다. 문제는 한 단어가 문맥에 따라 뜻이 달라진다는 점이다. '배'는 먹는 배일 수도, 타는 배일 수도, 신체의 배일 수도 있는데, 정적 임베딩은 이 셋에 같은 좌표를 준다.

트랜스포머(Transformer) 기반 LLM은 여기서 한 걸음 나아간다. 입력 토큰의 초기 임베딩을 그대로 쓰지 않고, 어텐션을 거치며 주변 토큰의 정보를 반영해 좌표를 문맥에 맞게 다시 조정한다. 그 결과 같은 '배'라도 문장에 따라 서로 다른 표현을 갖는다. 이를 문맥 임베딩(contextual embedding)이라 한다.

정리하면 이렇다. 아래 표는 두 방식의 차이를 압축한다.

두 임베딩 방식 한눈에 비교

| 구분 | 정적 임베딩 | 문맥 임베딩 |

|---|---|---|

| 대표 예 | word2vec, GloVe | 트랜스포머 기반 LLM |

| 좌표 결정 | 단어마다 고정 | 문장 문맥에 따라 변함 |

| 다의어 처리 | 한 좌표로 뭉뚱그림 | 뜻마다 다른 표현 |

| 계산 비용 | 낮음(조회만) | 높음(매번 계산) |

| 주 용도 | 유사어 검색, 초기 특성 | LLM 입력·이해 전반 |

실무에서 임베딩이라는 말은 두 갈래로 쓰인다. 하나는 지금 설명한 LLM 내부의 입력 층이고, 다른 하나는 검색·추천에 쓰는 '문장 임베딩 API'다. 후자는 문장 전체를 하나의 벡터로 압축해 준다. RAG(검색 증강 생성)에서 문서를 미리 임베딩해 벡터 데이터베이스에 저장해 두고, 질문이 들어오면 질문 임베딩과 가까운 문서를 찾아 함께 넣어 주는 방식이 대표적이다.

실무에서 토큰과 임베딩을 다룰 때

실무의 첫 관문은 컨텍스트 윈도우(context window)다. 모델이 한 번에 처리할 수 있는 토큰 수에는 상한이 있다. 프롬프트와 응답을 합친 총 토큰이 이 한도를 넘으면 잘려 나가거나 요청이 거절된다. 긴 문서를 다룰 때는 미리 토큰 수를 세어 적절히 나누는(chunking) 작업이 필수다.

모델별 컨텍스트 윈도우 크기 — 한 번에 다루는 토큰의 양

비용 관리도 토큰 감각에서 출발한다. API 요금은 입력·출력 토큰 수에 비례한다. 앞서 봤듯 한국어는 같은 내용이라도 토큰이 더 많이 나오므로, 프롬프트를 간결하게 다듬거나 반복되는 지시를 줄이는 것만으로 비용을 상당히 아낄 수 있다. 개발 단계에서 tiktoken으로 실제 토큰 수를 재 보는 습관이 도움이 된다.

임베딩을 직접 다루는 실무라면 RAG 파이프라인이 대표 사례다. 문서를 적당한 크기로 쪼개 임베딩하고 벡터 데이터베이스에 저장한 뒤, 사용자의 질문과 코사인 유사도가 높은 조각을 검색해 프롬프트에 붙인다. 이때 문서 조각의 크기, 임베딩 모델의 선택, 검색 결과 개수가 답변 품질을 좌우한다.

흔한 오해와 한계

첫 번째 오해는 토큰이 단어와 같다는 생각이다. 토큰은 단어보다 잘게 쪼개진 서브워드일 때가 많고, 문법 단위와도 일치하지 않는다. '토큰 100개'를 '단어 100개'로 여기면 컨텍스트 계산이 어긋난다. 두 번째 오해는 토큰 번호의 크기에 의미가 있다는 착각이다. 번호는 목록 안의 순번일 뿐, 크기 차이가 의미 차이를 뜻하지 않는다. 뜻의 거리를 담는 것은 번호가 아니라 임베딩 벡터다.

임베딩에도 한계가 있다. 임베딩은 학습에 쓴 글뭉치의 편향을 그대로 흡수한다. 특정 직업이나 집단에 치우친 연상이 좌표에 새겨질 수 있고, 이는 하류 작업의 편향으로 이어진다. 또 임베딩 공간의 '거리'가 언제나 우리가 원하는 의미의 유사성과 일치하지는 않는다. 표면적 표현이 비슷해 좌표가 가까워도 실제 뜻은 다를 수 있다.

다국어에서도 주의가 필요하다. 영어 중심으로 학습된 토크나이저와 임베딩은 한국어를 비롯한 비영어권 언어에서 토큰이 잘게 쪼개지고 표현이 덜 정교해지는 경향이 있다. 최근 모델들이 이 격차를 줄이고 있지만, 언어마다 성능과 비용이 다르다는 점은 여전히 실무의 변수다.

토큰 하나에 매겨지는 가격표

상용 LLM API를 실제로 붙여 쓰다 보면 토큰이 곧 돈이라는 사실을 금방 체감한다. 대부분의 제공사가 입력 토큰과 출력 토큰을 나눠 과금하고, 보통 출력 쪽이 몇 배 비싸다. 이유는 단순하다. 입력은 한 번에 병렬로 처리하지만, 출력은 한 토큰씩 순차적으로 생성해야 하므로 계산 비용이 훨씬 크다. 그래서 같은 작업이라도 프롬프트를 길게 쓰는 편과 응답을 길게 받는 편의 비용 구조가 다르다.

여기서 자주 놓치는 함정이 있다. 한국어는 앞선 절에서 다뤘듯 같은 의미를 담는 데 영어보다 토큰이 더 많이 든다. 즉 동일한 문서를 요약시켜도 한국어 원문은 영어 원문보다 입력 토큰이 불어난다. 실무에서 대량 배치 작업을 돌리면 이 차이가 청구서에 그대로 쌓인다. 비용을 아끼려면 프롬프트에서 군더더기 지시문을 걷어내고, 반복되는 시스템 프롬프트는 캐싱 기능(프롬프트 캐싱)을 쓰는 편이 낫다.

컨텍스트 윈도(context window)도 결국 토큰 단위로 계산된다. '128K 컨텍스트'라는 말은 입력과 출력을 합쳐 최대 12만 8천 토큰까지 한 번에 다룬다는 뜻이지 글자 수가 아니다. 긴 문서를 통째로 넣을 수 있는지 판단하려면 문서를 토크나이저로 먼저 세어봐야 한다. 대충 글자 수로 어림잡다가 윈도를 넘겨 앞부분이 잘려 나가는 사고가 흔하다.

그래서 토큰 회계는 단순한 잔재주가 아니라 서비스 설계의 뼈대다. 예를 들어 사용자당 하루 요청 한도를 정할 때, 요청 수가 아니라 누적 토큰량으로 제한을 걸어야 실제 원가와 맞아떨어진다. RAG 파이프라인을 짤 때도 검색으로 끌어온 청크를 몇 개까지 프롬프트에 붙일지가 곧 토큰 예산 배분 문제가 된다. 품질과 비용 사이의 균형점을 토큰 단위로 계산하는 감각이 실무자에게는 필수다.

숫자 벡터를 다시 문장으로 되돌리는 길, 디코딩

임베딩과 토큰화가 문장을 숫자로 바꾸는 과정이라면, 그 반대편에는 모델이 뱉은 숫자 분포를 다시 토큰으로 골라 문장을 짓는 과정이 있다. 이 마지막 선택 단계를 디코딩(decoding)이라 부른다. 모델은 매 스텝마다 어휘 사전 전체에 대한 확률 분포를 내놓는다. 어휘가 5만 개라면 5만 개 후보 각각에 확률이 매겨진다. 이 분포에서 다음 토큰 하나를 어떻게 뽑느냐가 출력의 성격을 완전히 바꾼다.

가장 단순한 방법은 확률이 가장 높은 토큰을 매번 고르는 그리디 디코딩(greedy decoding)이다. 결정적이고 재현 가능하지만, 문장이 뻣뻣해지고 같은 표현을 반복하는 경향이 있다. 이를 완화하려고 여러 후보 경로를 동시에 유지하며 전체 확률이 높은 문장을 찾는 빔 서치(beam search)를 쓰기도 한다. 다만 빔 서치는 번역처럼 정답에 가까운 출력이 있는 작업엔 좋지만, 창의적 생성에는 오히려 밋밋한 결과를 낸다.

실제 챗봇이 자연스러운 이유는 확률 분포에서 무작위로 뽑는 샘플링(sampling)을 쓰기 때문이다. 이때 온도(temperature)가 분포의 날카로움을 조절한다. 온도를 로짓에 나누는 값으로 이해하면 직관적이다. 온도가 낮으면(예: 0.2) 분포가 뾰족해져 안전한 답만 나오고, 높으면(예: 1.2) 분포가 평평해져 뜻밖의 단어까지 튀어나온다. top-k는 상위 k개 후보만 남기고 나머지를 버리는 방식이고, top-p(누적 확률 샘플링)는 확률을 높은 순으로 더해 임계값 p에 닿을 때까지의 후보만 남긴다. top-p가 top-k보다 널리 쓰이는 까닭은 문맥에 따라 후보 개수를 유연하게 조절하기 때문이다.

아래는 실무에서 파라미터를 잡을 때 참고할 만한 감각이다. 정답이 하나로 정해진 작업일수록 온도를 낮추고, 다양성이 필요한 작업일수록 온도와 top-p를 올린다.

작업 유형 temperature top-p 이유
코드 생성·데이터 추출 0~0.3 0.1~0.5 정확성과 재현성이 최우선
일반 대화·요약 0.5~0.8 0.9 자연스러움과 안정성의 균형
창작·브레인스토밍 0.9~1.2 0.95~1.0 다양성과 참신함을 우선

온도와 top-p를 동시에 극단으로 올리면 문장이 무너지므로, 보통 둘 중 하나만 만지고 다른 하나는 기본값에 둔다.

임베딩 벡터의 거리는 어떻게 재는가

임베딩을 실무에 쓸 때 가장 먼저 부딪히는 질문은 '두 벡터가 얼마나 비슷한가'를 어떻게 재느냐다. 검색이든 추천이든 중복 제거든, 결국 벡터 사이의 유사도를 계산하는 문제로 귀결된다. 가장 널리 쓰이는 척도가 코사인 유사도(cosine similarity)다. 두 벡터가 이루는 각도의 코사인 값을 재는데, 방향이 같으면 1, 직각이면 0, 정반대면 -1이 나온다. 크기가 아니라 방향으로 의미의 닮음을 판단하는 셈이다.

왜 유클리드 거리(직선 거리)가 아니라 각도를 보느냐면, 임베딩에서는 벡터의 길이가 문서 길이나 등장 빈도 같은 부수 요인에 휘둘리기 쉽기 때문이다. '고양이'가 한 번 나온 문장과 열 번 나온 문장은 벡터 크기는 다르지만 의미의 방향은 비슷할 수 있다. 그래서 방향만 비교하는 코사인 유사도가 의미 검색에 잘 맞는다. 실제로 임베딩을 미리 정규화(normalize)해 길이를 1로 맞춰두면, 코사인 유사도와 내적(dot product)이 같아져 계산도 빨라진다.

벡터가 수백만 개로 불어나면 매번 전수 비교를 할 수 없다. 여기서 근사 최근접 이웃 탐색(ANN, Approximate Nearest Neighbor)이 등장한다. HNSW 같은 그래프 기반 색인이나 IVF 같은 군집 기반 색인을 써서, 정확도를 조금 양보하는 대신 검색 속도를 수십에서 수백 배 끌어올린다. FAISS(라이브러리), pgvector(Postgres 확장), Milvus·Qdrant(벡터 데이터베이스) 같은 도구가 이런 색인을 제공한다. RAG 시스템의 검색 품질과 지연 시간은 결국 이 색인 설정에서 갈린다.

한 가지 주의할 점은 서로 다른 모델이 만든 임베딩을 섞어 쓰면 안 된다는 것이다. 임베딩 공간은 모델마다 좌표계가 다르다. A 모델로 문서를 색인해두고 B 모델로 질의를 임베딩하면 좌표계가 어긋나 엉뚱한 결과가 나온다. 검색 인덱스를 구축한 모델과 질의를 임베딩하는 모델은 반드시 같아야 하고, 임베딩 모델을 교체하면 전체 인덱스를 다시 만들어야 한다.

토크나이저가 만들어내는 눈에 안 보이는 버그

토큰화는 조용히 성능을 갉아먹는 버그의 온상이다. 대표적인 사례가 숫자 처리다. 초기 BPE(Byte Pair Encoding) 토크나이저는 큰 수를 일관되지 않게 쪼갠다. '1234'가 통째로 한 토큰이 될 수도 있고 '12'와 '34'로 갈릴 수도 있어, 모델이 자릿수 개념을 잡기 어렵다. 이 때문에 LLM이 여러 자리 덧셈에서 종종 틀린다. 최근 모델들이 숫자를 한 자리씩 강제로 쪼개도록 토크나이저를 손본 것도 이런 산술 오류를 줄이려는 조치다.

공백과 대소문자도 함정이다. 많은 토크나이저가 앞에 공백이 붙은 토큰과 붙지 않은 토큰을 다르게 취급한다. 예를 들어 문장 첫머리의 'Hello'와 문장 중간의 ' Hello'가 서로 다른 토큰 번호를 갖는다. 프롬프트 끝에 실수로 공백을 하나 더 넣으면 모델이 이어붙일 토큰의 후보 분포가 미묘하게 바뀐다. 세밀하게 출력을 통제해야 하는 작업에서는 이런 사소한 차이가 결과를 흔든다.

이른바 '글리치 토큰(glitch token)' 현상도 유명하다. 학습 코퍼스에는 거의 나오지 않지만 토크나이저 사전에는 등록된 희귀 토큰들이 있는데, 이런 토큰을 입력에 넣으면 모델이 앞뒤가 안 맞는 이상 행동을 보인다. 웹 크롤링 데이터에 섞인 특정 사용자명이나 자동 생성된 문자열이 토크나이저를 만들 땐 자주 등장해 사전에 올랐지만, 정작 본 학습 단계에선 걸러져 임베딩이 제대로 훈련되지 않은 탓이다.

이런 문제들은 모델을 바꾸지 않아도 재현되므로 디버깅이 까다롭다. 성능이 이상하게 나올 때는 프롬프트를 실제 토큰 열로 펼쳐 눈으로 확인하는 습관이 도움이 된다. 특히 코드나 표, 정형 데이터를 다룰 때는 들여쓰기 공백이 어떻게 토큰으로 묶이는지 살펴야 한다. 탭과 스페이스가 뒤섞이면 같은 코드라도 토큰 열이 달라져 모델의 이해도가 떨어진다.

멀티모달 시대의 토큰, 픽셀과 소리도 조각이 된다

토큰은 더 이상 글자만의 개념이 아니다. 이미지와 음성, 영상까지 한 모델이 다루는 멀티모달(multimodal) 시대로 접어들면서, 서로 다른 매체를 모두 '토큰'이라는 공통 화폐로 환산하는 방식이 자리 잡았다. 핵심 발상은 단순하다. 텍스트를 조각내 번호를 매기고 임베딩했듯, 이미지도 잘게 나눠 벡터로 바꾸면 트랜스포머가 똑같이 처리할 수 있다.

이미지 쪽에서는 그림을 격자로 잘라 작은 패치(patch)로 나눈다. 예컨대 224×224 크기 이미지를 16×16 픽셀짜리 패치로 자르면 196개 조각이 나오고, 각 패치를 벡터로 펼쳐 임베딩한 뒤 텍스트 토큰과 같은 시퀀스에 이어붙인다. 이것이 비전 트랜스포머(ViT)의 기본 아이디어다. 모델 입장에서는 단어 토큰이든 이미지 패치 토큰이든 결국 벡터 열일 뿐이라, 하나의 어텐션(attention) 메커니즘으로 글과 그림을 함께 이해한다.

음성은 파형을 짧은 구간으로 잘라 특징을 뽑거나, 아예 오디오 코덱으로 이산 토큰(discrete token)을 만들어 텍스트처럼 다룬다. 이렇게 하면 음성 인식과 음성 합성을 하나의 언어모델 틀에서 처리할 수 있다. 실제로 최근 음성 대화 모델들은 소리를 토큰 열로 바꿔 넣고 답변도 토큰으로 생성한 뒤 다시 소리로 되돌린다.

여기서 실무적으로 기억할 점은, 이미지 한 장이 상당한 수의 토큰을 잡아먹는다는 사실이다. 고해상도 이미지는 수백에서 수천 토큰에 해당해 컨텍스트 윈도와 비용을 빠르게 소진한다. 멀티모달 API에서 이미지 여러 장을 던지면 청구 토큰이 급증하는 이유가 이것이다. 결국 매체가 무엇이든 토큰과 임베딩이라는 두 개념이 모든 현대 AI 모델의 공통 입구라는 점은 변하지 않는다.

더 깊이 들어가려면

토큰화의 기초를 다지려면 서브워드 알고리즘의 원조인 BPE 논문(Neural Machine Translation of Rare Words with Subword Units)과 언어에 독립적인 토크나이저를 다룬 SentencePiece를 읽어 볼 만하다. OpenAI가 공개한 tiktoken 저장소를 직접 돌려 보면 GPT 계열이 실제로 어떻게 문장을 쪼개는지 눈으로 확인할 수 있다.

임베딩의 원리는 word2vec을 소개한 'Efficient Estimation of Word Representations'와 그 확장인 'Distributed Representations of Words and Phrases', 그리고 통계적 접근을 취한 GloVe 논문에서 뿌리를 확인할 수 있다. 벡터 유추와 코사인 유사도가 어떻게 의미를 담는지 이 자료들이 잘 보여 준다.

다음 단계는 어텐션과 트랜스포머다. 임베딩이 어텐션을 거치며 문맥 임베딩으로 바뀌는 과정, 그리고 그 결과가 다음 토큰의 확률 분포로 이어지는 흐름까지 이해하면 LLM이 '다음 단어를 고르는' 전체 그림이 완성된다. 토큰화와 임베딩은 그 긴 여정의 첫 두 정거장이다.

출처

  1. Efficient Estimation of Word Representations (word2vec)
  2. GloVe: Global Vectors for Word Representation
  3. Neural Machine Translation of Rare Words with Subword Units (BPE)
  4. SentencePiece: A simple and language independent subword tokenizer
  5. Distributed Representations of Words and Phrases
  6. tiktoken (OpenAI BPE tokenizer)
뉴스레터로 매주 받아보기 ← 기술블로그 목록