前言
在訓練深度學習模型時,常想一窺網絡結構中的attention層權重分布,觀察序列輸入的哪些詞或者詞組合是網絡比較care的。在小論文中主要研究了關於詞性POS對輸入序列的注意力機制。同時對比實驗采取的是words的self-attention機制。
效果
下圖主要包含兩列:word_attention是self-attention機制的模型訓練結果,POS_attention是詞性模型的訓練結果。
可以看出,相對於word_attention,POS的注意力機制不僅能夠捕捉到評價的aspect,也能根據aspect關聯的詞借助情感語義表達的詞性分布,care到相關詞性的情感詞。
核心代碼
可視化樣例
# coding: utf-8
def highlight(word, attn):
html_color = '#%02X%02X%02X' % (255, int(255*(1 - attn)), int(255*(1 - attn)))
return '<span style="background-color: {}">{}</span>'.format(html_color, word)
def mk_html(seq, attns):
html = ""
for ix, attn in zip(seq, attns):
html += ' ' + highlight(
ix,
attn
)
return html + "<br>"
from IPython.display import HTML, display
batch_size = 1
seqs = [["這", "是", "一個", "測試", "樣例", "而已"]]
attns = [[0.01, 0.19, 0.12, 0.7, 0.2, 0.1]]
for i in range(batch_size):
text = mk_html(seqs[i], attns[i])
display(HTML(text))
接入model
需要在model的返回列表中,添加attention_weight的輸出,理論上維度應該和輸入序列的長度是一致的。
# load model
import torch
# if you train on gpu, you need to move onto cpu
model = torch.load("../docs/model_chk/2018-11-07-02:45:37", map_location=lambda storage, location: storage)
from torch.autograd import Variable
for batch_idx, samples in enumerate(test_loader, 0):
v_word = Variable(samples['word_vec'])
v_final_label = samples['top_label']
model.eval()
final_probs, att_weight = model(v_word, v_pos)
batch_words = toWords(samples["word_vec"].numpy(), idx_word) # id轉化為word
batch_att = getAtten(batch_words, att_weight.data.numpy()) # 去除padding詞,根據words的長度截取attention
labels = toLabel(samples['top_label'].numpy()) # 真實標簽
pre_labels = toLabel(final_probs.data.numpy() >= 0.5) # 預測標簽
for i in range(len(batch_words)):
text = mk_html(batch_words[i], batch_att[i])
print(labels[i], pre_labels[i])
display(HTML(text))
總結
- 建議把可視化獨立出來,用jupyter-notebook編輯,方便分段調試和copy;同時因為是借助html渲染的,所以需要notebook
- 項目代碼我后期后同步到github上,歡迎一起交流