精通 Transformers(四)(2)https://developer.aliyun.com/article/1510720
使用 BertViz 进行多尺度注意力头的可视化
现在,我们将编写一些代码来使用 BertViz 可视化头,这是一个可视化 Transformer 模型中注意力的工具,就像 exBERT 一样。它是由 Jesse Vig 在 2019 年开发的(Transformer 模型中注意力的多尺度可视化,Jesse Vig,2019)。它是 Tensor2Tensor 可视化工具(Jones, 2017)工作的延伸。我们可以通过 Python 应用程序编程接口(API)监视模型的内部部分进行多尺度定性分析。BertViz 的优点在于,我们可以通过 Python 应用程序编程接口(API)使用大多数 Hugging Face 托管的模型(如双向编码器转换器表示(BERT)、生成的预训练转换器(GPT)和跨语言语言模型(XLM))。因此,我们也将能够使用非英语模型或任何预训练模型。我们将很快一起检查这样的示例。您可以从以下 GitHub 链接访问 BertViz 资源和其他信息:github.com/jessevig/bertviz
。
与 exBERT 类似,BertViz 在一个界面中可视化注意力头。此外,它支持鸟瞰视角和低级别的神经元视角,我们可以观察个别神经元如何相互作用以构建注意力权重。一个有用的演示视频可在以下链接找到:vimeo.com/340841955
。
在开始之前,我们需要安装必要的库,如下所示:
!pip install bertviz ipywidgets
然后我们导入以下模块:
from bertviz import head_view from Transformers import BertTokenizer, BertModel
BertViz 支持三种视图:头视图、模型视图和神经元视图。让我们逐一检查这些视图。不过,首先需要指出的是,在 exBERT 中,我们从 1 开始索引层和头。但在 BertViz 中,我们从 0 开始索引,与 Python 编程相同。如果我说 exBERT 中的一个 <9,9> 头,它的 BertViz 对应物是 <8,8>。
让我们从头视图开始。
注意力头视图
头视图是 BertViz 中我们在前一节中使用 exBERT 已经体验过的等价物。注意力头视图可视化基于一个或多个注意力头的注意力模式在所选层中:
- 首先,我们定义一个
get_bert_attentions()
函数,用于检索给定模型和给定句对的注意力和标记。函数定义如下代码块所示:
def get_bert_attentions(model_path, sentence_a, sentence_b): model = BertModel.from_pretrained(model_path, output_attentions=True) tokenizer = BertTokenizer.from_pretrained(model_path) inputs = tokenizer.encode_plus(sentence_a, sentence_b, return_tensors='pt', add_special_tokens=True) token_type_ids = inputs['token_type_ids'] input_ids = inputs['input_ids'] attention = model(input_ids, token_type_ids=token_type_ids)[-1] input_id_list = input_ids[0].tolist() tokens = tokenizer.convert_ids_to_tokens(input_id_list) return attention, tokens
- 在下面的代码片段中,我们加载了
bert-base-cased
模型,并检索了给定两个句子的标记和相应的注意力。然后我们在最后调用了head_view()
函数来可视化注意力。以下是代码执行:
model_path = 'bert-base-cased' sentence_a = "The cat is very sad." sentence_b = "Because it could not find food to eat." attention, tokens=get_bert_attentions(model_path, sentence_a, sentence_b) head_view(attention, tokens)
- 代码输出是一个界面,如下所示:
图 11.9 - BertViz 的头视图输出
图 11.9 左侧是首先出现的界面。在任何左侧的令牌上悬停将显示从该令牌出发的注意力。顶部的彩色块对应于注意力头。双击其中的任何一个将选择它并丢弃其余部分。较粗的注意力线表示更高的注意力权重。
请记住,在前面的 exBERT 示例中,我们观察到 <9,9> 头(由于索引的原因,在 BertViz 中等效于 <8, 8>)具有代词-先行关系。我们观察到相同的模式在 图 11.9 中,选择第 8 层和第 8 头。然后,当我们悬停在 它 上时,在 图 11.9 的右侧看到了界面,它 强烈关注 cat 和 it 令牌。那么,在其他预训练语言模型中我们能观察到这些语义模式吗?虽然其它模型中头部不一定完全相同,但一些头部可能会编码这些语义特性。我们也从最近的工作中得知,语义特征主要编码在较高的层中。 - 让我们在土耳其语言模型中寻找一个指代模式。以下代码加载了一个土耳其
bert-base
模型并取了一个句子对。我们在这里观察到,<8,8> 头在土耳其语言模型中具有与英语模型相同的语义特征,如下所示:
model_path = 'dbmdz/bert-base-turkish-cased' sentence_a = "Kedi çok üzgün." sentence_b = "Çünkü o her zamanki gibi çok fazla yemek yedi." attention, tokens=\ get_bert_attentions(model_path, sentence_a, sentence_b) head_view(attention, tokens)
- 从前面的代码中,
sentence_a
和sentence_b
意味着 The cat is sad 和 Because it ate too much food as usual,当悬停在 o(它)上时,它 关注 Kedi(猫),如下所示:
图 11.10 – 土耳其语言模型中的指代模式
除了 o 之外的所有其他标记大多数关注到了 SEP 分隔符标记,这是 BERT 架构中所有头部中的一种主导行为模式。 - 作为头视图的最后一个示例,我们将解释另一个语言模型,并继续查看模型视图特性。这次,我们选择
bert-base-german-cased
德语语言模型并将其可视化为输入——即,我们用于土耳其语的同一个句对的德语等价句对。 - 以下代码加载了一个德语模型,消耗了一对句子,并对其进行了可视化:
model_path = 'bert-base-german-cased' sentence_a = "Die Katze ist sehr traurig." sentence_b = "Weil sie zu viel gegessen hat" attention, tokens=\ get_bert_attentions(model_path, sentence_a, sentence_b) head_view(attention, tokens)
- 当我们检查头部时,我们可以再次在第 8 层中看到指代模式,但这次是在第 11 个头部。要选择 <8,11> 头部,从下拉菜单中选择第 8 层并双击最后的头部,如下所示:
图 11.11 – 德语语言模型中的指代关系模式
如你所见,在悬停在 sie 上时,你会看到对 Die Katze 的强烈关注。虽然这个 <8,11> 头是最强大的指代关系头(在计算语言学文献中被称为先行关系),这种关系可能已经传播到许多其他头中。为了观察它,我们必须逐个检查所有的头。
另一方面,BertViz 的模型视图功能让我们基本了解所有头一次看到。 让我们在下一节中看一下。
模型视图
模型视图允许我们全面查看所有头和层的注意力。 自注意力头以表格形式显示,行和列分别对应层和头。 每个头以可点击的缩略图形式呈现,其中包括注意力模型的总体形状。
这个视图可以告诉我们 BERT 是如何工作的,并且更容易解释。 许多最近的研究,比如BERTology 初级入门:我们知道 BERT 如何工作,Anna Rogers,Olga Kovaleva,Anna Rumshisky,2021,找到了一些关于层行为的线索并达成了共识。 我们已经在解释注意头部分列出了其中一些。 您可以使用 BertViz 的模型视图自行测试这些事实。
让我们查看一下我们刚刚使用的德语语言模型,如下:
- 首先,导入以下模块:
from bertviz import model_view from Transformers import BertTokenizer, BertModel
- 现在,我们将使用 Jesse Vig 开发的
show_model_view()
包装函数。 您可以在以下链接找到原始代码:github.com/jessevig/bertviz/blob/master/notebooks/model_view_bert.ipynb
。 - 您还可以在我们书本的 GitHub 链接中找到函数定义,链接地址为
github.com/PacktPublishing/Mastering-Transformers/tree/main/CH11
。 这里只是放出函数头部:
def show_model_view(model, tokenizer, sentence_a, sentence_b=None, hide_delimiter_attn=False, display_mode="dark"): . . .
- 让我们再次加载德语模型。 如果您已经加载了它,可以跳过前五行。 这是您需要的代码:
model_path='bert-base-german-cased' sentence_a = "Die Katze ist sehr traurig." sentence_b = "Weil sie zu viel gegessen hat" model = BertModel.from_pretrained(model_path, output_attentions=True) tokenizer = BertTokenizer.from_pretrained(model_path) show_model_view(model, tokenizer, sentence_a, sentence_b, hide_delimiter_attn=False, display_mode="light")
- 这是输出结果:
图 11.12 – 德语语言模型的模型视图
这个视图帮助我们轻松观察到许多模式,比如下一个令牌(或上一个令牌)的注意力模式。 正如我们在解释注意头部分中提到的,令牌通常倾向于关注定界符,具体来说是在下层关注 CLS 定界符,在上层关注 SEP 定界符。 因为这些令牌未被屏蔽,它们可以促进信息的流动。 在最后的层中,我们只观察到 SEP 定界符为中心的注意力模式。 可以推测,SEP 用于收集段级信息,然后用于跨句任务,比如下一句预测(NSP)或编码句级含义。
另一方面,我们观察到指代关系模式主要编码在 <8,1>, <8,11>, <10,1>, and <10,7> 头部。 再次可以明确说,<8, 11> 头部是编码德语模型中指代关系的最强头部,我们已经讨论过。 - 当您点击该缩略图时,您将看到相同的输出,如下:
图 11.13 – 模型视图中<8,11>头部的放大图
你可以再次悬停在标记上,查看映射关系。
我认为头视图和模型视图的工作已经足够了。现在,让我们通过神经元视图拆解模型,并试图理解这些头部是如何计算权重的。
神经元视图
到目前为止,我们已经可视化了给定输入的计算权重。神经元视图可视化了查询中的神经元和关键向量,以及基于相互作用计算标记之间的权重。我们可以追踪任意两个标记之间的计算阶段。
接下来,我们将加载德语模型,并可视化刚刚处理过的同一句对,以保持连贯性。我们执行以下代码:
from bertviz.Transformers_neuron_view import BertModel, BertTokenizer from bertviz.neuron_view import show model_path='bert-base-german-cased' sentence_a = "Die Katze ist sehr traurig." sentence_b = "Weil sie zu viel gegessen hat" model = BertModel.from_pretrained(model_path, output_attentions=True) tokenizer = BertTokenizer.from_pretrained(model_path) model_type = 'bert' show(model, model_type, tokenizer, sentence_a, sentence_b, layer=8, head=11)
这就是输出:
图 11.14 – 核指关系模式的神经元视图(头部<8,11>)
这个视图帮助我们追踪了我们在左边选择的sie标记到右边其他标记的注意力计算。正值是蓝色的,负值是橙色的。颜色的强度代表了数值的大小。查询sie与Die和Katze的键非常相似。如果你仔细观察图案,你会注意到这些向量有多么相似。因此,它们的点积要比其他的比较更高,这建立了这些标记之间强烈的注意力。我们还可以追踪点积和 Softmax 函数的输出,当我们向右移动时。当点击左边的其他标记时,你也可以追踪其他的计算。
现在,让我们为相同的输入选择一个头部承载的下一个标记的注意力模式,并对其进行追踪。为此,我们选择*<2,6>* 头部。在这个模式中,几乎所有的注意力都集中在下一个字上。我们再次点击sie标记,如下所示:
图 11.15 – 下一个标记注意力模式的神经元视图(<2,6>头部)
现在,sie 标记的注意力集中在下一个标记上,而不是它自己的先行词(Die Katze)。当我们仔细观察查询和候选键时,我们会发现与sie的查询最相似的键是下一个标记zu。同样地,在这过程中我们可以看到点乘和 Softmax 函数是如何应用的。
在下一节,我们将简要讨论解释Transformers(Transformers)的探针分类器。
通过解读Transformers的探针分类器理解 BERT 的内部部分
DL 学到的内容的不透明性导致了许多关于这些模型解释的研究。我们试图回答这样的问题:Transformer 模型的哪些部分负责某些语言特征,或者输入的哪些部分导致模型做出特定的决定。为了做到这一点,除了可视化内部表示之外,我们还可以对表示进行分类器训练,以预测一些外部形态、句法或语义属性。因此,我们可以确定是否将内部 表示 与外部 属性 关联起来。模型的成功训练将是这种关联的定量证据——即,语言模型已经学会了与外部属性相关的信息。这种方法称为 探测分类器 方法,是自然语言处理和其他 DL 研究中的一种重要分析技术。基于注意力的探测分类器以注意力映射作为输入,并预测外部属性,如共指关系或头部修饰关系。
如前面的实验所示,我们可以使用get_bert_attention()
函数获取给定输入的自注意权重。我们可以直接将这些权重传递到分类管道中,而不是将它们可视化。因此,在监督下,我们可以确定哪个头适合哪个语义特征——例如,我们可以通过标记数据找出哪些头适合共指。
现在,让我们转向模型跟踪部分,这对于构建高效的模型至关重要。
精通 Transformers(四)(4)https://developer.aliyun.com/article/1510723