赞
踩
本文在上文不要停止预训练实战-Roberta与Albert的基础上,进一步完成以下内容:
BERT等预训练模型中掩码任务主要涉及下列要素:
常用掩码比例设置为15%,该比例经过许多研究,已证明该比例能够取得很好的效果。
从理论上来说,笔者从网上找到的说法为:“当取15%时,恰好大概7个词mask一个,正好就是CBOW中,长度为7的滑动窗口的中心词,因此会有比较好的效果”
而近日丹琦大佬等人的论文Should You Mask 15% in Masked Language Modeling?表明掩码40%能够取得与15%差不多的效果。
该论文表明**“所谓的optimal masking rate并不是一个一成不变的神奇数字,而是一个随着模型大小、mask策略、训练recipe、下游任务变化的函数。”**
常用的替换策略如下:
这样做的目的在于强迫模型学习词语上下文的语义信息。任何一个词语都有可能被替换,不仅靠当前词语,还需要利用上下文的信息预测当前词语。
但是[MASK]标签并未出现在下游任务中,因此存在预训练与微调的不一致问题。
MacBERT提出MLM as correction的方法,替换策略如下:
MacBERT论文中与下列替换策略进行对比,对比结果如图所示:
图中横坐标代表训练步数,纵坐标代表EM值。第一幅图是CMRC数据集结果,第二幅图是DRCD数据集结果。
目前的掩码方式主要分为以下几种:
中文 | 英文 | |
---|---|---|
原句 | 使用语言模型来预测下一个词的概率。 | we use a language model to predict the probability of the next word. |
分词 | 使用 语言 模型 来 预测 下 一个 词 的 概率 。 | - |
BERT Tokenizer | 使 用 语 言 模 型 来 预 测 下 一 个 词 的 概 率 。 | we use a language model to pre ##di ##ct the pro ##ba ##bility of the next word. |
单词掩码 | 使 用 语 言 [M] 型 来 [M] 测 下 一 个 词 的 概 率 。 | we use a language [M] to [M] ##di ##ct the pro [M] ##bility of the next word. |
全词掩码 | 使 用 语 言 [M] [M] 来 [M] [M] 下 一 个 词 的 概 率 。 | we use a language [M] to [M] [M] [M] the [M] [M] [M] of the next word. |
实体掩码 | 使 用 [M] [M] [M] [M] 来 [M] [M] 下 一 个 词 的 概 率 。 | we use a [M] [M] to [M] [M] [M] the [M] [M] [M] of the next word. |
N-gram掩码 | 使 用 [M] [M] [M] [M] 来 [M] [M] 下 一 个 词 的 概 率 。 | we use a [M] [M] to [M] [M] [M] the [M] [M] [M] [M] [M] next word. |
Span掩码 | 使 用 [M] [M] [M] [M] [M] [M] [M] 下 一 个 词 的 概 率 。 | we use a [M] [M] [M] [M] [M] [M] the [M] [M] [M] [M] [M] next word. |
MAC掩码 | 使 用 语 法 建 模 来 预 见 下 一 个 词 的 几 率 。 | we use a text system to ca ##lc ##ulate the po ##si ##bility of the next word. |
以分词结果为最小粒度,完成掩码任务。
同样以分词结果为最小粒度,以n-gram取词语进行掩码。
例如MacBERT采用基于分词的n-gram masking,1-gram~4gram Masking的概率分别是40%、30%、20%、10%。
代表模型为:ERNIE
引入命名实体信息,将实体作为最小粒度,进行掩码。
代表模型为:SpanBERT
以上做法让人认为,或许必须得引入类似词边界信息才能帮助训练。但前不久的 MASS 模型,却表明可能并不需要,随机遮盖可能效果也很好,于是就有SpanBERT的 idea:
根据几何分布,先随机选择一段(span)的长度,之后再根据均匀分布随机选择这一段的起始位置,最后按照长度遮盖。文中使用几何分布取 p=0.2,最大长度只能是 10,利用此方案获得平均采样长度分布。
相关代码实现可见:https://github.com/447428054/Pretrain/tree/master/KerasExample/pretraining
Span掩码核心代码如下:
def __init__( self, tokenizer, word_segment, lower=1, upper=10, p=0.3, mask_rate=0.15, sequence_length=512 ): """参数说明: tokenizer必须是bert4keras自带的tokenizer类; word_segment是任意分词函数。 """ super(TrainingDatasetRoBERTa, self).__init__(tokenizer, sequence_length) self.word_segment = word_segment self.mask_rate = mask_rate self.lower = lower self.upper = upper self.p = p self.lens = list(range(self.lower, self.upper + 1)) self.len_distrib = [self.p * (1-self.p)**(i - self.lower) for i in range(self.lower, self.upper + 1)] if self.p >= 0 else None self.len_distrib = [x / (sum(self.len_distrib)) for x in self.len_distrib] print(self.len_distrib, self.lens) def sentence_process(self, text): """单个文本的处理函数 流程:分词,然后转id,按照mask_rate构建全词mask的序列 来指定哪些token是否要被mask """ word_tokens = self.tokenizer.tokenize(text=text)[1:-1] word_token_ids = self.tokenizer.tokens_to_ids(word_tokens) sent_length = len(word_tokens) mask_num = math.ceil(sent_length * self.mask_rate) mask = set() spans = [] while len(mask) < mask_num: span_len = np.random.choice(self.lens, p=self.len_distrib) # 随机选择span长度 anchor = np.random.choice(sent_length) if anchor in mask: # 随机生成起点 continue left1 = anchor spans.append([left1, left1]) right1 = min(anchor + span_len, sent_length) for i in range(left1, right1): if len(mask) >= mask_num: break mask.add(i) spans[-1][-1] = i spans = merge_intervals(spans) word_mask_ids = [0] * len(word_tokens) for (st, ed) in spans: for idx in range(st, ed + 1): wid = word_token_ids[idx] word_mask_ids[idx] = self.token_process(wid) + 1 return [word_token_ids, word_mask_ids]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。