BERT√

输入为什么有512这个长度限制?

原文:To speed up pretraing in our experiments, we pre-train the model with sequence length of 128 for 90% of the steps. Then, we train the rest 10% of the steps of sequence of 512 to learn the positional embeddings.
学习了512长度的positional embeddings,如果长于512则不存在位置信息,出错。BERT中的Positional Embedding和Transformer中的Positional Embedding实现方式并不一样。
BERT中的Positional Embedding本质上是一个可学习的参数,也就是说每个位置所对应的位置向量就类似于Token Embedding中每个词对应的词向量。如下代码所示为Positional Embedding部分的代码实现,可以发现其本质上也就是一个普通的可学习的Embedding层。

DiskGenius

 class PositionalEmbedding(nn.Module):
 
 def __init__(self, hidden_size, max_position_embeddings=512, initializer_range=0.02):
     super(PositionalEmbedding, self).__init__()
     self.embedding = nn.Embedding(max_position_embeddings, hidden_size)      
     
 def forward(self, position_ids):
     return self.embedding(position_ids).transpose(0, 1)

因此,除非是你自己从零开始训练一个模型,否则如果你使用的是谷歌开源的预训练模型,那么这个词表的大小将会被限制在512。 当然,我们依旧可以突破这个限制,那就是重新初始化Positional Embedding中的向量,并将前512个向量用已有的进行替换,超出部分就使用随机初始化的权重在语料上进行微调或训练。代码实现:

nvm

 1     @classmethod
 2     def from_pretrained(cls, config, pretrained_model_dir=None):
 3         model = cls(config)  # 初始化模型,cls为未实例化的对象,即一个未实例化的BertModel对象
 4         pretrained_model_path = os.path.join(pretrained_model_dir, "pytorch_model.bin")
 5         if not os.path.exists(pretrained_model_path):
 6             raise ValueError(f"<路径:{pretrained_model_path} 中的模型不存在,请仔细检查!>")
 7         loaded_paras = torch.load(pretrained_model_path)
 8         state_dict = deepcopy(model.state_dict())
 9         loaded_paras_names = list(loaded_paras.keys())[:-8]
10         model_paras_names = list(state_dict.keys())[1:]
11         for i in range(len(loaded_paras_names)):
12             state_dict[model_paras_names[i]] = loaded_paras[loaded_paras_names[i]]
13             logging.debug(f"## 成功将参数:{loaded_paras_names[i]}赋值给{model_paras_names[i]},"
14                           f"参数形状为:{state_dict[model_paras_names[i]].size()}")        
15         model.load_state_dict(state_dict)
16         return model

在上述代码中,第3-10行用来载入本地的模型参数;第11-15行则是用来将载入的模型参数赋值到现有的模型。
进一步,我们只需要判断在第12行之前判断当前参数是否为positional embeding层,如果是进行替换即可,代码如下:

sql优化

1     def replace_512_position(init_embedding, loaded_embedding, config):
 2         logging.info(f"模型参数max_positional_embedding > 512,采用替换处理!")
 3         init_embedding[:512, :] = loaded_embedding[:512, :]
 4         return init_embedding
 5 
 6     @classmethod
 7     def from_pretrained(cls, config, pretrained_model_dir=None):
 8         # 此处代码同上
 9         for i in range(len(loaded_paras_names)):
10             if "position_embeddings" in model_paras_names[i]:
11                 # 这部分代码用来消除预训练模型只能输入小于512个字符的限制
12                 if config.max_position_embeddings > 512:
13                     new_embedding = replace_512_position(state_dict[model_paras_names[i]],
14                                                          loaded_paras[loaded_paras_names[i]],
15                                                          config)
16                     state_dict[model_paras_names[i]] = new_embedding
17             else:
18                 state_dict[model_paras_names[i]] = loaded_paras[loaded_paras_names[i]]
19             logging.debug(f"## 成功将参数:{loaded_paras_names[i]}赋值给{model_paras_names[i]},"
20                           f"参数形状为:{state_dict[model_paras_names[i]].size()}")
21         model.load_state_dict(state_dict)
22         return model

通过上述代码,我们在载入预训练模型的同时就成功将随机初始化positional embedding中的前512个向量替换为了预训练模型中positional embedding中的参数。在这之后,剩余部分的参数可以通过下游任务来进行微调,也可以在一些语料上根据NSP和MLM任务进行训练。
Transformer中的Positional Embedding是通过公式得到的
在这里插入图片描述

图像生成

参考

https://zhuanlan.zhihu.com/p/493424507

c++11

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注