mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
422 lines
19 KiB
Markdown
422 lines
19 KiB
Markdown
# 4. Dikkat Mekanizmaları
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Dikkat Mekanizmaları ve Sinir Ağlarındaki Kendine Dikkat
|
||
|
||
Dikkat mekanizmaları, sinir ağlarının **her bir çıktı parçasını oluştururken girişin belirli kısımlarına odaklanmasını** sağlar. Farklı girişlere farklı ağırlıklar atayarak, modelin mevcut görevle en ilgili girişleri belirlemesine yardımcı olur. Bu, makine çevirisi gibi görevlerde, tüm cümlenin bağlamını anlamanın doğru çeviri için gerekli olduğu durumlarda kritik öneme sahiptir.
|
||
|
||
> [!TIP]
|
||
> Bu dördüncü aşamanın amacı çok basit: **Bazı dikkat mekanizmaları uygulamak**. Bunlar, **LLM'yi eğitmek için kullanılan mevcut cümledeki bir kelimenin komşularıyla olan ilişkisini yakalayacak çok sayıda **tekrarlanan katman** olacak.**\
|
||
> Bunun için çok sayıda katman kullanılır, bu nedenle çok sayıda eğitilebilir parametre bu bilgiyi yakalayacaktır.
|
||
|
||
### Dikkat Mekanizmalarını Anlamak
|
||
|
||
Dil çevirisi için kullanılan geleneksel sıralı-sıralı modellerde, model bir giriş dizisini sabit boyutlu bir bağlam vektörüne kodlar. Ancak, bu yaklaşım uzun cümlelerle zorlanır çünkü sabit boyutlu bağlam vektörü gerekli tüm bilgileri yakalayamayabilir. Dikkat mekanizmaları, modelin her çıktı tokenini oluştururken tüm giriş tokenlerini dikkate almasına olanak tanıyarak bu sınırlamayı aşar.
|
||
|
||
#### Örnek: Makine Çevirisi
|
||
|
||
Almanca "Kannst du mir helfen diesen Satz zu übersetzen" cümlesini İngilizceye çevirmeyi düşünün. Kelime kelime çeviri, diller arasındaki dilbilgisel yapı farklılıkları nedeniyle gramer açısından doğru bir İngilizce cümle üretmez. Bir dikkat mekanizması, modelin çıktı cümlesinin her kelimesini oluştururken giriş cümlesinin ilgili kısımlarına odaklanmasını sağlar ve bu da daha doğru ve tutarlı bir çeviri ile sonuçlanır.
|
||
|
||
### Kendine Dikkate Giriş
|
||
|
||
Kendine dikkat, veya iç-dikkat, dikkat mekanizmasının tek bir dizide uygulanarak o dizinin bir temsilini hesapladığı bir mekanizmadır. Bu, dizideki her tokenin diğer tüm tokenlere dikkat etmesine olanak tanır ve modelin tokenler arasındaki bağımlılıkları, dizideki mesafelerine bakılmaksızın yakalamasına yardımcı olur.
|
||
|
||
#### Temel Kavramlar
|
||
|
||
- **Tokenler**: Giriş dizisinin bireysel elemanları (örneğin, bir cümledeki kelimeler).
|
||
- **Gömme**: Anlamsal bilgiyi yakalayan tokenlerin vektör temsilleri.
|
||
- **Dikkat Ağırlıkları**: Her tokenin diğerlerine göre önemini belirleyen değerler.
|
||
|
||
### Dikkat Ağırlıklarını Hesaplama: Adım Adım Bir Örnek
|
||
|
||
**"Hello shiny sun!"** cümlesini ele alalım ve her kelimeyi 3 boyutlu bir gömme ile temsil edelim:
|
||
|
||
- **Hello**: `[0.34, 0.22, 0.54]`
|
||
- **shiny**: `[0.53, 0.34, 0.98]`
|
||
- **sun**: `[0.29, 0.54, 0.93]`
|
||
|
||
Amacımız, **shiny** kelimesi için kendine dikkat kullanarak **bağlam vektörünü** hesaplamaktır.
|
||
|
||
#### Adım 1: Dikkat Puanlarını Hesapla
|
||
|
||
> [!TIP]
|
||
> Sadece sorgunun her boyut değerini ilgili tokenin boyut değeri ile çarpın ve sonuçları toplayın. Her token çifti için 1 değer elde edersiniz.
|
||
|
||
Cümledeki her kelime için, **shiny** ile ilgili dikkat puanını, gömmelerinin noktasal çarpımını hesaplayarak hesaplayın.
|
||
|
||
**"Hello" ve "shiny" Arasındaki Dikkat Puanı**
|
||
|
||
<figure><img src="../../images/image (4) (1) (1).png" alt="" width="563"><figcaption></figcaption></figure>
|
||
|
||
**"shiny" ve "shiny" Arasındaki Dikkat Puanı**
|
||
|
||
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1).png" alt="" width="563"><figcaption></figcaption></figure>
|
||
|
||
**"sun" ve "shiny" Arasındaki Dikkat Puanı**
|
||
|
||
<figure><img src="../../images/image (2) (1) (1) (1) (1).png" alt="" width="563"><figcaption></figcaption></figure>
|
||
|
||
#### Adım 2: Dikkat Puanlarını Normalleştirerek Dikkat Ağırlıklarını Elde Et
|
||
|
||
> [!TIP]
|
||
> Matematiksel terimlerde kaybolmayın, bu fonksiyonun amacı basit, tüm ağırlıkları normalleştirin ki **toplamları 1 olsun**.
|
||
>
|
||
> Ayrıca, **softmax** fonksiyonu, üstel kısım nedeniyle farklılıkları vurguladığı için, yararlı değerleri tespit etmeyi kolaylaştırır.
|
||
|
||
Dikkat puanlarına **softmax fonksiyonunu** uygulayarak, toplamı 1 olan dikkat ağırlıklarına dönüştürün.
|
||
|
||
<figure><img src="../../images/image (3) (1) (1) (1) (1).png" alt="" width="293"><figcaption></figcaption></figure>
|
||
|
||
Üstel değerleri hesaplama:
|
||
|
||
<figure><img src="../../images/image (4) (1) (1).png" alt="" width="249"><figcaption></figcaption></figure>
|
||
|
||
Toplamı hesaplama:
|
||
|
||
<figure><img src="../../images/image (5) (1) (1).png" alt="" width="563"><figcaption></figcaption></figure>
|
||
|
||
Dikkat ağırlıklarını hesaplama:
|
||
|
||
<figure><img src="../../images/image (6) (1) (1).png" alt="" width="404"><figcaption></figcaption></figure>
|
||
|
||
#### Adım 3: Bağlam Vektörünü Hesapla
|
||
|
||
> [!TIP]
|
||
> Her dikkat ağırlığını alın ve ilgili token boyutlarıyla çarpın, ardından tüm boyutları toplayarak sadece 1 vektör (bağlam vektörü) elde edin.
|
||
|
||
**Bağlam vektörü**, tüm kelimelerin gömmelerinin ağırlıklı toplamı olarak hesaplanır ve dikkat ağırlıkları kullanılır.
|
||
|
||
<figure><img src="../../images/image (16).png" alt="" width="369"><figcaption></figcaption></figure>
|
||
|
||
Her bileşeni hesaplama:
|
||
|
||
- **"Hello" için Ağırlıklı Gömme**:
|
||
|
||
<figure><img src="../../images/image (7) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
- **"shiny" için Ağırlıklı Gömme**:
|
||
|
||
<figure><img src="../../images/image (8) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
- **"sun" için Ağırlıklı Gömme**:
|
||
|
||
<figure><img src="../../images/image (9) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
Ağırlıklı gömmeleri toplama:
|
||
|
||
`bağlam vektörü=[0.0779+0.2156+0.1057, 0.0504+0.1382+0.1972, 0.1237+0.3983+0.3390]=[0.3992,0.3858,0.8610]`
|
||
|
||
**Bu bağlam vektörü, "shiny" kelimesi için zenginleştirilmiş gömme temsilini, cümledeki tüm kelimelerden gelen bilgileri içerecek şekilde temsil eder.**
|
||
|
||
### Sürecin Özeti
|
||
|
||
1. **Dikkat Puanlarını Hesapla**: Hedef kelimenin gömmesi ile dizideki tüm kelimelerin gömmeleri arasındaki noktasal çarpımı kullanın.
|
||
2. **Ağırlıkları Elde Etmek için Puanları Normalleştir**: Dikkat puanlarına softmax fonksiyonunu uygulayarak toplamı 1 olan ağırlıklar elde edin.
|
||
3. **Bağlam Vektörünü Hesapla**: Her kelimenin gömmesini dikkat ağırlığı ile çarpın ve sonuçları toplayın.
|
||
|
||
## Eğitilebilir Ağırlıklarla Kendine Dikkat
|
||
|
||
Pratikte, kendine dikkat mekanizmaları **eğitilebilir ağırlıklar** kullanarak sorgular, anahtarlar ve değerler için en iyi temsilleri öğrenir. Bu, üç ağırlık matrisinin tanıtılmasını içerir:
|
||
|
||
<figure><img src="../../images/image (10) (1) (1).png" alt="" width="239"><figcaption></figcaption></figure>
|
||
|
||
Sorgu, daha önce olduğu gibi kullanılacak veridir, anahtarlar ve değerler matrisleri ise sadece rastgele eğitilebilir matrislerdir.
|
||
|
||
#### Adım 1: Sorguları, Anahtarları ve Değerleri Hesapla
|
||
|
||
Her token, tanımlanan matrislerle boyut değerlerini çarparak kendi sorgu, anahtar ve değer matrisine sahip olacaktır:
|
||
|
||
<figure><img src="../../images/image (11).png" alt="" width="253"><figcaption></figcaption></figure>
|
||
|
||
Bu matrisler, orijinal gömmeleri dikkat hesaplamaları için uygun yeni bir alana dönüştürür.
|
||
|
||
**Örnek**
|
||
|
||
Varsayalım:
|
||
|
||
- Giriş boyutu `din=3` (gömme boyutu)
|
||
- Çıkış boyutu `dout=2` (sorgular, anahtarlar ve değerler için istenen boyut)
|
||
|
||
Ağırlık matrislerini başlatın:
|
||
```python
|
||
import torch.nn as nn
|
||
|
||
d_in = 3
|
||
d_out = 2
|
||
|
||
W_query = nn.Parameter(torch.rand(d_in, d_out))
|
||
W_key = nn.Parameter(torch.rand(d_in, d_out))
|
||
W_value = nn.Parameter(torch.rand(d_in, d_out))
|
||
```
|
||
Sorguları, anahtarları ve değerleri hesapla:
|
||
```python
|
||
queries = torch.matmul(inputs, W_query)
|
||
keys = torch.matmul(inputs, W_key)
|
||
values = torch.matmul(inputs, W_value)
|
||
```
|
||
#### Adım 2: Ölçeklenmiş Nokta-Ürün Dikkatini Hesapla
|
||
|
||
**Dikkat Puanlarını Hesapla**
|
||
|
||
Önceki örneğe benzer, ancak bu sefer, token'ların boyutlarının değerlerini kullanmak yerine, token'ın anahtar matrisini (zaten boyutlar kullanılarak hesaplanmış) kullanıyoruz:. Yani, her sorgu `qi` ve anahtar `kj` için:
|
||
|
||
<figure><img src="../../images/image (12).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
**Puanları Ölçekle**
|
||
|
||
Nokta ürünlerinin çok büyük olmasını önlemek için, bunları anahtar boyutunun karekökü `dk` ile ölçeklendir:
|
||
|
||
<figure><img src="../../images/image (13).png" alt="" width="295"><figcaption></figcaption></figure>
|
||
|
||
> [!TIP]
|
||
> Puan, boyutların kareköküne bölünür çünkü nokta ürünleri çok büyük hale gelebilir ve bu, onları düzenlemeye yardımcı olur.
|
||
|
||
**Dikkat Ağırlıklarını Elde Etmek İçin Softmax Uygula:** İlk örnekte olduğu gibi, tüm değerleri normalize et, böylece toplamları 1 olur.
|
||
|
||
<figure><img src="../../images/image (14).png" alt="" width="295"><figcaption></figcaption></figure>
|
||
|
||
#### Adım 3: Bağlam Vektörlerini Hesapla
|
||
|
||
İlk örnekte olduğu gibi, her birini dikkat ağırlığı ile çarparak tüm değer matrislerini topla:
|
||
|
||
<figure><img src="../../images/image (15).png" alt="" width="328"><figcaption></figcaption></figure>
|
||
|
||
### Kod Örneği
|
||
|
||
[https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb) adresinden bir örnek alarak, bahsettiğimiz kendine dikkat işlevselliğini uygulayan bu sınıfı kontrol edebilirsiniz:
|
||
```python
|
||
import torch
|
||
|
||
inputs = torch.tensor(
|
||
[[0.43, 0.15, 0.89], # Your (x^1)
|
||
[0.55, 0.87, 0.66], # journey (x^2)
|
||
[0.57, 0.85, 0.64], # starts (x^3)
|
||
[0.22, 0.58, 0.33], # with (x^4)
|
||
[0.77, 0.25, 0.10], # one (x^5)
|
||
[0.05, 0.80, 0.55]] # step (x^6)
|
||
)
|
||
|
||
import torch.nn as nn
|
||
class SelfAttention_v2(nn.Module):
|
||
|
||
def __init__(self, d_in, d_out, qkv_bias=False):
|
||
super().__init__()
|
||
self.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
|
||
def forward(self, x):
|
||
keys = self.W_key(x)
|
||
queries = self.W_query(x)
|
||
values = self.W_value(x)
|
||
|
||
attn_scores = queries @ keys.T
|
||
attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)
|
||
|
||
context_vec = attn_weights @ values
|
||
return context_vec
|
||
|
||
d_in=3
|
||
d_out=2
|
||
torch.manual_seed(789)
|
||
sa_v2 = SelfAttention_v2(d_in, d_out)
|
||
print(sa_v2(inputs))
|
||
```
|
||
> [!TIP]
|
||
> Matrisleri rastgele değerlerle başlatmak yerine, tüm ağırlıkları eğitilecek parametreler olarak işaretlemek için `nn.Linear` kullanıldığını unutmayın.
|
||
|
||
## Nedensel Dikkat: Gelecek Kelimeleri Gizleme
|
||
|
||
LLM'ler için modelin, **bir sonraki token'ı tahmin etmek** amacıyla mevcut pozisyondan önceki token'ları dikkate almasını istiyoruz. **Nedensel dikkat**, aynı zamanda **maskelenmiş dikkat** olarak da bilinir, dikkat mekanizmasını değiştirerek gelecekteki token'lara erişimi engelleyerek bunu başarır.
|
||
|
||
### Nedensel Dikkat Maskesi Uygulama
|
||
|
||
Nedensel dikkati uygulamak için, dikkat puanlarına **softmax işleminden önce** bir maske uygularız, böylece kalanlar hala 1'e toplamış olur. Bu maske, gelecekteki token'ların dikkat puanlarını negatif sonsuz olarak ayarlayarak, softmax'tan sonra dikkat ağırlıklarının sıfır olmasını sağlar.
|
||
|
||
**Adımlar**
|
||
|
||
1. **Dikkat Puanlarını Hesapla**: Önceki gibi.
|
||
2. **Maske Uygula**: Diyagonalın üstünde negatif sonsuz ile doldurulmuş bir üst üçgen matris kullanın.
|
||
|
||
```python
|
||
mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1) * float('-inf')
|
||
masked_scores = attention_scores + mask
|
||
```
|
||
|
||
3. **Softmax Uygula**: Maskelenmiş puanları kullanarak dikkat ağırlıklarını hesaplayın.
|
||
|
||
```python
|
||
attention_weights = torch.softmax(masked_scores, dim=-1)
|
||
```
|
||
|
||
### Ek Dikkat Ağırlıklarını Dropout ile Maskeleme
|
||
|
||
**Aşırı uyum sağlamayı önlemek** için, softmax işleminden sonra dikkat ağırlıklarına **dropout** uygulayabiliriz. Dropout, eğitim sırasında **dikkat ağırlıklarının bazılarını rastgele sıfırlar**.
|
||
```python
|
||
dropout = nn.Dropout(p=0.5)
|
||
attention_weights = dropout(attention_weights)
|
||
```
|
||
Bir normal dropout yaklaşık %10-20'dir.
|
||
|
||
### Kod Örneği
|
||
|
||
Kod örneği [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb):
|
||
```python
|
||
import torch
|
||
import torch.nn as nn
|
||
|
||
inputs = torch.tensor(
|
||
[[0.43, 0.15, 0.89], # Your (x^1)
|
||
[0.55, 0.87, 0.66], # journey (x^2)
|
||
[0.57, 0.85, 0.64], # starts (x^3)
|
||
[0.22, 0.58, 0.33], # with (x^4)
|
||
[0.77, 0.25, 0.10], # one (x^5)
|
||
[0.05, 0.80, 0.55]] # step (x^6)
|
||
)
|
||
|
||
batch = torch.stack((inputs, inputs), dim=0)
|
||
print(batch.shape)
|
||
|
||
class CausalAttention(nn.Module):
|
||
|
||
def __init__(self, d_in, d_out, context_length,
|
||
dropout, qkv_bias=False):
|
||
super().__init__()
|
||
self.d_out = d_out
|
||
self.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.dropout = nn.Dropout(dropout)
|
||
self.register_buffer('mask', torch.triu(torch.ones(context_length, context_length), diagonal=1)) # New
|
||
|
||
def forward(self, x):
|
||
b, num_tokens, d_in = x.shape
|
||
# b is the num of batches
|
||
# num_tokens is the number of tokens per batch
|
||
# d_in is the dimensions er token
|
||
|
||
keys = self.W_key(x) # This generates the keys of the tokens
|
||
queries = self.W_query(x)
|
||
values = self.W_value(x)
|
||
|
||
attn_scores = queries @ keys.transpose(1, 2) # Moves the third dimension to the second one and the second one to the third one to be able to multiply
|
||
attn_scores.masked_fill_( # New, _ ops are in-place
|
||
self.mask.bool()[:num_tokens, :num_tokens], -torch.inf) # `:num_tokens` to account for cases where the number of tokens in the batch is smaller than the supported context_size
|
||
attn_weights = torch.softmax(
|
||
attn_scores / keys.shape[-1]**0.5, dim=-1
|
||
)
|
||
attn_weights = self.dropout(attn_weights)
|
||
|
||
context_vec = attn_weights @ values
|
||
return context_vec
|
||
|
||
torch.manual_seed(123)
|
||
|
||
context_length = batch.shape[1]
|
||
d_in = 3
|
||
d_out = 2
|
||
ca = CausalAttention(d_in, d_out, context_length, 0.0)
|
||
|
||
context_vecs = ca(batch)
|
||
|
||
print(context_vecs)
|
||
print("context_vecs.shape:", context_vecs.shape)
|
||
```
|
||
## Tek Başlı Dikkati Çok Başlı Dikkate Genişletme
|
||
|
||
**Çok başlı dikkat**, pratikte **kendi ağırlıklarıyla** her biri **birden fazla örneği** kendine dikkat fonksiyonunu çalıştırmaktan oluşur, böylece farklı son vektörler hesaplanır.
|
||
|
||
### Kod Örneği
|
||
|
||
Önceki kodu yeniden kullanmak ve sadece birkaç kez çalıştıran bir sarmalayıcı eklemek mümkün olabilir, ancak bu, tüm başları aynı anda işleyen [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb) adresinden daha optimize edilmiş bir versiyondur (pahalı for döngülerinin sayısını azaltır). Kodda görebileceğiniz gibi, her bir token'ın boyutları baş sayısına göre farklı boyutlara bölünmüştür. Bu şekilde, eğer token 8 boyuta sahipse ve 3 baş kullanmak istiyorsak, boyutlar 4 boyuttan oluşan 2 diziye bölünecek ve her baş bunlardan birini kullanacaktır:
|
||
```python
|
||
class MultiHeadAttention(nn.Module):
|
||
def __init__(self, d_in, d_out, context_length, dropout, num_heads, qkv_bias=False):
|
||
super().__init__()
|
||
assert (d_out % num_heads == 0), \
|
||
"d_out must be divisible by num_heads"
|
||
|
||
self.d_out = d_out
|
||
self.num_heads = num_heads
|
||
self.head_dim = d_out // num_heads # Reduce the projection dim to match desired output dim
|
||
|
||
self.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)
|
||
self.out_proj = nn.Linear(d_out, d_out) # Linear layer to combine head outputs
|
||
self.dropout = nn.Dropout(dropout)
|
||
self.register_buffer(
|
||
"mask",
|
||
torch.triu(torch.ones(context_length, context_length),
|
||
diagonal=1)
|
||
)
|
||
|
||
def forward(self, x):
|
||
b, num_tokens, d_in = x.shape
|
||
# b is the num of batches
|
||
# num_tokens is the number of tokens per batch
|
||
# d_in is the dimensions er token
|
||
|
||
keys = self.W_key(x) # Shape: (b, num_tokens, d_out)
|
||
queries = self.W_query(x)
|
||
values = self.W_value(x)
|
||
|
||
# We implicitly split the matrix by adding a `num_heads` dimension
|
||
# Unroll last dim: (b, num_tokens, d_out) -> (b, num_tokens, num_heads, head_dim)
|
||
keys = keys.view(b, num_tokens, self.num_heads, self.head_dim)
|
||
values = values.view(b, num_tokens, self.num_heads, self.head_dim)
|
||
queries = queries.view(b, num_tokens, self.num_heads, self.head_dim)
|
||
|
||
# Transpose: (b, num_tokens, num_heads, head_dim) -> (b, num_heads, num_tokens, head_dim)
|
||
keys = keys.transpose(1, 2)
|
||
queries = queries.transpose(1, 2)
|
||
values = values.transpose(1, 2)
|
||
|
||
# Compute scaled dot-product attention (aka self-attention) with a causal mask
|
||
attn_scores = queries @ keys.transpose(2, 3) # Dot product for each head
|
||
|
||
# Original mask truncated to the number of tokens and converted to boolean
|
||
mask_bool = self.mask.bool()[:num_tokens, :num_tokens]
|
||
|
||
# Use the mask to fill attention scores
|
||
attn_scores.masked_fill_(mask_bool, -torch.inf)
|
||
|
||
attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)
|
||
attn_weights = self.dropout(attn_weights)
|
||
|
||
# Shape: (b, num_tokens, num_heads, head_dim)
|
||
context_vec = (attn_weights @ values).transpose(1, 2)
|
||
|
||
# Combine heads, where self.d_out = self.num_heads * self.head_dim
|
||
context_vec = context_vec.contiguous().view(b, num_tokens, self.d_out)
|
||
context_vec = self.out_proj(context_vec) # optional projection
|
||
|
||
return context_vec
|
||
|
||
torch.manual_seed(123)
|
||
|
||
batch_size, context_length, d_in = batch.shape
|
||
d_out = 2
|
||
mha = MultiHeadAttention(d_in, d_out, context_length, 0.0, num_heads=2)
|
||
|
||
context_vecs = mha(batch)
|
||
|
||
print(context_vecs)
|
||
print("context_vecs.shape:", context_vecs.shape)
|
||
|
||
```
|
||
Başka bir kompakt ve verimli uygulama için PyTorch'taki [`torch.nn.MultiheadAttention`](https://pytorch.org/docs/stable/generated/torch.nn.MultiheadAttention.html) sınıfını kullanabilirsiniz.
|
||
|
||
> [!TIP]
|
||
> ChatGPT'nin, her başın tüm token'ların tüm boyutlarını kontrol etmesi yerine token'ların boyutlarını başlar arasında bölmenin neden daha iyi olduğuna dair kısa yanıtı:
|
||
>
|
||
> Her başın tüm gömme boyutlarını işlemesine izin vermek, her başın tam bilgiye erişimi olacağı için avantajlı gibi görünse de, standart uygulama **gömme boyutlarını başlar arasında bölmektir**. Bu yaklaşım, hesaplama verimliliği ile model performansını dengeleyerek her başın çeşitli temsilleri öğrenmesini teşvik eder. Bu nedenle, gömme boyutlarını bölmek, her başın tüm boyutları kontrol etmesinden genellikle tercih edilir.
|
||
|
||
## References
|
||
|
||
- [https://www.manning.com/books/build-a-large-language-model-from-scratch](https://www.manning.com/books/build-a-large-language-model-from-scratch)
|
||
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|