在自然语言处理(NLP)中,语言模型的评估是衡量模型表现的重要步骤之一。评估指标多种多样,而其中困惑度(Perplexity)是最常用的评估方法之一。
简单来说,困惑度(Perplexity)是衡量语言模型对给定文本的 “困惑” 程度的指标。它反映了模型对语言数据的预测能力。具体而言,困惑度越低,模型的表现就越好,表明它能够更准确地预测文本中的词汇。
可以把困惑度想象成模型面对一个序列时的“困惑程度”。如果模型很容易预测下一个词,那么它就不困惑,困惑度较低;反之,如果模型的预测不准确,困惑度就会较高。
困惑度计算公式如下:

其中:
- \( N \) 表示文本中的总 Token 数量
- \( P(w_{i} | w_{1}, w_{2} .. w_{i-1}) \) 是模型预测的第 \( i \) 个词 \( w_{i} \) 在给定上下文下的条件概率
下面是 awq.evaluation.evaluate_perplexity 中对困惑度计算的实现,我只是修改了下数据加载部分的代码。
import torch
import torch.nn as nn
from tqdm import tqdm
import pickle
def evaluate_perplexity(estimator, tokenizer):
def _perplexity(nlls, nums):
return torch.exp(torch.stack(nlls).sum() / sum(nums))
def _load_data(tokenizer):
eval_data = pickle.load(open('calib_data/03-评估数据.pkl', 'rb'))
input_data = []
for data in eval_data:
message = [{'role': 'user', 'content': data['prompt']},
{'role': 'assistant', 'content': data['output']}]
inputs = tokenizer.apply_chat_template(message,
add_generation_prompt=False,
tokenize=True,
return_tensors='pt')
input_data.append(inputs)
return input_data
eval_data = _load_data(tokenizer)
nlls = []
nums = []
with tqdm(range(len(eval_data)), desc="Perplexity -") as progress_bar:
for i in progress_bar:
inputs = eval_data[i].to(estimator.device)
with torch.no_grad():
logits = estimator(inputs).logits
shift_logits = logits[:, :-1, :].contiguous().float()
shift_labels = inputs[:, 1:]
loss_fct = nn.CrossEntropyLoss(reduction='sum')
neg_log_likelihood = loss_fct(
shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)
)
token_num = shift_labels.shape[1]
nums.append(token_num)
nlls.append(neg_log_likelihood)
curr_ppl = _perplexity(nlls, nums)
progress_bar.set_description(f"Perplexity {curr_ppl:.3f}")
ppl = _perplexity(nlls, nums)
return ppl.item()

冀公网安备13050302001966号