Albert(A Lite Bert For Self-Supervised Learning Of Language Representations)是对 Bert 的改进,其主要思想就是用更少的参数,取得更好的效果。所以, 可以理解 Albert 是对 Bert 的改进版本,其主要的一些改进如下:
- 分解词嵌入矩阵
- 跨层参数共享
Paper:https://arxiv.org/pdf/1909.11942.pdf
1. 嵌入矩阵分解(Factorized embedding parameterization)
在 Bert 模型的词嵌入矩阵包含了大量的参数,但是在训练过程中,这些参数可能只存在稀疏的更新。我们以 transformres 库的代码实现为例,例如:Bert 模型中会构建一个 21128×768 的词嵌入矩阵,用来独立的表示输入字,每个词嵌入向量中并不包含词与词之间的关系。即:此时需要学习的参数就有 21128×768=2100万多。Albert 通过改进这个矩阵,就使得这一部分的参数量下降了 80%,但是性能只有很小的下降。
Albert 中是如何改进的?
Albert 通过降低词嵌入层的维度,从 768 改成 128,然后增加 embedding_hidden_mapping_in 线性层将 128 再映射为 768 维度。
我们看下 Bert 和 Albert 在 tramsformers 库的具体实现来看下这个变化。Bert Embedding 实现代码部分如下:
class BertEmbeddings(nn.Module): """Construct the embeddings from word, position and token_type embeddings.""" def __init__(self, config): super().__init__() # config.vocab_size 21128 # config.hidden_size 768 self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=config.pad_token_id) ......
Albert 的 Embedding 实现代码部分如下:
class AlbertEmbeddings(nn.Module): """ Construct the embeddings from word, position and token_type embeddings. """ def __init__(self, config): super().__init__() # config.vocab_size 21128 # config.embedding_size 128 self.word_embeddings = nn.Embedding(config.vocab_size, config.embedding_size, padding_idx=config.pad_token_id) ......
Albert 的 Encoder 的实现代码中,将传入进来的 128 维度的词向量,通过 embedding_hidden_mapping_in 进行了维度变换,如下代码所示:
self.embedding_hidden_mapping_in = nn.Linear(config.embedding_size, config.hidden_size) hidden_states = self.embedding_hidden_mapping_in(hidden_states)
2. 跨层参数共享(Cross-layer parameter sharing)
Paper 中提到共享参数的方法很多,比如只共享 FF 层的参数,或者只共享注意力层的参数等等,Albert 默认是跨层共享所有参数,即:注意力、FF 等整个层的参数。
3. SOP 预训练任务(Sentence Order Prediction)
Bert 模型中使用 NSP 预训练任务,Paper 中认为该任务缺乏难度,对模型性能没有更好的提升。所以将其改为 SOP 预训练任务。
Bert NSP 在训练前,从语料中构建输入句子 A,50% 从使用原始语料中选择连续的下一个句子 B 组成输入正样本,标记为 IsNext。 50% 从语料中随机挑选一些不挨着的句子 B 组成负样本,标记为 NotNext。最终,使用 [CLS] 对应的输出计算概率句子B是句子A 的 IsNext 和 NotNext 的概率。
Albert SOP 在训练前,也是从语料中采样连续的两个句子 A 和 B 作为正样本,预测 B 是否是 A 的下一句。但是负样本则是将句子 A 和 B 交换顺序,即:预测 A 是不是 B 的下一句。
4. N-gram Mask
Bert 中对字进行随机掩码,对被掩码的字之间做了独立性假设。而 Albert 则使用 n-gram mask,掩码一个相关的字词,避免了这个独立性假设问题。Albert 中 n-gram 最大值为 3,即:随机从 1-gram、2-gram、3-gram 中随机选择,选择概率为:
因为Bert 没有出现过拟合的现象,所以,Albert 去掉 Dropout,在 Albert 默认的配置参数中,dropout 这一项都是 0,如下:
AlbertConfig { "attention_probs_dropout_prob": 0, "bos_token_id": 2, "classifier_dropout_prob": 0.1, "embedding_size": 128, "eos_token_id": 3, "hidden_act": "gelu_new", "hidden_dropout_prob": 0, "hidden_size": 4096, "initializer_range": 0.02, "inner_group_num": 1, "intermediate_size": 16384, "layer_norm_eps": 1e-12, "max_position_embeddings": 512, "model_type": "albert", "num_attention_heads": 64, "num_hidden_groups": 1, "num_hidden_layers": 12, "pad_token_id": 0, "position_embedding_type": "absolute", "transformers_version": "4.22.2", "type_vocab_size": 2, "vocab_size": 30000 }
其实,从 Albert 干的这些事,也大体了解其就是尽量的给 Bert 瘦身,减少参数量、减少不必要的计算。所以,也可以把 Albert 理解为一个性能还不错,但是轻量级的 Bert 模型。
- 1-gram:6/11
- 2-gram:3/11
- 3-gram:2/11
1-gram 概率最大,3-gram 概率最低。
AlbertForSequenceClassification.from_pretrained('model/albert_chinese_tiny')