일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- fp16
- 합성곱 신경망
- deep learning
- Mean squared error
- rag parsing
- Time Series
- leetcode
- fp32
- anomaly detection
- 데이터 파싱
- fine tuning
- LLaVA
- visual instruction tuning
- 파인튜닝
- Cross Entropy Error
- 손실함수
- multi-query
- rag-fusion
- gemma3
- Non-Maximum Suppression
- 이상탐지
- bf16
- 딥러닝
- pdf parsing
- rrf
- LLM
- qlora
- 오차역전파
- 활성화 함수
- 활성화함수
- Today
- Total
Attention, Please!!!
과연, Perplexity를 기반으로 LLM을 평가하는 것이 합리적일까? 본문
요즘 여러 모델들을 다뤄보고 LLM 관련 논문을 읽어보면서, 문득 이런 생각이 들었다. "과연, Perplexity를 기반으로 LLM을 평가하는 것이 합리적일까?" 물론 Perplexity는 언어 모델들의 주요 평가 지표 중 하나로 가장 많이 사용되고 있다. 이를 통해 모델이 주어진 토큰 시퀀스를 얼마나 잘 예측하는지를 측정하게 되며, 학습 중에 모델의 목표는 이 값을 최소화하는 것이다. 따라서 Perplexity가 낮을수록 모델이 더 좋은 성능을 발휘한다고 일반적으로 이야기할 수 있게 된다. 하지만 이 지표만으로 모든 것을 판단하는 것이 정말 타당할까라는 의문이 든다. 이에 본 게시물에서는 "만약 동일 데이터 셋을 기반으로 학습된 모델 A의 perplexity가 2.5이고, 모델 B의 perplexity는 2.1라면, 모델 B가 더 좋은걸까?"와 같은 질문에 답변할 수 있는 인사이트를 제공하고자 한다.
Perplexity의 개념
Perplexity를 간단하게 설명하자면, 모델이 주어진 토큰 시퀸스를 얼마나 잘 예측하는지 측정하는 지표이다. 즉, 모델이 데이터 셋에 대해 얼마나 "당황"하거나 예측이 어려운지를 나타내는 값이다. HuggingFace의 perplexity에 대해 살펴보면 다음과 같다:
이 수식을 보자면, pθ는 특정 모델(파라미터 θ를 가진 모델)이 토큰 시퀀스를 생성하거나 예측할 때 사용하는 확률 분포를 나타내며, 이 모델은 이전 토큰들을 기반으로 다음 토큰이 나타날 확률을 계산하게 된다. 또한, i번째 토큰의 log-likelihood는 모델이 i번째 토큰을 얼마나 잘 예측했는지를 평가하는 값이며, 이는 이전 i-1개의 토큰을 조건으로 한 i번째 토큰의 조건부 확률에 로그를 취한 값이다. 이때 로그를 취하는 이유는 확률 값을 더 쉽게 다루기 위해서이다. 아래 예시를 통해 perplexity에 대해 자세히 알아보도록 하겠다.
나는 AI를 공부하는 사람이다.
"나는 AI를 공부하는 사람이다." 라는 시퀸스를 점진적으로 확장하면서 각 단계에서 perplexity를 계산하게 된다.
나는
나는 AI를
나는 AI를 공부하는
나는 AI를 공부하는 사람이다
나는 AI를 공부하는 사람이다 .
문장 1: "나는" → 토큰: ["나는"]
문장 2: "나는 AI를" → 토큰: ["나는", "AI를"]
문장 3: "나는 AI를 공부하는" → 토큰: ["나는", "AI를", "공부하는"]
문장 4: "나는 AI를 공부하는 사람이다" → 토큰: ["나는", "AI를", "공부하는", "사람이다"]
문장 5: "나는 AI를 공부하는 사람이다 ." → 토큰: ["나는", "AI를", "공부하는", "사람이다", "."]
### perplexity 계산 예시 ###
세 번째 토큰 "나는 AI를 공부하는"
-토큰: ["나는", "AI를", "공부하는"]
-확률: [0.4, 0.15, 0.15]
-로그 확률 합: log2(0.4)+log2(0.15)+log2(0.15)≈ −1.3219−2.7369−2.7369 =−6.7957
토큰의 개수는 3이므로,
-1/3(-6.7957) = 2.2652
따라서,
PPL = 2^2.2652 = 4.8
위와 같은 방식으로 계산해보면, 각 토큰의 perplexity를 아래처럼 구할 수 있게된다.
"나는": PPL ≈ 2.5
"나는 AI를": PPL ≈ 4.1
"나는 AI를 공부하는": PPL ≈ 4.8
"나는 AI를 공부하는 사람이다": PPL ≈ 5.2
"나는 AI를 공부하는 사람이다 .": PPL ≈ 5.5
과연, Perplexity 지표를 기반으로 비교하는 것이 합리적일까?
이처럼 Perplexity는 언어 모델의 성능을 평가하는 데 사용되는 지표 중 하나로, 모델이 특정 텍스트나 시퀸스를 얼마나 잘 예측할 수 있는지에 대해 평가를 수행한다. 이러한 값이 낮을수록 모델이 더 좋은 성능을 의미한다. 그러나, perplexity를 계산하는 과정에서 토큰의 개수를 기반으로 정규화를 수행한다는 점이 본 게시물에서 중점이 되는 내용이다.
이러한 정규화 과정이 문제의 핵심이다. 토큰의 개수(t)에 따라 perplexity 값이 달라지기 때문에, 대규모 언어 모델을 perplexity 기반으로 비교하는 것이 과연 합리적일까 라는 생각을 할 수 있다. 예를 들어, 토크나이저가 시퀸스 모델링을하기 위해 더 많은 토큰을 생성하는 모델인 경우, 토큰의 개수(t)가 기하급수적으로 증가하게 된다. 그 결과, 정규화 과정에서 이러한 증가로 인하여 perplexity의 값은 낮아지게 된다. 즉, 토큰의 개수(t)가 많을수록 perplexity는 낮아지는 경향이 있어, 토크나이저의 차이로 인해 모델 성능의 차이가 발생할 수 있다는 논점이다.
또한, 언어 모델은 텍스트를 예측할 때, 다음에 올 토큰의 확률을 계산하게 된다. 예를 들어, "나는" 다음에 "AI를"이 나올 확률을 계산하려면, 모델은 "AI를"뿐만 아니라 모든 가능한 단어의 확률을 고려해야 한다. 이때 "모든 가능한 단어"의 집합을 모델의 어휘(Vocabulary)라고 부른다. 어휘 크기가 다른 모델을 단순히 perplexity를 기반으로 비교하게 되면, 어휘가 큰 모델은 기본적으로 더 높은 불확실성(엔트로피)을 가지므로 퍼플렉서티가 높게 나올 가능성이 크다. 반면에, 어휘가 작은 모델은 선택지가 적어 퍼플렉서티가 낮게 나올 수 있다. 이러한 차이는 모델의 실제 예측 능력보다는 어휘 크기의 차이로 인해 발생하므로 공정하게 비교한다는 것은 사실상 어렵다.
Gemma 2: 9B, LLaMA3: 8B, Mistral 7B 모델 간의 perplexity 계산
여태까지 다른 대규모 언어 모델(LLMs)에 대해 perplexity를 기반으로 비교할 수 없는지에 대한 인사이트를 얻었으니, 실질적인 예시를 통해 구체적으로 살펴보고자 한다. 동일한 시퀸스에 대해 세 가지 다른 LLM을 기반으로 Perplexity를 계산해서 비교 해보고자 한다.
거대 언어 모델의 perplexity를 계산하는 것은 생각보다 단순하다. Hugging Face Transformers나 다른 프레임워크에서 Llama 3와 같은 LLM의 forward pass는 입력 시퀀스(토큰화된 텍스트)를 모델에 전달하여 다음 토큰의 확률을 예측하거나, 주어진 시퀀스에 대한 손실(loss)을 계산하게 된다. 이를 통해서 perplexity를 계산하기 위해서는 간단하게 loss 값을 지수화(exponential)를 통해 구할 수 있다.
Hugging Face Transformers를 사용하면 이를 쉽게 구현할 수 있다:
- 모델과 토크나이저를 로드한다.
- perplexity를 계산하는 데 사용할 시퀀스 또는 데이터 셋을 토큰화한다.
- 시퀀스의 input ids를 복제하여 이를 라벨로 사용한다.
- 모델의 forward pass를 input ids에 적용한다.
def calculate_perplexity(model_name, example):
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=True)
model = AutoModelForCausalLM.from_pretrained(
model_name, device_map={"": 0}, torch_dtype=torch.float16
)
inputs = tokenizer(example, return_tensors="pt").to("cuda")
input_ids = inputs["input_ids"]
target_ids = input_ids.clone()
with torch.no_grad():
outputs = model(input_ids, labels=target_ids)
print("Negative log-likelihood: "+str(outputs.loss.item()))
print("Perplexity: "+str(torch.exp(outputs.loss).item()))
이를 기반으로 각 모델에 대한 perplexity를 계산하고자 하며, 시퀸스는 "The Loss is calculated using CrossEntropyLoss which averages over valid labels." 사용하겠습니다. 이에 대해 tokenize()을 적용해보면 아래와 같은 결과를 반환 받게 됩니다.
'input_ids': tensor([[ 1, 415, 4320, 349, 13507, 1413, 10464, 3989, 14261, 28758,
2158, 690, 13363, 1291, 754, 3716, 12499, 28723]],device='cuda:0'),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]],device='cuda:0')}
이제 loss 값을 계산하기 위해 사용할 Label로 Input Ids를 가지고 온 후 각 모델에 던져주면, 아래와 같이 Negative log-likelihood와 Perplexity 결과를 반환 받을 수 있게 된다.
Gemma 2: 9B (256,000 Vocabulary Size)
- Negative log-likelihood: 5.265849590301514
- Perplexity: 193.6107177734375
- Tokenized Sequence: 15 tokens total
'<bos>', 'The', '▁loss', '▁is', '▁calculated', '▁using', '▁Cross', 'Entropy', 'Loss', '▁which', '▁averages', '▁over', '▁valid', '▁labels', '.'
LLama 3: 8B (128,000 Vocabulary Size)
- Negative log-likelihood: 4.738579273223877
- Perplexity: 114.27174377441406
- Tokenized Sequence: 15 tokens total
['<|begin_of_text|>', 'The', 'Ġloss', 'Ġis', 'Ġcalculated', 'Ġusing', 'ĠCross', 'Entropy', 'Loss', 'Ġwhich', 'Ġaverages', 'Ġover', 'Ġvalid', 'Ġlabels', '.']
Mistral 7B (32,000 Vocabulary Size)
- Negative log-likelihood: 4.033050060272217
- Perplexity: 56.43277359008789
- Tokenized Sequence: 18 tokens total
['<s>', '▁The', '▁loss', '▁is', '▁calculated', '▁using', '▁Cross', 'Ent', 'ropy', 'L', 'oss', '▁which', '▁aver', 'ages', '▁over', '▁valid', '▁labels', '.']
그렇다면, Perplexity가 가장 낮은 순으로 Mistral 7B > LLaMA3:8B > Gemma2:9B 다음에 올 토큰에 대해 잘 예측한다고 할 수 있을까? 실험 결과만 놓고 보았을 때, 동일한 데이터 셋과 토크나이저를 사용 했음에도 불구하고 Mistral 7B가 가장 좋다고 할 순 없다. 위에서 언급하였듯이 Perplexity를 지표로 삼을 때 가장 중요한 것은 어휘의 크기이다. 따라서, Vocabulary size가 Mistral 7B > LLaMA3:8B > Gemma2:9B 순으로 클수록 perplexity가 낮아지는 경향을 보였다.
'LLM' 카테고리의 다른 글
Pytorch의 Buffer를 사용해야 하는 이유 via. Attention (0) | 2025.06.23 |
---|---|
"Attention Is All You Need" 의 대항마 : Multi-Head Latent Attention (0) | 2025.05.31 |
거대 언어 모델 : BF16, FP16, FP32에 따른 추론 성능 알아보기 (2) | 2025.05.03 |
Google의 새로운 대항마 Gemma 3 모델 리뷰 (0) | 2025.03.31 |
LLM 추론 시 GPU 메모리 사용량 알아보기 (0) | 2025.03.22 |