0. Basic LLM Concepts

Pretraining

Pretraining to podstawowa faza w rozwijaniu dużego modelu językowego (LLM), w której model jest narażony na ogromne i różnorodne ilości danych tekstowych. W tym etapie LLM uczy się fundamentalnych struktur, wzorców i niuansów języka, w tym gramatyki, słownictwa, składni i relacji kontekstowych. Przetwarzając te obszerne dane, model nabywa szerokie zrozumienie języka i ogólnej wiedzy o świecie. Ta kompleksowa baza umożliwia LLM generowanie spójnego i kontekstowo odpowiedniego tekstu. Następnie ten wstępnie wytrenowany model może przejść do fine-tuningu, gdzie jest dalej trenowany na wyspecjalizowanych zbiorach danych, aby dostosować swoje możliwości do konkretnych zadań lub dziedzin, poprawiając swoją wydajność i trafność w docelowych zastosowaniach.

Główne komponenty LLM

Zazwyczaj LLM charakteryzuje się konfiguracją używaną do jego trenowania. Oto wspólne komponenty podczas trenowania LLM:

  • Parametry: Parametry to uczone wagi i biasy w sieci neuronowej. To są liczby, które proces treningowy dostosowuje, aby zminimalizować funkcję straty i poprawić wydajność modelu w zadaniu. LLM zazwyczaj używa milionów parametrów.

  • Długość kontekstu: To maksymalna długość każdego zdania używanego do wstępnego trenowania LLM.

  • Wymiar osadzenia: Rozmiar wektora używanego do reprezentacji każdego tokena lub słowa. LLM zazwyczaj używa miliardów wymiarów.

  • Wymiar ukryty: Rozmiar warstw ukrytych w sieci neuronowej.

  • Liczba warstw (głębokość): Ile warstw ma model. LLM zazwyczaj używa dziesiątek warstw.

  • Liczba głów uwagi: W modelach transformatorowych, to ile oddzielnych mechanizmów uwagi jest używanych w każdej warstwie. LLM zazwyczaj używa dziesiątek głów.

  • Dropout: Dropout to coś w rodzaju procentu danych, które są usuwane (prawdopodobieństwa stają się 0) podczas treningu, używanego do zapobiegania przeuczeniu. LLM zazwyczaj używa od 0 do 20%.

Konfiguracja modelu GPT-2:

GPT_CONFIG_124M = {
"vocab_size": 50257,  // Vocabulary size of the BPE tokenizer
"context_length": 1024, // Context length
"emb_dim": 768,       // Embedding dimension
"n_heads": 12,        // Number of attention heads
"n_layers": 12,       // Number of layers
"drop_rate": 0.1,     // Dropout rate: 10%
"qkv_bias": False     // Query-Key-Value bias
}

Tensors in PyTorch

W PyTorch, tensor to podstawowa struktura danych, która służy jako wielowymiarowa tablica, uogólniając pojęcia takie jak skalar, wektor i macierz do potencjalnie wyższych wymiarów. Tensory są głównym sposobem reprezentacji i manipulacji danymi w PyTorch, szczególnie w kontekście uczenia głębokiego i sieci neuronowych.

Mathematical Concept of Tensors

  • Skalary: Tensory rangi 0, reprezentujące pojedynczą liczbę (zero-wymiarowe). Jak: 5

  • Wektory: Tensory rangi 1, reprezentujące jednowymiarową tablicę liczb. Jak: [5,1]

  • Macierze: Tensory rangi 2, reprezentujące dwuwymiarowe tablice z wierszami i kolumnami. Jak: [[1,3], [5,2]]

  • Tensory wyższej rangi: Tensory rangi 3 lub wyższej, reprezentujące dane w wyższych wymiarach (np. tensory 3D dla obrazów kolorowych).

Tensors as Data Containers

Z perspektywy obliczeniowej, tensory działają jako pojemniki dla wielowymiarowych danych, gdzie każdy wymiar może reprezentować różne cechy lub aspekty danych. To sprawia, że tensory są bardzo odpowiednie do obsługi złożonych zbiorów danych w zadaniach uczenia maszynowego.

PyTorch Tensors vs. NumPy Arrays

Chociaż tensory PyTorch są podobne do tablic NumPy w ich zdolności do przechowywania i manipulacji danymi numerycznymi, oferują dodatkowe funkcjonalności kluczowe dla uczenia głębokiego:

  • Automatyczna różniczkowanie: Tensory PyTorch wspierają automatyczne obliczanie gradientów (autograd), co upraszcza proces obliczania pochodnych wymaganych do trenowania sieci neuronowych.

  • Przyspieszenie GPU: Tensory w PyTorch mogą być przenoszone i obliczane na GPU, co znacznie przyspiesza obliczenia na dużą skalę.

Creating Tensors in PyTorch

Możesz tworzyć tensory za pomocą funkcji torch.tensor:

pythonCopy codeimport torch

# Scalar (0D tensor)
tensor0d = torch.tensor(1)

# Vector (1D tensor)
tensor1d = torch.tensor([1, 2, 3])

# Matrix (2D tensor)
tensor2d = torch.tensor([[1, 2],
[3, 4]])

# 3D Tensor
tensor3d = torch.tensor([[[1, 2], [3, 4]],
[[5, 6], [7, 8]]])

Typy danych tensorów

Tensory PyTorch mogą przechowywać dane różnych typów, takich jak liczby całkowite i liczby zmiennoprzecinkowe.

Możesz sprawdzić typ danych tensora, używając atrybutu .dtype:

tensor1d = torch.tensor([1, 2, 3])
print(tensor1d.dtype)  # Output: torch.int64
  • Tensory utworzone z liczb całkowitych Pythona są typu torch.int64.

  • Tensory utworzone z liczb zmiennoprzecinkowych Pythona są typu torch.float32.

Aby zmienić typ danych tensora, użyj metody .to():

float_tensor = tensor1d.to(torch.float32)
print(float_tensor.dtype)  # Output: torch.float32

Common Tensor Operations

PyTorch provides a variety of operations to manipulate tensors:

  • Accessing Shape: Use .shape to get the dimensions of a tensor.

print(tensor2d.shape)  # Output: torch.Size([2, 2])
  • Reshaping Tensors: Use .reshape() or .view() to change the shape.

reshaped = tensor2d.reshape(4, 1)
  • Transposing Tensors: Use .T to transpose a 2D tensor.

transposed = tensor2d.T
  • Matrix Multiplication: Use .matmul() or the @ operator.

result = tensor2d @ tensor2d.T

Importance in Deep Learning

Tensors are essential in PyTorch for building and training neural networks:

  • Przechowują dane wejściowe, wagi i biasy.

  • Ułatwiają operacje wymagane do przeprowadzania kroków w przód i w tył w algorytmach treningowych.

  • Dzięki autograd, tensory umożliwiają automatyczne obliczanie gradientów, upraszczając proces optymalizacji.

Automatic Differentiation

Automatic differentiation (AD) is a computational technique used to evaluate the derivatives (gradients) of functions efficiently and accurately. In the context of neural networks, AD enables the calculation of gradients required for optimization algorithms like gradient descent. PyTorch provides an automatic differentiation engine called autograd that simplifies this process.

Mathematical Explanation of Automatic Differentiation

1. The Chain Rule

At the heart of automatic differentiation is the chain rule from calculus. The chain rule states that if you have a composition of functions, the derivative of the composite function is the product of the derivatives of the composed functions.

Mathematically, if y=f(u) and u=g(x), then the derivative of y with respect to x is:

2. Computational Graph

In AD, computations are represented as nodes in a computational graph, where each node corresponds to an operation or a variable. By traversing this graph, we can compute derivatives efficiently.

  1. Example

Let's consider a simple function:

Where:

  • σ(z) is the sigmoid function.

  • y=1.0 is the target label.

  • L is the loss.

We want to compute the gradient of the loss L with respect to the weight w and bias b.

4. Computing Gradients Manually

5. Numerical Calculation

Implementing Automatic Differentiation in PyTorch

Now, let's see how PyTorch automates this process.

pythonCopy codeimport torch
import torch.nn.functional as F

# Define input and target
x = torch.tensor([1.1])
y = torch.tensor([1.0])

# Initialize weights with requires_grad=True to track computations
w = torch.tensor([2.2], requires_grad=True)
b = torch.tensor([0.0], requires_grad=True)

# Forward pass
z = x * w + b
a = torch.sigmoid(z)
loss = F.binary_cross_entropy(a, y)

# Backward pass
loss.backward()

# Gradients
print("Gradient w.r.t w:", w.grad)
print("Gradient w.r.t b:", b.grad)

Wyjście:

cssCopy codeGradient w.r.t w: tensor([-0.0898])
Gradient w.r.t b: tensor([-0.0817])

Backpropagation w większych sieciach neuronowych

1. Rozszerzenie na sieci wielowarstwowe

W większych sieciach neuronowych z wieloma warstwami proces obliczania gradientów staje się bardziej złożony z powodu zwiększonej liczby parametrów i operacji. Jednak podstawowe zasady pozostają takie same:

  • Forward Pass: Oblicz wyjście sieci, przekazując dane wejściowe przez każdą warstwę.

  • Compute Loss: Oceń funkcję straty, używając wyjścia sieci i docelowych etykiet.

  • Backward Pass (Backpropagation): Oblicz gradienty straty względem każdego parametru w sieci, stosując regułę łańcuchową rekurencyjnie od warstwy wyjściowej do warstwy wejściowej.

2. Algorytm Backpropagation

  • Krok 1: Zainicjalizuj parametry sieci (wagi i biasy).

  • Krok 2: Dla każdego przykładu treningowego wykonaj forward pass, aby obliczyć wyjścia.

  • Krok 3: Oblicz stratę.

  • Krok 4: Oblicz gradienty straty względem każdego parametru, używając reguły łańcuchowej.

  • Krok 5: Zaktualizuj parametry, używając algorytmu optymalizacji (np. gradient descent).

3. Reprezentacja matematyczna

Rozważ prostą sieć neuronową z jedną ukrytą warstwą:

4. Implementacja w PyTorch

PyTorch upraszcza ten proces dzięki swojemu silnikowi autograd.

import torch
import torch.nn as nn
import torch.optim as optim

# Define a simple neural network
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.fc1 = nn.Linear(10, 5)  # Input layer to hidden layer
self.relu = nn.ReLU()
self.fc2 = nn.Linear(5, 1)   # Hidden layer to output layer
self.sigmoid = nn.Sigmoid()

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

# Instantiate the network
net = SimpleNet()

# Define loss function and optimizer
criterion = nn.BCELoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)

# Sample data
inputs = torch.randn(1, 10)
labels = torch.tensor([1.0])

# Training loop
optimizer.zero_grad()          # Clear gradients
outputs = net(inputs)          # Forward pass
loss = criterion(outputs, labels)  # Compute loss
loss.backward()                # Backward pass (compute gradients)
optimizer.step()               # Update parameters

# Accessing gradients
for name, param in net.named_parameters():
if param.requires_grad:
print(f"Gradient of {name}: {param.grad}")

W tym kodzie:

  • Forward Pass: Oblicza wyjścia sieci.

  • Backward Pass: loss.backward() oblicza gradienty straty względem wszystkich parametrów.

  • Parameter Update: optimizer.step() aktualizuje parametry na podstawie obliczonych gradientów.

5. Zrozumienie Backward Pass

Podczas backward pass:

  • PyTorch przeszukuje graf obliczeniowy w odwrotnej kolejności.

  • Dla każdej operacji stosuje regułę łańcuchową do obliczania gradientów.

  • Gradienty są akumulowane w atrybucie .grad każdego tensora parametru.

6. Zalety automatycznej różniczkowania

  • Efektywność: Unika zbędnych obliczeń poprzez ponowne wykorzystanie wyników pośrednich.

  • Dokładność: Zapewnia dokładne pochodne do precyzji maszyny.

  • Łatwość użycia: Eliminuje ręczne obliczanie pochodnych.

Last updated