如何可视化bert的注意力权重
目录
参考链接:
- bertviz github
- 使用指南:BERT可视化工具bertviz体验
- 一些bert中存在的模式解析:Deconstructing BERT, Part 2: Visualizing the Inner Workings of Attention,最强NLP模型BERT可视化学习
一些观察到的模式
1. 以定界符为中心的注意力模式(eg,第 7 层、第 3 个头):Delimiter-focused attention patterns
- 当注意力头在输入句子中找不到要关注的任何其他内容时,它会关注[SEP]标记。那么,BERT 究竟是如何锁定[SEP]令牌的呢?(对于每个查询词的q向量,和其他所有词的k向量,一起确定这个查询词对于其他词的关注分数,正值呈蓝色,负值呈橙色,颜色强度表示幅度。)
- 在Key列中,[SEP]两次出现的key 向量带有一个独特的特征:它们都有很少量具有强正(蓝色)或强负(橙色)值,以及大量的神经元的值都是接近零的值(浅蓝色/橙色或白色),之所以对[SEP]的得分高,是因为the的查询向量在[SEP]的活跃维度(强蓝和强橙)匹配上了,其他维度的查询向量本身也比较微弱,所以和其他的词的匹配程度不高。
- 因此,似乎 BERT 已将一小组神经元指定为“[SEP]-匹配神经元”,并且查询向量被分配的值与这些位置的[SEP]关键向量相匹配。结果就是以[SEP]为中心的注意力模式。
2. 词袋注意模式 Bag of Words attention pattern(第0层,第0个头)
-
在这个模式下,注意力在同一个句子中的所有单词上相当平均地分配。BERT 本质上是通过对同一个句子中的词嵌入进行(几乎)平均来计算词袋的嵌入。
-
那么 BERT 如何巧妙地处理查询和键以形成这种注意力模式呢?让我们再次转向neuron view:在q×k列中我们可以很明显的看到每个向量中只有少量的(大概2-4个)主导了相关分数(强蓝色or强橙色),
-
当q和k向量在同一个句子中时(在本例中为第一个句子),会在qxk向量的某些位置匹配成功显示出强蓝色。当 query 和 key vector 在不同的句子中时,会在qxk向量会在相同的位置上显示出强橙色。--》 对于q和k向量,有一些位置是专门进行句子区分的。
3. 下一个词的注意模式 Next-word attention patterns(eg,layer2,head0)
- 在下一个词的注意力模式中,几乎所有的注意力都集中在输入序列中的下一个词上,除了[SEP]和[CLS]标记。模型会关注下一个单词是有道理的,因为相邻的单词通常与理解单词在上下文中的含义最相关。
- 让我们检查一下neuron view:我们看到“the”的query向量和“store”(下一个词)的key向量的乘积在大多数神经元中都是强正的。对于下一个标记以外的标记,键查询产品包含正值和负值的某种组合。结果是“the”和“store”之间的注意力得分很高。
- 下一个词注意模式和前2种模式不同(以定界符为中心和以句子为中心),前2种模式中,是query和key向量中某些少量的神经元位置决定的分数(对于这两种模式,只需要几个神经元,因为模式非常简单)。但是下一个词注意模式,对于一个给定位置,需要跟踪 512 个词来确定哪个词是next word。如果希望达成给下一个词最高注意力分数的目的,模型需要生成query和key向量,使得给定query向量与512 种可能性中的唯一key向量相匹配,使用一小部分神经元很难实现这一点。
- 具体,bert是通过position embedding 来确定这一点的。
4. 6种模式(未完待续)
Deconstructing BERT: Distilling 6 Patterns from 100 Million Parameters
左图中,[SEP]指向了[CLS],而非“at”,也就是说,指向下一个单词的这种模式只在句子中起作用,而在句子间的效果较弱。
代码(保存成html)
from transformers import AutoTokenizer, AutoModel, utils
from bertviz import model_view, head_view
utils.logging.set_verbosity_error() # Suppress standard warnings
model_name='/downloads/bert-base-chinese'
input_text = item['title']+item['key_word']
tokenizer = AutoTokenizer.from_pretrained('/downloads/bert-base-chinese')
tokenizer.add_special_tokens({ "additional_special_tokens": [ "[unused1]", "[unused2]", "[unused3]"] })
model = AutoModel.from_pretrained(model_name, output_attentions=True) # Configure model to return attention values
inputs = tokenizer.encode(input_text, return_tensors='pt') # Tokenize input text
print('inputs:', inputs)
outputs = model(inputs) # Run model
attention = outputs[-1] # Retrieve attention from model outputs
tokens = tokenizer.convert_ids_to_tokens(inputs[0]) # Convert input ids to token strings
print('tokens:', tokens)
# print('attention:',attention)
# model_view(attention, tokens) # Display model view
html_head_view = head_view(attention, tokens, html_action='return')
with open("views/bert.html", 'w') as file:
file.write(html_head_view.data)