LLM - Benckmark调研心得 —— MCQA与Generative任务

概述

经历过一段时间的LLM评测调研,对LLM的评测有了不一样的体会,现将其做一个记录。

此次调研主要关注了LLM-Benchmark评测集、测评工具、测评方式。具体来讲,是调研评测工具对评测集的评测方式。

对于评测方式,我们通常希望关注:评测思路、评测具体实施。

一些评测集的评测思路容易也难以理解,但也需要关注这些问题:让模型直接输出答案?还是让模型通过CoT方式输出答案?使用loglikehood方式?还是Generative方式?等等

评测具体实施方法不禁要问:评测Prompt怎么写?参数怎么设置?是否需要用json_schema来规范输出格式?还是使用extract关键信息并match方式?等等

因为我们的出发点是评测集,所以下面的小节内容安排也将按照上面的逻辑来进行。

MCQA

MCQA,Multiple Choices Question & Answers,是大部分数据集构建的方式。如,MMLUMMLU_PROGPQA等等。这种构建数据集方式的好处在于给予模型固定的答案选项,不让模型过度发挥。主要关注模型解决问题的能力。

那么评测MCQA的思路是什么呢?

通常,我们的第一直接告诉我们:直接把问题和答案告诉模型,并让它直接输出答案,我们只需要从中提取关键选项就行了。

然而,evaluation-guidebook建议我们使用loglikehood方式来评测MCQA任务。

那么什么又是loglikehood

简单来说,loglikehood的评测方式是通过返回预测tokens的概率,而不是tokens本身。概率P越大,P约接近于1,loglikehood的值约接近于0。

loglikehood评测方式是否又存在细微的差别?

当然,这篇文章介绍了三种针对MMLU数据集的loglikehood评测方式。简单总结一下:

Default:仅关注预测tokens中的最大概率选项

HELM:仅关注预测tokens中的第一个最大概率token

Harness:不仅关注选项正确,也关注答案正确

那么loglikehood具体怎么实现呢?

MMLU官方给出了一份评测脚本,这段代码详细的描述了如何使用loglikehood进行MCQA的评测。

然而这段代码有点老旧了,我们简单对它进行修改,就能够得到适用于目前OpenAI API的评测脚本:

 def eval(args, subject, dev_df, test_df):
     cors = []
     all_probs = []
     answers = choices[:test_df.shape[1]-2]
 ​
     for i in range(test_df.shape[0]):
         # get prompt and make sure it fits
         k = args.ntrain
         prompt_end = format_example(test_df, i, include_answer=False)
         train_prompt = gen_prompt(dev_df, subject, k)
         prompt = train_prompt + prompt_end
         while crop(prompt) != prompt:
             k -= 1
             train_prompt = gen_prompt(dev_df, subject, k)
             prompt = train_prompt + prompt_end
 ​
         label = test_df.iloc[i, test_df.shape[1]-1]
 ​
         try:
             response = client.chat.completions.create(
                 model=args.model_name,
                 messages=[
                     {"role": "system", "content": prompt},
                 ],
                 max_tokens=1,
                 logprobs=True,
                 top_logprobs=20,
                 temperature=0
             )
         except Exception as e:
             raise e
         top_logprobs = response.choices[0].logprobs.content[-1].top_logprobs
         lprobs = []
         for ans in answers:
             found = False
             for top_logprob in top_logprobs:
                 if top_logprob.token == ans:
                     lprobs.append(top_logprob.logprob)
                     found = True
                     break
             if not found:
                 print("Warning: {} not found. Artificially adding log prob of -100.".format(ans))
                 lprobs.append(-100)
         pred = {0: "A", 1: "B", 2: "C", 3: "D"}[np.argmax(lprobs)]
         probs = softmax(np.array(lprobs))
 ​
         cor = pred == label
         cors.append(cor)
         all_probs.append(probs)
 ​
     acc = np.mean(cors)
     cors = np.array(cors)
 ​
     all_probs = np.array(all_probs)
     print("Average accuracy {:.3f} - {}".format(acc, subject))
 ​
     return cors, acc, all_probs

那么使用loglikehood请求方式,response如下:

 ----------------------------prompt--------------------------
 The following are multiple choice questions (with answers) about  abstract algebra.
 ​
 Find all c in Z_3 such that Z_3[x]/(x^2 + c) is a field.
 A. 0
 B. 1
 C. 2
 D. 3
 Answer: B
 ​
 Statement 1 | If aH is an element of a factor group, then |aH| divides |a|. Statement 2 | If H and K are subgroups of G then HK is a subgroup of G.
 A. True, True
 B. False, False
 C. True, False
 D. False, True
 Answer: B
 ​
 Statement 1 | Every element of a group generates a cyclic subgroup of the group. Statement 2 | The symmetric group S_10 has 10 elements.
 A. True, True
 B. False, False
 C. True, False
 D. False, True
 Answer: C
 ​
 Statement 1| Every function from a finite set onto itself must be one to one. Statement 2 | Every subgroup of an abelian group is abelian.
 A. True, True
 B. False, False
 C. True, False
 D. False, True
 Answer: A
 ​
 Find the characteristic of the ring 2Z.
 A. 0
 B. 3
 C. 12
 D. 30
 Answer: A
 ​
 Statement 1 | If H is a subgroup of G and a belongs to G then |aH| = |Ha|. Statement 2 | If H is a subgroup of G and a and b belong to G, then aH and Hb are identical or disjoint.
 A. True, True
 B. False, False
 C. True, False
 D. False, True
 Answer:
 --------------------------response------------------------
 ChatCompletion(id='chat-3e3ef7af5257479094af5b9bb61daf39', choices=[Choice(finish_reason='length', index=0, logprobs=ChoiceLogprobs(content=[ChatCompletionTokenLogprob(token='A', bytes=[65], logprob=-0.41949766874313354, top_logprobs=[TopLogprob(token='A', bytes=[65], logprob=-0.41949766874313354), TopLogprob(token='Let', bytes=[76, 101, 116], logprob=-2.0444977283477783), TopLogprob(token='The', bytes=[84, 104, 101], logprob=-2.1694977283477783), TopLogprob(token='To', bytes=[84, 111], logprob=-3.5444977283477783), TopLogprob(token='**', bytes=[42, 42], logprob=-3.6694977283477783), TopLogprob(token='Statement', bytes=[83, 116, 97, 116, 101, 109, 101, 110, 116], logprob=-3.7944977283477783), TopLogprob(token='Answer', bytes=[65, 110, 115, 119, 101, 114], logprob=-4.419497489929199), TopLogprob(token='###', bytes=[35, 35, 35], logprob=-5.669497489929199), TopLogprob(token='We', bytes=[87, 101], logprob=-6.419497489929199), TopLogprob(token='C', bytes=[67], logprob=-6.544497489929199), TopLogprob(token='B', bytes=[66], logprob=-6.919497489929199), TopLogprob(token='Correct', bytes=[67, 111, 114, 114, 101, 99, 116], logprob=-7.294497489929199), TopLogprob(token='D', bytes=[68], logprob=-7.669497489929199), TopLogprob(token='E', bytes=[69], logprob=-7.794497489929199), TopLogprob(token='First', bytes=[70, 105, 114, 115, 116], logprob=-8.2944974899292), TopLogprob(token='Based', bytes=[66, 97, 115, 101, 100], logprob=-8.5444974899292), TopLogprob(token='For', bytes=[70, 111, 114], logprob=-8.9194974899292), TopLogprob(token='Both', bytes=[66, 111, 116, 104], logprob=-9.0444974899292), TopLogprob(token='This', bytes=[84, 104, 105, 115], logprob=-9.2944974899292), TopLogprob(token=' Statement', bytes=[32, 83, 116, 97, 116, 101, 109, 101, 110, 116], logprob=-10.7944974899292)])], refusal=None), message=ChatCompletionMessage(content='A', refusal=None, role='assistant', audio=None, function_call=None, tool_calls=[]), stop_reason=None)], created=1736836251, model='Qwen/Qwen2.5-7B-Instruct', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=1, prompt_tokens=385, total_tokens=386, completion_tokens_details=None, prompt_tokens_details=None), prompt_logprobs=None)

从上面的response可以看到,官方在prompt中使用了few-shot那么为什么要用few-shot呢?答案是为了保持格式一致。那为什么不在prompt中加一句,“请直接输出答案,不要解释”呢?我的理解是为了保持评测的纯净性——尽量避免Prompt中出现与评测任务无关的描述,减少冗余prompt对生成结果的影响。

那么是否MCQA任务就一定要用loglikehood方式呢?

根据我调研到的结果,GPQA在他们的代码中注释掉了loglikehood方法。这是为什么呢?这就引出了另外一个问题:

对于MCQA任务,什么情况使用loglikehood方式,什么情况使用generative + extract_match方式呢?

我的理解是:简单的MCQA问题可以使用loglikehood方式;困难的MCQA问题使用generative + extract_match方式。

原因:困难问题使用loglikehood方法会导致模型能力不能完全发挥。之前的CoT和最近的omni模型都是通过增加模型上下文,让模型具有思考能力,来使模型表达更强。如果用loglikehood方式,限制模型只输出选项答案,这限制了模型的思考能力,固然结果会变差。

Generative

我对Generative评测集的定义是:无选择性的生成式评测任务。像gsm8k(数学)、HumanEval(代码)、chinese_sampleqa(通识)、CLUEWSC2020(理解)、Arena-Hard-Auto(指令调优),都属于Generative任务。

那么这类任务的评测方式如何呢?

因为是生成式任务,所以我们通常只需要promptparameters就足够了,然后从中进行extract。我们更多需要关注的是metric

那么上述任务的metric有什么不同呢?

  • gsm8k:acc

  • HumanEval:pass@k

  • chinese_sampleqa:llm as judge

  • CLUEWSC2020:acc

  • Arena-Hard-Auto:llm as judge

那么chinese_sampleqaArena-Hard-Auto都使用llm as judge方式,他们有什么区别呢?

区别在于,chinese_sampleqa使用的是一个Judge-LLM+一个Task-LLM,而Arena-Hard-Auto使用的是一个Judge-LLM+两个Task-LLM

为什么有这样的区别呢?

我们首先来看一下两个评测集的样例:

chinese_sampleqa:

 {
     "primary_category": "中华文化",
     "secondary_category": "道教",
     "question": "《三教源流搜神大全》中的记载”终南山人,头戴铁冠,手执铁鞭,面如黑炭,胡须四张”是形容的道教中的哪位神明?",
     "answer": "赵公明"
 }

Arena-Hard-Auto

 {
   "question_id": "328c149ed45a41c0b9d6f14659e63599", 
  
     "category": "arena-hard-v0.1", 
   
   "cluster": "ABC Sequence Puzzles & Groups", 
   
   "turns": [{"content": "Use ABC notation to write a melody in the style of a folk tune."}]
 ​
 }

可以看到,chinese_sampleqa是有参考答案,而Arena-Hard-Auto没有。

那么答案就呼之欲出了:因为缺少参考答案,所以需要对比的Task-LLM来生成参考答案进行对比。

小结

从上面的内容可以看到,生成式任务评测方式也并不是想象中的简单。在没有llm as judge之前,NLP通常使用perplexity的方式,如ROUGE, BLEU, N-Gram的计算方式。但这对于大模型时代较为落后了,因为语义是无法被计算的,只能被理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值