28  Tahák NumPy a PyTorch

Rychlý přehled nejpoužívanějších příkazů pro práci s NumPy a PyTorch.

28.1 NumPy - Základy

28.1.1 Import a vytváření polí

import numpy as np

# Vytvoření polí
a = np.array([1, 2, 3])              # 1D pole
b = np.array([[1, 2], [3, 4]])       # 2D pole (matice)

# Speciální pole
np.zeros((3, 4))                     # Nulová matice 3x4
np.ones((2, 3))                      # Matice jedniček 2x3
np.eye(4)                            # Jednotková matice 4x4
np.full((2, 2), 7)                   # Matice samých 7

# Sekvence
np.arange(0, 10, 2)                  # [0, 2, 4, 6, 8]
np.linspace(0, 1, 5)                 # [0, 0.25, 0.5, 0.75, 1]

# Náhodná čísla
np.random.rand(3, 4)                 # Uniformní [0, 1)
np.random.randn(3, 4)                # Normální N(0, 1)
np.random.randint(0, 10, (3, 4))     # Celá čísla [0, 10)
np.random.seed(42)                   # Nastavení seedu

28.1.2 Vlastnosti polí

a.shape                              # Rozměry (tuple)
a.ndim                               # Počet dimenzí
a.size                               # Celkový počet prvků
a.dtype                              # Datový typ
len(a)                               # Délka první dimenze

28.1.3 Změna tvaru

a.reshape(3, 4)                      # Změna tvaru na 3x4
a.flatten()                          # Zploštění na 1D
a.ravel()                            # Zploštění (view)
a.T                                  # Transpozice
a.transpose(1, 0, 2)                 # Přeházení os

np.expand_dims(a, axis=0)            # Přidání dimenze
np.squeeze(a)                        # Odstranění dimenzí velikosti 1

28.1.4 Indexování a slicing

a[0]                                 # První prvek
a[-1]                                # Poslední prvek
a[1:4]                               # Prvky 1-3
a[::2]                               # Každý druhý
a[::-1]                              # Obrácené pořadí

# 2D indexování
b[0, 1]                              # Řádek 0, sloupec 1
b[0, :]                              # Celý řádek 0
b[:, 1]                              # Celý sloupec 1
b[1:3, 0:2]                          # Podmatice

# Boolean indexování
a[a > 5]                             # Prvky větší než 5
a[a % 2 == 0]                        # Sudé prvky

# Fancy indexování
a[[0, 2, 4]]                         # Prvky na indexech 0, 2, 4

28.1.5 Aritmetické operace

# Po prvcích (element-wise)
a + b                                # Sčítání
a - b                                # Odčítání
a * b                                # Násobení
a / b                                # Dělení
a ** 2                               # Mocnina
np.sqrt(a)                           # Odmocnina
np.exp(a)                            # Exponenciála
np.log(a)                            # Přirozený logaritmus

# Maticové operace
a @ b                                # Maticové násobení
np.dot(a, b)                         # Dot product
np.matmul(a, b)                      # Maticové násobení
a * b                                # Hadamardův součin (po prvcích)

28.1.6 Agregační funkce

np.sum(a)                            # Součet všech prvků
np.sum(a, axis=0)                    # Součet přes osu 0
np.mean(a)                           # Průměr
np.std(a)                            # Směrodatná odchylka
np.var(a)                            # Rozptyl
np.min(a), np.max(a)                 # Minimum, maximum
np.argmin(a), np.argmax(a)           # Index min/max
np.cumsum(a)                         # Kumulativní součet
np.prod(a)                           # Součin všech prvků

28.1.7 Lineární algebra

np.linalg.norm(a)                    # L2 norma
np.linalg.norm(a, ord=1)             # L1 norma
np.linalg.inv(A)                     # Inverze matice
np.linalg.det(A)                     # Determinant
np.linalg.eig(A)                     # Vlastní čísla a vektory
np.linalg.svd(A)                     # Singulární rozklad
np.linalg.solve(A, b)                # Řešení Ax = b

28.1.8 Spojování a rozdělování

np.concatenate([a, b], axis=0)       # Spojení podle osy
np.vstack([a, b])                    # Vertikální stack
np.hstack([a, b])                    # Horizontální stack
np.stack([a, b], axis=0)             # Stack s novou osou

np.split(a, 3)                       # Rozdělení na 3 části
np.array_split(a, 3)                 # Nerovnoměrné rozdělení

28.1.9 Broadcasting

# NumPy automaticky rozšíří menší pole
a = np.array([[1], [2], [3]])        # Shape (3, 1)
b = np.array([10, 20, 30])           # Shape (3,)
a + b                                # Shape (3, 3)

# Pravidla:
# 1. Menší pole se rozšíří přidáním 1 na začátek
# 2. Dimenze velikosti 1 se "natáhne"

28.2 PyTorch - Základy

28.2.1 Import a vytváření tensorů

import torch
import torch.nn as nn
import torch.nn.functional as F

# Vytvoření tensorů
x = torch.tensor([1, 2, 3])
x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)

# Speciální tensory
torch.zeros(3, 4)
torch.ones(2, 3)
torch.eye(4)
torch.full((2, 2), 7)
torch.empty(3, 4)                    # Neinicializované

# Sekvence
torch.arange(0, 10, 2)
torch.linspace(0, 1, 5)

# Náhodné tensory
torch.rand(3, 4)                     # Uniformní [0, 1)
torch.randn(3, 4)                    # Normální N(0, 1)
torch.randint(0, 10, (3, 4))         # Celá čísla
torch.manual_seed(42)                # Seed

# Z NumPy a zpět
torch.from_numpy(np_array)
tensor.numpy()                       # Pouze CPU tensor

28.2.2 Vlastnosti tensorů

x.shape                              # Rozměry
x.size()                             # Rozměry (metoda)
x.ndim                               # Počet dimenzí
x.numel()                            # Počet prvků
x.dtype                              # Datový typ
x.device                             # cpu nebo cuda
x.requires_grad                      # Sledování gradientů

28.2.3 Změna tvaru

x.view(3, 4)                         # Změna tvaru (sdílí data)
x.reshape(3, 4)                      # Změna tvaru (může kopírovat)
x.flatten()                          # Zploštění
x.squeeze()                          # Odstranění dimenzí 1
x.unsqueeze(0)                       # Přidání dimenze
x.T                                  # Transpozice 2D
x.transpose(0, 1)                    # Prohození dimenzí
x.permute(2, 0, 1)                   # Přeházení dimenzí
x.contiguous()                       # Zajištění spojitosti v paměti

28.2.4 Operace s tensory

# Element-wise operace
x + y, torch.add(x, y)
x - y, torch.sub(x, y)
x * y, torch.mul(x, y)
x / y, torch.div(x, y)
x ** 2, torch.pow(x, 2)
torch.sqrt(x)
torch.exp(x)
torch.log(x)
torch.abs(x)
torch.clamp(x, min=0, max=1)

# Maticové operace
x @ y                                # Maticové násobení
torch.matmul(x, y)
torch.mm(x, y)                       # 2D matice
torch.bmm(x, y)                      # Batch maticové násobení
torch.dot(x, y)                      # Dot product (1D)

# Porovnání
x == y, torch.eq(x, y)
x > y, torch.gt(x, y)
torch.allclose(x, y)                 # Přibližná rovnost

28.2.5 Agregace

x.sum()
x.sum(dim=0)
x.mean()
x.std()
x.var()
x.min(), x.max()
x.argmin(), x.argmax()
torch.topk(x, k=3)                   # Top k hodnot

28.2.6 GPU operace

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

x = x.to(device)                     # Přesun na GPU
x = x.cuda()                         # Přímý přesun na GPU
x = x.cpu()                          # Přesun zpět na CPU

# Vytvoření přímo na GPU
x = torch.randn(3, 4, device=device)

28.3 PyTorch - Autograd

28.3.1 Automatická derivace

# Zapnutí sledování gradientů
x = torch.tensor([2.0], requires_grad=True)

# Forward pass
y = x ** 2 + 3 * x + 1

# Backward pass
y.backward()

# Gradient
print(x.grad)                        # dy/dx = 2*x + 3 = 7

# Reset gradientů
x.grad.zero_()                       # In-place reset

# Kontext bez gradientů
with torch.no_grad():
    y = x ** 2                       # Nesleduje se

# Detach od grafu
y = x.detach()                       # Nový tensor bez gradientů

28.4 PyTorch - Neuronové sítě

28.4.1 Definice modelu

class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, output_dim)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = MLP(784, 128, 10)

28.4.2 Vrstvy (nn.Module)

# Lineární vrstvy
nn.Linear(in_features, out_features)
nn.Bilinear(in1, in2, out)

# Konvoluční vrstvy
nn.Conv1d(in_ch, out_ch, kernel_size)
nn.Conv2d(in_ch, out_ch, kernel_size, stride, padding)

# Normalizace
nn.BatchNorm1d(num_features)
nn.BatchNorm2d(num_features)
nn.LayerNorm(normalized_shape)

# Dropout
nn.Dropout(p=0.5)
nn.Dropout2d(p=0.5)

# Aktivační funkce
nn.ReLU()
nn.LeakyReLU(negative_slope=0.01)
nn.Sigmoid()
nn.Tanh()
nn.Softmax(dim=-1)
nn.GELU()

# Pooling
nn.MaxPool2d(kernel_size)
nn.AvgPool2d(kernel_size)
nn.AdaptiveAvgPool2d(output_size)

# Embedding
nn.Embedding(num_embeddings, embedding_dim)

# RNN
nn.RNN(input_size, hidden_size, num_layers)
nn.LSTM(input_size, hidden_size, num_layers)
nn.GRU(input_size, hidden_size, num_layers)

# Transformer
nn.Transformer(d_model, nhead, num_encoder_layers, num_decoder_layers)
nn.TransformerEncoder(encoder_layer, num_layers)
nn.TransformerDecoder(decoder_layer, num_layers)
nn.MultiheadAttention(embed_dim, num_heads)

28.4.3 Funkcionální API

# Aktivace
F.relu(x)
F.leaky_relu(x, negative_slope=0.01)
F.sigmoid(x)
F.tanh(x)
F.softmax(x, dim=-1)
F.log_softmax(x, dim=-1)
F.gelu(x)

# Loss funkce
F.mse_loss(pred, target)
F.cross_entropy(logits, target)
F.binary_cross_entropy(pred, target)
F.nll_loss(log_probs, target)

# Dropout
F.dropout(x, p=0.5, training=True)

28.4.4 Loss funkce

nn.MSELoss()                         # Mean Squared Error
nn.L1Loss()                          # Mean Absolute Error
nn.CrossEntropyLoss()                # Cross-entropy (logity)
nn.NLLLoss()                         # Negative Log-Likelihood
nn.BCELoss()                         # Binary Cross-Entropy
nn.BCEWithLogitsLoss()               # BCE + sigmoid
nn.KLDivLoss()                       # KL divergence

28.4.5 Optimizéry

import torch.optim as optim

# Základní
optim.SGD(model.parameters(), lr=0.01)
optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optim.SGD(model.parameters(), lr=0.01, momentum=0.9, weight_decay=1e-4)

# Adaptivní
optim.Adam(model.parameters(), lr=0.001)
optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
optim.RMSprop(model.parameters(), lr=0.01)

# Learning rate scheduler
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=5)

28.4.6 Trénovací smyčka

model = MLP(784, 128, 10)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# Trénink
model.train()
for epoch in range(num_epochs):
    for batch_x, batch_y in dataloader:
        # Forward pass
        outputs = model(batch_x)
        loss = criterion(outputs, batch_y)

        # Backward pass
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    scheduler.step()

# Evaluace
model.eval()
with torch.no_grad():
    outputs = model(test_x)
    predictions = outputs.argmax(dim=1)

28.4.7 Ukládání a načítání

# Uložení celého modelu
torch.save(model, 'model.pt')
model = torch.load('model.pt')

# Uložení pouze vah (doporučeno)
torch.save(model.state_dict(), 'weights.pt')
model.load_state_dict(torch.load('weights.pt'))

# Uložení checkpointu
checkpoint = {
    'epoch': epoch,
    'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
    'loss': loss,
}
torch.save(checkpoint, 'checkpoint.pt')

28.5 PyTorch - Data

28.5.1 DataLoader

from torch.utils.data import Dataset, DataLoader, TensorDataset

# Jednoduchý dataset z tensorů
dataset = TensorDataset(X_tensor, y_tensor)

# DataLoader
dataloader = DataLoader(
    dataset,
    batch_size=32,
    shuffle=True,
    num_workers=4,
    pin_memory=True
)

# Iterace
for batch_x, batch_y in dataloader:
    ...

28.5.2 Vlastní Dataset

class MyDataset(Dataset):
    def __init__(self, data, labels, transform=None):
        self.data = data
        self.labels = labels
        self.transform = transform

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        x = self.data[idx]
        y = self.labels[idx]

        if self.transform:
            x = self.transform(x)

        return x, y

28.6 Porovnání NumPy vs PyTorch

Operace NumPy PyTorch
Vytvoření pole np.array([1,2,3]) torch.tensor([1,2,3])
Nuly np.zeros((3,4)) torch.zeros(3,4)
Náhodná np.random.randn(3,4) torch.randn(3,4)
Reshape a.reshape(3,4) x.view(3,4)
Transpozice a.T x.T
Součet np.sum(a) x.sum()
Maticové násobení a @ b x @ y
Norma np.linalg.norm(a) torch.norm(x)
Z NumPy torch.from_numpy(a)
Do NumPy x.numpy()
GPU x.cuda()

28.7 Tipy a triky

28.7.1 NumPy

# Vektorizace místo cyklů
# Špatně:
result = []
for i in range(len(a)):
    result.append(a[i] ** 2)

# Dobře:
result = a ** 2

# Efektivní paměť
a = np.array([1, 2, 3], dtype=np.float32)  # 32-bit místo 64-bit

# Kopírování vs view
b = a.copy()                         # Nová kopie
b = a.view()                         # Sdílená paměť

28.7.2 PyTorch

# Gradient clipping
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

# Zmrazení vrstev
for param in model.fc1.parameters():
    param.requires_grad = False

# Počet parametrů
sum(p.numel() for p in model.parameters())
sum(p.numel() for p in model.parameters() if p.requires_grad)

# Mixed precision training
from torch.cuda.amp import autocast, GradScaler

scaler = GradScaler()
with autocast():
    output = model(input)
    loss = criterion(output, target)

scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()