26  Úvod do transformerů

26.1 Motivace: Revoluce v AI

V roce 2017 výzkumníci z Google publikovali článek “Attention Is All You Need” a představili architekturu Transformer. Od té doby transformery změnily svět AI:

  • GPT (OpenAI) - generování textu
  • BERT (Google) - porozumění jazyku
  • ChatGPT, Claude - konverzační AI
  • DALL-E, Stable Diffusion - generování obrázků
  • AlphaFold - predikce struktury proteinů

Klíčem k úspěchu transformerů je mechanismus attention (pozornost), který umožňuje modelu “zaměřit se” na relevantní části vstupu.

import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.nn.functional as F

# Vizualizace attention
fig, ax = plt.subplots(figsize=(10, 8))

# Příklad věty
words_from = ['The', 'cat', 'sat', 'on', 'the', 'mat']
words_to = words_from.copy()

# Simulované attention váhy (které slovo se dívá na které)
np.random.seed(42)
attention = np.array([
    [0.7, 0.1, 0.1, 0.05, 0.03, 0.02],  # The
    [0.1, 0.5, 0.1, 0.1, 0.1, 0.1],      # cat
    [0.05, 0.4, 0.3, 0.1, 0.1, 0.05],    # sat
    [0.1, 0.2, 0.1, 0.4, 0.1, 0.1],      # on
    [0.3, 0.1, 0.1, 0.1, 0.3, 0.1],      # the
    [0.1, 0.3, 0.2, 0.1, 0.1, 0.2],      # mat
])

# Heatmapa
im = ax.imshow(attention, cmap='Blues', aspect='auto')

ax.set_xticks(range(len(words_to)))
ax.set_yticks(range(len(words_from)))
ax.set_xticklabels(words_to, fontsize=12)
ax.set_yticklabels(words_from, fontsize=12)

ax.set_xlabel('Na které slovo se díváme', fontsize=12)
ax.set_ylabel('Které slovo se dívá', fontsize=12)
ax.set_title('Self-Attention: Které slovo je důležité pro které?', fontsize=14)

# Hodnoty v buňkách
for i in range(len(words_from)):
    for j in range(len(words_to)):
        text = ax.text(j, i, f'{attention[i, j]:.2f}',
                      ha='center', va='center', fontsize=10,
                      color='white' if attention[i, j] > 0.3 else 'black')

plt.colorbar(im, label='Attention váha')
plt.tight_layout()
plt.show()

26.2 Co je Attention?

Attention mechanismus umožňuje modelu dynamicky vybírat, na které části vstupu se zaměřit při zpracování každé pozice.

PoznámkaIntuice: Attention jako vyhledávání

Představte si attention jako systém Query-Key-Value:

  • Query (Q): “Co hledám?”
  • Key (K): “Co nabízím?”
  • Value (V): “Jakou informaci mám?”

Výstup = vážený součet Values, kde váhy jsou určeny podobností Query a Keys.

import numpy as np

def simple_attention(query, keys, values):
    """
    Jednoduchý attention mechanismus.

    Args:
        query: Co hledáme (d_k,)
        keys: Klíče (n, d_k)
        values: Hodnoty (n, d_v)

    Returns:
        Vážený součet values
    """
    # Skóre = podobnost query a keys (dot product)
    scores = keys @ query

    # Váhy = softmax(skóre)
    weights = np.exp(scores) / np.sum(np.exp(scores))

    # Výstup = vážený součet values
    output = values.T @ weights

    return output, weights

# Příklad
np.random.seed(42)
d_k, d_v, n = 4, 3, 5

query = np.random.randn(d_k)
keys = np.random.randn(n, d_k)
values = np.random.randn(n, d_v)

output, weights = simple_attention(query, keys, values)

print("Jednoduchý Attention:")
print(f"  Query shape: {query.shape}")
print(f"  Keys shape: {keys.shape}")
print(f"  Values shape: {values.shape}")
print(f"  Attention weights: {weights.round(3)}")
print(f"  Output shape: {output.shape}")
Jednoduchý Attention:
  Query shape: (4,)
  Keys shape: (5, 4)
  Values shape: (5, 3)
  Attention weights: [0.915 0.03  0.023 0.004 0.028]
  Output shape: (3,)

26.3 Scaled Dot-Product Attention

Transformery používají scaled dot-product attention:

PoznámkaScaled Dot-Product Attention

\[\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V\]

kde: - \(Q \in \mathbb{R}^{n \times d_k}\) jsou queries - \(K \in \mathbb{R}^{n \times d_k}\) jsou keys - \(V \in \mathbb{R}^{n \times d_v}\) jsou values - \(\sqrt{d_k}\) je škálovací faktor

import numpy as np
import matplotlib.pyplot as plt

def scaled_dot_product_attention(Q, K, V, mask=None):
    """
    Scaled Dot-Product Attention.

    Args:
        Q: Queries (batch, n, d_k)
        K: Keys (batch, n, d_k)
        V: Values (batch, n, d_v)
        mask: Volitelná maska pro kauzální attention
    """
    d_k = Q.shape[-1]

    # Skóre - transpozice posledních dvou dimenzí
    K_T = np.swapaxes(K, -2, -1)  # Transpozice pro NumPy
    scores = Q @ K_T / np.sqrt(d_k)

    # Aplikace masky (pro dekodér)
    if mask is not None:
        scores = np.where(mask, scores, -1e9)

    # Softmax přes keys
    attention_weights = np.exp(scores - np.max(scores, axis=-1, keepdims=True))
    attention_weights = attention_weights / np.sum(attention_weights, axis=-1, keepdims=True)

    # Vážený součet values
    output = attention_weights @ V

    return output, attention_weights

# Příklad s sekvencí
seq_len, d_k, d_v = 4, 8, 8

Q = np.random.randn(1, seq_len, d_k)
K = np.random.randn(1, seq_len, d_k)
V = np.random.randn(1, seq_len, d_v)

output, weights = scaled_dot_product_attention(Q, K, V)

print("Scaled Dot-Product Attention:")
print(f"  Vstup Q, K, V: (1, {seq_len}, {d_k})")
print(f"  Attention weights: {weights[0].round(2)}")
print(f"  Výstup: {output.shape}")

# Vizualizace attention weights
plt.figure(figsize=(8, 6))
plt.imshow(weights[0], cmap='Blues')
plt.colorbar(label='Attention váha')
plt.xlabel('Key pozice')
plt.ylabel('Query pozice')
plt.title('Attention Weights')
plt.show()
Scaled Dot-Product Attention:
  Vstup Q, K, V: (1, 4, 8)
  Attention weights: [[0.2  0.2  0.22 0.39]
 [0.18 0.3  0.27 0.25]
 [0.27 0.09 0.48 0.16]
 [0.24 0.33 0.18 0.26]]
  Výstup: (1, 4, 8)

26.4 Multi-Head Attention

Transformery používají více attention hlav paralelně, každá se zaměřuje na jiné aspekty:

PoznámkaMulti-Head Attention

\[\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h)W^O\]

kde každá hlava: \[\text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)\]

import numpy as np

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, n_heads):
        super().__init__()
        self.n_heads = n_heads
        self.d_k = d_model // n_heads

        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)

    def forward(self, Q, K, V, mask=None):
        batch_size = Q.size(0)

        # Lineární projekce a rozdělení na hlavy
        Q = self.W_q(Q).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        K = self.W_k(K).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        V = self.W_v(V).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)

        # Attention
        scores = Q @ K.transpose(-2, -1) / np.sqrt(self.d_k)
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
        attention = F.softmax(scores, dim=-1)
        x = attention @ V

        # Spojení hlav
        x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.n_heads * self.d_k)

        return self.W_o(x), attention

# Test
torch.manual_seed(42)
d_model, n_heads, seq_len = 64, 8, 10

mha = MultiHeadAttention(d_model, n_heads)
x = torch.randn(2, seq_len, d_model)

output, attn = mha(x, x, x)

print("Multi-Head Attention:")
print(f"  Vstup: {x.shape}")
print(f"  Počet hlav: {n_heads}")
print(f"  d_k na hlavu: {d_model // n_heads}")
print(f"  Výstup: {output.shape}")
print(f"  Attention shape: {attn.shape}")
Multi-Head Attention:
  Vstup: torch.Size([2, 10, 64])
  Počet hlav: 8
  d_k na hlavu: 8
  Výstup: torch.Size([2, 10, 64])
  Attention shape: torch.Size([2, 8, 10, 10])

26.4.1 Vizualizace více hlav

# Vizualizace attention pro různé hlavy
import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 4, figsize=(16, 8))

for i, ax in enumerate(axes.flatten()):
    if i < n_heads:
        im = ax.imshow(attn[0, i].detach().numpy(), cmap='Blues')
        ax.set_title(f'Hlava {i+1}')
        ax.set_xlabel('Key')
        ax.set_ylabel('Query')

plt.suptitle('Multi-Head Attention: Každá hlava se zaměřuje na něco jiného', fontsize=14)
plt.tight_layout()
plt.show()

26.5 Pozicové kódování

Attention je permutačně invariantní - nezáleží na pořadí. Pro zachycení pozice přidáváme positional encoding:

PoznámkaSinusoidální pozicové kódování

\[PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)\] \[PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)\]

Různé frekvence pro různé dimenze umožňují modelu rozlišovat pozice.

import numpy as np
import matplotlib.pyplot as plt

def positional_encoding(seq_len, d_model):
    """Generuje sinusoidální pozicové kódování."""
    PE = np.zeros((seq_len, d_model))

    position = np.arange(seq_len)[:, np.newaxis]
    div_term = np.exp(np.arange(0, d_model, 2) * (-np.log(10000.0) / d_model))

    PE[:, 0::2] = np.sin(position * div_term)
    PE[:, 1::2] = np.cos(position * div_term)

    return PE

# Vizualizace
seq_len, d_model = 50, 64
PE = positional_encoding(seq_len, d_model)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

# Heatmapa
im = ax1.imshow(PE, cmap='RdBu', aspect='auto')
ax1.set_xlabel('Dimenze')
ax1.set_ylabel('Pozice')
ax1.set_title('Pozicové kódování')
plt.colorbar(im, ax=ax1)

# Jednotlivé dimenze
for i in [0, 1, 4, 5, 10, 11]:
    ax2.plot(PE[:, i], label=f'dim {i}')
ax2.set_xlabel('Pozice')
ax2.set_ylabel('Hodnota')
ax2.set_title('Pozicové kódování pro vybrané dimenze')
ax2.legend()
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

26.6 Transformer blok

Kompletní Transformer blok obsahuje:

  1. Multi-Head Self-Attention
  2. Add & Norm (residual connection + layer normalization)
  3. Feed-Forward Network
  4. Add & Norm
class TransformerBlock(nn.Module):
    def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
        super().__init__()

        self.attention = MultiHeadAttention(d_model, n_heads)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)

        self.ff = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.GELU(),
            nn.Linear(d_ff, d_model),
            nn.Dropout(dropout)
        )

        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        # Self-Attention + Residual
        attn_out, _ = self.attention(x, x, x, mask)
        x = self.norm1(x + self.dropout(attn_out))

        # Feed-Forward + Residual
        ff_out = self.ff(x)
        x = self.norm2(x + ff_out)

        return x

# Test
block = TransformerBlock(d_model=64, n_heads=8, d_ff=256)
x = torch.randn(2, 10, 64)
output = block(x)

print("Transformer Block:")
print(f"  Vstup: {x.shape}")
print(f"  Výstup: {output.shape}")
Transformer Block:
  Vstup: torch.Size([2, 10, 64])
  Výstup: torch.Size([2, 10, 64])

26.6.1 Architektura bloku

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(8, 12))

# Komponenty
components = [
    (0.5, 0.9, 'Input Embeddings', '#3498db'),
    (0.5, 0.78, 'Positional Encoding', '#9b59b6'),
    (0.5, 0.65, 'Multi-Head\nSelf-Attention', '#2ecc71'),
    (0.5, 0.52, 'Add & Norm', '#f39c12'),
    (0.5, 0.39, 'Feed-Forward\nNetwork', '#e74c3c'),
    (0.5, 0.26, 'Add & Norm', '#f39c12'),
    (0.5, 0.13, 'Output', '#3498db'),
]

for x, y, label, color in components:
    rect = plt.Rectangle((x-0.15, y-0.05), 0.3, 0.1,
                         facecolor=color, edgecolor='black', lw=2)
    ax.add_patch(rect)
    ax.text(x, y, label, ha='center', va='center', fontsize=10, fontweight='bold')

# Šipky
for i in range(len(components) - 1):
    y1 = components[i][1] - 0.05
    y2 = components[i+1][1] + 0.05
    ax.annotate('', xy=(0.5, y2), xytext=(0.5, y1),
               arrowprops=dict(arrowstyle='->', color='black', lw=2))

# Residual connections
ax.annotate('', xy=(0.35, 0.57), xytext=(0.35, 0.7),
           arrowprops=dict(arrowstyle='->', color='gray', lw=1.5,
                          connectionstyle='arc3,rad=-0.3'))
ax.annotate('', xy=(0.35, 0.31), xytext=(0.35, 0.44),
           arrowprops=dict(arrowstyle='->', color='gray', lw=1.5,
                          connectionstyle='arc3,rad=-0.3'))
ax.text(0.25, 0.635, 'Residual', fontsize=8, color='gray')
ax.text(0.25, 0.375, 'Residual', fontsize=8, color='gray')

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
ax.set_title('Transformer Block', fontsize=14, fontweight='bold')

plt.tight_layout()
plt.show()

26.7 Jednoduchý GPT-style model

Sestavíme jednoduchý dekodérový model typu GPT:

class SimpleGPT(nn.Module):
    def __init__(self, vocab_size, d_model, n_heads, n_layers, max_len=512):
        super().__init__()

        self.token_embedding = nn.Embedding(vocab_size, d_model)
        self.position_embedding = nn.Embedding(max_len, d_model)

        self.blocks = nn.ModuleList([
            TransformerBlock(d_model, n_heads, d_model * 4)
            for _ in range(n_layers)
        ])

        self.ln_final = nn.LayerNorm(d_model)
        self.head = nn.Linear(d_model, vocab_size, bias=False)

    def forward(self, idx):
        B, T = idx.shape

        # Embeddingy
        tok_emb = self.token_embedding(idx)
        pos_emb = self.position_embedding(torch.arange(T, device=idx.device))
        x = tok_emb + pos_emb

        # Kauzální maska
        mask = torch.tril(torch.ones(T, T)).unsqueeze(0).unsqueeze(0)

        # Transformer bloky
        for block in self.blocks:
            x = block(x)

        # Výstup
        x = self.ln_final(x)
        logits = self.head(x)

        return logits

# Test
model = SimpleGPT(vocab_size=1000, d_model=64, n_heads=4, n_layers=2)
idx = torch.randint(0, 1000, (2, 20))
logits = model(idx)

print("Simple GPT:")
print(f"  Vstup (token ids): {idx.shape}")
print(f"  Výstup (logits): {logits.shape}")
print(f"  Počet parametrů: {sum(p.numel() for p in model.parameters()):,}")
Simple GPT:
  Vstup (token ids): torch.Size([2, 20])
  Výstup (logits): torch.Size([2, 20, 1000])
  Počet parametrů: 260,864

26.8 Generování textu

def generate(model, idx, max_new_tokens, temperature=1.0):
    """Generuje nové tokeny pomocí autoregresivního vzorkování."""
    model.eval()

    for _ in range(max_new_tokens):
        # Predikce dalšího tokenu
        with torch.no_grad():
            logits = model(idx)
            logits = logits[:, -1, :] / temperature

        # Vzorkování z distribuce
        probs = F.softmax(logits, dim=-1)
        next_token = torch.multinomial(probs, num_samples=1)

        # Přidání k sekvenci
        idx = torch.cat([idx, next_token], dim=1)

    return idx

# Generování
torch.manual_seed(42)
start = torch.randint(0, 1000, (1, 5))
generated = generate(model, start, max_new_tokens=10)

print("Generování textu:")
print(f"  Počáteční tokeny: {start[0].tolist()}")
print(f"  Vygenerované tokeny: {generated[0].tolist()}")
Generování textu:
  Počáteční tokeny: [542, 67, 876, 414, 26]
  Vygenerované tokeny: [542, 67, 876, 414, 26, 798, 772, 382, 458, 504, 302, 819, 671, 545, 46]

26.9 Řešené příklady

26.9.1 Příklad 1: Ruční výpočet attention

Zadání: Pro \(Q = [1, 0]\), \(K = [[1, 0], [0, 1], [1, 1]]\), \(V = [[1], [2], [3]]\) spočítejte attention výstup.

Řešení:

import numpy as np

Q = np.array([1, 0])
K = np.array([[1, 0], [0, 1], [1, 1]])
V = np.array([[1], [2], [3]])

print("Ruční výpočet Attention:")
print(f"Q = {Q}")
print(f"K = \n{K}")
print(f"V = \n{V}")

# Skóre
scores = K @ Q
print(f"\n1. Skóre = K @ Q = {scores}")

# Scaling
d_k = len(Q)
scaled_scores = scores / np.sqrt(d_k)
print(f"2. Scaled skóre = scores / √d_k = {scaled_scores}")

# Softmax
exp_scores = np.exp(scaled_scores - np.max(scaled_scores))
weights = exp_scores / np.sum(exp_scores)
print(f"3. Attention weights = softmax(scaled) = {weights.round(4)}")

# Výstup
output = V.T @ weights
print(f"4. Výstup = V.T @ weights = {output}")
Ruční výpočet Attention:
Q = [1 0]
K = 
[[1 0]
 [0 1]
 [1 1]]
V = 
[[1]
 [2]
 [3]]

1. Skóre = K @ Q = [1 0 1]
2. Scaled skóre = scores / √d_k = [0.70710678 0.         0.70710678]
3. Attention weights = softmax(scaled) = [0.4011 0.1978 0.4011]
4. Výstup = V.T @ weights = [2.]

26.9.2 Příklad 2: Kauzální maska

Zadání: Vysvětlete a vizualizujte kauzální masku pro autoregresivní modely.

Řešení:

import numpy as np
import matplotlib.pyplot as plt

seq_len = 6

# Kauzální maska - dolní trojúhelníková matice
causal_mask = np.tril(np.ones((seq_len, seq_len)))

# Jak vypadají attention váhy s maskou
attention_scores = np.random.randn(seq_len, seq_len)
masked_scores = np.where(causal_mask, attention_scores, -1e9)
attention_weights = np.exp(masked_scores) / np.exp(masked_scores).sum(axis=-1, keepdims=True)

fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 4))

ax1.imshow(causal_mask, cmap='Greens')
ax1.set_title('Kauzální maska')
ax1.set_xlabel('Key pozice')
ax1.set_ylabel('Query pozice')
for i in range(seq_len):
    for j in range(seq_len):
        ax1.text(j, i, int(causal_mask[i, j]), ha='center', va='center')

ax2.imshow(masked_scores, cmap='RdBu', vmin=-5, vmax=5)
ax2.set_title('Maskované skóre')
ax2.set_xlabel('Key pozice')
ax2.set_ylabel('Query pozice')

ax3.imshow(attention_weights, cmap='Blues')
ax3.set_title('Attention weights')
ax3.set_xlabel('Key pozice')
ax3.set_ylabel('Query pozice')

plt.suptitle('Kauzální maska: Token může vidět pouze předchozí tokeny', fontsize=12)
plt.tight_layout()
plt.show()

print("Kauzální maska zajišťuje, že při predikci tokenu t")
print("model vidí pouze tokeny 1, 2, ..., t-1")

Kauzální maska zajišťuje, že při predikci tokenu t
model vidí pouze tokeny 1, 2, ..., t-1

26.9.3 Příklad 3: Porovnání attention hlav

Zadání: Ukažte, jak různé attention hlavy zachycují různé vztahy.

Řešení:

# Simulace specializovaných hlav
import numpy as np
import matplotlib.pyplot as plt

seq_len = 8

# Hlava 1: Lokální attention (sousední tokeny)
local_attn = np.zeros((seq_len, seq_len))
for i in range(seq_len):
    for j in range(max(0, i-1), min(seq_len, i+2)):
        local_attn[i, j] = 1
local_attn = local_attn / local_attn.sum(axis=1, keepdims=True)

# Hlava 2: Globální attention (první token)
global_attn = np.zeros((seq_len, seq_len))
global_attn[:, 0] = 1
global_attn = global_attn / global_attn.sum(axis=1, keepdims=True)

# Hlava 3: Syntaktická attention (sudé tokeny)
syntactic_attn = np.zeros((seq_len, seq_len))
syntactic_attn[:, ::2] = 1
syntactic_attn = syntactic_attn / syntactic_attn.sum(axis=1, keepdims=True)

# Hlava 4: Předchozí token
prev_attn = np.zeros((seq_len, seq_len))
for i in range(seq_len):
    if i > 0:
        prev_attn[i, i-1] = 1
    else:
        prev_attn[i, i] = 1

fig, axes = plt.subplots(1, 4, figsize=(16, 4))
heads = [
    (local_attn, 'Lokální (sousední)'),
    (global_attn, 'Globální (první token)'),
    (syntactic_attn, 'Strukturální (sudé)'),
    (prev_attn, 'Předchozí token')
]

for ax, (attn, title) in zip(axes, heads):
    ax.imshow(attn, cmap='Blues')
    ax.set_title(title)
    ax.set_xlabel('Key')
    ax.set_ylabel('Query')

plt.suptitle('Různé attention hlavy zachycují různé vztahy', fontsize=12)
plt.tight_layout()
plt.show()

26.10 Matematika za transformery - shrnutí

# Přehled všech konceptů z knihy použitých v transformerech
import matplotlib.pyplot as plt

concepts = [
    ("Vektory a matice", "Embeddingy slov, váhové matice W_Q, W_K, W_V"),
    ("Maticové násobení", "QK^T pro attention skóre, projekce"),
    ("Softmax", "Převod skóre na pravděpodobnosti"),
    ("Derivace", "Gradienty pro trénink"),
    ("Řetízkové pravidlo", "Backpropagation skrz attention"),
    ("Pravděpodobnost", "Podmíněná pravděpodobnost dalšího tokenu"),
    ("Cross-entropy", "Loss funkce pro jazykové modelování"),
    ("Gradient descent", "Optimalizace (Adam)"),
    ("Normální rozdělení", "Inicializace vah, dropout"),
]

fig, ax = plt.subplots(figsize=(12, 8))
ax.axis('off')

ax.text(0.5, 0.95, 'Matematika v Transformerech', ha='center', fontsize=16,
        fontweight='bold', transform=ax.transAxes)

y = 0.85
for concept, usage in concepts:
    ax.text(0.1, y, f"• {concept}:", fontsize=12, fontweight='bold',
            transform=ax.transAxes)
    ax.text(0.4, y, usage, fontsize=11, transform=ax.transAxes)
    y -= 0.08

ax.text(0.5, 0.05, 'Všechny koncepty z této knihy se spojují v architektuře Transformer!',
        ha='center', fontsize=12, style='italic', transform=ax.transAxes)

plt.tight_layout()
plt.show()

26.11 Cvičení

PoznámkaCvičení 1: Implementace attention

Implementujte scaled dot-product attention v čistém NumPy včetně kauzální masky.

PoznámkaCvičení 2: Pozicové kódování

Navrhněte alternativní pozicové kódování (např. learnable embeddings) a porovnejte se sinusoidálním.

PoznámkaCvičení 3: Vizualizace attention

Pro natrénovaný jazykový model vizualizujte attention patterns. Jaké vzory pozorujete?

PoznámkaCvičení 4: Mini transformer

Natrénujte mini-transformer na jednoduché úloze (např. kopírování sekvence nebo sčítání).

PoznámkaCvičení 5: Efektivita

Spočítejte, kolik operací (FLOPs) vyžaduje jeden forward pass transformeru. Jak škáluje s délkou sekvence?

26.12 Shrnutí

TipCo jsme se naučili
  1. Attention mechanismus umožňuje dynamické zaměření na relevantní části vstupu
  2. Scaled dot-product attention: \(\text{softmax}(QK^T/\sqrt{d_k})V\)
  3. Multi-head attention kombinuje více specializovaných “pohledů”
  4. Pozicové kódování přidává informaci o pořadí tokenů
  5. Transformer blok = Self-Attention + FFN + Residual + LayerNorm
  6. Kauzální maska zajišťuje autoregresivní generování
  7. Transformery využívají všechny koncepty z této knihy
DůležitéKlíčové vzorce
  • Attention: \(\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V\)
  • Multi-Head: \(\text{MultiHead} = \text{Concat}(\text{head}_1, \ldots, \text{head}_h)W^O\)
  • Pozicové kódování: \(PE_{(pos, 2i)} = \sin(pos / 10000^{2i/d})\)
  • Transformer blok: \(x = \text{LayerNorm}(x + \text{Attention}(x))\)

26.13 Závěr knihy

Gratulujeme! Prošli jste celou cestu od základních funkcí až po architekturu, která stojí za moderními jazykovými modely.

Co jste se naučili:

  1. Funkce a grafy - základní stavební kameny
  2. Vektory a matice - reprezentace dat a transformace
  3. Derivace a gradient - měření změny a směr optimalizace
  4. Pravděpodobnost - modelování nejistoty
  5. Optimalizace - jak se modely učí
  6. Neuronové sítě - od perceptronu po transformery

Nyní máte matematické základy pro pochopení a práci s moderními modely strojového učení. Další kroky mohou zahrnovat:

  • Hlubší studium konkrétních architektur (BERT, GPT, ViT)
  • Praktické projekty s PyTorch nebo TensorFlow
  • Pokročilá témata (attention mechanisms, efficient transformers)
  • Výzkum v oblasti AI

Hodně štěstí na vaší cestě!