Python 如何获得特定层的梯度wrt';s输出pytorch

Python 如何获得特定层的梯度wrt';s输出pytorch,python,huggingface-transformers,Python,Huggingface Transformers,这背后的想法是,我想用伯特模型尝试一些老式的梯度上升式可视化 我想知道输入对特定层的特定维度的影响。因此,我将特定层的特定维度的输出梯度wrt作为第一个单词嵌入层的输出 在这里,我能做的最好的事情是: from transformers import BertTokenizer, BertModel model = BertModel.from_pretrained('bert-base-uncased', output_attentions=True,output_hidden_states=

这背后的想法是,我想用伯特模型尝试一些老式的梯度上升式可视化

我想知道输入对特定层的特定维度的影响。因此,我将特定层的特定维度的输出梯度wrt作为第一个单词嵌入层的输出

在这里,我能做的最好的事情是:

from transformers import BertTokenizer, BertModel
model = BertModel.from_pretrained('bert-base-uncased', output_attentions=True,output_hidden_states=True)
tokenizer = BertTokenizer.from_pretrained(model_version, do_lower_case=True)
s = 'I want to sleep'
inputs = tokenizer.encode_plus(s,return_tensors='pt', add_special_tokens=False,is_pretokenized=True)
input_ids = inputs['input_ids']
output = model(input_ids)
hidden_states = output[-2]

X = hidden_states[0] #embedding space, shape: [1,4,768] (batch_size,sentence_length,embedding dimension)
y = hidden_states[3][0][0][0] ##the 0th position and 0th dimension of output of 3rd hidden layer. Dimension should just be [1], a scalar.

torch.autograd.grad(y,X,retain_graph=True, create_graph=True) #I take the gradient of y wrt. Since y is scalar. The dimension of the gradient is just the dimension of X. 
然而,这还不够好。我想梯度wrt的实际单词嵌入层。然而,Transformer的嵌入包含“位置嵌入”和“令牌类型嵌入”。下面是第一层嵌入的代码:

class BertEmbeddings(nn.Module):
    """Construct the embeddings from word, position and token_type embeddings.
    """
    def __init__(self, config):
        super(BertEmbeddings, self).__init__()
        self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=0)
        self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.hidden_size)
        self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)

        # self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load
        # any TensorFlow checkpoint file
        self.LayerNorm = BertLayerNorm(config.hidden_size, eps=config.layer_norm_eps)
        self.dropout = nn.Dropout(config.hidden_dropout_prob)

    def forward(self, input_ids, token_type_ids=None, position_ids=None):
        seq_length = input_ids.size(1)
        if position_ids is None:
            position_ids = torch.arange(seq_length, dtype=torch.long, device=input_ids.device)
            position_ids = position_ids.unsqueeze(0).expand_as(input_ids)
        if token_type_ids is None:
            token_type_ids = torch.zeros_like(input_ids)

        words_embeddings = self.word_embeddings(input_ids)
        position_embeddings = self.position_embeddings(position_ids)
        token_type_embeddings = self.token_type_embeddings(token_type_ids)

        embeddings = words_embeddings + position_embeddings + token_type_embeddings
        embeddings = self.LayerNorm(embeddings)
        embeddings = self.dropout(embeddings)
        return embeddings
理想情况下,我希望梯度wrt只是“单词嵌入”,而不是wrt“单词嵌入+位置嵌入+标记类型嵌入”,后面是LayerForm和dropout


我想我可以通过修改或更改模型来做到这一点。有没有办法在不更改模型的情况下实现这一点?

我正在尝试做类似的事情。但我不明白为什么您必须这样做?
y=hidden_states[3][0][0]
。你能稍微解释一下这一行吗?例如,如果我试图将第1层w.r.t的梯度作为输出(让我们说“睡眠”),为什么我必须检查第3层的输出?它不应该是第1层,下一层吗?很抱歉回答得太晚。注意y是我的“输出”",不是我取梯度的输入。我想你的输出是一些分类任务。我问这个问题的重点是试图找出伯特的隐藏状态是否有语义意义。我们发现伯特的潜在空间不同于CNN,没有语义意义。需要使用一些统计方法来分离吃我们的那些语义。对于你们当中感兴趣的人来说,这是我们将这些语义分开的努力: