Metadata-Version: 2.4
Name: tota
Version: 1.0.1
Summary: Prosta biblioteka do tworzenia i uczenia sieci neuronowych
Author: Tomasz Tota
License: MIT
Keywords: machine-learning,neural-networks,pytorch,education
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch>=2.0
Dynamic: license-file

# tota

Prosta, edukacyjna biblioteka Python do tworzenia i uczenia małych sieci neuronowych.

Biblioteka korzysta z PyTorch do obliczeń tensorowych na CPU.

## Instalacja

```bash
python -m pip install tota
```

Wersja z lokalnego repozytorium:

```bash
python -m pip install .
```

## Szybki start

```python
from tota import Layer, Network

training_data = [
    ([1], 0),
    ([2], 0),
    ([6], 1),
    ([8], 1),
]

network = Network([
    Layer(5, 1),
    Layer(1, 5),
])

print(network.learn(
    training_data,
    learning_rate=0.01,
    epochs=5000,
))

print(network.predict([7]))
```

## Główne klasy

Wersja `1.0.1` zachowuje stabilne klasy `Neuron`, `Layer` i `Network`.

### `Neuron`

Pojedynczy neuron z wagami, biasem i funkcją aktywacji.

```python
from tota import Neuron

neuron = Neuron([0.5, -0.2], 0.0, activation="sigmoid")
wynik = neuron.forward([1.0, 2.0])
```

### `Layer`

Warstwa wielu neuronów:

```python
from tota import Layer

warstwa = Layer(5, 2, activation="relu")
wynik = warstwa.forward([1.0, 2.0])
```

### `Network`

Łączy warstwy i udostępnia uczenie oraz predykcję:

```python
from tota import Layer, Network

network = Network([
    Layer(5, 2),
    Layer(1, 5),
])

network.learn(dane, learning_rate=0.01, epochs=5000)
klasa = network.predict([1, 2])
```

## Funkcje aktywacji

Dostępne są:

- `sigmoid` — domyślna funkcja,
- `relu`,
- `tanh`,
- `linear`,
- `leaky_relu`,
- `step`.

Aktywację ustawia się osobno dla każdej warstwy:

```python
network = Network([
    Layer(8, 2, activation="relu"),
    Layer(1, 8, activation="sigmoid"),
])
```

## Parametry `Network.learn`

```python
network.learn(
    training_data,
    learning_rate=0.01,
    epochs=50000,
    show_progress=True,
    progress_interval=1000,
)
```

Metoda używa optymalizatora SGD i zwraca tekst z liczbą wykonanych epok oraz końcowym błędem.

## Rozwój lokalny

```bash
python -m pip install -e .
python -m pip install pytest
pytest
```

## Transformer — beta

Moduł Transformera jest eksperymentalny. API oraz sposób zapisu checkpointów
mogą się zmienić przed wydaniem stabilnym. Korzysta z PyTorch i obsługuje
sekwencje w formacie `(batch_size, sequence_length)` oraz logity w formacie
`(batch_size, sequence_length, vocab_size)`.

### Tokenizer

`Tokenizer` jest obecnie tokenizerem znakowym. Buduje słownik na podstawie
tekstu i udostępnia tokeny specjalne `<PAD>`, `<UNK>`, `<BOS>` i `<EOS>`:

```python
from tota import Tokenizer

tokenizer = Tokenizer("Ala ma kota")
tokens = tokenizer.encode("Ala ma")
tekst = tokenizer.decode(tokens)
print(tokenizer.vocab_size, tokens, tekst)
```

Można wyłączyć dodawanie tokenów początku i końca sekwencji przez
`encode(tekst, add_bos=False, add_eos=False)`. BPE nie jest jeszcze dostępny.

### Model językowy

`TransformerLM` składa się z embeddingów, kodowania pozycyjnego, bloków
multi-head attention, sieci feed-forward, LayerNorm oraz liniowej głowicy
przewidującej następny token:

```python
from tota import Tokenizer, TransformerLM

with open("data.txt", encoding="utf-8") as file:
    text = file.read()

tokenizer = Tokenizer(text)
model = TransformerLM(
    tokenizer,
    dlugosc_sekwencji=32,
    rozmiar_embeddingu=64,
    liczba_glow=4,
    liczba_blokow=2,
    rozmiar_feed_forward=128,
)
```

### Trening i generowanie

`train_text` tworzy pary wejście-cel przesunięte o jeden token, używa
`CrossEntropyLoss` i optymalizatora AdamW. Dostępne są `batch_size`, `warmup`,
`checkpoint` oraz clipping gradientów:

```python
historia = model.train_text(
    text,
    epochs=5,
    batch_size=8,
    learning_rate=0.001,
    warmup=1,
    checkpoint="model.tota",
)

wynik = model.generate("Ala ma", max_tokens=40, temperature=0.8, top_k=5, top_p=0.9)
print(wynik)
```

Poza `TransformerLM` dostępne są komponenty `Embedding`, `PositionalEncoding`,
`Linear`, `LayerNorm`, `SelfAttention`, `MultiHeadAttention`, `FeedForward`,
`TransformerBlock`, `CrossEntropyLoss` i `AdamW`. Wszystkie są oznaczone jako
beta i wymagają dalszych testów na większych zbiorach danych.

### Jak działa trening

Model uczy się przewidywać token znajdujący się o jedną pozycję dalej:

```text
wejście: Ala ma kota
cel:       ma kota <EOS>
```

Tekst jest dzielony na fragmenty o długości `dlugosc_sekwencji`. Krótsze
fragmenty są uzupełniane tokenem `<PAD>`, który jest pomijany przez funkcję
straty. Maska przyczynowa w attention uniemożliwia modelowi odczytanie
przyszłych tokenów.

### Dobór parametrów

- `dlugosc_sekwencji` — maksymalna długość kontekstu; większa wymaga więcej pamięci.
- `rozmiar_embeddingu` — rozmiar wektora tokenu; musi dzielić się przez `liczba_glow`.
- `liczba_glow` — liczba niezależnych głów attention.
- `liczba_blokow` — liczba bloków Transformera.
- `rozmiar_feed_forward` — szerokość sieci wewnątrz każdego bloku.
- `temperature` — większa wartość daje bardziej losowe generowanie.
- `top_k` — ogranicza losowanie do `k` najbardziej prawdopodobnych tokenów.
- `top_p` — ogranicza losowanie do najmniejszego zbioru tokenów o łącznym prawdopodobieństwie `p`.

Na początek warto użyć małych wartości:

```python
model = TransformerLM(
    tokenizer,
    dlugosc_sekwencji=32,
    rozmiar_embeddingu=64,
    liczba_glow=4,
    liczba_blokow=2,
    rozmiar_feed_forward=128,
)
```

### Checkpointy

Parametr `checkpoint` zapisuje wagi po każdej epoce. Do wznowienia pracy
tworzy się model o tej samej architekturze i ładuje jego `state_dict`:

```python
import torch

torch.save(model.state_dict(), "model.tota")
model.load_state_dict(torch.load("model.tota", weights_only=True))
```

Można też zapisać model razem z informacją o epoce i stanem optymalizatora:

```python
model.save_checkpoint("model-full.tota", epoch=5)
model.load_checkpoint("model-full.tota")
```

Tokenizer należy zapisać osobno, ponieważ model nie przechowuje jego słownika:

```python
tokenizer.save("tokenizer.json")
tokenizer = Tokenizer.load("tokenizer.json")
```

### Pełny przykład z plikiem `data.txt`

```python
from tota import Tokenizer, TransformerLM

with open("data.txt", encoding="utf-8") as file:
    text = file.read()

tokenizer = Tokenizer(text)
model = TransformerLM(tokenizer, dlugosc_sekwencji=32)
model.train_text(text, epochs=10, batch_size=8, checkpoint="model.tota")
tokenizer.save("tokenizer.json")
print(model.generate("Początek", max_tokens=80, temperature=0.8))
```

### Aktualne ograniczenia beta

- tokenizer obsługuje znaki, ale nie ma jeszcze BPE ani tokenizacji słów;
- model jest przeznaczony do małych eksperymentów edukacyjnych;
- implementacja nie oferuje jeszcze gotowego loadera dużych zbiorów danych;
- RoPE i mixed precision są planowane;
- kompatybilność dotyczy API, ale format checkpointów beta może się zmienić.

## Licencja

MIT — zobacz plik `LICENSE`.
