Transformer 中 Mask 的那些事

文章探讨了Transformer结构中的Mask机制,从BERT的随机遮蔽单个字到ERNIE的PhraseMask和EntityMask,再到RoBERTa的动态遮蔽和MacBERT的全词与N-gram遮蔽及同义词替换。研究表明,不同的遮蔽策略对模型的预训练和微调性能有显著影响,例如,40%的遮蔽率可能优于传统的15%,且只使用[MASK]进行预训练可能更为有效。

Mask 的灵感是来自于完形填空。Transformer 结构包括编码器和解码器,在编码过程中目的就是为了让模型看到当前位置前后的信息,所以不需要 attention mask。但是在解码过程中为了模拟在真实的 inference 场景中,当前位置看不到下一位置,且同时需要上一位置的信息,所以在训练的时候加了attention mask。能很有效提升泛化性。

对于原始的 BERT,训练时,会随机选取整句中的最小输入单元 token 来进行遮盖。因为用到 Byte Pair Encoding (BPE)技术,所以也可以把这些最小单元当作是子词(subword),比如说superman,分成 super+man 两个子词。

BERT 模型在训练时使用了两个预训练任务:Masked LM 和 Next Sentence Prediction。BERT Mask 过程中会把 15% 的字遮挡起来,然后让模型预测被遮挡的字。BERT 会把每个字单独处理,即 Mask 时不考虑词组信息,例如句子 "静夜思的作者是李白",BERT 有可能会 Mask 得到 "静夜思的作者是[Mask]白"。

这种方式可能会有点问题,[MASK] token在微调阶段从未出现,这会造成预训练任务与下游微调任务不一致。

后来 Bert 进一步提出了一种称为全字 mask(wwm) 的技术,用于优化 MLM 任务中的原始 mask。 在这种设置下,不会随机选择要 mask 的 WordPiece token(Wu 等,2016),而是总是同时 mask 与全词相对应的所有 token。 这将明确迫使模型在MLM 预训练任务中恢复全词,而不仅仅是恢复 WordPiece token(Cui等人,2019a)。

轮文《ERNIE: Enhanced Representation through Knowledge Integration》。ERINE 的作者认为 BERT 遮挡单个字的方式通常会忽略句子中的先验知识,例如对于句子 "哈利波特的作者是 J.K.罗琳",如果模型遮挡了 "哈利波特" 中的随机一个字,则模型不需要利用句子的知识就很容易预测出 "哈利波特"。但是如果将 "哈利波特" 整个实体遮挡起来, BERT 就不能正确预测了,说明 BERT 不能很好地利用整个句子的知识。

ERINE 提出了一种新策略,称为 Knowledge Mask。主要包括 Phrase Mask (短语) 和 Entity Mask (实体),可以由多个字组成。通过对句子中的一些词组进行遮挡并预测整个词组,可以让 ERNIE 更好地捕获词组、实体之间的关系。下图显示了 BERT 和 ERNIE Mask 策略的区别。

RoBERTa 采用原始 BERT 架构,但进行更精确的修改以显示 BERT 的特征,这一点被低估了。 他们对 BERT 的各个组成部分进行了仔细的比较,包括 mask 策略,训练步骤等。经过全面评估,他们得出了使 BERT 更加强大的几个有用结论,其中包括动态mask。

RoBERTa 中将原始数据复制 n 份,每份都进行随机的静态 mask,从而每份数据的mask 结果都不太一样。huggingface 中 data allcator 使用的是动态 mask,但不是复制数据,而是每一个 epoch 的 mask 策略都不同,这样就可以达到动态 mask 的效果了,从而使得每一个 epoch 的 mask 的情况都不同。

MacBert 提出了一种有趣的 Mask:

  • 我们使用全词 masked 以及 Ngram masked 策略来选择候选 token 来 masked,单词级别的 unigram 到 4-gram 的比例为 40%,30%,20%,10%。
  • 提议不使用 [MASK]token 进行 mask,因为在 token 微调阶段从未出现过[MASK],我们提议使用类似的单词进行 mask。 通过使用基于word2vec(Mikolov et al。,2013) 相似度计算的同义词工具包 (Wang and Hu,2017) 获得相似的单词。 如果选择一个 N-gram 进行 mask,我们将分别找到相似的单词。 在极少数情况下,当没有相似的单词时,我们会降级以使用随机单词替换。
  • 我们对 15% 比例的输入单词进行 mask,其中 80% 替换为相似的单词,10% 将替换为随机单词,其余 10% 则保留原始单词。

在消融实验上,其实也是证明了有效性。总体平均得分是通过平均每个任务的测试得分获得的( EM 和 F1 指标在总体平均之前进行平均)。从总体上看,删除 MacBERT 中的任何组件都将导致平均性能下降,这表明所有修改都有助于总体改进。具体来说,最有效的修改是 N-gram mask 和相似的单词替换,这是对 mask 的语言模型任务的修改。当我们比较 N-gram mask 和相似的单词替换时,我们可以看到明显的优缺点,其中 N-gram mask 在文本分类任务中似乎更有效,而阅读理解任务的性能似乎从相似的单词中受益更多。通过将这两个任务结合起来,可以互相补偿,并且在两种类型上都有更好的表现。

在《Should You Mask 15% in Masked Language Modeling?》提了个新观点。以往遮蔽预训练模型中,遮蔽语言模型通常使用 15% 的遮蔽率,作者团队认为更多的遮蔽将提供足够的上下文来学习良好的表示,而更少的遮蔽会使训练过于昂贵。令人惊讶的是,我们发现 40% 的遮蔽概率的输入序列可以优于 15% 的基线,通过对下游任务的微调来衡量可以发现,甚至遮蔽 80% 的字符也可以保留大部分性能。

我们可以发现与默认的 15% 遮蔽模型相比,高达 50% 的遮蔽可以达到相当甚至更好的结果。 遮蔽 40% 总体上实现了最佳的下游任务性能(尽管不同下游任务的最佳掩蔽率有所不同)。 结果表明语言模型预训练不必使用小于 15% 的掩码率,而使用高效预训练侧率的大型模型的最佳掩码率高达 40%。

这篇论文中其实是有反驳 MacBert 使用的 80-10-10 方法。

2019 年以来,大多数认为用将原始 token 10% 替换(保持单词不变),用随机token 替换 10% 是有益的。从那时起,在过往预训练模型研究中,80-10-10 规则在几乎所有的 MLM 预训练工作中被广泛采用。其动机是遮蔽标记在训练前和下游微调之间造成不匹配,使用原始或随机的标记作为 [MASK] 的替代方法可以缓解这种差距。基于这一推理,理应认为屏蔽更多的上下文应该会进一步增加差异,但作者在下游任务中观察到更强的性能。这就引出了是否完全需要 80-10-10 法则的疑虑。

根据实验结果,我们观察到,相同的字符预测和随机字符损坏会降低大多数下游任务的性能。“80-10-10” 规则比简单地使用 [MASK] 的所有任务效果更差。这表明,在微调范式中,[MASK] 模型可以快速适应完整的、未损坏的句子,而不需要随机替换。鉴于实验结果,作者建议只使用 [MASK] 来做预训练。

### Transformer 模型中的 Mask 机制 在 Transformer 模型中,Mask 机制用于处理特定类型的输入数据,确保模型不会泄露未来的信息给当前时间步。这种机制对于解码器部分尤为重要,在训练过程中防止模型查看未来的 token。 #### 解码器中的掩码操作 为了实现这一点,引入了 **Self-Attention with Masking** 的概念。具体来说,在计算 Query 和 Key 的点积之后、Softmax 函数之前会加上一个非常大的负数(通常为 `-inf`),使得这些位置的概率接近于零[^1]。这一步骤可以阻止某些不必要的连接,特别是当目标是预测下一个词时,不允许访问后续词语的信息。 ```python import torch import math def create_mask(size, pad_token=0): # 创建下三角矩阵作为mask mask = (torch.triu(torch.ones((size, size))) == 0).transpose(0, 1) mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0)) return mask # 示例:创建大小为5的mask print(create_mask(5)) ``` 此外,还有一个重要的方面是在处理填充(Padding)的时候也需要做相应的遮蔽工作。因为批次内的句子长度不一致,较短的句子会被补全至最大句长,而这些额外添加的部分应当被忽略掉。因此还需要构建 padding masks 来屏蔽掉那些非有效的位置[^3]。 ```python def create_padding_mask(seq): seq = (seq != 0).unsqueeze(-2) # 假设pad_token为0 batch_size, seq_len = seq.size() mask = seq.expand(batch_size, seq_len, seq_len) return mask # 示例:假设有一个batch内有两个句子分别为[1,2,3,0],[4,5,6,7],其中0代表padding input_seq = torch.tensor([[1, 2, 3, 0], [4, 5, 6, 7]]) print(create_padding_mask(input_seq)) ``` 通过上述两种方法共同作用,可以在保持序列间依赖的同时有效地控制信息流的方向性和范围,这对于提高模型性能至关重要[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值