본 글은 행렬과 벡터의 기본 개념(벡터의 의미, 행렬 곱셈 등)이 있는 독자를 대상으로 합니다. 깊은 지식은 다루지 않으며 LLM에 대한 내용을 추상적으로 살펴봅니다. 총 2부로 AWS Bedrock 사용 경험을 공유하고자 합니다.
LLM은 Large Language Model, 말 그대로 거대한 언어 모델입니다.
여러 설명이 있지만, 수식도 구조도 다 빼고 완전히 추상화하면 행렬 계산기라고 할 수 있습니다.
요즘은 여러 기능을 제공하지만 아주 단순히 텍스트 입력을 받아 텍스트 출력을 생성하는 LLM이 동작하는 과정을 요약하면
텍스트(우리의 input)가 벡터(혹은 행렬)로 바뀌고,
그걸 내부의 거대한 행렬과 곱해서 또 다른 벡터를 만들어냅니다.
그 결과는 다시 텍스트로 바뀌죠.
즉, LLM을 사용하는 과정을 이렇게 정리할 수 있습니다:
텍스트 → 행렬 → 계산(내부 거대 행렬) → 행렬 → 텍스트
그런데 이런 질문이 떠오르지 않나요? "자연어가 어떻게 숫자가 되는거지..?"
LLM은 입력도 숫자, 출력도 숫자, 내부도 전부 숫자 계산입니다.
그럼 도대체 텍스트는 어떻게 숫자로 바뀌는 걸까요?
RGB 색상 체계를 예로 들어보겠습니다. 빨강(R), 초록(G), 파랑(B) 값의 조합으로 색상을 표현하는 방식이죠.
(170, 33, 22)
이 숫자만 보면 우리는 "아, 빨간색 계열이구나"라고 떠올릴 수 있죠.
RGB처럼 숫자에도 정보가 담길 수 있다는 뜻입니다.
단어도 마찬가지입니다.
'강아지'와 '고양이'는 비슷한 맥락에서 등장하니, 숫자로 표현했을 때도 가까워야 자연스럽습니다.
이런 벡터를 만드는 방법에는 여러 가지가 있습니다.
RGB에서 색을 RED, GREEN, BLUE라는 단위로 쪼갠 것처럼,텍스트도 적절한 단위로 나눠야 합니다.
이 작업을 해주는 것이 바로 토크나이저(tokenizer)입니다.
하지만 텍스트는 색보다 훨씬 복잡하죠.
“어디서 끊을 것인가?”, “무엇을 의미 단위로 볼 것인가?”에는 여러 해석이 존재합니다.
예를 들어, 아래 문장을 보겠습니다:
고양이는 귀엽다
이 것을
이처럼 단어를 나누는 방식은 언어마다, 목적마다 달라질 수 있습니다.
그래서 등판하는 것이 바로 형태소 분석기입니다.
형태소는 의미를 가지는 최소 단위입니다.
예시) “고양이는” → "고양이"(명사) + "는"(조사)
형태소 분석기는 텍스트를 이 단위로 쪼개주는 역할을 합니다. 한국어는 특히 조사, 어미 등이 단어에 붙기 때문에 이 작업이 중요합니다. (예: “보다”, “보았다”, “보이기도 했다” → 각각 다른 의미지만, 모두 ‘보’라는 공통 뿌리를 가짐)
형태소 분석기 예시: Khaiii github, Khaiii 소개 글
형태소 분석이라는 방법은 특히 한국어처럼 단어가 여러 조각으로 구성된 언어에서 유용하게 쓰일 수 있습니다. 하지만 LLM에서 사용하는 토크나이저(tokenizer) 는 꼭 형태소 분석을 거치지 않아도 됩니다.
실제로 많은 LLM은, 텍스트를 일정한 규칙에 따라 작은 단위로 나누는 방식을 사용합니다.
이렇게 텍스트를 계산 가능한 단위로 쪼개는 과정을 토크나이징(tokenizing) 이라고 하고, 이 일을 해주는 도구가 토크나이저(tokenizer) 입니다.
토크나이징 방법에는 다양한 종류가 있습니다만...
지금은 “텍스트를 숫자로 바꾸기 전에, 적절한 단위로 잘 쪼갠다” 정도로만 이해해도 충분합니다.
다양한 방식이 궁금하다면 다음 키워드로 공부해보는 것을 추천합니다: Subword, BPE, SentencePiece, WordPiece, ...
추천 글
이제 텍스트를 어떤 단위로 나눌지까지는 정해졌습니다.
그렇다면 다음 질문은 이것입니다:
“그 조각에 의미를 어떻게 담을 것인가?”
그 의미를 벡터로 바꾸는 대표적인 방법부터 하나씩 살펴보겠습니다.
예전엔 사람이 단어 간의 의미를 직접 정의했습니다.
대표적으로 WordNet 같은 시소러스가 있죠.
예시)
이런 관계를 그래프로 표현하고, 0과 1로 연결 여부를 나타내는 인접 행렬도 만들 수 있습니다.
하지만 너무 손이 많이 들고, 새로운 단어나 미묘한 뉘앙스는 담기 어렵습니다.
그래서 지금은 대부분 통계 기반이나 추론 기반 기법을 사용합니다.
말뭉치(corpus)란 사람이 쓴 텍스트 모음입니다.
뉴스, 블로그, 커뮤니티 글, 댓글 등 전부 말뭉치가 될 수 있죠.
말뭉치는 그냥 데이터 같지만, 그 안에는 자연어 사용에 대한 단어 선택, 문법, 뉘앙스 등과 같은 사람의 지식이 담겨 있습니다.
이 말뭉치를 잘 관찰하면, 단어들이 어떤 맥락에서 자주 등장하는지를 파악할 수 있습니다.
예를 들어, ‘고양이’라는 단어가 자주 함께 나오는 단어들을 보면 그 단어가 어떤 의미를 가지는지 어렴풋이 짐작할 수 있겠죠.
즉, 단어는 주변 단어를 보면 의미를 알 수 있다는 가설을 세울 수 있고
→ 이것을 분포 가설(distributional hypothesis)이라고 합니다
이 가설을 바탕으로, 단어들이 어떤 단어들과 자주 함께 등장하는지를 숫자로 정리한 것이 바로 동시발생 행렬입니다.
예시)
"고양이는 귀엽다"
"고양이는 털이 많다"
"고양이와 강아지는 다르다"
→ '고양이' 기준 동시발생 행렬:
고양이 귀엽다 털 많다 강아지 는 와 다르다
고양이 0 1 1 1 1 3 1 1
귀엽다 1 0 0 0 0 1 0 0
강아지 1 0 0 0 0 1 1 1
이런 식으로 단어를 벡터로 바꿔 표현할 수 있습니다.
벡터 간 유사도는 코사인 유사도 같은 걸로 계산합니다.
단어 수가 많아질수록, 동시발생 행렬은 거대한 희소 행렬(sparse matrix)이 됩니다.
즉, 대부분이 0이고 쓸모 있는 정보는 적죠.
지금 이 글에서만 뽑아도 '이', '은', '는' 같은 자주 등장하는 단어들이 행렬 전체를 덮어버릴 수 있습니다.
그래서 필요한 정보만 남기고 나머지는 줄입니다.
여기서 PPMI, SVD 같은 기법들이 등장하지만...
지금은 그냥 "쓸데없는 건 줄이고, 중요한 정보만 남긴다" 정도로 기억해두면 충분합니다.
더 알고 싶다면 관련 키워드를 따로 공부해보는 것을 추천합니다 :)
통계 기반은 한 번 계산해서 끝나는 방식이었습니다. 하지만 새로운 단어나 복잡한 문맥을 다루긴 어렵죠.
새로운 단어가 추가되면, 전체 데이터를 다시 계산해야 하기 때문에 유연하게 확장하기도 어렵습니다.
그래서 등장한 것이 추론 기반 방식입니다.
추론 기반 방식은 문장 속에 빈칸이 있을 때 어떤 단어가 들어갈지 예측하는 문제를 반복하면서 벡터를 조정합니다.
예시)
"고양이 __ 귀엽다"
"__와 강아지는 다르다"
빈칸에 어떤 단어가 가장 잘 어울리는지를 계속 맞춰보는 과정을 모델이 스스로 수행하는 겁니다.
여기서 말하는 ‘모델’은 수 많은 행렬 계산이 연결된 구조입니다.
즉, 예측도 행렬 계산으로 이루어지고, 수정도 행렬 값을 바꾸는 식으로 이루어집니다.
모델이 학습한다는 건 결국 "예측이 틀렸을 때, 내부 행렬을 어떻게 바꿀까?"라는 문제를 푸는 겁니다.
즉, 예측 → 오차(loss) 계산 → 내부 행렬 수정 → 다시 예측의 과정입니다.
처음에는 모델의 가중치가 임의의 초기값으로 설정되어 있어 정확한 예측이 어렵습니다.
하지만 정답과 다르면, 얼마나 차이가 나는지를 계산합니다. 이걸 오차(loss)라고 합니다.
오차가 생기면, 모델은 그걸 줄이기 위해 내부의 행렬(=가중치) 값을 조금씩 조정합니다.
가중치를 바꾸는 방식은 다양하지만, 대표적으로 경사하강법(Gradient Descent) 계열의 최적화 알고리즘을 많이 사용합니다.
추천 영상
경사하강법을 간결히 설명하자면 오차가 줄어드는 방향을 계산해서, 그쪽으로 조금 이동시키는 방식입니다.
하지만 내부 계산은 여러 층으로 연결돼 있어서,"어디서 문제가 발생했는지" 추적해야 합니다.
그걸 돕는 방법이 역전파(backpropagation)입니다.
추천 영상
역전파를 간결히 설명하자면 오차를 출력에서부터 거꾸로 따라가며, 각 가중치가 얼마나 영향을 줬는지 계산하는 기법입니다.
간단히 정리하면 모델 학습은 아래 사이클을 수백만 번 반복합니다.
예측 → 오차(loss) 계산 → 영향 추적(역전파) → 가중치 조정
그 결과로, 학습이 잘 된다면 '고양이'는 '강아지'와 가까운 벡터가 되고,'자동차'는 멀어진 벡터가 됩니다.
이제 모델은 우리가 입력한 문장에 대해 계산만 수행해서 결과를 뱉는 역할, 즉 추론(inference)을 하게 됩니다.
더 이상 오차를 계산하거나 가중치를 바꾸지 않고, 학습된 값 그대로 “예측만 하는 계산기”가 되는 거죠.
지금까지 살펴본 추론 기반 방식은 단어 하나에 의미를 담는 과정을 반복 계산으로 학습하는 구조였습니다.
예측을 해보고, 틀리면 오차를 계산하고, 내부 가중치를 조정하는 이 과정은, 지금 우리가 사용하는 LLM의 핵심 원리와 사실상 동일합니다.
LLM은 이 구조를 더 크고 정교하게 확장한 모델입니다.
단어 하나하나의 의미만 학습하는 것이 아니라, 문장 전체의 흐름과 의미, 단어들의 순서, 앞뒤 문맥의 연결 등과같은 정보까지 함께 고려하며 다음에 나올 단어를 예측할 수 있도록 훈련된 구조입니다.
즉, 작은 단위(단어 벡터)를 다루던 모델이,
더 많은 층과 더 복잡한 계산을 포함하면서 문맥을 이해하는 모델로 성장한 것이 바로 LLM입니다.
GPT는 Generative Pre-trained Transformer의 약자입니다. 이름을 하나하나 풀어보면 아래와 같습니다.
즉, GPT는 트랜스포머 구조를 사용하여 대규모 데이터로 사전 학습된 텍스트 생성 모델입니다.
지금까지 우리는 단어를 숫자로 바꾸고, 그 숫자를 가지고 계산을 반복해서 의미를 배우는 구조까지 살펴봤습니다.
이 모든 계산과 더 다양한 정보 계산을 효율적으로 설계한 구조가 바로 Transformer입니다.
즉 Transformer는
이런 고민을 반영해서 만든 계산의 설계도입니다.
GPT, BERT, LLaMA 등 대부분의 최신 LLM은 Transformer 구조를 기반으로 만들어져 있고, 현재도 발전된 변형들이 계속 나오고 있습니다.
자세한 구조가 궁금하다면 다음 키워드로 공부해보는 걸 추천합니다:
Transformer, Self-Attention, Positional Encoding, Multi-Head Attention
지금까지
를 최대한 단순하고 추상적으로 풀어보았습니다.
그렇다면 이제 이런 생각이 들 수 있습니다.
이미 거대한 데이터로 학습된 LLM, 조금만 내 목적에 맞게 바꿀 수 없을까?
그게 바로 Fine-Tuning입니다. 그런데 LLM은 정말 큽니다. 예를 들어, 구 모델이 되어버린 LLaMA3.1 8B 모델은 대략 80억 개의 파라미터를 가집니다. 여기서 파라미터란 내부 계산을 담당하는 행렬 속 숫자 값들로, 이 숫자 하나하나가 모델의 의미를 결정합니다. (본 글에서 나온 행렬=가중치 라고 이해해도 무방합니다.)
그런데 이걸 전부 바꾸려면 계산 비용이 엄청나고 데이터도 많이 필요하고 시간도 오래 걸리겠죠.
아래와 같은 Fine-Tuning 기법들은 이 계산을 줄이고자 합니다.
핵심은 간단합니다. 전체를 바꾸기엔 너무 크니까, 조금만 바꿔서 원하는 능력을 덧입히자.
하지만 모델 크기가 너무 크니 조금만 바꾸는 것도 손쉽지 않겠죠? 조금만 바꾼다 해도 GPU, 멀티 코어 등 자원이 필요하긴 마찬가지입니다.
하지만 이걸 클라우드에서 쉽게 해볼 수 있는 환경도 있습니다.
바로 AWS Bedrock입니다.
다음 글에서는
차근차근 다뤄보겠습니다.
정말 긴 글 읽어주셔서 감사합니다 :)