LLM #1 LLM 이해와 Transformer #
#2025-08-11
1. LLM 기본이해 #
#1 Word Embedding (p.27-28)
Word Embedding
- 핵심 아이디어는 단어가 어떤 맥락에서 자주 함께 등장하는지를 학습.
- “you say goodbye and I say hello”에서
- ‘goodbye’주변에는 ‘you’, ‘say’, ‘and’, ‘I’ 같은 단어가 함께 등장하고 그 관계를 학습하도록 신경망을 훈련시킨다.
- 학습이 반복되면 각 단어는 벡터로 표현되고 의미가 비슷한 단어일수록 벡터 공간에서 가깝게 위치한다.
- Input이 ‘goodbye’이고 Target이 ‘you’, ‘say’, ‘and’, ‘I’여도 된다.
Word Embedding - 신경망 구조 그림
- 왼쪽 단어 목록, 가운데는 은닉층, 오른쪽에 단어 목록
- “eat"이 입력으로 들어가면 은닉층을 거쳐서 출력 쪽에서 “apple”, “juice”, “rice” 같은 주변 단어들이 활성화되고 이 과정에서 모델은 입력 단어와 주변 단어 사이의 연관성을 학습한다.
Reasoning
- 만들어진 벡터는 단순한 유사성뿐 아니라 관계까지 담고 있다.
- ‘king - man + woman = queen’
- ‘왕에서 남성을 빼고 여성을 더하면 여왕’이라는 단어의 의미 관계가 수학적으로 표현된다.
- Reasoning?
- 놀이터에서 ‘( )가 나를 바라보고 있다’라는 문장에서 빈칸에 들어갈 수 있는 적절한 단어를 유사한 문장들의 패턴을 통해 추론 가능하다.
- 단어 벡터 공간에서의 위치 관계 그림
- king, queen, man, woman 같은 단어들이 점으로 표시되고 상대적인 거리와 벡터 방향이 있으니까 King - Man + Woman = Queen 같은 의미적 연산이 가능하다.
의문점
- Word Embedding이 분포가설의 구현이라고했는데 분포랑 무슨상관이지?
- 단어가 어떤 단어들과 자주 같이 나타나느냐의 분포가 그 단어의 의미를 규정한다는 게 분포가설.
- Word Embedding은 비슷한 맥락에서 쓰이는 단어들은 비슷한 임베딩 벡터로 표현된다 즉 주변 단어와의 관계가 임베딩 공간에 투영된다.
- 단어의 분포적 특성이 수치화되어 벡터 공간에 반영된다 = 분포가설을 계산가능한 형태로 구현한것이다.
- 정리
- 어떤 분포를 (즉 평균 분산을) 진짜로 구현한다기보다 ‘단어의 분포(유사한 단어와 자주 나타나는 정도)적 특성이 있다’라는 이론을, Word Embedding은 주변 단어와의 관계를 비슷한 임베딩 벡터로 표현 즉 수치화함으로써 ‘구현’했다.
#
#2 RNN, seq2seq, attention (p.30-31)
- RNN은 입력된 단어를 임베딩이라는 연속형 벡터로 바꿔서 모델에 넣고 바로 앞까지 처리된 hidden state 벡터와 함께 계산한다.
- 예를 들어 what, will, the, fat 같은 단어가 순서대로 들어오면 모델은 마지막 시점에 얻어진 벡터로 다음 단어를 예측한다. 이때 소프트맥스를 사용해 확률 분포를 만들고 가장 높은 값, 예를 들어 0.7이 나온 단어를 선택하는 식이다. 하지만 이 구조는 오래된 정보가 뒤로 갈수록 점점 희미해져서 30~50칸 전의 단어는 사실상 기억하기 어렵다는 장기의존성 문제가 생긴다.
- seq2seq 모델에서는 인코더가 전체 입력 시퀀스를 읽고 그 맥락을 하나의 컨텍스트 벡터로 압축, 컨텍스트 벡터를 디코더가 받아서 출력 시퀀스를 생성한다. 영어 문장을 인코더에 넣으면 전체 문장이 하나의 벡터로 변환되고 그 벡터를 토대로 디코더가 프랑스어 문장을 순서대로 만들어낸다. 하지만 문장이 너무 길면 이 하나의 벡터가 과도하게 많은 정보를 담아야 해서 정보 소실이 발생한다.
- 어텐션은 입력 문장을 하나로 압축하지 않는데 인코더가 만들어낸 모든 hidden state도 사용한다.
- 사용 = 디코더가 단어를 출력할 때마다 인코더의 전체 hidden state 중에서 어떤 부분을 주목할지 점수를 계산하고 그 점수에 따라 필요한 정보를 골라온다. (hidden state = 인코더의 output인 문맥 벡터)
- 예를 들어 번역에서 “it”이라는 단어를 생성하려 할 때, 인코더 입력 중에서 “animal”인지 “street”인지 같은 후보들에 대해 각각 점수를 매기고 가장 관련이 높은 단어를 참고하는 방식이다.
- 이렇게 하면 입력 전체를 다시 들여다볼 수 있으므로 문장이 길어도 특정 단어와의 연결 관계를 놓치지 않는다.
- 또한 입력을 순차적으로만 처리하지 않고 병렬적으로 계산할 수 있다. RNN처럼 컨베이어 벨트 방식으로 단어를 하나하나 넘기는 대신 전체 입력 문장에서 각 단어와의 연관성을 한 번에 계산하기 때문에 연산 효율이 좋아지고 장기의존성 문제도 해결된다.
- 사용 = 디코더가 단어를 출력할 때마다 인코더의 전체 hidden state 중에서 어떤 부분을 주목할지 점수를 계산하고 그 점수에 따라 필요한 정보를 골라온다. (hidden state = 인코더의 output인 문맥 벡터)
#
#3 Contextual Embedding (p.32)
- Word Embedding은 “단어 하나 = 벡터 하나”라는 고정 표현을 만든다.
- 그림에서 “bank”라는 표기가 좌표평면에 점 하나로 찍혀 있고 이건 돈의 bank인지 강둑의 bank이든 한 벡터에 섞여버린다.
- 트랜스포머 기반의 Contextual Embedding은 같은 철자라도 문맥이 바뀌면 다른 벡터를 생성한다. self attention에서 입력 문장의 각 토큰이 주변 모든 토큰을 참고해 자기만의 문맥 표현을 만들기때문에 최종 hidden state(=그 토큰의 임베딩)가 글자가 같아도 문맥에 의존해 달라진다.
- “He deposited money in the bank”에서 bank의 벡터는 money, deposit, loan 같은 단어에 높은 어텐션 가중치를 주며 금융 의미 쪽으로 이동한다.
- “They had a picnic on the river bank”에서는 river, shore, picnic에 주목해 물가 의미 쪽으로 이동한다.
- 좌표평면 그림에서
- bank가 문맥에 따라 “돈/대출” 근처에 위치하기도 하고 “강/물가” 근처에 위치하기도 한다.
#
#4 Transfer Learning (p.33)
- 딥러닝의 기본은 복잡한 문제를 풀기 전에 여러 중간 단계를 거쳐 추상적인 개념을 점차 쌓아가는 표현 학습(임베딩).
- 비슷한 문제에서 사전 학습된 모델이 이미 학습해 둔 개념들(임베딩 벡터)을 가져와 특정 문제를 푸는 방식이 Transfer Learning.
#
2. 유사도 #
#1 Cosine Similarity (p.45-48)
개념
- 두 벡터가 서로 얼마나 같은 방향을 가리키는가?
- 수학적 개념: 두 벡터의 내적을 각 벡터의 크기로 나누어 정규화한 값 (정규화=크기는 사라지고 각도 즉 코사인만 남는다)
유사도 판단 (수치)
- 두 벡터 사이 각도는 0도이면 코사인은 1이 되고 유사도는 최대치인 1로 계산된다.
- 두 벡터가 정반대 방향이라면 각도는 180도가 되고 코사인은 -1이 되고 유사도가 최소가 된다.
- 두 벡터가 직각이라면 각도가 90도가 되고 코사인 값이 0이 되고 벡터 사이에 방향성의 유사성이 전혀 없다고 해석한다.
- cf) 유사도가 최소이다 vs 방향성의 유사성이 전혀 없다.
- 최소는 -1이고 0이기만해도 유사성은 전혀 없다.
- 실제 계산에서는 보통 모든 성분이 양수인 경우가 많기 때문에 유사도의 최소값은 0으로 취급하는 경우가 많다고함.
유사도 판단 (실제 case)
- 단어의 빈도수가 달라져도 방향이 비슷하다면 코사인 유사도가 높다.
- 문서 하나가 apple과 banana를 각각 한 번씩 포함하고 또 다른 문서가 apple과 banana를 세 번씩 포함했다면 두 문서의 벡터는 크기는 다르지만 방향은 같다.
- 그래서 코사인 유사도는 1이 되어 두 문서가 같은 주제를 다루고 있다고 판단한다.
case study
- 문서1은 apple과 banana를 포함해 (1,1,0)/ 문서2는 apple, banana, carrot을 포함해 (1,1,1) / 문서3은 apple과 banana가 여러 번 반복되어 (3,3,0) 벡터로 표현.
- 유클리드 거리를 기준으로 보면 문서1은 문서2와 더 가깝지만 코사인 유사도를 기준으로 보면 문서1과 문서3이 더 가깝다.
- 코사인 유사도가 벡터 크기의 차이를 무시하고 방향만 보기 때문에 텍스트 데이터처럼 길이가 달라도 같은 주제를 다룰 수 있는 상황에 유용하다(데이터가 크기와는 무관하게 같은 맥락이나 주제를 향하고 있는지를 확인).
#
3. Transformer #
#1 Self-Attention
인코딩과 디코딩 (p.55)
- 인코딩은 비정형적인 입력을 의미 있는 벡터로 바꾸는 과정이다.
- 디코딩은 이 벡터를 기반으로 새로운 대상을 생성하는 과정이다.
- 예를 들어 문장을 입력하면 인코더가 문장을 수치 벡터로 변환하고 디코더가 이를 이용해 번역된 문장을 만들어낸다.
#
Query, Key, Value (p.56)
- 입력으로 들어온 벡터의 크기가 4×10
- 여기에 가중치 행렬을 곱해서 차원을 줄이거나 변형한다.
- 예를 들어 10×5 크기의 가중치 행렬을 곱해주면 입력은 4×5 크기로 변환되어 원래 10차원이었던 단어 임베딩 벡터가 5차원 표현으로 바뀌게 된다.
- 선형 변환으로 차원을 바꾼 뒤 Query, Key, Value 벡터로 나눈다.
- Query는 “내가 누구를 참고할지, 어디에 집중할지”
- Key는 “Query가 참고할 수 있는 정보”
- Value는 “실제로 전달될 정보”
cf) Key가 Query가 참고할수있는 정보라는게 무슨말인지?
- Query는 질문이고, Key는 후보 답변. Query는 지금 단어는 누구한테서 힌트를 얻어야 하지? Key는 이 특징이 지금 단어가 찾는 ‘누구’랑 얼마나 맞을까?
- 예시 “I love pizza”
- Query: 현재 내가 집중하는 단어 -> “love”
- Key: 문장 안의 모든 단어가 가짐 -> I(Key), love(Key), pizza(Key).
- Query(“love”)가 Key들과 내적을 해서 유사도를 보니 Key(“pizza”)랑 점수가 높으면 “love는 pizza랑 관련이 크다” / Key(“I”)랑 점수는 낮으면 “love는 I와는 관련이 약하다” 그럼 “love”라는 단어는 “pizza”의 정보를 더 많이 참고해야겠구나 하고 판단.
#
Self-Attention에서 토큰이 자기 자신과 다른 모든 토큰들 사이의 관련성을 계산하는 법 (p.57-60)
- Query와 Key를 내적해 4×4 크기의 score 행렬을 만든다. (i, j) 위치의 값은 i번째 토큰이 j번째 토큰을 얼마나 주목해야 하는지 score인데 내적 값이 크면 유사성이 높다는 뜻이고 주목해야 할 대상이라는 뜻이다. (이처럼 토큰들 사이의 관련성을 자기 자신 안에서 계산하기 때문에 Self-Attention이라고한다)
- 내적 값이 너무 커질 경우 특정 항목만 지나치게 강조될 수 있으므로 score를 Key 차원의 제곱근으로 나누어 스케일링하는 과정을 통해 값의 분산이 안정화해서 학습을 안정화한다.
- Softmax 함수를 적용해 각 행이 합이 1이 되도록 확률 분포로 바꾼다. 이렇게 변환된 값이 Attention Score로, 각 토큰이 다른 토큰을 얼마나 참고할지를 확률 형태로 표현한 것이다.
- Value 벡터와 이 Attention Score를 곱한다 즉 원래의 정보(Value)를 점수에 비례해 가중합한 새로운 벡터를 만든다. 이 결과는 원래 토큰 벡터를 업데이트한 것과 같다. 즉, 각 토큰이 문맥 속에서 어떤 다른 토큰과 얼마나 연결되어 있는지를 반영해 다시 표현된 새로운 벡터가 생성된다.
#
#2 Multi-Head Attention (p.61-62)
Multi-Head 필요성
- Self-Attention을 한 번만 거치면, 특정한 기준(맥락, 의미, 어휘적 유사성 등)에서만 관계를 포착할 수 있다.
- 멀티 헤드 어텐션은 이런 Self-Attention을 여러 개 병렬로 실행해서, 서로 다른 관점에서 입력을 바라볼 수 있도록 한다. 예를 들어 어떤 헤드는 단어의 순서적 맥락에 집중할 수 있고, 또 다른 헤드는 의미적 유사성에 주목할 수 있으며, 또 다른 헤드는 특정 어휘 패턴을 따라가며 관계를 본다. 이렇게 여러 헤드가 만들어내는 다양한 관점을 합치면 일종의 앙상블처럼 작동해서 모델은 훨씬 다차원의 표현을 생성하게된다.
학습 과정
- 각 헤드는 Q, K, V를 각각 독립적인 가중치 행렬로 변환한다. 따라서 같은 입력이라도 헤드마다 Q, K, V가 달라지고 그 결과로 나온 Attention Output도 서로 다르다 즉 헤드별로 서로 다른 방식으로 “무엇을 주목할지”를 학습한다.
- 각 헤드의 Attention Output은 보통 4×5와 같은 크기의 행렬로 나오는데 여러 헤드의 출력들을 옆으로 이어붙이는 방식으로 결합한다(Concat).
- 단순히 붙인 결과는 각 헤드의 특징이 분리된 채로 남아 있어, 모델이 이를 자연스럽게 활용하기 어려우므로 이어붙인 벡터를 다시 한 번 선형 변환(Linear Transformation)해서 하나의 통합된 표현으로 만든다. 이렇게 하면 맥락 정보, 의미 정보, 어휘 정보 등 다양한 관점의 결과가 하나의 일관된 벡터 공간 안에서 재표현되어 이후 레이어들이 이 표현을 자연스럽게 사용할 수 있다.
#
#3 정규화, 잔차 연결, Feed Forward Layer, Positional Encoding (p.63-65)
정규화(Normalization)
- 정규화는 LayerNorm을 통해 이루어진다. 이는 각 토큰 벡터 차원별 평균과 분산을 정규화해서 입력 분포가 일정하게 유지되도록 만든다. 이렇게 하면 학습이 빠르고 안정적이 되며, 그래디언트 소실이나 폭주를 막을 수 있다. 실제로 Multi-Head Attention 같은 연산을 통과하면 값의 크기가 커지거나 불안정해질 수 있는데, LayerNorm을 거치면서 다시 안정된 값으로 조정된다.
잔차 연결(Residual Connection)
- 연산 과정에서 원래 입력 정보를 보존하기 위해 사용된다. 예를 들어 어텐션 결과만 계속 쌓아가면 초기 입력의 정보가 소실될 수 있다. 이를 방지하기 위해 원래 입력을 연산 결과에 더해주는 방식으로 정보 흐름을 유지한다. 이렇게 하면 기존 정보 위에 추가적인 정보를 겹쳐 쌓는 구조가 되고, Gradient가 지나갈 통로도 유지되어 학습이 더 잘 이뤄진다. 즉, 단순히 변형된 표현만 쓰는 게 아니라 원래 입력과 변형된 출력을 함께 사용하는 것이다.
Feed Forward Layer
- 어텐션만으로는 거의 선형 결합만 수행되므로 모델의 표현력이 부족할 수 있다. 딥러닝의 핵심은 비선형성을 주입하는 것인데, 이를 위해 활성함수(Activation Function)를 사용한다. 트랜스포머에서는 보통 ReLU 같은 비선형 함수를 적용해 입력 표현을 더 복잡하고 풍부하게 바꾼다. 이 과정에서 단순한 선형 결합을 넘어 복잡한 패턴을 학습할 수 있게 된다.
Positional Encoding
- 어텐션 메커니즘은 모든 토큰을 동시에 바라보기 때문에 토큰의 순서를 직접적으로 알 수 없다. 예를 들어 “나는 밥을 먹었다”와 “밥이 나를 먹었다”는 순서가 바뀌면 의미가 완전히 달라지지만, 어텐션만 사용하면 두 문장을 구분하기 어렵다. 이를 해결하기 위해 입력 임베딩에 순서 정보를 더해주는 것이 Positional Encoding이다. 위치 정보를 단순히 정수로 추가하면 값의 범위가 커져서 다루기 힘들기 때문에, 사인(sin)과 코사인(cos) 함수를 이용해 주기적인 패턴으로 위치를 표현한다. 이렇게 하면 어떤 위치든 간결하게 표현할 수 있고, 모델은 순서를 반영한 연산을 할 수 있다. 사인과 코사인은 시간적, 순차적 데이터를 표현할 때 자주 쓰이는 방식인데, 여기서는 토큰의 위치 정보를 수학적 벡터로 만들어 임베딩과 더해주어 순서를 구분할 수 있도록 돕는다.
#
#4 디코더에서의 Masked Self-Attention (p.66-67)
마스킹(masking)
- 트랜스포머의 기본적인 어텐션 메커니즘은 모든 단어가 한꺼번에 보일 때 서로 간의 문맥을 파악하는 구조지만 디코더는 문장을 생성할 때 미래 단어까지 동시에 볼 수 없도록 제한해야 한다. 예를 들어 “I study"까지 입력이 주어졌다면, 그 시점에서 “AI hard"라는 단어들은 아직 주어지지 않은 정보이므로 모델이 참고하면 안 된다.
- 이를 위해 마스킹 과정을 거친다. 어텐션 스코어 매트릭스를 계산할 때, 미래 토큰에 해당하는 위치는 마스크 처리해서 무시한다. 따라서 주어진 입력이 “I study"라면, 모델은 오직 “I"와 “study” 사이의 관계만 학습하고 그 이후 단어와는 내적을 하지 않는데 이렇게 하면 디코더는 항상 현재까지의 단어들만을 기반으로 다음 단어를 예측하게 된다.
- 마스킹에서 중요한 연산은 Q(쿼리)와 K(키)의 내적을 통해 어텐션 스코어 행렬을 만드는 것이다. 그런데 마스킹이 적용되면 아직 주어지지 않은 단어는 스코어 계산에서 제외된다. 따라서 어텐션 스코어 행렬에는 주어진 토큰까지만 반영된다. 예를 들어 “I"가 입력이면 자기 자신만 참조할 수 있고, “I study"라면 “I"와 “study"만 참조할 수 있다.
- 훈련(학습) 과정에서는 모델이 만든 출력과 실제 정답(ground truth)을 비교하면서 학습한다. 예를 들어 “I study"까지 입력했을 때 다음 단어로 “AI"가 올 확률을 모델이 예측하고, 확률 분포를 생성해서 생성한 확률 분포로부터 얻은 예측값을 실제 정답과 비교해서 Loss를 계산한다. 이 손실을 역전파하면서 모델의 weight가 업데이트된다.