Glyce-用于汉字表示的字形向量

摘要

显而易见,像中文这样的标识语言的自然语言处理任务应该受益于这些语言中字形信息的使用。然而,由于字形中缺乏丰富的象形证据,标准计算机视觉模型对字符数据的泛化能力较弱,如何有效地利用字形信息仍有待探索。

在这篇文章中,我们通过提出汉字表示的字形向量Glyce来解决这个问题。

我们有三大创新:(1)利用中国历史文字(如青铜器文字、篆书、繁体字等)丰富文字中的象形证据;(2)我们设计了适合汉字图像处理的CNN结构(称为天田字格-CNN);(3)在多任务学习环境中,我们使用图像分类作为辅助任务,以提高模型的泛化能力。

我们表明,在广泛的中文自然语言处理任务中,基于字形的模型能够一致地优于基于单词/字符ID的模型。我们能够为各种中文自然语言处理任务设置最新的结果,包括标注(NER,CWS,POS),句子对分类,单句分类任务,依存句法分析,以及语义角色标注。例如,该模型在OntoNotes数据集NER上的F1得分为80.6,在BERT上的F1得分为+1.5;在复旦语料库上的文本分类准确率几乎达到99.8%。


1. 简介

汉语是一种象形文字。汉字的字形编码了丰富的词义信息。因此,汉语自然语言处理任务应该受益于字形信息的使用,这是很直观的。考虑到标识信息应该有助于语义建模。

最近的研究间接支持了这一观点:偏旁表征被证明在广泛的语言理解任务中是有用的[Shih等人,2015,Li等人,2015,殷等人,2016,Sun等人,2014,Shao等人,2017]。

据报道,使用五笔编码方案(一种模仿汉字编码部首序列的顺序的顺序的汉字编码方法)可改善汉英机器翻译的性能[Tan等,2018]。

曹等[2018]归结为更大粒度的单位,并提出了用于字符建模的笔画n-gram

近来,已经进行了一些努力,将基于CNN的算法应用于字符的视觉特征。不幸的是,它们并没有表现出持续的性能提升[Liu et al,2017,Zhang和LeCun,2017年],甚至产生负面结果[Dai and Cai,2017]。

例如,Dai和Cai[2017]对字符标识运行CNN以获得汉字表示,并将其用于下游语言建模任务。他们报告说,加入字形表示实际上会降低性能,并得出结论,基于CNN的表示没有为语言建模提供额外的有用信息。

使用类似的策略,刘等人[2017]张和乐存[2017]在文本分类任务上测试了这一想法,只有在非常有限的设置下才能观察到性能提升。

Su和Lee[2017]得出了积极的结果,他们发现字形嵌入有助于两个任务:词的类比和词的相似度。遗憾的是,Su和Lee[2017]只关注词汇层面的语义任务,而没有将词汇层面的改进扩展到更高层次的自然语言处理任务,如短语、句子或语篇层面。

结合激进的表述,邵某等人[2017]对字符图形运行CNN,并将输出用作POS标记任务中的辅助特征。

对于早先基于CNN的模型中报道的负面结果,我们提出了以下解释[Dai和Cai,2017]:

(一)文字版本不正确:汉字系统有很长的演变历史。人物从好画开始,慢慢过渡到好写。此外,随着时间的推移,它们变得不那么象形化,也变得不那么具体了。迄今为止使用最广泛的文字版本简体中文是最容易写的文字,但不可避免地丢失了最重要的象形文字信息。例如,意义不相关的“人”(人)和“入”(进入)在简体中文中的形状非常相似,但在青铜器文字等历史语言中却有很大的不同。

(2)没有使用正确的CNN结构:与ImageNet图像[邓等人,2009]不同,其大小大多在800*600的比例,字符徽标明显较小(通常为12*12)。它需要不同的CNN架构来捕捉字符图像的局部图形特征;

(3)以前的工作没有使用正则化功能:与ImageNet数据集上包含数千万个数据点的分类任务不同,只有1万个左右的汉字。因此,辅助训练目标对于防止过度拟合和提高模型的泛化能力至关重要。

本文提出了一种用于汉字表示的字形矢量GLYCE。我们将汉字视为图像,并使用CNN来获取其表示。我们通过使用以下关键技术来解决上述问题:

  • 我们使用历史文字和当代文字(如青铜器文字、文书文字、篆书、繁体汉字等)的组合,以及不同书写风格的文字(如草书)来丰富人物形象中的象形文字信息。
  • 我们利用为逻辑字符建模量身定制的Tianzige-CNN(田字格)结构。
  • 我们通过添加图像分类损失函数来使用多任务学习方法,以提高模型的泛化能力。

发现Glyce可以改善各种中文NLP任务。我们能够获得广泛的中文NLP任务SOTA表现,包括标记(NER,CWS,POS),句子对分类(BQ,LCQMC,XNLI,NLPCC-DBQA),单句分类任务(ChnSentiCorp,复旦语料库(iFeng),依赖项解析和语义角色标记。


2. Glyce

2.1 使用历史文字

正如第一节所讨论的那样,简体中文文字中的象形文字信息大量丢失。因此,我们建议使用历史上不同时期的文字,也可以使用不同写作风格的文字。我们收集了以下主要的历史手稿,详细情况如表1所示。不同历史时期的手稿通常形状迥异,有助于模型整合来自不同来源的象形文字证据;不同书写风格的手稿有助于提高模型的泛化能力。这两种策略都类似于计算机视觉中广泛使用的数据增强策略。

2.2 用于Glyce的田字格-CNN

直接使用深层CNN在我们的任务中由于(1)字符图像的尺寸相对较小而导致性能很弱:Imagent的图像通常是800 * 600,而汉字图像的尺寸明显较小,通常为12*12的比例;(2)缺乏训练示例:ImageNet数据集上的分类利用了数千万种不同的图像。相反,只有大约10000个不同的汉字。

为了解决这些问题,我们提出了适合于汉字建模的田字格-CNN结构,如图1所示。

image-20201012160545873

田字格是中国书法的传统形式。这是一种四方形格式(类似于田字),供初学者学习书写汉字。输入图像$x_{image}$首先通过内核大小为5,输出通道为1024的卷积层,以捕获较低级别的图形特征。

然后将核尺寸为4的max-pooling应用于特征图,从而将分辨率从$8\times 8$降低到$2\times 2$。这种$2\times 2$的田字格结构显示了汉字的部首排列方式以及汉字的书写顺序。最后,我们应用组卷积[Krizhevsky 等,2012,Zhang 等,2017],而不是传统的卷积运算将田字格网格映射到最终输出。

组卷积滤波器比它们的普通卷积滤波器小得多,因此不易过拟合。将模型从单个字符调整为多个字符很容易,只需将输入从2D(既,$d_{font}\times d_{font}$)转为3D(既,$d_{font}\times d_{font}\times N_{script}$),其中$d_{font}$代表字体大小,$N_{script}$代表使用的字的数量。

2.3 图像分类作为辅助目标

为了进一步防止过拟合,我们使用图像分类任务作为辅助训练目标。来自CNN的 glyph嵌入将转发到图像分类目标,以预测对应的 charID。假设图像$x$的标签为$z$。图像分类任务$\mathcal{L}(cls)$的训练目标如下:
$$
\begin{aligned} \mathcal { L } ( \mathrm { cls } ) & = - \log p ( z \mid x ) \ & = - \log \operatorname { softmax } \left( W \times h _ { \mathrm { image } } \right) \end{aligned} \tag{1}
$$
让$\mathcal{L}(task)$表示我们要解决的任务的特定任务目标,例如语言建模,分词等。我们将$\mathcal{L}(task)$和$\mathcal{L}(cls)$线性组合,使最终目标训练函数如下:
$$
\mathcal { L } = ( 1 - \lambda ( t ) ) \mathcal { L } ( \text { task } ) + \lambda ( t ) \mathcal { L } ( \mathrm { cls } ) \tag{2}
$$
其中$\lambda(t)$控制特定任务目标和辅助图像分类目标之间的权衡。$\lambda$是关于epoch $t$的函数:$\lambda(t)=\lambda_0\lambda_1^t$,其中$\lambda_0\in [0,1]$代表起始值,$\lambda_1 \in [0,1]$代表衰减值。这意味着随着训练的进行,来自图像分类目标的影响会减小,直观的解释是,在训练的早期,我们需要更多来自图像分类任务的规则。将图像分类作为训练目标,模仿了多任务学习的思想。

2.4 用BERT结合字形信息

glyph嵌入可以直接输出到RNN、LSTM、transformers等下游模型。

由于使用语言模型的大规模预训练系统,如BERTElmoGPT,已经被证明在广泛的NLP任务中是有效的,因此我们探索了将glyph嵌入与Bery嵌入相结合的可能性。

这样的策略将潜在地赋予该模型glyph证据和大规模预训练的优势。图2显示了组合的概述。

image-20201012183508599

该模型由四层组成:BERT层、glyph层、Glyce-BERT层和特定于任务的输出层。

  • BERT层:每个输入矩阵$S$与表示句子开始的特殊标记$\text{CLS}$标记和表示句子结束的$\text{SEP}$标记连接在一起。在给定预训练的BERT模型的情况下,使用BERT计算$S$的每个标记的嵌入。我们使用BERT转换器的最后一层的输出来表示当前标记。
  • Glyph层:田字格-CNNs的输出-glyph嵌入
  • Glyce-BERT层:位置嵌入首先被添加到字形嵌入。然后将添加的内容与BERT连接起来,以获得完整的Glyce表示。
  • 特定于任务的输出层Glyce表示用于表示该位置的标记,类似于单词嵌入或Elmo嵌入[Peters等人,2018年]。上下文感知信息已经在BERT表示中编码,但不是glyph表示。因此,我们需要额外的上下文模型来编码上下文感知的glyph表示。这里,我们选择多层transformers。Transformer的输出表示用作预测层的输入。值得注意的是特殊的CLSSEP标记的表示在最终的特定于任务的嵌入层中维护。

3. 任务

在本节中,我们描述了glyph嵌入如何用于不同的NLP任务。在原始版本中,glyph嵌入被简单地视为字符嵌入,他们被馈送到建立在词嵌入层之上的模型,例如RNN,CNN或更复杂的模型。

如果结合BERT,我们需要在不同的情况下专门处理glyph嵌入和来自BERT的预训练嵌入直接的集成,如下所述:

序列标记任务 许多中文NLP任务,例如命名实体识别(NER),中文分词(CWS)和部分语音标记(POS),都可以形式化为字符级序列标记任务,其中我们需要预测每个字符的标记。对于 glyce-BERT模型,来自任务特定层的嵌入输出(在第2.4节中进行了描述)被送到CRF模型以进行标签预测。

单句分类 对于文本分类任务,将为整个句子预测单个标签。在BERT模型中,将BERT的最后一层中CLS标记的表示输出到softmax层进行预测。我们采用类似的策略,在该策略中,特定于任务的层中CLS标记的表示被馈送到softmax层以预测标签。

句子对分类 对于像SNIS这样的句子对分类任务[Bowman等,2015],模型需要处理两个句子之间的交互,并输出一对句子的标签。在BERT设置中,一个句子对$(s_1,s_2)$与一个$\text{CLS}$和两个$\text{SEP}$连接起来,由$[\text{CLS},s_1,\text{SEP},s_2,\text{SEP}]$表示。将连接送到BERT模型,然后获得的$\text{CLS}$表示被送到Softmax层用于预测。我们对Glyce-BERT采用相同的策略,其中$[\text{CLS},s_1,\text{SEP},s_2,\text{SEP}]$随后通过BERT层、Glyph层、Glyce-BERT层和特定于任务的输出层。来自特定任务输出层的$\text{CLS}$表示被送到softmax函数以用于最终标签预测。


4. 实验

为了实现苹果之间的比较,我们在开发集上对基线和建议的模型都执行了网格参数搜索。我们按顺序描述了我们正在处理的任务。

4.1 标记

NER

对于中文NER的任务,我们使用了广泛使用的OntoNotes,MSRA,微博和简历数据集。由于大多数数据集没有黄金标准的分词,因此该任务通常被视为字符级标记任务:为每个字符输出一个NER标记。目前使用最广泛的非BERT模型是Lattice-LSTM[Y Ang et al.,2018,Zhang and Y Ang,2018],取得了比CRF+LSTM更好的性能[Ma和Hovy,2016]。

CWS

中文分词通常被视为字符级标注问题。我们使用了广泛使用的北大、MSR、CITU和SIGHAN 2005年的烘焙比赛作为基准进行评估。

POS

汉语词性标注任务通常被形式化为字符级序列标注任务,为序列内的每个字符分配标签。我们使用CTB5、CTB9和UD1(通用依赖)基准来测试我们的模型。

4.2 句子对分类

对于句子对分类任务,我们需要为每对句子输出一个标签。对于句子对分类任务,我们需要为每对句子输出一个标签。我们使用以下四个不同的数据集:(1)BQ(二进制分类任务)[Bowman等,2015];(2)LCQMC(二进制分类任务)[Liu等,2018];(3)XNLI(三类分类任务)[Williams和Bowman],以及(4)NLPCC-DBQA(二进制分类任务)。

4.3 单句分类

对于单个句子/文档分类,我们需要为文本序列输出标签。标签可以是情感指标或新闻类型。我们使用的数据集包括:(1)ChnSentiCorp(二进制分类); (2)复旦语料库(5级分类)[Li,2011]; (3)Ifeng(5类分类)。

表6显示了针对不同任务的不同模型的结果。我们观察到与以前类似的现象:Glyce + BERT在所有数据集上都获得了SOTA结果。具体来说,Glyce + BERT模型在复旦语料库上实现了几乎完美的准确性(99.8)。

4.4 依存关系解析和语义角色标注

对于依存关系分析[Chen和Manning,2014,Dyer等人,2015],我们使用了广泛使用的中文Penn Treebank 5.1数据集进行评估。我们的实现使用了之前最先进的深度双仿射模型Dozat和Manning[2016]作为骨干。我们将双仿射模型中的词向量替换为Glyce-Word嵌入,并严格遵循其模型结构和训练/开发/测试分割准则。我们报告无标签依恋分数(UAS)和有标签依恋分数(LAS)的分数。以前模型的结果复制自[Dozat和Manning,2016,Ballesteros等人,2016,Cheng等人,2016]。Glyce-Word在UAS和LAS得分方面将SOTA的表现分别提高了+0.9和+0.8。

对于语义角色标注(SRL)任务[Roth和Lapata,2016,Marcheggiani和Diego,2017,他等人,2018],我们使用了CoNLL-2009共享任务。我们使用目前的SOTA模型,k阶剪枝算法[He等人,2018年]作为骨干。我们用Glyce嵌入替换了词嵌入。Glyce在F1得分方面比之前的SOTA表现高出0.9分,达到了83.7的新SOTA得分。

BERT在这两个任务中的表现不具竞争力,因此结果被省略了。


5. 消融实验

在这一部分中,我们讨论了不同因素对模型的影响。我们使用句子对预测任务的LCQMC数据集进行说明。我们讨论的因素包括训练策略、模型结构、辅助图像分类目标等。

5.1 训练策略

本节讨论一种训练策略(用BERT-glyce-joint表示),在这种策略中,给定特定任务的监督,我们首先微调BERT模型,然后冻结BERT来微调glyph层,最后联合调整两层,直到收敛。

我们将这种策略与其他策略进行比较,包括(1)Glyph-Joint策略,其中BERT在开始时没有进行微调:冻结BERT来调整glyph层,然后联合调整两个层,直到收敛;和(2)联合策略,其中我们直接联合训练两个模型,直到收敛。

结果如表8所示。可以看出,BERT-glyce-joint优于其余两种策略。

image-20201013013032025

我们对联合策略较差性能的解释如下:BERT层是预处理的,但glyce层是随机初始化的。给定相对少量的训练信号,BERT层可能在训练的早期被随机初始化的Glyph层误导,导致较差的最终性能。

5.2 特定任务输出层的结构

glyph嵌入和BERT嵌入的连接被馈送到任务特定的输出层。特定于任务的输出层由两层Transformer层组成。这里我们把Transformer换成其他结构比如BiLSTMs和CNNs来探究影响。我们还尝试了王等人[2017]的BiMPM结构来查看结果。

性能如表9所示。

image-20201013013414048

可以看出,Transformer的表现不仅优于BiLSTMs和CNNs,也优于专为句子对分类任务构建的BiMPM结构。我们猜想这是因为Transformer和BERT结构之间的一致性。

5.3 图像分类训练目标

我们还探讨了图像分类训练目标的影响,它将Glyph表示输出到图像分类目标。表10代表了它的影响。

image-20201013013701475

可以看出,这个辅助训练目标给了+0.8的性能提升。

5.4 CNN 结构

不同CNN结构的结果如表11所示。

image-20201013013747165

可以看出,田字格网结构的采用带来了F1+1.0左右的性能提升。在我们的任务中直接使用深层神经网络会导致非常差的性能,因为(1)字符图像的尺寸相对较小:ImageNet图像的大小通常在800*600的比例,而汉字图像的大小明显较小,通常在12*12的比例;(2)缺乏训练样本:在ImageNet数据集上的分类利用了数千万个不同的图像。

相比之下,只有大约一万个不同的汉字。我们利用田字格-CNN专为中文标识字符建模而定制的结构。这种田字格结构在提取字符含义方面非常重要。


6. 总结

在本文中,我们提出了汉字表示的字形向量。Glyce将汉字视为图像,利用田字格-CNN提取字符语义。Glyce提供了一种通用的方法来模拟标识语言的字符语义。它是一般的和基本的。就像单词嵌入一样,Glyce可以集成到任何现有的深度学习系统中。

关键代码

  1. /home/stu/LRR/glyce-master/glyce/scripts/fudan_glyce_bert.sh
  2. /home/stu/LRR/glyce-master/glyce/bin/run_bert_glyce_classifier.py

读取图像的代码位于:/home/stu/LRR/glyce-master/glyce/glyph_cnn_models

1
2
3
4
5
6
7
8
9
10
11
# 定义Glyph特征读取模型
if self.config.num_fonts_concat:
# 定义特征读取模型
self.glyph_cnn_model = GlyphGroupCNN(
num_features=self.config.glyph_embsize, cnn_drop=self.config.cnn_dropout,
font_channels=self.config.random_fonts or self.config.font_channels, groups=self.config.glyph_groups)
# 定义分类层 [768,21128]
self.glyph_classifier = nn.Linear(self.config.glyph_embsize, len(self.config.idx2char))
# print(self.glyph_classifier)
# 损失函数
self.glyph_classification_criterion = MaskCrossEntropy(self.config.loss_mask_ids)

在这里其是当成了分类任务去做。

文件关系

  • glyce_bert_classifier.py 中的GlyceBertClassifier 定义了GlyceTransformer,包含对字形特征的处理,其输入有input_ids,token_type_ids,attention_mask
  • glyce_transformer.py中的GlyceTransformer定义了GlyphPositionEmbedder,包含获取字形特征,以及图像分类损失(以汉字为级别的分类),输入为input_ids
  • glyph_position_embed.py中的GlyphPositionEmbedder定义了CharGlyphEmbedding,包含了对字形特征进行编码的过程,损失是在这里进行计算(输入为input_ids)。

字形特征使用

glyce_transformer.py中通过 input_features = torch.cat([glyph_embed, context_bert_output], -1)操作将 字形特征 与 bert预训练的字向量进行连接,然后送入bert编码器,再进行分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class GlyceBertClassifier(nn.Module):
def __init__(self, config, num_labels=2):
super(GlyceBertClassifier, self).__init__()
self.num_labels = num_labels
self.glyph_transformer = GlyceTransformer(config, num_labels=num_labels)
# config involves here
# 1. config.glyph_config
# 2. config.bert_config
# 3. transformer_config
self.dropout = nn.Dropout(config.hidden_dropout_prob)
if config.classifier_sign == "single_linear":
self.classifier = SingleLinearClassifier(config.hidden_size, self.num_labels)
elif config.classifier_sign == "multi_nonlinear":
self.classifier = MultiNonLinearClassifier(config.hidden_size, self.num_labels)
else:
raise ValueError

def forward(self, input_ids, token_type_ids=None, attention_mask=None, \
labels=None):


encoded_layers, pooled_output, glyph_cls_loss = self.glyph_transformer(input_ids, \
token_type_ids=token_type_ids, attention_mask=attention_mask)

features_output = encoded_layers[-1]
# print(features_output.shape)
features_output = features_output[:, 0, :]

features_output = self.dropout(features_output)
logits = self.classifier(features_output)

# 如果label不为空
if labels is not None:
loss_fct = CrossEntropyLoss()
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
return loss, glyph_cls_loss
else:
return logits, glyph_cls_loss

Glyce-用于汉字表示的字形向量

http://example.com/2020/10/13/paper-glyce/

作者

bd160jbgm

发布于

2020-10-13

更新于

2021-06-10

许可协议