10.2. Dikkat Ortaklama: Nadaraya-Watson Çekirdek Bağlanımı
Open the notebook in Colab
Open the notebook in Colab
Open the notebook in Colab
Open the notebook in SageMaker Studio Lab

Artık Fig. 10.1.3 çerçevesinde dikkat mekanizmalarının ana bileşenlerini biliyorsunuz. Yeniden özetlemek için sorgular (istemli işaretler) ve anahtarlar (istemsiz işaretler) arasındaki etkileşimler dikkat ortaklama ile sonuçlanır. Dikkat ortaklama, çıktıyı üretmek için seçici olarak değerleri (duyusal girdiler) bir araya getirir. Bu bölümde, dikkat mekanizmalarının pratikte nasıl çalıştığına dair üst düzey bir görünüm vermek için dikkat ortaklamasını daha ayrıntılı olarak anlatacağız. Özellikle, 1964 yılında önerilen Nadaraya-Watson çekirdek bağlanım modeli, makine öğrenmesini dikkat mekanizmaları ile göstermek için basit ama eksiksiz bir örnektir.

from d2l import mxnet as d2l
from mxnet import autograd, gluon, np, npx
from mxnet.gluon import nn

npx.set_np()
import torch
from torch import nn
from d2l import torch as d2l
import tensorflow as tf
from d2l import tensorflow as d2l

tf.random.set_seed(seed=1322)

10.2.1. Veri Kümesi Oluşturma

İşleri basit tutmak için, aşağıdaki regresyon problemini ele alalım: \(\{(x_1, y_1), \ldots, (x_n, y_n)\}\) girdi-çıktı çiftlerinin bir veri kümesi verildiğinde \(\{(x_1, y_1), \ldots, (x_n, y_n)\}\), \(\hat{y} = f(x)\) yeni bir \(x\) girdisinin çıktısını tahmin etmek için \(\hat{y} = f(x)\) nasıl öğrenilir?

Burada \(\epsilon\) gürültü terimi ile aşağıdaki doğrusal olmayan fonksiyona göre yapay bir veri kümesi oluşturuyoruz:

(10.2.1)\[y_i = 2\sin(x_i) + x_i^{0.8} + \epsilon,\]

burada \(\epsilon\) sıfır ortalama ve 0.5 standart sapma ile normal bir dağılıma uyar. Hem 50 eğitim örneği hem de 50 test örneği üretilir. Dikkat modelini daha sonra daha iyi görselleştirmek için, eğitim girdileri sıralanır.

n_train = 50  # Eğitim örneklerinin adedi
x_train = np.sort(np.random.rand(n_train) * 5)   # Eğitim girdileri

def f(x):
    return 2 * np.sin(x) + x**0.8

y_train = f(x_train) + np.random.normal(0.0, 0.5, (n_train,))  # Eğitim çıktıları
x_test = np.arange(0, 5, 0.1)  # Test örnekleri
y_truth = f(x_test)  # Test örneklerinin adedi gerçek referans değeri
n_test = len(x_test)  # Test örneklerinin adedi
n_test
50
n_train = 50  # Eğitim örneklerinin adedi
x_train, _ = torch.sort(torch.rand(n_train) * 5)   # Eğitim girdileri

def f(x):
    return 2 * torch.sin(x) + x**0.8

y_train = f(x_train) + torch.normal(0.0, 0.5, (n_train,))  # Eğitim çıktıları
x_test = torch.arange(0, 5, 0.1)  # Test örnekleri
y_truth = f(x_test)  # Test örneklerinin adedi gerçek referans değeri
n_test = len(x_test)  # Test örneklerinin adedi
n_test
50
n_train = 50
x_train = tf.sort(tf.random.uniform(shape=(n_train,), maxval=5))

def f(x):
    return 2 * tf.sin(x) + x**0.8

y_train = f(x_train) + tf.random.normal((n_train,), 0.0, 0.5)  # Eğitim çıktıları
x_test = tf.range(0, 5, 0.1)  # Test örnekleri
y_truth = f(x_test)  # Test örneklerinin adedi gerçek referans değeri
n_test = len(x_test)  # Test örneklerinin adedi
n_test
50

Aşağıdaki işlev, tüm eğitim örneklerini (dairelerle temsil edilmiş), gürültü terimi olmadan gerçek referans değer veri üretme işlevi ‘f’yi (“Truth” ile etiketlenmiş) ve öğrenilen tahmin işlevini (“Pred” ile etiketlenmiş) çizer.

def plot_kernel_reg(y_hat):
    d2l.plot(x_test, [y_truth, y_hat], 'x', 'y', legend=['Truth', 'Pred'],
             xlim=[0, 5], ylim=[-1, 5])
    d2l.plt.plot(x_train, y_train, 'o', alpha=0.5);

10.2.2. Ortalama Ortaklama

Bu regresyon problemi için belki de dünyanın “en aptalca” tahmin edicisiyle başlıyoruz: Ortalama ortaklama kullanarak tüm eğitim çıktıları üzerinde ortalama,

(10.2.2)\[f(x) = \frac{1}{n}\sum_{i=1}^n y_i,\]

aşağıda çizilmiştir. Gördüğümüz gibi, bu tahminci gerçekten o kadar akıllı değil.

y_hat = y_train.mean().repeat(n_test)
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_29_0.svg
y_hat = torch.repeat_interleave(y_train.mean(), n_test)
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_32_0.svg
y_hat = tf.repeat(tf.reduce_mean(y_train), repeats=n_test)
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_35_0.svg

10.2.3. Parametrik Olmayan Dikkat Ortaklama

Açıkçası, ortalama ortaklama girdileri, \(x_i\), atlar. Girdi yerlerine göre \(y_i\) çıktılarını ağırlıklandırmak için Nadaraya (Nadaraya, 1964) ve Watson (Watson, 1964) tarafından daha iyi bir fikir önerildi:

(10.2.3)\[f(x) = \sum_{i=1}^n \frac{K(x - x_i)}{\sum_{j=1}^n K(x - x_j)} y_i,\]

burada \(K\) bir çekirdektir. (10.2.3) içindeki tahmin ediciye Nadaraya-Watson çekirdek regresyonu denir. Burada çekirdeklerin ayrıntılarına dalmayacağız. Fig. 10.1.3 içindeki dikkat mekanizmalarının çerçevesini hatırlayın. Dikkat açısından bakıldığında, (10.2.3) denklemini dikkat ortaklamanın daha genelleştirilmiş bir formunda yeniden yazabiliriz:

(10.2.4)\[f(x) = \sum_{i=1}^n \alpha(x, x_i) y_i,\]

burada \(x\) sorgu ve \((x_i, y_i)\) anahtar-değer çiftidir. (10.2.4) ve (10.2.2) karşılaştırılırsa, buradaki dikkat havuzlama \(y_i\) değerlerinin ağırlıklı bir ortalamasıdır. (10.2.4) içindeki dikkat ağırlığı \(\alpha(x, x_i)\), \(x\) sorgu ve \(\alpha\) ile modellenen anahtar \(x_i\) arasındaki etkileşime dayalı olarak karşılık gelen \(y_i\) değerine atanır. Herhangi bir sorgu için, tüm anahtar-değer çiftleri üzerindeki dikkat ağırlıkları geçerli bir olasılık dağılımıdır: Negatif değillerdir ve bire toplanırlar.

Dikkat ortaklama sezgileri kazanmak için, sadece aşağıda tanımlanan bir Gauss çekirdeğini düşünün

(10.2.5)\[K(u) = \frac{1}{\sqrt{2\pi}} \exp(-\frac{u^2}{2}).\]

Gauss çekirdeğini (10.2.4) ve (10.2.3) denklemlerine koyarsak

(10.2.6)\[\begin{split}\begin{aligned} f(x) &=\sum_{i=1}^n \alpha(x, x_i) y_i\\ &= \sum_{i=1}^n \frac{\exp\left(-\frac{1}{2}(x - x_i)^2\right)}{\sum_{j=1}^n \exp\left(-\frac{1}{2}(x - x_j)^2\right)} y_i \\&= \sum_{i=1}^n \mathrm{softmax}\left(-\frac{1}{2}(x - x_i)^2\right) y_i. \end{aligned}\end{split}\]

(10.2.6) içinde, verilen \(x\) sorgusuna daha yakın olan bir \(x_i\) anahtarı, anahtarın karşılık gelen \(y_i\) değerine atanan daha büyük bir dikkat ağırlığı aracılığıyla daha fazla dikkat alacaktır.

Nadaraya-Watson çekirdek regresyonu parametrik olmayan bir modeldir; bu nedenle (10.2.6), parametrik olmayan dikkat ortaklama örneğidir. Aşağıda, bu parametrik olmayan dikkat modeline dayanarak tahmini çiziyoruz. Tahmin edilen çizgi düzgün ve ortalama ortaklama tarafından üretilen gerçek referans değere daha yakındır.

# `X_repeat` şekli: (`n_test`, `n_train`), burada her satır aynı test
# girdilerini içerir (yani aynı sorgular)
X_repeat = x_test.repeat(n_train).reshape((-1, n_train))
# `x_train`'in anahtarları içerdiğine dikkat edin. `attention_weights` şekli:
# (`n_test`, `n_train`)'dir, burada her satır, her sorguya verilen değerler
# (`y_train`) arasında atanacak dikkat ağırlıklarını içerir
attention_weights = npx.softmax(-(X_repeat - x_train)**2 / 2)
# Each element of `y_hat` is weighted average of values, where weights are
# attention weights
# `y_hat`'nin her bir öğesi, ağırlıkların dikkat ağırlıkları olduğu
# değerlerin ağırlıklı ortalamasıdır.
y_hat = np.dot(attention_weights, y_train)
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_41_0.svg
# `X_repeat` şekli: (`n_test`, `n_train`), burada her satır aynı test
# girdilerini içerir (yani aynı sorgular)
X_repeat = x_test.repeat_interleave(n_train).reshape((-1, n_train))
# `x_train`'in anahtarları içerdiğine dikkat edin. `attention_weights` şekli:
# (`n_test`, `n_train`)'dir, burada her satır, her sorguya verilen değerler
# (`y_train`) arasında atanacak dikkat ağırlıklarını içerir
attention_weights = nn.functional.softmax(-(X_repeat - x_train)**2 / 2, dim=1)
# `y_hat`'nin her bir öğesi, ağırlıkların dikkat ağırlıkları olduğu
# değerlerin ağırlıklı ortalamasıdır.
y_hat = torch.matmul(attention_weights, y_train)
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_44_0.svg
# `X_repeat` şekli: (`n_test`, `n_train`), burada her satır aynı test
# girdilerini içerir (yani aynı sorgular)
X_repeat = tf.repeat(tf.expand_dims(x_train, axis=0), repeats=n_train, axis=0)
# `x_train`'in anahtarları içerdiğine dikkat edin. `attention_weights` şekli:
# (`n_test`, `n_train`)'dir, burada her satır, her sorguya verilen değerler
# (`y_train`) arasında atanacak dikkat ağırlıklarını içerir
attention_weights = tf.nn.softmax(-(X_repeat - tf.expand_dims(x_train, axis=1))**2/2, axis=1)
# `y_hat`'nin her bir öğesi, ağırlıkların dikkat ağırlıkları olduğu
# değerlerin ağırlıklı ortalamasıdır.
y_hat = tf.matmul(attention_weights, tf.expand_dims(y_train, axis=1))
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_47_0.svg

Şimdi dikkat ağırlıklarına bir göz atalım. Burada test girdileri sorgulardır, eğitim girdileri ise anahtarlardır. Her iki girdi sıralandığından, sorgu-anahtar çifti ne kadar yakın olursa, dikkat ortaklamasında dikkat ağırlığı o kadar yüksek olur.

d2l.show_heatmaps(np.expand_dims(np.expand_dims(attention_weights, 0), 0),
                  xlabel='Sorted training inputs',
                  ylabel='Sorted testing inputs')
../_images/output_nadaraya-watson_61a333_53_0.svg
d2l.show_heatmaps(attention_weights.unsqueeze(0).unsqueeze(0),
                  xlabel='Sorted training inputs',
                  ylabel='Sorted testing inputs')
../_images/output_nadaraya-watson_61a333_56_0.svg
d2l.show_heatmaps(tf.expand_dims(tf.expand_dims(attention_weights, axis=0), axis=0),
                  xlabel='Sorted training inputs',
                  ylabel='Sorted testing inputs')
../_images/output_nadaraya-watson_61a333_59_0.svg

10.2.4. Parametrik Dikkat Ortaklama

Parametrik olmayan Nadaraya-Watson çekirdek regresyonu tutarlılık avantajından yararlanır: Yeterli veri verildiğinde bu model en uygun çözüme yakınlaşır. Bununla birlikte, öğrenilebilir parametreleri dikkat ortaklamasına kolayca tümleştirebiliriz.

Örnek olarak, (10.2.6) denkleminden biraz farklı olarak, aşağıdaki gibi \(x\) sorgu ve \(x_i\) anahtarı arasındaki uzaklık, öğrenilebilir bir parametre \(w\) ile çarpılır:

(10.2.7)\[\begin{split}\begin{aligned}f(x) &= \sum_{i=1}^n \alpha(x, x_i) y_i \\&= \sum_{i=1}^n \frac{\exp\left(-\frac{1}{2}((x - x_i)w)^2\right)}{\sum_{j=1}^n \exp\left(-\frac{1}{2}((x - x_j)w)^2\right)} y_i \\&= \sum_{i=1}^n \mathrm{softmax}\left(-\frac{1}{2}((x - x_i)w)^2\right) y_i.\end{aligned}\end{split}\]

Bölümün geri kalanında, (10.2.7) denklemindeki dikkat ortaklama parametresini öğrenerek bu modeli eğiteceğiz.

10.2.4.1. Toplu Matris Çarpması

Minigruplar için dikkati daha verimli bir şekilde hesaplamak için, derin öğrenme çerçeveleri tarafından sağlanan toplu matris çarpma yardımcı programlarından yararlanabiliriz.

İlk minigrup \(n\) matrisleri \(\mathbf{X}_1, \ldots, \mathbf{X}_n\) şekil \(a\times b\) içerdiğini ve ikinci minibatch \(n\) matrisleri \(b\times c\) şekilli \(\mathbf{Y}_1, \ldots, \mathbf{Y}_n\) matrisleri içerdiğini varsayalım. Onların toplu matris çarpımı \(n\) şekil \(a\times c\) matrisleri \(\mathbf{X}_1\mathbf{Y}_1, \ldots, \mathbf{X}_n\mathbf{Y}_n\) ile sonuçlanır. Bu nedenle, iki şekil tensör verilen (\(n\), \(a\), \(b\)) ve (\(n\), \(b\), \(c\)), toplu matris çarpma çıktılarının şekli (\(n\), \(a\), \(c\))’dir.

İlk minigrubun \(a\times b\) şeklinde \(\mathbf{X}_1, \ldots, \mathbf{X}_n\) \(n\) matrisi içerdiğini ve ikinci minigrubun \(b\times c\) şeklinde \(\mathbf{Y}_1, \ldots, \mathbf{Y}_n\) \(n\) matrisi içerdiğini varsayalım. Onların toplu matris çarpımı, \(\mathbf{X}_1\mathbf{Y}_1, \ldots, \mathbf{X}_n\mathbf{Y}_n\) \(a\times c\) şeklinde \(n\) matris ile sonuçlanır. Bu nedenle, (\(n\), \(a\), \(b\)) ve (\(n\), \(b\), \(c\)) şeklinde iki tensör verildiğinde, toplu matris çarpım çıktılarının şekli (\(n\), \(a\), \(c\))’dir.

X = np.ones((2, 1, 4))
Y = np.ones((2, 4, 6))
npx.batch_dot(X, Y).shape
(2, 1, 6)
X = torch.ones((2, 1, 4))
Y = torch.ones((2, 4, 6))
torch.bmm(X, Y).shape
torch.Size([2, 1, 6])
X = tf.ones((2, 1, 4))
Y = tf.ones((2, 4, 6))
tf.matmul(X, Y).shape
TensorShape([2, 1, 6])

Dikkat mekanizmaları bağlamında, bir minigruptaki değerlerin ağırlıklı ortalamalarını hesaplamak için minigrup matris çarpımını kullanabiliriz.

weights = np.ones((2, 10)) * 0.1
values = np.arange(20).reshape((2, 10))
npx.batch_dot(np.expand_dims(weights, 1), np.expand_dims(values, -1))
array([[[ 4.5]],

       [[14.5]]])
weights = torch.ones((2, 10)) * 0.1
values = torch.arange(20.0).reshape((2, 10))
torch.bmm(weights.unsqueeze(1), values.unsqueeze(-1))
tensor([[[ 4.5000]],

        [[14.5000]]])
weights = tf.ones((2, 10)) * 0.1
values = tf.reshape(tf.range(20.0), shape = (2, 10))
tf.matmul(tf.expand_dims(weights, axis=1), tf.expand_dims(values, axis=-1)).numpy()
array([[[ 4.5]],

       [[14.5]]], dtype=float32)

10.2.4.2. Modeli Tanımlama

Minigrup matris çarpımını kullanarak, aşağıda (10.2.7) denklemindeki parametrik dikkat ortaklamayı temel alan Nadaraya-Watson çekirdek regresyonunun parametrik versiyonunu tanımlıyoruz.

class NWKernelRegression(nn.Block):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.w = self.params.get('w', shape=(1,))

    def forward(self, queries, keys, values):
        # `queries` ve `attention_weights` çıktısının şekli:
        # (sorgu sayısı, anahtar/değer çifti sayısı)
        queries = queries.repeat(keys.shape[1]).reshape((-1, keys.shape[1]))
        self.attention_weights = npx.softmax(
            -((queries - keys) * self.w.data())**2 / 2)
        # `values` (değerler) şekli: (sorgu sayısı, anahtar/değer çifti sayısı)
        return npx.batch_dot(np.expand_dims(self.attention_weights, 1),
                             np.expand_dims(values, -1)).reshape(-1)
class NWKernelRegression(nn.Module):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.w = nn.Parameter(torch.rand((1,), requires_grad=True))

    def forward(self, queries, keys, values):
        # `queries` ve `attention_weights` çıktısının şekli:
        # (sorgu sayısı, anahtar/değer çifti sayısı)
        queries = queries.repeat_interleave(keys.shape[1]).reshape((-1, keys.shape[1]))
        self.attention_weights = nn.functional.softmax(
            -((queries - keys) * self.w)**2 / 2, dim=1)
        # `values` (değerler) şekli: (sorgu sayısı, anahtar/değer çifti sayısı)
        return torch.bmm(self.attention_weights.unsqueeze(1),
                         values.unsqueeze(-1)).reshape(-1)
class NWKernelRegression(tf.keras.layers.Layer):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.w = tf.Variable(initial_value=tf.random.uniform(shape=(1,)))

    def call(self, queries, keys, values, **kwargs):
        # For training queries are `x_train`. Keys are distance of taining data for each point. Values are `y_train`.
        # Shape of the output `queries` and `attention_weights`: (no. of queries, no. of key-value pairs)
        queries = tf.repeat(tf.expand_dims(queries, axis=1), repeats=keys.shape[1], axis=1)
        self.attention_weights = tf.nn.softmax(-((queries - keys) * self.w)**2 /2, axis =1)
        # Shape of `values`: (no. of queries, no. of key-value pairs)
        return tf.squeeze(tf.matmul(tf.expand_dims(self.attention_weights, axis=1), tf.expand_dims(values, axis=-1)))

10.2.4.3. Eğitim

Aşağıda, dikkat modelini eğitmek için eğitim veri kümesini anahtar ve değerlere dönüştürürüz. Parametrik dikkat ortaklamada, herhangi bir eğitim girdisi çıktısını tahmin etmek için kendisi dışındaki tüm eğitim örneklerinden anahtar-değer çiftlerini alır.

# `X_tile`'in şekli: (`n_train`, `n_train`), burada her sütun aynı
#  eğitim girdilerini içerir
X_tile = np.tile(x_train, (n_train, 1))
# `Y_tile`'in şekli: (`n_train`, `n_train`), burada her sütun aynı
# eğitim çıktılarını içerir
Y_tile = np.tile(y_train, (n_train, 1))
# `keys`'in şekli: (`n_train`, `n_train` - 1)
keys = X_tile[(1 - np.eye(n_train)).astype('bool')].reshape((n_train, -1))
# `values`'in şekli: (`n_train`, `n_train` - 1)
values = Y_tile[(1 - np.eye(n_train)).astype('bool')].reshape((n_train, -1))
# `X_tile`'in şekli: (`n_train`, `n_train`), burada her sütun aynı
#  eğitim girdilerini içerir
X_tile = x_train.repeat((n_train, 1))
# `Y_tile`'in şekli: (`n_train`, `n_train`), burada her sütun aynı
# eğitim çıktılarını içerir
Y_tile = y_train.repeat((n_train, 1))
# `keys`'in şekli: (`n_train`, `n_train` - 1)
keys = X_tile[(1 - torch.eye(n_train)).type(torch.bool)].reshape((n_train, -1))
# `values`'in şekli: (`n_train`, `n_train` - 1)
values = Y_tile[(1 - torch.eye(n_train)).type(torch.bool)].reshape((n_train, -1))
# `X_tile`'in şekli: (`n_train`, `n_train`), burada her sütun aynı
#  eğitim girdilerini içerir
X_tile = tf.repeat(tf.expand_dims(x_train, axis=0), repeats=n_train, axis=0)
# `Y_tile`'in şekli: (`n_train`, `n_train`), burada her sütun aynı
# eğitim çıktılarını içerir
Y_tile = tf.repeat(tf.expand_dims(y_train, axis=0), repeats=n_train, axis=0)
# `keys`'in şekli: (`n_train`, `n_train` - 1)
keys = tf.reshape(X_tile[tf.cast(1 - tf.eye(n_train), dtype=tf.bool)], shape=(n_train, -1))
# `values`'in şekli: (`n_train`, `n_train` - 1)
values = tf.reshape(Y_tile[tf.cast(1 - tf.eye(n_train), dtype=tf.bool)], shape=(n_train, -1))

Kare kayıp ve rasgele gradyan inişi kullanarak, parametrik dikkat modelini eğitiriz.

net = NWKernelRegression()
net.initialize()
loss = gluon.loss.L2Loss()
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.5})
animator = d2l.Animator(xlabel='epoch', ylabel='loss', xlim=[1, 5])

for epoch in range(5):
    with autograd.record():
        l = loss(net(x_train, keys, values), y_train)
    l.backward()
    trainer.step(1)
    print(f'epoch {epoch + 1}, loss {float(l.sum()):.6f}')
    animator.add(epoch + 1, float(l.sum()))
../_images/output_nadaraya-watson_61a333_113_0.svg
net = NWKernelRegression()
loss = nn.MSELoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=0.5)
animator = d2l.Animator(xlabel='epoch', ylabel='loss', xlim=[1, 5])

for epoch in range(5):
    trainer.zero_grad()
    l = loss(net(x_train, keys, values), y_train)
    l.sum().backward()
    trainer.step()
    print(f'epoch {epoch + 1}, loss {float(l.sum()):.6f}')
    animator.add(epoch + 1, float(l.sum()))
../_images/output_nadaraya-watson_61a333_116_0.svg
net = NWKernelRegression()
loss_object = tf.keras.losses.MeanSquaredError()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.5)
animator = d2l.Animator(xlabel='epoch', ylabel='loss', xlim=[1, 5])


for epoch in range(5):
    with tf.GradientTape() as t:
        loss = loss_object(y_train, net(x_train, keys, values)) * len(y_train)
    grads = t.gradient(loss, net.trainable_variables)
    optimizer.apply_gradients(zip(grads, net.trainable_variables))
    print(f'epoch {epoch + 1}, loss {float(loss):.6f}')
    animator.add(epoch + 1, float(loss))
../_images/output_nadaraya-watson_61a333_119_0.svg

Parametrik dikkat modelini eğittikten sonra, tahminini çizebiliriz. Eğitim veri kümesini gürültüye oturtmaya çalışırken, tahmin edilen çizgi, daha önce çizilen parametrik olmayan karşılığından daha az pürüzsüzdür.

# `keys`'in şekli: (`n_test`, `n_train`), burada her sütun aynı eğitim
# girdilerini (yani aynı anahtarları) içerir
keys = np.tile(x_train, (n_test, 1))
# `value`'in şekli: (`n_test`, `n_train`)
values = np.tile(y_train, (n_test, 1))
y_hat = net(x_test, keys, values)
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_125_0.svg
# `keys`'in şekli: (`n_test`, `n_train`), burada her sütun aynı eğitim
# girdilerini (yani aynı anahtarları) içerir
keys = x_train.repeat((n_test, 1))
# `value`'in şekli: (`n_test`, `n_train`)
values = y_train.repeat((n_test, 1))
y_hat = net(x_test, keys, values).unsqueeze(1).detach()
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_128_0.svg
# `keys`'in şekli: (`n_test`, `n_train`), burada her sütun aynı eğitim
# girdilerini (yani aynı anahtarları) içerir
keys = tf.repeat(tf.expand_dims(x_train, axis=0), repeats=n_test, axis=0)
# `value`'in şekli: (`n_test`, `n_train`)
values = tf.repeat(tf.expand_dims(y_train, axis=0), repeats=n_test, axis=0)
y_hat = net(x_test, keys, values)
plot_kernel_reg(y_hat)
../_images/output_nadaraya-watson_61a333_131_0.svg

Parametrik olmayan dikkat ortaklama ile karşılaştırıldığında, öğrenilebilir ve parametrik ayarda büyük dikkat ağırlıkları olan bölge daha keskinleşir.

d2l.show_heatmaps(np.expand_dims(np.expand_dims(net.attention_weights, 0), 0),
                  xlabel='Sorted training inputs',
                  ylabel='Sorted testing inputs')
../_images/output_nadaraya-watson_61a333_137_0.svg
d2l.show_heatmaps(net.attention_weights.unsqueeze(0).unsqueeze(0),
                  xlabel='Sorted training inputs',
                  ylabel='Sorted testing inputs')
../_images/output_nadaraya-watson_61a333_140_0.svg
d2l.show_heatmaps(tf.expand_dims(tf.expand_dims(net.attention_weights, axis=0), axis=0),
                  xlabel='Sorted training inputs',
                  ylabel='Sorted testing inputs')
../_images/output_nadaraya-watson_61a333_143_0.svg

10.2.5. Özet

  • Nadaraya-Watson çekirdek regresyonu, makine öğrenmesinin dikkat mekanizmaları ile bir örneğidir.

  • Nadaraya-Watson çekirdek regresyonunun dikkat ortaklaması, eğitim çıktılarının ağırlıklı bir ortalamasıdır. Dikkat açısından bakıldığında, dikkat ağırlığı, bir sorgunun işlevine ve değerle eşleştirilmiş anahtara dayanan bir değere atanır.

  • Dikkat ortaklama parametrik olabilir de olmayabilir de.

10.2.6. Alıştırmalar

  1. Eğitim örneklerinin sayısını artırın. Parametrik olmayan Nadaraya-Watson çekirdek regresyonunu daha iyi öğrenebilir misin?

  2. Parametrik dikkat ortaklama deneyinde öğrendiğimiz \(w\)’nin değeri nedir? Dikkat ağırlıklarını görselleştirirken ağırlıklı bölgeyi neden daha keskin hale getiriyor?

  3. Daha iyi tahmin etmek için parametrik olmayan Nadaraya-Watson çekirdek regresyonuna nasıl hiper parametre ekleyebiliriz?

  4. Bu bölümün çekirdek regresyonu için başka bir parametrik dikkat ortaklama tasarlayın. Bu yeni modeli eğitin ve dikkat ağırlıklarını görselleştirin.