在 Huggingface BERT 模型之上添加密集层
Posted
技术标签:
【中文标题】在 Huggingface BERT 模型之上添加密集层【英文标题】:Add dense layer on top of Huggingface BERT model 【发布时间】:2021-01-17 05:23:58 【问题描述】:我想在输出原始隐藏状态的裸 BERT 模型转换器之上添加一个密集层,然后微调生成的模型。具体来说,我使用的是this 基本模型。这是模型应该做的:
-
对句子进行编码(句子的每个标记包含 768 个元素的向量)
只保留第一个向量(与第一个标记相关)
在该向量顶部添加一个密集层,以获得所需的转换
到目前为止,我已经成功编码了句子:
from sklearn.neural_network import MLPRegressor
import torch
from transformers import AutoModel, AutoTokenizer
# List of strings
sentences = [...]
# List of numbers
labels = [...]
tokenizer = AutoTokenizer.from_pretrained("dbmdz/bert-base-italian-xxl-cased")
model = AutoModel.from_pretrained("dbmdz/bert-base-italian-xxl-cased")
# 2D array, one line per sentence containing the embedding of the first token
encoded_sentences = torch.stack([model(**tokenizer(s, return_tensors='pt'))[0][0][0]
for s in sentences]).detach().numpy()
regr = MLPRegressor()
regr.fit(encoded_sentences, labels)
通过这种方式,我可以通过输入编码句子来训练神经网络。然而,这种方法显然没有微调基础 BERT 模型。有谁能够帮我?如何构建一个可以完全微调的模型(可能在 pytorch 中或使用 Huggingface 库)?
【问题讨论】:
【参考方案1】:如果要调整 BERT 模型本身,则需要修改模型的参数。为此,您很可能希望使用 PyTorch 进行工作。下面是一些粗略的伪代码来说明:
from torch.optim import SGD
model = ... # whatever model you are using
parameters = model.parameters() # or some more specific set of parameters
optimizer = SGD(parameters,lr=.01) # or whatever optimizer you want
optimizer.zero_grad() # boiler-platy pytorch function
input = ... # whatever the appropriate input for your task is
label = ... # whatever the appropriate label for your task is
loss = model(**input, label) # usuall loss is the first item returned
loss.backward() # calculates gradient
optim.step() # runs optimization algorithm
我省略了所有相关的细节,因为它们非常繁琐且特定于您的具体任务。 Huggingface 有一篇不错的文章,详细介绍了 here,当您使用任何 pytorch 东西时,您肯定会想参考一些 pytorch 文档。我强烈推荐pytorch blitz,然后再尝试使用它。
【讨论】:
好吧,你并没有谈论最相关的一点,即如何在 BERT 模型的单个输出之上添加一层(我不想全部使用)跨度> 抱歉,您的优化不适合底层模型似乎是最大的问题。也许下面的人有更多相关信息。【参考方案2】:有两种方法:由于您希望为类似于分类的下游任务微调模型,您可以直接使用:
BertForSequenceClassification
类。对输出维度 768 的逻辑回归层进行微调。
或者,您可以定义一个自定义模块,该模块基于预训练的权重创建一个 bert 模型并在其上添加层。
from transformers import BertModel
class CustomBERTModel(nn.Module):
def __init__(self):
super(CustomBERTModel, self).__init__()
self.bert = BertModel.from_pretrained("dbmdz/bert-base-italian-xxl-cased")
### New layers:
self.linear1 = nn.Linear(768, 256)
self.linear2 = nn.Linear(256, 3) ## 3 is the number of classes in this example
def forward(self, ids, mask):
sequence_output, pooled_output = self.bert(
ids,
attention_mask=mask)
# sequence_output has the following shape: (batch_size, sequence_length, 768)
linear1_output = self.linear1(sequence_output[:,0,:].view(-1,768)) ## extract the 1st token's embeddings
linear2_output = self.linear2(linear2_output)
return linear2_output
tokenizer = AutoTokenizer.from_pretrained("dbmdz/bert-base-italian-xxl-cased")
model = CustomBERTModel() # You can pass the parameters if required to have more flexible model
model.to(torch.device("cpu")) ## can be gpu
criterion = nn.CrossEntropyLoss() ## If required define your own criterion
optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()))
for epoch in epochs:
for batch in data_loader: ## If you have a DataLoader() object to get the data.
data = batch[0]
targets = batch[1] ## assuming that data loader returns a tuple of data and its targets
optimizer.zero_grad()
encoding = tokenizer.batch_encode_plus(data, return_tensors='pt', padding=True, truncation=True,max_length=50, add_special_tokens = True)
outputs = model(input_ids, attention_mask=attention_mask)
outputs = F.log_softmax(outputs, dim=1)
input_ids = encoding['input_ids']
attention_mask = encoding['attention_mask']
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
【讨论】:
以上是关于在 Huggingface BERT 模型之上添加密集层的主要内容,如果未能解决你的问题,请参考以下文章
如何在 HuggingFace Transformers 库中获取中间层的预训练 BERT 模型输出?
输入文件应该如何格式化以进行语言模型微调(BERT 通过 Huggingface Transformers)?
pytorch+huggingface实现基于bert模型的文本分类(附代码)
在训练 Bert 二进制分类模型时,Huggingface 变形金刚返回“ValueError:要解包的值太多(预期为 2)”