首页 > 其他分享 >【论文解读】(拼音+字形+字三种信息的中文BERT)ChineseBERT: Chinese Pretraining Enhanced by Glyph and Pinyin Information

【论文解读】(拼音+字形+字三种信息的中文BERT)ChineseBERT: Chinese Pretraining Enhanced by Glyph and Pinyin Information

时间:2023-05-08 16:39:35浏览次数:63  
标签:BERT Chinese Information pinyin self length embedding font size


文章目录

  • 1. 相关信息
  • 2. 论文内容
  • 3. 论文模型
  • 3.1 Glyph Embedding
  • 3.2 Pinyin Embedding
  • 4. 实验与结论
  • 5. 模型使用方式

1. 相关信息

论文年份:2021

论文地址:https://aclanthology.org/2021.acl-long.161.pdf

论文代码(官方) : https://github.com/ShannonAI/ChineseBert

Hugging Face: ShannonAI/ChineseBERT-base (560M+), ShannonAI/ChineseBERT-large (1.4G)

处理好后代码(自己处理的,详情参考最后章节模型使用方式):ChineseBert(百度网盘)

纯模型链接:

2. 论文内容

论文思路和背景:目前中文BERT的做法和英文BERT一样,都是使用MLM任务和NSP任务进行训练的。但是,中文和英文不同,中文的拼音和字形也能为句子和词的语义提供信息。目前传统的做法忽略了这两个重要信息。所以作者就针对这一点,对BERT进行了改进,增加了这两种信息。

论文内容:

3. 论文模型

【论文解读】(拼音+字形+字三种信息的中文BERT)ChineseBERT: Chinese Pretraining Enhanced by Glyph and Pinyin Information_Glyph

论文模型和传统的BERT一样,只是增加了字形编码(Glyph embedding)和拼音编码(Pinyin embedding)。

模型描述:首先,将每个token获取其"char embedding"、“glyph embedding”和"pinyin embedding"。然后将其Concat到一起,然后通过一个Fusion Layer(全连接层)将三种embedding进行融合。 之后就和普通BERT一样,增加position embedding,然后经过多层Transformer。最终得到每个token的hidden state。

fusion层核心代码如下:

# init
self.map_fc = nn.Linear(config.hidden_size * 3, config.hidden_size)

# forward
concat_embeddings = torch.cat((word_embeddings, pinyin_embeddings, glyph_embeddings), 2)
inputs_embeds = self.map_fc(concat_embeddings)

3.1 Glyph Embedding

对于字形编码(Glyph Embedding)的获取如下图所示:

【论文解读】(拼音+字形+字三种信息的中文BERT)ChineseBERT: Chinese Pretraining Enhanced by Glyph and Pinyin Information_卷积_02

作者使用的是一个字的三种书写方式的24x24的灰度图像作为输入图片,然后将其concat后送入全连接层进行特征提取,最终得到该字的Glyph Embedding。

例如上例中的字,将经历如下步骤:

  1. 字分别用“仿宋”、“行楷”和“隶书”三种方式绘制成24x24的灰度图片。最终得到一个24x24x3的tensor
  2. 然后将其进行flatten操作,得到一个1728(24243)的tensor。(在论文中作者说是2352,应该是写错了)
  3. 最后将其通过一个全连接层进行特征提取。

作者对于字形的提取并没有使用卷积网络,可能是因为图片并不大,所以没必要。

虽然上面这么说,但作者的源码实现略有不同,但本质是一样的,作者源码如下:

class GlyphEmbedding(nn.Module):
    """Glyph2Image Embedding"""

    def __init__(self, font_npy_files: List[str]):
        super(GlyphEmbedding, self).__init__()
        # font_arrays[i]存储了这个字的字形。 font_arrays[i].shape为(23236, 24, 24),其中23236是字典大小。数字范围为[0,255]
        font_arrays = [
            np.load(np_file).astype(np.float32) for np_file in font_npy_files
        ]
        self.vocab_size = font_arrays[0].shape[0]   # 字典大小,也就是23236
        self.font_num = len(font_arrays)    # 字体数量,三种字体:“仿宋”、“行楷”和“隶书”
        self.font_size = font_arrays[0].shape[-1]   # 图片大小,24.
        # N, C, H, W
        font_array = np.stack(font_arrays, axis=1)  # 将三种字体组合到一起,font_array.shape为(23236, 3, 24, 24)
        self.embedding = nn.Embedding(  # 定义全连接层(Embedding和Linear本质是一样的)
            num_embeddings=self.vocab_size,
            embedding_dim=self.font_size ** 2 * self.font_num,  # 将字编码成24*24*3大小的tensor
            _weight=torch.from_numpy(font_array.reshape([self.vocab_size, -1]))
        )

    def forward(self, input_ids):
        """
            get glyph images for batch inputs
        Args:
            input_ids: [batch, sentence_length]
        Returns:
            images: [batch, sentence_length, self.font_num*self.font_size*self.font_size]
        """
        # return self.embedding(input_ids).view([-1, self.font_num, self.font_size, self.font_size])
        return self.embedding(input_ids)

在上述Fusion层还有这么两行代码:

# init中定义的全连接层
self.glyph_map = nn.Linear(1728, config.hidden_size)
# forward中将1728维的字形特征映射到768维
glyph_embeddings = self.glyph_map(self.glyph_embeddings(input_ids))  # [bs,l,hidden_size]

3.2 Pinyin Embedding

与直觉相反,作者在Pinyin Embedding过程使用了卷积层(1维卷积),但Glyph Embedding却没有使用。

作者的思路如下图:

【论文解读】(拼音+字形+字三种信息的中文BERT)ChineseBERT: Chinese Pretraining Enhanced by Glyph and Pinyin Information_卷积_03

作者首先将字转换成拼音+音调,由于不同的字拼音长度不同,所以作者将长度固定为8,不足补0。然后将获取到的token编码成8个128维的向量。之后使用1维卷积(kernal_size=2, stride=1)对这8个向量进行卷积操作,最终会得到7个768维的输出向量。最后使用max_pool选择出一个最终的特征向量作为该字的pinyin embedding。

之所以使用Conv来完成拼音特征的提取,作者说是因为拼音长度不固定,为了避免补0给特征提取带来影响,所以使用卷积。

代码如下:

class PinyinEmbedding(nn.Module):
    def __init__(self, embedding_size: int, pinyin_out_dim: int, config_path):
        """
            Pinyin Embedding Module
        Args:
            embedding_size: the size of each embedding vector
            pinyin_out_dim: kernel number of conv
        """
        super(PinyinEmbedding, self).__init__()
        with open(os.path.join(config_path, 'pinyin_map.json')) as fin:
            pinyin_dict = json.load(fin)
        self.pinyin_out_dim = pinyin_out_dim    # 要将token编码成的向量维度,例如768。
        # Embedding(32, 128)。其中32为6+26:6种音调, 26个英文字母。128为将一个拼音中字母(或音调)编码成128维的向量
        self.embedding = nn.Embedding(len(pinyin_dict['idx2char']), embedding_size)
        # 卷积层,输入通道数为128,输出通道数为768。
        self.conv = nn.Conv1d(in_channels=embedding_size, out_channels=self.pinyin_out_dim, kernel_size=2,
                              stride=1, padding=0)

    def forward(self, pinyin_ids):
        """
        Args:
            pinyin_ids: (batch_size, sentence_length, 8), sentence_length包含101和102, 8是固定长度(拼音+音调+不足补0)。

        Returns:
            pinyin_embed: (bs,sentence_length,pinyin_out_dim)
        """
        # 将每个字母(或音调或[PAD])编码成128维的向量。embed.shape为[bs,sentence_length,8,embed_size],例如(1, 6, 8, 128)。
        embed = self.embedding(pinyin_ids)  # [bs,sentence_length,pinyin_locs,embed_size]
        bs, sentence_length, pinyin_locs, embed_size = embed.shape
        # 为了进行后续卷积,将batch_size和sentence_length合并。然后embed_size提前。
        view_embed = embed.view(-1, pinyin_locs, embed_size)  # [(bs*sentence_length),pinyin_locs,embed_size]
        input_embed = view_embed.permute(0, 2, 1)  # [(bs*sentence_length), embed_size, pinyin_locs]
        # conv + max_pooling    # 卷积+max_pooling操作
        pinyin_conv = self.conv(input_embed)  # [(bs*sentence_length),pinyin_out_dim,H]
        pinyin_embed = F.max_pool1d(pinyin_conv, pinyin_conv.shape[-1])  # [(bs*sentence_length),pinyin_out_dim,1]
        return pinyin_embed.view(bs, sentence_length, self.pinyin_out_dim)  # [bs,sentence_length,pinyin_out_dim]

4. 实验与结论

作者在6种任务上进行了实验,要么和其他BERT打平,要么就是赢,反正就是效果挺不错的。详情可以参考作者代码或原论文

5. 模型使用方式

ChineseBert并不能直接像其他Huggging Face的Model直接从使用transformers代码加载,需要一些特殊操作。

我的处理步骤如下:

  1. 首先在项目下新建ChineseBert目录用于存放作者代码。
  2. 将作者的代码从Github上下载下来,将datasetsmodelsutils 三个目录放入ChineseBert目录下
  3. 从HuggingFace上下载ChineseBERT-base模型,放入ChineseBert/model目录下。(注意:不能使用作者提供的Google Drive下载,那个文件有问题)
  4. 将左右的from models.* 改为 from ChineseBert.models.*。因为我在作者的基础上外面包了一层ChineseBert
  5. ChineseBert与其下的所有的文件夹加入__init__.py文件,让它们都由普通文件夹变成Python Package
  6. 将所有的from transformers.modeling_bert.*改为from transformers.models.bert.modeling_bert.*,因为高版本的transformers改变了一些类的路径

可以直接使用我封装好的代码:ChineseBert(百度网盘)

当上面都做完后,就可以将ChineseBert作为一个第三方依赖进行调用了,样例代码如下:

from ChineseBert.datasets.bert_dataset import BertDataset
from ChineseBert.models.modeling_glycebert import GlyceBertForMaskedLM

tokenizer = BertDataset("./ChineseBert/model/ChineseBERT-base")
chinese_bert = GlyceBertForMaskedLM.from_pretrained("./ChineseBert/model/ChineseBERT-base")
sentence = '我喜欢猫'

input_ids, pinyin_ids = tokenizer.tokenize_sentence(sentence)
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.size())
print(output_hidden)

输出为:

torch.Size([1, 6, 23236])
tensor([[[ -8.6706,  -8.5349,  -8.4511,  ...,  -9.3002, -10.3638,  -9.6329],
         [ -7.4224,  -7.6068,  -7.6662,  ...,  -9.5153,  -8.1475,  -9.8946],
         [-11.5929, -10.2694, -11.1009,  ..., -13.2361, -12.7843, -17.3548],
         [-11.8149, -10.0489, -10.2216,  ..., -12.4247, -14.1545, -18.0415],
         [ -6.2827,  -5.1745,  -7.0772,  ...,  -6.9521,  -7.4132,  -5.3711],
         [ -8.6707,  -8.5348,  -8.4511,  ...,  -9.3002, -10.3638,  -9.6329]]],
       grad_fn=<ViewBackward0>)


标签:BERT,Chinese,Information,pinyin,self,length,embedding,font,size
From: https://blog.51cto.com/u_11466419/6254910

相关文章

  • 【论文笔记】MacBert:Revisiting Pre-trained Models for Chinese Natural Language Pr
    文章目录相关信息摘要(Abstract)1.介绍(Introduction)2.相关工作(RelatedWork)3.中文预训练模型(ChinesePre-trainedLanguageModels)3.1BERT-wwm&RoBERTa-wwm3.2MacBERT4.实验设置(ExperimentSetups)4.1SetupsforPre-TrainedLanguageModels4.2SetupsforFine-tuningTask......
  • bert中mask
     bert中n(seq_len)默认是512,通过padding,head_size=64hidden_size=768默认计算方式是hidden_size/heads(12) =64,输入为seq_len(句子长度)*batch(句子个数)*embedingsize (44条消息)BERT原理和结构详解_bert结构______miss的博客-CSDN博客在BERT小模型中,每个head......
  • 使用BERT的两层encoder实现tweet sentiment extraction
    文章目录使用BERT的两层encoder实现tweetsentimentextraction1.前言1.1Required1.2分析给定的数据2.模型构造2.1数据清洗2.2模型结构使用BERT的两层encoder实现tweetsentimentextractionTweetsentimentextraction是kaggle的一个比赛,这个代码主要是想尝试利用BERT模型实......
  • 利用Tensorflow使用BERT模型+输出句向量和字符向量
    文章目录1.前言2.BERT模型2.1下载预训练好的模型2.2导入BERT模型2.3数据下载和预处理2.4模型训练2.5直接输出BERT模型的句向量或者是字符向量1.前言最近想着如何利用tensorflow调用BERT模型,发现其源码已经有比较详细的调用代码,具体的链接如下:https://github.com/google-resear......
  • ITIL信息技术基础架构库Information Technology Infrastructure Library
    ITIL是什么?|ITIL流程和框架-ManageEngineServiceDeskPlusITIL是InformationTechnologyInfrastructureLibrary的缩写,即:信息技术基础架构库。ITIL是由英国政府部门CCTA(CentralComputingandTelecommunicationsAgency)在20世纪80年代末开发的一套IT服务管理标准库,它......
  • Controllable Guarantees for Fair Outcomes via Contrastive Information Estimation
    目录概符合说明Motivation优化目标代码GuptaU.,FerberA.M.,DilkinaB.andSteegG.V.Controllableguaranteesforfairoutcomesviacontrastiveinformationestimation.AAAI,2021.概本文提出了一种类似InformationBottleneck的方式用于保证两个群体的fairn......
  • MySQL5.7 访问Information_schema.TABLES 导至内存持续增长
    在生产环境5.7.30的数据库中,部署了MYSQL监控,但是发现部署完监控后,mysqld的内存持续增长。后通过监控发现也正是监控用户占用了大量的内存。目录适用范围问题概述问题原因解决方案参考文档适用范围mysql5.7问题概述在生产环境5.7.30的数据库中,部署了MYSQL监......
  • gpt bert
    Transformer的结构标准的Transformer模型主要由两个模块构成:Encoder(左边):负责理解输入文本,为每个输入构造对应的语义表示(语义特征),;Decoder(右边):负责生成输出,使用Encoder输出的语义表示结合其他输入来生成目标序列。这两个模块可以根据任务的需求而单独使用:纯Encoder......
  • abc268 C - Chinese Restaurant
    C-ChineseRestaurant 算贡献就是在普通思路上交换循环数,或是交换求和符号的2边的个数,来达到优化和解题的目的对于该题,我刚开始的想法是循环旋转次数,再去查看符合要求的菜的个数,这样是O^2的于是我们交换循环数,先去循环每个菜,我们发现每个菜实际上只对3个循环次数有贡献,于是......
  • 【论文解读】BERT和ALBERT
    文章目录1.前言2.BERT2.1引入2.2以前的工作2.2.1feature-based方法2.2.2fine-tuning方法2.2.3迁移学习方法2.3BERT架构2.3.1MLM2.3.2NSP2.4实验2.4.1BERT模型的效果2.4.2验证性实验3.ALBERT3.1引入3.2相关工作3.2.1cross-layerparametersharing(交叉层的参数共享......