所用模型:Qwen1.5-7B-Chat, Qwen2.5, GPT3.5-turbo, GPT4o-mini
Step-by-step thinking 的重要性
对于复杂的问题,相比起让大模型直接给答案,让大模型一步一步演算出结果的正确率会更高(也就是著名的 Chain of Thought 思想)。这一点不仅适用于 prompt 的高效设计,同样也适用于微调数据集格式的设计。
比如说,提供给 Qwen1.5-7B-Chat 的 prompt 是一个场景,场景里有一个盒子,盒子内外有一定数量的不同颜色的积木。我想让大模型告诉我盒子外有多少个积木(盒子外有 8 个),它回答了两次都是 9 个。但如果我先让大模型告诉我,盒子外的积木有哪些,再计算盒子外有多少积木,它就能够回答正确。同样,让 Qwen1.5-7B-Chat 去比较哪个颜色的积木数量最多,它给的答案也是错误的。
(ps. 测试了Qwen2.5 和 GPT4,目前size越大的模型对于数字的认知能力强很多,在相对简单的场景里问题不大)
对于微调来说,训练数据集中 output 设计成 chain of thought 的形式可以一定程度降低大模型自己学习和推理的成本。不过与之伴随的一个问题是,由于生成的 token 数量大大增加了,回答的随机性也会增加。在数据集不够大的情况下,大模型推理时未必会按照数据集设定的格式进行回答。个人推测,在比较固定的场景里,这个问题可以通过去设定 top-p,temperature这些参数去改善(让大模型回答保持相对固定);不过如果是在对于生成内容的创意/随机性要求高的场景里,设定较低的 top-p 和 temperature 不一定是好的解决方法。
(ps. 如果希望得到的输出只是简单的数字或者标签的话,只需要额外加一层后处理提取出所需要的信息)
尽可能显式地建立信息和信息之间的联系
尽可能明显地把关键信息之间联系起来可以使得指令内容对于大模型来说更加清晰明了,一定程度上降低大模型自己去学习和推理一句话中远距离字词之间关系的成本。
比如说我有一个场景,场景内有许多不同的积木,上游传来的信息如下:
[{'id': '', 'label': '盒子', 'color': '红色', 'location': ''}, {'id': '0', 'label': '积木', 'color': '蓝色', 'location': '盒子外'}, {'id': '1', 'label': '积木', 'color': '红色', 'location': '盒子内'}, {'id': '2', 'label': '积木', 'color': '白色', 'location': '盒子外'}, {'id': '3', 'label': '积木', 'color': '蓝色', 'location': '盒子外'}, {'id': '4', 'label': '积木', 'color': '黄色', 'location': '盒子外'}, {'id': '5', 'label': '积木', 'color': '蓝色', 'location': '盒子内'}, {'id': '6', 'label': '积木', 'color': '紫色', 'location': '盒子内'}]
user input: 盒子外有几个蓝色积木?
模型要做的事情有:1. 首先需要从user input 提取出关键信息:盒子外,蓝色,积木 2. 在场景信息中根据字段去筛选出符合user input的instance 3. 对符合条件的积木计数(这一步尤其容易出错)
在把场景信息输入给模型之前,我们可以进行一个预处理,不用让模型自己去记忆并计算每种积木的数量,而是通过代码先计算一遍,如:
盒子内:1 个红色积木,1 个蓝色积木,1 个紫色积木; 盒子外:2 个蓝色积木,1 个黄色积木,1 个白色积木
这时我们会发现,因为“盒子内”和“紫色积木”距离太远,大模型可能无法正确将它们联系在一起,以至于会认为紫色积木也是盒子外的,进一步改进:
盒子内有 1 个红色积木,盒子内有 1 个蓝色积木,盒子内有 1 个紫色积木;盒子外有 2 个蓝色积木,盒子外有 1 个黄色积木,盒子外有 1 个白色积木
因为大模型本质上是大语言模型,训练数据还是以语料为主,它对于语言的理解和信息提取能力应该是要比从抽象结构中去理解和提取信息的能力更强,所以也许用语言来重新表达关键信息能够一定程度提升大模型完成任务的水准。同时,这样的转换也降低了任务的难度,相当于只是让大模型去抽取关键信息。据我实践,不管是prompt还是SFT的数据格式,最后一种设计方式模型回答的正确率都提高不少(虽然让它计算总数时还是偶有出错...)
经济方面的考虑?
对于后续要部署落地的应用,选择大模型首先要在效果和推理效率之间平衡。在资源有限的情况下很难去部署一个超大的模型(即便超大模型如Qwen72B效果会远超7B,14B的模型)。
不过,在生成SFT训练数据的阶段,可以在经济可承受范围内用最好的模型。
OpenAI 报价:https://openai.com/api/pricing/
在我的任务场景中,亲测合成数据指令遵循的效果:gpt4o-mini > gpt4 > gpt3.5
价格:gpt4 >>>>gpt4o-min=gpt3.5
最后最后 - 一个小提醒
如果是调用 OpenAI 的 API,可以通过在参数设置 response_format={ "type": "json_object" } 让输出格式为 JSON。不过要记得 prompt 里也需要显式地提出 大模型必须以 JSON 格式输出回答,否则会报错。
一些尚未解决的问题
1. 碰到好几次大模型推理的时候输出无法停止的情况,上网查了一下可能和 stop token 有关
2. 同一次调用微调好的模型时生成数据的格式相似,但不同次调用微调好的模型时生成数据格式会有比较明显的差异,有时会出现某一次效果奇佳,但其他时候去调用效果奇差的状况。