Добавьте плотный слой поверх модели Huggingface BERT
Я хочу добавить плотный слой поверх простого преобразователя модели BERT, выводящего необработанные скрытые состояния, а затем точно настроить полученную модель. В частности, я использую эту базовую модель. Вот что должна делать модель:
- Закодируйте предложение (вектор с 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), которую можно полностью настроить?
Ответы
Это можно сделать двумя способами: поскольку вы хотите настроить модель для последующей задачи, подобной классификации, вы можете напрямую использовать:
BertForSequenceClassificationкласс. Выполняет тонкую настройку слоя логистической регрессии для выходного измерения 768.
В качестве альтернативы вы можете определить собственный модуль, который создает модель берта на основе предварительно натренированных весов и добавляет слои поверх нее.
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()
Если вы хотите настроить саму модель 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 есть хорошая статья, в которой подробно рассказывается об этом здесь , и вы обязательно захотите обратиться к некоторой документации по pytorch, когда используете любые материалы pytorch. Я настоятельно рекомендую Pytorch Blitz, прежде чем пытаться сделать с ним что-нибудь серьезное.