亚马逊AWS官方博客
LLM 微调实践 – 利用大语言模型微调进行翻译质量检测(下)
![]() |
上篇对于翻译质检模型的微调进行了初步验证, 其方法基本有效。但在第一阶段优化时,获取的数据具有很不平衡的情况,为了减少其带来的影响,仅仅限定在拼写/语法/符号错误的数据。和真实的线上环境还是有很大差别。真实的生产数据包含多种错误类型,分布也不均匀,有些错误出现的虽少,但业务上很敏感,无法忽略。下图展示了错误的分布情况。
![]() |
图 1. 错误分布图
对当前所有数据按照 error_type 和 dest_lang 进行均衡采样,每个类别上限 100 条,共筛选得到 3.6k 训练集和 669 条测试集。和直接按照第一阶段的方法进行训练和评估,得到的指标大大下滑,检出率下滑到 71.15%。
真值 \ 预测值 | 类别 A(fail) | 类别 B(Pass) |
类别 A(fail) | 476 | 193 |
类别 B(Pass) | 73 | 596 |
类别 A(fail) – 检出率(Recall) | 476/(476+193) = 71.15% | |
类别 A(fail) – 精准率(Precision) | 476/(476+73) = 86.7% |
COT 思考&迭代
Tips – 1:COT 序列不能在开始时暴露结论
从指标上看,精准率下降不多,但是检出率下降很多,模型明显存在偏差,偏向通过。从测试集的输出仔细分析发现,输出中几乎都是以“The translation performs well in several aspects:”开头。
由于所有的正例的 COT 都是以这句开头,在数据量上处于主导地位,导致模型偏向输出这个开头,根据自回归的特点,导致还没有展开分析,结论就已经基本确定了,影响了最终的效果。
基于这个猜测,作者重新合成了数据,在负例和正例中,都通过 prefill 的技巧,在 COT 的开头加上了一句引导词“Let me check the content as thoroughly as possible.”。再次重新训练进行评估,效果整体并没有提高。
再次分析数据,发现是因为正例的 COT 过程都高度相似,导致这种模式的数据在整体数据中的占比过大,使得模型无法聚焦到我们期望模型关注的差异上。
Tips – 2 :别让模型偷懒
基于上面的分析,COT 的合成需要尽可能保证多样性,于是作者尝试在正例的 COT 过程中,分别对各个规则进行判断,并给出针对当前翻译的事实性的证据。根据这个思路,合成了如下的 COT 数据,其中的 COT 确实也已经包含了一些事实性的数据。
再次训练及评估,发现检出率(recall)指标反而进一步下降到 37% 左右。而且在观察 loss 的曲线的时候,发现 loss 在训练的初始阶段下降的速度和幅度比之前更大,20 轮即下降到 0.2 左右。
![]() |
![]() |
图 2. 调整前 loss 曲线 |
图 3. 调整后 loss 曲线 |
针对性地分析一些例子,发现在对应的规则下幻觉很严重,明显的负例仍然输出为“Yes”。这说明模型偷懒了,忽略了真正的学习目标,反而学习了一些更加简单的规律 , 即每个规则点后面都会跟随一个 Yes,正例数据中全部符合这种规律,负例中也仅仅只有个别 rule 才会出现“No”,从 loss 的计算上看,每条训练样本,仅仅只出现一次 pass 或 fail,但是却有多次 Yes 出现,他们都只占一个 token,权重层面是完全等价的。
基于这种推断,作者通过数据处理的方式,把每条规则的结论“Yes”和“No”给去掉,仅仅保留分析的部分,再次进行训练,loss 曲线较之前平滑了很多,但评估指标依然没有明显提高。
多任务微调思路
再次对测试结果进行具体分析,不同错误的的指标差别较大,下图为几种主要检测规则的精准率:
![]() |
图 4. 不同类型错误检测精准率
在 COT 中进行多种错误类型检测,本质上是一种多任务微调,这些错误的数量分布不均,如果混合到一起来生成 COT 数据,那么在一条训练样本中,错误负例对应的那部分 token 数量相对于样本整体的 token 数量则占比太小,从而导致被忽视。从另外一个角度看,COT 中的大部分 token 都跟最后的检查结论没有关系,对最终结论的概率分布没有作用,意味着推理时输出它们是没有意义的,反而造成了推理延迟和计算资源的浪费。
为了应对这些弊端,只能在训练数据层面把多任务完全拆开。例如目前共有7条检测规则,那么则拆成 7 条样本,让合成出的推理过程都对最终结论的概率分布产生影响。
从理论上来讲,单任务模型效果要好于针对多个检测规则的多任务模型,不同任务之间肯定会存在相互影响,除非训练多个独立的模型,这样虽然可以提升整体的并发,降低整体检测的延迟,但是意味着要同时部署多个模型。这对生产应用带来了很大的成本压力和不便。
在本文的实践中,为了避免这个矛盾,采用了逐个添加单个任务训练数据到训练集的方式,依次判断是否对其他任务产生了较大的负面影响, 得到了如下评测数据。
模型类别 | 检测目标 | 检出率 | 精准率 |
单任务模型 | 数量/量词/单位错误 | 93.9% | 93.9% |
多任务模型 | 数量/量词/单位错误 | 84.8%(↓9.1%) | 90.9%(↓3%) |
多任务模型 | 语种夹杂 | 87.8% | 92.0% |
多任务模型 | 拼写/语法/符号错误 | 93.1% | 100% |
单任务模型 | 词汇遗漏或不当 | 78.69% | 57.5% |
上面表格中,考虑到统计的可靠性,仅保留统计量高于 30 的错误类型。得到的结论是,对于前 6 条检查类型,合并训练带来的下降不太明显;第 7 条检查类型,也就是词汇遗漏或者不当,这类错误在真实数据中的占比是最高的,但即使采用单任务模型,其指标也远远达不到要求。
简单问题和困难问题
相对于第 7 条检测规则(词汇遗漏或者不当)来说,前 6 条检测规则对于问题的定义是比较清晰和明确的,对它们进行判断仅仅需要把握简单的规律,这对于模型来说比较简单。但第 7 条规则出错的形式、种类以及涉及到的词汇则要多很多,它的定义也相对比较模糊,在人工标注上也是分布最多的,这说明很多不易划分的错误也划分到了这一类。
甚至说用来合成 COT 过程的商业大模型,其实也不能推断出识别出业务期望的错误,一些 COT 的合成其实带偏了方向。举例说明:
Src | Translation | 期待的COT |
女士可爱卡通熊印花扎染修身截短款抹胸上衣夏季 | Women Cute Cartoon Bear Print Tie-dye Cropped Camisole Top For Summer | I found that \”抹胸\” in the source text specifically means a strapless/tube top, while the translation used \”Camisole\” which refers to a top with straps. These are two distinct styles of tops with different design features, making this translation inaccurate.\n. So my answer is No. |
这个例子中,”Camisole”的意思是吊带,抹胸的正确译法是”Tube Top”。在没有提供专家译文对照的时候,商业模型会忽略掉这个错误,即使提供了专家译文对照的情况下,类似的情况下,也会存在很大几率找不对错误原因。
为了提升 COT 的质量,在合成过程中,作者也采用了一种技巧来降低难度, 思路如下图所示:
![]() |
图 5. 优化后的 COT 合成思路
这种合成思路,先提取关键词的映射关系,然后通过代码提取出两者差异,再提示 LLM 关注这个差异。通过这种方法合成的 COT 过程,其 token 序列的多样性大大增强。其模型补全部分,先输出事实性观察,再给出关键性证据,最后给出结论。
再次进行训练评估,loss 下降变得更加平滑,相对于前一个版本的指标,虽然检出率稍微下降,但精准率明显提升,不再是近乎随机的状态,说明针对困难问题,这种方式是有效的。
真值 \ 预测值 | 类别 A(fail) | 类别 B(Pass) |
类别 A(fail) | 122 | 47 |
类别 B(Pass) | 27 | 142 |
类别 A(fail) – 检出率(Recall) | 122/(122+47) = 72.1% (↓6.59%) | |
类别 A(fail) – 精准率(Precision) | 122/(122+27) = 81.8% (↑24.3%) |
样本质量和数量的影响
目前的检出率还是达不到要求,为了进一步提高,仔细观察训练数据。有两个方面的重要观察:
- 训练数据量存在不足
第 7 条检测规则(词汇遗漏或者不当)的训练集总量仅仅为 837 条,拆分到各个语言上数量更有限。
![]() |
图 6. 分语言的训练样本量分布
- 合成 COT 中识别的错误类型和人工标记的存在较大差异
产生这种情况的主要原因是,人工标记来自多个人,标注的标准本来也有差异,多个规则之间本身存在一定的模糊地带。
为了缓解这两方面的问题,首先采集了更多的数据,样本数据扩展到 5w 条以上,其中针对 Rule 7 的样本量为 3.2w。然后在 COT 合成时添加了投票机制,会推理三次,取多数命中的错误类型,如果不存在多数命中的情况则放弃掉该样本,如果投票得到的错误类型和人工标注不一致也放弃掉该样本,最终筛选出 1.2w+ 样本,相对之前的 837 条,数据规模扩大约 15 倍。对于 Rule 1-6 的训练数据,也采取了类似的机制,只不过还要考虑多任务之间的均衡采样,采样后共得到 1249 条样本。
再次进行训练评估得到指标,其中困难任务 Rule 7 在检出率和精准率提升幅度明显,这说明对于复杂任务,大量且高质量的数据对性能提升十分有效。简单任务 Rule 1-6,受到数据量的限制,指标基本和之前大致持平,也基本满足业务需求。
rule – (1-6) | Rule – (7) | |||
真值 \ 预测值 | 类别 A(fail) | 类别 B(Pass) | 类别 A(fail) | 类别 B(Pass) |
类别 A(fail) | 140 | 15 | 136 | 21 |
类别 B(Pass) | 15 | 140 | 16 | 139 |
类别 A(fail) – 检出率(Recall) | 140/155 = 90.32% | 136/157 = 86.6%(↑14.5%) | ||
类别 A(fail) – 精准率(Precision) | 140/155 = 90.32% | 136/152 = 89.4%(↑7.6%) |
尝试 DPO 训练
前文采用了 Pairwise 思路的训练数据,但本质上其 loss 的并不是提升模型对于正例和负例的区分能力,所以采用 DPO 的方式另外进行了一些尝试。其训练数据的形式如下:
但实现效果 DPO 不达预期,模型出现了比较严重复读机现象。目前判断主要原因是因为合成 COT 的数据中, 存在多次类似的句式的重复,数据的多样性无法保证。
工程角度需要另外注意的是 DPO 需要加载两遍模型,显存用量翻倍。在机型不变的情况下,只能降低 batch_size,或者采用 Lora 训练,否则 p4d.24xlarge 的机型不足以训练 7B 规模的模型。
训练超参数影响
在 SFT(Supervised Full Finetune)阶段,训练超参的影响一般不大,作者主要尝试过的参数如下:
- Learning rate
- Epoch
- Batch size per device
- Gradient accumulation
- Warmup steps
- Logging steps
- Save steps
在本场景的实验中,Learning rate 和 Warmup steps 的对训练效果影响不大,Epoch 分别验证过 2、4、6,这个参数和训练集大小有关,训练集够大,一般 2 个 epoch 即可充分训练,在本场景中,epoch=4 取得最优效果,但增益较小。Logging steps 和 Save steps 会影响到 loss 曲线的平滑程度,为了更好观察 loss 曲线可以设置更小的 Logging steps。Save steps 可以设置大一些,避免存贮过多的 checkpoints,当前场景的训练量一般最长几个小时即可完成,无需考虑从 checkpoint 进行恢复训练。Batch size per device 从理论上来讲越大越好,但对于 7B 模型来说,A10*8 卡基本上无法支撑其显存占用,这个值只能为 1 或 2。A100*4 卡可以支持其显存占用,可以酌情调高一些,但也不能太高。
在 GPU 显存不足的情况下,无法开大 batch_size,可能导致训练不稳定。Gradient accumulation 参数是一种替代措施,可以累积多次 loss 再进行梯度下降。从原理上讲,两者是等价的。于是作者调大了该参数,参考下面 loss 的曲线图,当 Gradient accumulation=32 时,其 loss 曲线更加平滑,训练更加稳定。
![]() |
![]() |
图 7. 参数 bs=2, gas=4 的 loss 曲线 |
图 8. 参数 bs=2, gas=32 的 loss 曲线 |
但是在 HuggingFace 的实现中,存在一个 Issue,导致使用梯度累计并不一定等价于对应的 batch 训练,会有非常明显的精度损失!在作者的对比实验中,检出率下降了 7.7pp。
batch_size =2, Gradient accumulation = 4 | batch_size =2, Gradient accumulation = 32 | ||||
真值 \ 预测值 | 类别 A(fail) | 类别 B(Pass) | 真值 \ 预测值 | 类别 A(fail) | 类别 B(Pass) |
类别 A(fail) | 136 | 21 | 类别 A(fail) | 124 | 33 |
类别 B(Pass) | 18 | 139 | 类别 B(Pass) | 11 | 146 |
类别 A(fail) – 检出率(Recall) | 136/157 = 86.6% | 类别 A(fail) – 检出率(Recall) | 124/157 = 78.9%(↓7.7%) | ||
类别 A(fail) – 精准率(Precision) | 136/155 = 88.3% | 类别 A(fail) – 精准率(Precision) | 124/135 = 91.85% |
这个损失跟模型补全的序列长度有关。假设两个样本的序列长度不等长,1 个是 m1, 1 个是 m2,对于 batch 内累计 loss 的情况:
loss = (l1+l2) / (m1+m2)
对于多次训练梯度累计的情况:
loss = l1/2m1 + l2/2m2
明显看出在 m1 和 m2 不相等时,两者是明显不等价的。比如,m1=10, m2=1000 时,会发现 l2 会被压缩,而 l1 会被严重放大。所以在这个 Issue 解决前,不建议设置较大的 Gradient accumulation。
工程最佳实践
本文中的工作,涉及到大量模型训练、部署、测试(batch)、数据合成等方面,工作量非常巨大。缺乏有效的工程支撑平台,以上的工作很难正确快速的推进。在实践中,借助了 Model Hub 和 Dify 工具,使得整个实验流程事半功倍。
Model Hub 是亚马逊云科技在 Github 上的一个开源项目,基于 LLaMA-Factory 和 HAQM SageMaker 提供了一站式的模型微调、部署、调试的零代码可视化平台,可以帮助用户快速微调各类开源模型,高效同时地进行大量的实验和验证,提升模型微调的工程效率。特别适合希望用到亚马逊云上的训练资源,能够进行大量并行微调实验,但又不希望花太多精力关注 HAQM SageMaker 的使用方式和代码开发的用户。
它具备 LLaMA-Factory 的所有优势,如可以直接部署微调 HuggingFace 上的几乎所有 LLM,训练中可以通过选项的形式引入任何公开的数据集, 同时它还可以使用亚马逊云上的 spot 实例,降低训练成本。
在 Model Hub 的设计中,LLaMA-Factory 是其中的引用的一个子仓库,意味着它可以随着 LLaMA-Factory 的社区生态一起进化。比如遇到训练问题可以到它的社区里寻找解答,对于新发布的模型,Model Hub 和 LLaMA-Factory 的支持时间点是一致的。作为 LLaMA-Factory 生态的参与方,您可以在它官方的 README 中找到介绍 Model Hub 使用的 AWS 官方 Blog。
在本文的工作实践中,从各个维度做了对比实验,训练方式上有 Lora Finetune 和 Full Finetune 的对比;基础模型选型上,在 5 个模型之间进行了对比;在数据层面,前前后后实验了 10 个以上的数据版本;训练参数层面,也对超过 5 个参数做了观察比较。包括一些消融实验,微调实验的次数超过了 100。
一个生产级的模型微调项目,其实验过程中往往会达到比较大的训练次数,Model Hub 作为一种交互良好的实验平台,可供使用者依据需求选择 SageMaker 中 G 系列或 P 系列的机型并发若干个实验,以无代码、流水线的形式完成模型训练和部署,参考下图。
![]() |
![]() |
图 9. 训练任务列表 | 图 10. 部署端点列表 |
此外,Model Hub 支持接入 Wandb(一个用于机器学习实验跟踪、可视化和协作的工具),可以方便地查验训练中的各种指标细节,帮助你观察了解 loss、learning_rate 等多种指标,从而更好地发现训练中的一些问题线索。
![]() |
图 11. Wandb 指标图
它是一个开源的大语言模型(LLM)应用开发平台,它融合了后端即服务(BaaS)和 LLMOps 理念,可快速搭建生产级的生成式 AI 应用。目前在 Github 上已经超 52k star 数,非常的流行。为了借助 Dify 的力量,作者之前的工作 – aws-samples/dify-aws-tool 这个仓库提供了众多的 AWS 与 Dify 集成的模型连接器和工具。Dify 主分支已经整合 aws-samples/dify-aws-tool 的全部工作,使得 Dify 和 Model Hub 完成了接口层面的对齐,所有通过 Model Hub 部署的 LLM 模型(On SageMaker)都可以在 Dify 直接使用。
在训练数据合成阶段,作者利用 Dify 的 workflow 编排功能,以低代码的形式,高效的编排了较为复杂的数据合成的工作流。其演进过程是从单次 LLM 调用,到多次 LLM 调用,再到并发多个 LLM 进行投票,再到结合代码进行一些逻辑处理。 COT 合成数据的过程迭代了至少 10 轮,通过 Dify 工作流,让作者能够快速的通过可视化的方式进行数据校验和调优。
![]() |
图 12 – Dify 样本合成工作流
模型训练完毕以后,在模型的测试阶段,作者利用 Dify 对接 SageMaker 中部署的微调模型,仅仅需要填写 SageMaker 中的 Endpoint 即可。如下图所示,左图为配置 SageMaker 的界面,右图为作者配置的所有用于测试的模型。
![]() |
![]() |
图 13. Dify 的 SageMaker 模型配置 | 图 14. Dify 的 SageMaker 模型列表 |
模型配置好以后,可以很容易地编排到测试验证工作流中,比如下面的工作流可以并发的检测 7 条规则,在发布该工作流以后,就得到了一个公开可以访问的测试 API 供外部集成测试,并且可以获得一个测试前端页面,可以上传 csv 文件,进行批量的测试,非常有利于分享给业务方,用于后续的验证评估。
![]() |
![]() |
图 15. Dify 测试工作流 | 图 16. Dify 工作流测试页面 |
总结
由于大语言模型输出的不稳定性和风控对齐等因素的影响,翻译场景下大语言模型始终面临一定的出错概率。翻译质量检测,一方面可以改善通用的翻译质量问题,另外一方面也可以通过模型去满足业务上的特殊诉求。
翻译质量检测模型,需要平衡的是效果、性价比以及延迟。本文中涉及到的数据和场景尚不够全面,但本文中的研究思路和总结的经验,包括训练数据调优、不同模型效果评估以及工程最佳实践等等,对类似的工作具备一定的借鉴作用。
比较通用和重要的微调经验可以归纳为以下几点:
- 模型输出加入 COT,可以提升微调的效果。COT 序列的多样性很重要,不要让模型学习时偷懒。
- 对于特定任务,Full Finetune 一般要优于 Lora Finetune。
- 对于困难问题,其 COT 推理逻辑越循序渐进越好。尽可能的提高样本质量和数量,它是提高效果的关键性因素。
未来还存在一些优化方向可以尝试,比如在训练数据中精简 COT 的分析过程,使得模型推理时也倾向输出更短文本,从而优化延迟问题,或者尝试其他更小的模型等。
*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您了解行业前沿技术和发展海外业务选择推介该服务。
参考资料
技术博客:基于 SageMaker 和 LLaMA-Factory 打造一站式无代码模型微调部署平台
Model Hub 代码仓库:http://github.com/aws-samples/llm_model_hub
Dify-AWS-Tool 代码仓库:http://github.com/aws-samples/dify-aws-tool
系列博客
- LLM 微调实践-微调大语言模型进行翻译质检(上)
- LLM 微调实践-微调大语言模型进行翻译质检(下)