Mushens Version von „Learning Deep Learning by Hands“ ist eine Lernnotiz, in der der Lernprozess aufgezeichnet wird. Für detaillierte Inhalte kaufen Sie bitte Bücher.
Link zum Video der B-Station,
Open-Source-Tutorial-Link
Aufmerksamkeitswert
Abschnitt 64 verwendet einen Gaußschen Kernel, um die Beziehung zwischen Abfragen und Schlüsseln zu modellieren . Der exponentielle Teil im Gaußschen Kernel kann als Aufmerksamkeitsbewertungsfunktion ( ) betrachtet werden , die als Bewertungsfunktionattention scoring function
bezeichnet wird . Anschließend wird die Ausgabe dieser Funktion zur Operation in die Softmax-Funktion eingegeben und die Wahrscheinlichkeitsverteilung des entsprechenden Werts berechnet Der Schlüssel (d. h. das Aufmerksamkeitsgewicht) wird ermittelt. . Die Ausgabe des endgültigen Aufmerksamkeitspoolings basiert auf der gewichteten Summe der Werte dieser Aufmerksamkeitsgewichte.
Die obige Abbildung zeigt, wie die Ausgabe des Aufmerksamkeitspoolings als gewichtete Summe von Werten berechnet wird, wobei α \alphaα bezeichnet die Aufmerksamkeitsbewertungsfunktion. Da Aufmerksamkeitsgewichte Wahrscheinlichkeitsverteilungen sind, ist die gewichtete Summe im Wesentlichen ein gewichteter Durchschnitt.
Die Längen von Abfrage, Schlüssel und Wert können unterschiedlich sein, Abfrage qi q_iQichund Schlüssel ki k_ikichDas Aufmerksamkeitsgewicht wird durch die Aufmerksamkeitsbewertungsfunktion α \alpha übergebenα ordnet zwei Vektoren Skalaren zu und wählt nach der Softmax-Operation ein anderesα \alphaα führt zu unterschiedlichen Aufmerksamkeitsbündelungsoperationen.
additive Aufmerksamkeit
Wenn Abfragen und Schlüssel unterschiedliche Längen haben, kann die additive Aufmerksamkeit als Bewertungsfunktion verwendet werden.
Skalierte Punktproduktaufmerksamkeit
Wenn die Abfrage und der Schlüssel dieselbe Länge haben, verwenden Sie das Skalarprodukt, um eine Bewertungsfunktion mit höherer Recheneffizienz zu erhalten, und dividieren Sie diese durch die Länge d, um die Länge weniger zu beeinflussen. (Unter der Annahme, dass sowohl die Abfrage als auch der Schlüssel unabhängige Zufallsvariablen mit einem Mittelwert von Null und einer Einheitsvarianz sind, hat das Skalarprodukt zweier Vektoren einen Mittelwert von 0 und eine Varianz d. Um sicherzustellen, dass die Varianz des Skalarprodukts unabhängig von der Vektorlänge 1 beträgt unabhängig von der Länge des Vektors, und teile dann das Skalarprodukt durch d \sqrt{d}DErhalten Sie die Aufmerksamkeit des skalierten Skalarprodukts ( scaled dot-product attention
).
Zusammenfassen
Die Aufmerksamkeitsbewertung ist die Ähnlichkeit zwischen Abfrage und Schlüssel, und die Aufmerksamkeitsgewichtung ist das Softmax-Ergebnis der Bewertung.
praktisches Lernen
Aufmerksamkeitsbewertungsfunktion
import math
import torch
from torch import nn
from d2l import torch as d2l
# 掩蔽softmax操作
def masked_softmax(X, valid_lens):
"""通过在最后一个轴上掩蔽元素来执行softmax操作"""
# X:3D张量,valid_lens:1D或2D张量
if valid_lens is None:
return nn.functional.softmax(X, dim=-1)
else:
shape = X.shape
if valid_lens.dim() == 1:
valid_lens = torch.repeat_interleave(valid_lens, shape[1])
else:
valid_lens = valid_lens.reshape(-1)
# 最后一轴上被掩蔽的元素使用一个非常大的负值替换,从而其softmax输出为0
X = d2l.sequence_mask(X.reshape(-1, shape[-1]), valid_lens,
value=-1e6)
return nn.functional.softmax(X.reshape(shape), dim=-1)
masked_softmax(torch.rand(2, 2, 4), torch.tensor([2, 3])) # 两个批次
tensor([[[0.4074, 0.5926, 0.0000, 0.0000],
[0.5424, 0.4576, 0.0000, 0.0000]],
[[0.3432, 0.3032, 0.3536, 0.0000],
[0.3251, 0.4291, 0.2458, 0.0000]]])
masked_softmax(torch.rand(2, 2, 4), torch.tensor([[1, 3], [2, 4]]))
tensor([[[1.0000, 0.0000, 0.0000, 0.0000],
[0.3577, 0.2927, 0.3496, 0.0000]],
[[0.5817, 0.4183, 0.0000, 0.0000],
[0.2940, 0.2301, 0.2602, 0.2157]]])
additive Aufmerksamkeit
#@save
class AdditiveAttention(nn.Module):
"""加性注意力"""
def __init__(self, key_size, query_size, num_hiddens, dropout, **kwargs):
super(AdditiveAttention, self).__init__(**kwargs)
self.W_k = nn.Linear(key_size, num_hiddens, bias=False)
self.W_q = nn.Linear(query_size, num_hiddens, bias=False)
self.w_v = nn.Linear(num_hiddens, 1, bias=False)
self.dropout = nn.Dropout(dropout)
def forward(self, queries, keys, values, valid_lens): # valid_lens:多少对key-value对是需要考虑的
queries, keys = self.W_q(queries), self.W_k(keys)
# 在维度扩展后,
# queries的形状:(batch_size,查询的个数,1,num_hidden)
# key的形状:(batch_size,1,“键-值”对的个数,num_hiddens)
# 使用广播方式进行求和
features = queries.unsqueeze(2) + keys.unsqueeze(1) # 升到四维
features = torch.tanh(features)
# self.w_v仅有一个输出,因此从形状中移除最后那个维度。
# scores的形状:(batch_size,查询的个数,“键-值”对的个数)
scores = self.w_v(features).squeeze(-1)
self.attention_weights = masked_softmax(scores, valid_lens) # batch_size*查询个数*10
# values的形状:(batch_size,“键-值”对的个数,值的维度)
return torch.bmm(self.dropout(self.attention_weights), values) # 最后得到的是query长度*value长度
queries, keys = torch.normal(0, 1, (2, 1, 20)), torch.ones((2, 10, 2)) # 20个query长度是1,10个key长度是2
# values的小批量,两个值矩阵是相同的
values = torch.arange(40, dtype=torch.float32).reshape(1, 10, 4).repeat(2, 1, 1) # 10个value长度是4
valid_lens = torch.tensor([2, 6])
attention = AdditiveAttention(key_size=2, query_size=20, num_hiddens=8,
dropout=0.1)
attention.eval()
attention(queries, keys, values, valid_lens) # 2*1*4
tensor([[[ 2.0000, 3.0000, 4.0000, 5.0000]],
[[10.0000, 11.0000, 12.0000, 13.0000]]], grad_fn=<BmmBackward0>)
# attention.attention_weights 2* 1* 10 中间维度被加权
print(attention.attention_weights.shape)
d2l.show_heatmaps(attention.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
Skalierte Punktproduktaufmerksamkeit
#@save
class DotProductAttention(nn.Module):
"""缩放点积注意力"""
def __init__(self, dropout, **kwargs):
super(DotProductAttention, self).__init__(**kwargs)
self.dropout = nn.Dropout(dropout)
# queries的形状:(batch_size,查询的个数,d)
# keys的形状:(batch_size,“键-值”对的个数,d)
# values的形状:(batch_size,“键-值”对的个数,值的维度)
# valid_lens的形状:(batch_size,)或者(batch_size,查询的个数)
def forward(self, queries, keys, values, valid_lens=None):
d = queries.shape[-1]
# 设置transpose_b=True为了交换keys的最后两个维度
scores = torch.bmm(queries, keys.transpose(1,2)) / math.sqrt(d)
self.attention_weights = masked_softmax(scores, valid_lens)
return torch.bmm(self.dropout(self.attention_weights), values)
queries = torch.normal(0, 1, (2, 1, 2))
attention = DotProductAttention(dropout=0.5)
attention.eval()
attention(queries, keys, values, valid_lens)
d2l.show_heatmaps(attention.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
tensor([[[ 2.0000, 3.0000, 4.0000, 5.0000]],
[[10.0000, 11.0000, 12.0000, 13.0000]]])