Viv*_*ian 7 python nlp tensorflow bert-language-model huggingface-transformers
该HuggingFace BERT TensorFlow实施使我们能够进在预先计算的地方嵌入查找是原产于BERT的嵌入。这是使用模型call方法的可选参数inputs_embeds(代替input_ids)完成的。为了测试这一点,我想确保如果我确实输入了 BERT 的嵌入查找,我会得到与输入input_ids它们自己相同的结果。
BERT 嵌入查找的结果可以通过将 BERT 配置参数设置output_hidden_states为True并从该call方法的最后一个输出中提取第一个张量来获得。(其余 12 个输出对应于 12 个隐藏层中的每一个。)
因此,我编写了以下代码来测试我的假设:
import tensorflow as tf
from transformers import BertConfig, BertTokenizer, TFBertModel
bert_tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
input_ids = tf.constant(bert_tokenizer.encode("Hello, my dog is cute", add_special_tokens=True))[None, :]
attention_mask = tf.stack([tf.ones(shape=(len(sent),)) for sent in input_ids])
token_type_ids = tf.stack([tf.ones(shape=(len(sent),)) for sent in input_ids])
config = BertConfig.from_pretrained('bert-base-uncased', output_hidden_states=True)
bert_model = TFBertModel.from_pretrained('bert-base-uncased', config=config)
result = bert_model(inputs={'input_ids': input_ids,
'attention_mask': attention_mask,
'token_type_ids': token_type_ids})
inputs_embeds = result[-1][0]
result2 = bert_model(inputs={'inputs_embeds': inputs_embeds,
'attention_mask': attention_mask,
'token_type_ids': token_type_ids})
print(tf.reduce_sum(tf.abs(result[0] - result2[0]))) # 458.2522, should be 0
Run Code Online (Sandbox Code Playgroud)
同样,该call方法的输出是一个元组。这个元组的第一个元素是BERT最后一层的输出。因此,我期望result[0]和result2[0]匹配。为什么不是这样?
我使用的是 Python 3.6.10tensorflow版本 2.1.0 和transformers版本 2.5.1。
编辑:查看HuggingFace 的一些代码,似乎在input_ids给定时查找或在inputs_embeds给定时分配的原始嵌入被添加到位置嵌入和标记类型嵌入中,然后再被送入后续层。如果是这样的话,那么它可能是可能的,就是我从获得result[-1][0]的原始嵌入加上位置和令牌类型的嵌入。这意味着,他们错误地得到再次加入时,我养活result[-1][0]的inputs_embeds,以便计算result2。
有人可以告诉我是否是这种情况,如果是,请解释如何获取位置和标记类型嵌入,以便我可以将它们减去?以下是我根据此处给出的方程得出的位置嵌入(但根据BERT 论文,实际上可能会学习位置嵌入,因此我不确定这些是否有效):
import numpy as np
positional_embeddings = np.stack([np.zeros(shape=(len(sent),768)) for sent in input_ids])
for s in range(len(positional_embeddings)):
for i in range(len(positional_embeddings[s])):
for j in range(len(positional_embeddings[s][i])):
if j % 2 == 0:
positional_embeddings[s][i][j] = np.sin(i/np.power(10000., j/768.))
else:
positional_embeddings[s][i][j] = np.cos(i/np.power(10000., (j-1.)/768.))
positional_embeddings = tf.constant(positional_embeddings)
inputs_embeds += positional_embeddings
Run Code Online (Sandbox Code Playgroud)
我对添加位置和令牌类型嵌入的直觉被证明是正确的。仔细查看代码后,我替换了该行:
inputs_embeds = result[-1][0]
Run Code Online (Sandbox Code Playgroud)
与行:
embeddings = bert_model.bert.get_input_embeddings().word_embeddings
inputs_embeds = tf.gather(embeddings, input_ids)
Run Code Online (Sandbox Code Playgroud)
现在,正如预期的那样,差异为 0.0。
| 归档时间: |
|
| 查看次数: |
948 次 |
| 最近记录: |