1. 언어 모델의 아키텍처¶
1.1 모델의 내부 구조¶
언어 모델은 요청을 받아 응답을 반환하는 서비스로 볼 수 있다. 프로토타입 단계에서는 현재 사용하는 방식으로 충분하지만, 시스템을 설계할 때는 그렇지 않다. 모델은 주변 아키텍처를 형성하는 비기능적 속성을 가지고 있으며, 이러한 속성은 입력 및 출력 형식으로만 환원될 수 없다.
비용과 지연 시간은 입력 길이에 비선형적으로 의존한다.
답변 품질은 컨텍스트 창이 넘칠 때와 관련 없는 자료로 가득 찰 때 저하된다.
출력의 재현성은 보장되지 않으며 디코딩 매개변수에 따라 결정된다.
밀집형 아키텍처와 희소형(전문가 혼합형) 아키텍처 중 선택은 서비스 제공을 위한 메모리 및 컴퓨팅 요구 사항을 설정해야한다.
이러한 각 속성은 컨텍스트 예산, 모델 선택, 서비스 전략, 지연 시간 요구 사항과 같은 설계 결정에 영향을 미친다. 따라서 이 장의 목표는 모델을 처음부터 학습시키는 것이 아니라 이러한 속성들이 도출되는 최소한의 모델을 구축하는 것이다. 이 장의 핵심 아이디어는 언어 모델이 정의된 속성 집합을 가진 구성 요소이며, 이 책에서 이어지는 내용(프롬프트 설계, RAG, 에이전트, 연산)은 대부분 해당 구성 요소의 확률적 특성을 관리하는 것에 관한 것이다.
대규모 언어 모델(LLM)은 주어진 토큰 시퀀스에 대해 다음 토큰에 대한 확률 분포를 계산하는 매개변수화된 함수이며, 이 함수는 자기회귀적으로 적용된다. 선택된 토큰은 입력에 추가되고 계산이 반복된다. 관찰 가능한 모델의 모든 동작은 수십억 개의 매개변수를 가지고 수조 개의 토큰으로 학습된 모델이 수행하는 이 단일 연산에서 비롯된다. 중요한 것은 모델이 단일한 답이 아니라 분포를 계산한다는 점이며, 이로 인해 출력의 비결정성과 진실성을 나타내는 내장 신호의 부재가 발생한다.
1.2 토큰화¶
토큰은 모델이 작동하는 가장 작은 단위로, 문자나 단어가 아니라 서브워드, 즉 BPE(바이트 쌍 인코딩) 계열 알고리즘으로 구축된 어휘의 항목을 의미한다. 이 알고리즘은 두 단계로 구성된다. 먼저 토크나이저를 학습시키는데(모델 자체를 학습시키기 전에 한 번만 수행), 기본 알파벳에서 시작하여 가장 빈번하게 나타나는 인접한 두 단위를 반복적으로 병합하여 어휘가 목표 크기(일반적으로 30,000~130,000개)에 도달할 때까지 학습한다. 결과적으로 병합된 항목들의 순서가 지정된 테이블이 생성된다. 이 테이블을 적용하면 텍스트가 해당 테이블을 기준으로 결정론적으로 분할된다. 빈번하게 나타나는 단어와 형태소는 하나의 토큰으로 인코딩되고, 드물게 나타나는 것들은 분할된다.
바이트 수준 BPE(바이트 인코딩 최적화): 최신 모델(GPT-2부터)은 유니코드 문자가 아닌 UTF-8 바이트에 BPE를 적용한다. 이를 통해 모든 문자열을 표현할 수 있게된다. 즉, 이전에 본 적 없는 문자, 이모지, 또는 손상된 입력도 일련의 바이트 토큰으로 분해된다. 결과적으로, 진정한 의미의 어휘 외 문자는 존재하지 않는다. “Unkown” 문자는 단순히 더 많은 토큰을 사용하여 더 비싼 방식으로 인코딩될 뿐이다. 키릴 문자의 경우, 이는 문자열 분할 현상의 원인이기도 하다. 기본 라틴 문자 범위를 벗어난 문자는 여러 바이트를 차지하므로 잠재적으로 여러 토큰이 필요할 수 있다.
대안적인 토큰화 알고리즘: BPE가 현대 LLM(GPT 및 LLaMA 계열)에서 지배적이지만, 역사적으로나 구조적으로 다른 강력한 접근 방식들도 존재한다. 이러한 알고리즘들을 구분하는 것은 문자를 하위 단어로 병합하거나 분리하는 수학적 기준이다.
내부 작동 방식(반복 루프):
기능: replace_in_text(전체_텍스트, 합칠_짝꿍, 새_토큰)
1. 전체 텍스트를 처음부터 끝까지 한 단어씩(또는 글자 단위로) 훑어본다.
2. 텍스트 안에서 [합칠_짝꿍[0]]과 [합칠_짝꿍[1]]이 바로 붙어있는 곳을 찾는다.
예: 만약 합칠_짝꿍이 ('un', 'believable') 라면,
텍스트에서 "un" 바로 뒤에 "believable"이 나오는 지점을 찾는다.
3. 찾은 모든 위치에서 두 조각을 지우고, 대신 [새_토큰] ("unbelievable") 하나로 바꾼다.
4. 새로 합쳐져서 단어가 바뀐 전체 텍스트를 반환한다.이해를 돕기 위해 실제 동작을 설명하면, 만약, 텍스트가 아래와 같이 글자 단위로 쪼개져 있다고 가정해보자.
현재 텍스트 상태: [‘l’,‘e’,‘a’,‘r’,‘n’,‘i’,‘n’,‘g’]
이번 루프에서 찾은 최적의 짝꿍(best_pair): (‘i’,‘n’)
새로 만들어진 토큰(new_token): ‘in’
이 함수가 실행되면 텍스트는 아래처럼 바뀐다.
(‘i’,‘n’)이 붙어 있는 구간을 발견
[‘l’,‘e’,‘a’,‘r’,‘n’,‘i’,‘n’,‘g’]
두 글자를 하나로 합침 -> [‘l’, ‘e’, ‘a’, ‘r’, ‘n’, ‘in’ , ‘g’]
이제 다음 루프에서는 ‘in’ 이라는 단어 조각이 하나의 단위로 취급되어, 다른 글자(e.g. ‘in’ + ‘g’)와 다시 합쳐질 기회를 얻게 된다.