本次分享的论文ChineseBERT来自于ACL 2021会议,论文全名为ChineseBERT: Chinese Pretraining Enhanced by Glyph and Pinyin Information,即融合字形与拼音信息的中文预训练模型。
论文地址:https://aclanthology.org/2021.acl-long.161/
代码地址:https://github.com/ShannonAI/ChineseBert
目前,预训练语言模型在自然语言处理领域取得了显著地效果。但是由于BERT等预训练模式最初为英文设计,对于中文来说,汉语是一种符号语言,字符的符号包含一些额外的语义信息,因此,原始的预训练语言模型的形式缺失了字形信息和拼音信息两个重要的信息。
字形背后蕴含着丰富的语义,可以增强汉语自然语言模型的表现力。例如,“液”、“河”和“湖”都有“氵”,表示这些字符都与“水”的语义相关。
拼音,一个汉字的罗马化序列表示其发音,在建模语义和语法信息是至关重要的,同样的汉字在不同的读音下,有着不同的涵义。例如:“乐”字,读“yuè”时表示音乐,读“lè” 时表示快乐。
该论文将字形和拼音信息融入到预训练语言模型中,在中文多个领域(机器阅读理解、自然语言推理、文本分类、句对匹配、命名实体识别和分词任务上)都达到了SOTA。
下面主要针对ChineseBERT模型的模型结构、预训练设置以及结果分析进行详细介绍。
模型整体结构,如图1所示。模型将字符嵌入(char embedding)、字形嵌入(glyph embedding)和拼音嵌入(pinyin embedding)进行拼接起来;然后通过融合层,得到一个d维融合嵌入(fusionembedding);最后将其与位置嵌入(position embedding)、片段嵌入(segment embedding)相加,形成Transformer-Encoder层的输入。
由于预训练时没有使用NSP任务,因此模型结构图省略了片段嵌入(segment embedding)。实际上下游任务输入为多个段落时(例如:文本匹配、阅读理解等任务),是采用了segment embedding的,详细见:fusion_embedding.py文件的34行。
Char Embedding
字符嵌入与原始BERT模型中的token embedding一致,仅在字符粒度上进行embedding。
Glyph Embedding
字形嵌入如图2所示,采用三种中文字体(仿宋、行楷和隶书),分别将每个汉字进行24 × 24的图形向量化,然后将其拼接后拉平成2352维向量,送入一个全连接层,最终获取某个字的字形嵌入。
Pinyin Embedding
拼音嵌入如图3所示,首先使用开源的pypinyin包为输入字符序列转换成拼音序列,其中每个字符的拼音序列由罗马字符和四种音调组成,使用特殊标记来表示音调,音调被附加到罗马字符序列的末尾。然后在拼音序列进行embedding,并使用宽度为2的CNN模型进行卷积,最后使用最大池获取到拼音嵌入。
Data
数据来自CommonCrawl,见https://commoncrawl.org/。预训练ChineseBERT的数据规模为约4B。并在全词掩码时使用LTP工具进行词语识别。
Masking Strategies
在ChineseBERT模型中,使用全词掩码(Whole WordMasking,WWM)和字符掩码(Char Masking,CM)两种策略。
字符掩码,即对单独的字符进行MASK;全词掩码,即对一个词语中所有的字符进行MASK。
Pretraining Details
ChineseBERT模型与原始BERT模型结构不同,因此,没有加载原始模型的参数,而是从头进行预训练的。为了解决长短依赖的问题,在训练过程中,采用packed input和single input交替训练,比例为9:1,其中single input为一个单句,packed input由总长度不超过512字符的多个单句拼接而成。并且90%的概率进行全字掩码,10%的概率进行字符掩码。词语或字符的mask概率为15%,80%的概率将mask的字符使用[MASK]替换,10%的概率将mask的字符使用随机字符替换,10%的概率将mask的字符保持不变。采用了动态掩码策略来避免数据的重复训练。
Base与Large模型的层数与原始BERT一致,分别是12层和24层,输入维度和头数分别为768/12和1024/16。Base模型训练了500K步,学习率为1e-4,warmup步数为20k,batch大小为3.2K。Base模型训练280K步,学习率为3e-4,warmup步数为90k,batch大小为8K。
Github中给了详细的代码,还是满良心的,可以直接调用,具体如下:
from datasets.bert_dataset import BertDataset
from models.modeling_glycebert import GlyceBertModel
bert_path = ""
tokenizer = BertDataset(bert_path)
chinese_bert = GlyceBertModel.from_pretrained(bert_path)
sentence = '我喜欢猫'
input_ids, pinyin_ids = tokenizer.tokenize_sentence(sentence)
print("input_ids:", input_ids)
print("pinyin_ids:", pinyin_ids)
length = input_ids.shape[0]
input_ids = input_ids.view(1, length)
pinyin_ids = pinyin_ids.view(1, length, 8)
output_hidden = chinese_bert.forward(input_ids, pinyin_ids)[0]
print("output_hidden:", output_hidden)
总结:
在预训练时候,该论文丢弃了SOP或NSP任务,有一些疑惑,在实验中也没有提到;并且模型是从头训练也比较奇怪,虽然说embedding层不一样,但是transformer-encoder层的参数还是可以用的吧!!!
不过增加字形和拼音特征的思路还是蛮正的,并且评测数据均为中文数据。
以后做模型融合时,又多了一个和而不同的模型,哈哈哈~~~~