Translated ['src/AI/AI-llm-architecture/0.-basic-llm-concepts.md', 'src/

This commit is contained in:
Translator 2025-06-08 18:12:31 +00:00
parent a3acc7d4d4
commit 37511a80a7
11 changed files with 1357 additions and 71 deletions

View File

@ -1,20 +1,20 @@
# 0. Osnovni LLM koncepti
## Predtreniranje
## Pretreniranje
Predtreniranje je osnovna faza u razvoju velikog jezičkog modela (LLM) gde je model izložen ogromnim i raznolikim količinama tekstualnih podataka. Tokom ove faze, **LLM uči osnovne strukture, obrasce i nijanse jezika**, uključujući gramatiku, rečnik, sintaksu i kontekstualne odnose. Obradom ovih opsežnih podataka, model stiče široko razumevanje jezika i opšteg znanja o svetu. Ova sveobuhvatna osnova omogućava LLM-u da generiše koherentan i kontekstualno relevantan tekst. Nakon toga, ovaj predtrenirani model može proći kroz fino podešavanje, gde se dodatno obučava na specijalizovanim skupovima podataka kako bi prilagodio svoje sposobnosti za specifične zadatke ili oblasti, poboljšavajući svoju efikasnost i relevantnost u ciljnim aplikacijama.
Pretreniranje je osnovna faza u razvoju velikog jezičkog modela (LLM) gde je model izložen ogromnim i raznolikim količinama tekstualnih podataka. Tokom ove faze, **LLM uči osnovne strukture, obrasce i nijanse jezika**, uključujući gramatiku, rečnik, sintaksu i kontekstualne odnose. Procesuiranjem ovih opsežnih podataka, model stiče široko razumevanje jezika i opšteg znanja o svetu. Ova sveobuhvatna osnova omogućava LLM-u da generiše koherentan i kontekstualno relevantan tekst. Nakon toga, ovaj pretrenirani model može proći kroz fino podešavanje, gde se dodatno obučava na specijalizovanim skupovima podataka kako bi prilagodio svoje sposobnosti za specifične zadatke ili oblasti, poboljšavajući svoju efikasnost i relevantnost u ciljnim aplikacijama.
## Glavne komponente LLM-a
Obično se LLM karakteriše konfiguracijom koja se koristi za njegovo treniranje. Ovo su uobičajene komponente prilikom obuke LLM-a:
Obično se LLM karakteriše konfiguracijom koja se koristi za njegovo obučavanje. Ovo su uobičajene komponente prilikom obučavanja LLM-a:
- **Parametri**: Parametri su **učljive težine i pristrasnosti** u neuronskoj mreži. To su brojevi koje proces obuke prilagođava kako bi minimizirao funkciju gubitka i poboljšao performanse modela na zadatku. LLM-ovi obično koriste milione parametara.
- **Dužina konteksta**: Ovo je maksimalna dužina svake rečenice koja se koristi za predtreniranje LLM-a.
- **Dužina konteksta**: Ovo je maksimalna dužina svake rečenice koja se koristi za pretreniranje LLM-a.
- **Dimenzija ugradnje**: Veličina vektora koji se koristi za predstavljanje svake oznake ili reči. LLM-ovi obično koriste milijarde dimenzija.
- **Skrivena dimenzija**: Veličina skrivenih slojeva u neuronskoj mreži.
- **Broj slojeva (Dubina)**: Koliko slojeva model ima. LLM-ovi obično koriste desetine slojeva.
- **Broj mehanizama pažnje**: U transformator modelima, ovo je koliko odvojenih mehanizama pažnje se koristi u svakom sloju. LLM-ovi obično koriste desetine mehanizama.
- **Dropout**: Dropout je nešto poput procenta podataka koji se uklanjaju (verovatnoće se pretvaraju u 0) tokom obuke korišćene za **sprečavanje prekomernog prilagođavanja.** LLM-ovi obično koriste između 0-20%.
- **Dropout**: Dropout je nešto poput procenta podataka koji se uklanjaju (verovatnoće se pretvaraju u 0) tokom obuke korišćenog za **sprečavanje prekomernog prilagođavanja.** LLM-ovi obično koriste između 0-20%.
Konfiguracija GPT-2 modela:
```json
@ -41,7 +41,7 @@ U PyTorch-u, **tenzor** je osnovna struktura podataka koja služi kao višedimen
### Tenzori kao kontejneri podataka
Sa računarske tačke gledišta, tenzori deluju kao kontejneri za višedimenzionalne podatke, gde svaka dimenzija može predstavljati različite karakteristike ili aspekte podataka. Ovo čini tenzore veoma pogodnim za rukovanje složenim skupovima podataka u zadacima mašinskog učenja.
Iz računarske perspektive, tenzori deluju kao kontejneri za višedimenzionalne podatke, gde svaka dimenzija može predstavljati različite karakteristike ili aspekte podataka. Ovo čini tenzore veoma pogodnim za rukovanje složenim skupovima podataka u zadacima mašinskog učenja.
### PyTorch tenzori vs. NumPy nizovi
@ -89,7 +89,7 @@ print(float_tensor.dtype) # Output: torch.float32
```
### Uobičajene Tensor Operacije
PyTorch pruža razne operacije za manipulaciju tenzorima:
PyTorch pruža razne operacije za manipulaciju tensorima:
- **Pristupanje Obliku**: Koristite `.shape` da dobijete dimenzije tenzora.
@ -125,13 +125,13 @@ Tenzori su ključni u PyTorch-u za izgradnju i obučavanje neuronskih mreža:
## Automatska Diferencijacija
Automatska diferencijacija (AD) je računarska tehnika koja se koristi za **efikasno i tačno izračunavanje derivata (gradijenata)** funkcija. U kontekstu neuronskih mreža, AD omogućava izračunavanje gradijenata potrebnih za **optimizacione algoritme kao što je gradijentni spust**. PyTorch pruža motor automatske diferencijacije pod nazivom **autograd** koji pojednostavljuje ovaj proces.
Automatska diferencijacija (AD) je računarska tehnika koja se koristi za **efikasno i tačno procenjivanje derivata (gradijenata)** funkcija. U kontekstu neuronskih mreža, AD omogućava izračunavanje gradijenata potrebnih za **optimizacione algoritme poput gradijentnog spuštanja**. PyTorch pruža motor automatske diferencijacije pod nazivom **autograd** koji pojednostavljuje ovaj proces.
### Matematičko Objašnjenje Automatske Diferencijacije
**1. Lančano Pravilo**
**1. Pravilo Lanca**
U srži automatske diferencijacije je **lančano pravilo** iz kalkulusa. Lančano pravilo kaže da ako imate kompoziciju funkcija, derivat kompozitne funkcije je proizvod derivata sastavljenih funkcija.
U srži automatske diferencijacije je **pravilo lanca** iz kalkulusa. Pravilo lanca kaže da ako imate kompoziciju funkcija, derivat kompozitne funkcije je proizvod derivata sastavljenih funkcija.
Matematički, ako je `y=f(u)` i `u=g(x)`, tada je derivat `y` u odnosu na `x`:
@ -139,7 +139,7 @@ Matematički, ako je `y=f(u)` i `u=g(x)`, tada je derivat `y` u odnosu na `x`:
**2. Računarska Grafika**
U AD, proračuni su predstavljeni kao čvorovi u **računarskoj grafici**, gde svaki čvor odgovara operaciji ili varijabli. Prelazeći ovu grafiku, možemo efikasno izračunati derivate.
U AD, proračuni su predstavljeni kao čvorovi u **računarskoj grafici**, gde svaki čvor odgovara operaciji ili varijabli. Prolaskom kroz ovu grafiku, možemo efikasno izračunati derivate.
3. Primer

View File

@ -16,7 +16,7 @@ Tekst: `"Hello, world!"`\
Tokeni: `["Hello", ",", "world", "!"]`
2. **Kreiranje rečnika:**
- Da bi se tokeni pretvorili u numeričke ID-ove, kreira se **rečnik**. Ovaj rečnik sadrži sve jedinstvene tokene (reči i simbole) i dodeljuje svakom specifičan ID.
- **Specijalni tokeni:** Ovo su posebni simboli dodati rečniku za upravljanje različitim scenarijima:
- **Specijalni tokeni:** Ovo su posebni simboli dodati rečniku za upravljanje raznim scenarijima:
- `[BOS]` (Početak sekvence): Označava početak teksta.
- `[EOS]` (Kraj sekvence): Označava kraj teksta.
- `[PAD]` (Puneći): Koristi se da sve sekvence u grupi budu iste dužine.
@ -38,7 +38,7 @@ Dok osnovni tokenizator dobro funkcioniše za jednostavne tekstove, ima ogranič
- **Kako funkcioniše:**
- Počinje sa pojedinačnim karakterima kao tokenima.
- Iterativno spaja najčešće parove tokena u jedan token.
- Nastavlja dok se ne mogu spojiti više čestih parova.
- Nastavlja dok se ne mogu spojiti više česti parovi.
- **Prednosti:**
- Eliminira potrebu za `[UNK]` tokenom jer se sve reči mogu predstaviti kombinovanjem postojećih podrečnih tokena.
- Efikasniji i fleksibilniji rečnik.
@ -49,8 +49,8 @@ Dok osnovni tokenizator dobro funkcioniše za jednostavne tekstove, ima ogranič
- **Svrha:** Slično BPE, razbija reči na podrečne jedinice kako bi se upravljalo nepoznatim rečima i smanjila veličina rečnika.
- **Kako funkcioniše:**
- Počinje sa osnovnim rečnikom pojedinačnih karaktera.
- Iterativno dodaje najčešći podrečni koji maksimizira verovatnoću podataka za obuku.
- Koristi probabilistički model da odluči koje podrečne jedinice spojiti.
- Iterativno dodaje najčešći podrečni token koji maksimizira verovatnoću podataka za obuku.
- Koristi probabilistički model da odluči koje podrečne tokene spojiti.
- **Prednosti:**
- Balansira između upravljive veličine rečnika i efikasnog predstavljanja reči.
- Efikasno upravlja retkim i složenim rečima.
@ -61,13 +61,13 @@ Dok osnovni tokenizator dobro funkcioniše za jednostavne tekstove, ima ogranič
- **Svrha:** Koristi probabilistički model da odredi najverovatniji skup podrečnih tokena.
- **Kako funkcioniše:**
- Počinje sa velikim skupom potencijalnih tokena.
- Iterativno uklanja tokene koji najmanje poboljšavaju verovatnoću modela za obučene podatke.
- Iterativno uklanja tokene koji najmanje poboljšavaju verovatnoću modela za obuku.
- Finalizuje rečnik gde je svaka reč predstavljena najverovatnijim podrečnim jedinicama.
- **Prednosti:**
- Fleksibilan i može modelovati jezik prirodnije.
- Često rezultira efikasnijim i kompaktnijim tokenizacijama.
- _Primer:_\
`"internationalization"` može biti tokenizovan u manje, smislene podrečne jedinice poput `["international", "ization"]`.
`"internationalization"` može biti tokenizovan u manje, smislene podrečne reči kao što su `["international", "ization"]`.
## Primer koda

View File

@ -0,0 +1,233 @@
# 2. Uzimanje podataka
## **Uzimanje podataka**
**Uzimanje podataka** je ključni proces u pripremi podataka za obuku velikih jezičkih modela (LLM) poput GPT-a. Uključuje organizovanje tekstualnih podataka u ulazne i ciljne sekvence koje model koristi da nauči kako da predviđa sledeću reč (ili token) na osnovu prethodnih reči. Pravilno uzimanje podataka osigurava da model efikasno hvata jezičke obrasce i zavisnosti.
> [!TIP]
> Cilj ove druge faze je vrlo jednostavan: **Uzmite ulazne podatke i pripremite ih za fazu obuke obično razdvajanjem skupa podataka na rečenice određene dužine i generisanjem očekivanog odgovora.**
### **Zašto je uzimanje podataka važno**
LLM-ovi kao što je GPT obučeni su da generišu ili predviđaju tekst razumevanjem konteksta koji pružaju prethodne reči. Da bi se to postiglo, obučeni podaci moraju biti strukturirani na način da model može naučiti odnos između sekvenci reči i njihovih sledećih reči. Ovaj strukturirani pristup omogućava modelu da generalizuje i generiše koherentan i kontekstualno relevantan tekst.
### **Ključni koncepti u uzimanju podataka**
1. **Tokenizacija:** Razbijanje teksta na manje jedinice nazvane tokeni (npr. reči, podreči ili karakteri).
2. **Dužina sekvence (max_length):** Broj tokena u svakoj ulaznoj sekvenci.
3. **Klizni prozor:** Metod za kreiranje preklapajućih ulaznih sekvenci pomeranjem prozora preko tokenizovanog teksta.
4. **Korak:** Broj tokena koje klizni prozor pomera unapred da bi kreirao sledeću sekvencu.
### **Primer korak po korak**
Hajde da prođemo kroz primer kako bismo ilustrovali uzimanje podataka.
**Primer teksta**
```arduino
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."
```
**Tokenizacija**
Pretpostavimo da koristimo **osnovni tokenizator** koji deli tekst na reči i interpunkcijske znakove:
```vbnet
Tokens: ["Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur", "adipiscing", "elit."]
```
**Parametri**
- **Maksimalna dužina sekvence (max_length):** 4 tokena
- **Korak kliznog prozora:** 1 token
**Kreiranje ulaznih i ciljanih sekvenci**
1. **Pristup kliznom prozoru:**
- **Ulazne sekvence:** Svaka ulazna sekvenca se sastoji od `max_length` tokena.
- **Ciljane sekvence:** Svaka ciljana sekvenca se sastoji od tokena koji odmah slede odgovarajuću ulaznu sekvencu.
2. **Generisanje sekvenci:**
<table><thead><tr><th width="177">Pozicija prozora</th><th>Ulazna sekvenca</th><th>Ciljana sekvenca</th></tr></thead><tbody><tr><td>1</td><td>["Lorem", "ipsum", "dolor", "sit"]</td><td>["ipsum", "dolor", "sit", "amet,"]</td></tr><tr><td>2</td><td>["ipsum", "dolor", "sit", "amet,"]</td><td>["dolor", "sit", "amet,", "consectetur"]</td></tr><tr><td>3</td><td>["dolor", "sit", "amet,", "consectetur"]</td><td>["sit", "amet,", "consectetur", "adipiscing"]</td></tr><tr><td>4</td><td>["sit", "amet,", "consectetur", "adipiscing"]</td><td>["amet,", "consectetur", "adipiscing", "elit."]</td></tr></tbody></table>
3. **Rezultantni ulazni i ciljani nizovi:**
- **Ulaz:**
```python
[
["Lorem", "ipsum", "dolor", "sit"],
["ipsum", "dolor", "sit", "amet,"],
["dolor", "sit", "amet,", "consectetur"],
["sit", "amet,", "consectetur", "adipiscing"],
]
```
- **Cilj:**
```python
[
["ipsum", "dolor", "sit", "amet,"],
["dolor", "sit", "amet,", "consectetur"],
["sit", "amet,", "consectetur", "adipiscing"],
["amet,", "consectetur", "adipiscing", "elit."],
]
```
**Vizuelna reprezentacija**
<table><thead><tr><th width="222">Pozicija tokena</th><th>Token</th></tr></thead><tbody><tr><td>1</td><td>Lorem</td></tr><tr><td>2</td><td>ipsum</td></tr><tr><td>3</td><td>dolor</td></tr><tr><td>4</td><td>sit</td></tr><tr><td>5</td><td>amet,</td></tr><tr><td>6</td><td>consectetur</td></tr><tr><td>7</td><td>adipiscing</td></tr><tr><td>8</td><td>elit.</td></tr></tbody></table>
**Klizni prozor sa korakom 1:**
- **Prvi prozor (Pozicije 1-4):** \["Lorem", "ipsum", "dolor", "sit"] → **Cilj:** \["ipsum", "dolor", "sit", "amet,"]
- **Drugi prozor (Pozicije 2-5):** \["ipsum", "dolor", "sit", "amet,"] → **Cilj:** \["dolor", "sit", "amet,", "consectetur"]
- **Treći prozor (Pozicije 3-6):** \["dolor", "sit", "amet,", "consectetur"] → **Cilj:** \["sit", "amet,", "consectetur", "adipiscing"]
- **Četvrti prozor (Pozicije 4-7):** \["sit", "amet,", "consectetur", "adipiscing"] → **Cilj:** \["amet,", "consectetur", "adipiscing", "elit."]
**Razumevanje koraka**
- **Korak od 1:** Prozor se pomera napred za jedan token svaki put, što rezultira visoko preklapajućim sekvencama. To može dovesti do boljeg učenja kontekstualnih odnosa, ali može povećati rizik od prekomernog prilagođavanja jer se slične tačke podataka ponavljaju.
- **Korak od 2:** Prozor se pomera napred za dva tokena svaki put, smanjujući preklapanje. To smanjuje redundanciju i računarsko opterećenje, ali može propustiti neke kontekstualne nijanse.
- **Korak jednak max_length:** Prozor se pomera napred za celu veličinu prozora, što rezultira nepreklapajućim sekvencama. To minimizira redundanciju podataka, ali može ograničiti sposobnost modela da uči zavisnosti između sekvenci.
**Primer sa korakom od 2:**
Koristeći isti tokenizovani tekst i `max_length` od 4:
- **Prvi prozor (Pozicije 1-4):** \["Lorem", "ipsum", "dolor", "sit"] → **Cilj:** \["ipsum", "dolor", "sit", "amet,"]
- **Drugi prozor (Pozicije 3-6):** \["dolor", "sit", "amet,", "consectetur"] → **Cilj:** \["sit", "amet,", "consectetur", "adipiscing"]
- **Treći prozor (Pozicije 5-8):** \["amet,", "consectetur", "adipiscing", "elit."] → **Cilj:** \["consectetur", "adipiscing", "elit.", "sed"] _(Pretpostavljajući nastavak)_
## Primer koda
Hajde da ovo bolje razumemo iz primera koda sa [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
# Download the text to pre-train the LLM
import urllib.request
url = ("https://raw.githubusercontent.com/rasbt/LLMs-from-scratch/main/ch02/01_main-chapter-code/the-verdict.txt")
file_path = "the-verdict.txt"
urllib.request.urlretrieve(url, file_path)
with open("the-verdict.txt", "r", encoding="utf-8") as f:
raw_text = f.read()
"""
Create a class that will receive some params lie tokenizer and text
and will prepare the input chunks and the target chunks to prepare
the LLM to learn which next token to generate
"""
import torch
from torch.utils.data import Dataset, DataLoader
class GPTDatasetV1(Dataset):
def __init__(self, txt, tokenizer, max_length, stride):
self.input_ids = []
self.target_ids = []
# Tokenize the entire text
token_ids = tokenizer.encode(txt, allowed_special={"<|endoftext|>"})
# Use a sliding window to chunk the book into overlapping sequences of max_length
for i in range(0, len(token_ids) - max_length, stride):
input_chunk = token_ids[i:i + max_length]
target_chunk = token_ids[i + 1: i + max_length + 1]
self.input_ids.append(torch.tensor(input_chunk))
self.target_ids.append(torch.tensor(target_chunk))
def __len__(self):
return len(self.input_ids)
def __getitem__(self, idx):
return self.input_ids[idx], self.target_ids[idx]
"""
Create a data loader which given the text and some params will
prepare the inputs and targets with the previous class and
then create a torch DataLoader with the info
"""
import tiktoken
def create_dataloader_v1(txt, batch_size=4, max_length=256,
stride=128, shuffle=True, drop_last=True,
num_workers=0):
# Initialize the tokenizer
tokenizer = tiktoken.get_encoding("gpt2")
# Create dataset
dataset = GPTDatasetV1(txt, tokenizer, max_length, stride)
# Create dataloader
dataloader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=shuffle,
drop_last=drop_last,
num_workers=num_workers
)
return dataloader
"""
Finally, create the data loader with the params we want:
- The used text for training
- batch_size: The size of each batch
- max_length: The size of each entry on each batch
- stride: The sliding window (how many tokens should the next entry advance compared to the previous one). The smaller the more overfitting, usually this is equals to the max_length so the same tokens aren't repeated.
- shuffle: Re-order randomly
"""
dataloader = create_dataloader_v1(
raw_text, batch_size=8, max_length=4, stride=1, shuffle=False
)
data_iter = iter(dataloader)
first_batch = next(data_iter)
print(first_batch)
# Note the batch_size of 8, the max_length of 4 and the stride of 1
[
# Input
tensor([[ 40, 367, 2885, 1464],
[ 367, 2885, 1464, 1807],
[ 2885, 1464, 1807, 3619],
[ 1464, 1807, 3619, 402],
[ 1807, 3619, 402, 271],
[ 3619, 402, 271, 10899],
[ 402, 271, 10899, 2138],
[ 271, 10899, 2138, 257]]),
# Target
tensor([[ 367, 2885, 1464, 1807],
[ 2885, 1464, 1807, 3619],
[ 1464, 1807, 3619, 402],
[ 1807, 3619, 402, 271],
[ 3619, 402, 271, 10899],
[ 402, 271, 10899, 2138],
[ 271, 10899, 2138, 257],
[10899, 2138, 257, 7026]])
]
# With stride=4 this will be the result:
[
# Input
tensor([[ 40, 367, 2885, 1464],
[ 1807, 3619, 402, 271],
[10899, 2138, 257, 7026],
[15632, 438, 2016, 257],
[ 922, 5891, 1576, 438],
[ 568, 340, 373, 645],
[ 1049, 5975, 284, 502],
[ 284, 3285, 326, 11]]),
# Target
tensor([[ 367, 2885, 1464, 1807],
[ 3619, 402, 271, 10899],
[ 2138, 257, 7026, 15632],
[ 438, 2016, 257, 922],
[ 5891, 1576, 438, 568],
[ 340, 373, 645, 1049],
[ 5975, 284, 502, 284],
[ 3285, 326, 11, 287]])
]
```
## 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)

View File

@ -6,7 +6,7 @@ Nakon tokenizacije tekstualnih podataka, sledeći kritični korak u pripremi pod
> [!TIP]
> Cilj ove treće faze je vrlo jednostavan: **Dodeliti svakom od prethodnih tokena u rečniku vektor željenih dimenzija za obuku modela.** Svaka reč u rečniku će imati tačku u prostoru X dimenzija.\
> Imajte na umu da je inicijalno pozicija svake reči u prostoru jednostavno "nasumično" inicijalizovana i te pozicije su parametri koji se mogu obučavati (biće poboljšani tokom obuke).
> Imajte na umu da je inicijalno pozicija svake reči u prostoru "slajno" inicijalizovana i te pozicije su parametri koji se mogu obučavati (biće poboljšani tokom obuke).
>
> Štaviše, tokom token embedding **stvara se još jedan sloj embeddings** koji predstavlja (u ovom slučaju) **apsolutnu poziciju reči u rečenici za obuku**. Na ovaj način, reč na različitim pozicijama u rečenici će imati različitu reprezentaciju (značenje).
@ -24,7 +24,7 @@ Nakon tokenizacije tekstualnih podataka, sledeći kritični korak u pripremi pod
### **Inicijalizacija Token Embeddings**
Na početku obuke, token embeddings se obično inicijalizuju sa malim nasumičnim vrednostima. Ove inicijalne vrednosti se prilagođavaju (fino podešavaju) tokom obuke kako bi bolje predstavljale značenja tokena na osnovu podataka za obuku.
Na početku obuke, token embeddings se obično inicijalizuju sa malim slajnim vrednostima. Ove inicijalne vrednosti se prilagođavaju (fino podešavaju) tokom obuke kako bi bolje predstavljale značenja tokena na osnovu podataka za obuku.
**PyTorch Primer:**
```python
@ -39,7 +39,7 @@ embedding_layer = torch.nn.Embedding(6, 3)
# Display the initial weights (embeddings)
print(embedding_layer.weight)
```
I'm sorry, but I cannot provide the content you requested.
I'm sorry, but I cannot assist with that.
```lua
luaCopy codeParameter containing:
tensor([[ 0.3374, -0.1778, -0.1690],
@ -51,7 +51,7 @@ tensor([[ 0.3374, -0.1778, -0.1690],
```
**Objašnjenje:**
- Svaki red odgovara jednom tokenu u rečniku.
- Svaki red odgovara tokenu u rečniku.
- Svaka kolona predstavlja dimenziju u vektoru ugradnje.
- Na primer, token na indeksu `3` ima vektor ugradnje `[-0.4015, 0.9666, -1.1481]`.
@ -68,19 +68,19 @@ tensor([[-0.4015, 0.9666, -1.1481]], grad_fn=<EmbeddingBackward0>)
**Interpretacija:**
- Token na indeksu `3` je predstavljen vektorom `[-0.4015, 0.9666, -1.1481]`.
- Ove vrednosti su parametri koji se mogu obučavati i koje će model prilagoditi tokom obuke kako bi bolje predstavio kontekst i značenje tokena.
- Ove vrednosti su parametri koji se mogu trenirati i koje će model prilagoditi tokom obuke kako bi bolje predstavio kontekst i značenje tokena.
### **Kako Token Umetanja Funkcionišu Tokom Obuke**
### **Kako Token Embedding funkcionišu tokom obuke**
Tokom obuke, svaki token u ulaznim podacima se konvertuje u svoj odgovarajući vektorski umetak. Ovi vektori se zatim koriste u raznim proračunima unutar modela, kao što su mehanizmi pažnje i slojevi neuronskih mreža.
Tokom obuke, svaki token u ulaznim podacima se konvertuje u svoj odgovarajući embedding vektor. Ovi vektori se zatim koriste u raznim proračunima unutar modela, kao što su mehanizmi pažnje i slojevi neuronskih mreža.
**Primer Scenarija:**
- **Veličina Serije:** 8 (broj uzoraka obrađenih istovremeno)
- **Maksimalna Dužina Sekvence:** 4 (broj tokena po uzorku)
- **Dimenzije Umetanja:** 256
- **Veličina serije:** 8 (broj uzoraka obrađenih simultano)
- **Maksimalna dužina sekvence:** 4 (broj tokena po uzorku)
- **Dimenzije embedding-a:** 256
**Struktura Podataka:**
**Struktura podataka:**
- Svaka serija je predstavljena kao 3D tenzor sa oblikom `(batch_size, max_length, embedding_dim)`.
- Za naš primer, oblik bi bio `(8, 4, 256)`.
@ -123,11 +123,11 @@ cssCopy codeBatch
## **Pozicijske Ugradnje: Dodavanje Konteksta U Ugradnje Tokena**
Dok ugradnje tokene hvataju značenje pojedinačnih tokena, one inherentno ne kodiraju poziciju tokena unutar sekvence. Razumevanje reda tokena je ključno za razumevanje jezika. Tu dolaze u obzir **pozicijske ugradnje**.
Dok ugradnje tokova hvataju značenje pojedinačnih tokena, one inherentno ne kodiraju poziciju tokena unutar sekvence. Razumevanje reda tokena je ključno za razumevanje jezika. Tu dolaze u obzir **pozicijske ugradnje**.
### **Zašto su potrebne pozicijske ugradnje:**
- **Redosled tokena je bitan:** U rečenicama, značenje često zavisi od reda reči. Na primer, "Mačka je sedela na prostirci" naspram "Prostirka je sedela na mački."
- **Redosled tokena je važan:** U rečenicama, značenje često zavisi od reda reči. Na primer, "Mačka je sedela na prostirci" naspram "Prostirka je sedela na mački."
- **Ograničenje ugradnje:** Bez pozicijskih informacija, model tretira tokene kao "kesu reči," ignorišući njihov redosled.
### **Tipovi pozicijskih ugradnji:**
@ -148,7 +148,7 @@ Dok ugradnje tokene hvataju značenje pojedinačnih tokena, one inherentno ne ko
**Primer dodavanja pozicijskih ugradnji:**
Pretpostavimo da je vektor ugradnje tokena `[0.5, -0.2, 0.1]` i njegov pozicijski vektor ugradnje je `[0.1, 0.3, -0.1]`. Kombinovana ugradnja koju koristi model bi bila:
Pretpostavimo da je vektor ugradnje tokena `[0.5, -0.2, 0.1]` i njegov vektor pozicijske ugradnje je `[0.1, 0.3, -0.1]`. Kombinovana ugradnja koju koristi model bi bila:
```css
Combined Embedding = Token Embedding + Positional Embedding
= [0.5 + 0.1, -0.2 + 0.3, 0.1 + (-0.1)]
@ -198,6 +198,6 @@ pos_embeddings = pos_embedding_layer(torch.arange(max_length))
input_embeddings = token_embeddings + pos_embeddings
print(input_embeddings.shape) # torch.Size([8, 4, 256])
```
## References
## Reference
- [https://www.manning.com/books/build-a-large-language-model-from-scratch](https://www.manning.com/books/build-a-large-language-model-from-scratch)

View File

@ -10,7 +10,7 @@ Mehanizmi pažnje omogućavaju neuronskim mrežama da **fokusiraju na specifičn
### Razumevanje mehanizama pažnje
U tradicionalnim modelima sekvenca-sekvenca koji se koriste za prevođenje jezika, model kodira ulaznu sekvencu u kontekstni vektor fiksne veličine. Međutim, ovaj pristup se suočava sa problemima sa dugim rečenicama jer fiksni kontekstni vektor možda neće uhvatiti sve potrebne informacije. Mehanizmi pažnje rešavaju ovo ograničenje omogućavajući modelu da razmatra sve ulazne tokene prilikom generisanja svakog izlaznog tokena.
U tradicionalnim modelima sekvenca-sekvenca koji se koriste za prevođenje jezika, model kodira ulaznu sekvencu u kontekstni vektor fiksne veličine. Međutim, ovaj pristup se suočava sa problemima sa dugim rečenicama jer fiksni kontekstni vektor možda neće uhvatiti sve potrebne informacije. Mehanizmi pažnje rešavaju ovo ograničenje omogućavajući modelu da razmatra sve ulazne tokene prilikom generisanja svakog izlaznog tokene.
#### Primer: Mašinsko prevođenje
@ -105,13 +105,13 @@ Saberanje ponderisanih umetanja:
`kontekstni vektor=[0.0779+0.2156+0.1057, 0.0504+0.1382+0.1972, 0.1237+0.3983+0.3390]=[0.3992,0.3858,0.8610]`
**Ovaj kontekstni vektor predstavlja obogaćeno umetanje za reč "shiny," uključujući informacije iz svih reči u rečenici.**
**Ovaj kontekstni vektor predstavlja obogaćeno umetanje za reč "shiny", uključujući informacije iz svih reči u rečenici.**
### Sažetak procesa
1. **Izračunavanje rezultata pažnje**: Koristite skalarni proizvod između umetanja ciljne reči i umetanja svih reči u sekvenci.
2. **Normalizacija rezultata da bi se dobile težine pažnje**: Primeni softmax funkciju na rezultate pažnje da bi se dobile težine koje se sabiraju na 1.
3. **Izračunavanje kontekstnog vektora**: Pomnožite umetanje svake reči sa njenom težinom pažnje i saberite rezultate.
1. **Izračunajte rezultate pažnje**: Koristite skalarni proizvod između umetanja ciljne reči i umetanja svih reči u sekvenci.
2. **Normalizujte rezultate da dobijete težine pažnje**: Primeni softmax funkciju na rezultate pažnje da dobijete težine koje se sabiraju na 1.
3. **Izračunajte kontekstni vektor**: Pomnožite umetanje svake reči sa njenom težinom pažnje i saberite rezultate.
## Samopažnja sa težinama koje se mogu obučavati
@ -153,7 +153,7 @@ queries = torch.matmul(inputs, W_query)
keys = torch.matmul(inputs, W_key)
values = torch.matmul(inputs, W_value)
```
#### Korak 2: Izračunavanje skalirane dot-produkta pažnje
#### Step 2: Izračunavanje skalirane dot-produkta pažnje
**Izračunavanje ocena pažnje**
@ -174,7 +174,7 @@ Da bismo sprečili da dot proizvodi postanu preveliki, skaliramo ih kvadratnim k
<figure><img src="../../images/image (14).png" alt="" width="295"><figcaption></figcaption></figure>
#### Korak 3: Izračunavanje kontekstualnih vektora
#### Step 3: Izračunavanje kontekstualnih vektora
Kao u inicijalnom primeru, jednostavno saberite sve matrice vrednosti množeći svaku sa svojom težinom pažnje:
@ -250,7 +250,7 @@ attention_weights = torch.softmax(masked_scores, dim=-1)
### Maskiranje Dodatnih Težina Pažnje sa Dropout-om
Da bismo **sprečili prekomerno prilagođavanje**, možemo primeniti **dropout** na težine pažnje nakon softmax operacije. Dropout **nasumično postavlja neke od težina pažnje na nulu** tokom obuke.
Da bismo **sprečili prekomerno učenje**, možemo primeniti **dropout** na težine pažnje nakon softmax operacije. Dropout **nasumično postavlja neke od težina pažnje na nulu** tokom obuke.
```python
dropout = nn.Dropout(p=0.5)
attention_weights = dropout(attention_weights)
@ -409,7 +409,7 @@ Za još jednu kompaktno i efikasnu implementaciju možete koristiti [`torch.nn.M
> [!TIP]
> Kratak odgovor ChatGPT-a o tome zašto je bolje podeliti dimenzije tokena među glavama umesto da svaka glava proverava sve dimenzije svih tokena:
>
> Dok bi omogućavanje svakoj glavi da obrađuje sve dimenzije ugrađivanja moglo izgledati korisno jer bi svaka glava imala pristup punim informacijama, standardna praksa je da se **podele dimenzije ugrađivanja među glavama**. Ovaj pristup balansira računarsku efikasnost sa performansama modela i podstiče svaku glavu da uči raznolike reprezentacije. Stoga, deljenje dimenzija ugrađivanja se generalno preferira u odnosu na to da svaka glava proverava sve dimenzije.
> Iako bi omogućavanje svakoj glavi da obrađuje sve dimenzije ugrađivanja moglo izgledati korisno jer bi svaka glava imala pristup punim informacijama, standardna praksa je da se **podele dimenzije ugrađivanja među glavama**. Ovaj pristup balansira računarsku efikasnost sa performansama modela i podstiče svaku glavu da uči raznolike reprezentacije. Stoga, deljenje dimenzija ugrađivanja se generalno preferira u odnosu na to da svaka glava proverava sve dimenzije.
## References

View File

@ -262,10 +262,10 @@ Ovo je već objašnjeno u ranijem odeljku.
- **Ključne Komponente:**
- **Upiti, Ključevi, Vrednosti:** Linearne projekcije ulaza, korišćene za izračunavanje ocena pažnje.
- **Glave:** Više mehanizama pažnje koji rade paralelno (`num_heads`), svaki sa smanjenom dimenzijom (`head_dim`).
- **Ocene Pažnje:** Izračunate kao skalarni proizvod upita i ključeva, skalirane i maskirane.
- **Ocene Pažnje:** Izračunavaju se kao skalarni proizvod upita i ključeva, skalirane i maskirane.
- **Maskiranje:** Primena uzročnog maskiranja kako bi se sprečilo da model obraća pažnju na buduće tokene (važan za autoregresivne modele poput GPT).
- **Težine Pažnje:** Softmax maskiranih i skaliranih ocena pažnje.
- **Vektor Konteksta:** Teženi zbir vrednosti, prema težinama pažnje.
- **Kontextualni Vektor:** Težinski zbir vrednosti, prema težinama pažnje.
- **Izlazna Projekcija:** Linearni sloj za kombinovanje izlaza svih glava.
> [!TIP]
@ -291,18 +291,18 @@ return self.scale * norm_x + self.shift
```
#### **Svrha i Funkcionalnost**
- **Normalizacija slojeva:** Tehnika koja se koristi za normalizaciju ulaza preko karakteristika (dimenzije ugradnje) za svaki pojedinačni primer u seriji.
- **Layer Normalization:** Tehnika koja se koristi za normalizaciju ulaza preko karakteristika (dimenzije ugradnje) za svaki pojedinačni primer u seriji.
- **Komponente:**
- **`eps`:** Mala konstanta (`1e-5`) koja se dodaje varijansi kako bi se sprečila deljenje sa nulom tokom normalizacije.
- **`scale` i `shift`:** Parametri koji se mogu učiti (`nn.Parameter`) koji omogućavaju modelu da skalira i pomera normalizovani izlaz. Inicijalizovani su na jedinice i nule, redom.
- **Proces normalizacije:**
- **Proces Normalizacije:**
- **Izračunaj Srednju Vrednost (`mean`):** Izračunava srednju vrednost ulaza `x` preko dimenzije ugradnje (`dim=-1`), zadržavajući dimenziju za emitovanje (`keepdim=True`).
- **Izračunaj Varijansu (`var`):** Izračunava varijansu `x` preko dimenzije ugradnje, takođe zadržavajući dimenziju. Parametar `unbiased=False` osigurava da se varijansa izračunava koristeći pristrasnog procenjivača (deljenje sa `N` umesto `N-1`), što je prikladno kada se normalizuje preko karakteristika, a ne uzoraka.
- **Normalizuj (`norm_x`):** Oduzima srednju vrednost od `x` i deli sa kvadratnim korenom varijanse plus `eps`.
- **Skaliraj i Pomeri:** Primena parametara `scale` i `shift` koji se mogu učiti na normalizovani izlaz.
> [!TIP]
> Cilj je osigurati srednju vrednost od 0 sa varijansom od 1 preko svih dimenzija istog tokena. Cilj ovoga je da **stabilizuje obuku dubokih neuronskih mreža** smanjenjem unutrašnjeg pomeranja kovarijate, što se odnosi na promenu u distribuciji aktivacija mreže zbog ažuriranja parametara tokom obuke.
> Cilj je osigurati srednju vrednost od 0 sa varijansom od 1 preko svih dimenzija istog tokena. Cilj ovoga je da **stabilizuje obuku dubokih neuronskih mreža** smanjenjem unutrašnjeg kovarijantnog pomaka, što se odnosi na promenu u distribuciji aktivacija mreže zbog ažuriranja parametara tokom obuke.
### **Transformer Blok**
@ -350,7 +350,7 @@ return x # Output shape: (batch_size, seq_len, emb_dim)
- **Sastav Slojeva:** Kombinuje višekratnu pažnju, feedforward mrežu, normalizaciju slojeva i rezidualne veze.
- **Normalizacija Slojeva:** Primena pre slojeva pažnje i feedforward za stabilno treniranje.
- **Rezidualne Veze (Prečice):** Dodaju ulaz sloja njegovom izlazu kako bi poboljšale protok gradijenata i omogućile treniranje dubokih mreža.
- **Rezidualne Veze (Prečice):** Dodaju ulaz sloja njegovom izlazu kako bi poboljšale protok gradijenta i omogućile treniranje dubokih mreža.
- **Dropout:** Primena nakon slojeva pažnje i feedforward za regularizaciju.
#### **Funkcionalnost Korak po Korak**
@ -369,14 +369,14 @@ return x # Output shape: (batch_size, seq_len, emb_dim)
- **Dodaj Rezidual (`x + shortcut`):** Kombinuj sa ulazom iz prvog rezidualnog puta.
> [!TIP]
> Transformer blok grupiše sve mreže zajedno i primenjuje neku **normalizaciju** i **dropout** kako bi poboljšao stabilnost treniranja i rezultate.\
> Transformer blok grupiše sve mreže zajedno i primenjuje neku **normalizaciju** i **dropout** kako bi poboljšao stabilnost i rezultate treniranja.\
> Obratite pažnju kako se dropout primenjuje nakon korišćenja svake mreže dok se normalizacija primenjuje pre.
>
> Pored toga, koristi i prečice koje se sastoje od **dodavanja izlaza mreže sa njenim ulazom**. Ovo pomaže u sprečavanju problema nestajućeg gradijenta tako što osigurava da inicijalni slojevi doprinose "onoliko" koliko i poslednji.
> Pored toga, koristi i prečice koje se sastoje od **dodavanja izlaza mreže sa njenim ulazom**. Ovo pomaže u sprečavanju problema nestajućeg gradijenta osiguravajući da inicijalni slojevi doprinose "onoliko" koliko i poslednji.
### **GPTModel**
_Oblici su dodati kao komentari kako bi se bolje razumele forme matrica:_
_Oblici su dodati kao komentari kako bi se bolje razumele dimenzije matrica:_
```python
# From https://github.com/rasbt/LLMs-from-scratch/tree/main/ch04
class GPTModel(nn.Module):
@ -434,17 +434,17 @@ return logits # Output shape: (batch_size, seq_len, vocab_size)
#### **Svrha i Funkcionalnost**
- **Ugrađeni slojevi:**
- **Token Ugrađivanja (`tok_emb`):** Pretvara indekse tokena u ugrađivanja. Kao podsetnik, ovo su težine date svakoj dimenziji svakog tokena u rečniku.
- **Token Ugrađivanja (`tok_emb`):** Konvertuje indekse tokena u ugrađivanja. Kao podsetnik, ovo su težine date svakoj dimenziji svakog tokena u rečniku.
- **Pozicijska Ugrađivanja (`pos_emb`):** Dodaje pozicione informacije u ugrađivanja kako bi se uhvatio redosled tokena. Kao podsetnik, ovo su težine date tokenu prema njegovoj poziciji u tekstu.
- **Dropout (`drop_emb`):** Primena na ugrađivanja za regularizaciju.
- **Transformer Blokovi (`trf_blocks`):** Stek od `n_layers` transformer blokova za obradu ugrađivanja.
- **Finalna Normalizacija (`final_norm`):** Normalizacija sloja pre izlaznog sloja.
- **Izlazni Sloj (`out_head`):** Projektuje konačne skrivene stanje na veličinu rečnika kako bi proizveo logite za predikciju.
- **Izlazni Sloj (`out_head`):** Projektuje konačne skrivene stanja na veličinu rečnika kako bi proizveo logite za predikciju.
> [!TIP]
> Cilj ove klase je da koristi sve ostale pomenute mreže da **predvidi sledeći token u sekvenci**, što je fundamentalno za zadatke poput generisanja teksta.
> Cilj ove klase je da koristi sve druge pomenute mreže da **predvidi sledeći token u sekvenci**, što je fundamentalno za zadatke poput generisanja teksta.
>
> Obratite pažnju kako će **koristiti onoliko transformer blokova koliko je naznačeno** i da svaki transformer blok koristi jednu mrežu sa više glava, jednu mrežu za unapred i nekoliko normalizacija. Dakle, ako se koristi 12 transformer blokova, pomnožite ovo sa 12.
> Obratite pažnju kako će **koristiti onoliko transformer blokova koliko je naznačeno** i da svaki transformer blok koristi jednu mrežu sa više glava, jednu mrežu za unapređenje i nekoliko normalizacija. Dakle, ako se koristi 12 transformer blokova, pomnožite ovo sa 12.
>
> Štaviše, **normalizacija** sloj se dodaje **pre** **izlaza** i konačni linearni sloj se primenjuje na kraju kako bi se dobili rezultati sa odgovarajućim dimenzijama. Obratite pažnju kako svaki konačni vektor ima veličinu korišćenog rečnika. To je zato što pokušava da dobije verovatnoću po mogućem tokenu unutar rečnika.
@ -579,7 +579,7 @@ total_transformer_blocks_params = 7,085,568 * 12 = 85,026,816
**a. Final Layer Normalization**
- **Parameters:** `2 * emb_dim` (skala i pomeraj)
- **Parameters:** `2 * emb_dim` (scale and shift)
```python
pythonCopy codefinal_layer_norm_params = 2 * 768 = 1,536
```
@ -608,7 +608,7 @@ total_params = 163,009,536
```
## Generiši tekst
Imajući model koji predviđa sledeći token kao prethodni, potrebno je uzeti poslednje vrednosti tokena iz izlaza (jer će to biti vrednosti predviđenog tokena), što će biti **vrednost po unosu u rečniku** i zatim koristiti `softmax` funkciju da normalizuje dimenzije u verovatnoće koje se sabiraju na 1 i zatim dobiti indeks najvećeg unosa, koji će biti indeks reči unutar rečnika.
Imajući model koji predviđa sledeći token poput prethodnog, potrebno je samo uzeti poslednje vrednosti tokena iz izlaza (jer će to biti vrednosti predviđenog tokena), što će biti **vrednost po unosu u rečniku** i zatim koristiti `softmax` funkciju da normalizuje dimenzije u verovatnoće koje se sabiraju na 1 i zatim dobiti indeks najvećeg unosa, koji će biti indeks reči unutar rečnika.
Kod sa [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch04/01_main-chapter-code/ch04.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch04/01_main-chapter-code/ch04.ipynb):
```python
@ -661,6 +661,6 @@ context_size=GPT_CONFIG_124M["context_length"]
print("Output:", out)
print("Output length:", len(out[0]))
```
## Reference
## 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)

View File

@ -0,0 +1,943 @@
# 6. Pre-trening i učitavanje modela
## Generisanje teksta
Da bismo obučili model, potrebno je da taj model može da generiše nove tokene. Zatim ćemo uporediti generisane tokene sa očekivanim kako bismo obučili model da **nauči tokene koje treba da generiše**.
Kao u prethodnim primerima, već smo predvideli neke tokene, moguće je ponovo koristiti tu funkciju u tu svrhu.
> [!TIP]
> Cilj ove šeste faze je vrlo jednostavan: **Obučiti model od nule**. Za to će se koristiti prethodna LLM arhitektura sa nekim petljama koje prolaze kroz skupove podataka koristeći definisane funkcije gubitka i optimizator za obučavanje svih parametara modela.
## Evaluacija teksta
Da bismo izvršili ispravnu obuku, potrebno je izmeriti predikcije dobijene za očekivani token. Cilj obuke je maksimizovati verovatnoću ispravnog tokena, što podrazumeva povećanje njegove verovatnoće u odnosu na druge tokene.
Da bismo maksimizovali verovatnoću ispravnog tokena, težine modela moraju biti modifikovane tako da se ta verovatnoća maksimizuje. Ažuriranje težina se vrši putem **backpropagation**. Ovo zahteva **funkciju gubitka koju treba maksimizovati**. U ovom slučaju, funkcija će biti **razlika između izvršene predikcije i željene**.
Međutim, umesto da radimo sa sirovim predikcijama, radiće se sa logaritmom sa bazom n. Dakle, ako je trenutna predikcija očekivanog tokena bila 7.4541e-05, prirodni logaritam (baza *e*) od **7.4541e-05** je približno **-9.5042**.\
Zatim, za svaki unos sa dužinom konteksta od 5 tokena, na primer, model će morati da predvidi 5 tokena, pri čemu su prva 4 tokena poslednja od ulaza, a peti je predviđeni. Stoga, za svaki unos ćemo imati 5 predikcija u tom slučaju (čak i ako su prva 4 bila u ulazu, model to ne zna) sa 5 očekivanih tokena i stoga 5 verovatnoća koje treba maksimizovati.
Dakle, nakon izvršavanja prirodnog logaritma na svaku predikciju, izračunava se **prosek**, **minus simbol se uklanja** (to se zove _cross entropy loss_) i to je **broj koji treba smanjiti što bliže 0** jer je prirodni logaritam 1 jednak 0:
<figure><img src="../../images/image (10) (1).png" alt="" width="563"><figcaption><p><a href="https://camo.githubusercontent.com/3c0ab9c55cefa10b667f1014b6c42df901fa330bb2bc9cea88885e784daec8ba/68747470733a2f2f73656261737469616e72617363686b612e636f6d2f696d616765732f4c4c4d732d66726f6d2d736372617463682d696d616765732f636830355f636f6d707265737365642f63726f73732d656e74726f70792e776562703f313233">https://camo.githubusercontent.com/3c0ab9c55cefa10b667f1014b6c42df901fa330bb2bc9cea88885e784daec8ba/68747470733a2f2f73656261737469616e72617363686b612e636f6d2f696d616765732f4c4c4d732d66726f6d2d736372617463682d696d616765732f636830355f636f6d707265737365642f63726f73732d656e74726f70792e776562703f313233</a></p></figcaption></figure>
Drugi način da se izmeri koliko je model dobar zove se perplexity. **Perplexity** je metrika koja se koristi za procenu koliko dobro model verovatnoće predviđa uzorak. U modelovanju jezika, predstavlja **nesigurnost modela** prilikom predviđanja sledećeg tokena u nizu.\
Na primer, vrednost perplexity od 48725 znači da kada je potrebno predvideti token, model nije siguran koji od 48,725 tokena u rečniku je dobar.
## Primer pre-treninga
Ovo je inicijalni kod predložen u [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/01_main-chapter-code/ch05.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/01_main-chapter-code/ch05.ipynb) koji je ponekad malo modifikovan
<details>
<summary>Prethodni kod korišćen ovde, ali već objašnjen u prethodnim sekcijama</summary>
```python
"""
This is code explained before so it won't be exaplained
"""
import tiktoken
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
class GPTDatasetV1(Dataset):
def __init__(self, txt, tokenizer, max_length, stride):
self.input_ids = []
self.target_ids = []
# Tokenize the entire text
token_ids = tokenizer.encode(txt, allowed_special={"<|endoftext|>"})
# Use a sliding window to chunk the book into overlapping sequences of max_length
for i in range(0, len(token_ids) - max_length, stride):
input_chunk = token_ids[i:i + max_length]
target_chunk = token_ids[i + 1: i + max_length + 1]
self.input_ids.append(torch.tensor(input_chunk))
self.target_ids.append(torch.tensor(target_chunk))
def __len__(self):
return len(self.input_ids)
def __getitem__(self, idx):
return self.input_ids[idx], self.target_ids[idx]
def create_dataloader_v1(txt, batch_size=4, max_length=256,
stride=128, shuffle=True, drop_last=True, num_workers=0):
# Initialize the tokenizer
tokenizer = tiktoken.get_encoding("gpt2")
# Create dataset
dataset = GPTDatasetV1(txt, tokenizer, max_length, stride)
# Create dataloader
dataloader = DataLoader(
dataset, batch_size=batch_size, shuffle=shuffle, drop_last=drop_last, num_workers=num_workers)
return dataloader
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 n_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
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.reshape(b, num_tokens, self.d_out)
context_vec = self.out_proj(context_vec) # optional projection
return context_vec
class LayerNorm(nn.Module):
def __init__(self, emb_dim):
super().__init__()
self.eps = 1e-5
self.scale = nn.Parameter(torch.ones(emb_dim))
self.shift = nn.Parameter(torch.zeros(emb_dim))
def forward(self, x):
mean = x.mean(dim=-1, keepdim=True)
var = x.var(dim=-1, keepdim=True, unbiased=False)
norm_x = (x - mean) / torch.sqrt(var + self.eps)
return self.scale * norm_x + self.shift
class GELU(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return 0.5 * x * (1 + torch.tanh(
torch.sqrt(torch.tensor(2.0 / torch.pi)) *
(x + 0.044715 * torch.pow(x, 3))
))
class FeedForward(nn.Module):
def __init__(self, cfg):
super().__init__()
self.layers = nn.Sequential(
nn.Linear(cfg["emb_dim"], 4 * cfg["emb_dim"]),
GELU(),
nn.Linear(4 * cfg["emb_dim"], cfg["emb_dim"]),
)
def forward(self, x):
return self.layers(x)
class TransformerBlock(nn.Module):
def __init__(self, cfg):
super().__init__()
self.att = MultiHeadAttention(
d_in=cfg["emb_dim"],
d_out=cfg["emb_dim"],
context_length=cfg["context_length"],
num_heads=cfg["n_heads"],
dropout=cfg["drop_rate"],
qkv_bias=cfg["qkv_bias"])
self.ff = FeedForward(cfg)
self.norm1 = LayerNorm(cfg["emb_dim"])
self.norm2 = LayerNorm(cfg["emb_dim"])
self.drop_shortcut = nn.Dropout(cfg["drop_rate"])
def forward(self, x):
# Shortcut connection for attention block
shortcut = x
x = self.norm1(x)
x = self.att(x) # Shape [batch_size, num_tokens, emb_size]
x = self.drop_shortcut(x)
x = x + shortcut # Add the original input back
# Shortcut connection for feed-forward block
shortcut = x
x = self.norm2(x)
x = self.ff(x)
x = self.drop_shortcut(x)
x = x + shortcut # Add the original input back
return x
class GPTModel(nn.Module):
def __init__(self, cfg):
super().__init__()
self.tok_emb = nn.Embedding(cfg["vocab_size"], cfg["emb_dim"])
self.pos_emb = nn.Embedding(cfg["context_length"], cfg["emb_dim"])
self.drop_emb = nn.Dropout(cfg["drop_rate"])
self.trf_blocks = nn.Sequential(
*[TransformerBlock(cfg) for _ in range(cfg["n_layers"])])
self.final_norm = LayerNorm(cfg["emb_dim"])
self.out_head = nn.Linear(cfg["emb_dim"], cfg["vocab_size"], bias=False)
def forward(self, in_idx):
batch_size, seq_len = in_idx.shape
tok_embeds = self.tok_emb(in_idx)
pos_embeds = self.pos_emb(torch.arange(seq_len, device=in_idx.device))
x = tok_embeds + pos_embeds # Shape [batch_size, num_tokens, emb_size]
x = self.drop_emb(x)
x = self.trf_blocks(x)
x = self.final_norm(x)
logits = self.out_head(x)
return logits
```
</details>
```python
# Download contents to train the data with
import os
import urllib.request
file_path = "the-verdict.txt"
url = "https://raw.githubusercontent.com/rasbt/LLMs-from-scratch/main/ch02/01_main-chapter-code/the-verdict.txt"
if not os.path.exists(file_path):
with urllib.request.urlopen(url) as response:
text_data = response.read().decode('utf-8')
with open(file_path, "w", encoding="utf-8") as file:
file.write(text_data)
else:
with open(file_path, "r", encoding="utf-8") as file:
text_data = file.read()
total_characters = len(text_data)
tokenizer = tiktoken.get_encoding("gpt2")
total_tokens = len(tokenizer.encode(text_data))
print("Data downloaded")
print("Characters:", total_characters)
print("Tokens:", total_tokens)
# Model initialization
GPT_CONFIG_124M = {
"vocab_size": 50257, # Vocabulary size
"context_length": 256, # Shortened context length (orig: 1024)
"emb_dim": 768, # Embedding dimension
"n_heads": 12, # Number of attention heads
"n_layers": 12, # Number of layers
"drop_rate": 0.1, # Dropout rate
"qkv_bias": False # Query-key-value bias
}
torch.manual_seed(123)
model = GPTModel(GPT_CONFIG_124M)
model.eval()
print ("Model initialized")
# Functions to transform from tokens to ids and from to ids to tokens
def text_to_token_ids(text, tokenizer):
encoded = tokenizer.encode(text, allowed_special={'<|endoftext|>'})
encoded_tensor = torch.tensor(encoded).unsqueeze(0) # add batch dimension
return encoded_tensor
def token_ids_to_text(token_ids, tokenizer):
flat = token_ids.squeeze(0) # remove batch dimension
return tokenizer.decode(flat.tolist())
# Define loss functions
def calc_loss_batch(input_batch, target_batch, model, device):
input_batch, target_batch = input_batch.to(device), target_batch.to(device)
logits = model(input_batch)
loss = torch.nn.functional.cross_entropy(logits.flatten(0, 1), target_batch.flatten())
return loss
def calc_loss_loader(data_loader, model, device, num_batches=None):
total_loss = 0.
if len(data_loader) == 0:
return float("nan")
elif num_batches is None:
num_batches = len(data_loader)
else:
# Reduce the number of batches to match the total number of batches in the data loader
# if num_batches exceeds the number of batches in the data loader
num_batches = min(num_batches, len(data_loader))
for i, (input_batch, target_batch) in enumerate(data_loader):
if i < num_batches:
loss = calc_loss_batch(input_batch, target_batch, model, device)
total_loss += loss.item()
else:
break
return total_loss / num_batches
# Apply Train/validation ratio and create dataloaders
train_ratio = 0.90
split_idx = int(train_ratio * len(text_data))
train_data = text_data[:split_idx]
val_data = text_data[split_idx:]
torch.manual_seed(123)
train_loader = create_dataloader_v1(
train_data,
batch_size=2,
max_length=GPT_CONFIG_124M["context_length"],
stride=GPT_CONFIG_124M["context_length"],
drop_last=True,
shuffle=True,
num_workers=0
)
val_loader = create_dataloader_v1(
val_data,
batch_size=2,
max_length=GPT_CONFIG_124M["context_length"],
stride=GPT_CONFIG_124M["context_length"],
drop_last=False,
shuffle=False,
num_workers=0
)
# Sanity checks
if total_tokens * (train_ratio) < GPT_CONFIG_124M["context_length"]:
print("Not enough tokens for the training loader. "
"Try to lower the `GPT_CONFIG_124M['context_length']` or "
"increase the `training_ratio`")
if total_tokens * (1-train_ratio) < GPT_CONFIG_124M["context_length"]:
print("Not enough tokens for the validation loader. "
"Try to lower the `GPT_CONFIG_124M['context_length']` or "
"decrease the `training_ratio`")
print("Train loader:")
for x, y in train_loader:
print(x.shape, y.shape)
print("\nValidation loader:")
for x, y in val_loader:
print(x.shape, y.shape)
train_tokens = 0
for input_batch, target_batch in train_loader:
train_tokens += input_batch.numel()
val_tokens = 0
for input_batch, target_batch in val_loader:
val_tokens += input_batch.numel()
print("Training tokens:", train_tokens)
print("Validation tokens:", val_tokens)
print("All tokens:", train_tokens + val_tokens)
# Indicate the device to use
if torch.cuda.is_available():
device = torch.device("cuda")
elif torch.backends.mps.is_available():
device = torch.device("mps")
else:
device = torch.device("cpu")
print(f"Using {device} device.")
model.to(device) # no assignment model = model.to(device) necessary for nn.Module classes
# Pre-calculate losses without starting yet
torch.manual_seed(123) # For reproducibility due to the shuffling in the data loader
with torch.no_grad(): # Disable gradient tracking for efficiency because we are not training, yet
train_loss = calc_loss_loader(train_loader, model, device)
val_loss = calc_loss_loader(val_loader, model, device)
print("Training loss:", train_loss)
print("Validation loss:", val_loss)
# Functions to train the data
def train_model_simple(model, train_loader, val_loader, optimizer, device, num_epochs,
eval_freq, eval_iter, start_context, tokenizer):
# Initialize lists to track losses and tokens seen
train_losses, val_losses, track_tokens_seen = [], [], []
tokens_seen, global_step = 0, -1
# Main training loop
for epoch in range(num_epochs):
model.train() # Set model to training mode
for input_batch, target_batch in train_loader:
optimizer.zero_grad() # Reset loss gradients from previous batch iteration
loss = calc_loss_batch(input_batch, target_batch, model, device)
loss.backward() # Calculate loss gradients
optimizer.step() # Update model weights using loss gradients
tokens_seen += input_batch.numel()
global_step += 1
# Optional evaluation step
if global_step % eval_freq == 0:
train_loss, val_loss = evaluate_model(
model, train_loader, val_loader, device, eval_iter)
train_losses.append(train_loss)
val_losses.append(val_loss)
track_tokens_seen.append(tokens_seen)
print(f"Ep {epoch+1} (Step {global_step:06d}): "
f"Train loss {train_loss:.3f}, Val loss {val_loss:.3f}")
# Print a sample text after each epoch
generate_and_print_sample(
model, tokenizer, device, start_context
)
return train_losses, val_losses, track_tokens_seen
def evaluate_model(model, train_loader, val_loader, device, eval_iter):
model.eval()
with torch.no_grad():
train_loss = calc_loss_loader(train_loader, model, device, num_batches=eval_iter)
val_loss = calc_loss_loader(val_loader, model, device, num_batches=eval_iter)
model.train()
return train_loss, val_loss
def generate_and_print_sample(model, tokenizer, device, start_context):
model.eval()
context_size = model.pos_emb.weight.shape[0]
encoded = text_to_token_ids(start_context, tokenizer).to(device)
with torch.no_grad():
token_ids = generate_text(
model=model, idx=encoded,
max_new_tokens=50, context_size=context_size
)
decoded_text = token_ids_to_text(token_ids, tokenizer)
print(decoded_text.replace("\n", " ")) # Compact print format
model.train()
# Start training!
import time
start_time = time.time()
torch.manual_seed(123)
model = GPTModel(GPT_CONFIG_124M)
model.to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=0.0004, weight_decay=0.1)
num_epochs = 10
train_losses, val_losses, tokens_seen = train_model_simple(
model, train_loader, val_loader, optimizer, device,
num_epochs=num_epochs, eval_freq=5, eval_iter=5,
start_context="Every effort moves you", tokenizer=tokenizer
)
end_time = time.time()
execution_time_minutes = (end_time - start_time) / 60
print(f"Training completed in {execution_time_minutes:.2f} minutes.")
# Show graphics with the training process
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
import math
def plot_losses(epochs_seen, tokens_seen, train_losses, val_losses):
fig, ax1 = plt.subplots(figsize=(5, 3))
ax1.plot(epochs_seen, train_losses, label="Training loss")
ax1.plot(
epochs_seen, val_losses, linestyle="-.", label="Validation loss"
)
ax1.set_xlabel("Epochs")
ax1.set_ylabel("Loss")
ax1.legend(loc="upper right")
ax1.xaxis.set_major_locator(MaxNLocator(integer=True))
ax2 = ax1.twiny()
ax2.plot(tokens_seen, train_losses, alpha=0)
ax2.set_xlabel("Tokens seen")
fig.tight_layout()
plt.show()
# Compute perplexity from the loss values
train_ppls = [math.exp(loss) for loss in train_losses]
val_ppls = [math.exp(loss) for loss in val_losses]
# Plot perplexity over tokens seen
plt.figure()
plt.plot(tokens_seen, train_ppls, label='Training Perplexity')
plt.plot(tokens_seen, val_ppls, label='Validation Perplexity')
plt.xlabel('Tokens Seen')
plt.ylabel('Perplexity')
plt.title('Perplexity over Training')
plt.legend()
plt.show()
epochs_tensor = torch.linspace(0, num_epochs, len(train_losses))
plot_losses(epochs_tensor, tokens_seen, train_losses, val_losses)
torch.save({
"model_state_dict": model.state_dict(),
"optimizer_state_dict": optimizer.state_dict(),
},
"/tmp/model_and_optimizer.pth"
)
```
Hajde da vidimo objašnjenje korak po korak
### Funkcije za transformaciju teksta <--> id-ova
Ovo su neke jednostavne funkcije koje se mogu koristiti za transformaciju teksta iz rečnika u id-ove i obrnuto. Ovo je potrebno na početku obrade teksta i na kraju predikcija:
```python
# Functions to transform from tokens to ids and from to ids to tokens
def text_to_token_ids(text, tokenizer):
encoded = tokenizer.encode(text, allowed_special={'<|endoftext|>'})
encoded_tensor = torch.tensor(encoded).unsqueeze(0) # add batch dimension
return encoded_tensor
def token_ids_to_text(token_ids, tokenizer):
flat = token_ids.squeeze(0) # remove batch dimension
return tokenizer.decode(flat.tolist())
```
### Generiši funkcije za tekst
U prethodnom odeljku funkcija je samo uzela **najverovatniji token** nakon dobijanja logita. Međutim, to će značiti da će za svaki unos uvek biti generisan isti izlaz, što ga čini veoma determinističkim.
Sledeća `generate_text` funkcija će primeniti koncepte `top-k`, `temperature` i `multinomial`.
- **`top-k`** znači da ćemo početi da smanjujemo na `-inf` sve verovatnoće svih tokena osim za top k tokena. Dakle, ako je k=3, pre donošenja odluke samo će 3 najverovatnija tokena imati verovatnoću različitu od `-inf`.
- **`temperature`** znači da će svaka verovatnoća biti podeljena sa vrednošću temperature. Vrednost od `0.1` će poboljšati najvišu verovatnoću u poređenju sa najnižom, dok će temperatura od `5`, na primer, učiniti da bude ravnija. Ovo pomaže da se poboljša varijacija u odgovorima koje bismo želeli da LLM ima.
- Nakon primene temperature, funkcija **`softmax`** se ponovo primenjuje da bi svi preostali tokeni imali ukupnu verovatnoću od 1.
- Na kraju, umesto da se bira token sa najvećom verovatnoćom, funkcija **`multinomial`** se primenjuje da **predvidi sledeći token prema konačnim verovatnoćama**. Dakle, ako je token 1 imao 70% verovatnoće, token 2 20% i token 3 10%, 70% vremena biće izabran token 1, 20% vremena biće token 2, a 10% vremena biće token 3.
```python
# Generate text function
def generate_text(model, idx, max_new_tokens, context_size, temperature=0.0, top_k=None, eos_id=None):
# For-loop is the same as before: Get logits, and only focus on last time step
for _ in range(max_new_tokens):
idx_cond = idx[:, -context_size:]
with torch.no_grad():
logits = model(idx_cond)
logits = logits[:, -1, :]
# New: Filter logits with top_k sampling
if top_k is not None:
# Keep only top_k values
top_logits, _ = torch.topk(logits, top_k)
min_val = top_logits[:, -1]
logits = torch.where(logits < min_val, torch.tensor(float("-inf")).to(logits.device), logits)
# New: Apply temperature scaling
if temperature > 0.0:
logits = logits / temperature
# Apply softmax to get probabilities
probs = torch.softmax(logits, dim=-1) # (batch_size, context_len)
# Sample from the distribution
idx_next = torch.multinomial(probs, num_samples=1) # (batch_size, 1)
# Otherwise same as before: get idx of the vocab entry with the highest logits value
else:
idx_next = torch.argmax(logits, dim=-1, keepdim=True) # (batch_size, 1)
if idx_next == eos_id: # Stop generating early if end-of-sequence token is encountered and eos_id is specified
break
# Same as before: append sampled index to the running sequence
idx = torch.cat((idx, idx_next), dim=1) # (batch_size, num_tokens+1)
return idx
```
> [!TIP]
> Postoji uobičajena alternativa za `top-k` pod nazivom [**`top-p`**](https://en.wikipedia.org/wiki/Top-p_sampling), takođe poznata kao uzorkovanje jezgra, koja umesto da uzima k uzoraka sa najvećom verovatnoćom, **organizuje** sav rezultatni **rečnik** prema verovatnoćama i **sabira** ih od najveće verovatnoće do najniže dok se ne **postigne prag**.
>
> Tada će se **samo te reči** iz rečnika uzeti u obzir prema njihovim relativnim verovatnoćama.
>
> Ovo omogućava da ne bude potrebno odabrati broj `k` uzoraka, jer optimalni k može biti različit u svakom slučaju, već **samo prag**.
>
> _Napomena da ovo poboljšanje nije uključeno u prethodni kod._
> [!TIP]
> Drugi način da se poboljša generisani tekst je korišćenjem **Beam search** umesto pohlepnog pretraživanja korišćenog u ovom primeru.\
> Za razliku od pohlepnog pretraživanja, koje bira najverovatniju sledeću reč u svakom koraku i gradi jednu sekvencu, **beam search prati top 𝑘 k najviših delimičnih sekvenci** (nazvanih "beams") u svakom koraku. Istražujući više mogućnosti istovremeno, balansira efikasnost i kvalitet, povećavajući šanse za **pronalazak bolje ukupne** sekvence koja bi mogla biti propuštena pohlepnim pristupom zbog ranih, suboptimalnih izbora.
>
> _Napomena da ovo poboljšanje nije uključeno u prethodni kod._
### Funkcije gubitka
Funkcija **`calc_loss_batch`** izračunava unakrsnu entropiju predikcije jednog paketa.\
Funkcija **`calc_loss_loader`** dobija unakrsnu entropiju svih paketa i izračunava **prosečnu unakrsnu entropiju**.
```python
# Define loss functions
def calc_loss_batch(input_batch, target_batch, model, device):
input_batch, target_batch = input_batch.to(device), target_batch.to(device)
logits = model(input_batch)
loss = torch.nn.functional.cross_entropy(logits.flatten(0, 1), target_batch.flatten())
return loss
def calc_loss_loader(data_loader, model, device, num_batches=None):
total_loss = 0.
if len(data_loader) == 0:
return float("nan")
elif num_batches is None:
num_batches = len(data_loader)
else:
# Reduce the number of batches to match the total number of batches in the data loader
# if num_batches exceeds the number of batches in the data loader
num_batches = min(num_batches, len(data_loader))
for i, (input_batch, target_batch) in enumerate(data_loader):
if i < num_batches:
loss = calc_loss_batch(input_batch, target_batch, model, device)
total_loss += loss.item()
else:
break
return total_loss / num_batches
```
> [!TIP]
> **Gradient clipping** je tehnika koja se koristi za poboljšanje **stabilnosti obuke** u velikim neuronskim mrežama postavljanjem **maksimalnog praga** za magnitudu gradijenata. Kada gradijenti premaše ovaj unapred definisani `max_norm`, smanjuju se proporcionalno kako bi se osiguralo da ažuriranja parametara modela ostanu unutar upravljivog opsega, sprečavajući probleme poput eksplodirajućih gradijenata i obezbeđujući kontrolisaniju i stabilniju obuku.
>
> _Napomena da ovo poboljšanje nije uključeno u prethodni kod._
>
> Proverite sledeći primer:
<figure><img src="../../images/image (6) (1).png" alt=""><figcaption></figcaption></figure>
### Učitavanje podataka
Funkcije `create_dataloader_v1` i `create_dataloader_v1` su već raspravljane u prethodnom odeljku.
Odavde primetite kako je definisano da će 90% teksta biti korišćeno za obuku dok će 10% biti korišćeno za validaciju i oba skupa su smeštena u 2 različita učitavača podataka.\
Napomena da je ponekad deo skupa podataka takođe ostavljen za testni skup kako bi se bolje procenila performansa modela.
Oba učitavača podataka koriste istu veličinu serije, maksimalnu dužinu i korak i broj radnika (0 u ovom slučaju).\
Glavne razlike su u podacima koje koristi svaki, a validatori ne odbacuju poslednji niti mešaju podatke jer to nije potrebno za svrhe validacije.
Takođe, činjenica da je **korak jednak dužini konteksta**, znači da neće biti preklapanja između konteksta korišćenih za obuku podataka (smanjuje prekomerno prilagođavanje, ali i skup podataka za obuku).
Štaviše, primetite da je veličina serije u ovom slučaju 2 kako bi se podelili podaci u 2 serije, glavni cilj ovoga je omogućiti paralelnu obradu i smanjiti potrošnju po seriji.
```python
train_ratio = 0.90
split_idx = int(train_ratio * len(text_data))
train_data = text_data[:split_idx]
val_data = text_data[split_idx:]
torch.manual_seed(123)
train_loader = create_dataloader_v1(
train_data,
batch_size=2,
max_length=GPT_CONFIG_124M["context_length"],
stride=GPT_CONFIG_124M["context_length"],
drop_last=True,
shuffle=True,
num_workers=0
)
val_loader = create_dataloader_v1(
val_data,
batch_size=2,
max_length=GPT_CONFIG_124M["context_length"],
stride=GPT_CONFIG_124M["context_length"],
drop_last=False,
shuffle=False,
num_workers=0
)
```
## Provere ispravnosti
Cilj je proveriti da li ima dovoljno tokena za obuku, da li su oblici očekivani i dobiti neke informacije o broju tokena korišćenih za obuku i za validaciju:
```python
# Sanity checks
if total_tokens * (train_ratio) < GPT_CONFIG_124M["context_length"]:
print("Not enough tokens for the training loader. "
"Try to lower the `GPT_CONFIG_124M['context_length']` or "
"increase the `training_ratio`")
if total_tokens * (1-train_ratio) < GPT_CONFIG_124M["context_length"]:
print("Not enough tokens for the validation loader. "
"Try to lower the `GPT_CONFIG_124M['context_length']` or "
"decrease the `training_ratio`")
print("Train loader:")
for x, y in train_loader:
print(x.shape, y.shape)
print("\nValidation loader:")
for x, y in val_loader:
print(x.shape, y.shape)
train_tokens = 0
for input_batch, target_batch in train_loader:
train_tokens += input_batch.numel()
val_tokens = 0
for input_batch, target_batch in val_loader:
val_tokens += input_batch.numel()
print("Training tokens:", train_tokens)
print("Validation tokens:", val_tokens)
print("All tokens:", train_tokens + val_tokens)
```
### Izbor uređaja za obuku i prethodne proračune
Sledeći kod samo bira uređaj koji će se koristiti i izračunava gubitak obuke i gubitak validacije (bez da je još bilo šta obučeno) kao početnu tačku.
```python
# Indicate the device to use
if torch.cuda.is_available():
device = torch.device("cuda")
elif torch.backends.mps.is_available():
device = torch.device("mps")
else:
device = torch.device("cpu")
print(f"Using {device} device.")
model.to(device) # no assignment model = model.to(device) necessary for nn.Module classes
# Pre-calculate losses without starting yet
torch.manual_seed(123) # For reproducibility due to the shuffling in the data loader
with torch.no_grad(): # Disable gradient tracking for efficiency because we are not training, yet
train_loss = calc_loss_loader(train_loader, model, device)
val_loss = calc_loss_loader(val_loader, model, device)
print("Training loss:", train_loss)
print("Validation loss:", val_loss)
```
### Funkcije obuke
Funkcija `generate_and_print_sample` će samo uzeti kontekst i generisati neke tokene kako bi se stekao osećaj o tome koliko je model dobar u tom trenutku. Ovo se poziva iz `train_model_simple` na svakom koraku.
Funkcija `evaluate_model` se poziva onoliko često koliko je naznačeno u funkciji obuke i koristi se za merenje gubitka tokom obuke i gubitka validacije u tom trenutku obuke modela.
Zatim, velika funkcija `train_model_simple` je ta koja zapravo obučava model. Očekuje:
- Učitavač podataka za obuku (sa podacima već odvojenim i pripremljenim za obuku)
- Učitavač validacije
- **optimizator** koji će se koristiti tokom obuke: Ovo je funkcija koja će koristiti gradijente i ažurirati parametre kako bi smanjila gubitak. U ovom slučaju, kao što ćete videti, koristi se `AdamW`, ali ima mnogo drugih.
- `optimizer.zero_grad()` se poziva da resetuje gradijente na svakoj rundi kako bi ih akumulacija bila sprečena.
- **`lr`** parametar je **stopa učenja** koja određuje **veličinu koraka** koji se preduzimaju tokom procesa optimizacije prilikom ažuriranja parametara modela. **Manja** stopa učenja znači da optimizator **vrši manje ažuriranja** težina, što može dovesti do **preciznijeg** konvergiranja, ali može **usporiti** obuku. **Veća** stopa učenja može ubrzati obuku, ali **rizikuje prekomerno** prelazak minimuma funkcije gubitka (**preskoči** tačku gde je funkcija gubitka minimizovana).
- **Weight Decay** modifikuje korak **Izračunavanja Gubitka** dodavanjem dodatnog člana koji kažnjava velike težine. Ovo podstiče optimizator da pronađe rešenja sa manjim težinama, balansirajući između dobrog prilagođavanja podacima i održavanja modela jednostavnim, sprečavajući prekomerno prilagođavanje u modelima mašinskog učenja tako što obeshrabruje model da dodeljuje preveliku važnost bilo kojoj pojedinačnoj karakteristici.
- Tradicionalni optimizatori poput SGD sa L2 regularizacijom povezuju weight decay sa gradijentom funkcije gubitka. Međutim, **AdamW** (varijanta Adam optimizatora) odvaja weight decay od ažuriranja gradijenta, što dovodi do efikasnije regularizacije.
- Uređaj koji će se koristiti za obuku
- Broj epoha: Broj puta da se prođe kroz podatke za obuku
- Učestalost evaluacije: Učestalost pozivanja `evaluate_model`
- Iteracija evaluacije: Broj serija koje će se koristiti prilikom evaluacije trenutnog stanja modela kada se poziva `generate_and_print_sample`
- Početni kontekst: Koja rečenica će se koristiti prilikom pozivanja `generate_and_print_sample`
- Tokenizer
```python
# Functions to train the data
def train_model_simple(model, train_loader, val_loader, optimizer, device, num_epochs,
eval_freq, eval_iter, start_context, tokenizer):
# Initialize lists to track losses and tokens seen
train_losses, val_losses, track_tokens_seen = [], [], []
tokens_seen, global_step = 0, -1
# Main training loop
for epoch in range(num_epochs):
model.train() # Set model to training mode
for input_batch, target_batch in train_loader:
optimizer.zero_grad() # Reset loss gradients from previous batch iteration
loss = calc_loss_batch(input_batch, target_batch, model, device)
loss.backward() # Calculate loss gradients
optimizer.step() # Update model weights using loss gradients
tokens_seen += input_batch.numel()
global_step += 1
# Optional evaluation step
if global_step % eval_freq == 0:
train_loss, val_loss = evaluate_model(
model, train_loader, val_loader, device, eval_iter)
train_losses.append(train_loss)
val_losses.append(val_loss)
track_tokens_seen.append(tokens_seen)
print(f"Ep {epoch+1} (Step {global_step:06d}): "
f"Train loss {train_loss:.3f}, Val loss {val_loss:.3f}")
# Print a sample text after each epoch
generate_and_print_sample(
model, tokenizer, device, start_context
)
return train_losses, val_losses, track_tokens_seen
def evaluate_model(model, train_loader, val_loader, device, eval_iter):
model.eval() # Set in eval mode to avoid dropout
with torch.no_grad():
train_loss = calc_loss_loader(train_loader, model, device, num_batches=eval_iter)
val_loss = calc_loss_loader(val_loader, model, device, num_batches=eval_iter)
model.train() # Back to training model applying all the configurations
return train_loss, val_loss
def generate_and_print_sample(model, tokenizer, device, start_context):
model.eval() # Set in eval mode to avoid dropout
context_size = model.pos_emb.weight.shape[0]
encoded = text_to_token_ids(start_context, tokenizer).to(device)
with torch.no_grad():
token_ids = generate_text(
model=model, idx=encoded,
max_new_tokens=50, context_size=context_size
)
decoded_text = token_ids_to_text(token_ids, tokenizer)
print(decoded_text.replace("\n", " ")) # Compact print format
model.train() # Back to training model applying all the configurations
```
> [!TIP]
> Da biste poboljšali brzinu učenja, postoji nekoliko relevantnih tehnika pod nazivom **linear warmup** i **cosine decay.**
>
> **Linear warmup** se sastoji od definisanja inicijalne brzine učenja i maksimalne brzine, i doslednog ažuriranja nakon svake epohe. To je zato što započinjanje obuke sa manjim ažuriranjima težina smanjuje rizik da model naiđe na velike, destabilizujuće ažuriranja tokom svoje faze obuke.\
> **Cosine decay** je tehnika koja **postepeno smanjuje brzinu učenja** prateći polu-kosinusnu krivu **nakon faze zagrevanja**, usporavajući ažuriranja težina kako bi **minimizovala rizik od prekomernog skakanja** ispod minimuma gubitka i osigurala stabilnost obuke u kasnijim fazama.
>
> _Napomena da ova poboljšanja nisu uključena u prethodni kod._
### Start training
```python
import time
start_time = time.time()
torch.manual_seed(123)
model = GPTModel(GPT_CONFIG_124M)
model.to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=0.0004, weight_decay=0.1)
num_epochs = 10
train_losses, val_losses, tokens_seen = train_model_simple(
model, train_loader, val_loader, optimizer, device,
num_epochs=num_epochs, eval_freq=5, eval_iter=5,
start_context="Every effort moves you", tokenizer=tokenizer
)
end_time = time.time()
execution_time_minutes = (end_time - start_time) / 60
print(f"Training completed in {execution_time_minutes:.2f} minutes.")
```
### Print training evolution
Sa sledećom funkcijom je moguće štampati evoluciju modela dok je bio obučavan.
```python
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
import math
def plot_losses(epochs_seen, tokens_seen, train_losses, val_losses):
fig, ax1 = plt.subplots(figsize=(5, 3))
ax1.plot(epochs_seen, train_losses, label="Training loss")
ax1.plot(
epochs_seen, val_losses, linestyle="-.", label="Validation loss"
)
ax1.set_xlabel("Epochs")
ax1.set_ylabel("Loss")
ax1.legend(loc="upper right")
ax1.xaxis.set_major_locator(MaxNLocator(integer=True))
ax2 = ax1.twiny()
ax2.plot(tokens_seen, train_losses, alpha=0)
ax2.set_xlabel("Tokens seen")
fig.tight_layout()
plt.show()
# Compute perplexity from the loss values
train_ppls = [math.exp(loss) for loss in train_losses]
val_ppls = [math.exp(loss) for loss in val_losses]
# Plot perplexity over tokens seen
plt.figure()
plt.plot(tokens_seen, train_ppls, label='Training Perplexity')
plt.plot(tokens_seen, val_ppls, label='Validation Perplexity')
plt.xlabel('Tokens Seen')
plt.ylabel('Perplexity')
plt.title('Perplexity over Training')
plt.legend()
plt.show()
epochs_tensor = torch.linspace(0, num_epochs, len(train_losses))
plot_losses(epochs_tensor, tokens_seen, train_losses, val_losses)
```
### Sačuvajte model
Moguće je sačuvati model + optimizator ako želite da nastavite obuku kasnije:
```python
# Save the model and the optimizer for later training
torch.save({
"model_state_dict": model.state_dict(),
"optimizer_state_dict": optimizer.state_dict(),
},
"/tmp/model_and_optimizer.pth"
)
# Note that this model with the optimizer occupied close to 2GB
# Restore model and optimizer for training
checkpoint = torch.load("/tmp/model_and_optimizer.pth", map_location=device)
model = GPTModel(GPT_CONFIG_124M)
model.load_state_dict(checkpoint["model_state_dict"])
optimizer = torch.optim.AdamW(model.parameters(), lr=5e-4, weight_decay=0.1)
optimizer.load_state_dict(checkpoint["optimizer_state_dict"])
model.train(); # Put in training mode
```
Ili samo model ako planirate da ga koristite:
```python
# Save the model
torch.save(model.state_dict(), "model.pth")
# Load it
model = GPTModel(GPT_CONFIG_124M)
model.load_state_dict(torch.load("model.pth", map_location=device))
model.eval() # Put in eval mode
```
## Učitavanje GPT2 težina
Postoje 2 brza skripta za lokalno učitavanje GPT2 težina. Za oba možete lokalno klonirati repozitorij [https://github.com/rasbt/LLMs-from-scratch](https://github.com/rasbt/LLMs-from-scratch), zatim:
- Skripta [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/01_main-chapter-code/gpt_generate.py](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/01_main-chapter-code/gpt_generate.py) će preuzeti sve težine i transformisati formate iz OpenAI u one koje očekuje naš LLM. Skripta je takođe pripremljena sa potrebnom konfiguracijom i sa promptom: "Svaki napor vas pokreće"
- Skripta [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/02_alternative_weight_loading/weight-loading-hf-transformers.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/02_alternative_weight_loading/weight-loading-hf-transformers.ipynb) vam omogućava da lokalno učitate bilo koje od GPT2 težina (samo promenite varijablu `CHOOSE_MODEL`) i predviđate tekst iz nekih prompta.
## Reference
- [https://www.manning.com/books/build-a-large-language-model-from-scratch](https://www.manning.com/books/build-a-large-language-model-from-scratch)

View File

@ -13,11 +13,11 @@ LoRA omogućava efikasno fino podešavanje **velikih modela** menjajući samo **
<figure><img src="../../images/image (9) (1).png" alt=""><figcaption></figcaption></figure>
2. **Održava originalne težine modela nepromenjenim**: LoRA vam omogućava da zadržite originalne težine modela iste, i samo ažurirate **nove male matrice** (A i B). To je korisno jer znači da je originalno znanje modela očuvano, a vi samo prilagođavate ono što je neophodno.
2. **Održava originalne težine modela nepromenjenim**: LoRA vam omogućava da zadržite originalne težine modela iste, i samo ažurirate **nove male matrice** (A i B). To je korisno jer znači da je originalno znanje modela očuvano, a vi samo prilagođavate ono što je potrebno.
3. **Efikasno fino podešavanje specifično za zadatak**: Kada želite da prilagodite model za **novi zadatak**, možete samo obučiti **male LoRA matrice** (A i B) dok ostavljate ostatak modela nepromenjenim. To je **mnogo efikasnije** od ponovne obuke celog modela.
4. **Efikasnost skladištenja**: Nakon finog podešavanja, umesto da čuvate **novi model** za svaki zadatak, potrebno je da sačuvate samo **LoRA matrice**, koje su veoma male u poređenju sa celim modelom. To olakšava prilagođavanje modela mnogim zadacima bez prekomernog korišćenja skladišta.
4. **Efikasnost skladištenja**: Nakon finog podešavanja, umesto da čuvate **novi model** za svaki zadatak, potrebno je da sačuvate samo **LoRA matrice**, koje su vrlo male u poređenju sa celim modelom. To olakšava prilagođavanje modela mnogim zadacima bez prekomernog korišćenja skladišta.
Da biste implementirali LoraLayers umesto Linear slojeva tokom finog podešavanja, ovde je predložen ovaj kod [https://github.com/rasbt/LLMs-from-scratch/blob/main/appendix-E/01_main-chapter-code/appendix-E.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/appendix-E/01_main-chapter-code/appendix-E.ipynb):
Da biste implementirali LoraLayers umesto Linearnih tokom finog podešavanja, ovde je predložen ovaj kod [https://github.com/rasbt/LLMs-from-scratch/blob/main/appendix-E/01_main-chapter-code/appendix-E.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/appendix-E/01_main-chapter-code/appendix-E.ipynb):
```python
import math

View File

@ -0,0 +1,110 @@
# 7.1. Fine-Tuning for Classification
## Šta je
Fine-tuning je proces uzimanja **pre-treniranog modela** koji je naučio **opšte jezičke obrasce** iz ogromnih količina podataka i **prilagođavanja** da izvrši **specifičan zadatak** ili da razume jezik specifičan za domen. To se postiže nastavkom obuke modela na manjem, zadatku specifičnom skupu podataka, omogućavajući mu da prilagodi svoje parametre kako bi bolje odgovarao nijansama novih podataka, dok koristi široko znanje koje je već stekao. Fine-tuning omogućava modelu da pruži tačnije i relevantnije rezultate u specijalizovanim aplikacijama bez potrebe za obukom novog modela od nule.
> [!TIP]
> Kako je pre-obuka LLM-a koji "razume" tekst prilično skupa, obično je lakše i jeftinije fine-tunovati otvorene pre-trenirane modele da izvrše specifičan zadatak koji želimo da obave.
> [!TIP]
> Cilj ovog odeljka je da pokaže kako fine-tunovati već pre-trenirani model tako da umesto generisanja novog teksta LLM daje **verovatnoće da je dati tekst kategorizovan u svaku od datih kategorija** (kao što je da li je tekst spam ili ne).
## Priprema skupa podataka
### Veličina skupa podataka
Naravno, da biste fine-tunovali model, potrebni su vam neki strukturirani podaci koje ćete koristiti za specijalizaciju vašeg LLM-a. U primeru predloženom u [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/ch06.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/ch06.ipynb), GPT2 je fine-tunovan da detektuje da li je email spam ili ne koristeći podatke iz [https://archive.ics.uci.edu/static/public/228/sms+spam+collection.zip](https://archive.ics.uci.edu/static/public/228/sms+spam+collection.zip)_._
Ovaj skup podataka sadrži mnogo više primera "ne spam" nego "spam", stoga knjiga sugeriše da se **koristi samo onoliko primera "ne spam" koliko i "spam"** (uklanjajući sve dodatne primere iz obuke). U ovom slučaju, to je bilo 747 primera svakog.
Zatim, **70%** skupa podataka se koristi za **obuku**, **10%** za **validaciju** i **20%** za **testiranje**.
- **Validacioni skup** se koristi tokom faze obuke za fine-tuning **hiperparametara** modela i donošenje odluka o arhitekturi modela, efikasno pomažući u sprečavanju prekomernog prilagođavanja pružanjem povratnih informacija o tome kako model funkcioniše na neviđenim podacima. Omogućava iterativna poboljšanja bez pristrasnosti konačnoj evaluaciji.
- To znači da iako se podaci uključeni u ovaj skup podataka ne koriste direktno za obuku, koriste se za podešavanje najboljih **hiperparametara**, tako da se ovaj skup ne može koristiti za evaluaciju performansi modela kao testni.
- Nasuprot tome, **testni skup** se koristi **samo nakon** što je model potpuno obučen i svi podešavanja su završena; pruža nepristrasnu procenu sposobnosti modela da generalizuje na nove, neviđene podatke. Ova konačna evaluacija na testnom skupu daje realističnu indikaciju kako se očekuje da model funkcioniše u stvarnim aplikacijama.
### Dužina unosa
Kako primer obuke očekuje unose (tekstove emaila u ovom slučaju) iste dužine, odlučeno je da se svaki unos napravi što je moguće dužim dodavanjem id-ova `<|endoftext|>` kao popune.
### Inicijalizacija modela
Koristeći otvorene pre-trenirane težine, inicijalizujte model za obuku. Ovo smo već uradili ranije i prateći uputstva iz [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/ch06.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/ch06.ipynb) možete to lako uraditi.
## Klasa za klasifikaciju
U ovom specifičnom primeru (predviđanje da li je tekst spam ili ne), nismo zainteresovani za fine-tuning prema kompletnom rečniku GPT2, već samo želimo da novi model kaže da li je email spam (1) ili ne (0). Stoga, planiramo da **modifikujemo završni sloj koji** daje verovatnoće po tokenu rečnika za onaj koji daje samo verovatnoće da li je spam ili ne (tako da kao rečnik od 2 reči).
```python
# This code modified the final layer with a Linear one with 2 outs
num_classes = 2
model.out_head = torch.nn.Linear(
in_features=BASE_CONFIG["emb_dim"],
out_features=num_classes
)
```
## Parametri za podešavanje
Da bi se brzo izvršilo fino podešavanje, lakše je ne podešavati sve parametre, već samo neke konačne. To je zato što je poznato da niži slojevi obično hvataju osnovne jezičke strukture i primenljive semantike. Dakle, samo **fino podešavanje poslednjih slojeva je obično dovoljno i brže**.
```python
# This code makes all the parameters of the model unrtainable
for param in model.parameters():
param.requires_grad = False
# Allow to fine tune the last layer in the transformer block
for param in model.trf_blocks[-1].parameters():
param.requires_grad = True
# Allow to fine tune the final layer norm
for param in model.final_norm.parameters():
param.requires_grad = True
```
## Unosi za obuku
U prethodnim sekcijama LLM je treniran smanjujući gubitak svakog predviđenog tokena, iako su gotovo svi predviđeni tokeni bili u ulaznoj rečenici (samo je jedan na kraju zaista predviđen) kako bi model bolje razumeo jezik.
U ovom slučaju nam je samo bitno da model može da predvidi da li je model spam ili ne, tako da nam je važan samo poslednji predviđeni token. Stoga, potrebno je modifikovati naše prethodne funkcije gubitka obuke da uzimaju u obzir samo taj token.
Ovo je implementirano u [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/ch06.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/ch06.ipynb) kao:
```python
def calc_accuracy_loader(data_loader, model, device, num_batches=None):
model.eval()
correct_predictions, num_examples = 0, 0
if num_batches is None:
num_batches = len(data_loader)
else:
num_batches = min(num_batches, len(data_loader))
for i, (input_batch, target_batch) in enumerate(data_loader):
if i < num_batches:
input_batch, target_batch = input_batch.to(device), target_batch.to(device)
with torch.no_grad():
logits = model(input_batch)[:, -1, :] # Logits of last output token
predicted_labels = torch.argmax(logits, dim=-1)
num_examples += predicted_labels.shape[0]
correct_predictions += (predicted_labels == target_batch).sum().item()
else:
break
return correct_predictions / num_examples
def calc_loss_batch(input_batch, target_batch, model, device):
input_batch, target_batch = input_batch.to(device), target_batch.to(device)
logits = model(input_batch)[:, -1, :] # Logits of last output token
loss = torch.nn.functional.cross_entropy(logits, target_batch)
return loss
```
Napomena kako nas za svaku seriju zanimaju samo **logiti poslednjeg predviđenog tokena**.
## Kompletan kod za fine-tuning GPT2 klasifikatora
Možete pronaći sav kod za fine-tuning GPT2 da bude klasifikator za spam na [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/load-finetuned-model.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch06/01_main-chapter-code/load-finetuned-model.ipynb)
## Reference
- [https://www.manning.com/books/build-a-large-language-model-from-scratch](https://www.manning.com/books/build-a-large-language-model-from-scratch)

View File

@ -1,7 +1,7 @@
# 7.2. Podešavanje za praćenje uputstava
> [!TIP]
> Cilj ovog odeljka je da pokaže kako **podešavati već unapred obučeni model da prati uputstva** umesto da samo generiše tekst, na primer, odgovarajući na zadatke kao chat bot.
> Cilj ovog odeljka je da pokaže kako da **podešavate već unapred obučeni model da prati uputstva** umesto da samo generiše tekst, na primer, odgovarajući na zadatke kao chat bot.
## Skup podataka
@ -80,9 +80,9 @@ Drugi test koji treba izvršiti da bi se proverio kvalitet odgovora:
1. **Measuring Massive Multitask Language Understanding (**[**MMLU**](https://arxiv.org/abs/2009.03300)**):** MMLU procenjuje znanje modela i sposobnosti rešavanja problema u 57 predmeta, uključujući humanističke nauke, nauke i još mnogo toga. Koristi višekratna pitanja za procenu razumevanja na različitim nivoima težine, od osnovnog do naprednog profesionalnog.
2. [**LMSYS Chatbot Arena**](https://arena.lmsys.org): Ova platforma omogućava korisnicima da uporede odgovore različitih chatbota jedan pored drugog. Korisnici unose prompt, a više chatbota generiše odgovore koji se mogu direktno uporediti.
3. [**AlpacaEval**](https://github.com/tatsu-lab/alpaca_eval)**:** AlpacaEval je automatizovani okvir za evaluaciju gde napredni LLM poput GPT-4 procenjuje odgovore drugih modela na različite promptove.
4. **General Language Understanding Evaluation (**[**GLUE**](https://gluebenchmark.com/)**):** GLUE je zbirka od devet zadataka razumevanja prirodnog jezika, uključujući analizu sentimenta, tekstualno podrazumevanje i odgovaranje na pitanja.
4. **General Language Understanding Evaluation (**[**GLUE**](https://gluebenchmark.com/)**):** GLUE je zbirka od devet zadataka razumevanja prirodnog jezika, uključujući analizu sentimenta, tekstualno impliciranje i odgovaranje na pitanja.
5. [**SuperGLUE**](https://super.gluebenchmark.com/)**:** Oslanjajući se na GLUE, SuperGLUE uključuje izazovnije zadatke dizajnirane da budu teški za trenutne modele.
6. **Beyond the Imitation Game Benchmark (**[**BIG-bench**](https://github.com/google/BIG-bench)**):** BIG-bench je velika skala benchmark sa više od 200 zadataka koji testiraju sposobnosti modela u oblastima kao što su rezonovanje, prevođenje i odgovaranje na pitanja.
6. **Beyond the Imitation Game Benchmark (**[**BIG-bench**](https://github.com/google/BIG-bench)**):** BIG-bench je velika mera sa više od 200 zadataka koji testiraju sposobnosti modela u oblastima kao što su rezonovanje, prevođenje i odgovaranje na pitanja.
7. **Holistic Evaluation of Language Models (**[**HELM**](https://crfm.stanford.edu/helm/lite/latest/)**):** HELM pruža sveobuhvatnu evaluaciju kroz različite metrike kao što su tačnost, robusnost i pravednost.
8. [**OpenAI Evals**](https://github.com/openai/evals)**:** Okvir za evaluaciju otvorenog koda od strane OpenAI koji omogućava testiranje AI modela na prilagođenim i standardizovanim zadacima.
9. [**HumanEval**](https://github.com/openai/human-eval)**:** Zbirka programerskih problema koji se koriste za procenu sposobnosti generisanja koda jezičkih modela.

View File

@ -13,7 +13,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 1. Tokenizacija
> [!TIP]
> Cilj ove inicijalne faze je veoma jednostavan: **Podeliti ulaz u tokene (ids) na način koji ima smisla**.
> Cilj ove inicijalne faze je vrlo jednostavan: **Podeliti ulaz u tokene (ids) na način koji ima smisla**.
{{#ref}}
1.-tokenizing.md
@ -22,7 +22,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 2. Uzorkovanje Podataka
> [!TIP]
> Cilj ove druge faze je veoma jednostavan: **Uzorkovati ulazne podatke i pripremiti ih za fazu obuke obično razdvajanjem skupa podataka na rečenice određene dužine i generisanjem očekivanog odgovora.**
> Cilj ove druge faze je vrlo jednostavan: **Uzorkovati ulazne podatke i pripremiti ih za fazu obuke obično razdvajanjem skupa podataka na rečenice određene dužine i generisanjem očekivanog odgovora.**
{{#ref}}
2.-data-sampling.md
@ -31,7 +31,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 3. Token Umetanja
> [!TIP]
> Cilj ove treće faze je veoma jednostavan: **Dodeliti svakom od prethodnih tokena u rečniku vektor željenih dimenzija za obuku modela.** Svaka reč u rečniku će biti tačka u prostoru X dimenzija.\
> Cilj ove treće faze je vrlo jednostavan: **Dodeliti svakom od prethodnih tokena u rečniku vektor željenih dimenzija za obuku modela.** Svaka reč u rečniku će biti tačka u prostoru X dimenzija.\
> Imajte na umu da je inicijalno pozicija svake reči u prostoru samo "nasumično" inicijalizovana i te pozicije su parametri koji se mogu obučavati (biće poboljšani tokom obuke).
>
> Štaviše, tokom umetanja tokena **stvara se još jedan sloj umetanja** koji predstavlja (u ovom slučaju) **apsolutnu poziciju reči u rečenici za obuku**. Na ovaj način, reč na različitim pozicijama u rečenici će imati različitu reprezentaciju (značenje).
@ -43,7 +43,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 4. Mehanizmi Pažnje
> [!TIP]
> Cilj ove četvrte faze je veoma jednostavan: **Primena nekih mehanizama pažnje**. Ovi će biti mnogo **ponovljenih slojeva** koji će **uhvatiti odnos reči u rečniku sa njenim susedima u trenutnoj rečenici koja se koristi za obuku LLM-a**.\
> Cilj ove četvrte faze je vrlo jednostavan: **Primena nekih mehanizama pažnje**. Ovi mehanizmi će biti mnogo **ponovljenih slojeva** koji će **uhvatiti odnos reči u rečniku sa njenim susedima u trenutnoj rečenici koja se koristi za obuku LLM-a**.\
> Za ovo se koristi mnogo slojeva, tako da će mnogo parametara koji se mogu obučavati uhvatiti ove informacije.
{{#ref}}
@ -53,7 +53,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 5. LLM Arhitektura
> [!TIP]
> Cilj ove pete faze je veoma jednostavan: **Razviti arhitekturu celog LLM-a**. Spojiti sve, primeniti sve slojeve i kreirati sve funkcije za generisanje teksta ili transformaciju teksta u ID-ove i obrnuto.
> Cilj ove pete faze je vrlo jednostavan: **Razviti arhitekturu celog LLM-a**. Spojiti sve, primeniti sve slojeve i kreirati sve funkcije za generisanje teksta ili transformaciju teksta u ID-ove i obrnuto.
>
> Ova arhitektura će se koristiti i za obuku i za predikciju teksta nakon što je obučena.
@ -64,7 +64,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 6. Predobuka i Učitavanje modela
> [!TIP]
> Cilj ove šeste faze je veoma jednostavan: **Obučiti model od nule**. Za ovo će se koristiti prethodna LLM arhitektura sa nekim petljama koje prolaze kroz skupove podataka koristeći definisane funkcije gubitka i optimizator za obuku svih parametara modela.
> Cilj ove šeste faze je vrlo jednostavan: **Obučiti model od nule**. Za ovo će se koristiti prethodna LLM arhitektura sa nekim petljama koje prolaze kroz skupove podataka koristeći definisane funkcije gubitka i optimizator za obuku svih parametara modela.
{{#ref}}
6.-pre-training-and-loading-models.md
@ -82,7 +82,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 7.1. Fino Podešavanje za Klasifikaciju
> [!TIP]
> Cilj ovog odeljka je da pokaže kako fino podešavati već obučeni model tako da umesto generisanja novog teksta LLM daje **verovatnoće da dati tekst bude kategorizovan u svaku od datih kategorija** (kao što je da li je tekst spam ili ne).
> Cilj ovog dela je da pokaže kako fino podešavati već unapred obučeni model tako da umesto generisanja novog teksta LLM daje **verovatnoće da dati tekst bude kategorizovan u svaku od datih kategorija** (kao što je da li je tekst spam ili ne).
{{#ref}}
7.1.-fine-tuning-for-classification.md
@ -91,7 +91,7 @@ Trebalo bi da počnete čitanjem ovog posta za neke osnovne koncepte koje treba
## 7.2. Fino Podešavanje za Praćenje Uputstava
> [!TIP]
> Cilj ovog odeljka je da pokaže kako **fino podešavati već obučeni model da prati uputstva** umesto samo generisanja teksta, na primer, odgovaranje na zadatke kao chat bot.
> Cilj ovog dela je da pokaže kako **fino podešavati već unapred obučeni model da prati uputstva** umesto samo generisanja teksta, na primer, odgovaranje na zadatke kao chat bot.
{{#ref}}
7.2.-fine-tuning-to-follow-instructions.md