简介
此篇文章是对macbert4csc模型的一次尝试与思考,废话不多说,看内容。
[x180/macbert4csc-scalarmix-base-chinese]https://huggingface.co/x180/macbert4csc-scalarmix-base-chinese)。
模型结构
这个模型分成两部分:
- 使用BertForMaskedLM对预训练模型做mask训练。
- 对预测的结果输入linear,判断预测的结果和真实的结果是否相同,即二分类。
举例:
比如错句为我和你在一其
,正确的句子为我和你在一起
,错句输入MLM,得到的结果假设为我和你在一器
。然后输入linear判别器,判断和正确的句子做二分类。最后两个loss进行相加。
思考
为什么选择macbert
首先看看什么是macbert,全称是(MLM as corrector),它是哈工大和讯飞一起训练的模型。主要做的内容有两点:
- 修改bert mask预处理代码,将bert做[mask]的地方用同义词来替代。同时引入全词mask。
- 替换NSP任务,使用SOP来替代。
第一条的做法好处是下游任务一般不会有[mask],那么就不会带来预训练模型和下游任务不匹配的问题。
第二条的做法好处是简单来讲就是更能理解句子的语义性(合理以及通顺)。
为什么代码没有在错字地方做mask
这个问题就是为什么选择macbert做微调,因为macbert对mlm中做mask替代的地方用了同义词替换。
和electra有什么关系
这个问题是我自己强行加进来的,哈哈。。
先来看下electra的结构图。
electra模型分成两部分:
- 生成器。例如上图,对
the
和painting
做[MASK]
,然后使用生成器进行训练获取结果, 其中the
对了,painting
对应了car
。 - 将生成的结果送入判别器,和原句做二分类,发现
painting
生成错了。
其loss计算方式如下所示:
有木有发现,两者其实还蛮像的,哈哈。
下面是正经思考:
- 错字识别是否可以使用electra模型来训练?
- 其中 λ是否可以进行借鉴?
回答1:我觉得阔以,甚者我觉得结果要比macbert4csc更好,为什么?
- 实验结果,macbert4csc的训练结果没有electra的结果好,你可以说不是同一类型的任务。
- macbert做同义词替换,如果没有对应的同义词呢,或者说同义词替换更关注实体词呢,错字是有可能哪里都可能错的。
但是,这些想法都是有些牵强的,只有自己跑出来才知道结果。
回答2:我觉得阔以,因为对于多loss,一般没有好的解决方法,明明超参数,只能实验呗。作者在这里选择了50,因为他认为
二分类相比mlm的交叉熵更容易一些,所以给予了更大的权重。
但是我觉得还可以有另外一种思路来参考,即灾难性遗忘
,它是说下游任务对预训练模型进行fine-tune,会对预训练模型造成干扰,那么loss计算时可以分成两部分,pretrained loss和fine-tune loss,一般按经验fine-tune loss权重为0.5。
改进
一. 调整λ值
作者这里使用0.7/0.3的权重分配给MLM和sigmoid二分类,这里我对其做了如下调整:
ID | MLM weight | sigmoid二分类 weight | dev metric |
---|---|---|---|
1 | 1 | 0.5 | epoch26:0.9168 |
2 | 1 | 5 | epoch35:0.914 |
3 | 1 | 50 |
1. ID(1)
以macbert eval.py为准进行测试,记得把macbert_model_dir改成自己的。
以epoch 26的模型为准:
1 | Sentence Level: acc:0.7040, precision:0.8545, recall:0.6087, f1:0.7109, cost time:5.35 s |
和”shibing624/macbert4csc-base-chinese”进行对比,发现recall要高了不少,结果效果更好了些~。
2. ID(2)
dev metric 在epoch 35的时候为0.914,相比ID(1)在epoch 26 0.9168的结果,发现收敛速度变的慢了。
故这个忽略。
3. ID(3)
dev metric 在epoch 35的时候为0.9112,虽说还有小量上涨可能,但是train metric已经过拟合了,这个结果让我觉得…,emmmm,这些超参没有达到想象中的区别哇。
2. 对hidden_states分配权重
作者在进行二分类的时候使用了最后一层的hidden_states,那么是否可以对所有的hiddeen_states分配不同的权重。为什么?前面的layer更偏向浅层语义信息,比如词法,句法等,越往后代表的含义可能更深层次,本来就是预测词对不对,搞那么深不一定适合。
所以下面对其进行尝试。
添加scalarmix层,代码如下:
1 | class ScalarMix(nn.Module): |
结果如下:
ID | MLM weight | sigmoid二分类 weight | dev metric |
---|---|---|---|
1 | 1 | 0.5 | epoch12:0.9118 |
为啥epoch 12就停了,因为train metric基本已经达到1了。。。
由此可见,整个准确率的提升,更多是在mlm这个任务上,加了二分类判断其对不对,整体影响并没那个大。。。
后来我发现了一个地方,mlm weight和二分类weight我给的是1和0.5,压缩到1之内就分别是0.6666和0.3333,我嘞个去,这不基本和作者的0.7和0.3很相近了么。。下次需要提前注意下。
最后
当我对mlm loss weight分配了更高的权重,结果发现效果有提升。
总结
- 对mlm和二分类分配不同权重发现,mlm的权重应该更高一些。这个和electra中那个50稍微有点偏差。不过我觉得又可以理解,因为它上游是生成器,任务不同~。
- 添加了ScalarMix层给hidden_states分配不同的权重,其对结果并没有产生有效影响,其本质问题还是在于mlm loss还是应该占据更大的比例。
- 至于为什么不尝试Chinese-BERT-wwm,因为MacBERT在其个任务效果对比中比前者整体表现会偏更好一些,另外都是做wwm,所以本质没有区别。