ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

多模型混排的文本纠错实战:从KenLM到LLaMA的管线配置与避坑指南

多模型混排的文本纠错实战:从KenLM到LLaMA的管线配置与避坑指南 简介pycorrector 是一套开源中文文本纠错工具面向自然语言处理开发者和算法工程师用于快速解决音似字混淆、形近字误用及常见语法错误等中文文本质量问题可应用在数据清洗、问答系统预处理和语音识别后处理等场景。资源完整实现了 Kenlm、ConvSeq2Seq、BERT、MacBERT、ELECTRA、ERNIE、Transformer并进一步支持 T5、ChatGLM3、LLaMA 等模型的纠错应用各模型均在 SigHAN 数据集上完成效果评估便于横向对比不同方案的真实表现。压缩包共 192 个文件以 111 个 Python 源码文件为主体搭配 22 个 txt 数据与说明、16 个 md 文档、6 个 YAML 环境配置以及 png/jpg 网络结构图等整体约 10.95MB目录划分清晰适合直接阅读和复用。已有 445 人学习下载包内除模型训练与推理脚本外还提供容器化部署配置、项目说明、引用规范等工程化内容可帮助读者快速搭建本地纠错服务或基于现有代码开展二次开发与实验对照。1. 文本纠错的开箱即用多模型混排不是调一个接口的事把“文本纠错”做成开箱即用最容易翻车的不是模型跑不起来而是以为一个模型就能覆盖所有错误类型。标题里这一串名字——KenLM、MacBERT、T5、ChatGLM3、LLaMA——对应了纠错任务里三个不同层次统计语言模型做候选评分掩码语言模型做错字召回生成式模型做整句改写。模板拿到手、脚本能启动只是第一步真要让管线进业务得知道每个模型站在哪个环节、边界在哪以及它们对同一个字意见不一致时怎么仲裁。这篇笔记按我实际搭过并迭代过的路子来讲写给想把纠错服务真正落地、而不是停在跑通 demo 的读者。2. 原理与选型KenLM、MacBERT、T5 在纠错管线里各守哪一段2.1 一个输入样本走完纠错的完整链路文本纠错最常见的工程结构不是让多个模型排队各自输出一遍而是分成召回、过滤、改写三段。输入句子先进召回层通过规则、混淆集和掩码模型找出可疑位置并生成候选字然后过滤层用 KenLM 对每个候选句子做整体评分把自然度不达标的候选排掉过滤完还不确定的句子再交给 T5、ChatGLM3、LLaMA 这种生成式模型做整句改写。这样做的原因是成本和置信度都很受控能走规则就绝不动用大模型召回层已经把搜索空间收窄KenLM 挡住明显不通顺的句子生成式模型只处理真正棘手的歧义和长距离错误。用代码描述这条链路比画流程图更落地。我会用一个Config把每个阶段的参数集中在同一个地方这在后面做回归实验时非常有用。from dataclasses import dataclass, field dataclass class CorrectionConfig: # 召回层MacBERT mask 预测的候选个数 macbert_topk: int 10 # 召回层混淆集词典格式为“错字\t正确字” confusion_path: str confusion.txt # 过滤层KenLM 模型路径与每字平均对数概率阈值 kenlm_path: str zh_corpus.arpa kenlm_threshold: float -2.85 # 改写层允许作为 fallback 的模型按优先级排列 fallback_models: list field(default_factorylambda: [t5, chatglm3, llama]) # 生成参数 t5_max_length: int 128 glm_max_new_tokens: int 64 llama_max_new_tokens: int 64这个类本身不干活但它把后面所有调参会用到的数值固定在一处。macbert_topk决定召回层的候选宽度太大容易把无关字带进来太小又可能漏掉正确答案kenlm_threshold是过滤层松紧的开关既要挡住不通顺候选又不能把正确改法也挡掉fallback_models的排列顺序决定了成本和效果之间的取舍。把这些集中在 config 里之后每换一次语料或模型只需要改这个文件而不是钻进代码里找魔数。核心处理函数再把链路串起来def correct(sentence: str, cfg: CorrectionConfig) - str: # 第一层规则和混淆集先处理确定性错误 fixed apply_confusion_rules(sentence, cfg.confusion_path) if fixed ! sentence: return fixed # 第二层MacBERT 在可疑位置召回候选 candidates macbert_recall(sentence, cfg.macbert_topk) # 第三层KenLM 对候选句子整体打分 best kenlm_rerank(sentence, candidates, cfg.kenlm_path, cfg.kenlm_threshold) # 第四层前面都没把握时才交给生成式模型 if best is None: best generate_fallback(sentence, cfg.fallback_models, cfg) return best这里每一层的返回值都有讲究。第一层直接返回是因为混淆集里的形近字、音近字错误有相当部分是确定性的规则处理又快又零成本第二层和第三层之间是候选生成与候选淘汰的关系best is None表示 KenLM 认为所有候选都不如原句通顺这时才升级到生成式模型避免把默认正确句子改坏也避免所有请求都去打大模型。这个四层结构在线上环境里能把大模型的调用量压到总流量的 20% 以下延迟也随之降到可接受的范围。2.2 KenLMn-gram 语言模型做候选过滤与置信度KenLM 是一个很成熟的 n-gram 语言模型工具包它本身并不能发现“哪个字错了”只能对已经给定的句子打分一个句子中 n-gram 出现的概率有多高。在纠错场景里这个能力刚好用来做两件事。第一把 MacBERT 给出的 top-k 候选重新排序选出整句最通顺的那个第二对生成式模型的输出做最后一道校验如果输出句子的概率还不如输入句高大概率是模型编造了新内容应直接回退。KenLM 的训练语料可以来自业务数据比如客服对话、评论和商品标题也可以用通用中文语料先跑一个底模训练成本非常低。一个典型的加载与打分流程如下import kenlm # 加载 arpa 或二进制模型二进制格式 mmap 加载更快 model kenlm.Model(zh_corpus.arpa) def kenlm_score(sentence: str) - float: # score 返回 (log10 条件概率, oov 标记)bos/eos 统一加句首句尾 log_prob, _ model.score(sentence, bosTrue, eosTrue) # 按字数归一化避免长句被天然惩罚 return log_prob / max(len(sentence), 1) for cand in [我要去公司上班, 我要去工司上班, 我要去公司上搬]: print(cand, round(kenlm_score(cand), 4))model.score(sentence, bosTrue, eosTrue)返回两个值第一个是整句的 log10 概率第二个标记是否命中 OOV。不加bos/eos时首词和尾词会缺上下文约束在短句上很容易把明显错误的候选打出偏高分数加上之后让开头的字也必须符合语言模型分布。按字数归一化则是因为 n-gram 概率是逐词累乘的句子越长分数越低直接比较会让模型永远倾向于短候选。这里有一个高频踩坑点KenLM 的 API 在多个版本下对 OOV 的处理不一致有的版本遇到未登录词直接抛异常。所以我在线上代码里一般把它包一层 try/exceptOOV 相关的候选直接降权而不是让整个进程崩溃。def safe_kenlm_score(sentence: str, model) - float: try: log_prob, is_oov model.score(sentence, bosTrue, eosTrue) if is_oov: return float(-inf) return log_prob / max(len(sentence), 1) except Exception: # 遇到 OOV 或状态异常时不应让下游跟着崩 return float(-inf)kenlm_threshold的取值很看场景。我一般先收集 2 万句线上真实句子统计它们的平均对数概率分布取 5% 分位数作为初始阈值后面再用样例数据手动过一遍看有没有把明显正确的句子留下、把明显错误的句子放出来。阈值设太高会把纠错动作全部拦死设太低则会让 KenLM 形同虚设。这个参数没有普适值属于需要反复试的玄学区间好在线索非常明确看被拦掉的候选里有多少是正确的。2.3 MacBERT掩码语言模型做候选召回关键在混淆集与掩码策略MacBERT 在纠错里的角色是候选召回器。与生成式模型直接输出整句不同它做一个填空任务把句子里的某个字换成[MASK]然后模型根据全句语境预测这个位置最可能是哪些字。MacBERT 的预训练目标之一就是纠错型 MLM和 BERT 原版比它更贴合中文纠错场景这也是标题里出现它的原因。使用它的前提是能定位可疑位置。常见做法有两种一是用混淆集词典把“工司→公司”“合子→盒子”这类成对错误直接命中二是用字向量和编辑距离先算每个字在上下文里的预期字再找和预期字读音相近或字形相近的差异候选。在纯召回阶段直接对全句每个字依次做 mask 预测然后用 KenLM 过滤也足够处理大部分单字错误。from transformers import AutoTokenizer, AutoModelForMaskedLM import torch tokenizer AutoTokenizer.from_pretrained(chinese-macbert-base) model AutoModelForMaskedLM.from_pretrained(chinese-macbert-base) model.eval() def macbert_recall(sentence: str, target_pos: int, top_k: int 10): # 按字切分把目标位置替换成 [MASK] chars list(sentence) chars[target_pos] [MASK] masked .join(chars) inputs tokenizer(masked, return_tensorspt) with torch.no_grad(): logits model(**inputs).logits[0] # 中文 BERT 类模型会加 [CLS]目标位置在字符序列里偏移一位 mask_pos target_pos 1 probs torch.softmax(logits[mask_pos], dim-1) top_tokens torch.topk(probs, top_k) candidates [] for token_id, prob in zip(top_tokens.indices, top_tokens.values): word tokenizer.decode(token_id.item()).strip() candidates.append((word, round(prob.item(), 4))) return candidates print(macbert_recall(我要去工司上班, 3, top_k10))对整句做掩码时模型会把[MASK]处预测成“公”或“工”返回的字和置信度就是候选。mask_pos这里偏移一位是因为 tokenizer 在句首拼了一个[CLS]。中文按字切所以天然是单 token 对齐但如果你处理的句子带有英文、数字或标点字符索引和 token 索引就不一致了必须用tokenizer(..., return_offsets_mappingTrue)做偏移对齐不能照搬这个位置公式。参数设置上top_k建议 10 到 20。太低容易漏正确字太高会给 KenLM 过滤层制造大量噪声。另外一次只 mask 一个位置同时 mask 两三个位置时模型会倾向于输出互相通顺但并非错误修正的搭配这对纠错毫无用处。如果候选的置信度普遍低于 0.1说明模型对这里也没有信心这时不应该硬取 top1而应该把这条句子的路由权交给改写层。注意MacBERT 召回的是“通顺度最高”的候选不是“错误概率最高”的候选。不要把召回 top1 直接当成纠错结果输出一定要经过 KenLM 或下游改写模型确认。2.4 T5序列到序列做整句改写难点在解码限制T5 是 text-to-text 模型很适合作为改写层的低成本选项。它的定位是对召回层给出多个候选却仍有歧义的句子用整句生成的办法做一次全局改写。因为它是自回归生成能捕捉更长距离的依赖但代价是可能生成输入里没有的实体或重复片段所以解码参数必须限制住。from transformers import T5Tokenizer, T5ForConditionalGeneration import torch tokenizer T5Tokenizer.from_pretrained(your-t5-correction-model) model T5ForConditionalGeneration.from_pretrained(your-t5-correction-model) model.eval() def t5_rewrite(sentence: str, max_len: int 128) - str: prompt f纠错{sentence} inputs tokenizer(prompt, return_tensorspt, max_lengthmax_len, truncationTrue) with torch.no_grad(): output_ids model.generate( inputs.input_ids, max_lengthmax_len, num_beams4, do_sampleFalse, no_repeat_ngram_size3, early_stoppingTrue, ) return tokenizer.decode(output_ids[0], skip_special_tokensTrue)num_beams4是收益最明显的参数从贪心解码换成 4 条 beam纠错准确率在我自己的测试集上能提高 1 到 2 个点再往上加 beam收益就开始递减。no_repeat_ngram_size3用来禁止同一个三连字重复出现中文生成模型在长句上很容易把“的的的”这类片段循环出来。early_stoppingTrue配合 beam search让模型在生成完最后一个 token 后及时收住避免无意义延长。T5 作为改写层还有一个容易被忽视的用法如果线上只有 CPU 或小显存可以用它替代 ChatGLM3 和 LLaMA 做默认改写只有 T5 的输出被 KenLM 判定为不如原句时才继续升级到大模型。这样既能保住绝大多数简单错字的修改质量又不会让整条管线的推理成本被大模型拖垮。3. 把 ChatGLM3 和 LLaMA 接进纠错场景指令模板与生成控制3.1 ChatGLM3 的指令式纠错系统提示、少样本和输出解析ChatGLM3 这一类对话式模型接入纠错场景最自然的方式不是直接让它翻译而是给它一段带指令和示例的 prompt让它只输出纠错后的句子。这类模型的优势在于能处理“多字、少字、语序错乱”这类掩码模型和 T5 都难处理的整体性问题例如“我到昨天才知到”这种需要语感才能改对的句子。关键在 prompt 设计。我的做法是固定一套系统提示再加三条和业务数据同分布的 few-shot 示例最后才放真实输入。from transformers import AutoTokenizer, AutoModel import torch tokenizer AutoTokenizer.from_pretrained(path/to/chatglm3, trust_remote_codeTrue) model AutoModel.from_pretrained(path/to/chatglm3, trust_remote_codeTrue, device_mapauto).eval() GLM_PROMPT 你是一个中文文本纠错助手。只输出纠错后的句子不解释、不输出其他内容。 输入我要去工司上班 输出我要去公司上班 输入我今天心晴很好 输出我今天心情很好 输入昨天买了个便当河 输出昨天买了个便当盒 输入{user_input} 输出 def correct_with_glm(user_input: str) - str: prompt GLM_PROMPT.format(user_inputuser_input) inputs tokenizer(prompt, return_tensorspt).to(model.device) with torch.no_grad(): outputs model.generate( **inputs, max_new_tokens64, do_sampleFalse, temperature0.2, ) # 截掉 prompt 部分只保留模型新生成的内容 response tokenizer.decode( outputs[0][inputs.input_ids.shape[1]:], skip_special_tokensTrue ) return response.strip()do_sampleFalse表示走贪心解码配合temperature0.2并不冲突——部分模型实现里即使关掉采样温度也会影响 logits 的软度这里把温度调低的目的是让输出更保守。max_new_tokens64对纠错场景够用中文纠错一般只需要改动几个字给太大会让模型有机会输出一段解释性文字。few-shot 示例要跟你业务里的句子长度和错误类型接近如果业务是短标题、示例却全是长句模型会学到错误的输出风格。输出解析是所有对话式模型接入时最容易翻车的一环。模型偶尔会在“输出”后面追加一句“我把工司改成了公司”如果直接把返回字符串作为结果下游拿到的就是垃圾。我会在解析阶段做两层过滤先按行切分取最后一行再用正则去掉“输出”“纠错后”这类前缀。3.2 LLaMA 在中文纠错上的接法与后处理LLaMA 系列模型在中文场景下的表现不如它在英文上那么顺手尤其小尺寸版本。但这不代表不能用而是要给它更明确的指令、更严格的输出格式约束以及更彻底的后处理。实际接入时我会把它作为管线的最后一环并且只在前面所有模型都失效时才调用。调用方式不再是“对话式”而是“指令式续写”。这类模型的 tokenizer 对中文的支持取决于词表部分版本会出现一个字被切成多个 token 的情况导致生成结果里出现英文空格或乱码。from transformers import AutoModelForCausalLM, AutoTokenizer tokenizer AutoTokenizer.from_pretrained(path/to/llama-local) model AutoModelForCausalLM.from_pretrained( path/to/llama-local, torch_dtypeauto, device_mapauto, ) def correct_with_llama(user_input: str) - str: prompt ( Rewrite the following Chinese sentence to fix typos. Return only the corrected sentence, no explanation.\n fInput: {user_input}\nOutput: ) inputs tokenizer(prompt, return_tensorspt).to(model.device) outputs model.generate( **inputs, max_new_tokens64, temperature0.1, top_p0.9, repetition_penalty1.2, ) raw tokenizer.decode( outputs[0][inputs.input_ids.shape[1]:], skip_special_tokensTrue ) # 只取第一行去掉换行后残余文本 return raw.strip().splitlines()[0] if raw.strip() else user_input参数上temperature0.1和top_p0.9的组合基本锁死了随机性因为纠错任务要的是确定性输出不是创意。repetition_penalty1.2对中文生成很管用LLaMA 在长句上容易把刚才生成过的字再重复一遍这个参数会抑制重复。后处理比模型本身更重要。我见过最多的情况是模型输出了“输入…… 输出……”这种完整模板或者句子里混入了一个英文冒号。解决办法是取第一行、丢掉所有包含“输入”或“Output”的行、最后和原句做一次字符级 diff如果没有差异就不改动。LLaMA 不适合做第一层召回因为它的幻觉概率在开放生成里不可控但它作为兜底改写对“语义通顺但用词错误”的句子往往能给出其他模型给不出的改法。3.3 本地推理资源参数量化、batch 与长度控制同时挂载 MacBERT、T5、ChatGLM3、LLaMA 四个模型最现实的问题是显存和内存。我一般把模型分成两档常驻档和按需加载档。MacBERT 和 T5 体量小常驻没问题ChatGLM3 和 LLaMA 则建议按路由结果动态加载或者只保留其中一个。如果两台模型都要常驻量化是必须做的。常见做法是用 int8 或 4bit 加载生成式模型。ChatGLM3 在 4bit 下显存占用能从 12GB 左右降到 6GB 上下LLaMA 7B 也是类似的量级。代价是输出质量会略有下降在纠错这种对字词精确度要求高的任务里建议只量化注意力层的部分参数或者用 int8 而不是 4bit。批量推理时动态 padding 到 batch 内最长句比固定 padding 到 128 能省出三分之一显存但要注意 mask 和 attention 的配合。max_new_tokens是延迟的隐形杀手。很多模型默认允许生成 256 个 token但纠错输出往往只有几十个 token。把它压到 64 甚至 32单次请求延迟能下降一大截。我习惯在路由逻辑里先看原句长度短句用 32超过 50 字的句子才升到 64这样绝大多数请求都在低延迟区间结束。4. 开箱即用的避坑清单五类高频翻车现象4.1 现象一KenLM 对长句候选永远打出更低分导致长句拒改现象输入 30 字以上的句子时无论如何纠错KenLM 都判定候选不如原句管线永远不动作。原因score返回的是全句累积 log 概率字越多累积数值越小。直接拿整句分数比较长句天然吃亏。我在第一次接入时也栽在这里写出来的逻辑对短句有效对长句全部放行原句。解决按字数归一化用每字平均对数概率替代整句分数。更稳一点的做法是先过滤掉长度超过 100 字的输入强制走生成式模型不让 KenLM 对超长句做裁决。4.2 现象二MacBERT 召回的候选全是原词现象把“工司”改成[MASK]MacBERT 返回的前 10 个候选里原字排第一且置信度超过 0.8没有出现“公”。原因模型学到的分布里通顺原句的概率最高。尤其当句子里没有明显的语法异常时MLM 倾向于保持原字这在短句中非常明显。解决把召回候选和原字做字符级比对如果候选中没有原字就额外把原字加进候选集同时过滤掉那些置信度低于原字置信度的候选因为这些改法大概率会把句子改坏。更主动的方案是从混淆集里把形近字、音近字的候选直接注入不依赖 MLM 自己能不能想到。4.3 现象三T5 输出和输入一模一样现象T5 生成结果等于原句但句中确实存在“合子”这类明显错字。原因两种情况。一是该 checkpoint 在纠错语料上训练不足模型学到的映射是恒等映射二是 prompt 格式和训练时不一致比如训练用的是纠错句子推理时却直接塞句子。解决先按训练时的输入格式构造 prompt别自创前缀如果仍然恒等输出就检查训练数据里“原句和纠错句相同”的负样本占比。负样本占太少时模型会偏向不改动我一般把负样本比例控制在 20% 到 30% 之间。4.4 现象四ChatGLM3 输出停在解释性文字上现象返回结果是“原句中‘工司’应为‘公司’。今天的天气很好。”这类带说明、带断句的长文本。原因few-shot 示例太少或者示例里没有覆盖“只输出结果”的约束。模型把纠错当成对话任务想着把推理过程说出来。解决prompt 里把约束句提到最前面用“只输出纠错后的句子不解释、不输出其他内容”这种复合祈使句few-shot 加到 3 到 5 条解析时丢弃所有包含“应”或“应为”的片段。如果模型风格实在太啰嗦可以直接放弃对话式 API改用纯续写模式强制让它从“输出”后面开始生成。4.5 现象五LLaMA 在中文上输出乱码或英文现象输出里有大量、英文单词或拼音句子完全不可用。原因中文 tokenizer 词表覆盖不足或输入 prompt 里中英文混杂导致模型切换到英文续写模式。一些小尺寸 LLaMA 版本对中文的支持确实很差这不是参数能解决的。解决先检查 tokenizer 词表里中文字符的覆盖度偏低就直接换模型。如果必须用当前模型把 prompt 全部改成中文避免英文指令生成后如果检测到非法字符回退到上一层级模型的输出。我的经验是LLaMA 在中文纠错上的可用性低于 ChatGLM3除非你已经基于中文语料做过增量预训练否则别把它放在主链路上。5. 参数与调度让四条模型路径协同工作的配置参考5.1 纠错管线中的关键参数集阈值、top_k、beam 与 temperature这一节把前面提到的参数汇总成一个可以直接抄作业的参考表参数值是我在通用场景下的初始值不是最终值。每个参数都要结合自己的评测集调整但至少能让你拿到一套能跑、不会明显改坏句子的起点。参数作用推荐初始值调整方向macbert_topk召回层候选个数10漏召回时调大到 20噪声多时调小到 5kenlm_threshold每字平均对数概率下限-2.85用 5% 分位数初始化再人工过样例t5 num_beamsT5 解码宽度4效果不足时试 6延迟超标时回 2t5 no_repeat_ngram_size重复片段抑制3长句重复严重时调到 2glm temperatureChatGLM3 输出随机性0.2输出不稳定时降到 0.1glm max_new_tokensChatGLM3 生成长度64短句压到 32长句放宽到 128llama repetition_penaltyLLaMA 重复惩罚1.2出现重复时调到 1.3过高会丢错字这些参数之间的联动比单个参数更重要。macbert_topk变大的时候KenLM 阈值要适当收紧否则更多噪声候选会挤进重排T5 的 beam 调大之后no_repeat_ngram_size也要同步收小否则 beam 之间会共享重复片段。我通常每改一个参数就跑一遍 mini 评测集而不是一口气调三四个参数否则出了问题很难定位责任方。5.2 串行还是并行按延迟预算选择调用策略如果四个模型全串行一次纠错要经历 MacBERT 推理、KenLM 打分、T5 生成、ChatGLM3 或 LLaMA 生成总延迟轻松突破 3 到 5 秒多数业务承受不了。我的做法是把管线切成两组快速组和重写组。快速组包含混淆集规则、MacBERT 和 KenLM只做局部修改p95 延迟可以控制在 200ms 以内。重写组包含 T5、ChatGLM3、LLaMA只在快速组判定“不确定”时才触发。这样大多数简单错字都在快速组内解决重写组只承担 10% 到 20% 的流量。如果重写组内部还要多级 fallback我建议先并行跑 T5 和 ChatGLM3取 KenLM 分数更高的输出而不是串行等完 T5 再等 ChatGLM3。并行调用会成倍增加显存压力所以实际落地时我会给重写组设一个信号量限制最大并发请求数。超出的请求直接返回快速组的结果不让用户一直等着大模型出结果。5.3 微调的边界“开箱即用”到什么时候要重新训练标题里的“开箱即用”指的是工程上拿来能跑不代表模型权重不用动。业务数据和你测试时的公开数据集分布差异大效果下降是必然的。我的判断标准很简单如果 mini 评测集上精确率低于 85%先不急着调参大概率是数据分布问题要采集业务语料做增量训练。MacBERT 和 T5 的微调成本低值得优先做。MacBERT 用掩码预测任务继续训练 1 到 2 个 epochT5 用“错误句-正确句”平行数据做序列到序列训练。ChatGLM3 和 LLaMA 在纠错任务上一般不做全量微调成本太高优先靠 prompt 工程解决只有当你积累了几万条高质量纠错数据、且 prompt 怎么调都压不住幻觉时才考虑 LoRA。记住微调不是万能的如果错误类型主要是混淆集能覆盖的错别字把混淆集加大比重新训练 T5 更划算。6. 用你自己的 mini 评测集做回归闭环6.1 200 条手工标注样本错误类型标清楚比数量重要别信模型在演示样例上的表现那些句子多半是作者反复挑过的。我会自己建一个 200 条左右的评测集每条包含“原句、正确句、错误类型”错误类型分三档错别字、多字少字、语义不通。数量不用多但每一类都要有而且要把容易误伤的近义词也放进去比如“做”和“作”这类模型容易改错的。6.2 三个数字精确率、召回率、过纠率评测时我看三个数字。精确率是“改动过的句子中有多少改对了”召回率是“应该改的句子中有多少改了”过纠率是“不该改的句子中有多少被改了”。精确率低于 90% 时别上线过纠率高于 5% 要优先处理因为用户对一个本来正确的句子被改坏的容忍度极低。6.3 参数快照把每次实验变成可回滚的一条记录每次调参我把 config 连同评测集结果存成一个 json 文件文件名带日期和 hash。这样下次发现线上效果变差可以直接回滚到任意历史版本不用靠记忆猜当时用了什么参数。有一回我把macbert_topk从 10 调到 20精确率掉了三个点原因还不是召回本身变差而是 KenLM 被更多噪声候选带偏。如果没有参数快照这种问题根本无从查起。这个习惯后来救了我好几次。模型管线越复杂越要在早期就把回归闭环建立起来而不是等项目快上线了才去补。希望帮到你。本文还有配套的精品资源点击获取
返回列表