.. _sec_attention-scoring-functions:
Dikkat Puanlama Fonksiyonları
=============================
:numref:`sec_nadaraya-watson` içinde, sorgular ve anahtarlar
arasındaki etkileşimleri modellemek için bir Gauss çekirdeği kullandık.
:eq:`eq_nadaraya-watson-gaussian` denkleminde Gauss çekirdeğinin
üssüne bir *dikkat puanlama fonksiyonu* (veya kısaca *puanlama
fonksiyonu*) olarak muamele edilerek, bu fonksiyonun sonuçları temelde
bir softmaks işlemine beslendi. Sonuç olarak, anahtarlarla eşleştirilmiş
değerler üzerinde bir olasılık dağılımı (dikkat ağırlıkları) elde ettik.
Sonunda, dikkat ortaklamasının çıktısı, bu dikkat ağırlıklarına dayanan
değerlerin ağırlıklı bir toplamıdır.
Üst seviyede, :numref:`fig_qkv` şeklindeki dikkat mekanizmalarının
çerçevesini oluşturmak için yukarıdaki algoritmayı kullanabiliriz.
:math:`a` ile dikkat ortaklama işlevini gösteren
:numref:`fig_attention_output` şekli, dikkat havuzlama çıktısının
ağırlıklı bir değer toplamı olarak nasıl hesaplanabileceğini
göstermektedir. Dikkat ağırlıkları bir olasılık dağılımı olduğundan,
ağırlıklı toplamı esas olarak ağırlıklı bir ortalamadır.
.. _fig_attention_output:
.. figure:: ../img/attention-output.svg
Değerlerin ağırlıklı ortalaması olarak dikkat ortaklamasının
çıktısını hesaplama.
Matematiksel olarak, :math:`\mathbf{q} \in \mathbb{R}^q` sorgumuz ve
:math:`m`
:math:`(\mathbf{k}_1, \mathbf{v}_1), \ldots, (\mathbf{k}_m, \mathbf{v}_m)`
anahtar-değer çiftlerimiz olduğunu varsayalım, öyle ki
:math:`\mathbf{k}_i \in \mathbb{R}^k` ve
:math:`\mathbf{v}_i \in \mathbb{R}^v`. Dikkat ortaklama :math:`f`,
değerlerin ağırlıklı bir toplamı olarak örneklendirilir:
.. math:: f(\mathbf{q}, (\mathbf{k}_1, \mathbf{v}_1), \ldots, (\mathbf{k}_m, \mathbf{v}_m)) = \sum_{i=1}^m \alpha(\mathbf{q}, \mathbf{k}_i) \mathbf{v}_i \in \mathbb{R}^v,
:label: eq_attn-pooling
:math:`\mathbf{q}` ve anahtar :math:`\mathbf{k}_i` için dikkat ağırlığı
(skaler), iki vektörü bir skalere eşleyen bir dikkat puanlama işlevi
:math:`a`'nın softmaks işlemi ile hesaplanır:
.. math:: \alpha(\mathbf{q}, \mathbf{k}_i) = \mathrm{softmax}(a(\mathbf{q}, \mathbf{k}_i)) = \frac{\exp(a(\mathbf{q}, \mathbf{k}_i))}{\sum_{j=1}^m \exp(a(\mathbf{q}, \mathbf{k}_j))} \in \mathbb{R}.
:label: eq_attn-scoring-alpha
Gördüğümüz gibi, :math:`a` dikkat puanlama fonksiyonunun farklı
seçimleri farklı dikkat ortaklama davranışlarına yol açar. Bu bölümde,
daha sonra daha gelişmiş dikkat mekanizmaları geliştirmek için
kullanacağımız iki popüler puanlama fonksiyonunu tanıtıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import math
from d2l import mxnet as d2l
from mxnet import np, npx
from mxnet.gluon import nn
npx.set_np()
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import math
import torch
from torch import nn
from d2l import torch as d2l
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import tensorflow as tf
from d2l import tensorflow as d2l
.. raw:: html
.. raw:: html
Maskeli Softmaks İşlemi
-----------------------
Daha önce de belirttiğimiz gibi, olasılık dağılımını dikkat ağırlıkları
olarak elde etmek için bir softmaks işlemi kullanılır. Bazı durumlarda,
tüm değerler dikkat ortaklamasına beslenmemelidir. Örneğin,
:numref:`sec_machine_translation` içinde verimli minigrup işleme için,
bazı metin dizileri anlam taşımayan özel belirteçlerle doldurulmuştur.
Değerler olarak yalnızca anlamlı belirteçler üzerinde bir dikkat
ortaklamak için, softmaks hesaplarken bu belirtilen aralığın ötesinde
olanları filtrelemek için geçerli bir sıra uzunluğu (belirteç sayısı
olarak) belirtebiliriz. Bu şekilde, geçerli uzunluğun ötesinde herhangi
bir değerin sıfır olarak maskelendiği aşağıdaki ``masked_softmax``
işlevinde böyle bir *maskelenmiş softmaks işlemi* uygulayabiliriz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def masked_softmax(X, valid_lens):
"""Son eksendeki öğeleri maskeleyerek softmax işlemini gerçekleştirin."""
# `X`: 3B tensör, `valid_lens`: 1B veya 2B tensör
if valid_lens is None:
return npx.softmax(X)
else:
shape = X.shape
if valid_lens.ndim == 1:
valid_lens = valid_lens.repeat(shape[1])
else:
valid_lens = valid_lens.reshape(-1)
# Son eksende, maskelenmiş öğeleri, üsleri 0 olan çok büyük bir
# negatif değerle değiştirin
X = npx.sequence_mask(X.reshape(-1, shape[-1]), valid_lens, True,
value=-1e6, axis=1)
return npx.softmax(X).reshape(shape)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def masked_softmax(X, valid_lens):
"""Son eksendeki öğeleri maskeleyerek softmax işlemini gerçekleştirin."""
# `X`: 3B tensör, `valid_lens`: 1B veya 2B tensör
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)
# Son eksende, maskelenmiş öğeleri, üsleri 0 olan çok büyük bir
# negatif değerle değiştirin
X = d2l.sequence_mask(X.reshape(-1, shape[-1]), valid_lens,
value=-1e6)
return nn.functional.softmax(X.reshape(shape), dim=-1)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def masked_softmax(X, valid_lens):
"""Son eksendeki öğeleri maskeleyerek softmax işlemini gerçekleştirin."""
# `X`: 3B tensör, `valid_lens`: 1B veya 2B tensör
if valid_lens is None:
return tf.nn.softmax(X, axis=-1)
else:
shape = X.shape
if len(valid_lens.shape) == 1:
valid_lens = tf.repeat(valid_lens, repeats=shape[1])
else:
valid_lens = tf.reshape(valid_lens, shape=-1)
# Son eksende, maskelenmiş öğeleri, üsleri 0 olan çok büyük bir
# negatif değerle değiştirin
X = d2l.sequence_mask(tf.reshape(X, shape=(-1, shape[-1])), valid_lens, value=-1e6)
return tf.nn.softmax(tf.reshape(X, shape=shape), axis=-1)
.. raw:: html
.. raw:: html
Bu işlevin nasıl çalıştığını göstermek için, bu iki örnek için geçerli
uzunlukların sırasıyla iki ve üç olduğu iki tane :math:`2 \times 4`
matris örneğinden oluşan bir minigrup düşünün. Maskelenmiş softmaks
işleminin bir sonucu olarak, geçerli uzunlukların dışındaki değerlerin
tümü sıfır olarak maskelenir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
masked_softmax(np.random.uniform(size=(2, 2, 4)), np.array([2, 3]))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
array([[[0.488994 , 0.511006 , 0. , 0. ],
[0.4365484 , 0.56345165, 0. , 0. ]],
[[0.288171 , 0.3519408 , 0.3598882 , 0. ],
[0.29034296, 0.25239873, 0.45725837, 0. ]]])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
masked_softmax(torch.rand(2, 2, 4), torch.tensor([2, 3]))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
tensor([[[0.4434, 0.5566, 0.0000, 0.0000],
[0.5291, 0.4709, 0.0000, 0.0000]],
[[0.4512, 0.2650, 0.2839, 0.0000],
[0.2631, 0.5151, 0.2218, 0.0000]]])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
masked_softmax(tf.random.uniform(shape=(2, 2, 4)), tf.constant([2, 3]))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Benzer şekilde, her matris örneğindeki her satır için geçerli
uzunlukları belirtmede iki boyutlu bir tensör de kullanabiliriz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
masked_softmax(np.random.uniform(size=(2, 2, 4)),
np.array([[1, 3], [2, 4]]))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
array([[[1. , 0. , 0. , 0. ],
[0.35848376, 0.3658879 , 0.27562833, 0. ]],
[[0.54370314, 0.45629686, 0. , 0. ],
[0.19598778, 0.25580427, 0.19916739, 0.3490406 ]]])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
masked_softmax(torch.rand(2, 2, 4), torch.tensor([[1, 3], [2, 4]]))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
tensor([[[1.0000, 0.0000, 0.0000, 0.0000],
[0.3063, 0.3772, 0.3165, 0.0000]],
[[0.3269, 0.6731, 0.0000, 0.0000],
[0.1736, 0.3564, 0.1866, 0.2834]]])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
masked_softmax(tf.random.uniform((2, 2, 4)), tf.constant([[1, 3], [2, 4]]))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
.. _subsec_additive-attention:
Toplayıcı Dikkat
----------------
Genel olarak, sorgular ve anahtarlar farklı uzunluklarda vektörler
olduğunda, puanlama işlevi olarak toplayıcı dikkat kullanabiliriz. Bir
sorgu :math:`\mathbf{q} \in \mathbb{R}^q` ve bir anahtar
:math:`\mathbf{k} \in \mathbb{R}^k`, *toplayıcı dikkat* puanlama
fonksiyonu göz önüne alındığında şöyledir:
.. math:: a(\mathbf q, \mathbf k) = \mathbf w_v^\top \text{tanh}(\mathbf W_q\mathbf q + \mathbf W_k \mathbf k) \in \mathbb{R},
:label: eq_additive-attn
burada :math:`\mathbf W_q\in\mathbb R^{h\times q}`,
:math:`\mathbf W_k\in\mathbb R^{h\times k}` ve
:math:`\mathbf w_v\in\mathbb R^{h}` öğrenilebilir parametrelerdir.
:eq:`eq_additive-attn` denklemine eşdeğer olarak, sorgu ve anahtar
bitiştirilir ve gizli birim sayısı :math:`h` hiper parametresi olan bir
tek gizli katmanlı MLP'ye beslenir. Etkinleştirme fonksiyonu olarak
:math:`\tanh`'yi kullanarak ve ek girdi terimlerini devre dışı
bırakarak, aşağıdakilere toplayıcı dikkat uyguluyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class AdditiveAttention(nn.Block):
"""Additive attention."""
def __init__(self, num_hiddens, dropout, **kwargs):
super(AdditiveAttention, self).__init__(**kwargs)
# Diğer eksenlerin şekillerinin aynı kalması için yalnızca son
# ekseni dönüştürmek için `flatten=False` kullanın
self.W_k = nn.Dense(num_hiddens, use_bias=False, flatten=False)
self.W_q = nn.Dense(num_hiddens, use_bias=False, flatten=False)
self.w_v = nn.Dense(1, use_bias=False, flatten=False)
self.dropout = nn.Dropout(dropout)
def forward(self, queries, keys, values, valid_lens):
queries, keys = self.W_q(queries), self.W_k(keys)
# Boyut genişletmeden sonra, `queries`'in şekli: (`batch_size`,
# sorgu sayısı, 1, `num_hiddens`) ve `keys`'in şekli: (`batch_size`, 1,
# anahtar/değer çiftlerinin sayısı,`num_hiddens`).
# Yayınlarken onları toplayın.
features = np.expand_dims(queries, axis=2) + np.expand_dims(
keys, axis=1)
features = np.tanh(features)
# `self.w_v`nin sadece bir çıktısı var, bu yüzden şekilden
# son tek boyutlu girişi kaldırıyoruz. `scores`'ın şekli (`batch_size`,
# sorgu sayısı, anahtar/değer çifti sayısı)
scores = np.squeeze(self.w_v(features), axis=-1)
self.attention_weights = masked_softmax(scores, valid_lens)
# `values`'in şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı,
# değer boyutu)
return npx.batch_dot(self.dropout(self.attention_weights), values)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class AdditiveAttention(nn.Module):
"""Additive attention."""
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):
queries, keys = self.W_q(queries), self.W_k(keys)
# Boyut genişletmeden sonra, `queries`'in şekli: (`batch_size`,
# sorgu sayısı, 1, `num_hiddens`) ve `keys`'in şekli: (`batch_size`, 1,
# anahtar/değer çiftlerinin sayısı,`num_hiddens`).
# Yayınlarken onları toplayın.
features = queries.unsqueeze(2) + keys.unsqueeze(1)
features = torch.tanh(features)
# `self.w_v`nin sadece bir çıktısı var, bu yüzden şekilden
# son tek boyutlu girişi kaldırıyoruz. `scores`'ın şekli (`batch_size`,
# sorgu sayısı, anahtar/değer çifti sayısı)
scores = self.w_v(features).squeeze(-1)
self.attention_weights = masked_softmax(scores, valid_lens)
# `values`'in şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı,
# değer boyutu)
return torch.bmm(self.dropout(self.attention_weights), values)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class AdditiveAttention(tf.keras.layers.Layer):
"""Additive attention."""
def __init__(self, key_size, query_size, num_hiddens, dropout, **kwargs):
super().__init__(**kwargs)
self.W_k = tf.keras.layers.Dense(num_hiddens, use_bias=False)
self.W_q = tf.keras.layers.Dense(num_hiddens, use_bias=False)
self.w_v = tf.keras.layers.Dense(1, use_bias=False)
self.dropout = tf.keras.layers.Dropout(dropout)
def call(self, queries, keys, values, valid_lens, **kwargs):
queries, keys = self.W_q(queries), self.W_k(keys)
# Boyut genişletmeden sonra, `queries`'in şekli: (`batch_size`,
# sorgu sayısı, 1, `num_hiddens`) ve `keys`'in şekli: (`batch_size`, 1,
# anahtar/değer çiftlerinin sayısı,`num_hiddens`).
# Yayınlarken onları toplayın.
features = tf.expand_dims(queries, axis=2) + tf.expand_dims(
keys, axis=1)
features = tf.nn.tanh(features)
# `self.w_v`nin sadece bir çıktısı var, bu yüzden şekilden
# son tek boyutlu girişi kaldırıyoruz. `scores`'ın şekli (`batch_size`,
# sorgu sayısı, anahtar/değer çifti sayısı)
scores = tf.squeeze(self.w_v(features), axis=-1)
self.attention_weights = masked_softmax(scores, valid_lens)
# `values`'in şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı,
# değer boyutu)
return tf.matmul(self.dropout(
self.attention_weights, **kwargs), values)
.. raw:: html
.. raw:: html
Yukarıdaki 'AdditiveAttention' sınıfını sorguların, anahtarların ve
değerlerin şekillerinin (toplu iş boyutu, adım sayısı veya
belirteçlerdeki sıra uzunluğu, öznitelik boyutu) sırasıyla (:math:`2`,
:math:`1`, :math:`20`), (:math:`2`, :math:`10`, :math:`2`) ve
(:math:`2`, :math:`10`, :math:`4`) olduğu bir basit örnek ile
gösterelim.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
queries, keys = np.random.normal(0, 1, (2, 1, 20)), np.ones((2, 10, 2))
# `values` minigrubundaki iki değer matrisi aynıdır
values = np.arange(40).reshape(1, 10, 4).repeat(2, axis=0)
valid_lens = np.array([2, 6])
attention = AdditiveAttention(num_hiddens=8, dropout=0.1)
attention.initialize()
attention(queries, keys, values, valid_lens)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
array([[[ 2. , 3. , 4. , 5. ]],
[[10. , 11. , 12.000001, 13. ]]])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
queries, keys = torch.normal(0, 1, (2, 1, 20)), torch.ones((2, 10, 2))
# `values` minigrubundaki iki değer matrisi aynıdır
values = torch.arange(40, dtype=torch.float32).reshape(1, 10, 4).repeat(
2, 1, 1)
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)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
tensor([[[ 2.0000, 3.0000, 4.0000, 5.0000]],
[[10.0000, 11.0000, 12.0000, 13.0000]]], grad_fn=)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
queries, keys = tf.random.normal(shape=(2, 1, 20)), tf.ones((2, 10, 2))
# `values` minigrubundaki iki değer matrisi aynıdır
values = tf.repeat(tf.reshape(
tf.range(40, dtype=tf.float32), shape=(1, 10, 4)), repeats=2, axis=0)
valid_lens = tf.constant([2, 6])
attention = AdditiveAttention(key_size=2, query_size=20, num_hiddens=8,
dropout=0.1)
attention(queries, keys, values, valid_lens, training=False)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Her ne kadar toplayıcı dikkat öğrenilebilir parametreler içerse de, bu
örnekte her anahtar aynı olduğundan, önceden düzenlenmiş geçerli
uzunluklara göre belirlenen dikkat ağırlıkları tekdüzedir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.show_heatmaps(attention.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
.. figure:: output_attention-scoring-functions_2a8fdc_75_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.show_heatmaps(attention.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
.. figure:: output_attention-scoring-functions_2a8fdc_78_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.show_heatmaps(tf.reshape(attention.attention_weights, (1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
.. figure:: output_attention-scoring-functions_2a8fdc_81_0.svg
.. raw:: html
.. raw:: html
Ölçeklendirilmiş Nokta Çarpımı Dikkati
--------------------------------------
Puanlama fonksiyonu için hesaplama açısından daha verimli bir tasarım
basitçe nokta çarpımı olabilir. Ancak, nokta çarpımı işlemi hem sorgu
hem de anahtarın aynı vektör uzunluğuna sahip olmasını gerektirir, yani
:math:`d`. Sorgu ve anahtarın tüm öğelerinin sıfır ortalama ve birim
varyanslı bağımsız rasgele değişkenler olduğunu varsayalım. Her iki
vektörün nokta çarpımının sıfır ortalama ve :math:`d` varyansı vardır.
Nokta çarpımının varyansının vektör uzunluğundan bağımsız olarak hala
bir kalmasını sağlamak için *ölçeklendirilmiş nokta çarpımı dikkati*
puanlama işlevi
.. math:: a(\mathbf q, \mathbf k) = \mathbf{q}^\top \mathbf{k} /\sqrt{d}
nokta çarpımını :math:`\sqrt{d}` ile böler. Uygulamada, genellikle
verimlilik için, sorguların ve anahtarların :math:`d` uzunluğunda ve
değerlerin :math:`v` uzunluğunda olduğu :math:`n` adet sorgu ve
:math:`m` adet anahtar/değer çifti için dikkat hesaplama gibi,
minigruplar halinde düşünürüz. :math:`\mathbf Q\in\mathbb R^{n\times d}`
sorgularının, :math:`\mathbf K\in\mathbb R^{m\times d}` anahtarlarının
ve :math:`\mathbf V\in\mathbb R^{m\times v}` değerlerinin
ölçeklendirilmiş nokta çarpımı dikkati şöyledir
.. math:: \mathrm{softmax}\left(\frac{\mathbf Q \mathbf K^\top }{\sqrt{d}}\right) \mathbf V \in \mathbb{R}^{n\times v}.
:label: eq_softmax_QK_V
Aşağıdaki ölçeklendirilmiş nokta çarpımı dikkati uygulamasında, model
düzenlileştirmesi için hattan düşürme kullanıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class DotProductAttention(nn.Block):
"""Ölçeklendirilmiş nokta çarpım dikkati."""
def __init__(self, dropout, **kwargs):
super(DotProductAttention, self).__init__(**kwargs)
self.dropout = nn.Dropout(dropout)
# `queries`'in şekli: (`batch_size`, sorgu sayısı, `d`)
# `keys`'in şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı, `d`)
# `values`'un şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı, değer
# boyut)
# `valid_lens`'in şekli: (`batch_size`,) veya (`batch_size`, sorgu sayısı)
def forward(self, queries, keys, values, valid_lens=None):
d = queries.shape[-1]
# keys`'in son iki boyutunu değiştirmek için "transpose_b=True`
# diye ayarlayın
scores = npx.batch_dot(queries, keys, transpose_b=True) / math.sqrt(d)
self.attention_weights = masked_softmax(scores, valid_lens)
return npx.batch_dot(self.dropout(self.attention_weights), values)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class DotProductAttention(nn.Module):
"""Ölçeklendirilmiş nokta çarpım dikkati."""
def __init__(self, dropout, **kwargs):
super(DotProductAttention, self).__init__(**kwargs)
self.dropout = nn.Dropout(dropout)
# `queries`'in şekli: (`batch_size`, sorgu sayısı, `d`)
# `keys`'in şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı, `d`)
# `values`'un şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı, değer
# boyut)
# `valid_lens`'in şekli: (`batch_size`,) veya (`batch_size`, sorgu sayısı)
def forward(self, queries, keys, values, valid_lens=None):
d = queries.shape[-1]
# keys`'in son iki boyutunu değiştirmek için "transpose_b=True`
# diye ayarlayın
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)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
class DotProductAttention(tf.keras.layers.Layer):
"""Ölçeklendirilmiş nokta çarpım dikkati."""
def __init__(self, dropout, **kwargs):
super().__init__(**kwargs)
self.dropout = tf.keras.layers.Dropout(dropout)
# `queries`'in şekli: (`batch_size`, sorgu sayısı, `d`)
# `keys`'in şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı, `d`)
# `values`'un şekli: (`batch_size`, anahtar/değer çiftlerinin sayısı, değer
# boyut)
# `valid_lens`'in şekli: (`batch_size`,) veya (`batch_size`, sorgu sayısı)
def call(self, queries, keys, values, valid_lens, **kwargs):
d = queries.shape[-1]
scores = tf.matmul(queries, keys, transpose_b=True)/tf.math.sqrt(
tf.cast(d, dtype=tf.float32))
self.attention_weights = masked_softmax(scores, valid_lens)
return tf.matmul(self.dropout(self.attention_weights, **kwargs), values)
.. raw:: html
.. raw:: html
Yukarıdaki ``DotProductAttention`` sınıfını göstermek için, toplayıcı
dikkat için önceki basit örnekteki aynı anahtarları, değerleri ve
geçerli uzunlukları kullanıyoruz. Nokta çarpımı işlemi için, sorguların
öznitelik boyutunu anahtarlarınkiyle aynı yapıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
queries = np.random.normal(0, 1, (2, 1, 2))
attention = DotProductAttention(dropout=0.5)
attention.initialize()
attention(queries, keys, values, valid_lens)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
array([[[ 2. , 3. , 4. , 5. ]],
[[10. , 11. , 12.000001, 13. ]]])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
queries = torch.normal(0, 1, (2, 1, 2))
attention = DotProductAttention(dropout=0.5)
attention.eval()
attention(queries, keys, values, valid_lens)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
tensor([[[ 2.0000, 3.0000, 4.0000, 5.0000]],
[[10.0000, 11.0000, 12.0000, 13.0000]]])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
queries = tf.random.normal(shape=(2, 1, 2))
attention = DotProductAttention(dropout=0.5)
attention(queries, keys, values, valid_lens, training=False)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Toplayıcı dikkat gösterimindeki gibi, ``keys`` herhangi bir sorgu ile
ayırt edilemeyen aynı elemanı içerdiğinden, tekdüze dikkat ağırlıkları
elde edilir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.show_heatmaps(attention.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
.. figure:: output_attention-scoring-functions_2a8fdc_111_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.show_heatmaps(attention.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
.. figure:: output_attention-scoring-functions_2a8fdc_114_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.show_heatmaps(tf.reshape(attention.attention_weights, (1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
.. figure:: output_attention-scoring-functions_2a8fdc_117_0.svg
.. raw:: html
.. raw:: html
Özet
----
- Dikkat puanlama fonksiyonunun farklı seçeneklerinin dikkat
ortaklamasının farklı davranışlarına yol açtığı ağırlıklı bir değer
ortalaması olarak dikkat ortaklama çıktısını hesaplayabiliriz.
- Sorgular ve anahtarlar farklı uzunluklarda vektörler olduğunda,
toplayıcı dikkat puanlama işlevini kullanabiliriz. Aynı olduklarında,
ölçeklendirilmiş nokta çarpımı dikkat puanlama işlevi hesaplama
açısından daha verimlidir.
Alıştırmalar
------------
1. Basit örnekteki anahtarları değiştirin ve dikkat ağırlıklarını
görselleştirin. Toplayıcı dikkat ve ölçeklendirilmiş nokta çarpımı
dikkati hala aynı dikkat ağırlıklarını veriyor mu? Neden ya da neden
değil?
2. Yalnızca matris çarpımlarını kullanarak, farklı vektör uzunluklarına
sahip sorgular ve anahtarlar için yeni bir puanlama işlevi
tasarlayabilir misiniz?
3. Sorgular ve anahtarlar aynı vektör uzunluğuna sahip olduğunda, vektör
toplamı puanlama fonksiyonu için nokta çarpımından daha iyi bir
tasarım mıdır? Neden ya da neden değil?
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html