Si vous utilisez Pytorch. Vous pouvez utiliser https://github.com/huggingface/pytorch-pretrained-BERT qui est la mise en œuvre BERT la plus populaire pour Pytorch (c'est aussi un package pip!). Ici, je vais simplement expliquer comment l'utiliser correctement.
Pour ce problème particulier, il y a 2 approches - où vous ne pouvez évidemment pas utiliser la couche Embedding
:
- Vous pouvez incorporer la génération d'incorporations BERT dans votre pipeline de prétraitement des données. Vous devrez utiliser le propre tokenizer de BERT et le dictionnaire de mots-vers-ids. Le README du dépôt contient des exemples sur le prétraitement.
Vous pouvez écrire une boucle pour générer des jetons BERT pour des chaînes comme celle-ci (en supposant - car BERT consomme beaucoup de mémoire GPU) :
(Remarque : pour être plus correct, vous devriez également ajouter des masques d'attention - qui sont des LongTensor de 1 & 0 masquant les longueurs de phrases)
import torch
from pytorch_pretrained_bert import BertTokenizer, BertModel
taille_lot = 32
X_train, y_train = echantillons_de_fichier('train.csv') # Mettez votre fonction de chargement de données ici
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
X_train = [tokenizer.tokenize('[CLS] ' + sent + ' [SEP]') for sent in X_train] # Ajout des jetons [CLS] et [SEP] - cela peut probablement être fait de manière plus propre
bert_model = BertModel.from_pretrained('bert-base-uncased')
bert_model = bert_model.cuda()
X_train_tokens = [tokenizer.convert_tokens_to_ids(sent) for sent in X_train]
resultats = torch.zeros((len(X_test_tokens), bert_model.config.hidden_size)).long()
with torch.no_grad():
for stidx in range(0, len(X_test_tokens), batch_size):
X = X_test_tokens[stidx:stidx + batch_size]
X = torch.LongTensor(X).cuda()
_, pooled_output = bert_model(X)
resultats[stidx:stidx + batch_size,:] = pooled_output.cpu()
Après quoi vous obtenez le tenseur resultats
qui contient les embeddings calculés, que vous pouvez utiliser comme entrée pour votre modèle.
Le code complet (et plus propre) pour cela est fourni ici
Cette méthode a l'avantage de ne pas avoir à recalculer ces embeddings à chaque époque.
Avec cette méthode, par exemple pour la classification, votre modèle ne devrait consister qu'en une couche Linear(bert_model.config.hidden_size, num_labels)
, les entrées du modèle devraient être le tenseur resultats
dans le code ci-dessus
- Deuxième méthode, et probablement plus propre : Si vous consultez le dépôt, vous trouverez des enveloppes pour diverses tâches (par exemple
BertForSequenceClassification
). Il devrait également être facile d'implémenter vos propres classes qui héritent de BertPretrainedModel
et utilisent les différentes classes Bert du dépôt.
Par exemple, vous pouvez utiliser :
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', labels=num_labels) # Où num_labels est le nombre d'étiquettes que vous devez classer.
Après quoi, vous pouvez continuer avec le prétraitement, jusqu'à la génération des ids de jetons. Ensuite, vous pouvez entraîner l'ensemble du modèle (mais avec un faible taux d'apprentissage par exemple Adam 3e-5 pour taille_lot
= 32)
Avec cela, vous pouvez affiner les embeddings de BERT lui-même, ou utiliser des techniques comme geler BERT pendant quelques époques pour entraîner uniquement le classifieur, puis dégeler pour affiner etc. Mais c'est aussi plus coûteux en termes de calcul.
Un exemple de ceci est également fourni dans le dépôt