我正在寻找一些头脑,以训练一个传统的神经网络模型与伯特嵌入是动态生成的(伯特上下文嵌入,为同一个词生成不同的嵌入时,不同的上下文)。
在正常的神经网络模型中,我们会用手套或fasttext嵌入来初始化模型,比如,

import torch.nn as nn

embed = nn.Embedding(vocab_size, vector_size)

embed.weight.data.copy_(some_variable_containing_vectors)

我不想复制这样的静态向量并将其用于训练,而是希望将每个输入传递给一个BERT模型,并生成单词的动态嵌入,然后将它们馈送给模型进行训练。
那么,我应该改变模型中的前向函数来合并这些嵌入吗?
任何帮助都将不胜感激!

最佳答案

如果你用的是火把您可以使用https://github.com/huggingface/pytorch-pretrained-BERT这是pytorch最流行的bert实现(它也是一个pip包!)在这里,我将概述如何正确使用它。
对于这个特殊的问题,有两种方法-显然不能使用Embedding层:
您可以将生成的BERT嵌入合并到数据预处理管道中您需要使用BERT自己的标记器和word-to-ids字典回购协议的README有关于预处理的例子。
您可以编写一个循环来为这样的字符串生成bert令牌(假设-因为bert消耗了大量gpu内存):
(注意:为了更合适,你还应该加上注意遮罩-这是1&0的长传感器遮罩句子长度)

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张量。
第二种,也可以说是更干净的方法:如果您查看repo,您可以找到各种任务的包装器(例如BertForSequenceClassification)。实现从BertPretrainedModel继承并利用repo中的各种bert类的自定义类也应该很容易。
例如,您可以使用:
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', labels=num_labels) # Where num_labels is the number of labels you need to classify.

之后,您可以继续预处理,直到生成令牌ID。然后你可以训练整个模型(但是学习率很低,例如adam 3e-5 forbatch_size=32)
有了它,你可以对bert的嵌入本身进行微调,或者使用冻结bert等技术来训练分类器,然后解冻以进行微调,等等,但这也会增加计算成本。
repo中也提供了一个例子。

07-24 17:16