mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-23 13:13:41 +00:00
205 lines
8.8 KiB
Markdown
205 lines
8.8 KiB
Markdown
|
# 3. Token Embeddings
|
||
|
|
||
|
## Token Embeddings
|
||
|
|
||
|
Po tokenizacji danych tekstowych, kolejnym kluczowym krokiem w przygotowaniu danych do trenowania dużych modeli językowych (LLM) takich jak GPT jest tworzenie **token embeddings**. Token embeddings przekształcają dyskretne tokeny (takie jak słowa lub pod-słowa) w ciągłe wektory numeryczne, które model może przetwarzać i z których może się uczyć. To wyjaśnienie rozkłada token embeddings, ich inicjalizację, zastosowanie oraz rolę osadzeń pozycyjnych w poprawie zrozumienia sekwencji tokenów przez model.
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Celem tej trzeciej fazy jest bardzo proste: **Przypisanie każdemu z poprzednich tokenów w słowniku wektora o pożądanych wymiarach do trenowania modelu.** Każde słowo w słowniku będzie punktem w przestrzeni o X wymiarach.\
|
||
|
Zauważ, że początkowo pozycja każdego słowa w przestrzeni jest po prostu inicjowana "losowo", a te pozycje są parametrami, które można trenować (będą poprawiane podczas treningu).
|
||
|
|
||
|
Co więcej, podczas osadzania tokenów **tworzona jest kolejna warstwa osadzeń**, która reprezentuje (w tym przypadku) **absolutną pozycję słowa w zdaniu treningowym**. W ten sposób słowo w różnych pozycjach w zdaniu będzie miało różne reprezentacje (znaczenia).
|
||
|
{% endhint %}
|
||
|
|
||
|
### **Czym są Token Embeddings?**
|
||
|
|
||
|
**Token Embeddings** to numeryczne reprezentacje tokenów w ciągłej przestrzeni wektorowej. Każdy token w słowniku jest powiązany z unikalnym wektorem o stałych wymiarach. Te wektory uchwycają informacje semantyczne i syntaktyczne o tokenach, umożliwiając modelowi zrozumienie relacji i wzorców w danych.
|
||
|
|
||
|
* **Rozmiar słownika:** Całkowita liczba unikalnych tokenów (np. słów, pod-słów) w słowniku modelu.
|
||
|
* **Wymiary osadzenia:** Liczba wartości numerycznych (wymiarów) w wektorze każdego tokena. Wyższe wymiary mogą uchwycić bardziej subtelne informacje, ale wymagają więcej zasobów obliczeniowych.
|
||
|
|
||
|
**Przykład:**
|
||
|
|
||
|
* **Rozmiar słownika:** 6 tokenów \[1, 2, 3, 4, 5, 6]
|
||
|
* **Wymiary osadzenia:** 3 (x, y, z)
|
||
|
|
||
|
### **Inicjalizacja Token Embeddings**
|
||
|
|
||
|
Na początku treningu, token embeddings są zazwyczaj inicjowane małymi losowymi wartościami. Te początkowe wartości są dostosowywane (dostosowywane) podczas treningu, aby lepiej reprezentować znaczenia tokenów na podstawie danych treningowych.
|
||
|
|
||
|
**Przykład PyTorch:**
|
||
|
```python
|
||
|
import torch
|
||
|
|
||
|
# Set a random seed for reproducibility
|
||
|
torch.manual_seed(123)
|
||
|
|
||
|
# Create an embedding layer with 6 tokens and 3 dimensions
|
||
|
embedding_layer = torch.nn.Embedding(6, 3)
|
||
|
|
||
|
# Display the initial weights (embeddings)
|
||
|
print(embedding_layer.weight)
|
||
|
```
|
||
|
**Wynik:**
|
||
|
```lua
|
||
|
luaCopy codeParameter containing:
|
||
|
tensor([[ 0.3374, -0.1778, -0.1690],
|
||
|
[ 0.9178, 1.5810, 1.3010],
|
||
|
[ 1.2753, -0.2010, -0.1606],
|
||
|
[-0.4015, 0.9666, -1.1481],
|
||
|
[-1.1589, 0.3255, -0.6315],
|
||
|
[-2.8400, -0.7849, -1.4096]], requires_grad=True)
|
||
|
```
|
||
|
**Wyjaśnienie:**
|
||
|
|
||
|
* Każdy wiersz odpowiada tokenowi w słowniku.
|
||
|
* Każda kolumna reprezentuje wymiar w wektorze osadzenia.
|
||
|
* Na przykład, token o indeksie `3` ma wektor osadzenia `[-0.4015, 0.9666, -1.1481]`.
|
||
|
|
||
|
**Dostęp do osadzenia tokena:**
|
||
|
```python
|
||
|
# Retrieve the embedding for the token at index 3
|
||
|
token_index = torch.tensor([3])
|
||
|
print(embedding_layer(token_index))
|
||
|
```
|
||
|
**Wynik:**
|
||
|
```lua
|
||
|
tensor([[-0.4015, 0.9666, -1.1481]], grad_fn=<EmbeddingBackward0>)
|
||
|
```
|
||
|
**Interpretacja:**
|
||
|
|
||
|
* Token na indeksie `3` jest reprezentowany przez wektor `[-0.4015, 0.9666, -1.1481]`.
|
||
|
* Te wartości to parametry, które model będzie dostosowywał podczas treningu, aby lepiej reprezentować kontekst i znaczenie tokena.
|
||
|
|
||
|
### **Jak działają osadzenia tokenów podczas treningu**
|
||
|
|
||
|
Podczas treningu każdy token w danych wejściowych jest konwertowany na odpowiadający mu wektor osadzenia. Te wektory są następnie używane w różnych obliczeniach w modelu, takich jak mechanizmy uwagi i warstwy sieci neuronowej.
|
||
|
|
||
|
**Przykładowy scenariusz:**
|
||
|
|
||
|
* **Rozmiar partii:** 8 (liczba próbek przetwarzanych jednocześnie)
|
||
|
* **Maksymalna długość sekwencji:** 4 (liczba tokenów na próbkę)
|
||
|
* **Wymiary osadzenia:** 256
|
||
|
|
||
|
**Struktura danych:**
|
||
|
|
||
|
* Każda partia jest reprezentowana jako tensor 3D o kształcie `(batch_size, max_length, embedding_dim)`.
|
||
|
* W naszym przykładzie kształt będzie `(8, 4, 256)`.
|
||
|
|
||
|
**Wizualizacja:**
|
||
|
```css
|
||
|
cssCopy codeBatch
|
||
|
┌─────────────┐
|
||
|
│ Sample 1 │
|
||
|
│ ┌─────┐ │
|
||
|
│ │Token│ → [x₁₁, x₁₂, ..., x₁₂₅₆]
|
||
|
│ │ 1 │ │
|
||
|
│ │... │ │
|
||
|
│ │Token│ │
|
||
|
│ │ 4 │ │
|
||
|
│ └─────┘ │
|
||
|
│ Sample 2 │
|
||
|
│ ┌─────┐ │
|
||
|
│ │Token│ → [x₂₁, x₂₂, ..., x₂₂₅₆]
|
||
|
│ │ 1 │ │
|
||
|
│ │... │ │
|
||
|
│ │Token│ │
|
||
|
│ │ 4 │ │
|
||
|
│ └─────┘ │
|
||
|
│ ... │
|
||
|
│ Sample 8 │
|
||
|
│ ┌─────┐ │
|
||
|
│ │Token│ → [x₈₁, x₈₂, ..., x₈₂₅₆]
|
||
|
│ │ 1 │ │
|
||
|
│ │... │ │
|
||
|
│ │Token│ │
|
||
|
│ │ 4 │ │
|
||
|
│ └─────┘ │
|
||
|
└─────────────┘
|
||
|
```
|
||
|
**Wyjaśnienie:**
|
||
|
|
||
|
* Każdy token w sekwencji jest reprezentowany przez wektor o wymiarach 256.
|
||
|
* Model przetwarza te osadzenia, aby nauczyć się wzorców językowych i generować prognozy.
|
||
|
|
||
|
## **Osadzenia Pozycyjne: Dodawanie Kontekstu do Osadzeń Tokenów**
|
||
|
|
||
|
Podczas gdy osadzenia tokenów uchwycają znaczenie poszczególnych tokenów, nie kodują one z natury pozycji tokenów w sekwencji. Zrozumienie kolejności tokenów jest kluczowe dla zrozumienia języka. Tutaj wkraczają **osadzenia pozycyjne**.
|
||
|
|
||
|
### **Dlaczego Osadzenia Pozycyjne Są Potrzebne:**
|
||
|
|
||
|
* **Kolejność Tokenów Ma Znaczenie:** W zdaniach znaczenie często zależy od kolejności słów. Na przykład, "Kot usiadł na macie" vs. "Mata usiadła na kocie."
|
||
|
* **Ograniczenie Osadzenia:** Bez informacji pozycyjnej model traktuje tokeny jako "worek słów", ignorując ich sekwencję.
|
||
|
|
||
|
### **Rodzaje Osadzeń Pozycyjnych:**
|
||
|
|
||
|
1. **Absolutne Osadzenia Pozycyjne:**
|
||
|
* Przypisują unikalny wektor pozycji do każdej pozycji w sekwencji.
|
||
|
* **Przykład:** Pierwszy token w dowolnej sekwencji ma to samo osadzenie pozycyjne, drugi token ma inne, i tak dalej.
|
||
|
* **Używane przez:** Modele GPT OpenAI.
|
||
|
2. **Relatywne Osadzenia Pozycyjne:**
|
||
|
* Kodują względną odległość między tokenami, a nie ich absolutne pozycje.
|
||
|
* **Przykład:** Wskazują, jak daleko od siebie są dwa tokeny, niezależnie od ich absolutnych pozycji w sekwencji.
|
||
|
* **Używane przez:** Modele takie jak Transformer-XL i niektóre warianty BERT.
|
||
|
|
||
|
### **Jak Osadzenia Pozycyjne Są Zintegrowane:**
|
||
|
|
||
|
* **Te Same Wymiary:** Osadzenia pozycyjne mają tę samą wymiarowość co osadzenia tokenów.
|
||
|
* **Dodawanie:** Są dodawane do osadzeń tokenów, łącząc tożsamość tokenu z informacją pozycyjną bez zwiększania ogólnej wymiarowości.
|
||
|
|
||
|
**Przykład Dodawania Osadzeń Pozycyjnych:**
|
||
|
|
||
|
Załóżmy, że wektor osadzenia tokenu to `[0.5, -0.2, 0.1]`, a jego wektor osadzenia pozycyjnego to `[0.1, 0.3, -0.1]`. Połączone osadzenie używane przez model byłoby:
|
||
|
```css
|
||
|
Combined Embedding = Token Embedding + Positional Embedding
|
||
|
= [0.5 + 0.1, -0.2 + 0.3, 0.1 + (-0.1)]
|
||
|
= [0.6, 0.1, 0.0]
|
||
|
```
|
||
|
**Zalety osadzeń pozycyjnych:**
|
||
|
|
||
|
* **Świadomość kontekstowa:** Model potrafi rozróżniać tokeny na podstawie ich pozycji.
|
||
|
* **Zrozumienie sekwencji:** Umożliwia modelowi zrozumienie gramatyki, składni i znaczeń zależnych od kontekstu.
|
||
|
|
||
|
## Przykład kodu
|
||
|
|
||
|
Poniżej znajduje się przykład kodu z [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01\_main-chapter-code/ch02.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01\_main-chapter-code/ch02.ipynb):
|
||
|
```python
|
||
|
# Use previous code...
|
||
|
|
||
|
# Create dimensional emdeddings
|
||
|
"""
|
||
|
BPE uses a vocabulary of 50257 words
|
||
|
Let's supose we want to use 256 dimensions (instead of the millions used by LLMs)
|
||
|
"""
|
||
|
|
||
|
vocab_size = 50257
|
||
|
output_dim = 256
|
||
|
token_embedding_layer = torch.nn.Embedding(vocab_size, output_dim)
|
||
|
|
||
|
## Generate the dataloader like before
|
||
|
max_length = 4
|
||
|
dataloader = create_dataloader_v1(
|
||
|
raw_text, batch_size=8, max_length=max_length,
|
||
|
stride=max_length, shuffle=False
|
||
|
)
|
||
|
data_iter = iter(dataloader)
|
||
|
inputs, targets = next(data_iter)
|
||
|
|
||
|
# Apply embeddings
|
||
|
token_embeddings = token_embedding_layer(inputs)
|
||
|
print(token_embeddings.shape)
|
||
|
torch.Size([8, 4, 256]) # 8 x 4 x 256
|
||
|
|
||
|
# Generate absolute embeddings
|
||
|
context_length = max_length
|
||
|
pos_embedding_layer = torch.nn.Embedding(context_length, output_dim)
|
||
|
|
||
|
pos_embeddings = pos_embedding_layer(torch.arange(max_length))
|
||
|
|
||
|
input_embeddings = token_embeddings + pos_embeddings
|
||
|
print(input_embeddings.shape) # torch.Size([8, 4, 256])
|
||
|
```
|
||
|
## Odniesienia
|
||
|
|
||
|
* [https://www.manning.com/books/build-a-large-language-model-from-scratch](https://www.manning.com/books/build-a-large-language-model-from-scratch)
|