Metadata-Version: 2.4
Name: tota
Version: 1.1.0
Summary: Prosta biblioteka do tworzenia i uczenia sieci neuronowych
Author: Tomasz Tota
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch>=2.0
Requires-Dist: Pillow>=10
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Provides-Extra: keywords
Requires-Dist: machine-learning; extra == "keywords"
Requires-Dist: neural-networks; extra == "keywords"
Requires-Dist: pytorch; extra == "keywords"
Requires-Dist: education; extra == "keywords"
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 lub GPU CUDA.
Jeśli CUDA jest dostępna w zainstalowanej wersji PyTorch, urządzenie jest
wybierane automatycznie. Można je też wymusić przez parametr `device`.

## 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.1.0` zachowuje kompatybilność klas `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"),
])
```

`Network` automatycznie użyje CUDA, jeśli `torch.cuda.is_available()` zwraca
`True`. Urządzenie można zmienić później przez `network.to("cpu")` lub
`network.to("cuda")`.

## 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 -e ".[dev]"
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 tokenizerem znakowym. `BPETokenizer` uczy się dodatkowo
częstych połączeń znaków, dzięki czemu dłuższy tekst zajmuje mniej tokenów.
Oba udostępniają 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)
```

```python
from tota import BPETokenizer

tokenizer = BPETokenizer(tekst_treningowy, vocab_size=1024)
tokenizer.save("tokenizer.json")
tokenizer = BPETokenizer.load("tokenizer.json")
```

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

### 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`, przesuwane okna przez `stride`, bezpieczne przerwanie przez
`should_stop` 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 stan atomowo po każdej epoce. Bez
`checkpoint_metadata` i `resume_state` pozostaje to zwykły `state_dict`:

```python
import torch

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

Przekazanie `checkpoint_metadata` tworzy stan `tota-training-v2` zawierający
również optymalizator, numer epoki i stany generatorów losowych. Można go
przekazać ponownie jako `resume_state`; przerwana część epoki zostanie
dokończona od zapisanego batcha.

Można też użyć prostszego API checkpointu modelu:

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

Tokenizer należy zapisać osobno, ponieważ model nie osadza jego słownika w
`state_dict`:

```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

- model jest przeznaczony do małych eksperymentów edukacyjnych;
- jakość na nowych pytaniach wymaga odpowiednio dużego i zróżnicowanego zbioru;
- generowanie nie ma jeszcze cache KV, więc koszt rośnie wraz z odpowiedzią;
- RoPE, mixed precision i trening rozproszony nie są jeszcze dostępne;
- kompatybilność dotyczy API, ale format checkpointów beta może się zmienić.

## Licencja

MIT — zobacz plik `LICENSE`.

## Rozpoznawanie obrazów

Biblioteka zawiera prosty klasyfikator CNN oraz dataset katalogowy. Podkatalogi
oznaczają klasy, na przykład `obrazy/koty` i `obrazy/psy`:

```python
from tota import ImageClassifier, ImageFolderDataset

dataset = ImageFolderDataset("obrazy", image_size=64)
model = ImageClassifier(
    len(dataset.classes), image_size=64, classes=dataset.classes
)
model.fit(dataset, epochs=5, batch_size=16)
print(model.predict("obraz.jpg"))
model.save_checkpoint("klasyfikator.tota")
```

Klasyfikator automatycznie używa CUDA, jeśli bieżąca instalacja PyTorch ją
obsługuje. Ten segment wykonuje klasyfikację całego obrazu, a nie detekcję
wielu obiektów.
