大模型评估排障指南 | 关于可复现性
<p>这是 <strong>大模型评估排障指南</strong> 系列文章的第三篇,敬请关注系列文章:</p><ul>
<li>关于推理</li>
<li>关于 <span class="math inline">\(\LaTeX\)</span> 公式解析</li>
<li>关于可复现性</li>
</ul>
<p>假设你读了一篇最近的新模型技术报告,然后心血来潮想要在本机复现他们的结果,却发现根本没法复现,这是为什么?<br>
让我们来探讨一下原因。</p>
<h2 id="代码库不同">代码库不同</h2>
<p>要想复现论文或报告的评估得分并精确到小数点,首先要确保使用的代码库一致。</p>
<p>一般情况下,你可以选择使用作者提供的默认评估代码,或者参考标准代码库实现,如 EleutherAI 的 <code>lm_eval</code> 或 HuggingFace 的 <code>lighteval</code> 等。但如果作者没有说明评估代码的来源,那很遗憾,基本上不太可能精确复现了。</p>
<p>如果你想知道为什么代码实现不一样会导致结果差异,可以参考这篇我们与 Hugging Face 评估团队共同撰写的 博客 (⭐)。博客中介绍了对 3 种常见 MMLU 评估代码 (<code>lm_eval</code>、<code>helm</code>、以及原作者实现) 的研究测试,重点解释了实现差异以及对模型得分的影响。</p>
<p><em>注:正因如此,Hugging Face 团队决定推出 Open LLM Leaderboard,以便统一规范,使得在排行榜上的模型得分之间的对比更加公正。</em></p>
<h3 id="导致结果微妙差异的其他因素">导致结果微妙差异的其他因素</h3>
<p>即便使用的代码库相同,也会因为实现上的小细节不同而导致结果差异,可能因素有:</p>
<ul>
<li><strong>随机种子不同</strong>
<ul>
<li>一般来说,推理阶段受随机种子影响的程度要比训练阶段小得多。不过种子对 CUDA 运算 (可以参考 PyTorch 的 reproducibility 页面) 会产生一些影响从而改变预测结果,尤其是基于非贪心算法生成的时候。另外如果使用 few-shot 的方式推理,随机种子还可能影响 prompt、前后处理函数。-> 有时候微小的差距可能导致评估结果好几分的差异。</li>
</ul>
</li>
<li><strong>评估指标不同</strong>。在实践中,哪怕是指标的名字相同,也可能代表不同的含义,比如:
<ul>
<li>对于 <code>精确匹配</code> 任务,如果原作者使用 <em>对数似然</em> (计算不同答案的对数概率) 计算评估得分,而你采用 <em>生成式</em> (只比较贪心生成结果与参考答案),那你们计算出的指标就会不同。</li>
<li>我们还发现,有一些评估代码库虽然定义为 <code>精确匹配</code>,但实际计算的却是 <code>前缀精确匹配</code> (只比较生成结果与参考答案的开头部分),或者 <code>后缀精确匹配</code> (与前缀相反),亦或是 <code>准精确匹配</code> (归一化的精确匹配)。-> 因此,不能仅仅依赖于指标名称来判断实际评估方式,还是需要查看具体代码实现。</li>
</ul>
</li>
<li><strong>归一化方式不同</strong>
<ul>
<li>还以 <code>精确匹配</code> 为例,在 <code>lm_eval</code> 库的 v1 版本中,有一些任务就被简单地命名为 <em>生成式</em> <code>精确匹配</code>,如果不看代码,你可能觉得就是上文提到的那样,直接对比预测结果和参考答案,不过: 如果查看代码会发现,在做对比之前预测结果还多做了一步归一化 (去除标点符号、统一数字格式等),这明显会改变对比得分。(现在 <code>lm_eval</code> 库的 v2 版本已经在多数指标中添加归一化名称了。) -> 这是最容易出错的地方,特别是对于那些需要大量归一化或答案后处理的任务,例如数学评估 (需要从生成解释中提取答案)。</li>
</ul>
</li>
</ul>
<h2 id="prompt-不同">Prompt 不同</h2>
<p>Prompt 不同会导致模型输出和评分产生巨大的变化,主要包括 3 个类别:</p>
<h3 id="prompt-自身">Prompt 自身</h3>
<p>Prompt 格式可能会显著影响最终得分。</p>
<p>例如在多选题评估中,呈现选项的 prompt 常见格式有以下几种:</p>
<pre><code>问题: <问题文本>
选项:
</code></pre>
<pre><code class="language-markdown">| A. <Choice A> | (A) <Choice A> | <Choice A> |
| B. <Choice B> | (B) <Choice B> | <Choice B> |
| C. <Choice C> | (C) <Choice C> | <Choice C> |
| D. <Choice D> | (D) <Choice D> | <Choice D> |
</code></pre>
<pre><code>回答:
</code></pre>
<p>预测格式:<code>A</code>/<code>B</code>/<code>C</code>/<code>D</code> 或 <code><Choice A/B/C/D></code>。</p>
<p>这些选项是 <strong>语义等价</strong> 的,虽然它们包含的内容完全相同,但仍然会导致评估得分差异。我们有一些 实验结果 (同一模型评估结果差异高达 7 分) 以及 论文 阅读发现,都得出了类似的结论。</p>
<p>一些评估还会加入任务描述 prompt (例如: <code>以下问题都是关于 <主题> (The following questions are about <topic>)</code>)。同样地,这些 prompt 的存在与否也会影响评估得分。</p>
<p>这篇 优秀论文⭐ 阐述了这一问题: 许多模型在评估基准数据集上训练,过拟合了 prompt 和 标准回答的格式,才导致了对其他格式的 prompt 适应能力差。</p>
<p>我们在 Open LLM Leaderboard 2 上的 Llama3.1 系列模型也观察到了这一现象。它们在标准测试集 MATH-Hard 上预测的答案完全正确,但在 few-shot 简单模板测试中评估得分反而较低,很可能就是过拟合了 GSM8K 数据集 (另一个数学测试集) 的 prompt 和答案格式。</p>
<h3 id="系统-prompt-和聊天模板">系统 prompt 和聊天模板</h3>
<p>聊天模型的训练或微调方式通常是指令或偏好,也就是学习推理时遵循模板的能力。例如多轮对话中,模板一般以通用 prompt (也叫 <code>system prompt</code>) 开始,并以特殊 token (一般是 <code>System: </code>) 作为前缀。通用 prompt 的作用是为模型提供高层次指令,如某个角色的描述或者通用的指令格式。对话中可能还需要在文本前缀添加关键词,如询问时添加 <code>User</code>,回答时添加 <code>Assistant</code>。</p>
<p>小样本 (few-shot) 评估时,需要决定这些样本是一次性提供 (在一个 prompt 中),还是多轮分次提供 (模仿上一段中的 user/assistant 模式)。</p>
<p>如果不遵循模型推理的最佳模板格式,那么输出性能就会下降,因为会迫使输出偏离训练阶段收敛的概率空间。</p>
<h3 id="少样本-prompt">少样本 prompt</h3>
<p>使用少样本评估 (不熟悉少样本可以参考 <code>General knowledge/Model inference</code>) 时,需要注意两点:</p>
<p>显然,<strong>few-shot 示例数量应与参考任务相同</strong>。</p>
<p>此外,必须保证评估时输入不同模型的 <strong>少样本示例完全一致</strong> (没错不用惊讶,不一致时也会影响结果差异,因为不同模型对不同样本的表现是不一样的)。甚至你还得保证输入的 <strong>少样本示例顺序完全一致</strong>。我们观察到 MMLU 子测试集上,有些模型因为示例输入顺序的变化导致的评估结果 (点击 这里 可以查看一些结果) 差异最高可达 3 分。</p>
<p>这里的随机种子同样重要。</p>
<h2 id="生成参数不同">生成参数不同</h2>
<p>对于生成式评估的参数,需要注意:</p>
<ul>
<li>确保使用的 <strong>句子终止 token 相同</strong></li>
<li>确保模型评估的 <strong>生成 token 数相同</strong></li>
<li>确保采样的 <strong>种子和温度系数相同</strong></li>
</ul>
<h2 id="模型加载不同">模型加载不同</h2>
<p>我们观察到的差异点有:</p>
<ul>
<li><strong>硬件不同</strong><br>
Pytorch 库并不保证在不同硬件上进行非确定性操作时的可重现性</li>
<li><strong>代码库不同</strong><br>
例如推理后端的库: <code>transformers</code> 和 <code>vllm</code>,它们对矩阵计算的管理方式就不尽相同。</li>
<li><strong>batch size 不同</strong><br>
许多评估代码库和模型后端已经记录了这个问题: 推理时使用的 batch size 不同会导致结果差异。如果你想要完全复现结果,必须固定 batch size (当然有时候会因为显存问题无法做到)。</li>
<li><strong>模型加载精度不同</strong><br>
使用低精度加载模型 (实际上加载的是权重的不同版本) 可以减少内存占用和推理成本,但会导致计算结果改变。</li>
</ul>
<hr>
<blockquote>
<p>英文原文: https://github.com/huggingface/evaluation-guidebook/blob/main/contents/troubleshooting/troubleshooting-reproducibility.md</p>
<p>原文作者: Nathan Habib</p>
<p>译者: SuSung-boy</p>
<p>审校: Adeena</p>
</blockquote><br><br>
来源:https://www.cnblogs.com/huggingface/p/18874554
頁:
[1]