3. 误码注入概念与分类

做BERT微调,最怕什么?模型在干净数据上跑得飞起,一遇到真实世界的噪声就崩盘。误码注入就是专门对付这个问题的——说白了,就是故意往数据里“掺沙子”。

我刚开始接触这个领域的时候,总觉得这是折腾自己。好好的数据为什么要破坏?后来在一个医疗文本项目里,用户输入错别字和乱码直接导致模型预测偏移,我才意识到 — 你不主动注入误码,现实就会给你注入更大的麻烦。

3.1 什么是误码(Error)

误码,就是数据中不正确的符号、字符或词。在自然语言处理里,误码可以是一个写错的字,比如“买饭”写成“买反”;也可以是缺失的标点、多余的空格、甚至是像[UNK]这样的掩码标记。

从数学角度看,误码是原始数据与观测数据之间的差异。比如原始文本是“我今天很高兴”,经过误码注入后变成了“我今天很♂兴♀”。嘿,这种无意义替换,模型可能就懵了。

我记得有一次在电商评论模型里,用户评论“这个手机壳手感很好”被误码成“这个手‘壳’手感很好”,单引号插在中间,BPE tokenizer直接切碎了词。这就是典型的插入误码。

3.2 误码注入的目标

我们为什么要主动“破坏”数据?两个核心目标:

  • 测试鲁棒性:看模型在带噪声输入下还能不能稳定推理。比如你给BERT输入“我今天心晴不好”,它还能理解是“心情”吗?
  • 模拟真实噪声:现实中用户输入就是有错别字、网络传输可能丢包、OCR识别会漏字符。提前用类似噪声训练,模型才能在实际场景里扛得住。

我经历过一个惨痛教训:在某舆情系统里,模型对标准测试集准确率98%,上线第一天就被用户“花式输错”打回原形。从那以后,我把误码注入列为必须步骤。

3.3 误码类型

常见的误码操作有五种:替换、删除、插入、交换、掩码噪声。下面这个表总结得很直观:

类型操作示例(原句:我吃苹果)影响
替换用其他字符/词替换原字符我吃苹朵局部语义扭曲
删除随机删掉一个字符/词我吃果信息丢失
插入在随机位置插入新字符我吃苹果呀引入冗余噪声
交换相邻字符/词互换位置我吃果苹语序错误
掩码噪声用[MASK]或[UNK]隐藏原词我吃[MASK]强迫模型利用上下文

每种误码都有它的“脾气”。实际项目中,我通常按比例混合多种类型,而不是只用一种。比如文本分类任务,我倾向60%替换(模拟错字)+20%删除(模拟丢字符)+10%插入+5%交换+5%掩码。具体比例靠调参。

替换:最常用,但替换策略有讲究。纯随机替换会破坏太多语义,我建议用近音字、形近字或同义词替换——比如“苹果”→“萍果”,“高兴”→“快乐”。这样既引入噪声,又不完全偏离原意。

小经验:替换时优先替换非关键词(如形容词、助词),避免破坏实体名词。否则模型学到的可能全是噪声模式。

删除:随机删除一个或几个字符。注意删除位置——删在词首或词尾对中文影响较小,删在中间很容易造出非法。我的建议是,删除操作只作用于字符级(char-level),不要删整个wordpiece,否则BPE合并时可能出乱子。

避坑:我曾经在代码里直接用random.choice(indexes_to_delete),结果删了空格导致单词粘连,BERT tokenizer爆出一堆[UNK]。后来加了规则:删除前先检查是否是空格或标点,是的话跳过。

插入:在随机位置插入一个字符。这个操作容易产生奇怪的拼写,对中文来说,插入一个无意义的字符(如“的”)会让句子变得啰嗦,但模型通常能adapt。不过频率太高会变成垃圾。我的经验:插入概率控制在0.05以内。

交换:交换相邻的两个字符或词。中文里“吃苹果”和“果苹吃”完全是两个意思。但是交换操作对位置编码敏感的BERT是个考验——你想想看,一旦位置被打乱,自注意力就很难对齐。我曾经拿BERT做拼音纠错,发现交换误码比替换更难恢复。

掩码噪声:这是最温柔的一种。用[MASK]或[UNK]替换原词,本质上是一种数据增强,类似MLM预训练。掩码噪声不需要解码,直接让模型学会补全。如果目标任务是微调分类,掩码噪声可以提升模型对缺失信息的容忍度。

下面这张图,我把五种误码类型以及它们的目标、效果串在一起,方便你一眼看懂整个知识结构。

误码注入知识体系 误码注入 替换 删除 插入 交换 掩码噪声 目标:测试鲁棒性 / 模拟噪声 效果:局部语义扭曲 / 信息丢失 / 引入冗余 / 语序错误 / 上下文依赖

实际应用中,替换、删除这两个是最常用的(配合率约70%),其他三种作为补充。我个人建议初学者从替换和删除开始,先把鲁棒性基线拉起来,再逐步加入插入、交换、掩码。

注意:误码注入的量要控制好。我曾见过有人把所有训练数据都加10%误码,结果模型学成了“修正模式”——见到正常文本反而乱改。一般注入比例在5%~20%之间,根据任务复杂度调整。

3.4 如何选择合适的误码类型

这里没有银弹。你的选择取决于三个因素:

  1. 目标任务:文本分类、NER、QA,对误码的敏感度不同。NER对实体附近的删除和替换非常敏感。
  2. 真实场景噪声特性:如果是用户评论输入,替换居多;如果是OCR后处理,删除和插入更常见。
  3. 模型预训练方式:BERT已经在MLM中见过大量[MASK],所以掩码噪声对它影响最小。对RoBERTa来说,动态掩码让它对替换更不敏感。

我一般会先用一小批验证集,跑一遍各类型误码的评估,画个误差分析图,再决定最终混合策略。这叫“按需注入”,比盲目加噪声聪明得多。

好了,这一章概念部分就到这。记住一句话:误码注入不是破坏,而是让模型在真实世界的嘈杂中保持清醒。动手做一次,胜过读十遍理论。