【问题标题】:Gradient of the loss of DistilBERT for measuring token importanceDistilBERT 损失梯度用于衡量代币重要性
【发布时间】:2020-08-03 05:12:37
【问题描述】:

我正在尝试访问 DistilBERT 中关于第一层中每个注意力权重的损失梯度。当requires_grad=True 时,我可以通过以下代码访问输出权重矩阵的计算梯度值

loss.backward()
for name, param in model.named_parameters():
    if name == 'transformer.layer.0.attention.out_lin.weight':
       print(param.grad)  #shape is [768,768]

其中model 是加载的 distilbert 模型。 我的问题是如何获得关于 [SEP] 或 [CLS] 或其他令牌注意力的梯度?我需要它在以下链接中重现有关“注意 [SEP] 的基于梯度的特征重要性估计”的图: https://medium.com/analytics-vidhya/explainability-of-bert-through-attention-7dbbab8a7062

以下出于相同目的提出了类似的问题,但这不是我的问题: BERT token importance measuring issue. Grad is none

【问题讨论】:

    标签: pytorch transformer attention-model huggingface-transformers bert-language-model


    【解决方案1】:

    默认情况下,渐变只为参数保留,基本上只是为了节省内存。如果你需要计算图内部节点的梯度,你需要在调用backward()之前有各自的张量,并添加一个将在后向传递中执行的钩子。

    来自PyTorch forum的最小解决方案:

    yGrad = torch.zeros(1,1)
    def extract(xVar):
        global yGrad
        yGrad = xVar    
    
    xx = Variable(torch.randn(1,1), requires_grad=True)
    yy = 3*xx
    zz = yy**2
    
    yy.register_hook(extract)
    
    #### Run the backprop:
    print (yGrad) # Shows 0.
    zz.backward()
    print (yGrad) # Show the correct dzdy
    

    在这种情况下,梯度存储在一个全局变量中,在 PyTorch 将它们从图形本身中删除后它们会持续存在。

    【讨论】:

    • 非常感谢您的回复。现在我看到了如何保存中间节点的梯度。另一个问题是 DistilBERT 中的每一层都调用一个“MultiHeadSelfAttention”类的实例来本地计算注意力权重。因此,调用 register_hook() 的唯一位置是在计算权重的类的 forward() 内部。如果我们假设我们的 DistilBERT 模型有 6 层,那么 register_hook() 会被调用 6 次。在这种情况下,yGrad 将是一个保存所有层权重梯度的列表。在 forward() 中重复调用 register_hook() 是否正确?谢谢
    • 是的,那么只需 yGrad 将列表附加到钩子中的列表。
    • 谢谢,一个快速的问题:如果我使用 list 来保持每一层的梯度,它是否以与层从 1 到 6 相同的顺序附加,或者因为反向梯度计算它保持梯度值倒序,即第 6 层作为列表中的第一个元素,第 1 层作为最后一个元素?
    • 按预约顺序排列。
    猜你喜欢
    • 1970-01-01
    • 2020-05-03
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 2016-11-29
    • 2020-08-25
    相关资源
    最近更新 更多