如何用bert嵌入代替glove/fasttext等静态嵌入训练神经网络模型?

2024-09-29 03:33:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一些头脑,以训练一个传统的神经网络模型与伯特嵌入动态生成(伯特上下文化嵌入,它产生不同的嵌入同一个词时,在不同的上下文)。在

在正常的神经网络模型中,我们会用glow或fasttext嵌入来初始化模型,比如

import torch.nn as nn 

embed = nn.Embedding(vocab_size, vector_size)

embed.weight.data.copy_(some_variable_containing_vectors)

我不想像这样复制静态向量并将其用于训练,而是希望将每个输入传递到一个BERT模型,并动态生成单词的嵌入,并将它们馈送给模型进行训练。在

那么,我应该改变模型中的前向函数以合并这些嵌入吗?在

任何帮助都将不胜感激!在


Tags: 模型importsizeas动态神经网络embednn
1条回答
网友
1楼 · 发布于 2024-09-29 03:33:40

如果你用的是Pythorch。您可以使用https://github.com/huggingface/pytorch-pretrained-BERT,这是Pytorch最流行的BERT实现(它也是一个pip包!)。在这里我只想概述一下如何正确地使用它。在

对于这个特定的问题,有两种方法-显然不能使用Embedding层:

  1. 您可以将生成的BERT嵌入合并到数据预处理管道中。您将需要使用BERT自己的标记器和wordtoids字典。回购的README有预处理的例子。在

您可以编写一个循环来为这样的字符串生成BERT令牌(假设-因为BERT消耗大量GPU内存):

(注意:为了更恰当,你还应该加上注意面具——它是1&0的LongTensor,用来掩盖句子长度)

import torch
from pytorch_pretrained_bert import BertTokenizer, BertModel

batch_size = 32
X_train, y_train = samples_from_file('train.csv') # Put your own data loading function here
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
X_train = [tokenizer.tokenize('[CLS] ' + sent + ' [SEP]') for sent in X_train] # Appending [CLS] and [SEP] tokens - this probably can be done in a cleaner way
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]
results = 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)
        results[stidx:stidx + batch_size,:] = pooled_output.cpu()

之后,您将获得results张量,该张量包含计算的嵌入量,您可以将其用作模型的输入。在

为此提供了完整的(更合适的)代码here

这种方法的优点是不必每个历元都重新计算这些嵌入。在

使用这种方法,例如对于分类,您的模型应该只包含Linear(bert_model.config.hidden_size, num_labels)层,模型的输入应该是上面代码中的results张量

  1. 第二种,而且可以说是更干净的方法:如果您查看repo,您可以发现有各种任务的包装器(例如BertForSequenceClassification)。实现从BertPretrainedModel继承并利用来自repo的各种Bert类的定制类也应该很容易实现。在

例如,您可以使用:

^{2}$

之后,您可以继续进行预处理,直到生成令牌ID为止。然后您可以训练整个模型(但是学习率很低,例如adam3e-5 for batch_size=32)

有了这个你可以微调BERT的嵌入本身,或者使用一些技术,比如冻结BERT几个时期来只训练分类器,然后解冻到微调等等,但是它的计算成本也更高。在

repo中也提供了一个例子

相关问题 更多 >